/* ============================================================
   dungeonworks.com: THE LAMPLIT WORKSHOP (redesign, 2026-10)
   A drafting table under a workshop lamp: a charcoal ground, warm
   light pooled where the eye should go, a faint drafting grid and
   rising embers behind the content, gold as the ink for rules and type.
   Charcoal and gold are pinned brand commitments (Brand/brand.toml);
   walnut, also declared there, warms every raised surface.

   THIS FILE IS THE CONTROL POINT. Every colour, size, radius and
   timing is a token in :root; every text level is one role in TYPE.
   A page never sets its own colour or size: it picks a role or a
   component. Change a token here and the whole site follows.
   styleguide.html shows every token, role and component live.

   Two themes, one set of names. Light and dark define the SAME
   semantic tokens; components only ever read the semantic names.
   The visitor's device decides the first view (prefers-color-scheme),
   the header toggle overrides it and js/site.js remembers the choice
   on <html data-theme>. Decided 2026-10-07.

   The site's only stylesheet; every page loads it as css/plate.css?v=N.
   ============================================================ */

@font-face { font-family: 'Zilla Slab'; src: url('../fonts/ZillaSlab-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Zilla Slab'; src: url('../fonts/ZillaSlab-SemiBold.woff2') format('woff2'); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: 'Zilla Slab'; src: url('../fonts/ZillaSlab-Bold.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: 'Literata'; src: url('../fonts/Literata-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Literata'; src: url('../fonts/Literata-Bold.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; }

/* ============================================================
   TOKENS
   1. Brand: pinned, mirror of Brand/brand.toml. Never used raw by a
      component; the semantic layer below picks from them.
   2. Semantic: what a component reads. Light by default, dark below.
   3. Scale: type sizes, radii, spacing, motion. Theme-independent.
   ============================================================ */
:root {
  /* 1. brand, mirror of Brand/brand.toml */
  --charcoal: #1A1A1A;
  --gold: #C9A84C;
  --walnut: #3E2723;
  --cream: #F5F5DC;
  /* the second gold: brand gold lifted for type and filled controls, which read
     dim at #C9A84C on charcoal. Lines and rules stay brand gold. Decided 2026-10-06. */
  --gold-bright: #E2C46E;
  /* light theme's paper and ink, carried over from the light canvas direction (A) */
  --paper: #F3EFE6;
  --ink-black: #1D1A15;
  --gold-deep: #7A5C0E;      /* gold that passes AA as text on paper */
  /* walnut-warmed charcoal at the three fixed steps the dark theme raises surfaces by */
  --walnut-20: color-mix(in srgb, var(--charcoal) 80%, var(--walnut));
  --walnut-10: color-mix(in srgb, var(--charcoal) 90%, var(--walnut));
  --walnut-40: color-mix(in srgb, var(--charcoal) 60%, var(--walnut));

  /* 2. semantic, LIGHT (the default when the device states no preference) */
  color-scheme: light;
  --ground: var(--paper);                                   /* the page */
  --surface: #FBF9F4;                                       /* a card, a plate */
  --surface-deep: #EFE9DC;                                  /* a figure well, a card's picture */
  --surface-raised: #EAE2D2;                                /* a panel that sits above a card */
  --text-strong: var(--ink-black);                          /* headings, names, values */
  --ink: rgb(29 26 21 / 0.87);                              /* body copy */
  --ink-quiet: rgb(29 26 21 / 0.68);                        /* captions, secondary lines */
  --accent: var(--gold-deep);                               /* labels, links, numerals */
  --rule: rgb(150 118 40 / 0.42);                           /* a rule: card edges, ledger lines */
  --rule-faint: rgb(150 118 40 / 0.22);                     /* a hairline */
  --btn-bg: var(--ink-black);                               /* the primary control's fill */
  --btn-fg: var(--paper);
  --btn-hover: var(--gold-deep);
  --well: rgb(29 26 21 / 0.05);                             /* a sunk field */
  --scrim: rgb(29 26 21 / 0.55);                            /* behind a dialog */
  --grid-line: rgb(122 92 14 / 0.09);                       /* the drafting grid */
  --ember: var(--gold);
  --glow: rgb(214 160 70 / 0.22);                           /* lamplight */
  --glow-soft: rgb(190 120 50 / 0.10);
  --ok: #2F7A4A;                                            /* "out now" */
  --err: #B3261E;                                           /* a failed form's edge */
  --on-ok: #FFFFFF;                                         /* type on the out-now fill */
  --head-bg: color-mix(in srgb, var(--ground) 72%, transparent);
  --on-ok-halo: color-mix(in srgb, var(--on-ok) 50%, transparent);
  --shadow: 0 24px 48px -26px rgb(29 26 21 / 0.35);

  /* the Campaign Journal feature panel stays dark in both themes: in light it is
     the contrast island the light direction was liked for */
  --feature-a: var(--walnut-40);
  --feature-b: color-mix(in srgb, var(--charcoal) 85%, var(--walnut));
  /* the feature panel is dark in both themes, so its ink and rules are fixed, not themed */
  --feature-ink: color-mix(in srgb, var(--cream) 87%, transparent);
  --feature-ink-quiet: color-mix(in srgb, var(--cream) 82%, transparent);
  --feature-rule: color-mix(in srgb, var(--gold) 35%, transparent);
  --feature-chip: color-mix(in srgb, var(--gold) 45%, transparent);
  --feature-grid: color-mix(in srgb, var(--gold) 8%, transparent);
  --edge: var(--gold);                                      /* the gold edge a closing band opens on */

  --display: 'Zilla Slab', Rockwell, Georgia, serif;
  --text: 'Literata', Georgia, serif;

  /* 3. scale: one size per type role (TYPE, below) */
  --t-display: clamp(34px, 8vw, 104px);              /* the rolling title only */
  --t-headline: clamp(32px, 4vw, 52px);
  --t-title: clamp(21px, 2vw, 26px);
  --t-standfirst: clamp(18px, 1.5vw, 21px);
  --t-name: 18px;
  --t-body: 17px;        /* 16.5px under 720px, set in NARROW SHEETS */
  --t-control: 16px;
  --t-label: 12.5px;
  --t-caption: 14px;
  --t-ui-small: 15px;    /* small controls and side navigation: small buttons, the topics list, crosslink notes */
  --t-small: 12.5px;
  --t-glyph: 20px;       /* a drawn symbol set as text, the questions' plus */
  --t-close: 25px;       /* the dialog close cross, set as text */
  --t-wordmark: 21px;    /* the masthead's "Dungeon Works" beside the mark */
  --t-menu: 17px;        /* a row in the Shop menu */
  --t-control-large: 17px;  /* the large button */
  --t-value: 15.5px;     /* a ledger value */
  --t-field: 16px;       /* exactly: a field's type under 16px makes iOS zoom the page on focus */

  --r-small: 10px;       /* menu rows */
  --r-control: 12px;     /* buttons, fields, badges */
  --r-figure: 16px;      /* a figure well, a question card */
  --r-chip: 8px;         /* tags */
  --r-card: 20px;        /* cards, plates, panels */
  --r-panel: 28px;       /* the feature panel */
  --r-round: 50%;        /* a circle: numerals, the pulse dot, the questions' plus */

  --line-bold: 1.5px;    /* an edge heavier than a hairline: buttons, step numerals, the drawn title */
  --tap: 44px;           /* the smallest touch target: icon buttons, question and step rows */
  --badge-h: 48px;       /* a store badge's height */
  --gutter: clamp(26px, 3.4vw, 56px);                 /* between two paired columns */

  --measure: 68ch;
  --sheet: 1240px;                                    /* every band shares one margin */
  --margin: clamp(20px, 4vw, 48px);
  --step: clamp(64px, 8vw, 120px);                    /* one spacing rhythm, used everywhere */

  /* motion: one easing for settling, a few durations by job */
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-slide: cubic-bezier(0.5, 0, 0.2, 1);         /* the carousel track */
  --ease-roll: cubic-bezier(0.75, 0, 0.2, 1);         /* a caption of the rolling title landing */
  --t-snap: 140ms;       /* the skip link dropping in */
  --t-quick: 200ms;      /* colour, border and tint changes */
  --t-hover: 300ms;      /* a control's glow, a tile lifting, the questions' plus turning */
  --t-lift: 350ms;       /* a card lifting */
  --t-theme: 400ms;      /* the ground and ink crossing over on a theme change */
  --t-tilt: 450ms;       /* a deck card tilting */
  --t-arrive: 550ms;     /* the guide's new screen arriving */
  --t-picture: 600ms;    /* a picture settling: the shop card's zoom, the carousel's fade */
  --t-slide: 700ms;      /* the carousel track */
  --t-rise: 0.9s;        /* a hero line rising in */
  --t-stagger: 0.15s;    /* between one hero line and the next */
  --t-pulse: 2.2s;       /* the out-now dot */
  --t-bob: 8s;           /* a floating phone */
  --t-bob-2: 9s;         /* the second phone, out of step with the first */
  --t-bob-lag: -3s;
  --t-breathe: 9s;       /* the lamp */
  --t-roll: 62s;         /* the rolling title AND its outline drawing: one loop, keep them equal */
  --t-spin: 90s;         /* the turning die */
  --t-drift: 120s;       /* the grid and embers: three ember tiles, two grid cells per loop */
  --toc-w: 250px;        /* the support page's topics column */
  --help-gap: 48px;

  /* layers, bottom to top */
  --z-under: -1;         /* the body's grid and embers, under everything */
  --z-ambient: 0;        /* a container's .ambient and the turning die */
  --z-content: 1;        /* content over its ambient */
  --z-over: 2;           /* a tag or control pinned over content */
  --z-masthead: 50;
  --z-menu: 60;          /* the Shop menu */
  --z-skip: 100;         /* the skip link, over everything */

  /* shadows and glows; a drop is a filter, for a cut-out picture lifted off the bench */
  --halo: 0 0 36px var(--glow);                       /* the primary button lit */
  --halo-badge: 0 0 30px var(--glow);                 /* a store badge lit */
  --halo-field: 0 0 60px -20px var(--glow);           /* the help search, lit at rest */
  --focus-ring: 0 0 0 3px var(--glow);                /* a focused field */
  --pulse-from: 0 0 0 0 var(--on-ok-halo);            /* the out-now dot's ring, start and end */
  --pulse-to: 0 0 0 9px transparent;
  --drop-card: drop-shadow(0 20px 26px rgb(0 0 0 / 0.3));     /* the phone in a shop card */
  --drop-fan: drop-shadow(0 18px 24px rgb(0 0 0 / 0.3));      /* the fanned decks in a shop card */
  --drop-deck: drop-shadow(0 18px 24px rgb(0 0 0 / 0.4));     /* a deck card on a product page */
  --drop-phone: drop-shadow(0 24px 30px rgb(0 0 0 / 0.45));   /* the feature panel's outer phones */
  --drop-phone-front: drop-shadow(0 30px 40px rgb(0 0 0 / 0.55));  /* its front phone */
  --drop-screen: drop-shadow(0 30px 40px rgb(0 0 0 / 0.35));  /* the help guide's phone */
  --head-blur: blur(12px);                            /* the masthead's tint, the one approved blur */

  /* the page's four pools of light: the body's glow and the grid and embers masked to it
     (body::before, ::after) all read these, so the pools always line up */
  --spot-1: 900px 700px at 88% 12%;
  --spot-2: 800px 700px at 6% 42%;
  --spot-3: 900px 700px at 92% 72%;
  --spot-4: 1000px 600px at 50% 100%;

  /* the ambient layers (AMBIENT): the drafting grid and the one ember drift, shared by
     every .ambient and the body. Three tiles of dots at unrelated sizes; --ember-rise is
     exactly three tile heights, so the loop is seamless */
  --mask-ink: #000;                                   /* the opaque stop of a mask gradient */
  --grid-cell: 120px;
  --ember-dots:
    radial-gradient(circle at 18% 70%, var(--ember) 0 1.2px, transparent 1.8px),
    radial-gradient(circle at 64% 30%, var(--ember) 0 1px, transparent 1.6px),
    radial-gradient(circle at 40% 55%, var(--ember) 0 1.4px, transparent 2px);
  --ember-size: 340px 460px, 520px 610px, 430px 700px;
  --ember-rise: 90px -1380px, -120px -1830px, 60px -2100px;
}

/* 2. semantic, DARK. Two identical blocks: one for a device that prefers dark
   (unless the visitor chose light), one for a visitor who chose dark. Keep them identical. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ground: var(--charcoal);
    --surface: var(--walnut-20);
    --surface-deep: var(--walnut-10);
    --surface-raised: var(--walnut-40);
    --text-strong: var(--cream);
    --ink: rgb(245 245 220 / 0.87);
    --ink-quiet: rgb(245 245 220 / 0.68);
    --accent: var(--gold-bright);
    --rule: rgb(201 168 76 / 0.42);
    --rule-faint: rgb(201 168 76 / 0.20);
    --btn-bg: var(--gold-bright);
    --btn-fg: var(--charcoal);
    --btn-hover: var(--cream);
    --well: rgb(0 0 0 / 0.3);
    --scrim: rgb(0 0 0 / 0.68);
    --grid-line: rgb(226 196 110 / 0.08);
    --ember: var(--gold-bright);
    --glow: rgb(226 180 90 / 0.28);
    --glow-soft: rgb(160 100 40 / 0.14);
    --ok: #5FD08B;
    --on-ok: #10241A;
    --err: #FF8A7A;
    --shadow: 0 24px 48px -24px rgb(0 0 0 / 0.6);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --ground: var(--charcoal);
  --surface: var(--walnut-20);
  --surface-deep: var(--walnut-10);
  --surface-raised: var(--walnut-40);
  --text-strong: var(--cream);
  --ink: rgb(245 245 220 / 0.87);
  --ink-quiet: rgb(245 245 220 / 0.68);
  --accent: var(--gold-bright);
  --rule: rgb(201 168 76 / 0.42);
  --rule-faint: rgb(201 168 76 / 0.20);
  --btn-bg: var(--gold-bright);
  --btn-fg: var(--charcoal);
  --btn-hover: var(--cream);
  --well: rgb(0 0 0 / 0.3);
  --scrim: rgb(0 0 0 / 0.68);
  --grid-line: rgb(226 196 110 / 0.08);
  --ember: var(--gold-bright);
  --glow: rgb(226 180 90 / 0.28);
  --glow-soft: rgb(160 100 40 / 0.14);
  --ok: #5FD08B;
  --on-ok: #10241A;                                         /* white fails on the lighter dark-theme green */
  --err: #FF8A7A;
  --shadow: 0 24px 48px -24px rgb(0 0 0 / 0.6);
}

/* ============================================================
   BASE
   ============================================================ */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* The page is one continuous ground: warm light pooled down alternate sides, so no
   section ever starts on a cut. Positions are percentages of the page, so a short
   page and a long one both get the same rhythm of light. */
body {
  margin: 0;
  background:
    radial-gradient(var(--spot-1), var(--glow-soft), transparent 70%),
    radial-gradient(var(--spot-2), var(--glow-soft), transparent 70%),
    radial-gradient(var(--spot-3), var(--glow-soft), transparent 70%),
    radial-gradient(var(--spot-4), var(--glow-soft), transparent 70%),
    var(--ground);
  color: var(--ink);
  font-family: var(--text);
  font-size: var(--t-body);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--t-theme) ease, color var(--t-theme) ease;
  /* the lamp and the die are wider than a phone; clip, not hidden, so the header stays sticky */
  overflow-x: clip;
  position: relative;   /* the box body::before and ::after cover, so their spotlights line up with the glow */
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--text-strong); }
img, svg { max-width: 100%; height: auto; display: block; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.skip {
  position: absolute; left: 12px; top: -60px; z-index: var(--z-skip);
  background: var(--btn-bg); color: var(--btn-fg);
  padding: 10px 16px; border-radius: var(--r-control);
  font-family: var(--display); font-weight: 600;
  transition: top var(--t-snap) ease;
}
.skip:focus { top: 12px; text-decoration: none; }

/* a UA paints code in monospace, and the site has no third face */
code { font-family: var(--text); font-style: italic; }

/* ============================================================
   TYPE: every text role on the site, by level. Pick the role for the
   JOB the text does, not for the size you want. Sizes are the --t-*
   tokens; each role is one rule with its selectors grouped, and a
   component adds only spacing. A one-off that turns up three times
   is a missing role: add it here.

   Level         Role          Face, size                       Colour         Used for
   ------------  ------------  -------------------------------  -------------  ---------------------------------
   Display       Display       slab 700, --t-display            text-strong    the rolling title only (.hero-roll)
   H1, H2        Headline      slab 700, --t-headline           text-strong    every page's h1, a section's h2
   H3            Title         slab 700, --t-title              text-strong    card, step and document headings
   Tag           Label         slab 600, 12.5, 0.2em caps       accent         category tags on product pictures,
                                                                               ledger keys, menu headings. Never
                                                                               above a heading
   Name          Name          slab 600, --t-name               text-strong    product names in lists, questions
   Lead          Standfirst    Literata 400, --t-standfirst     ink            a page's one lead paragraph
   Body          Body          Literata 400, --t-body           ink            all reading text, 68ch measure
   Caption       Caption       Literata 400, 14, 1.5            ink-quiet      figure captions, secondary lines
   Small         Small caption Literata 400, 12.5, 1.5          ink-quiet      the legal and trademark lines
   Link          Link          inherits, underlined             accent         links in running text
   Button        Control       slab 600, 16, authored case      btn-fg on      buttons
                                                                btn-bg

   Case is authored, never transformed: Title Case for headings and
   buttons, sentence case for prose. Only Label is uppercase, and it is
   always letterspaced.
   ============================================================ */
h1, h2, h3 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.015em;
  color: var(--text-strong);
  text-wrap: balance;
  margin: 0 0 18px;
}
h1, h2 { font-size: var(--t-headline); }
h3 { font-size: var(--t-title); line-height: 1.15; margin-bottom: 12px; }
p { margin: 0 0 18px; max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

/* Label */
.rule-label, .label, .page-head__meta, .sg-spec__note,
.ledger__k, .form__k, .plate__no, .plate__stamp {
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--accent);
}
/* Name */
.figures h3, .qa summary, .crosslink__name {
  font-family: var(--display); font-weight: 600; font-size: var(--t-name); color: var(--text-strong);
}
/* Standfirst */
.page-head__standfirst, .hero__standfirst { font-size: var(--t-standfirst); color: var(--ink); }
/* Control */
.btn {
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--t-control);
  letter-spacing: 0;
}
/* Caption */
.plate__caption, .imprint__colophon, .dw-notify__note, .dw-notify__msg, .sg-note, .sg-swatch .meta {
  font-size: var(--t-caption); line-height: 1.5; color: var(--ink-quiet);
}
/* Small caption */
.imprint__stores, .sg-swatch code { font-size: var(--t-small); line-height: 1.5; color: var(--ink-quiet); }

/* ============================================================
   AMBIENT: the workshop around the content. A decorated container
   carries ONE element, <div class="ambient" aria-hidden="true"></div>,
   and this sheet draws everything in it: ::before is the lamp, ::after
   the drafting grid patch with embers rising through it. The embers are
   the same dot layer the body drifts (--ember-dots), so there is one
   ember method site-wide. A container picks what shows and where by
   setting the knobs below on `X > .ambient` (CONTEXTS), so changing a
   rule here changes every page. Decoration only: aria-hidden, pointer-
   events none, still and ember-free under reduced motion.
   ============================================================ */
/* the drafting grid: two line layers (rows, columns), so its size and drift are listed
   twice. Resolved again on each .ambient so a context can recolour or rescale it */
body, .ambient {
  --grid: linear-gradient(var(--grid-line) 1px, transparent 1px), linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  --grid-size: var(--grid-cell) var(--grid-cell), var(--grid-cell) var(--grid-cell);
  --grid-drift: calc(var(--grid-cell) * 2) calc(var(--grid-cell) * 2), calc(var(--grid-cell) * 2) calc(var(--grid-cell) * 2);
}
.ambient {
  /* the knobs, at their defaults */
  --lamp: block;                                  /* none: no lamp */
  --lamp-left: 50%; --lamp-top: -280px; --lamp-w: 1100px; --lamp-h: 900px;
  --lamp-shift: calc(var(--lamp-w) / -2);         /* centred on --lamp-left */
  --embers: var(--ember-dots);                    /* none, none, none: grid only */
  --patch: ellipse 50% 60% at 50% 45%;            /* the grid patch: its shape and centre */
  --patch-core: 10%; --patch-edge: 70%;           /* solid to here, gone by here */
  --grid-mask: radial-gradient(var(--patch), var(--mask-ink) var(--patch-core), transparent var(--patch-edge));
  --grid-inset: 0;
  position: absolute; inset: 0; pointer-events: none; z-index: var(--z-ambient);
}
.ambient::before, .ambient::after { content: ""; position: absolute; }
.ambient::before {
  display: var(--lamp);
  left: var(--lamp-left); top: var(--lamp-top); width: var(--lamp-w); height: var(--lamp-h); margin-left: var(--lamp-shift);
  background: radial-gradient(ellipse at center, var(--glow), var(--glow-soft) 40%, transparent 68%);
  animation: dwBreathe var(--t-breathe) ease-in-out infinite;
}
/* the lamp breathes in opacity only: scaling a gradient this size repaints it every frame,
   which halved the frame rate on a 4x-throttled phone (measured 2026-10-08); opacity is
   composited and runs at a full 60 */
@keyframes dwBreathe { 0%, 100% { opacity: 0.8; } 50% { opacity: 1; } }
/* the grid only ever shows as a soft-edged patch: it never covers a whole page */
.ambient::after {
  inset: var(--grid-inset);
  background-image: var(--embers), var(--grid);
  background-size: var(--ember-size), var(--grid-size);
  -webkit-mask-image: var(--grid-mask); mask-image: var(--grid-mask);
  animation: dwAmbient var(--t-drift) linear infinite;
}
/* one loop: each ember tile rises three tile heights (--ember-rise), the grid drifts two
   cells. body::after has only the ember layers, so it takes the first three positions */
@keyframes dwAmbient { to { background-position: var(--ember-rise), var(--grid-drift); } }

/* CONTEXTS: where each container's light falls */
.hero > .ambient { --grid-inset: -90px 0 -120px; --patch: 700px 520px at 50% 40%; }
.page-head > .ambient {
  --lamp-left: -120px; --lamp-shift: 0px; --lamp-top: -300px; --lamp-w: 900px; --lamp-h: 640px;
  --grid-inset: -90px 0 0; --patch: 620px 380px at 25% 50%;
}
.page-head--center > .ambient { --lamp-left: 50%; --lamp-w: 1000px; --lamp-shift: calc(var(--lamp-w) / -2); --patch: 700px 420px at 50% 45%; }
.closer > .ambient { --lamp-top: -320px; --lamp-w: 900px; --lamp-h: 600px; --patch: 640px 360px at 50% 0%; }
.product-card__fig > .ambient { --lamp: none; --grid-mask: none; }
.feature > .ambient, .guide__screen > .ambient { --lamp: none; --embers: none, none, none; }
.feature > .ambient { --grid-mask: none; --grid-line: var(--feature-grid); --grid-cell: 40px; }
.feature > .ambient::after { animation: none; }
.guide__screen > .ambient { --patch: circle at 50% 50%; --patch-core: 20%; --patch-edge: 75%; }
.sg-stage > .ambient { --lamp-top: -200px; --patch-core: 15%; --patch-edge: 72%; }

.die-spin {
  position: absolute; pointer-events: none; z-index: var(--z-ambient);
  left: 50%; top: 30px; width: 640px; height: 640px; margin-left: -320px;
  opacity: 0.09;
  animation: dwSpin var(--t-spin) linear infinite;
}
@keyframes dwSpin { to { transform: rotate(360deg); } }

/* the page's pools of light carry the workshop: the drafting grid (body::before) and a
   sparse drift of embers (body::after) show only inside the same four spotlights the body
   ground paints, so they fade out between them and never cover a whole page */
body::before, body::after {
  content: ""; pointer-events: none; z-index: var(--z-under);
  position: absolute; inset: 0;
  --spots:
    radial-gradient(var(--spot-1), var(--mask-ink), transparent 70%),
    radial-gradient(var(--spot-2), var(--mask-ink), transparent 70%),
    radial-gradient(var(--spot-3), var(--mask-ink), transparent 70%),
    radial-gradient(var(--spot-4), var(--mask-ink), transparent 70%);
  -webkit-mask-image: var(--spots); mask-image: var(--spots);
}
body::before { background-image: var(--grid); background-size: var(--grid-size); }
body::after {
  background-image: var(--ember-dots);
  background-size: var(--ember-size);
  opacity: 0.5;
  animation: dwAmbient var(--t-drift) linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  :root { --ember-dots: none, none, none; }
  .ambient::before, .ambient::after, body::after, .die-spin { animation: none; }
}

/* ============================================================
   MASTHEAD: lockup left, the site's pages, the theme toggle and the
   one call to action right. Pinned while the page scrolls. Under 820px
   the pages fold into a menu behind the burger (js/site.js); with no
   script the menu simply stays open.
   ============================================================ */
/* clear over the page's grid and glow at the top; once the page moves under it
   (js/site.js sets .is-scrolled) a blurred tint keeps the links legible */
.masthead { position: sticky; top: 0; z-index: var(--z-masthead); background: transparent; transition: background-color var(--t-quick), backdrop-filter var(--t-quick); }
.masthead.is-scrolled, .masthead.is-open { background: var(--head-bg); -webkit-backdrop-filter: var(--head-blur); backdrop-filter: var(--head-blur); }
/* with no script nothing ever sets .is-scrolled, so the tint is always on */
:root:not(.js) .masthead { background: var(--head-bg); -webkit-backdrop-filter: var(--head-blur); backdrop-filter: var(--head-blur); }
.masthead__inner {
  max-width: var(--sheet); margin: 0 auto;
  padding: 14px var(--margin);
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px 28px;
}
.masthead__home { display: flex; align-items: center; gap: 12px; text-decoration: none; color: var(--text-strong); }
.masthead__home:hover { color: var(--text-strong); }
.masthead__home img { width: var(--tap); height: var(--tap); flex: none; }
/* the mark per ground (Brand/brand.toml [logo].backgrounds): the parchment-gear icon on
   light, the primary icon on dark. Masthead and footer carry both; the theme shows one */
.logo--dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .logo--dark { display: block; }
  :root:not([data-theme="light"]) .logo--light { display: none; }
}
:root[data-theme="dark"] .logo--dark { display: block; }
:root[data-theme="dark"] .logo--light { display: none; }
.masthead__name { font-family: var(--display); font-weight: 700; font-size: var(--t-wordmark); letter-spacing: -0.01em; }

.masthead__nav { flex: 1 1 auto; }
/* the site pages sit centred in the bar, between the lockup and the tools */
.masthead__nav ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 30px; }
.masthead__nav li { position: relative; }
.masthead__nav a {
  display: block; padding: 8px 0;
  font-family: var(--display); font-weight: 600; font-size: var(--t-control);
  color: var(--text-strong); text-decoration: none;
}
.masthead__nav a:hover, .masthead__nav a[aria-current] { color: var(--accent); }
.masthead__nav a[aria-current] { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 8px; }

/* the Shop menu: CSS only, :hover plus :focus-within, so it is keyboard reachable with no
   script; visibility keeps the links out of tab order while shut */
.masthead__sub {
  position: absolute; top: 100%; left: -16px; z-index: var(--z-menu);
  min-width: 240px; margin: 0; padding: 8px;
  background: var(--surface); border: 1px solid var(--rule-faint); border-radius: var(--r-card);
  box-shadow: var(--shadow);
  visibility: hidden; opacity: 0; transform: translateY(6px);
  /* visibility is NOT transitioned: a transition holds it hidden for the first frame, and a
     keyboard user tabbing from Shop straight into the menu would skip every link in it */
  transition: opacity var(--t-quick) ease, transform var(--t-quick) var(--ease);
}
.masthead__nav ul.masthead__sub { display: block; }
.masthead__nav li:hover > .masthead__sub,
.masthead__nav li:focus-within > .masthead__sub { visibility: visible; opacity: 1; transform: none; }
.masthead__sub a { padding: 10px 14px; border-radius: var(--r-small); font-size: var(--t-menu); }
.masthead__sub a:hover { background: var(--well); }

.masthead__tools { display: flex; align-items: center; gap: 10px; }
.icon-btn {
  width: var(--tap); height: var(--tap); flex: none; border-radius: var(--r-control);
  border: 1px solid var(--rule); background: transparent; color: var(--accent);
  display: grid; place-items: center; cursor: pointer;
  transition: background var(--t-quick), border-color var(--t-quick);
}
.icon-btn:hover { background: var(--well); border-color: var(--accent); }
.icon-btn svg { width: 20px; height: 20px; }
/* the toggle shows the mode you would switch TO */
.theme-toggle .i-moon { display: none; }
.theme-toggle[aria-pressed="true"] .i-sun { display: none; }
.theme-toggle[aria-pressed="true"] .i-moon { display: block; }
.menu-toggle { display: none; }

/* ============================================================
   CONTROLS
   ============================================================ */
.btn {
  display: inline-block;
  padding: 14px 24px;
  border: var(--line-bold) solid var(--rule);
  border-radius: var(--r-control);
  background: transparent;
  color: var(--text-strong);
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: background var(--t-quick), color var(--t-quick), border-color var(--t-quick), box-shadow var(--t-hover);
}
.btn:hover { background: var(--well); border-color: var(--accent); color: var(--text-strong); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--btn-bg); border-color: var(--btn-bg); color: var(--btn-fg); }
.btn--primary:hover { background: var(--btn-hover); border-color: var(--btn-hover); color: var(--btn-fg); box-shadow: var(--halo); }
.btn--small { padding: 11px 18px; font-size: var(--t-ui-small); }
.btn--large { padding: 17px 30px; font-size: var(--t-control-large); }
.btn[disabled], .btn--quiet { border-color: var(--rule-faint); color: var(--ink-quiet); cursor: default; }

/* Official store artwork is never redrawn or recoloured: it sits on its own black art. */
.store-badge {
  display: inline-flex; justify-content: center; align-items: center;
  border-radius: var(--r-control);
  transition: transform var(--t-quick) var(--ease), box-shadow var(--t-hover);
}
.store-badge:hover { transform: translateY(-2px); box-shadow: var(--halo-badge); }
.store-badge img { max-width: none; height: var(--badge-h); width: auto; }
/* Google's badge carries its clear space inside the PNG at 6.34675% of its width */
.store-badge__apple { height: var(--badge-h); }
.store-badge__play { height: 71px !important; margin: -11.5px -11.7px; }

/* ============================================================
   LAYOUT
   ============================================================ */
.sheet { position: relative; max-width: var(--sheet); margin: 0 auto; padding: 0 var(--margin) var(--step); }
.section { position: relative; max-width: var(--sheet); margin: 0 auto; padding: 0 var(--margin) var(--step); }
.section__head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: end; gap: 16px 32px; margin-bottom: 44px; }
.section__head > div { display: flex; flex-direction: column; gap: 12px; }
.section__head h2 { margin: 0; }
.section__head p { margin: 0; max-width: 32em; color: var(--ink-quiet); }
/* content sits above its container's .ambient; :where keeps this at one class of specificity */
:is(.section, .sheet, .hero, .page-head) > :where(:not(.ambient)) { position: relative; z-index: var(--z-content); }

/* ============================================================
   HERO: the home page's first view. Centred rolling title under the
   lamp, the turning die behind it, embers rising through it.
   ============================================================ */
.hero { position: relative; text-align: center; }
.hero > .die-spin { position: absolute; }
.hero__inner {
  position: relative; z-index: var(--z-content);
  max-width: 1080px; margin: 0 auto;
  padding: clamp(64px, 10vw, 136px) var(--margin) var(--step);
  display: flex; flex-direction: column; align-items: center; gap: 26px;
}
.hero__standfirst { margin: 0 auto; max-width: 34em; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }

/* The rolling title: sixteen captions rolling like a die, the brand name drawing itself in
   outline three times per loop. The mask height, the row height and the keyframe pitch are
   all 1.32em and MUST resolve against the same font-size, so it is set here and inherited. */
.hero-roll { height: 1.32em; overflow: hidden; margin: 0; max-width: none; width: 100%; font-size: var(--t-display); }
.hero-roll ul { list-style: none; margin: 0; padding: 0; animation: dwRoll var(--t-roll) var(--ease-roll) infinite reverse; }
/* Captions are nowrap and own the full sheet width. Measure any new caption against the
   narrowest sheet at its own size, or it clips with no warning. */
.hero-roll li {
  text-align: center; height: 1.32em; line-height: 1.32; white-space: nowrap;
  font-family: var(--display); font-weight: 700; font-size: inherit; letter-spacing: -0.025em;
  color: var(--text-strong);
}
.hero-roll .dw { color: var(--accent); position: relative; display: inline-block; }
.hero-roll .dw::after {
  content: "Dungeon Works";
  position: absolute; inset: 0; color: transparent;
  -webkit-text-stroke: var(--line-bold) var(--text-strong);
  clip-path: inset(0 100% 0 0); opacity: 0;
  animation: dwDraw var(--t-roll) linear infinite;
}
@keyframes dwDraw {
  0%, 16%   { opacity: 0; clip-path: inset(0 100% 0 0); }
  17%       { opacity: 1; clip-path: inset(0 100% 0 0); }
  23%, 25%  { opacity: 1; clip-path: inset(0 0 0 0); }
  27%       { opacity: 0; clip-path: inset(0 0 0 0); }
  28%, 47%  { opacity: 0; clip-path: inset(0 100% 0 0); }
  48%       { opacity: 1; clip-path: inset(0 100% 0 0); }
  54%, 56%  { opacity: 1; clip-path: inset(0 0 0 0); }
  58%       { opacity: 0; clip-path: inset(0 0 0 0); }
  59%, 78%  { opacity: 0; clip-path: inset(0 100% 0 0); }
  79%       { opacity: 1; clip-path: inset(0 100% 0 0); }
  85%, 87%  { opacity: 1; clip-path: inset(0 0 0 0); }
  89%       { opacity: 0; clip-path: inset(0 0 0 0); }
  90%, 100% { opacity: 0; clip-path: inset(0 100% 0 0); }
}
@keyframes dwRoll {
  0.00%, 5.31%   { transform: translateY(-0.00em); }
  6.25%, 11.56%  { transform: translateY(-1.32em); }
  12.50%, 17.81% { transform: translateY(-2.64em); }
  18.75%, 24.06% { transform: translateY(-3.96em); }
  25.00%, 30.31% { transform: translateY(-5.28em); }
  31.25%, 36.56% { transform: translateY(-6.60em); }
  37.50%, 42.81% { transform: translateY(-7.92em); }
  43.75%, 49.06% { transform: translateY(-9.24em); }
  50.00%, 55.31% { transform: translateY(-10.56em); }
  56.25%, 61.56% { transform: translateY(-11.88em); }
  62.50%, 67.81% { transform: translateY(-13.20em); }
  68.75%, 74.06% { transform: translateY(-14.52em); }
  75.00%, 80.31% { transform: translateY(-15.84em); }
  81.25%, 86.56% { transform: translateY(-17.16em); }
  87.50%, 92.81% { transform: translateY(-18.48em); }
  93.75%, 99.06% { transform: translateY(-19.80em); }
  100%           { transform: translateY(-21.12em); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-roll ul { animation: none; }
  .hero-roll .dw::after { display: none; }
}

/* the page's entrance: each hero line rises in turn */
.rise { opacity: 0; transform: translateY(18px); animation: dwRise var(--t-rise) var(--ease) forwards; }
.rise--2 { animation-delay: var(--t-stagger); } .rise--3 { animation-delay: calc(var(--t-stagger) * 2); }
@keyframes dwRise { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .rise { animation: none; opacity: 1; transform: none; } }

/* ============================================================
   PAGE HEAD: how every page but the home page opens. A label, the
   headline, one standfirst, under the lamp with a grid patch behind.
   ============================================================ */
.page-head { position: relative; max-width: var(--sheet); margin: 0 auto; padding: clamp(40px, 5vw, 80px) var(--margin) clamp(40px, 5vw, 64px); }
.page-head h1 { margin-bottom: 14px; }
.page-head__standfirst { max-width: 44ch; margin: 0; }
.page-head__meta { margin: 16px 0 0; color: var(--ink-quiet); }
.page-head .rule-label { margin: 0 0 14px; }
.breadcrumb { margin: 0 0 14px; }
.breadcrumb a { color: var(--ink-quiet); text-decoration: none; }
.breadcrumb a:hover { color: var(--accent); }
.page-head + .sheet { padding-top: 0; }

/* ============================================================
   CARDS: the plate (a product's or a page's main card), the shop's
   product card, the feature panel, the cross-link.
   ============================================================ */
.plates { display: flex; flex-direction: column; gap: var(--step); }
.plate {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--rule-faint);
  border-radius: var(--r-card);
  padding: clamp(26px, 3.4vw, 52px);
}
.plate__no { margin: 0 0 18px; }
.plate__no--name { color: var(--accent); }
.plate__grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: var(--gutter); align-items: center; }
.plate--solo > :last-child { margin-bottom: 0; }

/* status, top right of a plate: a tag, not a sold-out badge */
.plate__stamp {
  position: absolute; top: 20px; right: 20px; margin: 0;
  padding: 7px 12px; border-radius: var(--r-chip);
  background: var(--ground); border: 1px solid var(--rule);
  color: var(--text-strong); white-space: nowrap;
}
.plate__stamp--issued { background: var(--ok); border-color: var(--ok); color: var(--on-ok); }

.plate__figure {
  position: relative; overflow: hidden;
  background: var(--surface-deep); border: 1px solid var(--rule-faint); border-radius: var(--r-figure);
  padding: clamp(14px, 1.6vw, 24px);
}
.plate__figure img, .plate__figure svg { width: 100%; }
.plate__caption { margin: 14px 0 0; max-width: none; }
.plate__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 14px; margin-top: 30px; }
/* The engraved Dice Scroller drawing is gold line on transparent: in light it is darkened
   so the line work holds on paper */
:root:not([data-theme="dark"]) img[src*="plate-dice-scroller"] { filter: brightness(0.55) saturate(1.3); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) img[src*="plate-dice-scroller"] { filter: none; } }

/* the issue line: a status stated as a sentence */
.issue { margin: 22px 0 0; padding: 14px 0 0; border-top: 1px solid var(--rule); font-style: italic; color: var(--ink); max-width: none; }
.issue b { font-style: normal; font-family: var(--display); font-weight: 600; color: var(--accent); }

/* THE SHOP: one card per product, as many as the range holds */
.shop { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 24px; }
/* Subgrid: every card in a row shares five tracks (figure, title, blurb, ledger, actions),
   so a blurb that wraps to an extra line moves every ledger down together, never one alone */
.product-card {
  position: relative; display: grid; grid-row: span 5; grid-template-rows: subgrid; row-gap: 0;
  background: var(--surface); border: 1px solid var(--rule-faint); border-radius: var(--r-card);
  overflow: hidden;
  transition: transform var(--t-lift) var(--ease), box-shadow var(--t-lift);
}
.product-card:hover { transform: translateY(-6px); box-shadow: var(--shadow); }
.product-card__fig { position: relative; height: 300px; display: grid; place-items: center; overflow: hidden; background: var(--surface-deep); }
.product-card__fig img { position: relative; z-index: var(--z-content); transition: transform var(--t-picture) var(--ease); }
.product-card:hover .product-card__fig img { transform: scale(1.04) rotate(-1deg); }
/* The phone is cropped by the figure: wide enough that the screen reads, top of it clear of the status chip */
.product-card__fig--phone img { align-self: start; width: min(76%, 330px); height: auto; margin-top: 72px; filter: var(--drop-card); }
.product-card__fig--fan img { width: 86%; margin-top: 16px; filter: var(--drop-fan); }
.product-card__fig--drawing img { width: 90%; }
.product-card__fig .label { position: absolute; top: 16px; left: 16px; z-index: var(--z-over); margin: 0; color: var(--ink-quiet); }
.product-card__body { grid-row: span 4; display: grid; grid-template-rows: subgrid; row-gap: 14px; padding: 28px; }
.product-card__body h3 { margin: 0; }
.product-card__body p { margin: 0; color: var(--ink-quiet); }
.product-card__body .ledger { margin: 0; }
.product-card__actions { align-self: end; display: flex; flex-wrap: wrap; gap: 10px; }
.product-card__actions .btn--primary { flex: 1; }
.status {
  position: absolute; top: 14px; right: 14px; z-index: var(--z-over);
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px; border-radius: var(--r-chip);
  background: var(--ground); border: 1px solid var(--rule);
  font-family: var(--display); font-weight: 600; font-size: var(--t-caption); color: var(--text-strong);
}
.status--live { background: var(--ok); border-color: var(--ok); color: var(--on-ok); }
.status--live::before { content: ""; width: 7px; height: 7px; border-radius: var(--r-round); background: var(--on-ok); animation: dwPulse var(--t-pulse) ease-out infinite; }
@keyframes dwPulse { 0% { box-shadow: var(--pulse-from); } 100% { box-shadow: var(--pulse-to); } }
@media (prefers-reduced-motion: reduce) { .status--live::before { animation: none; } .product-card:hover, .product-card:hover .product-card__fig img { transform: none; } }

/* THE FEATURE PANEL: Campaign Journal's spotlight. Dark in both themes. */
.feature {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); gap: 40px; align-items: center;
  padding: clamp(32px, 5vw, 72px);
  border-radius: var(--r-panel);
  background: linear-gradient(160deg, var(--feature-a), var(--feature-b));
  border: 1px solid var(--feature-rule);
  color: var(--feature-ink);
}
.feature h2 { color: var(--cream); }
.feature__sub { margin: -8px 0 0; color: var(--gold-bright); }
.feature .label { color: var(--gold-bright); margin: 0; }
.feature__copy { position: relative; z-index: var(--z-content); display: flex; flex-direction: column; gap: 20px; }
.feature__copy p { margin: 0; font-size: var(--t-standfirst); color: var(--feature-ink-quiet); }
.feature__copy a:not(.store-badge) { color: var(--gold-bright); font-family: var(--display); font-weight: 600; }
.feature__copy a:not(.store-badge):hover { color: var(--cream); }
.feature__tags { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0; padding: 0; }
.feature__tags li { border: 1px solid var(--feature-chip); border-radius: var(--r-chip); padding: 6px 14px; font-size: var(--t-caption); color: var(--cream); }
.feature__actions { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
/* three screens fanned like a hand of cards: the outer two tilt away from the centre, mirrored */
.feature__phones { position: relative; height: 620px; min-width: 0; }
.feature__phones img { position: absolute; top: 64px; height: 500px; width: auto; filter: var(--drop-phone); }
.feature__phones img:nth-child(1) { left: 0; rotate: -7deg; }
.feature__phones img:nth-child(2) { right: 0; rotate: 7deg; }
.feature__phones img:nth-child(3) { left: 50%; margin-left: -138px; top: 0; height: 585px; z-index: var(--z-content); filter: var(--drop-phone-front); }
.float { animation: dwBob var(--t-bob) ease-in-out infinite; }
.float--2 { animation-duration: var(--t-bob-2); animation-delay: var(--t-bob-lag); }
@keyframes dwBob { 0%, 100% { translate: 0 0; } 50% { translate: 0 -10px; } }
@media (prefers-reduced-motion: reduce) { .float { animation: none; } }

/* a card that points at another product, at the foot of a product page */
.crosslinks { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: 20px; }
.crosslink {
  display: flex; align-items: center; gap: 20px; padding: 20px;
  background: var(--surface); border: 1px solid var(--rule-faint); border-radius: var(--r-card);
  color: var(--ink); text-decoration: none;
  transition: transform var(--t-lift) var(--ease), box-shadow var(--t-lift);
}
.crosslink:hover { transform: translateY(-4px); box-shadow: var(--shadow); color: var(--ink); }
.crosslink__fig { flex: none; width: 112px; height: 112px; border-radius: var(--r-figure); background: var(--surface-deep); display: grid; place-items: center; overflow: hidden; }
.crosslink__fig img { max-height: 100%; width: auto; }
.crosslink__body { display: flex; flex-direction: column; gap: 4px; }
.crosslink__body .label { margin: 0; }
.crosslink__body span:last-child { font-size: var(--t-ui-small); color: var(--ink-quiet); }

/* ============================================================
   THE LEDGER: keys and values joined by a dotted leader
   ============================================================ */
.ledger { margin: 26px 0 0; border-top: 1px solid var(--rule); }
.ledger__row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--rule-faint); }
.ledger__k { line-height: 22px; flex: 0 0 auto; letter-spacing: 0.14em; }
.ledger__leader { flex: 1 1 auto; border-bottom: 1px dotted var(--rule); }
.ledger__v { flex: 0 0 auto; font-size: var(--t-value); line-height: 22px; text-align: right; color: var(--text-strong); }
/* A wide ledger, for values that are sentences: the key takes a fixed column, the value wraps */
.ledger--wide .ledger__row { align-items: baseline; }
.ledger--wide .ledger__k { flex: 0 0 clamp(112px, 13vw, 180px); }
.ledger--wide .ledger__v { flex: 1 1 auto; text-align: left; line-height: 1.6; color: var(--ink); }
.ledger--wide .ledger__leader { display: none; }

/* ============================================================
   BANDS: a section under a page's main card. No ruled cut between
   sections: the heading and the space carry the break.
   ============================================================ */
.plate[id], .band[id], .section[id], .help__section[id], .guide li[id] { scroll-margin-top: 90px; }
.band { padding-top: calc(var(--step) * 0.75); }
.band__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: var(--gutter); align-items: start; }
.band__grid > h2 { margin: 0; }
/* a band whose content is a row of cards takes the full width, heading above */
.band__grid:has(> .steps), .band__grid:has(> .figures), .band__grid:has(> div > .deck-pairs) { grid-template-columns: minmax(0, 1fr); }
.band__actions { display: flex; flex-wrap: wrap; gap: 12px 14px; align-items: center; }

/* THE STEPS: a numbered sequence on a product page, set as cards */
.steps { counter-reset: step; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: 16px; }
.step { background: var(--surface); border: 1px solid var(--rule-faint); border-radius: var(--r-card); padding: 28px; display: flex; flex-direction: column; gap: 12px; }
.step::before {
  counter-increment: step; content: counter(step);
  width: 48px; height: 48px; border-radius: var(--r-round);
  border: var(--line-bold) solid var(--accent); color: var(--accent);
  display: grid; place-items: center;
  font-family: var(--display); font-weight: 700; font-size: var(--t-name);
}
.step:last-child::before { background: var(--btn-bg); border-color: var(--btn-bg); color: var(--btn-fg); }
.step h3 { margin: 0; }
.step p { margin: 0; color: var(--ink-quiet); }
.band .steps { margin-top: 28px; }

/* Three app screens on a track, the active one centred and its neighbours dimmed. Every screen
   is a button, so it is operable by keyboard and touch (js/carousel.js). */
.figure-carousel {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--mask-ink) 15%, var(--mask-ink) 85%, transparent);
  mask-image: linear-gradient(90deg, transparent, var(--mask-ink) 15%, var(--mask-ink) 85%, transparent);
}
.figure-carousel__track { display: flex; gap: 20px; transition: transform var(--t-slide) var(--ease-slide); }
.figure-carousel__track button { flex: 0 0 62%; min-width: 0; padding: 0; border: 0; background: none; cursor: pointer; opacity: 0.4; transition: opacity var(--t-picture) ease; }
.figure-carousel__track button.is-active { opacity: 1; }
.figure-carousel__track button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .figure-carousel { -webkit-mask-image: none; mask-image: none; }
  .figure-carousel__track { transition: none; }
  .figure-carousel__track button { opacity: 1; }
}

/* A STRIP OF FIGURES: several figure wells on one row, each with its caption */
.figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: clamp(18px, 2vw, 28px); }
.figures .plate__figure { margin: 0; }
.figures h3 { margin: 14px 0 0; }
.band .figures { margin-top: 28px; }
/* Critical Fate's decks: cards lift and tilt as the pointer reaches them */
.figures--deck { display: flex; flex-wrap: wrap; justify-content: center; }
.figures--deck > * { flex: 1 1 170px; max-width: 220px; background: none; border: 0; padding: 0; overflow: visible; transition: transform var(--t-tilt) var(--ease); text-align: center; }
.figures--deck > *:hover { transform: translateY(-10px) rotate(-2deg); }
.figures--deck img { filter: var(--drop-deck); }
.figures--deck h3 { margin-top: 14px; }
.deck-pairs { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start; gap: clamp(28px, 3vw, 56px); margin-top: 28px; }
.deck-pair { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.deck-pair .rule-label { color: var(--ink-quiet); margin: 0; }
.deck-pair .figures--deck { margin-top: 0; flex-wrap: nowrap; }
.deck-pair .figures--deck > * { flex: 0 1 190px; }
@media (prefers-reduced-motion: reduce) { .figures--deck > *:hover { transform: none; } }

/* QUESTIONS: a list of cards that open in place */
.qa { display: flex; flex-direction: column; gap: 10px; max-width: var(--measure); }
.qa details { background: var(--surface); border: 1px solid var(--rule-faint); border-radius: var(--r-figure); transition: background var(--t-quick), border-color var(--t-quick); }
.qa details[open] { border-color: var(--rule); }
.qa summary { list-style: none; cursor: pointer; padding: 18px 64px 18px 20px; position: relative; min-height: var(--tap); }
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
  content: "+"; position: absolute; right: 16px; top: 50%; margin-top: -16px;
  width: 32px; height: 32px; border-radius: var(--r-round);
  border: 1px solid var(--rule); color: var(--accent);
  display: grid; place-items: center; font-size: var(--t-glyph); line-height: 1;
  transition: transform var(--t-hover) var(--ease), background var(--t-quick), color var(--t-quick);
}
.qa details[open] summary::after { transform: rotate(45deg); background: var(--btn-bg); border-color: var(--btn-bg); color: var(--btn-fg); }
.qa summary:hover { color: var(--accent); }
.qa details > p { margin: 0; padding: 0 20px 20px; color: var(--ink); }

/* ============================================================
   READ PAGES: policies, terms, shipping and the app's documents.
   An "On this page" menu beside one reading column. Sections are
   divided by a gold hairline that fades, never by a hard rule.
   ============================================================ */
.doc { display: flex; flex-wrap: wrap; gap: 56px; align-items: flex-start; }
.toc {
  flex: 1 1 200px; max-width: var(--toc-w);
  display: flex; flex-direction: column; gap: 2px;
  background: var(--surface); border: 1px solid var(--rule-faint); border-radius: var(--r-card);
  padding: 16px 10px; font-size: var(--t-ui-small);
}
.toc .label { margin: 4px 12px 10px; }
.toc a { display: block; padding: 8px 12px; border-radius: var(--r-small); color: var(--ink-quiet); text-decoration: none; }
.toc a:hover { background: var(--well); color: var(--text-strong); }
.prose { flex: 999 1 560px; min-width: 0; max-width: var(--measure); }
.prose h2 {
  font-size: var(--t-title);
  margin: clamp(40px, 4vw, 56px) 0 16px;
  padding-top: 20px;
  background: linear-gradient(90deg, var(--rule), transparent 70%) top / 100% 1px no-repeat;
}
.prose > :first-child { margin-top: 0; }
.prose h2:first-child { padding-top: 0; background: none; }
.prose ul, .prose ol { margin: 0 0 18px; padding-left: 22px; max-width: var(--measure); }
.prose li { margin-bottom: 8px; }
.prose li::marker { color: var(--accent); }
.prose strong, .prose b { font-family: var(--display); font-weight: 600; color: var(--text-strong); }
.prose .ledger { margin-top: 26px; }

/* ============================================================
   THE HELP CENTRE: Campaign Journal support. The lamp and embers
   stay in the head; below it the page calms into a manual: topics,
   a step guide whose phone follows the open step (js/help.js), and
   questions the search box filters.
   ============================================================ */
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.page-head--center { text-align: center; display: flex; flex-direction: column; align-items: center; }
.help-search { display: none; position: relative; width: 100%; max-width: 640px; margin: 10px 0 4px; }
.js .help-search { display: block; }
.help-search svg { position: absolute; left: 20px; top: 50%; margin-top: -10px; width: 20px; height: 20px; color: var(--accent); }
.help-search input {
  width: 100%; padding: 18px 20px 18px 54px;
  border: 1px solid var(--rule); border-radius: var(--r-control);
  background: var(--surface); color: var(--text-strong);
  font-family: var(--text); font-size: var(--t-standfirst);
  box-shadow: var(--halo-field);
}
.help-search input::placeholder { color: var(--ink-quiet); }
.help-search input:focus { outline: none; border-color: var(--accent); box-shadow: var(--focus-ring); }

.help { display: flex; flex-wrap: wrap; gap: var(--help-gap); align-items: flex-start; }
.help .toc .label { margin-top: 14px; }
.help .toc .label:first-child { margin-top: 4px; }
.help__main { flex: 999 1 560px; min-width: 0; display: flex; flex-direction: column; gap: clamp(56px, 6vw, 80px); }
/* side by side, the topics column is a fixed 250px, so the head above can centre its title,
   search and standfirst over the main column instead of the whole sheet. One breakpoint
   decides both: narrower, the topics stack below the main column and the head centres on the sheet */
@media (min-width: 960px) {
  .help { display: grid; grid-template-columns: var(--toc-w) minmax(0, 1fr); }
  .help > .toc { max-width: none; }
  .page-head--help { padding-left: calc(var(--margin) + var(--toc-w) + var(--help-gap)); }
  .page-head--help > .ambient { --lamp-shift: calc(var(--lamp-w) / -2 + (var(--toc-w) + var(--help-gap)) / 2); }
}
/* on a phone the topics follow the guides, so the answers come first */
@media (max-width: 959px) { .help > * { flex-basis: 100%; max-width: none; } .help > .toc { order: 2; } }
.help__section > h2 { margin-bottom: 14px; }
.help__section > .label { margin: 0 0 10px; }
.help__empty { margin-top: 16px; color: var(--ink-quiet); }
.help-search__status { margin: 0 0 6px; font-size: var(--t-caption); color: var(--ink-quiet); }

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: 14px; }
.tile {
  display: flex; flex-direction: column; gap: 8px; padding: 22px;
  background: var(--surface); border: 1px solid var(--rule-faint); border-radius: var(--r-card);
  color: var(--ink-quiet); text-decoration: none; font-size: var(--t-caption);
  transition: transform var(--t-hover) var(--ease), border-color var(--t-quick), box-shadow var(--t-hover);
}
.tile:hover { transform: translateY(-4px); border-color: var(--rule); box-shadow: var(--shadow); color: var(--ink-quiet); }
.tile svg { width: 26px; height: 26px; color: var(--accent); }
.tile__name { font-family: var(--display); font-weight: 700; font-size: var(--t-name); color: var(--text-strong); }

.guide { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 28px; align-items: start; margin-top: 24px; }
.guide__steps { list-style: none; margin: 0; padding: 0; counter-reset: guide; display: flex; flex-direction: column; gap: 8px; }
.guide__steps details { border: 1px solid transparent; border-radius: var(--r-figure); transition: background var(--t-quick), border-color var(--t-quick); }
.guide__steps details[open] { background: var(--surface); border-color: var(--rule); box-shadow: var(--shadow); }
.guide__steps summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 16px;
  padding: 16px 18px; min-height: var(--tap);
  font-family: var(--display); font-weight: 700; font-size: var(--t-name); color: var(--text-strong);
}
.guide__steps summary::-webkit-details-marker { display: none; }
.guide__steps summary::before {
  counter-increment: guide; content: counter(guide);
  flex: none; width: 34px; height: 34px; border-radius: var(--r-round);
  border: var(--line-bold) solid var(--rule); color: var(--accent);
  display: grid; place-items: center; font-size: var(--t-ui-small);
}
.guide__steps details[open] summary::before { background: var(--btn-bg); border-color: var(--btn-bg); color: var(--btn-fg); }
.guide__steps summary:hover { color: var(--accent); }
.guide__steps details > p { margin: 0; padding: 0 18px 18px 68px; color: var(--ink); }
.guide__screen {
  position: relative; margin: 0; height: 600px; overflow: hidden;
  display: grid; place-items: center;
  background: var(--surface-deep); border: 1px solid var(--rule-faint); border-radius: var(--r-card);
}
.guide__screen img { position: relative; z-index: var(--z-content); height: 520px; width: auto; filter: var(--drop-screen); }
.guide__screen img.is-new { animation: dwArrive var(--t-arrive) var(--ease); }
@keyframes dwArrive { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .guide__screen img.is-new { animation: none; } .tile:hover { transform: none; } }

.help__cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 16px; }
.help-card { padding: 32px; border-radius: var(--r-card); background: var(--surface); border: 1px solid var(--rule-faint); display: flex; flex-direction: column; gap: 14px; }
.help-card h2 { font-size: var(--t-title); margin: 0; }
.help-card p { margin: 0; }
.help-card--feature { background: linear-gradient(160deg, var(--surface-raised), var(--surface)); border-color: var(--rule); }

/* ============================================================
   THE CLOSER: a page's sign-off. A solid, dedicated band (it is the
   one place the page asks for something), ruled gold on top.
   ============================================================ */
.closer { position: relative; overflow: hidden; background: var(--surface); border-top: 2px solid var(--edge); border-bottom: 1px solid var(--rule-faint); }
.closer__inner {
  position: relative; z-index: var(--z-content);
  max-width: var(--sheet); margin: 0 auto;
  padding: clamp(56px, 7vw, 96px) var(--margin);
  display: flex; flex-direction: column; align-items: center; gap: 18px; text-align: center;
}
.closer h2 { margin: 0; }
.closer p { margin: 0; color: var(--ink); max-width: 44ch; }
.closer p em { font-family: var(--display); font-style: normal; font-weight: 600; color: var(--accent); }
.closer__actions { display: flex; flex-wrap: wrap; gap: 12px 14px; align-items: center; justify-content: center; margin-top: 10px; }

/* ============================================================
   FORMS: the contact page's form and the notify dialog's field
   ============================================================ */
.form label { display: block; margin-bottom: 18px; }
.form__k { display: block; margin-bottom: 8px; }
.form input, .form select, .form textarea, .dw-notify__form input[type=email] {
  width: 100%;
  padding: 13px 15px;
  border: 1px solid var(--rule);
  border-radius: var(--r-control);
  background: var(--well);
  color: var(--text-strong);
  font-family: var(--text);
  font-size: var(--t-field);
  line-height: 1.5;
}
.form textarea { resize: vertical; }
.form input:focus, .form select:focus, .form textarea:focus, .dw-notify__form input[type=email]:focus {
  outline: none; border-color: var(--accent); box-shadow: var(--focus-ring);
}
#dw-notify input::placeholder, .form input::placeholder { color: var(--ink-quiet); }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 clamp(16px, 2vw, 26px); }
.form .cf-turnstile { margin: 4px 0 18px; }
/* The worker redirects to /contact#sent or /contact#error after a post, so the
   result is :target state and needs no script. */
.form-flash { display: none; margin: 0 0 24px; padding: 14px 16px; border: 1px solid var(--rule); border-radius: var(--r-control); max-width: none; }
.form-flash:target, .form-flash.is-shown { display: block; }
.form-flash--ok:target { border-color: var(--ok); color: var(--text-strong); }
.form-flash--err:target, .form-flash--err.is-shown { border-color: var(--err); color: var(--text-strong); }
/* the unsubscribe page: once it reports a result, the button has nothing left to do */
.form-flash:target ~ .unsub { display: none; }
.form-alt { margin: 22px 0 0; padding-top: 14px; border-top: 1px solid var(--rule-faint); max-width: none; }
.hp { position: absolute !important; left: -9999px; }   /* honeypot: hidden from humans, visible to bots */

/* Two cards side by side, a form against the particulars */
.plates--pair { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: var(--gutter); align-items: start; }
.plates--pair .ledger__v { flex: 0 1 auto; }
.plate__no + .ledger { margin-top: 0; }

/* NOTIFY DIALOG: markup is injected by js/notify.js; these class
   names are its contract, do not rename them here alone. */
#dw-notify { border: 1px solid var(--rule); border-radius: var(--r-card); background: var(--surface); color: var(--ink); max-width: 440px; width: calc(100% - 32px); padding: 0; box-shadow: var(--shadow); }
#dw-notify::backdrop { background: var(--scrim); }
.dw-notify__body { padding: 32px 28px 26px; position: relative; }
.dw-notify__x { margin: 0; }
/* z-index is load-bearing: the body is position relative and painted over the cross */
.dw-notify__x button { position: absolute; z-index: var(--z-over); top: 6px; right: 8px; background: none; border: none; color: var(--ink-quiet); font-size: var(--t-close); line-height: 1; cursor: pointer; padding: 6px 10px; }
.dw-notify__x button:hover { color: var(--text-strong); }
#dw-notify h2 { font-size: var(--t-title); margin: 0 0 8px; }
.dw-notify__sub { color: var(--ink-quiet); margin: 0 0 18px; }
.dw-notify__form { display: flex; flex-direction: column; gap: 12px; }
.dw-notify__note { margin: 14px 0 0; }
.dw-notify__note a { color: var(--ink-quiet); }
.dw-notify__msg { color: var(--accent); margin: 12px 0 0; min-height: 1.1em; }
.dw-notify__msg:empty { margin: 0; }

/* NOT FOUND: one card and nothing else */
.sheet--single { padding-top: var(--step); }
.sheet--single .plate { text-align: center; max-width: 720px; margin: 0 auto; }
.sheet--single .plate p { margin-left: auto; margin-right: auto; }
.sheet--single .plate__actions { justify-content: center; }

/* ============================================================
   IMPRINT: the footer. Its top edge is a gold line that fades out at
   both ends, so the page ends without a cut.
   ============================================================ */
.imprint { background: linear-gradient(90deg, transparent, var(--rule), transparent) top / 100% 1px no-repeat; }
.imprint__inner {
  max-width: var(--sheet); margin: 0 auto;
  padding: 40px var(--margin) 36px;
  display: flex; flex-direction: column; align-items: center; gap: 16px; text-align: center;
}
.imprint__brand { display: flex; align-items: center; gap: 12px; margin: 0; color: var(--ink-quiet); font-size: var(--t-caption); }
.imprint__mark { width: 32px; height: 32px; }
.imprint nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 22px; }
.imprint nav a { color: var(--ink-quiet); text-decoration: none; font-size: var(--t-caption); }
.imprint nav a:hover { color: var(--accent); }
.imprint__colophon { margin: 0; max-width: none; }
.imprint__stores { margin: 0; max-width: var(--measure); }

/* ============================================================
   THE STYLEGUIDE: scaffolding for the specimen sheet, nothing else
   ============================================================ */
.sg-swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(178px, 1fr)); gap: 14px; }
.sg-swatch { border: 1px solid var(--rule-faint); border-radius: var(--r-figure); overflow: hidden; background: var(--surface); }
.sg-swatch .chip { height: 74px; border-bottom: 1px solid var(--rule-faint); }
.sg-swatch .meta { padding: 10px 12px; color: var(--ink); }
.sg-swatch code { display: block; margin-top: 3px; }
.sg-spec { display: grid; grid-template-columns: minmax(0, 1fr) 200px; gap: 24px; align-items: baseline; padding: 18px 0; border-bottom: 1px solid var(--rule-faint); }
.sg-spec > :first-child { margin: 0; max-width: none; }
.sg-spec__note { color: var(--ink-quiet); text-align: right; margin: 0; }
.sg-display { font-family: var(--display); font-weight: 700; font-size: var(--t-display); line-height: 1.08; letter-spacing: -0.025em; color: var(--text-strong); }
.sg-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.sg-note { margin: 12px 0 0; }
.sg-note + .sg-row { margin-top: 22px; }
.sg-stage { position: relative; min-height: 220px; border: 1px solid var(--rule-faint); border-radius: var(--r-card); overflow: hidden; display: grid; place-items: center; }

/* ============================================================
   NARROW SHEETS
   ============================================================ */
@media (max-width: 1080px) {
  .plate__grid { grid-template-columns: minmax(0, 1fr); }
  .plates--pair { grid-template-columns: minmax(0, 1fr); gap: var(--step); }
  .band__grid { grid-template-columns: minmax(0, 1fr); }
}

/* The menu folds behind the burger. .js is set on <html> by the head script, so with no
   script the menu stays open and every page is still reachable. */
@media (max-width: 820px) {
  .js .menu-toggle { display: grid; }
  .masthead__inner { gap: 12px 16px; }
  .masthead__nav { order: 3; flex-basis: 100%; }
  .js .masthead__nav { display: none; }
  .js .masthead.is-open .masthead__nav { display: block; }
  .masthead__nav ul { flex-direction: column; gap: 0; padding: 4px 0 12px; }
  .masthead__nav > ul > li > a { padding: 14px 0; font-size: var(--t-name); border-bottom: 1px solid var(--rule-faint); }
  /* on a phone the Shop menu is always open beneath its heading */
  .masthead__sub { position: static; visibility: visible; opacity: 1; transform: none; box-shadow: none; border: 0; background: none; padding: 0 0 6px 14px; min-width: 0; }
  .masthead__sub a { font-size: var(--t-menu); padding: 10px 0; }
  .masthead__tools .btn { display: none; }
}

@media (max-width: 720px) {
  :root { --t-body: 16.5px; }
  .ledger__row { flex-wrap: wrap; gap: 4px 12px; }
  .ledger__leader { display: none; }
  .ledger__v { text-align: left; }
  .plate__stamp { position: static; display: inline-block; margin-bottom: 14px; }
  .plate__actions .btn, .closer__actions .btn, .hero__actions .btn { flex: 1 1 100%; }
  .form__row { grid-template-columns: minmax(0, 1fr); }
  .feature__phones { height: 440px; }
  .feature__phones img { height: 330px; top: 44px; }
  .feature__phones img:nth-child(3) { height: 400px; margin-left: -95px; top: 0; }
  .toc { max-width: none; }
  .sg-spec { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .sg-spec__note { text-align: left; }
  .die-spin { width: 420px; height: 420px; margin-left: -210px; }
  .guide__screen { height: 440px; }
  .guide__screen img { height: 380px; }
  .guide__steps details > p { padding-left: 18px; }
}
