@media (max-width: 1080px) {
  .board { grid-template-columns: 200px minmax(0, 1fr) 260px; }
  .rail, .side { padding: 14px 12px; }
}

/* ── Phone: the canvas is the app, the panels are drawers ──────────────────
   Stacking three scrolling columns puts the stage below a wall of controls,
   which is the opposite of what someone making a quick collage needs. Instead
   the stage owns the viewport and each panel becomes a bottom sheet, one at a
   time, reachable from a fixed tab bar within thumb range. */
@media (max-width: 780px) {
  .board {
    display: block;
    min-height: calc(100dvh - 56px);
    background: var(--s-surround);
  }
  .stage-wrap {
    padding: 12px;
    min-height: calc(100dvh - 56px - var(--sheet-peek, 56px));
  }

  .rail, .side {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 40;
    max-height: 62dvh;
    overflow-y: auto;
    padding: 16px 16px calc(16px + env(safe-area-inset-bottom));
    background: var(--s-panel);
    border-top: 1px solid var(--b-subtle);
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -8px 28px rgba(0,0,0,.16);
    transform: translateY(100%);
    transition: transform .22s var(--ease-out);
  }
  .rail[data-open], .side[data-open] { transform: translateY(0); }

  /* One sheet at a time: a second open sheet would cover the canvas entirely. */
  .sheet-tabs {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 50;
    display: flex;
    gap: 8px;
    padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
    background: var(--s-panel);
    border-top: 1px solid var(--b-subtle);
  }
  .sheet-tabs button {
    flex: 1;
    min-height: 44px;            /* WCAG 2.5.8 floor is 24px; 44 is thumb-comfortable */
    font: inherit; font-size: .82rem; font-weight: 600;
    border: 1px solid var(--b-control);
    border-radius: 10px;
    background: transparent;
    color: var(--t-primary);
  }
  .sheet-tabs button[aria-expanded="true"] {
    background: var(--t-primary); color: #fff; border-color: var(--t-primary);
  }
  .sheet-close {
    position: sticky; top: 0; z-index: 1;
    display: block; min-height: 44px;
    /* Pull out to the sheet's padding so the bar spans full width, then push the
       content clear of it. Without the bottom margin the first heading scrolls
       under an opaque sticky bar and reads as clipped. */
    margin: -16px -16px 18px;
    width: calc(100% + 32px);
    padding: 12px;
    border: 0; border-bottom: 1px solid var(--b-hairline);
    background: var(--s-panel); color: var(--t-secondary);
    font: inherit; font-size: .82rem; cursor: pointer;
  }
  .rail .grp:first-of-type, .side .side-head { margin-top: 0; }

  /* Controls get thumb-sized rather than mouse-sized. */
  .chip { min-height: 36px; padding: 8px 13px; }
  .thumb-x { opacity: 1; width: 26px; height: 26px; }   /* no hover on touch */
  input[type="range"] { height: 32px; }
  .strip { grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); }
}

@media (min-width: 781px) { .sheet-tabs, .sheet-close { display: none; } }

/* ── Reset & base ──────────────────────────────────────────── */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

/*
 * ── Design tokens ─────────────────────────────────────────────
 *
 * Canonical tokens (colors, font, type scale, spacing, radii) come from the CDN:
 *   https://cdn.neorgon.org/v1.0.0/styles/base.css   (linked in index.html)
 * Do NOT redeclare them here — a local copy is how the fleet drifted. The block
 * below holds only what base.css does not define, plus the per-site accent.
 *
 * Motion: base.css still ships --ease-snap (bounce) for legacy sites, but it is
 * deprecated for new work (impeccable law: ease-out exponential, no bounce).
 * Use --ease-out below.
 */

:root {
  /* Per-site identity — set to this site's hub card accent (PROJECTS.md section 4) */
  --accent: #f43f5e;
  --accent-bright: #fb7185;

  /* Site extras base.css does not define */
  --surface-toast: #1a1730;
  --danger: #e11d48;
  --danger-hover: #f43f5e;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --control-height: 44px;
  --control-height-sm: 36px;
  --shadow-card: 0 12px 28px rgba(15, 23, 42, 0.5);
  --shadow-modal: 0 24px 48px rgba(2, 6, 23, 0.58);
  --z-sticky-header: 200;
  --z-modal: 400;
  --z-toast: 500;
}

/* Author display values (e.g. .section/.stack flex) would otherwise defeat the
   hidden attribute — restore its authority once, globally. */
[hidden] { display: none !important; }

html { height: 100%; }
body {
  font-family: var(--font);
  background: var(--bg);
  min-height: 100%;
  color: var(--text-primary);
  display: flex; flex-direction: column;
}

body.modal-open {
  overflow: hidden;
}

main#main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: 100%;
}

/* ── Layout ────────────────────────────────────────────────── */
/*
 * GOTCHA: body { display:flex; flex-direction:column } + margin: 0 auto
 * on a child collapses its width — always pair with width: 100%.
 *
 * GOTCHA: External images (YouTube ggpht, Gravatar, etc.) may block loading
 * when the Referer header points to localhost or an unknown origin. Fix:
 * 1. Add <meta name="referrer" content="no-referrer"> in <head> (global)
 * 2. Or add referrerpolicy="no-referrer" on each <img> tag
 */
.container {
  max-width: 900px;
  width: 100%;
  margin: 0 auto;
  padding: var(--space-6);
  flex: 1;
}

/* Vertical rhythm: use inside .container or nested regions */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}
.stack--tight { gap: var(--space-4); }
.stack--loose { gap: var(--space-8); }

/* Page section: title row + body (replaces “card everything” for grouping) */
.section {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.section__header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
}
.section__titles {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.section__title {
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-primary);
}
.section__lead {
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: 1.45;
  max-width: 52ch;
}
.section__lead code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
  font-size: 0.92em;
  color: var(--text-secondary);
}
.stack > .card { margin-bottom: 0; }
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* ── Header ────────────────────────────────────────────────────
 * Owned by the Neorgon Header Kit (css/neorgon-header.css — canonical
 * source: packages/neorgon-ui/header/). Do NOT style .header-bar,
 * .header-logo*, .header-title-link, .header-subtitle, .header-right,
 * .header-actions, or .header-home here. Auth styles (.auth-*) stay
 * site-owned below.
 */
nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ── Buttons (canonical) ─────────────────────────────────────
 * Use .btn + a variant. Aliases: .nav-link = toolbar ghost; .auth-* map below.
 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--control-height);
  padding: 0 var(--space-4);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-primary);
  transition:
    background-color var(--dur),
    color var(--dur),
    border-color var(--dur),
    box-shadow var(--dur),
    transform var(--dur-fast);
  -webkit-tap-highlight-color: transparent;
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
.btn--sm {
  min-height: var(--control-height-sm);
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
}
.btn--block { width: 100%; }
.btn--icon {
  min-width: var(--control-height);
  padding: 0;
}
.btn--primary {
  background: var(--accent);
  color: #fff;
  border-color: transparent;
}
.btn--primary:hover { background: var(--accent-bright); }
.btn--secondary {
  background: var(--surface-2);
  color: var(--text-primary);
  border-color: var(--border-strong);
}
.btn--secondary:hover {
  background: rgba(255, 255, 255, 0.1);
}
.btn--ghost {
  background: transparent;
  color: rgba(255,255,255,0.92);
  border-color: rgba(255,255,255,0.18);
}
.btn--ghost:hover {
  background: rgba(255,255,255,0.1);
  color: #fff;
}
.btn--danger {
  background: var(--danger);
  color: #fff;
  border-color: transparent;
}
.btn--danger:hover { background: var(--danger-hover); }

/* Toolbar ghost (header nav) — same as .btn.btn--ghost.btn--sm */
.nav-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-height);
  padding: 0 var(--space-3);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--radius-sm);
  background: transparent;
  color: rgba(255,255,255,0.92);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  transition: background-color var(--dur), color var(--dur), border-color var(--dur);
}
.nav-link:hover {
  background: rgba(255,255,255,0.1);
  color: #fff;
}

.auth-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--control-height);
  min-height: var(--control-height);
  padding: 0;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--radius-sm);
  background: transparent;
  color: rgba(255,255,255,0.92);
  cursor: pointer;
  font-family: inherit;
  transition: background-color var(--dur), color var(--dur), border-color var(--dur);
}
.auth-toggle:hover {
  background: rgba(255,255,255,0.1);
  color: #fff;
}
.auth-toggle svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  display: block;
}
.auth-toggle.logged-in { color: var(--accent); }
.auth-toggle.logged-in svg circle:nth-of-type(2) {
  fill: currentColor;
  stroke: none;
}

/* ── Sheet (inline panel under header) — not a modal ─────────
 * Use for auth, filters, compact forms. No backdrop; page scrolls.
 * For blocking overlays use .modal below.
 */
.auth-panel {
  background: rgba(255,255,255,0.02);
  border-bottom: 1px solid var(--border-subtle);
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease-out;
}
.auth-panel.open { max-height: 300px; }
.auth-panel-inner {
  padding: var(--space-6);
  max-width: 400px;
  margin: 0 auto;
}
.auth-tabs {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.auth-tab {
  flex: 1;
  min-height: var(--control-height-sm);
  padding: 0 var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  transition: background-color var(--dur), color var(--dur), border-color var(--dur);
}
.auth-tab.active {
  background: var(--surface-2);
  color: var(--text-primary);
  border-color: var(--border-strong);
}
.auth-form input {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-family: inherit;
}
.auth-submit {
  width: 100%;
  min-height: var(--control-height);
  padding: 0 var(--space-4);
  border: none;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-weight: 600;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background-color var(--dur);
}
.auth-submit:hover { background: var(--accent-bright); }
#authUser {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.auth-username {
  color: var(--text-primary);
  font-weight: 600;
}
.auth-logout {
  min-height: var(--control-height-sm);
  padding: 0 var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  transition: background-color var(--dur), color var(--dur), border-color var(--dur);
}
.auth-logout:hover {
  background: var(--surface-2);
  color: var(--text-primary);
}
.auth-divider {
  height: 1px;
  background: var(--border-subtle);
}

/* ── Modal (blocking overlay) ──────────────────────────────── */
.modal[hidden] {
  display: none !important;
}
.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 4, 12, 0.85);
  -webkit-backdrop-filter: blur(10px); /* Safari still needs the prefix */
  backdrop-filter: blur(10px);
}
.modal__dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: min(100%, 520px);
  max-height: min(90vh, 680px);
  overflow: hidden;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-modal);
}
/* For modals holding option grids or editors — narrow dialogs cramp them */
.modal__dialog--wide {
  width: min(100%, 760px);
}
.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--border-subtle);
}
.modal__header h2 {
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text-primary);
}
.modal__body {
  padding: var(--space-6);
  overflow: auto;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: 1.55;
}
.modal__body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
  font-size: 0.9em;
  color: var(--text-primary);
}
.modal__footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--border-subtle);
}

/* ── Card ──────────────────────────────────────────────────── */
/*
 * GOTCHA: backdrop-filter creates a stacking context — dropdowns inside
 * a card can be clipped by a later card's stacking context. Fix by adding
 * position: relative; z-index: 10 to the card that owns the open dropdown.
 *
 * Default: static surface (no hover lift — avoids generic “dashboard demo”).
 * Use .card--interactive for raised hover + entrance motion.
 *
 * GOTCHA: a <button> or <a> used AS a card does not inherit body text color —
 * buttons default to canvas text (near-black), rendering invisible on the dark
 * bg. When a card is an interactive element, set color: var(--text-primary)
 * and font-family: var(--font) explicitly on it.
 */
.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
  backdrop-filter: blur(10px);
  transition: border-color var(--dur), box-shadow var(--dur);
}
.card:hover {
  border-color: var(--border-strong);
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.45);
}
.card--interactive {
  transition:
    transform var(--dur) ease-out,
    box-shadow var(--dur) ease-out,
    border-color var(--dur);
  animation: fadeIn 0.35s ease-out both;
}
.card--interactive:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-card);
  border-color: var(--border-strong);
}
.card--enter {
  animation: fadeIn 0.35s ease-out both;
}
.card--flat:hover {
  box-shadow: none;
}
/* Card with an action row, in an equal-height grid: pin the toolbar to the
   bottom so buttons align across cards whose text wraps differently. */
.card--actions {
  display: flex;
  flex-direction: column;
}
.card--actions > .toolbar:last-child {
  margin-top: auto;
}

/* ── Button press feedback ─────────────────────────────────── */
button:active,
.btn:active,
.nav-link:active,
.auth-toggle:active,
.auth-tab:active,
.auth-submit:active,
.auth-logout:active {
  transform: scale(0.98);
  transition-duration: var(--dur-fast);
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Skeleton loading ──────────────────────────────────────── */
@keyframes shimmer { to { background-position: -200% 0; } }
.skeleton {
  background: linear-gradient(90deg, var(--surface-1) 25%, var(--surface-2) 50%, var(--surface-1) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s ease-in-out infinite;
  border-radius: var(--radius);
}

/* ── Toast ─────────────────────────────────────────────────── */
.toast {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  z-index: var(--z-toast);
  max-width: min(360px, calc(100vw - var(--space-8)));
  background: var(--surface-toast);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-primary);
  box-shadow: var(--shadow-card);
  pointer-events: none;
  transform: translateY(8px);
  opacity: 0;
  transition: opacity 0.2s ease-out, transform 0.2s ease-out;
}
.toast.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ── Footer ────────────────────────────────────────────────────
   Owned by the Neorgon Footer Kit (css/neorgon-footer.css).
   Don't add .neo-footer rules here — edit packages/neorgon-ui/footer/
   and re-run sync-footer.sh. */

/* ── Focus styles ──────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 2px;
}

/* ── Skip link ─────────────────────────────────────────────── */
.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-4);
  z-index: 1000;
  padding: var(--space-2) var(--space-4);
  background: var(--accent-bright);
  color: #000;
  font-weight: 600;
  font-size: var(--text-sm);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  text-decoration: none;
  transition: top var(--dur);
}
.skip-link:focus { top: 0; }

/* ── Reduced motion ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .card--interactive:hover { transform: none; }
}

/* ── Responsive ────────────────────────────────────────────── */
@media (max-width: 600px) {
  .container { padding: var(--space-4); }
  .toast {
    left: var(--space-4);
    right: var(--space-4);
    max-width: none;
  }
}


/* ══ Editor light dialect ═════════════════════════════════════════════════
   SIGNED in docs/design/dialects.md 2026-08-17.

   Every neutral here is strictly R=G=B. A tinted grey induces its complement
   into adjacent photographs through chromatic induction, which in a tool whose
   job is judging images is a correctness defect and not a matter of taste.

   The canvas surround is #CACACA (Munsell N8), the print industry's surround
   for colour comparison. It is deliberately NOT white: a white field makes
   users systematically over-brighten every photo they edit.
   ════════════════════════════════════════════════════════════════════════ */
:root {
  color-scheme: light;

  --s-page:     #F2F2F2;   /* chrome behind panels; not white, so panels read as objects */
  --s-panel:    #FFFFFF;   /* narrow strips only, never adjacent to a photo */
  --s-sunken:   #E8E8E8;   /* wells and tracks; in light themes recession goes darker */
  --s-surround: #CACACA;   /* THE CANVAS SURROUND. Munsell N8. */

  --b-hairline: #E2E2E2;
  --b-subtle:   #D4D4D4;   /* thumbnail keylines, panel edges */
  --b-control:  #6E6E6E;   /* the one border clearing 3:1 on every surface incl. surround */

  --t-primary:   #1A1A1A;  /* 17.40:1 on panel, 15.55 on page */
  --t-secondary: #595959;  /*  7.00:1 on panel,  5.72 on sunken */
  --t-disabled:  #9E9E9E;  /*  2.68:1, exempt under SC 1.4.3 */

  /* Alias EVERY colour token base.css defines. Missing one is not a partial
     override, it is white-on-white: --text-primary alone left every chip, button
     and select painting #f9f9f9 on a white panel. */
  --bg:              var(--s-page);
  --surface-1:       var(--s-panel);
  --surface-2:       var(--s-sunken);
  --text-primary:    var(--t-primary);
  --text-secondary:  var(--t-secondary);
  --text-muted:      var(--t-secondary);
  --border:          var(--b-subtle);
  --border-strong:   var(--b-control);
  --border-subtle:   var(--b-hairline);

  --sh-raised:   0 1px 2px rgba(0,0,0,.10), 0 0 0 1px rgba(0,0,0,.06);
  --sh-artboard: 0 2px 8px rgba(0,0,0,.18);
  --sh-keyline:  inset 0 0 0 1px var(--b-subtle);
}

/* base.css paints the fleet dark; this dialect owns its own page surface. */
html, body { background: var(--s-page); color: var(--t-primary); }

/* The header kit is dark-by-design, so this site declares its own light bar.
   data-header-skin="custom" is the one sanctioned exception to "no site-local
   header CSS"; data-season="off" keeps an armed seasonal theme from repainting
   a colour-judging surface. */
html:not([data-theme]) .header-bar[data-header-skin="custom"] {
  --header-bg-start: #FFFFFF;
  --header-bg-mid:   #FAFAFA;
  --header-bg-end:   #F2F2F2;
  --header-accent:   #1A1A1A;
  --header-text:     #1A1A1A;
  --header-text-dim: #595959;
  --header-icon-color: #1A1A1A;
  --header-border:        #E2E2E2;
  --header-border-strong: #D4D4D4;
  --header-control-border:#6E6E6E;
  --header-menu-bg:    #FFFFFF;
  --header-menu-hover: #EDEDED;
  --header-edge-from:  #E2E2E2;
  --header-edge-to:    #D4D4D4;
}

/* ══ Mosaic ═══════════════════════════════════════════════════════════════
   Tokens come from the CDN base.css. Nothing here redeclares a colour, type
   or spacing token; --accent in the block above is the one identity knob.
   ════════════════════════════════════════════════════════════════════════ */

#main { padding: 0; }

.board {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr) 300px;
  gap: 1px;
  background: var(--b-hairline);
  min-height: calc(100dvh - 56px - 70px);
}

.rail, .side { background: var(--s-panel); padding: 18px 16px; overflow-y: auto; }
.side { display: flex; flex-direction: column; gap: 14px; }

.grp { margin-bottom: 20px; }
.grp-t {
  font-size: .78rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-muted); margin: 0 0 10px; font-weight: 700;
}
.lab {
  display: block; font-size: .78rem; color: var(--text-muted);
  margin: 12px 0 5px;
}
.lab b { color: var(--accent); font-variant-numeric: tabular-nums; }
.hint { font-size: .75rem; color: var(--text-muted); margin: 9px 0 0; line-height: 1.45; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  font: inherit; font-size: .78rem; padding: 6px 11px; border-radius: 999px;
  border: 1px solid var(--border); background: transparent; color: var(--text-primary);
  cursor: pointer; transition: border-color .18s var(--ease-out), color .18s var(--ease-out);
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip.is-on { border-color: var(--t-primary); background: var(--t-primary); color: #fff; }
.chip--go { border-color: var(--accent); color: var(--accent); }
.chip:focus-visible, .thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

input[type="range"] { width: 100%; accent-color: var(--accent); }
input[type="color"] {
  width: 100%; height: 32px; padding: 0; border: 1px solid var(--border);
  border-radius: 6px; background: transparent; cursor: pointer;
}
select {
  width: 100%; font: inherit; font-size: .85rem; padding: 7px 9px;
  border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-primary);
}

/* ── stage ── */
.stage-wrap {
  display: grid; place-items: center; padding: 20px; min-height: 340px;
  background: var(--s-surround);   /* Munsell N8, the judging surround */
}
.stage-box { position: relative; display: grid; place-items: center; width: 100%; height: 100%; }
#stage {
  border-radius: 10px; box-shadow: var(--sh-artboard);
  touch-action: none;   /* the canvas owns pan and pinch, not the page */ max-width: 100%;
}
.empty {
  position: absolute; inset: 0; margin: auto; width: min(78%, 340px); height: fit-content;
  display: grid; gap: 6px; padding: 22px; border-radius: 12px; cursor: pointer;
  border: 2px dashed var(--b-control); background: color-mix(in srgb, var(--s-panel) 88%, transparent);
  color: var(--text-primary); font: inherit; text-align: center;
}
.empty strong { font-size: 1rem; }
.empty span { font-size: .8rem; color: var(--text-muted); }
.empty:hover { border-color: var(--accent); }
body.is-dropping .empty { border-color: var(--accent); }

/* ── photo strip ── */
.side-head { display: flex; align-items: center; gap: 8px; }
.count { font-size: .78rem; color: var(--text-muted); margin-right: auto; }
.strip {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px;
}
.thumb {
  position: relative; aspect-ratio: 1; border-radius: 8px; overflow: hidden;
  border: 2px solid transparent; cursor: grab; background: var(--s-sunken);
  box-shadow: var(--sh-keyline);
}
.thumb canvas { width: 100%; height: 100%; display: block; }
.thumb.is-sel { border-color: var(--t-primary); box-shadow: 0 0 0 2px #fff inset; }
.thumb-x {
  position: absolute; top: 3px; right: 3px; width: 20px; height: 20px; line-height: 1;
  border: 0; border-radius: 50%; background: rgba(0,0,0,.62); color: #fff;
  font-size: 15px; cursor: pointer; opacity: 0; transition: opacity .15s var(--ease-out);
}
.thumb:hover .thumb-x, .thumb-x:focus-visible { opacity: 1; }
.thumb-cut {
  position: absolute; left: 3px; bottom: 3px; font-size: .58rem; letter-spacing: .06em;
  padding: 1px 5px; border-radius: 4px; background: var(--accent); color: #fff;
}

.ins { border-top: 1px solid var(--border); padding-top: 14px; }

@media (max-width: 1080px) {
  .board { grid-template-columns: 1fr; }
  .rail, .side { max-height: none; }
  .stage-wrap { order: -1; }
}
@media (prefers-reduced-motion: reduce) {
  .chip, .thumb-x { transition: none; }
}

/* Chrome paints the colour input's wrapper white unless the swatch is styled. */
input[type="color"]::-webkit-color-swatch-wrapper { padding: 3px; }
input[type="color"]::-webkit-color-swatch { border: 0; border-radius: 4px; }

.chip[disabled] { opacity: .38; cursor: not-allowed; }
.chip[disabled]:hover { border-color: var(--border); color: var(--text-primary); }

#otext {
  width: 100%; font: inherit; font-size: .85rem; padding: 8px 9px; resize: vertical;
  border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-primary);
}
