/* public/app.css -- the whole theme (§7): dark like Stream, no framework.
 * The CSD brand kit is applied here (ruling U-12): Montserrat is the shop's
 * face, the accent is the shop's monochrome logic inverted for a dark shell,
 * and the one red is the shop's promo red. See Brandkit/design-system/MASTER.md. */

@font-face {
  font-family: Montserrat;
  font-style: normal;
  font-weight: 100 900;          /* one variable file covers every weight */
  font-display: swap;
  src: url('/public/fonts/montserrat-latin-var.woff2') format('woff2');
}

:root {
  --bg: #141416;
  --panel: #1e1e22;
  --panel-2: #26262c;
  --line: #3a3a42;          /* dividers and card edges (decorative) */
  --line-strong: #70707b;   /* the border IS the control: inputs, ghost buttons, dropzone (3:1) */
  --text: #e6e6e6;
  --muted: #9a9aa3;
  --accent: #ffffff;        /* the shop is black on white; a dark shell inverts it */
  --accent-ink: #141416;    /* text and icons ON an accent fill */
  --accent-soft: #9a9aa3;   /* accent at rest, where a white fill would shout */
  --danger: #ff6b6b;
  --danger-bg: #d14343;     /* the shop's promo-bar red; white on it is 4.57:1 */
  --ok: #6fcf87;
  --warn: #e0b341;
  --radius: 8px;
  --gap: 16px;
  color-scheme: dark;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.5 Montserrat, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

/* A white accent is the body text colour, so a bare content link is carried by
 * its underline, not by hue. Anything with a class is a component (button, tab,
 * pill, thumbnail, nav item) and keeps its own treatment. */
a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
a[class] { text-decoration: none; }
a[class]:hover { text-decoration: none; }
a:not([class]):hover { text-decoration-thickness: 2px; }
h1 { font-size: 20px; margin: 0 0 8px; }
h2 { font-size: 16px; margin: 0 0 12px; }
h3 { font-size: 14px; margin: 20px 0 8px; }
.muted { color: var(--muted); }
.spacer { flex: 1; }
kbd {
  display: inline-block;
  padding: 0 5px;
  margin-left: 6px;
  border: 1px solid var(--line);
  border-radius: 4px;
  font: 11px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
  opacity: 0.8;
}
/* Anything hidden stays hidden, whatever display its class asks for. Without
 * this the review's zoom overlay (display: flex) covered the whole screen
 * while `hidden`, and nothing under it could be clicked. */
[hidden] { display: none !important; }
/* Off-screen but not display:none: Safari will not open the file chooser for
 * a display:none <input type=file> clicked from script, Chromium will. */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---------------------------------------------------------------- top bar */

.topbar {
  display: flex;
  /* every label in the bar sits on the lockup's baseline, so the logo, the nav
   * and the sign-out group read as one line rather than three centred blocks */
  align-items: baseline;
  gap: var(--gap);
  /* baseline alignment reserves descender space under the line, so the bottom
   * padding is 3 px lighter: the bar keeps its old 46 px height and the cap
   * band stays optically centred rather than riding high. */
  padding: 12px 20px 9px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}

.brand { display: inline-flex; align-items: baseline; gap: 8px; color: var(--text); font-weight: 600; letter-spacing: 0.2px; }
.brand:hover { text-decoration: none; }
/* The wordmark is the shop's own mark; "Studio" is the sub-brand beside it,
 * lighter and tracked out so the lockup reads CSD first. */
/* The lockup reads as one name, so CSD and Studio share a baseline (Elias,
 * 2026-09-05). The mark's viewBox is trimmed to the ink and the wordmark has no
 * descenders, so the image's bottom edge IS the logo's baseline — which is the
 * edge `align-items: baseline` aligns a replaced element on. An `align-self:
 * center` here is what made Studio float inside the mark instead. */
.brand-mark { display: block; width: 56px; height: auto; }
.brand-word { font-weight: 400; font-size: 13px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.brand:hover .brand-word { color: var(--text); }
.nav { flex: 1; display: flex; align-items: center; gap: 14px; }
.nav a { color: var(--muted); text-decoration: none; }
.nav a.current, .nav a:hover { color: var(--text); text-decoration: none; }
.who { display: flex; align-items: baseline; gap: 12px; }
.email { color: var(--muted); }

.linkish {
  background: none;
  border: 0;
  padding: 0;
  color: var(--accent);
  font: inherit;
  cursor: pointer;
}
.linkish { text-decoration: underline; text-underline-offset: 3px; }
.linkish:hover { text-decoration-thickness: 2px; }
.linkish:disabled { opacity: 0.5; cursor: default; }

.crumbs { margin: 0 0 8px; }
.crumbs a, .crumb { color: var(--muted); }
.crumbs a:hover, .crumb:hover { color: var(--text); text-decoration: none; }

/* ----------------------------------------------------------------- banner */

.banner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 14px;
  background: var(--danger-bg);
  color: #fff;
  padding: 10px 20px;
}
.banner strong { font-weight: 600; }
.banner-detail { font-size: 12px; opacity: 0.9; }
/* a hold set on /settings, on every screen: plain, not red (`.notice` is the settings page's own yellow box) */
.hold-notice { padding: 8px 20px; background: var(--panel-2); color: var(--text); border-bottom: 1px solid var(--line); }

/* ------------------------------------------------------------------- page */

.main { padding: 24px 20px; }
body.wide .main { padding: 12px 16px; }

.centred {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 20px;
}

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
}

.login { width: 320px; max-width: 100%; }

/* ------------------------------------------------------------------ forms */

label { display: block; margin: 16px 0 6px; color: var(--muted); }
label.inline { display: inline-flex; align-items: center; gap: 6px; margin: 0; }

input, textarea, select {
  width: 100%;
  padding: 9px 10px;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  color: var(--text);
  font: inherit;
}
input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
textarea { min-height: 80px; resize: vertical; }
select { width: auto; min-height: 32px; padding: 0 8px; }

button[type='submit'] {
  width: 100%;
  margin-top: 20px;
  padding: 10px;
  background: var(--accent);
  border: 0;
  border-radius: var(--radius);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
button[type='submit']:disabled { opacity: 0.6; cursor: default; }

.error { margin: 16px 0 0; color: var(--danger); }
.ok { margin: 16px 0 0; color: var(--ok); }
.help { margin: 4px 0 var(--gap); }

/* Every control is 36 px tall: .button, .secondary, .mini, the segmented
 * switcher, the filter box and the selects share one height and one font. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 40px;
  padding: 0 16px;
  background: var(--accent);
  border: 0;
  border-radius: var(--radius);
  color: var(--accent-ink);
  font: inherit;
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.button:hover { text-decoration: none; background: var(--text); }
.button:disabled { opacity: 0.5; cursor: default; }
/* white ink on the shop's red (4.57:1); the dark --accent-ink would not carry here */
.button.danger { background: var(--danger-bg); color: #fff; }
.button.danger:hover { background: #bf3a3a; }
.secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 16px;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.secondary:hover { text-decoration: none; }
.mini {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 34px;
  padding: 0 10px;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  white-space: nowrap;
  cursor: pointer;
}
.mini:hover { background: var(--panel-2); text-decoration: none; }
/* the 404 / 500 pages (src/views/error.mjs) */
.oops { max-width: 520px; margin: 60px auto; text-align: center; }
.oops h1 { margin: 4px 0 12px; }
.oops .button { display: inline-flex; margin-top: 16px; }

/* the destructive secondary actions: Delete draft, Delete on a draft block */
.mini.danger, .secondary.danger { color: var(--danger); }
.mini.danger:hover, .secondary.danger:hover { border-color: var(--danger); }
.mini svg { width: 14px; height: 14px; }
.secondary:hover { border-color: var(--muted); }
.secondary:disabled { opacity: 0.6; cursor: default; }

/* F-2 refined (2026-09-06): a link with nothing behind it yet -- the Zip
   control while the archive would hold no pictures. It carries no href, so
   there is nothing to follow; this makes it look as dead as it is, and its
   title says why. */
a.mini[aria-disabled='true'],
a.secondary[aria-disabled='true'] { opacity: 0.45; cursor: default; }
a.mini[aria-disabled='true']:hover,
a.secondary[aria-disabled='true']:hover { background: transparent; border-color: var(--line-strong); }
/* D1: a zip link that has just been clicked. The server is building the archive
 * and the browser shows nothing, so the link looks disabled (the same greying)
 * and says it is working; app.js swallows clicks for ZIP_BUSY_MS. */
a.is-busy { opacity: 0.45; cursor: progress; }
a.is-busy:hover { background: transparent; border-color: var(--line-strong); }

.icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  color: var(--muted);
  font-size: 14px;
}
.icon:hover { background: var(--panel-2); color: var(--text); text-decoration: none; }
.icon svg { display: block; }

.segmented { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--radius); overflow: hidden; }
.segmented button {
  min-height: 34px;
  padding: 0 12px;
  background: var(--panel);
  border: 0;
  border-right: 1px solid var(--line);
  color: var(--muted);
  font: inherit;
  font-size: 15px;
  line-height: 20px;
  cursor: pointer;
}
.segmented button:last-child { border-right: 0; }
.segmented button.current { background: var(--panel-2); color: var(--text); }

.pills { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; align-items: center; }
.pill {
  padding: 2px 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  text-transform: capitalize;
}
.status-review { border-color: var(--accent); color: var(--accent); }
.status-done { border-color: #3a8f4f; color: var(--ok); }
.status-production { border-color: #6b5a20; color: var(--warn); }
/* V-1: an archived order is quiet -- the muted pill, nothing else. */
.status-archived { border-color: var(--line); color: var(--muted); }

.chip { padding: 2px 8px; border-radius: 999px; font-size: 12px; background: var(--line); white-space: nowrap; }
/* A-13: one word per state (pending | approved | rejected | redo | working |
   manual); the pipeline words stay for the review's own chip. */
.chip-done, .chip-pending, .chip-approved { background: #2a4b33; color: var(--ok); }
.chip-running, .chip-retrying, .chip-queued, .chip-working, .chip-redo { background: #3a3320; color: var(--warn); }
.chip-failed, .chip-rejected, .chip-manual { background: #4a2626; color: #ff9b9b; }

.badge {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  font-size: 10px;
  text-align: center;
  background: rgb(0 0 0 / 60%);
  color: var(--text);
  text-transform: capitalize;
}
.badge-approved { color: var(--ok); }
.badge-rejected, .badge-manual { color: #ff9b9b; }
.badge-working, .badge-redo, .badge-queued, .badge-running, .badge-retrying { color: var(--warn); }

.tag {
  margin-left: 8px;
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 400;
  color: var(--muted);
}

/* --------------------------------------------------------- board (§7 item 2) */

.board-head { display: flex; align-items: center; gap: var(--gap); margin-bottom: var(--gap); flex-wrap: wrap; }
.board-head h1 { flex: 1; margin: 0; }

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: var(--gap); overflow-x: auto; }
.tab { padding: 8px 12px; color: var(--muted); border-bottom: 2px solid transparent; white-space: nowrap; }
.tab:hover { text-decoration: none; color: var(--text); }
.tab.current { color: var(--text); border-bottom-color: var(--accent); }
.count { color: var(--muted); }

.toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: var(--gap); }
.toolbar .linkish { min-height: 36px; }
.filter { width: 240px; max-width: 100%; min-height: 36px; padding: 0 10px; }
.toolbar select { min-height: 36px; padding: 0 8px; }

/* U-9: the "Production date" side menu beside the board, Stream's tree. The
 * tree is plain <details>, so it folds without JavaScript; the arrow in its
 * head folds the whole menu to a rail (body.dates-closed, remembered). */
.board-body { display: grid; grid-template-columns: 276px minmax(0, 1fr); gap: 24px; align-items: start; }
.board-main { min-width: 0; }
.dates {
  position: sticky;
  top: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 8px 12px;
  overflow: hidden;
  transition: width 0.15s ease;
}
.dates-head { display: flex; align-items: center; gap: 8px; padding: 2px 4px 8px 8px; margin-bottom: 6px; border-bottom: 1px solid var(--line); }
.dates-title { display: inline-flex; align-items: center; gap: 8px; flex: 1; min-width: 0; font-size: 14px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; }
.dates-title .folder { flex: none; color: var(--muted); }
.dates-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.dates-toggle:hover { color: var(--text); border-color: var(--line); background: var(--panel-2); }
.dates-toggle svg { transform: rotate(180deg); transition: transform 0.15s ease; }
.date-tree, .date-children { list-style: none; margin: 0; padding: 0; }
.date-children { padding-left: 16px; }
.dates details > summary { list-style: none; cursor: pointer; display: flex; align-items: center; }
.dates details > summary::-webkit-details-marker { display: none; }
.dates details > summary::before {
  content: '';
  flex: none;
  width: 6px;
  height: 6px;
  margin: 0 4px 0 6px;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
}
.dates details[open] > summary::before { transform: rotate(45deg); }
.date-node {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 1;
  padding: 7px 8px;
  border-radius: 6px;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.3;
}
.date-node:hover { text-decoration: none; color: var(--text); background: var(--panel-2); }
.date-node.current { color: var(--text); background: var(--panel-2); font-weight: 600; }
/* Stream's marker on the selected folder: a bar of accent at the edge */
.date-node.current::after { content: ''; position: absolute; top: 6px; bottom: 6px; right: -8px; width: 3px; border-radius: 2px 0 0 2px; background: var(--accent); }
.date-node .folder { flex: none; color: var(--muted); }
.date-node.current .folder { color: var(--accent); }
/* closed folder on a folded node, open folder on an unfolded one or a day */
.date-node .folder-open, .dates details[open] > summary .date-node .folder-closed, .date-node.level-day .folder-closed, .date-node.level-all .folder-closed { display: none; }
.dates details[open] > summary .date-node .folder-open, .date-node.level-day .folder-open, .date-node.level-all .folder-open { display: inline; }
.date-node .date-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.date-node .count { margin-left: auto; padding-left: 6px; font-size: 12px; font-weight: 400; color: var(--muted); }
.date-node.level-all { margin: 0 0 4px; }
.date-node.level-day { padding-left: 24px; }
.date-empty { margin: 4px 8px; font-size: 13px; }
/* folded: a rail with the arrow, the tree tucked away */
body.dates-closed .board-body { grid-template-columns: 44px minmax(0, 1fr); }
body.dates-closed .dates { padding: 6px 7px; }
body.dates-closed .dates-head { padding: 0; margin: 0; border-bottom: 0; justify-content: center; }
body.dates-closed .dates-title, body.dates-closed .dates-body { display: none; }
body.dates-closed .dates-toggle svg { transform: none; }
@media (max-width: 900px) {
  .board-body { grid-template-columns: 200px minmax(0, 1fr); gap: 12px; }
  .dates { position: static; }
}

/* minmax(0, 1fr), not 1fr: a grid track never shrinks below its content's
 * min width, and a strip of previews is as wide as every preview -- on a phone
 * the whole page would scroll sideways. */
.orders { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.empty { padding: 14px; }
.disk { margin-top: var(--gap); }

.order {
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
}
.order-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* U-8: the chevron that unfolds a row's strip -- only the list view folds
 * strips, so only the list view shows it */
.order .toggle { display: none; }
/* min-width 0 + overflow-wrap so a name with no spaces wraps inside its block
 * instead of widening the whole board (one did, to 1.1 million px). */
.order-name { font-weight: 600; color: var(--text); font-size: 15px; min-width: 0; overflow-wrap: anywhere; }
.order-actions { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-left: 4px; }
/* counts + cost are grouped so the card view can give them a line of their
 * own; in the row views the group is transparent to the head's flex layout */
.order-stats { display: contents; }
.order .created { margin-left: auto; }
.order p { margin: 6px 0 0; }
.empty-strip { margin: 10px 0 0; }

/* the preview strip: Stream's row of frames under each order */
.previews {
  list-style: none;
  min-width: 0;
  display: flex;
  gap: 8px;
  margin: 12px 0 0;
  padding: 0 0 6px;
  overflow-x: auto;
  scrollbar-width: thin;
}
.preview { flex: 0 0 auto; width: 132px; }
.preview a { display: block; position: relative; color: var(--muted); }
.preview a:hover { text-decoration: none; color: var(--text); }
.preview img {
  display: block;
  width: 132px;
  height: 132px;
  object-fit: contain;
  background: #e8e8e8;
  border-radius: 6px;
}
/* 17px from 116px: one pixel past the 132px image, over the dark gap before
 * the name. With no height the badge was its 10px line of text, ~15px, and a
 * hairline of the tile's #e8e8e8 showed under it (Elias, 03:27) -- the same
 * fix as .strip-button .badge. */
.preview .badge { top: 116px; bottom: auto; height: 17px; line-height: 16px; border-radius: 0 0 6px 6px; }
/* the "+N more" tile that ends a capped strip */
.preview.more a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 132px;
  height: 132px;
  border: 1px dashed var(--line);
  border-radius: 6px;
  color: var(--muted);
  font-weight: 600;
}
.preview.more a:hover { border-color: var(--muted); color: var(--text); }
/* the whole tile is the link: no underline on the caption inside it */
.preview a { text-decoration: none; }
.preview-name {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.show-all .previews { flex-wrap: wrap; overflow: visible; }

/* the card view: the compact grid, previews as a mosaic of four */
.view-cards { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.view-cards .order-head { display: block; }
.view-cards .order-name { display: block; margin-bottom: 6px; }
.view-cards .order-stats { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.view-cards .counts { white-space: nowrap; }
.view-cards .cost::before { content: '\B7'; margin-right: 8px; }
.view-cards .order-actions, .view-cards .created { display: inline-flex; margin: 6px 6px 0 0; }
/* a done order carries five controls (Details, Review, Zip, Archive/Unarchive,
 * delete) and the card can be 260 px: the row must wrap inside the card, never
 * run past its edge. */
.view-cards .order-actions { display: flex; max-width: 100%; }
.view-cards .previews { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; overflow: hidden; }
.view-cards .preview { width: auto; }
.view-cards .preview:nth-child(n + 5) { display: none; }
.view-cards .preview img { width: 100%; height: 56px; }
.view-cards .preview-name, .view-cards .preview .badge { display: none; }

/* the list view: one line per order, the strip folded under it (U-8) */
.view-list .order { padding: 8px 14px; }
.view-list .previews, .view-list .empty-strip { display: none; }
.view-list .order .toggle { display: inline-flex; }
.view-list .order-head { cursor: pointer; }
.view-list .order.open .previews,
.view-list.show-all .previews { display: flex; }
.view-list .order.open .empty-strip,
.view-list.show-all .empty-strip { display: block; }
/* Show all images unfolds every row: the chevrons have nothing left to do */
.view-list.show-all .toggle { visibility: hidden; }
.toggle svg { transition: transform 0.15s ease; }
.order.open .toggle svg { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .toggle svg { transition: none; }
}

/* ---------------------------------------------------- new order (§7 item 3) */

.check input { width: auto; }
.check { display: inline-flex; align-items: center; gap: 6px; margin: 12px 0 0; }

.dropzone {
  padding: 32px;
  border: 2px dashed var(--line-strong);
  border-radius: var(--radius);
  text-align: center;
  cursor: pointer;
}
.dropzone.over { border-color: var(--accent); }
.dropzone:focus-visible { border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: 2px; }
.dropzone p { margin: 0 0 4px; }

.uploads, .check-frames, .frames { list-style: none; margin: 12px 0; padding: 0; }
.upload, .check-frames li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
  border-bottom: 1px solid var(--line);
}
.upload-name, .frame-name { flex: 1; overflow-wrap: anywhere; }
.upload-state { color: var(--muted); }
[data-state='failed'] .upload-state, [data-state='skipped'] .upload-state { color: var(--danger); }
.upload-summary { color: var(--danger); }

.check-product {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
  margin-bottom: 12px;
}
.check-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.check-head .check { margin: 0; }
/* the category dropdown is one control in the head, not the whole width */
.check-head select { width: auto; min-width: 140px; }
.warn { margin: 8px 0 0; color: var(--warn); }
.check-frames .warn { margin: 0; font-size: 12px; }
.check-thumb {
  width: 72px;
  height: 72px;
  object-fit: contain;
  background: #e8e8e8;
  border-radius: 4px;
  cursor: zoom-in;
  flex: 0 0 auto;
}
.check-frames .dims { font-size: 12px; }
/* The details column's `select { width: 100% }` must not reach the role
 * dropdown in a check-table row: at 100 % it squeezed the frame name beside it
 * to one character per line. */
.check-frames li select { width: 160px; flex: 0 0 auto; }
.check-frames .frame-name { min-width: 12ch; }

#submit-order {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-height: 36px;
  margin-top: var(--gap);
  padding: 0 16px;
  background: var(--accent);
  border: 0;
  border-radius: var(--radius);
  color: var(--accent-ink);
  font: inherit;
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  cursor: pointer;
}
#submit-order:disabled { opacity: 0.6; cursor: default; }

/* Stream's two columns: upload on the left, order details on the right. */
.create {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: 40px;
  align-items: start;
}
@media (max-width: 960px) { .create { grid-template-columns: 1fr; } }
.create-col { min-width: 0; }
.step {
  margin: 0 0 var(--gap);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.sub {
  margin: 28px 0 8px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.create textarea { min-height: 160px; }
.create select { width: 100%; padding: 9px 10px; }
.please-note { margin: var(--gap) 0 0; font-style: italic; }
.actions { display: flex; align-items: center; justify-content: flex-end; gap: 12px; flex-wrap: wrap; margin-top: 24px; }
.actions button, .actions #submit-order { margin-top: 0; }

/* The order's details, on the order page and the review screen. */
.details { display: grid; gap: 8px; margin: 12px 0 0; }
.details div { display: grid; grid-template-columns: 160px minmax(0, 1fr); gap: 12px; }
.details dt { color: var(--muted); }
.details dd { margin: 0; }
.prewrap { white-space: pre-wrap; }

/* --------------------------------------------------- order page (§7 item 4) */

.meta { margin: 8px 0 0; }
.progress { height: 6px; margin: 12px 0 4px; background: var(--line); border-radius: 3px; overflow: hidden; }
.progress-bar { height: 100%; background: var(--accent); transition: width 0.4s; }
.progress-text { margin: 0 0 var(--gap); }

.product h2 { font-size: 16px; margin: var(--gap) 0 0; font-weight: 600; }
.frame { border-bottom: 1px solid var(--line); }
.frame-link {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 6px;
  color: var(--text);
  border-radius: 6px;
}
.frame-link:hover { background: var(--panel); text-decoration: none; }
.frame-text { flex: 1; display: grid; gap: 2px; min-width: 0; }
.frame-text .frame-name { flex: none; }
.detail, .problem, .note { font-size: 12px; }
.problem { color: #ff9b9b; }
.note { color: var(--muted); }
.thumb {
  width: 120px;
  height: 120px;
  object-fit: contain;
  border-radius: 6px;
  background: #e8e8e8;
  flex: 0 0 auto;
}
.frame-text .frame-name { font-weight: 600; }
.role { color: var(--muted); width: 56px; }

/* --------------------------------------------------------------- lightbox */

.lightbox, .zoom {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 24px;
  background: rgb(0 0 0 / 88%);
  cursor: zoom-out;
}
.lightbox-pane { margin: 0; max-width: 48%; max-height: 100%; text-align: center; }
.lightbox-pane.solo { max-width: 100%; }
.lightbox-pane img { max-width: 100%; max-height: calc(100vh - 90px); border-radius: 6px; background: #e8e8e8; }
.lightbox-pane figcaption { margin-top: 8px; color: var(--muted); }
.lightbox-close {
  position: absolute;
  top: 14px;
  right: 16px;
  background: none;
  border: 0;
  color: var(--text);
  font-size: 22px;
  cursor: pointer;
}
.zoom { overflow: auto; display: block; padding: 0; }
.zoom img { display: block; max-width: none; margin: 0 auto; }

/* ------------------------------------------------ review screen (§7 item 5) */

/* Title on the left, actions on the right; when there is not room for both on
 * one line the actions move to a line of their own, whole. */
.review-head { display: flex; align-items: center; justify-content: space-between; gap: 12px 24px; flex-wrap: wrap; margin-bottom: 10px; }
.review-title, .review-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; min-width: 0; }
/* U-13: the counts are three short numbers now, so they stay on the title's own
 * line and let the actions sit beside them, centred on the same axis. */
.review-title { flex-wrap: nowrap; }
.review-title .counts { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.review-actions { margin-left: auto; gap: 8px; }
.review-head .crumb { font-weight: 600; color: var(--text); }
.review-head .close { font-size: 16px; }

.review {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) 300px 36px;
  gap: 12px;
  align-items: stretch;
}
.arrow {
  align-self: center;
  height: 120px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 26px;
  cursor: pointer;
}
.arrow:hover { background: var(--panel-2); }
.review-main { min-width: 0; }

.panes { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; }
.pane { margin: 0; min-width: 0; }
/* U-17 (Elias, 2026-09-06 03:08): each pane shows the picture at its own
 * proportions, and nothing else. The old box was a full-width, fixed-height
 * rectangle painted #e8e8e8 -- the retouch's own grey -- so the edited frame's
 * real edges vanished into it and the item looked centred (or not) in a box
 * that was not the file. Now the <img> IS the file: intrinsic ratio, capped by
 * the pane's width and the viewport's height, centred, with a one-pixel line
 * marking exactly where the delivered picture ends. */
.pane img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: calc(100vh - 330px);
  margin: 0 auto;
  border-radius: 0;
  background: none;
  outline: 1px solid var(--line);
  cursor: zoom-in;
}
.pane figcaption {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 6px;
  font-size: 12px;
}
.pane-label {
  padding: 1px 8px;
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--muted);
}
.pane-name { font-weight: 600; }
.pane-dl { color: var(--muted); padding: 6px 8px; margin: -6px 0; }
.pane-state {
  height: calc(100vh - 330px);
  min-height: 280px;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  background: var(--panel);
  border-radius: var(--radius);
}
.dims { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.decision-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
  display: grid;
  gap: 12px;
  align-content: start;
  min-width: 0;
  /* U-14: the same height the panes get, so unhiding the batch bar scrolls this
   * panel instead of making the whole review row taller and shoving the strip
   * (and its checkboxes) down the page mid-click. */
  max-height: max(300px, calc(100vh - 300px));
  overflow-y: auto;
}
.review-bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.decisions { display: grid; gap: 10px; }
.decisions .button { width: 100%; text-align: center; }
.select-frame { margin: 0; }
.batch {
  display: grid;
  gap: 6px;
  padding: 10px;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
}
.reject-box { display: grid; gap: 8px; padding-top: 6px; border-top: 1px solid var(--line); }
.reject-box h3 { margin: 4px 0 0; font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
.reject-box textarea { min-height: 64px; font-size: 13px; }
.reject-box .help { margin: 0; font-size: 12px; }

.facts, .kvs { margin: 0; display: grid; gap: 6px; font-size: 12px; }
.facts .kv, .kvs .kv { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: 8px; }
.kvs .kv { grid-template-columns: 180px minmax(0, 1fr); font-size: 13px; }
.facts dt, .kvs dt { color: var(--muted); }
.facts dd, .kvs dd { margin: 0; overflow-wrap: anywhere; }
.order-notes summary { cursor: pointer; color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
.order-notes .details { font-size: 12px; }
.order-notes .details div { grid-template-columns: 72px minmax(0, 1fr); }

.strip {
  list-style: none;
  display: flex;
  gap: 8px;
  /* U-14: the strip lines up with the pictures above it -- its first tile
   * starts where the Original pane starts and its last ends where the panel
   * ends, i.e. inset by the arrow column (36px) plus the grid gap (12px).
   * 3px of that inset is padding rather than margin: the current tile's 2px
   * outline sits outside the tile, and the strip's own overflow clipped it
   * flush on the left (Elias, 03:12). */
  margin: 12px 45px 0;
  padding: 8px 3px;
  overflow-x: auto;
  scrollbar-width: thin;
}
.strip-item { position: relative; flex: 0 0 auto; }
.strip-item.current .strip-button { outline: 2px solid var(--accent); }
.strip-item.selected .strip-button img { outline: 2px solid var(--accent); outline-offset: -2px; }
.strip-select {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 1;
  margin: 0;
  padding: 4px;
  line-height: 0;
  border-radius: 4px;
  background: color-mix(in srgb, var(--panel) 78%, transparent);
  cursor: pointer;
}
.strip-select input { display: block; width: 16px; height: 16px; margin: 0; cursor: pointer; }
.strip-button {
  position: relative;
  display: block;
  width: 108px;
  padding: 0 0 18px;
  background: none;
  border: 0;
  border-radius: 4px;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}
.strip-button img { width: 108px; height: 108px; object-fit: contain; background: #e8e8e8; border-radius: 4px; display: block; }
/* 17px from 92px: one pixel past the 108px image, over the dark gap before the
 * name. At 16px the badge ended exactly on the image's edge and Retina rounding
 * let a hairline of the tile's #e8e8e8 show under it (Elias, 03:20). */
.strip-button .badge { top: 92px; bottom: auto; height: 17px; line-height: 16px; border-radius: 0 0 4px 4px; }
.strip-name {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.review-grid { display: grid; gap: 12px; }
.grid-toolbar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.grid-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
}
.grid-card {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 8px;
}
.grid-card.selected { border-color: var(--accent); }
.grid-card.state-approved { border-color: #3a8f4f; }
.grid-card.state-rejected, .grid-card.state-manual { border-color: #6b2b2b; }
.grid-card.state-redo { border-color: #6b5a20; }
.grid-select { position: absolute; top: 12px; left: 12px; z-index: 1; margin: 0; }
.grid-select input { width: 20px; height: 20px; }
.grid-image { display: block; width: 100%; padding: 0; background: none; border: 0; cursor: zoom-in; }
.grid-image img { display: block; width: 100%; aspect-ratio: 3 / 4; object-fit: contain; background: #e8e8e8; border-radius: 6px; }
.grid-name {
  display: block;
  margin: 6px 0 14px;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.grid-card .badge { border-radius: 0 0 var(--radius) var(--radius); }

/* --------------------------------------------------------------- settings */

.settings { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: var(--gap); }
.settings .wide { grid-column: 1 / -1; }
.settings .card h2 { margin-top: 0; }
.stack input { margin-bottom: 4px; }
.stack .button { margin-top: 12px; border: 0; }
.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: 13px; }
.table th, .table td { padding: 6px 10px; text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; }
.table th { color: var(--muted); font-weight: 500; }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }
.table .err { color: #ff9b9b; overflow-wrap: anywhere; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }

/* -- settings console (ruling S-1) -- owned by the settings work; the rules
 * above this line are shared and untouched. */
/* Two columns, full width, whatever the screen: the auto-fit rule above opened
 * four 350 px columns on a wide monitor and the page only ever fills two, so
 * half the screen sat empty while every card was squeezed. */
.settings { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.settings-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--gap); flex-wrap: wrap; margin-bottom: 12px; }
.settings-head h1 { margin: 0; }
.settings-head p { margin: 0; font-size: 12px; }
.flash { margin: 0 0 12px; }
.notice {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  align-items: baseline;
  margin: 0 0 var(--gap);
  padding: 12px 16px;
  border: 1px solid #5a4d2a;
  border-radius: var(--radius);
  background: #3a3320;
  color: var(--warn);
}
.notice span { color: var(--text); }
.stat { margin: 0; font-size: 30px; font-weight: 600; line-height: 1.1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.stat small { margin-left: 6px; font-size: 13px; font-weight: 400; letter-spacing: 0; color: var(--muted); }
.bar { height: 6px; margin: 10px 0 6px; border-radius: 999px; background: var(--line); overflow: hidden; }
.bar > span { display: block; height: 100%; background: var(--accent); border-radius: inherit; transition: width 300ms ease; }
.bar.over > span { background: var(--danger); }
.settings .table-wrap + .prices-title { margin: 12px 0 2px; }
.prices { margin: 0 0 var(--gap); padding: 0; list-style: none; font-size: 12px; }
.prices li { padding: 1px 0; overflow-wrap: anywhere; }
.setting { display: grid; grid-template-columns: 180px minmax(0, 1fr); gap: 4px 12px; align-items: start; padding: 12px 0; border-top: 1px solid var(--line); }
.setting:first-of-type { border-top: 0; }
.setting label { margin: 8px 0 0; }
.setting .field { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.setting .field input { width: 160px; min-width: 0; }
.setting .field input.wide-input { width: auto; flex: 1 1 240px; }
.setting .field .mini { flex: 0 0 auto; }
.setting .help { margin: 6px 0 0; font-size: 12px; }
.setting .meta { margin: 4px 0 0; font-size: 12px; }
.setting .meta .linkish { padding: 0; font-size: 12px; }
.setting-form button[type='submit'] { width: auto; margin-top: 0; }
.setting-form button[type='submit'].linkish { margin: 0; padding: 0; background: none; color: var(--accent); font-weight: 400; }
.spend-table th, .spend-table td { white-space: nowrap; }
.spend-table small { font-size: 11px; }
.setting-form .mini { padding: 0 14px; }
.setting-form .error { margin: 6px 0 0; font-size: 12px; }
.hold-form { margin-top: 4px; }
.hold-form label { margin: 0 0 6px; }
.hold-form input[type='text'] { margin-bottom: 10px; }
.hold-form .help { margin: 8px 0 0; font-size: 12px; }
.days .spark-cell { width: 120px; }
.days .spark { display: inline-block; height: 8px; max-width: 100%; border-radius: 2px; background: var(--accent); vertical-align: middle; }
.days tr.quiet td { color: var(--muted); }
.settings details.calls summary { display: flex; align-items: baseline; gap: 8px; cursor: pointer; list-style: none; }
.settings details.calls summary::before { content: '▸'; color: var(--muted); }
.settings details.calls[open] summary::before { content: '▾'; }
.settings details.calls summary h2 { margin: 0; }
.settings details.calls[open] summary { margin-bottom: 12px; }
@media (max-width: 1100px) {
  .setting { grid-template-columns: 1fr; gap: 2px; }
  .setting label { margin-top: 0; }
}
@media (max-width: 900px) {
  .settings { grid-template-columns: minmax(0, 1fr); }
  .settings-head { flex-direction: column; align-items: flex-start; }
  .setting { grid-template-columns: 1fr; gap: 2px; }
  .setting label { margin-top: 0; }
  .setting .field input { width: 100%; }
  .days .spark-cell { display: none; }
}

/* ------------------------------------------------------------ small screens */

@media (max-width: 900px) {
  .review { grid-template-columns: 1fr; }
  /* prev/next stay reachable on a phone: pinned mid-screen over the panes */
  .arrow { position: fixed; top: 50%; transform: translateY(-50%); z-index: 5; height: 64px; width: 36px; padding: 0; opacity: 0.9; }
  #review-prev { left: 4px; }
  #review-next { right: 4px; }
  .panes { grid-template-columns: 1fr; }
  .pane img, .pane-state { height: auto; max-height: 60vh; }
  .lightbox { flex-direction: column; }
  .lightbox-pane { max-width: 100%; }
  .lightbox-pane img { max-height: 42vh; }
  .kvs .kv { grid-template-columns: 1fr; gap: 2px; }
}

@media (max-width: 600px) {
  /* the check table: a row wraps instead of pushing the role dropdown off-screen */
  .check-frames li { flex-wrap: wrap; }
  .check-frames li select { width: 100%; }
  .check-thumb { width: 56px; height: 56px; }
  /* the order page: a smaller preview, role and chip under the text */
  .thumb { width: 72px; height: 72px; }
  .frame-link { flex-wrap: wrap; gap: 8px 12px; }
  .frame-text { flex: 1 1 calc(100% - 84px); }
  .role { width: auto; }
  /* the top bar: no word-by-word wrapping; the name gives way to Sign out */
  .brand, .email, #signout { white-space: nowrap; }
  .who .email { display: none; }
}

/* ------------------------------------------------- delete an order (any status) */
/* The type-"delete" dialog public/app.js confirmDelete() builds for the trash
 * buttons on the board, the order page and the create screen. Above the
 * lightbox (z-index 20) so it wins if both are ever open. */
.confirm {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgb(0 0 0 / 70%);
}
.confirm-box {
  width: min(460px, 100%);
  padding: 20px 22px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 20px 50px rgb(0 0 0 / 50%);
}
.confirm-box h2 { margin: 0 0 10px; font-size: 16px; }
.confirm-box p { margin: 0 0 10px; }
.confirm-box .order-ref { font-weight: 600; overflow-wrap: anywhere; }
.confirm-box label { display: block; margin: 16px 0 6px; color: var(--muted); }
.confirm-box label b { color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.confirm-box input { width: 100%; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }
.confirm-box .error { margin: 10px 0 0; }
/* the trash button: icon only on the board, icon + word elsewhere; the
 * list view's chevron is the same square */
.mini.trash, .mini.toggle { width: 30px; padding: 0; justify-content: center; }
.mini.trash svg, .secondary.trash svg, .mini.toggle svg { width: 15px; height: 15px; }


/* ------------------------------------------------- focus, touch, motion (a11y)
 * Added 2026-09-05 from Brandkit/AUDIT.md findings 1, 5 and 6. Rules only, no
 * markup change: every interactive element gets the same ring, coarse pointers
 * get 44 px targets, and reduced motion stops every transition, not just the
 * board chevron's. */

:where(a, button, summary, [tabindex]):focus-visible,
.mini:focus-visible,
.tab:focus-visible,
.strip-button:focus-visible,
.grid-card:focus-visible,
.linkish:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
/* the input rule above draws its ring inside the field; keep that shape */
input:focus-visible, textarea:focus-visible, select:focus-visible { outline-offset: -1px; }

@media (pointer: coarse) {
  .mini { height: 44px; }
  .button { min-height: 44px; }
  .tab { padding: 12px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* skip link: off-screen until focused (AUDIT.md finding 7) */
.skip {
  position: absolute;
  left: 8px;
  top: -48px;
  z-index: 60;
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  color: var(--text);
  text-decoration: none;
  transition: top 0.15s ease;
}
.skip:focus-visible { top: 8px; outline: 2px solid var(--accent); outline-offset: 2px; }
#main:focus { outline: none; }

/* ------------------------------------------------------------- login lockup */
.login-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin: 0 0 4px; }
.login-mark { display: block; width: 132px; height: auto; }
.login-brand .brand-word { font-size: 14px; }
