/* GENERATED by `just css-bundle` — do not edit.
   Sources are static/css/*.css; edit those and rebuild. */

/* ---- fonts.css ---- */
/* Self-hosted variable fonts. No CDN, no render-blocking third party.
   Fraunces = display serif (engraved, high contrast). Inter = UI/body.
   Both are variable (weight axis); Fraunces also carries opsz/SOFT/WONK. */

/* Fraunces — latin */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/static/fonts/fraunces-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
    U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Fraunces — latin extended */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/static/fonts/fraunces-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

/* Inter — latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/static/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
    U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Inter — latin extended */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/static/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

/* ---- tokens.css ---- */
/* Marble Gallery design tokens — see docs/feature/design-system.md.
   Raw palette is fixed; the semantic layer flips for dark mode.
   Contrast notes (verified): brass on onyx 6.6:1, onyx on brass 6.6:1,
   ivory on onyx 17.7:1, brass-deep on ivory 4.7:1. Brass text on a
   light surface is NOT readable — use --accent-ink there. */
:root {
  /* Raw palette */
  --onyx: #101014;
  --onyx-soft: #191920;
  --onyx-lift: #23232c;
  --onyx-line: #2f2f3a;
  --ivory: #faf7f0;
  --alabaster: #f4f0e7;
  --porcelain: #ebe5d9;
  --brass: #b8924d;
  --brass-bright: #d4af6a;
  --brass-deep: #8a6a2e;
  --bronze-smoke: #6b5b45;
  --vein: rgba(16, 16, 20, 0.06);
  --vein-dark: rgba(250, 247, 240, 0.05);

  /* Status (AA on their own tinted grounds) */
  --jade: #2c6b4f;
  --jade-wash: #e4f0e8;
  --jade-ink: #2c6b4f;
  --garnet: #9b2c2c;
  --garnet-wash: #f6e4e4;
  --garnet-ink: #9b2c2c;
  --lapis: #2d4d7a;
  --lapis-wash: #e4ebf5;
  --lapis-ink: #2d4d7a;

  /* Geometry */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 16px;
  --radius-pill: 999px;
  --hairline: 1px;
  --check: 96px; /* marble tile size — museum floor, not race flag */

  /* Motion */
  --t-fast: 120ms;
  --t: 200ms;
  --t-slow: 420ms;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* Type */
  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Semantic — light (the gallery by day) */
  --surface: var(--ivory);
  --surface-raised: #fffdf8;
  --surface-sunken: var(--alabaster);
  --surface-inverse: var(--onyx);
  --ink: #16161c;
  --ink-muted: #55524a;
  --ink-faint: #6f6b63;
  --ink-inverse: var(--ivory);
  --line: #ddd6c8;
  --line-strong: #c3bba9;
  --accent: var(--brass);
  --accent-hover: var(--brass-bright);
  --accent-ink: #7d5f28; /* accent-colored TEXT on light — AA on both surfaces */
  --on-accent: var(--onyx); /* text sitting on a brass fill */
  --tile-a: var(--ivory);
  --tile-b: var(--porcelain);
  --veining: var(--vein);
  --shadow-sm: 0 1px 2px rgba(16, 16, 20, 0.06),
    0 1px 3px rgba(16, 16, 20, 0.04);
  --shadow-lift: 0 2px 4px rgba(16, 16, 20, 0.05),
    0 8px 24px rgba(16, 16, 20, 0.08);
  --shadow-deep: 0 4px 8px rgba(16, 16, 20, 0.06),
    0 18px 48px rgba(16, 16, 20, 0.14);
  --ring: 0 0 0 3px rgba(184, 146, 77, 0.38);
  /* Stone finish: raking light across polished marble, and how the
     grain texture composites. Flipped per theme so marble.css needs no
     theme-aware selectors of its own. */
  --sheen-hi: rgba(255, 255, 255, 0.5);
  --sheen-lo: rgba(16, 16, 20, 0.06);
  --grain-blend: multiply;
  --grain-opacity: 0.05;

  /* Aliases for ~60 inline styles in admin templates that reference
     --admin-* names which were never defined anywhere — that text was
     silently falling back to inherit. Retire them as those templates
     get rebuilt in later steps. */
  --admin-text-muted: var(--ink-muted);
  --admin-accent: var(--accent);
  --admin-border: var(--line);
  --admin-bg: var(--surface-sunken);
}

/* Semantic — dark (the gallery at night). Applied by preference, then
   overridden by the explicit toggle in either direction. */
@media (prefers-color-scheme: dark) {
  :root:not([data-dark='false']) {
    --surface: var(--onyx);
    --surface-raised: var(--onyx-soft);
    --surface-sunken: #0b0b0e;
    --surface-inverse: var(--ivory);
    --ink: #f2eee5;
    --ink-muted: #b0aa9c;
    --ink-faint: #8d8779;
    --ink-inverse: var(--onyx);
    --line: var(--onyx-line);
    --line-strong: #3d3d4a;
    --accent: var(--brass);
    --accent-hover: var(--brass-bright);
    --accent-ink: var(--brass-bright);
    --tile-a: var(--onyx);
    --tile-b: var(--onyx-soft);
    --veining: var(--vein-dark);
    --jade-wash: #16281f;
    --garnet-wash: #2b1616;
    --lapis-wash: #16202e;
    --jade-ink: #6fbf95;
    --garnet-ink: #e39a9a;
    --lapis-ink: #93b6e6;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
    --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.4),
      0 8px 24px rgba(0, 0, 0, 0.45);
    --shadow-deep: 0 4px 8px rgba(0, 0, 0, 0.45),
      0 18px 48px rgba(0, 0, 0, 0.6);
    --sheen-hi: rgba(255, 255, 255, 0.07);
    --sheen-lo: rgba(0, 0, 0, 0.4);
    --grain-blend: screen;
    --grain-opacity: 0.07;
  }
}

:root[data-dark='true'] {
  --surface: var(--onyx);
  --surface-raised: var(--onyx-soft);
  --surface-sunken: #0b0b0e;
  --surface-inverse: var(--ivory);
  --ink: #f2eee5;
  --ink-muted: #b0aa9c;
  --ink-faint: #8d8779;
  --ink-inverse: var(--onyx);
  --line: var(--onyx-line);
  --line-strong: #3d3d4a;
  --accent-ink: var(--brass-bright);
  --tile-a: var(--onyx);
  --tile-b: var(--onyx-soft);
  --veining: var(--vein-dark);
  --jade-wash: #16281f;
  --garnet-wash: #2b1616;
  --lapis-wash: #16202e;
  --jade-ink: #6fbf95;
  --garnet-ink: #e39a9a;
  --lapis-ink: #93b6e6;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.45);
  --shadow-deep: 0 4px 8px rgba(0, 0, 0, 0.45), 0 18px 48px rgba(0, 0, 0, 0.6);
  --sheen-hi: rgba(255, 255, 255, 0.07);
  --sheen-lo: rgba(0, 0, 0, 0.4);
  --grain-blend: screen;
  --grain-opacity: 0.07;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --t-fast: 0ms;
    --t: 0ms;
    --t-slow: 0ms;
  }
}

/* Icons. Rendered server-side as <svg class="ico"> by internal/icons;
   they inherit color, so a parent's `color` is all that styles them.
   Default tracks the text it sits beside; the size classes are for the
   deliberate exceptions. */
.ico {
  width: 1.15em;
  height: 1.15em;
  flex-shrink: 0;
  vertical-align: -0.18em;
  color: inherit;
}
.ico-xs { width: 14px; height: 14px; }
.ico-sm { width: 16px; height: 16px; }
.ico-md { width: 20px; height: 20px; }
.ico-lg { width: 24px; height: 24px; }
.ico-xl { width: 32px; height: 32px; }
/* The large cuts only appear in centred empty states. */
.ico-2xl,
.ico-3xl { display: block; margin: 0 auto 1rem; }
.ico-2xl { width: 48px; height: 48px; }
.ico-3xl { width: 64px; height: 64px; }
.ico-ghost { opacity: 0.35; }
.star-on { color: var(--accent); }
.star-off { color: var(--line-strong); }

/* ---- motion.css ---- */
/* Motion primitives — shared by landing, admin and the future portal.
   Two rules govern everything here:

   1. Nothing is hidden unless script can show it again. Every hidden
      state sits behind `html.anim`, set by the inline head script before
      first paint and dropped by a watchdog if reveal.js never arrives.
      With scripting off the page simply renders in its finished state.
   2. prefers-reduced-motion removes the movement, never the content. */

/* --reveal-op is an element's own resting opacity, and revealing has to
   restore that rather than assume 1: `.anim .reveal.is-in` outranks a
   plain `.rule-brass { opacity: .7 }`, so a hard 1 would quietly brighten
   every decorative element the moment it was revealed. It is read with a
   fallback and never declared here — declaring it on `.reveal` would
   make the fix depend on which stylesheet the page loads last. */
.reveal { --reveal-i: 0; }

.anim .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity var(--t-slow) var(--ease-out),
    transform var(--t-slow) var(--ease-out);
  transition-delay: calc(var(--reveal-i) * 90ms);
}

.anim .reveal.is-in {
  opacity: var(--reveal-op, 1);
  transform: none;
}

/* A group staggers its own children, so a card grid arrives in sequence
   instead of as one block. The indices are CSS rather than JS, so the
   delay is already right on the first frame — no reflow, no flicker. */
.reveal-group > *:nth-child(2) { --reveal-i: 1; }
.reveal-group > *:nth-child(3) { --reveal-i: 2; }
.reveal-group > *:nth-child(4) { --reveal-i: 3; }
.reveal-group > *:nth-child(5) { --reveal-i: 4; }

/* Headline: reveal.js splits the text into .word spans and stamps each
   with its index. The heading is held blank until it has been split, or
   the unsplit line paints for a frame and then jumps as it re-flows. */
.anim [data-split] { opacity: 0; }
.anim [data-split].is-split { opacity: 1; }

.word {
  --reveal-i: 0;
  display: inline-block;
}

.anim .word {
  opacity: 0;
  transform: translateY(0.42em);
  transition:
    opacity var(--t-slow) var(--ease-out),
    transform var(--t-slow) var(--ease-out);
  transition-delay: calc(var(--reveal-i) * 60ms);
}

.anim .word.is-in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .anim .reveal,
  .anim .word,
  .anim [data-split] {
    opacity: var(--reveal-op, 1);
    transform: none;
    transition: none;
  }
}

/* ---- ui.css ---- */
/* Shared UI components — landing, admin, and the future portal all load
   this. Tokens: tokens.css. Buttons v2: struck metal, not flat rectangles
   — layered gradient body, inset top highlight, soft drop, 1px sink on
   press, sheen sweep on hover.

   Contrast rule: a button's label is AA against its own body, always.
   Primary/brass carries ONYX text (6.6:1) — ivory on brass is 2.7:1 and
   is never used. */

.btn {
  --btn-face: var(--surface-raised);
  --btn-edge: var(--line-strong);
  --btn-ink: var(--ink);
  --btn-sink: rgba(16, 16, 20, 0.18);

  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.62em 1.35em;
  border: var(--hairline) solid var(--btn-edge);
  border-radius: var(--radius-pill);
  background: var(--btn-face);
  color: var(--btn-ink);
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 1px 2px rgba(16, 16, 20, 0.12);
  transition: transform var(--t-fast) var(--ease),
    box-shadow var(--t) var(--ease), background var(--t) var(--ease),
    border-color var(--t) var(--ease), color var(--t) var(--ease);
}

.btn:hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4),
    0 4px 10px var(--btn-sink);
  color: var(--btn-ink);
}

.btn:active {
  transform: translateY(1px);
  box-shadow: inset 0 2px 4px var(--btn-sink);
}

.btn:focus-visible {
  outline: none;
  box-shadow: var(--ring), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

.btn[disabled],
.btn[aria-disabled='true'] {
  opacity: 0.5;
  pointer-events: none;
}

/* Sheen: a slow highlight crossing the face on hover. Purely decorative,
   so it sits behind the label and is dropped for reduced motion. */
.btn::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    105deg,
    transparent 30%,
    rgba(255, 255, 255, 0.28) 48%,
    transparent 66%
  );
  transform: translateX(-120%);
  transition: transform var(--t-slow) var(--ease-out);
}
.btn:hover::after { transform: translateX(120%); }

@media (prefers-reduced-motion: reduce) {
  .btn::after { display: none; }
}

/* Variants — each sets its own face/edge/ink so the shared chrome above
   never has to know which one it is. */
.btn-primary {
  --btn-face: linear-gradient(
    180deg,
    var(--brass-bright) 0%,
    var(--brass) 52%,
    var(--brass-deep) 100%
  );
  --btn-edge: var(--brass-deep);
  --btn-ink: var(--onyx);
  --btn-sink: rgba(90, 66, 20, 0.4);
}

.btn-secondary {
  --btn-face: linear-gradient(180deg, var(--onyx-lift) 0%, var(--onyx) 100%);
  --btn-edge: var(--onyx);
  --btn-ink: var(--ivory);
  --btn-sink: rgba(0, 0, 0, 0.45);
}

.btn-danger {
  --btn-face: linear-gradient(180deg, #b83a3a 0%, var(--garnet) 100%);
  --btn-edge: #7d2020;
  --btn-ink: var(--ivory);
  --btn-sink: rgba(90, 20, 20, 0.4);
}

.btn-outline,
.btn-ghost {
  --btn-face: transparent;
  --btn-ink: var(--ink);
  box-shadow: none;
}
.btn-outline { --btn-edge: var(--line-strong); }
.btn-ghost { --btn-edge: transparent; }
.btn-outline:hover,
.btn-ghost:hover {
  --btn-face: var(--surface-sunken);
  --btn-edge: var(--accent);
  box-shadow: 0 4px 10px var(--btn-sink);
}

/* Sizes */
.btn-sm { padding: 0.4em 0.95em; font-size: 0.85rem; }
.btn-lg { padding: 0.8em 1.9em; font-size: 1.05rem; }

.btn .ico { width: 1.05em; height: 1.05em; }

/* ---- ui-forms.css ---- */
/* Custom form controls. The native control stays in the DOM as the
   form's source of truth and is hidden here; these are the visible UI.
   Enhanced by ui.js / ui-select.js / ui-dropzone.js. */

/* The native control stays in the DOM (it is what actually submits) but
   must never take space. !important is deliberate: page-level form CSS
   is more specific than this utility, and a native select left at
   width:100% while absolutely positioned pushed the landing page 600px
   wider than the viewport. */
.sel-native,
.dz-native,
.clr-native {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  margin: -1px !important;
  padding: 0 !important;
  border: 0 !important;
  overflow: hidden;
  clip-path: inset(50%);
  opacity: 0;
  pointer-events: none;
}

/* Floating-label text fields */
.field { position: relative; display: block; }
.field-label {
  position: absolute; left: 0.85rem; top: 0.72rem;
  color: var(--field-label, var(--ink-muted)); font-size: 1rem;
  pointer-events: none; transform-origin: left top;
  transition: transform var(--t) var(--ease-out), color var(--t) var(--ease);
}
.field.is-focus .field-label,
.field.is-filled .field-label { transform: translateY(-0.62rem) scale(0.75); }
.field.is-focus .field-label { color: var(--accent); }
.field .opt { font-size: 0.85em; margin-left: 0.35em; color: inherit; }
.field input,
.field textarea { padding-top: 1.35rem; padding-bottom: 0.4rem; }
.field textarea { padding-top: 1.5rem; }

/* Listbox */
/* min-width: 0 is what makes the truncation below actually bite: a grid
   or flex item's automatic minimum is its max-content width, so a
   nowrap option label widens the track instead of being clipped. */
.sel { position: relative; min-width: 0; }
.sel-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  width: 100%; min-width: 0; padding: 0.65rem 0.8rem;
  background: var(--field-face, var(--surface)); color: var(--field-ink, var(--ink));
  border: var(--hairline) solid var(--field-edge, var(--line-strong));
  border-radius: var(--radius-sm);
  font: inherit; text-align: left; cursor: pointer;
  transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
/* An option's text is whatever the page put in the <option> — on the QR
   designer that is a slug plus a full destination URL, which has no
   break opportunity in it and pushed a 390px viewport to 510px. The
   button truncates; the open list wraps, because there the whole value
   is what the operator is choosing between. */
.sel-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.sel-btn:hover { border-color: var(--accent); }
.sel-btn:focus-visible { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.sel-chev { transition: transform var(--t) var(--ease); opacity: 0.7; }
.sel.is-open .sel-chev { transform: rotate(180deg); }
.sel.is-open .sel-btn { border-color: var(--accent); box-shadow: var(--ring); }

.sel-list {
  position: absolute; z-index: 40; top: calc(100% + 4px); left: 0; right: 0;
  max-height: 15rem; overflow-y: auto; margin: 0; padding: 0.25rem; list-style: none;
  background: var(--surface-raised); color: var(--ink);
  border: var(--hairline) solid var(--line-strong); border-radius: var(--radius);
  box-shadow: var(--shadow-deep);
}
.sel-opt {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.5rem 0.7rem; border-radius: var(--radius-sm);
  font-size: 0.95rem; cursor: pointer; overflow-wrap: anywhere;
}
.sel-opt:hover { background: var(--surface-sunken); }
.sel-opt[aria-selected='true'] {
  background: var(--accent); color: var(--on-accent); font-weight: 600;
}

/* Filter box, added by ui-select-search.js above SEARCH_FROM options.
   Sticky so it survives scrolling a long list. */
.sel-search {
  position: sticky; top: 0; z-index: 1;
  padding: 0.25rem 0.25rem 0.35rem; margin: -0.25rem -0.25rem 0.25rem;
  background: var(--surface-raised);
  border-bottom: var(--hairline) solid var(--line);
}
.sel-search-input {
  width: 100%; padding: 0.45rem 0.6rem; font: inherit; font-size: 0.92rem;
  background: var(--surface); color: var(--ink);
  border: var(--hairline) solid var(--line-strong); border-radius: var(--radius-sm);
}
.sel-search-input:focus-visible { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.sel-empty { padding: 0.6rem 0.7rem; font-size: 0.92rem; color: var(--ink-faint); }

/* Dropzone */
.dz {
  display: flex; flex-direction: column; align-items: center; gap: 0.35rem;
  padding: 1.4rem 1rem; text-align: center; cursor: pointer;
  color: var(--field-ink, var(--ink-muted));
  background: var(--field-face, var(--surface));
  border: 1px dashed var(--field-edge, var(--line-strong));
  border-radius: var(--radius);
  transition: border-color var(--t) var(--ease), background var(--t) var(--ease),
    box-shadow var(--t) var(--ease);
}
.dz:hover, .dz.is-over { border-color: var(--accent); border-style: solid; }
.dz.is-over { box-shadow: var(--ring); }
.dz:focus-visible { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.dz.is-bad { border-color: var(--garnet-ink); }
.dz .ico { opacity: 0.6; }
.dz-prompt { font-size: 0.95rem; }
.dz-link { color: var(--field-accent, var(--accent-ink)); text-decoration: underline; text-underline-offset: 2px; }
.dz-hint { font-size: 0.82rem; opacity: 0.85; }

.dz-list { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 0.5rem; }
/* Inherits the page's ink by default, which on the landing funnel is
   ivory — the same colour as the item's own face. Pin it to the field
   ink so the filename is never invisible. */
.dz-item {
  display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem;
  color: var(--field-ink, var(--ink));
  background: var(--field-face, var(--surface-raised));
  border: var(--hairline) solid var(--field-edge, var(--line)); border-radius: var(--radius-sm);
}
.dz-thumb {
  width: 40px; height: 40px; flex: 0 0 40px; border-radius: var(--radius-sm);
  object-fit: cover; background: var(--surface-sunken);
}
.dz-thumb-doc {
  display: flex; align-items: center; justify-content: center;
  font-size: 0.65rem; font-weight: 700; letter-spacing: 0.06em;
  color: var(--ink-muted);
}
.dz-meta { display: flex; flex-direction: column; min-width: 0; flex: 1; text-align: left; }
.dz-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.9rem; }
.dz-size { font-size: 0.78rem; color: var(--ink-faint); }
.dz-remove {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; cursor: pointer;
  background: transparent; color: var(--ink-muted);
  border: var(--hairline) solid var(--line); border-radius: 50%;
  transition: all var(--t) var(--ease);
}
.dz-remove:hover { background: var(--garnet); color: var(--ivory); border-color: var(--garnet); }
.dz-remove:focus-visible { outline: none; box-shadow: var(--ring); }
.dz-error { margin-top: 0.5rem; font-size: 0.88rem; color: var(--garnet-ink); min-height: 1.2em; }

/* ---- skm-funnel.css ---- */
/* The landing contact block — the gallery at night. Split out of
   dubloons.css so the page shell has room to grow; loaded only by the
   landing page. The bronze edges keep the block legible when the whole
   page is already dark. */
.contact {
  background: var(--onyx); color: var(--ivory); padding: 3.5rem 0 4rem;
  border-top: var(--hairline) solid var(--bronze-smoke);
  border-bottom: var(--hairline) solid var(--bronze-smoke);
}
.contact h2 { color: var(--ivory); }
.contact-inner > p { color: #c6c0b3; margin-bottom: 2rem; }
.funnel-form { display: flex; flex-direction: column; gap: 1.1rem; max-width: 720px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
/* Field chrome for the funnel: the contact block is always the gallery
   at night, so the fields carry their own light palette rather than the
   page's. ui-forms.css reads these. */
.funnel-form {
  --field-face: var(--ivory);
  --field-ink: var(--onyx);
  --field-edge: var(--bronze-smoke);
  --field-label: #6b6558;
  /* The funnel's fields are ivory in BOTH themes, so anything drawn on
     them needs a fixed light-surface accent — the page-level
     --accent-ink flips to bright brass in dark and lands at 1.9:1. */
  --field-accent: #7d5f28;
}
/* Fallback layout for labels ui.js has not enhanced (JS off). */
.funnel-form label:not(.field) {
  display: flex; flex-direction: column; gap: 0.35rem;
  font-size: 0.92rem; letter-spacing: 0.04em; color: #ded8cb;
}
.funnel-form .field-block > label { display: block; margin-bottom: 0.4rem; font-size: 0.92rem; letter-spacing: 0.04em; color: #ded8cb; }
.funnel-form label:not(.field) .opt,
.funnel-form .field-block .opt { color: #a8a294; font-size: 0.85em; }
.funnel-form .field-hint { margin-top: -0.6rem; font-size: 0.85rem; color: #a8a294; }
.funnel-form input, .funnel-form select, .funnel-form textarea {
  font-family: inherit; font-size: 1rem; padding: 0.65rem 0.8rem; width: 100%;
  background: var(--field-face); color: var(--field-ink);
  border: var(--hairline) solid var(--field-edge); border-radius: var(--radius-sm);
}
.funnel-form input:focus, .funnel-form select:focus, .funnel-form textarea:focus {
  outline: none; border-color: var(--brass); box-shadow: var(--ring);
}
.funnel-form textarea { resize: vertical; }
.funnel-form .btn { align-self: flex-start; }
.hp { position: absolute !important; left: -9999px !important; height: 0; width: 0; opacity: 0; }
#lead-status { min-height: 1.4em; font-size: 0.95rem; }
#lead-status.ok { color: #9fd7ae; }
#lead-status.err { color: #e6a9a9; }

@media (max-width: 640px) {
  .field-row { grid-template-columns: 1fr; }
}

/* ---- pirate.css ---- */
/* Dubloons — the night palette and the paintings. This file owns what
   the page LOOKS like: tarnished gold on bone over near-black, and the
   generated brand art (static/img/brand/). dubloons.css owns the page
   shell. The landing pins data-dark, but every override below claims
   both states anyway — this deck has no daytime. */
:root, :root[data-dark="true"], :root[data-dark="false"] {
  --surface: #05080a;
  --surface-raised: #0a0f13;
  --surface-sunken: #030506;
  --ink: #d8d3c4;
  --ink-muted: #97907e;
  --ink-faint: #6a6455;
  --ink-inverse: #05080a;
  --line: rgba(201, 162, 39, 0.16);
  --line-strong: rgba(201, 162, 39, 0.30);
  --accent: #c9a227;
  --accent-hover: #e0bb3f;
  --accent-ink: #e6c655;
  --on-accent: #140e02;
  --btn-ink: #140e02;
  --sheen-hi: rgba(255, 220, 120, 0.22);
  --field-face: #0c1216;
  --field-ink: #d8d3c4;
  --spectral: #35c9b8;
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.55);
  --shadow-md: 0 8px 28px rgba(0, 0, 0, 0.65);
}

/* The deck itself: blackened parchment, tiled faintly. */
body {
  background-color: var(--surface);
  background-image: url('/static/img/brand/texture-md.webp');
  background-size: 780px;
  background-blend-mode: multiply;
}

/* Cards — a vitrine would gleam; these lurk. Gold hairline, black
   glass, and a spectral lift on hover. */
.card {
  background: linear-gradient(180deg, rgba(13, 19, 24, 0.92), rgba(6, 9, 11, 0.96));
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1.4rem 1.4rem 1.5rem;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--t-slow, .35s) var(--ease-out, ease-out),
              box-shadow var(--t-slow, .35s) var(--ease-out, ease-out),
              transform var(--t-slow, .35s) var(--ease-out, ease-out);
}
.card:hover {
  border-color: var(--line-strong);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.7), 0 0 22px rgba(53, 201, 184, 0.10);
  transform: translateY(-3px);
}
/* The same lift again, at the weight it needs to actually happen.
   motion.css lands a revealed element on `transform: none` through
   `.anim .reveal.is-in` — specificity (0,3,0) — and every card on this
   page carries class="card reveal". So the plain `.card:hover` above,
   at (0,2,0), lost the transform and kept only the glow: the cards have
   been lighting without lifting. Nothing errors when that happens,
   which is why it survived the theme rewrite. */
.card.reveal.is-in:hover { transform: translateY(-3px); }
.card h2, .card h3 { color: var(--accent-ink); font-size: 1.25rem; margin-bottom: 0.55rem; }
.card p { color: var(--ink-muted); font-size: 0.97rem; }
.card-art {
  display: block; width: calc(100% + 2.8rem); margin: -1.4rem -1.4rem 1.1rem;
  /* height:auto so the width/height ATTRIBUTES on the tag only reserve
     the box against layout shift, and aspect-ratio still decides the
     rendered shape. Without it the attribute height wins and the card
     art stretches to its full intrinsic height. */
  height: auto;
  border-radius: 9px 9px 0 0; aspect-ratio: 16 / 10; object-fit: cover;
  border-bottom: 1px solid var(--line);
  filter: saturate(0.92);
}

/* The hero painting: the leviathan's eye above our sinking coin, the
   top third left black for the headline. The captain (hero-lg.webp)
   still ships for the pitch deck. A scrim keeps the copy legible. */
.hero-art {
  position: absolute; inset: 0; z-index: -1;
  background: url('/static/img/brand/abyss-lg.webp') center 62% / cover no-repeat;
}
.hero-art::after {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 70% 60% at 50% 78%, rgba(3, 5, 6, 0.82), transparent 70%),
    linear-gradient(180deg, rgba(3, 5, 6, 0.55), rgba(3, 5, 6, 0.15) 40%, rgba(3, 5, 6, 0.88));
}

/* The colours, the ship behind the ritual. */
.how {
  background:
    linear-gradient(rgba(3, 5, 6, 0.86), rgba(3, 5, 6, 0.92)),
    url('/static/img/brand/kraken-lg.webp') center 60% / cover no-repeat;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

/* The black flag between ritual and trade — a band of painting. */
.flag-band {
  height: clamp(140px, 22vw, 240px);
  background: url('/static/img/brand/flag-lg.webp') center 42% / cover no-repeat;
  border-bottom: 1px solid var(--line);
  position: relative;
}
.flag-band::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(3,5,6,0.75), transparent 35%, transparent 70%, rgba(3,5,6,0.75));
}

/* Buttons: gold reads as treasure here, and the outline ghost-glows. */
.btn-primary { text-shadow: none; }
.btn-outline { border-color: var(--line-strong); color: var(--ink); }
.btn-outline:hover { border-color: var(--accent); color: var(--accent-ink); }

/* Steps: gold discs, spectral rail. */
.steps li::before { box-shadow: inset 0 1px 0 rgba(255, 235, 170, 0.4), 0 0 12px rgba(201, 162, 39, 0.35); }
.steps li strong { color: var(--accent-ink); }

/* Forms (skm-funnel.css assumes a lighter raised surface). */
.contact { background: var(--surface-sunken); border-top: 1px solid var(--line); }
/* skm-funnel.css keeps its fields ivory in both themes for the marble
   look; this deck is black water. The custom select and dropzone read
   these vars, so they flip everything at once. */
.funnel-form {
  --field-face: #0c1216;
  --field-ink: var(--ink);
  --field-edge: var(--line-strong);
  --field-label: var(--ink-muted);
  --field-accent: var(--accent-ink);
}
.funnel-form input, .funnel-form select, .funnel-form textarea {
  background: rgba(10, 15, 19, 0.9); color: var(--ink); border-color: var(--line-strong);
}
.funnel-form input:focus, .funnel-form textarea:focus {
  border-color: var(--accent); outline: none;
  box-shadow: 0 0 0 3px rgba(201, 162, 39, 0.18);
}

/* ---- dubloons.css ---- */
/* Dubloons — public splash, page shell. pirate.css owns the palette
   and the paintings; tokens.css still owns type and motion vars. What
   is left here is structure: header, hero, sections, footer. */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; }
body {
  font-family: var(--font-sans);
  background: var(--surface);
  color: var(--ink);
  line-height: 1.65;
}
.wrap { max-width: 1020px; margin: 0 auto; padding: 0 1.25rem; }
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-variation-settings: 'SOFT' 0, 'WONK' 0;
  letter-spacing: -0.005em;
}
h2 { font-size: 1.9rem; margin-bottom: 0.9rem; }
.rule-brass { max-width: 200px; margin: 0 0 1.6rem; }

/* Header */
.topbar {
  border-bottom: var(--hairline) solid var(--line);
  background: rgba(5, 8, 10, 0.88);
  position: sticky; top: 0; z-index: 10;
  backdrop-filter: blur(6px);
}
.topbar-inner { display: flex; align-items: center; justify-content: space-between; padding: 0.85rem 1.25rem; }
.wordmark {
  display: inline-flex; align-items: center; gap: 0.55em;
  font-family: var(--font-display); font-size: 1.3rem;
  letter-spacing: 0.22em; font-weight: 600;
  color: var(--accent-ink); text-decoration: none;
}
.wordmark-coin { width: 28px; height: 28px; border-radius: 50%; box-shadow: 0 0 10px rgba(201,162,39,0.45); }
.topnav { display: flex; align-items: center; gap: 1.4rem; }
.topnav a { color: var(--ink); text-decoration: none; font-size: 0.95rem; }
.topnav a:hover { color: var(--accent-ink); }
.topnav a.btn, .topnav a.btn:hover { color: var(--btn-ink); }

/* Footer links — legible discretion, not low contrast. */
.foot-admin {
  color: var(--ink-muted);
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.foot-admin:hover { color: var(--accent-ink); text-decoration-style: solid; }
.foot-link {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.foot-link:hover { color: var(--accent-ink); }

/* Hero — the captain's painting is full-bleed behind .hero-art. */
.hero { position: relative; isolation: isolate; overflow: hidden; }
.hero-inner { text-align: center; padding: clamp(9rem, 24vw, 15rem) 1.25rem 4.5rem; }
.hero h1 {
  font-size: clamp(2.1rem, 5vw, 3.6rem); line-height: 1.1;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.85);
}
.lede {
  max-width: 640px; margin: 1.5rem auto 2.2rem; font-size: 1.08rem;
  color: var(--ink); opacity: 0.92;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.9);
}
.hero-cta { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }

/* Card grids */
.features {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.25rem; padding-top: 3rem; padding-bottom: 3.5rem;
}

/* The ritual */
.how { padding: 3.5rem 0; }
.steps { position: relative; max-width: 720px; counter-reset: step; list-style: none; }
.steps::before {
  content: ''; position: absolute; left: 1.1rem; top: 1.9rem; bottom: 1.9rem;
  width: var(--hairline);
  background: linear-gradient(180deg, transparent, var(--line-strong) 12%, var(--line-strong) 88%, transparent);
}
.steps li { padding: 0.9rem 0 0.9rem 3.4rem; position: relative; counter-increment: step; border-bottom: var(--hairline) dotted var(--line-strong); }
.steps li:last-child { border-bottom: none; }
.steps li::before {
  content: counter(step); position: absolute; left: 0; top: 0.85rem;
  width: 2.2rem; height: 2.2rem; display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--on-accent); border-radius: 50%;
  font-family: var(--font-display); font-size: 0.95rem; font-weight: 600;
}

/* The trade */
.services { padding: 3.5rem 1.25rem; }
.services .features { padding-top: 0; }

/* Footer */
.footer { border-top: var(--hairline) solid var(--line); background: var(--surface-sunken); }
.footer-inner { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; padding: 1.2rem 1.25rem 2rem; color: var(--ink-muted); font-size: 0.9rem; }
.foot-tag { font-family: var(--font-display); font-style: italic; color: var(--accent-ink); }

@media (max-width: 640px) {
  .topnav a:not(.btn) { display: none; }
  .hero-inner { padding-top: clamp(7rem, 40vw, 10rem); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .card:hover { transform: none; }
}

/* ---- fleet.css ---- */
/* Dubloons — the coin showcase ("On the bench").
   Its own file rather than more of dubloons.css, which is at its line
   budget. Palette and card treatment still come from pirate.css; what
   is here is the coin itself, which is the one element on the page that
   has to look like an object rather than a panel. */

.fleet { padding: 3.5rem 1.25rem 1rem; }
.fleet-lede {
  max-width: 620px;
  margin: 0 0 2.4rem;
  color: var(--ink-muted);
}

.fleet-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 2rem 1.75rem;
}

/* A column, so the mark can be pushed to the bottom. The grid already
   stretches every card to the tallest, but the blurbs differ by two
   lines and the specs wrap differently — left alone, the three brass
   rules land at three different heights and the row reads as crooked. */
.coin-card {
  margin: 0;
  text-align: center;
  display: flex;
  flex-direction: column;
}
.coin-card figcaption {
  display: flex;
  flex-direction: column;
  flex: 1;
}
.coin-blurb { flex: 1; }

/* The coin sits on nothing. No card, no plate, no border — the assets
   are transparent outside the struck edge, and a frame around them
   would make three photographs of coins instead of three coins. The
   only ground is the glow it throws on the deck beneath it. */
.coin-shot {
  position: relative;
  margin: 0 auto 1.25rem;
  max-width: 300px;
}
.coin-shot::after {
  /* Lamplight pooling under the metal, not a drop shadow: the coins
     already carry their own shadow from the strike render. */
  content: '';
  position: absolute;
  left: 12%; right: 12%; bottom: 2%;
  height: 14%;
  background: radial-gradient(ellipse at center,
              rgba(201, 162, 39, 0.30), transparent 70%);
  filter: blur(10px);
  z-index: -1;
}
.coin-shot img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.75));
  transition: transform var(--t-slow, .35s) var(--ease-out, ease-out);
}
.coin-card:hover .coin-shot img { transform: translateY(-4px) scale(1.02); }

.coin-card h3 {
  font-size: 1.15rem;
  color: var(--accent-ink);
  margin-bottom: 0.2rem;
}
/* --ink-muted, not --ink-faint. The faint token is 3.5:1 on this
   surface, and this line is 13px uppercase — the exact case WCAG wants
   4.5:1 for. The muted token clears it at 6.3:1 and still reads as a
   caption next to the title above it. */
.coin-spec {
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 0.7rem;
}
.coin-blurb {
  font-size: 0.95rem;
  color: var(--ink);
  opacity: 0.9;
  margin-bottom: 0.9rem;
}

/* The spec line is two lines on some coins and one on others. Reserving
   the taller of the two keeps the blurbs starting level without forcing
   every spec to fit one line. */
.coin-spec { min-height: 2.4em; }

/* The payload, printed the way it is struck: uppercase, monospaced,
   so the string on screen is visibly the string on the metal. */
.coin-mark {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  color: var(--accent);
  border-top: var(--hairline) solid var(--line);
  padding-top: 0.7rem;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .coin-shot img,
  .coin-card:hover .coin-shot img { transition: none; transform: none; }
}

/* ---- strike.css ---- */
/* Dubloons — "Fresh from the strike": the first coins, photographed.
   The photographs are bright — struck brass on a white bench — on a
   page that is otherwise near-black. They are framed rather than
   blended: each sits in its own hairline card with a warm shadow, so
   the eye reads "a photograph pinned to the deck" instead of a hole in
   the theme. Nothing in this section is rendered, the copy says so, and
   the treatment must not pretend otherwise: no drop-shadow cut-outs, no
   lamplight, no coin floating on nothing. */

.strike {
  padding: 3.5rem 1.25rem 1.5rem;
  border-top: 1px solid var(--line);
}
.strike-lede {
  max-width: 620px;
  margin: 0 0 2rem;
  color: var(--ink-muted);
}

/* The reel. A still photograph until it moves, and a still again for
   anyone who asked for reduced motion (landing.js drops the autoplay).
   Capped so a wide screen does not get a wall of white bench. */
.strike-reel {
  margin: 0 0 2rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: #0b0d0f;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.6);
}
.strike-video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  max-height: 68vh;
  object-fit: cover;
  filter: saturate(0.94);
}
.strike-reel figcaption {
  padding: 0.7rem 1rem;
  font-size: 0.9rem;
  font-style: italic;
  color: var(--ink-muted);
  border-top: 1px solid var(--line);
}

/* Three photographs, square, captions beneath. Same auto-fit rhythm as
   the coin showcase below so the two rows line up column for column. */
.strike-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
}
.strike-shot {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-sunken, rgba(255, 255, 255, 0.03));
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5);
}
.strike-shot img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  filter: saturate(0.94);
}
.strike-shot figcaption {
  padding: 0.9rem 1rem 1.1rem;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink);
  opacity: 0.9;
}
.strike-shot figcaption strong {
  display: block;
  margin-bottom: 0.2rem;
  color: var(--accent-ink);
}

/* ---- deep.css ---- */
/* Dubloons — the deep. Leviathan bands, the manifesto that rises out of
   blur, the six answers, the questions, and the text motion the rest
   of the page borrows: gold tide on the headline, a word that turns.
   Same two laws as motion.css: nothing is hidden unless script can
   show it (every hidden state sits behind html.anim), and reduced
   motion removes the movement, never the words. */

/* --- the headline's tide: gold light sweeping the letters --- */
.tide, .tide .word {
  background: linear-gradient(100deg,
    var(--ink) 0%, var(--ink) 38%, var(--accent-ink) 50%, var(--ink) 62%, var(--ink) 100%);
  background-size: 260% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: tide 7s ease-in-out infinite;
}
@keyframes tide { 0% { background-position: 120% 0; } 100% { background-position: -140% 0; } }

.hero-turns { font-family: var(--font-display); font-size: clamp(1.2rem, 2.6vw, 1.7rem); color: var(--ink);
  margin: -0.8rem auto 2rem; text-shadow: 0 1px 14px rgba(0,0,0,.9); }

/* --- the word that turns: "it opens an album / a film / …" ---
   Pure CSS, so it turns with scripting off and never traps a word: the
   list stacks every item in one line box and rolls a window over it. */
.turns { display: inline-block; vertical-align: bottom; height: 1.2em; overflow: hidden; text-align: left; }
.turns-list { display: block; animation: turn 12s steps(6) infinite; }
.turns-list > span { display: block; height: 1.2em; line-height: 1.2; color: var(--accent-ink); white-space: nowrap; }
@keyframes turn { to { transform: translateY(-7.2em); } }
/* The seventh entry repeats the first so the loop's seam is invisible. */

/* --- the deep --- */
.deep { position: relative; isolation: isolate; overflow: hidden;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.deep-art { position: absolute; inset: 0; z-index: -1;
  background: url('/static/img/brand/deep-lg.webp') center 40% / cover no-repeat; }
.deep-art::after { content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(3,5,6,.92), rgba(3,5,6,.55) 45%, rgba(3,5,6,.94)); }
.deep-inner { padding: 6rem 1.25rem 4rem; max-width: 820px; }
.deep-kicker { font-size: .82rem; letter-spacing: .28em; text-transform: uppercase; color: var(--spectral); margin-bottom: 1.4rem; }
.deep-line { font-size: clamp(1.7rem, 4.2vw, 3rem); line-height: 1.12; margin: 0 0 .35em; color: var(--ink);
  text-shadow: 0 2px 30px rgba(0,0,0,.9); }
.deep-line:nth-of-type(2) { color: var(--accent-ink); }
.deep-line:nth-of-type(3) { color: var(--spectral); }
.deep-body { margin-top: 1.6rem; max-width: 640px; color: var(--ink); opacity: .9; font-size: 1.05rem;
  text-shadow: 0 1px 14px rgba(0,0,0,.9); }

/* Rising from the deep: blur and letter-spacing settle as the line
   surfaces. Word stagger comes from the [data-split] split. */
.anim .reveal-deep { opacity: 0; filter: blur(10px); letter-spacing: .06em; transform: translateY(18px);
  transition: opacity .9s var(--ease-out), filter .9s var(--ease-out),
              letter-spacing 1.1s var(--ease-out), transform .9s var(--ease-out); }
.anim .reveal-deep.is-in { opacity: 1; filter: blur(0); letter-spacing: -0.005em; transform: none; }
.anim .reveal-deep:nth-of-type(2) { transition-delay: .18s; }
.anim .reveal-deep:nth-of-type(3) { transition-delay: .36s; }

/* --- what a coin can answer with --- */
.opens-title { font-size: 1.15rem; letter-spacing: .04em; color: var(--ink-muted); margin: 0 0 1.2rem; padding: 0 1.25rem; }
.opens-grid { list-style: none; margin: 0; padding: 0 1.25rem 4.5rem;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: .9rem; }
.opens { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: .8rem;
  padding: 1rem 1.1rem; border: 1px solid var(--line); border-radius: 10px;
  background: rgba(5, 8, 10, .72); backdrop-filter: blur(4px);
  transition: border-color .35s var(--ease-out), box-shadow .35s var(--ease-out); }
.opens:hover { border-color: rgba(53,201,184,.45); box-shadow: 0 0 24px rgba(53,201,184,.12); }
.opens-glyph { grid-row: 1 / 3; font-size: 1.5rem; line-height: 1; color: var(--spectral); padding-top: .15rem;
  text-shadow: 0 0 12px rgba(53,201,184,.55); }
.opens strong { color: var(--accent-ink); font-family: var(--font-display); font-size: 1.05rem; }
.opens span:last-child { color: var(--ink-muted); font-size: .9rem; line-height: 1.45; }

/* --- questions --- */
.faq { padding: 3.5rem 1.25rem 2rem; position: relative; isolation: isolate; }
.faq::before { content: ''; position: absolute; inset: 0; z-index: -1; max-width: none;
  background: linear-gradient(90deg, rgba(3,5,6,.97) 0%, rgba(3,5,6,.9) 55%, rgba(3,5,6,.6) 100%),
              url('/static/img/brand/surface-lg.webp') right center / cover no-repeat; }
.faq-list { max-width: 760px; }
.faq details { border-top: 1px solid var(--line); padding: .2rem 0; }
.faq details:last-child { border-bottom: 1px solid var(--line); }
.faq summary { cursor: pointer; list-style: none; padding: .95rem 2.2rem .95rem 0; position: relative;
  font-family: var(--font-display); font-size: 1.12rem; color: var(--ink); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; position: absolute; right: .2rem; top: .8rem; color: var(--accent);
  font-size: 1.4rem; line-height: 1; transition: transform .35s var(--ease-out); }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq summary:hover { color: var(--accent-ink); }
.faq details p { padding: 0 0 1.1rem; color: var(--ink-muted); max-width: 680px; }

/* --- section titles arrive word by word (reveal.js splits any
   [data-split]); the hero's own rule in motion.css already covers the
   words, this only keeps a split title from flashing unsplit. --- */

@media (prefers-reduced-motion: reduce) {
  .tide { animation: none; -webkit-text-fill-color: currentColor; color: var(--ink); background: none; }
  .turns { height: auto; overflow: visible; }
  .turns-list { animation: none; display: inline; }
  .turns-list > span { display: inline; height: auto; }
  .turns-list > span:not(:first-child) { display: none; }
  .anim .reveal-deep { opacity: 1; filter: none; letter-spacing: -0.005em; transform: none; transition: none; }
  .faq summary::after { transition: none; }
}

/* --- the hero breathes: a muted loop under the headline. The painting
   (the poster) paints first and stays for scripting-off, reduced motion
   and any browser that will not autoplay; the clip fades over it only
   once it can actually play, so nobody sees a black box. --- */
.hero-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 40%;
  z-index: -1; opacity: 0; transition: opacity 1.4s ease-out; filter: saturate(.9) brightness(.85); }
.hero-video.is-playing { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hero-video { display: none; } }

/* --- the spot --- */
.spot { padding: 3.5rem 1.25rem 1rem; border-top: 1px solid var(--line); }
.spot-lede { max-width: 620px; margin: 0 0 1.6rem; color: var(--ink-muted); }
.spot-reel { margin: 0 0 2rem; border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  background: #000; box-shadow: 0 18px 40px rgba(0,0,0,.6); }
.spot-video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; }
