/* The generation workspace (WORKSPACE.md Phase C): control rail plus
   canvas on desktop, stacked on mobile. Rail cards reuse the upload-card
   and style-picker-card surfaces; this file only owns the layout, the
   style modal, and the board chrome. */

.workspace {
  display: grid;
  gap: var(--space-5);
  align-items: start;
}

.workspace-rail {
  display: grid;
  gap: var(--space-4);
}

.rail-scroll {
  display: grid;
  gap: var(--space-4);
  align-content: start;
}

.rail-pinned {
  display: grid;
  gap: var(--space-2);
}

@media (min-width: 1024px) {
  .workspace {
    grid-template-columns: 360px minmax(0, 1fr);
  }

  /* Fal-style rail (owner call 2026-07-18): the rail pins to the
     viewport, its controls scroll internally, and the pinned footer
     keeps the render button in reach no matter how long the canvas
     gets. The page scrollbar stays the canvas scrollbar. These rules
     must come after the base .workspace-rail block: they override its
     grid display at desktop widths.

     Two corrections (2026-07-24). The sticky offset clears the site
     header: at top: space-3 the rail's first card slid under the
     header's blur once you scrolled. And the height subtracts the
     header plus the greeting row, because at rest the rail starts
     below both; sizing against the bare viewport pushed .rail-pinned,
     and with it the render button, under the fold on arrival. Costs
     the rail --dash-chrome of scroll depth once scrolled past the
     greeting, which is the right trade for a CTA that is never
     off-screen. svh, not vh, so mobile browser chrome cannot do the
     same thing again. */
  .workspace-rail {
    position: sticky;
    top: calc(var(--header-h) + var(--space-3));
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    max-height: calc(100svh - var(--header-h) - var(--dash-chrome) - var(--space-5));
  }

  .rail-scroll {
    overflow-y: auto;
    min-height: 0;
    padding-right: var(--space-2);
    /* The overflow cut the quality cards clean in half with nothing to
       say more was below. A short static fade reads as a scroll edge.
       Deliberately not a scroll-driven animation that lifts at the end:
       animation-timeline is Chromium-only, and the fallback there is a
       permanently dimmed final control in Safari and Firefox. Static
       costs one faded hairline at the very bottom of the scroll and is
       the same everywhere. */
    mask-image: linear-gradient(to bottom, #000 calc(100% - var(--space-4)), transparent 100%);
    /* The rail's own scrollbar, quieted: the default macOS bar rendered
       as a hard grey rule between rail and canvas and read as a page
       artifact rather than as the rail's own overflow. */
    scrollbar-width: thin;
    scrollbar-color: var(--line) transparent;
  }

  .rail-scroll::-webkit-scrollbar {
    width: 6px;
  }

  .rail-scroll::-webkit-scrollbar-track {
    background: transparent;
  }

  .rail-scroll::-webkit-scrollbar-thumb {
    background: var(--line);
    border-radius: 3px;
  }

  .rail-scroll:hover::-webkit-scrollbar-thumb {
    background: var(--ink-soft);
  }

  /* The rail's vertical budget belongs to the controls that gate a
     render, not to the photo you set once: rail cards run tighter than
     the page-level card they share a class with. */
  .workspace-rail .upload-card,
  .workspace-rail .style-picker-card {
    padding: var(--space-4);
    margin-top: 0;
  }

  .rail-pinned {
    padding-top: 0;
  }

  /* The thumb is sized by .upload-current now (auth.css): a 5.5rem
     square beside the Replace button, rather than a full-width preview
     capped at 9rem. Overriding it here as well only reopened a
     specificity tie between two files. */
}

.workspace-canvas {
  display: grid;
  gap: var(--space-4);
}

/* Selected styles mirrored as chips in the rail */

.board-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.board-chip {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  border: 1px solid var(--ink);
  padding: 0.2em 0.6em;
  border-radius: var(--radius-pill);
  background: var(--paper);
}

.board-count {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-soft);
}

.board-note {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

/* The free-tier board upsell tile: honest tease, no fake locked slots */

.board-upsell {
  border: 1px dashed var(--ink-soft);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.board-upsell a {
  color: var(--accent);
}

/* The style picker modal */

.style-modal {
  width: min(64rem, calc(100vw - 2rem));
  max-height: 88vh;
  border: var(--border-hard);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  background: var(--paper);
}

.style-modal::backdrop {
  background: rgba(16, 16, 16, 0.55);
}

.style-modal-head {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  margin-bottom: var(--space-3);
}

.style-modal-head input[type="search"] {
  flex: 1;
  font: inherit;
  padding: 0.5em 0.9em;
  border: var(--border-hard);
  border-radius: var(--radius-pill);
  background: var(--paper-card);
}

/* The search filter sets [hidden]; the grid's display rule on
   .style-option would beat the UA stylesheet without this. */
.style-modal .style-option[hidden] {
  display: none;
}

.style-modal .style-picker-grid {
  max-height: 62vh;
  overflow-y: auto;
  padding-right: var(--space-1);
}

.style-modal-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-3);
}

/* Rail credit summary under the render button */

.rail-credits {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-soft);
}

/* Hint under the disabled render button until a pick arms it */

.rail-hint {
  font-size: var(--text-xs);
  color: var(--ink-soft);
}

/* Header credit chip (all authenticated pages): a star and two numbers.
   The word "Credits" lives in a visually-hidden span and the title
   attribute; spelled out it was the widest thing in the header and
   pushed 375px phones into horizontal overflow. */

.credit-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  border: 1px solid var(--ink);
  border-radius: var(--radius-pill);
  padding: 0.4em 0.8em;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}

.credit-star {
  width: 0.85em;
  height: 0.85em;
  fill: var(--accent);
  flex: none;
}

/* Empty-state worked example in the canvas */

.canvas-example {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
}

.canvas-example figure {
  margin: 0;
}

.canvas-example img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  display: block;
}

.canvas-example figcaption {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-soft);
  margin-top: var(--space-1);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* Render pages (Phase D) */

.render-meta {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.render-ba {
  margin-block: var(--space-4);
}

.render-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-block: var(--space-3);
}

.render-board-strip {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--space-2);
}

.render-board-thumb {
  display: grid;
  gap: var(--space-1);
  text-decoration: none;
  color: var(--ink-soft);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.render-board-thumb img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  display: block;
}

.gallery-fresh {
  margin-bottom: var(--space-6);
}

/* Premium style locks in the picker (Phase E) */

.style-option.is-locked {
  text-decoration: none;
  color: inherit;
}

.style-option.is-locked img {
  opacity: 0.55;
}

.style-lock {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 0.7em;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: var(--ink);
  color: var(--paper);
  padding: 0.15em 0.5em;
  border-radius: var(--radius-pill);
  margin-left: 0.4em;
}

/* The search filter also applies to locked cards */
.style-modal .style-option.is-locked[hidden] {
  display: none;
}

/* Admin render QC (owner-only, scope amendment 2026-07-18) */

.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--space-3);
  margin-block: var(--space-3) var(--space-5);
}

.admin-card {
  background: var(--paper-card);
  border: var(--border-hard);
  padding: var(--space-2);
  display: grid;
  gap: var(--space-2);
}

.admin-card img {
  width: 100%;
  height: auto;
  display: block;
}

.admin-card-meta {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-soft);
}

.admin-card-actions {
  display: flex;
  gap: var(--space-2);
}
