/* Hallmark · macrostructure: Workbench · genre: modern-minimal · theme: Cobalt
 * nav: N1b canonical three-section · footer: none (app surface) · enrichment: none
 * design-system: design.md (structural rules kept: spacing ownership, layout
 * primitives, component reuse, empty states. Visual layer re-themed on the
 * owner's instruction — Shopify two-track replaced by Cobalt.)
 * paper oklch(98.5% .004 250) cool near-white · ink oklch(24% .02 258) cool
 * charcoal · accent oklch(58% .20 256) electric cobalt, used as a signal
 * display Space Grotesk 500/600 · body Inter · mono JetBrains Mono
 * Hallmark · pre-emit critique: P4 H5 E5 S4 R5 V4
 * Deviation on record: design.md calls pills non-negotiable; Cobalt forbids them.
 * Buttons ship at 6px. Restore pills by setting --r-btn to var(--r-pill).
 */

@font-face { font-family: 'Inter Var'; font-style: normal; font-weight: 100 900;
  font-display: swap; src: url(/fonts/inter-variable-latin.woff2) format('woff2'); }
@font-face { font-family: 'Space Grotesk'; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url(/fonts/space-grotesk-latin.woff2) format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url(/fonts/jetbrains-mono-latin.woff2) format('woff2'); }

:root {
  /* Cobalt: cool engineered paper, never #fff. Ink is cool charcoal, never #000. */
  --paper:        oklch(98.5% 0.004 250);
  --paper-2:      oklch(96.5% 0.005 252);
  --paper-3:      oklch(94%   0.006 254);
  --rule:         oklch(91%   0.008 255);
  --muted:        oklch(56%   0.013 255);
  --ink-2:        oklch(34%   0.018 257);
  --ink:          oklch(24%   0.020 258);
  --accent:       oklch(58%   0.200 256);
  --accent-ink:   oklch(99%   0.004 256);
  --accent-quiet: oklch(92%   0.040 256);
  --graphite:     oklch(22%   0.016 260);

  /* names the pages already use, re-pointed at the Cobalt ramp */
  --primary: var(--accent);
  --on-primary: var(--accent-ink);
  --canvas-light: var(--paper);
  --canvas-cream: var(--paper-2);
  --canvas-night: var(--graphite);
  --canvas-night-elevated: oklch(18% 0.014 260);
  --surface-elevated-dark: oklch(28% 0.016 258);
  --shade-30: var(--rule);
  --shade-40: oklch(70% 0.010 255);
  --shade-50: var(--muted);
  --shade-60: var(--ink-2);
  --shade-70: oklch(30% 0.018 258);
  --hairline-light: var(--rule);
  --hairline-dark: oklch(32% 0.016 260);
  --aloe: var(--accent);
  --pistachio: var(--accent-quiet);
  --link-cool: oklch(72% 0.012 255);
  --danger: oklch(55% 0.180 25);
  --ok: oklch(52% 0.140 155);
  --warn: oklch(58% 0.130 70);

  --font-ui: 'Inter Var', Inter, ui-sans-serif, system-ui, sans-serif;
  --font-display: 'Space Grotesk', 'Inter Var', ui-sans-serif, system-ui, sans-serif;
  --font-code: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* tight technical radii — drawn with a ruler, not softened into pills */
  --r-xs: 3px; --r-sm: 4px; --r-md: 6px; --r-lg: 10px; --r-xl: 12px; --r-pill: 9999px;
  --r-btn: var(--r-md);
  --s-xxs: 2px; --s-xs: 4px; --s-sm: 8px; --s-md: 12px; --s-lg: 16px; --s-xl: 24px; --s-xxl: 32px; --s-huge: 64px;
  --band: 48px;

  /* hairlines do the work; the only lift is a barely-there one on raised cards */
  --shadow-card: 0 1px 2px oklch(24% 0.02 258 / .06);
  --shadow-modal: 0 16px 40px oklch(24% 0.02 258 / .18);

  --ease-out: cubic-bezier(.2,.7,.3,1);
  --ease-in: cubic-bezier(.5,0,.9,.4);
  --ease-in-out: cubic-bezier(.5,0,.3,1);
  --dur: .16s;
}

* { box-sizing: border-box; margin: 0; }
[hidden] { display: none !important; }
html, body { overflow-x: clip; }
body {
  font-family: var(--font-ui);
  font-size: 16px; line-height: 1.55; color: var(--ink-2); background: var(--paper);
  -webkit-font-smoothing: antialiased;
}
b, strong, .strong { font-weight: 600; color: var(--ink); }
a { color: var(--ink); text-decoration-color: var(--rule); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--accent); }

/* --- type roles: Space Grotesk display, Inter body, mono for machine readout --- */
h1, h2, h3, .display-xl, .display-lg, .display-md {
  font-family: var(--font-display); color: var(--ink); font-style: normal;
  overflow-wrap: anywhere; min-width: 0;
}
.display-xl { font-size: clamp(38px, 6vw, 60px); font-weight: 600; line-height: 1.04; letter-spacing: -.02em; }
.display-lg { font-size: clamp(32px, 4.6vw, 46px); font-weight: 600; line-height: 1.08; letter-spacing: -.02em; }
.display-md { font-size: clamp(26px, 3.4vw, 38px); font-weight: 600; line-height: 1.12; letter-spacing: -.018em; }
h1 { font-size: 26px; font-weight: 600; line-height: 1.24; letter-spacing: -.015em; }
h2 { font-size: 19px; font-weight: 600; line-height: 1.35; letter-spacing: -.01em; }
h3 { font-size: 16px; font-weight: 600; line-height: 1.3; letter-spacing: -.005em; }
.body-lg { font-size: 17px; line-height: 1.6; }
.caption { font-size: 14px; line-height: 1.5; color: var(--muted); }
.micro { font-size: 13px; }
/* mono labels — UPPERCASE machine readout against the grotesk display */
.eyebrow { font-family: var(--font-code); font-size: 11px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.mono { font-family: var(--font-code); font-size: 13px; }

/* --- buttons: 6px, one solid cobalt signal, everything else bordered --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-sm);
  padding: 9px 16px; border: 1px solid transparent; border-radius: var(--r-btn);
  font: inherit; font-size: 14px; font-weight: 550; line-height: 1.2;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: oklch(52% 0.20 256); }
.btn-primary:active { transform: translateY(1px); }
.btn-primary:disabled { background: var(--paper-3); color: var(--muted); cursor: default; transform: none; }
/* the old "positive" button — now the quiet cobalt tint, not a second signal */
.btn-aloe { background: var(--accent-quiet); color: var(--ink); border-color: var(--accent-quiet); }
.btn-aloe:hover { border-color: var(--accent); }
.btn-aloe:active { transform: translateY(1px); }
.btn-outline-light { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn-outline-light:hover { border-color: var(--ink); }
.btn-outline-dark { background: transparent; color: var(--paper); border-color: oklch(100% 0 0 / .4); }
.btn-outline-dark:hover { border-color: var(--paper); }
.btn-sm { padding: 6px 12px; font-size: 13px; }
.btn-danger { background: transparent; color: var(--danger); border-color: var(--danger); }
.btn-danger:hover { background: oklch(96% 0.03 25); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn[data-state="loading"] { opacity: .7; pointer-events: none; }

/* --- nav: N1b — flush bar, single hairline, wordmark + links left, actions right --- */
.nav {
  display: flex; align-items: center; gap: var(--s-xl);
  background: var(--paper); border-bottom: 1px solid var(--rule);
  padding: var(--s-md) var(--s-xl);
}
.nav .wordmark { font-family: var(--font-display); font-weight: 600; font-size: 17px;
  letter-spacing: -.02em; text-decoration: none; color: var(--ink); }
/* The mark is the real Space Grotesk G knocked out of a cobalt tile — the same
 * typeface the wordmark is set in, so the lockup is one voice rather than an
 * icon bolted onto a name. It replaces a plain coloured square, which is the
 * most-copied startup default there is. */
.nav .wordmark { display: inline-flex; align-items: center; gap: var(--s-sm); }
.nav .wordmark::before { content: ''; display: block; width: 20px; height: 20px;
  background: url(/mark.svg) center / contain no-repeat; flex: none; }
.nav .wordmark:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px;
  border-radius: var(--r-xs); }
.nav-dark .wordmark::before { filter: brightness(1.15); }
.nav a.navlink { color: var(--muted); text-decoration: none; font-size: 14px; font-weight: 500;
  padding-bottom: 2px; border-bottom: 1px solid transparent; }
.nav a.navlink:hover { color: var(--ink); border-bottom-color: var(--rule); }
.nav a.navlink.active { color: var(--ink); border-bottom-color: var(--accent); }
.nav .spacer { flex: 1; }
.nav-dark { background: var(--graphite); border-bottom: 1px solid var(--hairline-dark); }
.nav-dark .wordmark, .nav-dark a.navlink { color: var(--paper); }

/* --- layout: Workbench app shell (unchanged structure, per design.md) --- */
.page { max-width: 1080px; margin: 0 auto; padding: var(--s-xxl) var(--s-xl) var(--s-huge); }
.page-narrow { max-width: 440px; margin: 0 auto; padding: var(--s-huge) var(--s-xl); }
.page-head { display: flex; align-items: flex-start; gap: var(--s-lg); margin-bottom: var(--s-xxl); flex-wrap: wrap; }
.page-head .grow { flex: 1; min-width: 0; }
.page-head .display-md { margin-top: 2px; }
.page-head .caption { max-width: 62ch; margin-top: var(--s-sm); }

.workbench { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--s-xl); align-items: start; }
.workbench > aside { position: sticky; top: var(--s-lg); display: grid; gap: var(--s-lg); }
@media (max-width: 900px) { .workbench { grid-template-columns: minmax(0, 1fr); } .workbench > aside { position: static; } }

/* ===== Vertical rhythm — one owner per gap (design.md § Spacing ownership) ===== */
.page > * + *:not(.section) { margin-top: var(--band); }
.section { border-top: 1px solid var(--rule); padding-top: var(--s-xl); margin-top: var(--band); }
.section:first-child { margin-top: 0; }
.section > header { display: flex; align-items: baseline; gap: var(--s-md); margin-bottom: var(--s-lg); flex-wrap: wrap; }
.section > header .grow { flex: 1; min-width: 0; }
.section > header p { font-size: 14px; color: var(--muted); margin-top: var(--s-xs); }
.section > * + *:not(header) { margin-top: var(--s-lg); }

/* form fields pair up on wide viewports, stack on mobile — no more 320px columns */
.field-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--s-lg); }
.field-grid .full { grid-column: 1 / -1; }
.field { min-width: 0; }
.actions { display: flex; gap: var(--s-sm); flex-wrap: wrap; margin-top: var(--s-lg); }

/* module strip: compact, equal-height, visually distinct from content sections */
.modules { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--s-md); }
.module { display: flex; flex-direction: column; gap: var(--s-sm); min-width: 0;
  background: var(--canvas-light); border: 1px solid var(--hairline-light); border-radius: var(--r-lg);
  padding: var(--s-lg); text-decoration: none; color: var(--ink);
  transition: border-color .14s ease, transform .14s ease; }
.module:hover { border-color: var(--ink); }
.module:active { transform: translateY(1px); }
.module:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.module h3 { font-size: 16px; }
.module p { font-size: 13px; color: var(--shade-50); flex: 1; }
.module .go { font-family: var(--font-code); font-size: 12px; font-weight: 500; text-transform: uppercase; letter-spacing: .06em; color: var(--accent); }
.module[aria-disabled="true"] { background: transparent; border-style: dashed; pointer-events: none; }
.module[aria-disabled="true"] h3, .module[aria-disabled="true"] .go { color: var(--shade-50); }

/* --- cards (light track) — reserved for standalone panels, not page scaffolding --- */
.card { background: var(--paper); border: 1px solid var(--rule); border-radius: var(--r-lg); padding: var(--s-xxl); }
.card + .card, .stack > * + * { margin-top: var(--s-lg); }
/* inside a card: body flows at 12px, a new heading opens a 24px break */
.card > * + * { margin-top: var(--s-md); }
.card > * + h2, .card > * + h3 { margin-top: var(--s-xl); }
.card > :first-child { margin-top: 0; }
.card-flat { background: var(--paper-2); border: 1px solid var(--hairline-light); border-radius: var(--r-lg); padding: var(--s-lg); box-shadow: none; }
.card-pistachio { background: var(--pistachio); border-radius: var(--r-lg); padding: var(--s-xl); }
.rail-card { background: var(--canvas-light); border: 1px solid var(--hairline-light); border-radius: var(--r-lg); padding: var(--s-lg); }
.rail-card h3 { font-size: 15px; margin-bottom: var(--s-xs); }
.rail-card p { font-size: 13px; color: var(--shade-50); }
.rail-card .actions { margin-top: var(--s-md); }
.grid { display: grid; gap: var(--s-lg); }
.grid-3 { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.stat { background: var(--canvas-light); border: 1px solid var(--hairline-light); border-radius: var(--r-lg); padding: var(--s-lg); min-width: 0; }
.stat .v { font-family: var(--font-display); font-size: 26px; font-weight: 600; line-height: 1.1; letter-spacing: -.02em; }
.stat .l { font-size: 13px; color: var(--shade-50); margin-top: var(--s-xs); }

/* --- dialog ---------------------------------------------------------------
   A walkthrough that has to sit beside another window: the merchant reads a
   step here, does it in Shopify, comes back. So it is a real <dialog> — it
   keeps focus, closes on Escape, and cannot be scrolled away from behind. */
/* inset + auto margins: the reset zeroes dialog margins, and a zeroed margin
   pins a <dialog> to the top-left instead of centring it. */
dialog.sheet { inset: 0; margin: auto;
  width: min(720px, calc(100vw - 2 * var(--s-lg))); max-height: 86vh;
  padding: 0; border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--paper); color: var(--ink); box-shadow: var(--shadow-modal); overflow: hidden; }
dialog.sheet::backdrop { background: oklch(24% 0.02 258 / .42); }
.sheet-head { display: flex; align-items: flex-start; gap: var(--s-md);
  padding: var(--s-xl) var(--s-xl) var(--s-md); border-bottom: 1px solid var(--rule); }
.sheet-head h2 { margin: 0; }
.sheet-head .grow { min-width: 0; }
/* [open], not the bare selector: a closed <dialog> is display:none, and a
   display declared unconditionally would leave it on screen for ever. */
dialog.sheet[open] { display: flex; flex-direction: column; }
/* flex, not a height subtracted from the viewport: the header wraps to six
   lines on a phone and any fixed guess at its height cut the footer button off
   the bottom of the screen. */
.sheet-head, .sheet-foot { flex: 0 0 auto; }
.sheet-body { flex: 1 1 auto; min-height: 0; padding: var(--s-xl); overflow-y: auto; }
.sheet-body > * + * { margin-top: var(--s-md); }
.sheet-foot { display: flex; align-items: center; gap: var(--s-md); flex-wrap: wrap;
  padding: var(--s-md) var(--s-xl) var(--s-xl); border-top: 1px solid var(--rule); }
.sheet-foot .grow { min-width: 0; }

/* --- pills / tags --- */
.tag { display: inline-block; padding: 3px 8px; border-radius: var(--r-xs); font-family: var(--font-code); font-size: 11px; letter-spacing: .06em; text-transform: uppercase; }
.tag-mint { background: var(--accent-quiet); color: var(--ink); }
.tag-shade { background: var(--paper-3); color: var(--muted); }
/* An unfinished step, not an error: the brand exists, its store does not yet. */
.tag-warn { background: color-mix(in oklch, var(--warn) 16%, transparent); color: var(--warn); }

/* --- forms: label above, error below --- */
label { display: block; font-size: 13px; font-weight: 550; color: var(--ink-2); margin: 0 0 6px; }
.field > * + * { margin-top: 6px; }
/* a label that is NOT inside a .field still needs air above it */
:not(.field) > label + input, :not(.field) > label + select, :not(.field) > label + textarea { margin-bottom: var(--s-md); }
:not(.field) > * + label { margin-top: var(--s-lg); }
label .hint { font-weight: 400; color: var(--muted); }
input, select, textarea {
  width: 100%; padding: 10px 12px; font: inherit; font-size: 16px; color: var(--ink);
  background: var(--paper); border: 1px solid var(--rule); border-radius: var(--r-md);
  transition: border-color var(--dur) var(--ease-out);
}
/* Checkboxes and radios are glyphs, not fields — the 100% above stretched them
   to the full row, which pushed the label they belong to down to zero width in
   every picker on the site. */
input[type=checkbox], input[type=radio] { width: auto; padding: 0; }
input:hover, select:hover, textarea:hover { border-color: var(--shade-40); }
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.msg { margin-top: var(--s-md); font-size: 14px; }
.msg:empty { display: none; }
.msg-err { color: var(--danger); }
.msg-ok { color: var(--ok); }
.msg-warn { color: var(--warn); }
.is-warn { color: var(--warn); }

/* --- tables --- */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--hairline-light); vertical-align: top; }
tr:last-child td { border-bottom: 0; }
th { font-family: var(--font-code); color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .06em; font-weight: 500; white-space: nowrap; }
.scroll-x { overflow-x: auto; }

/* --- dark (cinematic) track --- */
.night { background: var(--canvas-night); color: var(--on-primary); }
.night .caption { color: var(--shade-40); }
.night a { color: var(--on-primary); }
.hero { max-width: 1100px; margin: 0 auto; padding: 128px var(--s-xl) var(--s-huge); }
.footer-dark { background: var(--canvas-night); color: var(--link-cool); font-size: 14px; padding: var(--s-huge) var(--s-xl); }

@media (prefers-reduced-motion: reduce) { * { transition-duration: .01ms !important; } }
/* nav wraps instead of overflowing; links stay one line each */
.nav { flex-wrap: wrap; row-gap: var(--s-sm); }
.nav a.navlink { white-space: nowrap; }
@media (max-width: 767px) {
  .nav { gap: var(--s-md); padding: var(--s-md) var(--s-lg); }
  .nav .spacer { flex-basis: 100%; height: 0; }
  .hero { padding-top: 72px; }
  .page { padding: var(--s-xl) var(--s-lg) var(--s-huge); }
}

/* brand page: colour input pairs with its hex field */
.swatch-row { display: flex; gap: var(--s-sm); align-items: center; }
.swatch-row input[type="color"] { width: 44px; height: 38px; padding: 2px; flex-shrink: 0; }
details summary { cursor: pointer; }
/* A summary that carries a second line: the qualifier belongs under the title,
   not run on after it, or the two read as one sentence. */
.summary-stack .hint { display: block; margin-top: 4px; }
details summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* tags must hug their text inside flex columns (flex stretch was widening them) */
.tag { align-self: flex-start; }
.module .go { margin-top: auto; }

/* page header stacks on narrow viewports — side-by-side actions overlapped the title */
@media (max-width: 640px) {
  .page-head { flex-direction: column; align-items: stretch; gap: var(--s-md); }
  .page-head .actions { margin-top: 0; }
}

/* connect-store walkthrough */
.steps { margin: var(--s-md) 0 0; padding-left: 18px; font-size: 13px; color: var(--shade-60); }
.steps li { margin-bottom: var(--s-sm); line-height: 1.5; }
.steps li b { color: var(--ink); }
.steps code { font-family: var(--font-code); font-size: 12px; background: var(--canvas-cream);
  border: 1px solid var(--hairline-light); border-radius: var(--r-xs); padding: 2px 6px; overflow-wrap: anywhere; }
.scope-row { display: flex; align-items: center; gap: var(--s-sm); margin: var(--s-xs) 0; flex-wrap: wrap; }
.steps .hint { display: block; margin-top: 2px; color: var(--shade-50); font-size: 12px; }

/* setup table: field → value, mirrors the Dev Dashboard form order */
.setup-table td { font-size: 13px; }
.setup-table td:first-child { white-space: nowrap; color: var(--shade-60); font-weight: 550; }
.copyable { display: flex; align-items: center; gap: var(--s-sm); flex-wrap: wrap; }
.copyable code { font-family: var(--font-code); font-size: 12px; background: var(--canvas-cream);
  border: 1px solid var(--hairline-light); border-radius: var(--r-xs); padding: 3px 6px; overflow-wrap: anywhere; }
.setup-table .hint { display: block; margin-top: 4px; color: var(--shade-50); font-size: 12px; }

/* utilities — use these instead of inline styles (lint-ui.js enforces it) */
.u-narrow { max-width: 780px; }
.u-muted { color: var(--shade-50); }
.u-full { width: 100%; }
.u-grow { flex: 1; min-width: 200px; }
.u-tight { margin-top: 0 !important; }
.u-row { display: flex; align-items: center; gap: var(--s-sm); flex-wrap: wrap; }
.u-nowrap { white-space: nowrap; }
.u-cool { color: var(--link-cool); }
.mono.micro { font-size: 12px; }
.swatch-dot { width: 20px; height: 20px; border-radius: var(--r-xs); border: 1px solid var(--hairline-light); display: inline-block; }
#name-picks label { margin: var(--s-xs) 0; align-items: baseline; }
#name-picks input[type="radio"] { width: auto; }

/* --- form field alignment ---
 * Inputs in a row must start at the same y. Two-line labels were pushing one
 * column down, so: labels stay one line, the explanation moves under the input. */
.field label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.field .caption { margin-top: 6px; }

/* --- dropzone: replaces the raw <input type=file> chrome --- */
.dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-xs);
  min-height: 104px; padding: var(--s-lg); text-align: center; cursor: pointer;
  background: var(--canvas-cream); border: 1px dashed var(--shade-30); border-radius: var(--r-lg);
  transition: border-color .14s ease, background .14s ease;
}
.dropzone:hover, .dropzone.is-over { border-color: var(--ink); background: var(--canvas-light); }
.dropzone:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dropzone .dz-title { font-size: 14px; font-weight: 550; }
.dropzone .dz-hint { font-size: 12px; color: var(--shade-50); }
.dropzone input[type="file"] { display: none; }

.chips { display: flex; flex-wrap: wrap; gap: var(--s-xs); margin-top: var(--s-sm); }
.chip {
  display: inline-flex; align-items: center; gap: var(--s-xs); max-width: 100%;
  padding: 4px 6px 4px 10px; border-radius: var(--r-pill);
  background: var(--canvas-light); border: 1px solid var(--hairline-light); font-size: 12px;
}
.chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 190px; }
.chip button {
  border: 0; background: none; cursor: pointer; color: var(--shade-50);
  font: inherit; line-height: 1; padding: 2px 4px; border-radius: var(--r-pill);
}
.chip button:hover { color: var(--danger); background: var(--canvas-cream); }
.chip.is-image { border-color: var(--accent); }

/* generated slide set */
.slide-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--s-lg); margin-top: var(--s-lg); }
.slide-card { margin: 0; background: var(--canvas-light); border: 1px solid var(--hairline-light); border-radius: var(--r-lg); overflow: hidden; min-width: 0; }
.slide-card img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; }
.slide-card .slide-pending { display: grid; place-items: center; aspect-ratio: 1; background: var(--canvas-cream); color: var(--shade-50); font-size: 13px; }
.slide-card figcaption { padding: var(--s-md); display: grid; gap: var(--s-xs); font-size: 13px; }

/* --- Job-runner components (shared by every module page) ---------------------
 * These lived as page-local <style> blocks in four different modules, which is
 * exactly the "component reuse before invention" rule in design.md — and why
 * each page drifted a little further from the last. One definition, one owner. */

/* live job output */
.log { font-family: var(--font-code); font-size: 13px; line-height: 1.6;
  background: var(--graphite); color: oklch(88% 0.01 255); border: 1px solid var(--hairline-dark);
  border-radius: var(--r-md); padding: var(--s-lg); max-height: 300px;
  overflow-y: auto; white-space: pre-wrap; overflow-wrap: anywhere; }

/* a clickable row in a run-history table */
.jobrow { cursor: pointer; }
.jobrow:hover td { background: var(--canvas-cream); }

/* where a product stands: numbered stages, read at a glance */
.pipeline { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--s-md); }
.stage { background: var(--canvas-light); border: 1px solid var(--hairline-light);
  border-radius: var(--r-lg); padding: var(--s-lg); display: grid; gap: var(--s-xs);
  align-content: start; min-width: 0; }
.stage .stage-n { font-family: var(--font-code); font-size: 12px; color: var(--shade-50); }
.stage h3 { font-size: 15px; }
.stage p { font-size: 13px; color: var(--shade-50); }
.stage.is-done { border-color: var(--accent); }

/* a picker of visual options — ad formats, layouts, anything with a preview.
 * Fixed shape whatever the label length: image, one-line head, footer pinned. */
.pick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--s-md); }
.pick { display: flex; flex-direction: column; min-width: 0;
  border: 1px solid var(--hairline-light); border-radius: var(--r-md);
  overflow: hidden; background: var(--canvas-light); }
.pick.is-picked { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.pick.is-off { opacity: .5; }
.pick .shot { aspect-ratio: 1 / 1; background: var(--canvas-cream); display: block; }
.pick.is-textonly .shot { display: none; }
.pick .shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pick .head { display: flex; gap: var(--s-xs); align-items: center; padding: var(--s-sm);
  border-top: 1px solid var(--hairline-light); }
.pick .head input { flex: none; margin: 0; }
.pick .head label { flex: 1; min-width: 0; font-size: 13px; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pick .tag { flex: none; font-family: var(--font-code); font-size: 11px;
  color: var(--shade-50); white-space: nowrap; }
.pick details { margin-top: auto; border-top: 1px solid var(--hairline-light); padding: var(--s-sm); }
.pick details p { font-size: 12px; color: var(--shade-50); }
.pick details p + p { margin-top: var(--s-xs); }
.pick-examples { display: flex; gap: var(--s-xs); overflow-x: auto; margin-top: var(--s-xs); }
.pick-examples img { height: 96px; width: auto; border-radius: var(--r-sm); flex: none; }

/* a module group: cards that link onward to a tool */
.mod-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--s-md); }
.mod { background: var(--canvas-light); border: 1px solid var(--hairline-light);
  border-radius: var(--r-lg); padding: var(--s-xl); display: grid; gap: var(--s-xs);
  align-content: start; min-width: 0; text-decoration: none; color: var(--ink); }
.mod:hover { border-color: var(--ink); }
.mod.is-soon { opacity: .6; }
.mod h2 { font-size: 17px; }
.mod p { font-size: 13px; color: var(--shade-50); }
.mod .tag { font-family: var(--font-code); font-size: 11px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--shade-50); }

/* rendered markdown report (research module) */
  .report { line-height: 1.65; overflow-x: auto; }
  .report h1 { font-size: 24px; margin: var(--s-md) 0 var(--s-md); }
  .report h2 { font-size: 20px; margin: var(--s-xl) 0 var(--s-sm); }
  .report h3 { font-size: 17px; margin: var(--s-lg) 0 var(--s-xs); }
  .report p, .report li { font-size: 14px; }
  .report ul, .report ol { padding-left: var(--s-xl); margin: var(--s-sm) 0; }
  .report table { margin: var(--s-md) 0; display: block; overflow-x: auto; white-space: nowrap; }
  .report blockquote { border-left: 2px solid var(--accent); margin: var(--s-md) 0; padding: var(--s-xxs) var(--s-md); color: var(--shade-50); }
  .report code { font-family: var(--font-code); font-size: 13px; background: var(--canvas-cream); padding: var(--s-xxs) var(--s-xs); border-radius: var(--r-xs); }
  .report hr { border: 0; border-top: 1px solid var(--hairline-light); margin: var(--s-xl) 0; }

/* a brand tile on the app home */
.brand-card { display: flex; flex-direction: column; gap: var(--s-xs); min-width: 0; text-decoration: none; color: var(--ink);
    background: var(--canvas-light); border: 1px solid var(--hairline-light); border-radius: var(--r-lg);
    padding: var(--s-lg); transition: border-color .14s ease, transform .14s ease; }
  .brand-card:hover { border-color: var(--ink); }
  .brand-card:active { transform: translateY(1px); }
  .brand-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  .brand-card .swatch { width: 24px; height: 24px; border-radius: var(--r-md); border: 1px solid var(--hairline-light); }
  .brand-card h2 { font-size: 17px; }
  .brand-card .meta { font-size: 13px; color: var(--shade-50); }

/* --- marketing surface (landing) ------------------------------------------
 * Bento Grid on Cobalt paper. Rhythm comes from unequal spans, not from card
 * uniformity: one lead tile carries the argument, the rest support it. The
 * module tiles inside .bento-modules are generated from the registry, so the
 * grid has to survive any count from zero upward. */

/* N9 edge-aligned: wordmark hard-left, one action hard-right, silence between */
.nav-edge { padding: var(--s-lg) var(--s-xl); }
.nav-edge .navlink { margin-right: var(--s-md); }

.bento { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--s-md); padding-top: var(--s-xxl); }
.tile { grid-column: span 2; min-width: 0;
  background: var(--paper); border: 1px solid var(--rule); border-radius: var(--r-lg);
  padding: var(--s-xl); display: grid; gap: var(--s-sm); align-content: start; }
.tile h3 { font-size: 16px; }
.tile p { font-size: 14px; color: var(--ink-2); }
.tile .tag { justify-self: start; }
.tile.is-soon { opacity: .6; }

/* the one idea gets four columns and the page's only display type */
.tile-lead { grid-column: span 6; padding: var(--s-huge) var(--s-xxl);
  background: var(--graphite); border-color: var(--hairline-dark);
  color: oklch(88% 0.01 255); }
.tile-lead h1 { color: oklch(98% 0.005 255); max-width: 18ch; }
.tile-lead .body-lg { color: oklch(80% 0.012 255); max-width: 60ch; margin-top: var(--s-md); }
/* Dark surfaces restyle light-track controls instead of swallowing them. This
 * has now shipped twice — the night-track hero and the Log in button here —
 * both times because a component built for paper was placed on graphite. The
 * surface, not the author, is the right place to fix it. */
.tile-lead .btn-outline-light,
.band .btn-outline-light {
  background: transparent; color: var(--paper);
  border-color: oklch(100% 0 0 / .4);
}
.tile-lead .btn-outline-light:hover,
.band .btn-outline-light:hover { border-color: var(--paper); }
.tile-lead .caption, .band .caption { color: oklch(74% 0.012 255); }
.tile-wide { grid-column: span 4; }
.tile-quiet { grid-column: span 6; background: var(--paper-2); }

/* the generated strip spans the grid and lays its own tiles out inside it */
.bento-modules { grid-column: span 6; display: grid; gap: var(--s-md);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }

@media (max-width: 820px) {
  .bento { grid-template-columns: minmax(0, 1fr); }
  .tile, .tile-lead, .tile-wide, .tile-quiet, .bento-modules { grid-column: span 1; }
  .tile-lead { padding: var(--s-xxl); }
}

/* Ft2 inline single line — one row, nothing to scan */
.footer-line { display: flex; align-items: center; gap: var(--s-md); flex-wrap: wrap;
  max-width: 1080px; margin: var(--band) auto 0; padding: var(--s-xl);
  border-top: 1px solid var(--rule); font-size: 13px; color: var(--muted); }
.footer-line .spacer { flex: 1; }

/* ---- video ads -------------------------------------------------------- */
/* A video tile is a pick with a portrait still: ad video is vertical, and a
   square crop hides exactly the top and bottom thirds where the hook and the
   offer sit. */
/* A vertical video in a square tile would be cropped to its middle third —
   exactly where nothing happens. Letterbox it at a fixed height instead, so the
   whole frame is visible and the tile stays the width of every other picker. */
.pick.is-video .shot { aspect-ratio: auto; height: 208px; width: 100%;
  object-fit: contain; background: var(--ink); }
.pick.is-video .head { flex-wrap: wrap; }
/* The filename is the only way to tell two clips apart — it wraps rather than
   truncating to 'ugc-hook-…'. */
.pick .head .grow { flex: 1 0 100%; min-width: 0; order: 3;
  white-space: normal; overflow-wrap: anywhere; }

/* One written ad, open for editing. Five of these stack under each video, so
   the chosen one has to be readable at a glance from the radio alone. */
.variant { border: 1px solid var(--rule); border-radius: var(--r-md);
  padding: var(--s-md); display: grid; gap: var(--s-sm); background: var(--paper); }
.variant.is-picked { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.variant > header { display: flex; align-items: baseline; gap: var(--s-sm); }
.variant > header input { flex: none; margin: 0; align-self: center; }
.variant > header b { font-size: 14px; }
.variant > header .caption { flex: 1; min-width: 0; }
.variant textarea { min-height: 132px; }
.variant .count { font-family: var(--font-code); font-size: 11px; color: var(--muted); }
.variant .count.is-over { color: var(--danger); }

/* The video and its five drafts, side by side while there is room. */
.video-copy { display: grid; grid-template-columns: 220px minmax(0, 1fr);
  gap: var(--s-lg); align-items: start; }
.video-copy .drafts { display: grid; gap: var(--s-md); min-width: 0; }
.video-copy video { width: 100%; border-radius: var(--r-md); background: var(--ink); display: block; }
@media (max-width: 820px) {
  .video-copy { grid-template-columns: minmax(0, 1fr); }
}

/* ---- image QC verdicts ------------------------------------------------- */
/* A flagged slide has to be obvious from across the grid — the whole point is
   that nobody was looking. Colour alone would not survive a screenshot, so the
   card is also outlined and the verdict is written out. */
.slide-card.is-fail { border-color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger); }
.slide-card.is-warn { border-color: var(--warn); }
.qc-flag { display: block; margin-top: var(--s-xs); font-family: var(--font-code);
  font-size: 11px; line-height: 1.45; }
.qc-flag.is-fail { color: var(--danger); }
.qc-flag.is-warn { color: var(--warn); }
.qc-flag b { font-weight: 600; }
.qc-summary { display: flex; gap: var(--s-md); align-items: baseline; flex-wrap: wrap; }
.qc-summary .count { font-family: var(--font-code); font-size: 12px; }
