/* ==========================================================================
   Shared chrome for every screen.

   Rebuilt for the redesign (design/redesign/IMPLEMENTATION_PLAN.md, lane 1)
   from design/redesign/studio-redesign.html: the top bar, the segments, the
   filter toolbar, the rows, the pager, the "with these products" menu, the
   store checks block, the Details drawer, the side panel, the toast, the
   product header with its identity line, the next-action strip and the four
   step rail. Light and dark come from the tokens, so nothing here names a
   colour.

   The second half keeps the classes the OLD page markup still uses, because
   lanes 2 to 4 have not rebuilt the four step bodies yet: the fold component,
   the status pills, the rendered description, the word diff and the AI shot
   reject row. Nothing was dropped.
   ========================================================================== */

/* ---------- store-mode banner ---------- */
/* Slim strip above the top bar on every screen naming the Shopify store this
   server is connected to (src/services/store-mode.js). Sticky so it stays in
   view on long pages; the top bar then sticks directly under it. Green for the
   dev store, red for the live store read-only, striped dark red for the live
   store with writes enabled. */
.store-banner {
  position: sticky; top: 0; z-index: 21;
  min-height: var(--store-banner-h); line-height: var(--store-banner-h);
  padding: 0 var(--s-5);
  padding-top: env(safe-area-inset-top, 0px);
  text-align: center; font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.02em;
  color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  justify-self: stretch; align-self: start; /* full width on the grid-centred sign-in pages */
}
.store-banner-dev { background: var(--ok); }
.store-banner-live-readonly { background: var(--danger); }
.store-banner-live-writable {
  background: repeating-linear-gradient(-45deg, #7A1A10 0 12px, #A3261A 12px 24px);
  font-weight: 700; letter-spacing: 0.06em;
}
.store-banner-none { background: var(--warn); }
.store-banner ~ .topbar { top: var(--store-banner-h); }
:root[data-theme="dark"] .store-banner-live-readonly { color: #2B100A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .store-banner-live-readonly { color: #2B100A; }
}

/* ---------- top bar ----------
   Three items: Catalogue, Queue (with the review count) and History. The store
   label and the read-only guard stay on the right. */
.topbar {
  height: var(--topbar-h);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: var(--s-5);
  padding: 0 var(--s-5);
  position: sticky; top: 0; z-index: 20;
}
.wordmark { display: flex; align-items: baseline; gap: var(--s-2); text-decoration: none; color: var(--ink); flex: 0 0 auto; }
.wordmark .name { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 600; letter-spacing: 0.01em; white-space: nowrap; }
.wordmark .sub { font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-faint); white-space: nowrap; }
.topnav { display: flex; gap: var(--s-1); margin-left: var(--s-2); flex: 0 0 auto; }
.topnav a {
  color: var(--ink-soft); text-decoration: none; font-size: var(--text-sm);
  padding: 6px 10px; border-radius: var(--r-md);
  white-space: nowrap;
}
.topnav a:hover { color: var(--ink); background: var(--surface-sunken); }
.topnav a[aria-current="page"] { color: var(--tan); font-weight: 600; }
/* The review count beside Queue: a number, not a badge. */
.topnav .n { color: var(--ink-faint); font-weight: 400; }
.topbar .user { margin-left: auto; display: flex; align-items: center; gap: var(--s-3); font-size: var(--text-sm); color: var(--ink-soft); min-width: 0; }
/* The chips and the signed-in name give way before anything wraps: one line
   each, truncated with an ellipsis, with the full text in the title attribute. */
.topbar .user > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.env-chip { font-size: var(--text-xs); border: 1px solid var(--line-strong); border-radius: var(--r-pill); padding: 2px 10px; color: var(--ink-soft); flex: 0 1 auto; max-width: 46ch; }
/* Read-only store mode chip: warn colours so the guard is visible on every screen. */
.env-chip-readonly { border-color: var(--warn); background: var(--warn-tint); color: var(--warn); font-weight: 600; }
.logout { font: inherit; font-size: var(--text-xs); background: none; border: 0; color: var(--ink-soft); cursor: pointer; padding: 0; white-space: nowrap; }
.logout:hover { color: var(--tan); text-decoration: underline; }

/* Narrow screens (OPUS_REVIEW_LOG entries 10 and 13: at 800 px "Leather
   Company" wrapped to two lines, "Review (5)" split and the store chip ran to
   three; at 400 px the bar was 671 px wide and pushed the whole page sideways).
   The bar never wraps now. Things give way in order as the screen narrows: the
   gaps tighten, then the chips truncate, then the Product Studio kicker and the
   signed-in name go (the sign-in page and the store banner still name both),
   then the chips shrink again. The wordmark and the three nav items always
   stay whole, because they are the navigation. */
@media (max-width: 900px) {
  .topbar { gap: var(--s-3); padding: 0 var(--s-4); }
  .topnav { margin-left: 0; }
  .topbar .user { gap: var(--s-2); }
  .env-chip { max-width: 16ch; }
}
@media (max-width: 700px) {
  .wordmark .sub { display: none; }
  .topbar .user > span:not(.env-chip) { display: none; }
  .env-chip { max-width: 10ch; }
}
/* Phone width. The three nav items, the read-only guard and Sign out are all
   that fit, so the wordmark goes (the Catalogue item next to it is the same
   link home) and the store chip goes with it (the store banner above names the
   store on every local page). The read-only chip stays whatever happens: it is
   the guard, and on the hosted instance, where there is no banner, it is the
   only thing that says so. */
@media (max-width: 520px) {
  .topbar { gap: var(--s-2); padding: 0 var(--s-3); }
  .wordmark { display: none; }
  .topnav { gap: 0; }
  .topnav a { padding: 6px 5px; font-size: var(--text-xs); }
  .topbar .user > .env-chip:not(.env-chip-readonly) { display: none; }
  .env-chip { max-width: 12ch; padding: 2px 6px; }
}

.page { max-width: var(--page-max); margin: 0 auto; padding: var(--s-6) var(--s-5) var(--s-7); }
@media (max-width: 640px) { .page { padding: var(--s-5) var(--s-4) var(--s-6); } }

/* ---------- display type and quiet text helpers ---------- */
.eyebrow {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--ink-faint); font-weight: 600;
}
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); }
.small { font-size: var(--text-sm); }

/* The page head: title and lede on the left, the segments or Details on the right. */
.head-row { display: flex; align-items: flex-end; gap: var(--s-4); flex-wrap: wrap; margin-bottom: var(--s-2); }
.head-row .grow { flex: 1 1 200px; min-width: 0; }
.head-row h1 { font-family: var(--font-display); font-size: var(--text-3xl); font-weight: 600; line-height: 1.18; letter-spacing: -0.012em; margin: 0; }
.lede { color: var(--ink-soft); margin: 6px 0 0; max-width: 62ch; }

/* ---------- buttons ---------- */
.btn {
  font: inherit; font-size: var(--text-sm); font-weight: 600;
  border-radius: var(--r-md); padding: 7px 14px;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
  cursor: pointer; display: inline-flex; align-items: center; gap: 7px;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
  text-decoration: none;
}
.btn:hover { background: var(--surface-sunken); }
.btn-primary { background: var(--tan); border-color: var(--tan); color: #fff; }
:root[data-theme="dark"] .btn-primary { color: #1A1209; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .btn-primary { color: #1A1209; }
}
.btn-primary:hover { background: var(--tan-deep); border-color: var(--tan-deep); }
/* The one green go button: the next action and Approve and write. */
.btn-go { background: var(--ok); border-color: var(--ok); color: #fff; }
:root[data-theme="dark"] .btn-go { color: #0E1A12; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .btn-go { color: #0E1A12; }
}
.btn-go:hover { filter: brightness(1.08); }
/* Quiet: a button that reads as a link until you are near it. */
.btn-quiet { border-color: transparent; background: none; color: var(--ink-soft); padding: 6px 8px; }
.btn-quiet:hover { background: var(--surface-sunken); color: var(--ink); }
.btn-sm { padding: 4px 10px; font-size: var(--text-xs); }
.btn-ok { border-color: var(--ok); color: var(--ok); }
.btn-ok:hover { background: var(--ok-tint); }
.btn-danger { border-color: var(--danger); color: var(--danger); }
.btn-danger:hover { background: var(--danger-tint); }
.btn-approve { background: var(--ok); border-color: var(--ok); color: #fff; }
.btn-approve:hover { filter: brightness(1.08); }
.btn-reject { border-color: var(--danger); color: var(--danger); background: var(--surface); }
.btn-reject:hover { background: var(--danger-tint); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
/* A plain text button that behaves like a link. */
.link { background: none; border: 0; font: inherit; color: var(--tan); cursor: pointer; padding: 0; text-decoration: underline; text-underline-offset: 2px; }

/* ---------- status marks ---------- */
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: 0 0 auto; background: var(--ink-faint); }
.dot.ok { background: var(--ok); }
.dot.warn { background: var(--warn); }
.dot.bad { background: var(--danger); }
.dot.info { background: var(--info); }
.state { display: inline-flex; align-items: center; gap: 7px; font-size: var(--text-sm); font-weight: 500; color: var(--ink-soft); }
/* Named ftag, not tag: the old step bodies already own .tag. */
.ftag {
  display: inline-block; font-size: var(--text-xs); font-weight: 600; border-radius: var(--r-pill);
  padding: 2px 9px; background: var(--surface-sunken); color: var(--ink-soft); border: 1px solid transparent;
}
.ftag.ok { background: var(--ok-tint); color: var(--ok); }
.ftag.warn { background: var(--warn-tint); color: var(--warn); }
.ftag.tan { background: var(--tan-tint); color: var(--tan); }

/* ---------- segments: Needs you | All products ---------- */
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--r-md); overflow: hidden; background: var(--surface); }
.seg a, .seg button {
  font: inherit; font-size: var(--text-sm); font-weight: 600; border: 0; background: none;
  color: var(--ink-soft); padding: 7px 14px; cursor: pointer; white-space: nowrap; text-decoration: none;
}
.seg a + a, .seg button + button { border-left: 1px solid var(--line); }
.seg a[aria-pressed="true"], .seg button[aria-pressed="true"] { background: var(--tan-tint); color: var(--tan); }

/* ---------- the filter toolbar ----------
   Filter is its own toolbar on the catalogue. Audit is not here any more: the
   store-wide checks are a block at the top of History. */
.toolbar { display: flex; gap: var(--s-2); align-items: flex-end; flex-wrap: wrap; margin: var(--s-5) 0 var(--s-3); }
.toolbar .fld { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.toolbar .fld > span { font-size: var(--text-xs); color: var(--ink-faint); font-weight: 600; }
.toolbar select, .toolbar input {
  font: inherit; font-size: var(--text-sm); padding: 7px 10px; border-radius: var(--r-md);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); max-width: 100%;
}
.toolbar .fld-search { flex: 1 1 220px; min-width: 0; }
.toolbar form { margin: 0; display: contents; }
/* "With these products" appears only once a filter is on. */
.filterline { display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap; font-size: var(--text-sm); color: var(--ink-soft); margin: 0 0 var(--s-3); }
.filterline form { margin: 0; }
.menu-wrap { position: relative; display: inline-block; }
.menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 25; min-width: 260px;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r-md);
  box-shadow: var(--shadow-raise); padding: var(--s-2);
}
.menu.left { left: 0; right: auto; }
.menu .mi, .menu button.mi {
  display: block; width: 100%; text-align: left; font: inherit; font-size: var(--text-sm);
  background: none; border: 0; border-radius: var(--r-sm); padding: 7px 9px; cursor: pointer; color: var(--ink);
}
.menu .mi:hover { background: var(--surface-sunken); }
.menu .mi small { display: block; color: var(--ink-faint); font-size: var(--text-xs); font-weight: 400; }
.menu .mi[disabled] { opacity: .5; cursor: not-allowed; }
.menu .mh { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.09em; color: var(--ink-faint); font-weight: 600; padding: var(--s-2) 9px 3px; }
.menu form { margin: 0; }

/* ---------- the row list ----------
   One row: thumbnail, clickable title, one status, one action. */
.list { border-top: 1px solid var(--line); }
.row {
  display: grid; grid-template-columns: 56px minmax(0, 1fr) 190px auto;
  gap: var(--s-4); align-items: center;
  padding: var(--s-4) var(--s-2); border-bottom: 1px solid var(--line);
}
.row:hover { background: var(--surface); }
.thumb {
  width: 56px; height: 68px; border-radius: var(--r-sm); background: var(--surface-sunken);
  overflow: hidden; display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb.noimg::after { content: "No photo"; font-size: 9px; color: var(--ink-faint); text-align: center; padding: 2px; line-height: 1.2; }
.thumb.noimg img { display: none; }
a.thumb, button.thumb { border: 0; cursor: pointer; padding: 0; }
.row .name { font-family: var(--font-display); font-size: var(--text-md); font-weight: 600; display: block; }
.row .sku { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-faint); }
.row .why { font-size: var(--text-sm); color: var(--ink-soft); margin-top: 3px; }
.row .act { text-align: right; }
.row .act form { margin: 0; }
/* The name and the thumbnail are both the way in, so both are links. */
.openit { font: inherit; background: none; border: 0; padding: 0; cursor: pointer; text-align: left; color: inherit; display: block; width: 100%; text-decoration: none; }
.openit .name { text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--line-strong); }
.openit:hover .name { text-decoration-color: var(--tan); color: var(--tan); }
/* The score badge on a row. */
.row .score {
  display: inline-flex; align-items: center; justify-content: center; min-width: 38px;
  padding: 2px 7px; border-radius: var(--r-pill); font-weight: 700; font-size: var(--text-xs);
  font-variant-numeric: tabular-nums; background: var(--surface-sunken); color: var(--ink-soft);
}
.row .score.good { background: var(--ok-tint); color: var(--ok); }
.row .score.mid { background: var(--warn-tint); color: var(--warn); }
.row .score.bad { background: var(--danger-tint); color: var(--danger); }
.row-empty { padding: var(--s-6) var(--s-2); text-align: center; color: var(--ink-faint); border-bottom: 1px solid var(--line); }
@media (max-width: 760px) {
  .row { grid-template-columns: 48px minmax(0, 1fr); grid-template-areas: "t n" "t s" ". a"; row-gap: var(--s-2); }
  .row .thumb { grid-area: t; width: 48px; height: 58px; }
  .row > .who { grid-area: n; }
  .row .st { grid-area: s; }
  .row .act { grid-area: a; text-align: left; }
}

/* ---------- the pager: "1 to 25 of N, page 1 of M" ---------- */
.pager { display: flex; gap: var(--s-3); align-items: center; margin-top: var(--s-4); color: var(--ink-soft); font-size: var(--text-sm); justify-content: flex-start; flex-wrap: wrap; }
.pager .of { font-variant-numeric: tabular-nums; }
.pager .pp { margin-left: auto; display: flex; gap: var(--s-2); align-items: center; }
.pager .pp form { margin: 0; display: flex; gap: 4px; align-items: center; }
.pager .pp select {
  font: inherit; font-size: var(--text-xs); padding: 3px 5px; border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); background: var(--surface); color: var(--ink);
}

/* ---------- store checks, on History now, not the catalogue ---------- */
.checks-block {
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface);
  padding: var(--s-4) var(--s-5); margin-bottom: var(--s-5);
}
.checks-block h2 { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 600; margin: 0 0 var(--s-1); }
.check-row { display: flex; gap: var(--s-4); align-items: center; flex-wrap: wrap; padding: var(--s-3) 0; border-top: 1px solid var(--line); }
.check-row form { margin: 0; }
.check-row .who2 { flex: 1 1 240px; min-width: 0; }
.check-row .who2 b { display: block; font-size: var(--text-base); }
.check-row .who2 span { font-size: var(--text-sm); color: var(--ink-soft); }
.check-row .last { font-size: var(--text-xs); color: var(--ink-faint); font-variant-numeric: tabular-nums; }

/* ---------- history: one line per job ---------- */
table.jobs { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
table.jobs th {
  text-align: left; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--ink-faint); font-weight: 600; padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--line-strong);
}
table.jobs td { padding: var(--s-3); border-bottom: 1px solid var(--line); vertical-align: top; }
table.jobs td.jid { font-family: var(--font-mono); color: var(--ink-faint); }
table.jobs .res { color: var(--ink-soft); }
@media (max-width: 700px) {
  table.jobs thead { display: none; }
  table.jobs tr { display: block; border-bottom: 1px solid var(--line); padding: var(--s-3) 0; }
  table.jobs td { display: block; border: 0; padding: 1px 0; }
}

/* ---------- product header: one identity line, then Studio details ---------- */
.crumb { font-size: var(--text-sm); color: var(--ink-soft); margin-bottom: var(--s-3); }
.crumb a { color: var(--tan); }
.prod-head { display: flex; gap: var(--s-4); align-items: flex-start; flex-wrap: wrap; margin-bottom: var(--s-5); }
.prod-head .thumb { width: 60px; height: 74px; }
.prod-head .who { flex: 1 1 320px; min-width: 0; }
.prod-head h1 { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: 600; line-height: 1.18; margin: 0; }
.prod-head .acts { margin-left: auto; display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap; }
.idline { display: flex; flex-wrap: wrap; gap: 4px var(--s-3); align-items: baseline; margin-top: 6px; font-size: var(--text-sm); color: var(--ink-soft); }
.idline .k { color: var(--ink-faint); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
.idline .v { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-soft); }
.idline .sep { color: var(--line-strong); }
.idline .sd {
  font: inherit; font-size: var(--text-sm); background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--tan); text-decoration: underline; text-underline-offset: 2px; font-weight: 600;
}

/* ---------- the next-action strip: one status, one action ---------- */
.nextbar {
  display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap;
  border: 1px solid var(--tan-tint); background: var(--tan-tint);
  border-radius: var(--r-lg); padding: var(--s-3) var(--s-4); margin-bottom: var(--s-5);
}
:root[data-theme="dark"] .nextbar { border-color: var(--line-strong); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .nextbar { border-color: var(--line-strong); }
}
.nextbar .t { font-family: var(--font-display); font-size: var(--text-md); font-weight: 600; }
.nextbar .s { color: var(--ink-soft); font-size: var(--text-sm); }
.nextbar .go { margin-left: auto; display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap; }
.nextbar .go form { margin: 0; }

/* ---------- the four step rail, across the top ---------- */
.rail { display: flex; gap: 0; border-bottom: 1px solid var(--line); margin-bottom: var(--s-5); overflow-x: auto; }
.rail a {
  font: inherit; background: none; border: 0; cursor: pointer; text-align: left; text-decoration: none;
  padding: var(--s-3) var(--s-4) var(--s-3) 0; margin-right: var(--s-5);
  border-bottom: 2px solid transparent; color: var(--ink-soft); white-space: nowrap;
  display: flex; gap: var(--s-3); align-items: baseline;
}
.rail a:last-child { margin-right: 0; }
.rail .num {
  font-family: var(--font-mono); font-size: 11px; color: var(--ink-faint);
  border: 1px solid var(--line-strong); border-radius: 50%; width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; align-self: center;
}
.rail .lbl { font-weight: 600; font-size: var(--text-base); display: block; }
.rail .sub { font-size: var(--text-xs); color: var(--ink-faint); display: block; font-weight: 400; }
.rail a[data-done="yes"] .num { border-color: var(--ok); color: var(--ok); }
.rail a[aria-current="step"] { color: var(--ink); border-bottom-color: var(--tan); }
.rail a[aria-current="step"] .num { border-color: var(--tan); background: var(--tan); color: #fff; }
:root[data-theme="dark"] .rail a[aria-current="step"] .num { color: #1A1209; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .rail a[aria-current="step"] .num { color: #1A1209; }
}

/* ---------- a step head, with its one Details trigger ---------- */
.step-head { display: flex; align-items: flex-end; gap: var(--s-4); flex-wrap: wrap; margin-bottom: var(--s-4); }
.step-head .grow { flex: 1 1 200px; min-width: 0; }
.step-head h2 { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 600; margin: 0; }
.step-head .note { color: var(--ink-soft); font-size: var(--text-sm); margin: 4px 0 0; }
.details-btn {
  font: inherit; font-size: var(--text-sm); background: none; border: 1px solid var(--line-strong);
  color: var(--ink-soft); border-radius: var(--r-md); padding: 6px 12px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
}
.details-btn:hover { background: var(--surface-sunken); color: var(--ink); }
.details-btn::after {
  content: ""; width: 6px; height: 6px; border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); margin-left: 1px;
}

/* ---------- the Details drawer and the side panel ----------
   One scrim, one open at a time, Escape closes, focus goes back to whatever
   opened it. public/drawer.js does the wiring. */
.scrim { position: fixed; inset: 0; background: var(--scrim); z-index: 40; border: 0; padding: 0; cursor: pointer; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(520px, 100%); z-index: 41;
  background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--shadow-raise);
  display: flex; flex-direction: column;
}
.drawer.wide { width: min(760px, 100%); }
.drawer .dhead {
  display: flex; align-items: center; gap: var(--s-3); padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--line); padding-top: calc(var(--s-4) + env(safe-area-inset-top, 0px));
}
.drawer .dhead h2 { flex: 1 1 auto; font-family: var(--font-display); font-size: var(--text-lg); font-weight: 600; margin: 0; }
.drawer .dbody {
  overflow-y: auto; padding: var(--s-4) var(--s-5) var(--s-6);
  padding-bottom: calc(var(--s-6) + env(safe-area-inset-bottom, 0px));
}
.drawer .dbody > details { border-bottom: 1px solid var(--line); }
.drawer .dbody > details > summary {
  cursor: pointer; padding: var(--s-3) 0; font-weight: 600; font-size: var(--text-sm);
  display: flex; align-items: baseline; gap: var(--s-3); list-style: none;
}
.drawer .dbody > details > summary::-webkit-details-marker { display: none; }
.drawer .dbody > details > summary::marker { content: ""; }
.drawer .dbody > details > summary::before {
  content: ""; width: 6px; height: 6px; flex: 0 0 auto; align-self: center;
  border-right: 1.5px solid var(--ink-faint); border-bottom: 1.5px solid var(--ink-faint);
  transform: rotate(-45deg); transition: transform .12s;
}
.drawer .dbody > details[open] > summary::before { transform: rotate(45deg); }
.drawer .dbody > details > summary .s { font-weight: 400; color: var(--ink-faint); font-size: var(--text-xs); }
.drawer .dbody > details > .inner { padding: 0 0 var(--s-4) calc(6px + var(--s-3)); font-size: var(--text-sm); color: var(--ink-soft); }
.drawer .dbody > details > .inner p:last-child { margin-bottom: 0; }
.drawer .group {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.09em; color: var(--ink-faint);
  font-weight: 600; margin: var(--s-5) 0 var(--s-2);
}
.drawer .group:first-child { margin-top: 0; }
.drawer p { margin: 0 0 var(--s-3); }
/* The drawer's own key and value list. Named dkv, not kv: the old step bodies
   already own .kv with a 190px first column. */
.dkv { display: grid; grid-template-columns: auto 1fr; gap: 4px var(--s-3); margin: 0; }
.dkv dt { color: var(--ink-faint); }
.dkv dd { margin: 0; overflow-wrap: anywhere; }
.checks { list-style: none; padding: 0; margin: 0; }
.checks li { display: flex; gap: var(--s-2); padding: 3px 0; align-items: baseline; }
.checks .m { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-faint); margin-left: auto; }
/* One labelled control in a drawer or a side panel. */
.fl { display: block; margin-bottom: var(--s-3); }
.fl > span { display: block; font-size: var(--text-xs); font-weight: 600; color: var(--ink-soft); margin-bottom: 4px; }
.fl input, .fl textarea, .fl select {
  font: inherit; width: 100%; padding: 8px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
}
.prow { display: flex; gap: var(--s-3); align-items: flex-start; flex-wrap: wrap; margin-bottom: var(--s-3); }
.prow .grow { flex: 1 1 200px; min-width: 0; }
.prow form { margin: 0; }
.panel-note { font-size: var(--text-sm); color: var(--ink-soft); margin: 0 0 var(--s-3); }

/* ---------- toast ---------- */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--s-5) + env(safe-area-inset-bottom, 0px)); z-index: 60;
  background: var(--ink); color: var(--paper); padding: 10px 18px; border-radius: var(--r-pill);
  font-size: var(--text-sm); font-weight: 500; box-shadow: var(--shadow-raise); max-width: calc(100vw - 32px);
}

/* ==========================================================================
   What the old markup still needs. Lanes 2 to 4 replace the four step bodies;
   until they do, these pages render as they always did.
   ========================================================================== */

/* ---------- status pills ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--text-xs); font-weight: 600;
  border-radius: var(--r-pill); padding: 2px 10px; white-space: nowrap;
}
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill-new       { background: var(--surface-sunken); color: var(--ink-soft); }
.pill-photos    { background: var(--info-tint);   color: var(--info); }
.pill-copy      { background: var(--tan-tint);    color: var(--tan-deep); }
.pill-review    { background: var(--warn-tint);   color: var(--warn); }
.pill-approved  { background: var(--ok-tint);     color: var(--ok); }
.pill-live      { background: var(--ok);          color: #fff; }
.pill-blocked   { background: var(--danger-tint); color: var(--danger); }
.pill-neutral   { background: var(--surface-sunken); color: var(--ink-soft); }
:root[data-theme="dark"] .pill-live { color: #0E1A12; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pill-live { color: #0E1A12; }
}

/* Screen-reader-only utility. `position: fixed` rather than absolute (lane 5):
   absolute made it position against the page itself inside a scroller that is
   not a containing block, so the hidden label on the Batches table's action
   column sat 727px across and pushed the whole page sideways at 400 px. Fixed
   takes it out of flow and out of every scroller's measurement, which is what
   "hidden" has to mean. inset:0 keeps it in the corner it is clipped to. */
.visually-hidden {
  position: fixed; inset: 0 auto auto 0; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- fold: the one collapsible, used inside the step bodies ----------
   design/UX_SIMPLIFICATION.md. Native <details>, so it is keyboard
   accessible and works with JavaScript off. Closed by default; the open
   state is remembered per browser by public/fold.js, keyed by page and
   section. Nothing is ever removed by a fold, only folded away. */
.fold {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  margin: var(--s-3) 0;
}
.fold > summary {
  display: flex; align-items: baseline; gap: var(--s-2);
  list-style: none; cursor: pointer;
  padding: var(--s-2) var(--s-3);
  font-size: var(--text-sm); font-weight: 600; color: var(--ink);
  border-radius: var(--r-md);
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::marker { content: ""; }
/* The chevron: points right when closed, down when open. */
.fold > summary::before {
  content: ""; flex: none;
  width: 6px; height: 6px; margin: 0 2px 0 1px;
  border-right: 2px solid var(--ink-faint);
  border-bottom: 2px solid var(--ink-faint);
  transform: rotate(-45deg);
  transition: transform .12s ease;
}
.fold[open] > summary::before { transform: rotate(45deg) translate(-1px, -1px); }
.fold > summary:hover { background: var(--surface-sunken); }
.fold > summary:hover::before { border-color: var(--tan); }
.fold[open] > summary { border-bottom: 1px solid var(--line); border-radius: var(--r-md) var(--r-md) 0 0; }
.fold-sum { font-weight: 400; font-size: var(--text-xs); color: var(--ink-soft); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fold-n { font-weight: 400; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.fold-body { padding: var(--s-3); }
.fold-body > *:first-child { margin-top: 0; }
.fold-body > *:last-child { margin-bottom: 0; }
/* Inside a card or a table cell: no frame, just the line and the chevron. */
.fold-inline { border: 0; background: none; margin: 0; }
.fold-inline > summary { padding: var(--s-2) 0; font-size: var(--text-xs); color: var(--tan-deep); }
.fold-inline > summary:hover { background: none; text-decoration: underline; }
.fold-inline[open] > summary { border-bottom: 0; }
.fold-inline > .fold-body { padding: 0 0 var(--s-2); }

/* ---------- a rendered product description ----------
   Descriptions are stored as HTML and are shown the way a shopper reads them,
   on the Review step's before and after and the Copy step. The service
   src/services/description-html.js sanitises first, so only these tags ever
   land here. Body type, with lists given room to breathe. */
.desc { font-size: var(--text-base); line-height: 1.55; color: inherit; }
.desc > *:first-child { margin-top: 0; }
.desc > *:last-child { margin-bottom: 0; }
.desc p { margin: 0 0 var(--s-3); }
.desc ul, .desc ol { margin: 0 0 var(--s-3); padding-left: var(--s-5); }
.desc li { margin: 0 0 var(--s-1); }
.desc li:last-child { margin-bottom: 0; }
.desc h2, .desc h3 {
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--text-base); margin: var(--s-4) 0 var(--s-2);
}
.desc strong { font-weight: 600; }
/* The same description as stored, behind the Show source fold. */
.desc-src {
  margin: 0; white-space: pre-wrap; overflow-wrap: anywhere;
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-soft);
  background: var(--surface-sunken); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3); max-height: 260px; overflow: auto;
}
/* Word-by-word comparison of the live and proposed descriptions. */
.wdiff { margin: 0; line-height: 1.7; font-size: var(--text-base); overflow-wrap: anywhere; }
.wdiff del { background: var(--danger-tint); color: var(--danger); border-radius: var(--r-sm); padding: 0 3px; }
.wdiff ins { background: var(--ok-tint); color: var(--ok); text-decoration: none; border-radius: var(--r-sm); padding: 0 3px; }
.wdiff-note { margin: 0 0 var(--s-2); font-size: var(--text-xs); color: var(--ink-soft); }

/* The reason read back on a rejected card. Rejecting asks for the reason in a
   box of its own on both surfaces now (lane 5), so the one-line inline form
   this section used to style has gone with the markup that drew it. */
.reject-why { padding: 0 var(--s-3) var(--s-2); font-size: var(--text-xs); font-style: italic; color: var(--ink-faint); overflow-wrap: anywhere; }
.aicard-rejected { opacity: 0.78; }

/* ===========================================================================
   LANE 2: the Copy step and the Review step
   (design/redesign/studio-redesign.html, the #step-copy and #step-review
   sections; design/REDESIGN_PROPOSAL_30_SEP.md section 4)
   ---------------------------------------------------------------------------
   The dummy calls a copy row ".field" and a review row ".diff". Both names are
   already taken in this app: the Amazon step's search pack and the gallery notes
   use ".field" and the word-by-word diff uses ".diff"-ish classes of its own, and
   the page CSS loads after this file. So, as lane 1 did with .tag to .ftag, the
   copy row is ".crow" and the review row is ".drow". Nothing else is renamed.
   =========================================================================== */

/* --- the gate verdict band, at the top of both steps --------------------- */
.gateband {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  border-left: 3px solid var(--ok); background: var(--ok-tint); color: var(--ok);
  padding: var(--s-3) var(--s-4); border-radius: 0 var(--r-md) var(--r-md) 0;
  margin-bottom: var(--s-5); font-weight: 600; font-size: var(--text-sm);
}
.gateband.warn { border-left-color: var(--warn); background: var(--warn-tint); color: var(--warn); }
.gateband.bad { border-left-color: var(--danger); background: var(--danger-tint); color: var(--danger); }
.gateband .grow { flex: 1 1 200px; min-width: 0; }
.gateband .details-btn { color: inherit; border-color: currentColor; }

/* --- one copy row: the value, with Edit and Rewrite on hover or focus ---- */
.crow { position: relative; border-bottom: 1px solid var(--line); padding: var(--s-4) 0; }
.crow:first-of-type { border-top: 1px solid var(--line); }
.crow-head { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; margin-bottom: var(--s-2); }
.crow-head .eyebrow { flex: 0 1 auto; }
.crow .ccount { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-faint); }
.crow .ccount.over { color: var(--warn); font-weight: 600; }
.crow .val { font-size: var(--text-base); overflow-wrap: anywhere; }
.crow .val .desc h2, .crow .val .desc h3 { font-family: var(--font-display); font-size: var(--text-md); font-weight: 600; }
.crow .val .empty-val { color: var(--ink-faint); font-style: italic; }
.crow .val .tagset { display: flex; flex-wrap: wrap; gap: 6px; }
.crow-note { font-size: var(--text-xs); color: var(--ink-soft); margin: var(--s-2) 0 0; }
.same-note {
  font-size: var(--text-xs); color: var(--ink-faint); margin: var(--s-4) 0 0;
  border-left: 2px solid var(--line-strong); padding-left: var(--s-3);
}

/* Edit and Rewrite. Each is a <details>, so the row opens with no JavaScript and
   takes the keyboard; opening one gives it the whole line under the head. The
   summary is quiet until the row is hovered or something in it has the focus,
   which is what the proposal asks for, always on at phone widths and on a
   touch screen, where there is no hover to reveal it with. */
.rowact { min-width: 0; }
.crow-head > .rowact:first-of-type, .dh > .rowact:first-of-type { margin-left: auto; }
.rowact > summary {
  list-style: none; cursor: pointer; opacity: 0; transition: opacity .12s;
  font: inherit; font-size: var(--text-xs); font-weight: 500; color: var(--ink-soft);
  border: 1px solid transparent; border-radius: var(--r-md); padding: 4px 10px; white-space: nowrap;
}
.rowact > summary::-webkit-details-marker { display: none; }
.rowact > summary::marker { content: ""; }
.rowact > summary:hover { background: var(--surface-sunken); color: var(--ink); }
.rowact > summary:focus-visible { opacity: 1; outline: 2px solid var(--tan); outline-offset: 2px; }
.crow:hover .rowact > summary,
.crow:focus-within .rowact > summary,
.drow:hover .rowact > summary,
.drow:focus-within .rowact > summary,
.rowact[open] > summary { opacity: 1; }
.rowact[open] > summary { background: var(--surface-sunken); color: var(--ink); }
.rowact[open] { width: 100%; margin-left: 0; order: 9; }
@media (hover: none) { .rowact > summary { opacity: 1; } }
@media (max-width: 560px) { .rowact > summary { opacity: 1; } }

/* the editor in place: Save, Cancel and nothing else */
.ebox { margin-top: var(--s-3); padding: var(--s-3); background: var(--surface-sunken); border-radius: var(--r-md); }
.ebox form + form { margin-top: var(--s-3); padding-top: var(--s-3); border-top: 1px solid var(--line); }
.ebox label { display: block; font-size: var(--text-xs); font-weight: 600; color: var(--ink-soft); margin-bottom: 4px; }
.ebox input, .ebox textarea, .ebox select {
  font: inherit; width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); resize: vertical;
}
.ebox .actions { display: flex; gap: var(--s-2); margin-top: var(--s-2); flex-wrap: wrap; align-items: center; }
.ebox .hint { font-size: var(--text-xs); color: var(--ink-soft); margin: 0; flex: 1 1 200px; }
.ebox .ticklist { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 2px var(--s-3); max-height: 240px; overflow-y: auto; }
.ebox .ticklist label { display: flex; align-items: center; gap: 6px; font-size: var(--text-sm); font-weight: 400; color: var(--ink); margin: 0; }
.ebox .ticklist input { width: auto; }

/* the rewrite box: one feedback field, the standing-note tick, one button */
.fbox {
  margin-top: var(--s-3); padding: var(--s-3); border: 1px solid var(--tan);
  border-radius: var(--r-md); background: var(--tan-tint);
}
:root[data-theme="dark"] .fbox { background: var(--surface-sunken); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .fbox { background: var(--surface-sunken); } }
.fbox label.lb { display: block; font-size: var(--text-xs); font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.fbox textarea, .fbox select {
  font: inherit; width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); resize: vertical;
}
.fbox .tick { display: flex; gap: 7px; align-items: flex-start; margin: var(--s-2) 0; font-size: var(--text-sm); cursor: pointer; }
.fbox .tick input { margin-top: 3px; flex: 0 0 auto; width: auto; }
.fbox .tick span small { display: block; color: var(--ink-soft); font-size: var(--text-xs); }
.fbox .actions { display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: center; }
.fbox .hint { font-size: var(--text-xs); color: var(--ink-soft); margin: 0; flex: 1 1 200px; }
/* what a refused empty note says: it names the button it is about */
.fbox-msg { margin: 0 0 var(--s-2); font-size: var(--text-xs); font-weight: 600; color: var(--danger); }
.fbox-msg:empty { display: none; }

.toolrow { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-top: var(--s-5); align-items: center; }
.toolrow form { margin: 0; }
.subhead {
  display: flex; align-items: baseline; gap: var(--s-3); flex-wrap: wrap;
  margin: var(--s-6) 0 var(--s-3); padding-bottom: var(--s-2); border-bottom: 1px solid var(--line);
}
.subhead h3 { flex: 1 1 auto; font-family: var(--font-display); font-size: var(--text-lg); font-weight: 600; margin: 0; }

/* --- one review row: live beside proposed, with its Write this tick ------ */
.drow { border: 1px solid var(--line); border-radius: var(--r-md); margin-bottom: var(--s-3); overflow: hidden; background: var(--surface); }
.drow.changed { border-left: 3px solid var(--tan); }
.drow.todo { border-left: 3px solid var(--danger); }
.drow .dh {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  padding: var(--s-3) var(--s-4); background: var(--surface-sunken); border-bottom: 1px solid var(--line);
}
.drow .dh .nm { font-weight: 600; }
.drow .dh .pick { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 600; color: var(--ink-soft); cursor: pointer; white-space: nowrap; }
.drow .dh .pick input { accent-color: var(--tan); }
/* THE DASHBOARD'S SEO LOCK (D40). A row the dashboard owns is unticked,
   disabled and says so where the tick would have been. */
.pick-locked { cursor: not-allowed; opacity: .75; }
.pick-locked input { cursor: not-allowed; }
.pick-locked .lock-note { font-weight: 700; color: var(--ink-soft); }
/* The one line under the Copy step's gate band when the dashboard owns the SEO. */
.gateband-sub { margin: calc(var(--s-2) * -1) 0 var(--s-4); font-size: var(--text-sm); color: var(--ink-soft); }
.drow .rowact[open] > summary { background: var(--surface); }
.drow .rowact[open] .ebox, .drow .rowact[open] .fbox { margin-bottom: var(--s-3); }
.dcols { display: grid; grid-template-columns: 1fr 1fr; }
.dcols > div { padding: var(--s-4); min-width: 0; overflow-wrap: anywhere; }
.dcols > div:first-child { border-right: 1px solid var(--line); color: var(--ink-soft); background: var(--paper); }
.dcols .dcol-h { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .09em; color: var(--ink-faint); margin-bottom: var(--s-2); font-weight: 600; }
.dcols .empty-val { color: var(--ink-faint); font-style: italic; }
.dcols .altthumb { display: block; width: 56px; height: 70px; object-fit: cover; border: 1px solid var(--line); border-radius: var(--r-sm); margin-bottom: var(--s-2); background: var(--surface-sunken); }
.dextra { border-top: 1px solid var(--line); padding: 0 var(--s-4); }
@media (max-width: 760px) {
  .dcols { grid-template-columns: 1fr; }
  .dcols > div:first-child { border-right: 0; border-bottom: 1px solid var(--line); }
}

/* --- one AI shot waiting on a decision, on the Review step -------------- */
.attachrow {
  display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap;
  border: 1px solid var(--line); border-left: 3px solid var(--info); border-radius: var(--r-md);
  background: var(--surface); padding: var(--s-3); margin-bottom: var(--s-3);
}
.attachrow .pic2 { width: 56px; height: 70px; flex: 0 0 auto; border-radius: var(--r-sm); overflow: hidden; background: var(--surface-sunken); }
.attachrow .pic2 img { width: 100%; height: 100%; object-fit: cover; display: block; }
.attachrow .grow { flex: 1 1 220px; min-width: 0; }
.attachrow .grow b { display: block; }
.attachrow .grow span { font-size: var(--text-sm); color: var(--ink-soft); }
.attachrow .acts2 { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.attachrow .acts2 form { margin: 0; }
.attachrow .pick { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 600; color: var(--ink-soft); cursor: pointer; white-space: nowrap; }
/* The reject reason box takes the whole row under the actions, as it does on a
   shot card on the Photos step (lane 5: one way of asking, both places). */
.attachrow > .fbox { flex: 1 1 100%; margin: var(--s-2) 0 0; }

/* --- the sticky approve bar --------------------------------------------- */
.approvebar {
  position: sticky; bottom: 0; z-index: 15; background: var(--surface);
  border-top: 1px solid var(--line); box-shadow: var(--shadow-bar, 0 -4px 16px rgba(0,0,0,.08));
  padding: var(--s-3) var(--s-5); padding-bottom: calc(var(--s-3) + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap; margin-top: var(--s-5);
}
.approvebar .txt { flex: 1 1 220px; font-size: var(--text-sm); color: var(--ink-soft); }
.approvebar .txt b { color: var(--ink); }
.approvebar form { margin: 0; }
/* Send back and the approve confirm both open ABOVE the bar, never over it. */
.barbox { max-width: 640px; margin-top: var(--s-5); }
.barbox[hidden] { display: none !important; }

/* ===========================================================================
   LANE 3: the Photos step
   (design/redesign/studio-redesign.html, the #step-photos section;
   design/REDESIGN_PROPOSAL_30_SEP.md section 4, "Photos step")
   ---------------------------------------------------------------------------
   Two bands of the same card: "On the store" and "AI model shots". The dummy
   calls the card ".shot" and that name was free in this app, so it is used as
   it is. A store card and an AI card are the same frame on purpose: the only
   difference you should see is what the card says and what it offers.
   =========================================================================== */

.shots { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--s-4); margin-top: var(--s-3); }
.shot {
  border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden;
  background: var(--surface); box-shadow: var(--shadow-card); display: flex; flex-direction: column; min-width: 0;
}
.shot .pic { display: block; aspect-ratio: 3 / 4; background: var(--surface-sunken); }
.shot .pic img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* A store photo is a packshot on white and must not be cropped: the whole
   product has to be visible, which is the point of looking at it here. */
.shot:not(.aishot) .pic img { object-fit: contain; background: #fff; }
.shot .body { padding: var(--s-3); font-size: var(--text-xs); color: var(--ink-soft); display: flex; flex-direction: column; gap: 6px; overflow-wrap: anywhere; }
.shot .body p { margin: 0; }
.shot .state { display: flex; align-items: center; gap: 6px; font-weight: 600; color: var(--ink); }
.shot .badges { display: flex; flex-wrap: wrap; gap: 4px; }
.shot .b {
  font-size: 10px; font-weight: 700; border-radius: var(--r-pill); padding: 1px 7px;
  background: var(--surface-sunken); border: 1px solid var(--line); color: var(--ink-soft);
}
.shot .b.ok { background: var(--ok-tint); border-color: var(--ok); color: var(--ok); }
.shot .b.warn { background: var(--warn-tint); border-color: var(--warn); color: var(--warn); }
.shot .b.fail { background: var(--danger-tint); border-color: var(--danger); color: var(--danger); }
.shot .b.ai { background: var(--tan-tint); border-color: var(--tan); color: var(--tan-deep); }
/* The one verdict line: the advice badge and the report beside it, never a
   pass or a fail. The headline note sits under it in the person's own words. */
.shot .verdict { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.shot .shot-advice { color: var(--ink-soft); }
.shot .shot-state { color: var(--ink); }
.shot .row2 { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.shot .row2 form { margin: 0; }
.shot .reject-why { color: var(--danger); }
/* A rejected card is still readable, just plainly out of play. */
.shot-rejected { opacity: .72; }
.shot-rejected .pic img { filter: grayscale(1); }
/* The reason and the feedback boxes open inside the card, so they take its
   width rather than the lane 2 box width. */
.shot .fbox { max-width: none; margin-top: 2px; }
.shot .fbox textarea { font-size: var(--text-xs); }

/* The one line under each band head: what the band is and where it stands. */
.band-note { font-size: var(--text-sm); color: var(--ink-soft); margin: 0 0 var(--s-2); }
.band-empty {
  font-size: var(--text-sm); color: var(--ink-soft); margin: var(--s-3) 0 0;
  border: 1px dashed var(--line-strong); border-radius: var(--r-md); padding: var(--s-4); background: var(--paper);
}
.cost-line { font-size: var(--text-sm); color: var(--ink-soft); margin: 0 0 var(--s-3); }

/* The advisory report, inside its side panel. Advice, never a verdict, so the
   notes read as a list of observations and nothing is coloured as a failure
   except a defect the checks call unarguable. */
.qa-notes { display: flex; flex-direction: column; gap: 5px; }
.qa-note { display: flex; align-items: baseline; gap: 7px; font-size: var(--text-sm); }
.qa-reject { color: var(--danger); font-weight: 600; margin: 0 0 var(--s-3); }
.dot.fail { background: var(--danger); }
.empty-val { color: var(--ink-faint); font-style: italic; }
ul.plain { margin: 0; padding-left: 1.1em; }
ul.plain li { margin-bottom: 4px; }

@media (max-width: 520px) {
  .shots { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

/* ===========================================================================
   LANE 4: the Amazon step. The category recipe line, the module cards, the
   gallery slot strip and what a side panel holds. The call-out editor keeps
   its own CSS in the page (the .co-* rules), so the loupe, the stage and the
   markers are exactly what they were before they moved into a panel.
   =========================================================================== */

/* The category recipe line: the resolved recipe, where it came from and the
   Change menu, above the A+ pack because the recipe decides what builds. */
.recipe {
  display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface);
  padding: var(--s-2) var(--s-3); margin: var(--s-4) 0; font-size: var(--text-sm);
}
.recipe .lb { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-faint); font-weight: 600; }
.recipe b { font-weight: 600; }
.recipe .why { color: var(--ink-soft); flex: 1 1 200px; min-width: 0; }
.menu .mi small { display: block; font-weight: 400; color: var(--ink-soft); font-size: var(--text-xs); margin-top: 2px; }

/* ONE CARD, the same frame for an A+ module and a gallery slot: the picture, a
   status dot, the name and the state in words. The whole card is the button. */
.mods { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--s-3); margin-top: var(--s-3); }
.slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: var(--s-3); margin-top: var(--s-3); }
.mod, .slot {
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface);
  overflow: hidden; cursor: pointer; text-align: left; font: inherit; color: inherit;
  padding: 0; display: block; width: 100%;
}
.mod:hover, .slot:hover { border-color: var(--line-strong); }
.mod:focus-visible, .slot:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.mod .pic { aspect-ratio: 1464 / 600; background: var(--surface-sunken); display: flex; align-items: center; justify-content: center; }
.slot .pic { aspect-ratio: 1 / 1; background: var(--surface-sunken); display: flex; align-items: center; justify-content: center; }
.mod .pic img, .slot .pic img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mod.noimg .pic img, .slot.noimg .pic img { display: none; }
/* A card with no picture says in its own frame WHY there is none: a text module
   that never has one, or an image nobody has made yet. A numbered gallery slot
   keeps the serif number it is known by. */
.slot.noimg .pic::after { content: attr(data-n); font-family: var(--font-display); font-size: 22px; color: var(--ink-faint); }
.mod.noimg .pic::after, .slot-waiting.noimg .pic::after {
  content: attr(data-n); font: inherit; font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-faint); text-align: center; padding: 0 7px; line-height: 1.4;
}
.mod .cap, .slot .cap {
  display: flex; align-items: center; gap: 7px; padding: 7px 9px;
  font-size: var(--text-sm); font-weight: 500;
}
.slot .cap { font-size: var(--text-xs); color: var(--ink-soft); }
.mod .cap .nm, .slot .cap .nm { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mod .st, .slot .st { display: block; padding: 0 9px 8px; font-size: var(--text-xs); color: var(--ink-faint); }
/* A card with no automated report is honest and quiet: the strip's loudest thing
   should be a finding, not the absence of one (lane 5). The count and the reason
   are one sentence above the strip and the full note is in the card's panel. */
.mod .st.st-quiet, .slot .st.st-quiet { font-style: italic; opacity: .72; }
.band-note-quiet { color: var(--ink-faint); }
.mod-add .pic { background: var(--paper); border-bottom: 1px dashed var(--line-strong); }
.mod-add .plus { font-family: var(--font-display); font-size: 28px; color: var(--ink-faint); line-height: 1; }
.slot-waiting .pic { background: var(--paper); }

/* WHAT A SIDE PANEL HOLDS. A group heading, a preview of the image the editor
   makes, the plain field rows and the row of buttons under them. */
.pgroup {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .09em;
  color: var(--ink-faint); font-weight: 600; margin: var(--s-5) 0 var(--s-2);
}
.pgroup:first-child { margin-top: 0; }
.preview {
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface-sunken);
  overflow: hidden; margin-bottom: var(--s-3); display: block;
}
.preview img { display: block; width: 100%; height: auto; }
.preview.flat { aspect-ratio: 1464 / 600; }
.preview.flat img { height: 100%; object-fit: cover; }
.co-editor > .panel-note:first-child { margin-top: 0; }
.pdrows { width: 100%; border-collapse: collapse; font-size: var(--text-sm); margin-bottom: var(--s-3); }
.pdrows th { text-align: left; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-faint); padding: 0 var(--s-2) 4px 0; }
.pdrows td { padding: 3px var(--s-2) 3px 0; border-top: 1px solid var(--line); vertical-align: middle; }
.pdrows td:first-child { width: 40%; color: var(--ink-soft); }
.pdrows input { font: inherit; font-size: var(--text-sm); width: 100%; padding: 5px 7px; border: 1px solid var(--line-strong); border-radius: var(--r-sm); background: var(--surface); color: var(--ink); }
.pdadd { margin-bottom: var(--s-3); }
.pdadd > summary { cursor: pointer; font-size: var(--text-sm); font-weight: 600; padding: var(--s-2) 0; }

@media (max-width: 520px) {
  .mods { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .slots { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
  .recipe { align-items: flex-start; }
}
