/* ══════════════════════════════════════════════════════════════════
   Category page styles — /events, /market, /circles, /arcade, /gist.
   ONE stylesheet for all five so a change lands everywhere at once.
   The sub-pages were previously each self-contained with their own
   <style>, which is fine for one bespoke page and awful for a set.
   /gist was the last holdout — it kept its own inline stylesheet, its
   own type scale and a purple gradient nothing else on the site used,
   so the fifth door opened onto a different website.

   Voice rules these styles support (see docs/repo-memory/
   product-categories-and-spines.md):
     * value first — the page says what you GET, never what you're
       currently doing wrong,
     * no claims — the price stub shows numbers and argues nothing,
     * limits stated out loud — `.limits` is styled as information,
       not as a warning, because it is not an apology.
   ══════════════════════════════════════════════════════════════════ */

:root {
  --cat-bg: #0A0A0A;
  --cat-panel: #131316;
  --cat-panel-2: #191920;
  --cat-line: rgba(255, 255, 255, .09);
  --cat-line-2: rgba(255, 255, 255, .17);
  --cat-text: #F3F2F0;
  --cat-text-2: #A5A39E;
  /* was #6C6A65 — 3.66:1, and 1.56 once a dream sat behind it */
  --cat-text-3: #928E86;
  --cat-accent: #E63946;
  --cat-gold: #F5C542;
  --cat-good: #35C88A;
  --cat-paper: #F6F2E8;
  /* Height of the dream band at the top of every category hero. Read by
     BOTH `.hero`'s padding-top and `.hero > aura-dream`'s height, so the
     artwork and the headline can never overlap by drifting apart. */
  --strip-h: clamp(110px, 15vh, 170px);
  --cat-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --cat-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--cat-bg);
  color: var(--cat-text);
  font-family: var(--cat-font);
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 820px; margin: 0 auto; padding: 0 clamp(1.15rem, 5vw, 2.25rem); }

/* ── Sideways nav ────────────────────────────────────────────────────
   Carries what the page doesn't. There's no fork on a category page, so
   the OTHER categories are the thing missing from this screen and belong
   here. The current category is deliberately absent — the page you're on
   is not somewhere to navigate to.
   (The front page does the inverse: its fork shows all five above the
   fold, so its nav holds only About and the two actions.)              */
.catnav {
  display: flex;
  align-items: center;
  gap: clamp(.6rem, 2vw, 1.4rem);
  flex-wrap: wrap;
  max-width: 820px;
  margin: 0 auto;
  padding: 1.1rem clamp(1.15rem, 5vw, 2.25rem);
  font-size: .87rem;
}
.catnav a { text-decoration: none; }
.catnav-home { color: var(--cat-text-2); font-weight: 600; white-space: nowrap; }
.catnav-home:hover { color: var(--cat-text); }
.catnav-links { display: flex; gap: clamp(.6rem, 1.8vw, 1.15rem); flex-wrap: wrap; margin-left: auto; }
.catnav-links a { color: var(--cat-text-3); }
.catnav-links a:hover { color: var(--cat-text-2); }
.catnav-cta {
  color: var(--cat-text);
  border: 1px solid var(--cat-line-2);
  border-radius: 6px;
  padding: .3rem .7rem;
  font-weight: 600;
  white-space: nowrap;
}
.catnav-cta:hover { border-color: var(--cat-accent); }
.catnav a:focus-visible { outline: 2px solid var(--cat-gold); outline-offset: 3px; border-radius: 4px; }

/* Below the fold-ish on a phone the sideways links matter less than the
   headline, so they drop under the home link rather than squeezing it. */
@media (max-width: 560px) {
  .catnav-links { margin-left: 0; order: 3; width: 100%; }
  .catnav-cta { margin-left: auto; }
}

.back {
  display: inline-block;
  margin: 1.75rem 0 0;
  color: var(--cat-text-3);
  text-decoration: none;
  font-size: .85rem;
}
.back:hover { color: var(--cat-text-2); }

.eyebrow {
  font-family: var(--cat-mono);
  font-size: .67rem;
  letter-spacing: .17em;
  text-transform: uppercase;
  color: var(--cat-text-3);
  display: block;
}

h1 {
  font-size: clamp(1.95rem, 4.8vw, 2.9rem);
  line-height: 1.09;
  letter-spacing: -.03em;
  font-weight: 700;
  text-wrap: balance;
  max-width: 16ch;
  margin: 0;
}
h2 {
  font-size: clamp(1.2rem, 2.4vw, 1.5rem);
  line-height: 1.25;
  letter-spacing: -.02em;
  font-weight: 650;
  text-wrap: balance;
  margin: 0;
}
p { margin: 0; }
.lede { color: var(--cat-text-2); max-width: 56ch; }
.small { font-size: .87rem; color: var(--cat-text-3); }

/* Links inside body copy — the "tell me" in every limits section, and the
   handful of cross-links. Unstyled they fall back to the browser's default
   blue, which on this ground reads as an unfinished page rather than a
   link. Underline stays; only the colour is ours. Footer and nav links
   are addressed separately and sit outside <p>/<dd>, so they don't collide. */
p a, dd a {
  color: var(--cat-text);
  text-decoration-color: var(--cat-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: .2em;
}
p a:hover, dd a:hover { color: var(--cat-accent); }
p a:focus-visible, dd a:focus-visible { outline: 2px solid var(--cat-gold); outline-offset: 3px; border-radius: 3px; }

.stack { display: flex; flex-direction: column; align-items: flex-start; gap: 1.15rem; }

/* ── The ask is brand, not category ────────────────────────────────
   This was `background: var(--cat-accent); color: #fff`, so the primary
   button took whichever hue the page happened to be wearing. Measured,
   a white label failed on ALL FIVE:

     gist    #2E9E63  3.39      circles #5B78C4  4.26
     events  #E63946  4.17      arcade  #8C6BD8  4.03
     market  #D9A441  2.25   ← worst, and it is the shop page

   None reach 4.5, because each hue was chosen for mood and none of them
   was ever asked to carry type. Market's gold is the clearest proof: a
   colour can be exactly right for a page and still be unable to hold a
   label.

   So the CONTROLS go to the brand — the metal ramp with an ink label,
   7.80 at its darkest stop and 11.60 at its lightest — while the washes,
   the signatures and the dream palettes stay per-category. Colour still
   tells you which room you are in; it just stops deciding whether you
   can read the button.
   Doctrine: visual-identity-doctrine.md §5b, §5h.
   ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-block;
  background: linear-gradient(135deg, #EAD491, #CEAB64 55%, #DCC08A);
  color: #241B08;
  font-weight: 600;
  padding: .8rem 1.4rem;
  border-radius: 7px;
  text-decoration: none;
  border: 1px solid #EAD491;
  transition: filter .15s ease;
}
.btn:hover { filter: brightness(1.13); }
.btn:focus-visible { outline: 2px solid var(--cat-gold); outline-offset: 3px; }

/* ══ Per-category signature ════════════════════════════════════════
   The four pages share a chassis, so without this they are the same
   black page four times. Each category gets a cloth it belongs to —
   the same palettes the dreams were repainted in — and that colour
   runs the whole page, not just the hero, so the background follows
   you down rather than stopping at the fold.

     events   ochre + drum-skin red   — arrival, the call
     market   Asante gold + green     — cloth made, cloth sold
     circles  indigo + undyed cotton  — adire, a pattern held by ties
     arcade   amber + violet          — the table, lit
     gist     leaf green + brass      — two heads talking, and the
                                        drum that says words

   Gist takes the one hue none of the others lead with. That is not
   only to keep them apart: Gist is the layer the other four stand on,
   so reading as a fifth flavour of the same red-gold family would
   have been the wrong signal.

   `--cat-wash` is the page-wide bloom; `--cat-accent` is the button
   and the eyebrow. The dream sets in /dreams/<category>.json are
   painted from the same palettes, so the hero and the page below it
   are the same colour by construction, not by coincidence.
   ════════════════════════════════════════════════════════════════ */
body[data-cat="events"] {
  --cat-accent: #E63946;
  --cat-signal: #F5C542;
  --cat-wash: rgba(230, 57, 70, .13);
  --cat-wash-2: rgba(245, 197, 66, .07);
}
body[data-cat="market"] {
  --cat-accent: #D9A441;
  --cat-signal: #35A06A;
  --cat-wash: rgba(217, 164, 65, .12);
  --cat-wash-2: rgba(30, 122, 60, .09);
}
body[data-cat="circles"] {
  --cat-accent: #5B78C4;
  --cat-signal: #EAE6DA;
  --cat-wash: rgba(30, 56, 116, .20);
  --cat-wash-2: rgba(234, 230, 218, .05);
}
body[data-cat="arcade"] {
  --cat-accent: #8C6BD8;
  --cat-signal: #F5C542;
  --cat-wash: rgba(124, 95, 207, .16);
  --cat-wash-2: rgba(245, 197, 66, .06);
}
/* The green and the gold are lifted straight out of dream-13, which is
   also the artwork on the profile in the hero shot — the two-heads motif
   turns up on this page three times without being placed there. */
body[data-cat="gist"] {
  --cat-accent: #2E9E63;
  --cat-signal: #F0CE7C;
  --cat-wash: rgba(42, 140, 72, .17);
  --cat-wash-2: rgba(240, 206, 124, .06);
}

/* The wash itself: fixed, so it doesn't scroll away, and behind
   everything. Two soft pools rather than one flat tint — a flat tint
   just makes the black look wrong, whereas pools read as light. */
body[data-cat]::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(58% 44% at 78% 4%, var(--cat-wash), transparent 68%),
    radial-gradient(50% 40% at 12% 42%, var(--cat-wash-2), transparent 72%);
}

/* ── Hero: headline left, a preview of what you get on the right ── */
.hero {
  /* padding-top now also has to clear the dream band, which is absolutely
     positioned at the top of this box. One variable so the two can never
     drift apart and drop artwork on top of a headline. */
  padding: calc(var(--strip-h) + clamp(1.75rem, 4vw, 2.75rem))
           0 clamp(2.25rem, 5vw, 3rem);
  position: relative;
  isolation: isolate;
}

/* ── <aura-dream> in ambient mode ──────────────────────────────────
   The component and its base styles live in landing-shared.css, which
   these pages deliberately do NOT load — its tokens collide with the
   ones above. So the ambient case is restated here, and only the
   ambient case: category heroes never use stage mode.
   ──────────────────────────────────────────────────────────────── */
/* ── The dream is a BAND, not a backdrop ───────────────────────────
   This used to be `inset: 0` — the artwork filled the hero and the
   headline sat on top of it at .34 opacity, with a partial scrim.

   That is the worst of both. Composited through the wash, the dream and
   the overlay, secondary copy measured:

     wash only        3.14
     mid dream        2.36
     bright dream     1.56      ← against a 4.5 floor

   and it VARIED with whichever dream happened to be rotating, so there
   was no number to hold. Meanwhile .34 is too dim to read as artwork —
   the page paid the full legibility cost and showed almost nothing.

   Given a band of its own it runs at FULL strength and costs nothing,
   because no text crosses it. Same move as the front page.
   Doctrine: visual-identity-doctrine.md §5h.
   ──────────────────────────────────────────────────────────────── */
.hero > aura-dream {
  display: block;
  position: absolute;
  top: 0;
  bottom: auto;
  /* Full-bleed out of the centred .wrap, so the band reaches both edges
     the way the front page's does. */
  left: 50%;
  transform: translateX(-50%);
  width: 100vw;
  height: var(--strip-h);
  overflow: hidden;
  background: #08070A;
  z-index: 0;
  pointer-events: none;
}
/* A lit edge, so the band reads as a deliberate object rather than as
   artwork that happened to get cropped. */
.hero > aura-dream::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 2px;
  z-index: 2;
  background: linear-gradient(90deg, #785520, #EAD491, #785520);
}
.hero > aura-dream .aura-dream__stage {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.hero > aura-dream .aura-dream__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  opacity: 0;
  transition: opacity 1.6s ease;
  pointer-events: none;
}
/* Full strength. This is the entire reason for giving it a band —
   .34 was the number that made the artwork invisible AND the text
   unreadable, which is a cost with no benefit on either side. */
.hero > aura-dream .aura-dream__frame.is-visible { opacity: 1; }
/* The overlay existed to scrim a headline that no longer sits here.
   Kept as an element (the component renders it) but given nothing to
   do — a fade to --cat-bg over full-strength art would just re-dim it. */
.hero > aura-dream .aura-dream__overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: none;
}
.hero > .wrap { position: relative; z-index: 1; }
.hero-grid {
  display: grid;
  grid-template-columns: 1fr minmax(0, 320px);
  gap: clamp(2rem, 5vw, 3.25rem);
  align-items: center;
}

/* ── The shot: a real page, photographed ──────────────────────────
   Not a mock. `ops/landing/capture-shots.mjs` shoots the live SSR
   pages on a phone-emulated headless Chrome; these are those PNGs.
   The whole thing is a link, because a screenshot of a page you can
   go and stand on should take you there.
   ─────────────────────────────────────────────────────────────── */
.shot {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: transform .3s ease;
}
.shot:hover { transform: translateY(-4px); }
.shot-frame {
  display: block;
  position: relative;
  border-radius: 26px;
  padding: 5px;
  background: linear-gradient(160deg, #26262E, #101014 60%);
  border: 1px solid var(--cat-line-2);
  box-shadow: 0 26px 52px rgba(0, 0, 0, .6);
}
.shot-crop {
  display: block;
  height: 560px;
  overflow: hidden;
  border-radius: 21px;
  /* The capture is taller than the frame on purpose — the page keeps
     going, so the bottom edge should dissolve rather than guillotine.
     Keep the fade in the last tenth: the prices sit just above it and
     they are the whole reason the shot is here. */
  -webkit-mask-image: linear-gradient(180deg, #000 88%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 88%, transparent 100%);
}
.shot-crop img {
  display: block;
  width: 100%;
  height: auto;
}
.shot-cap {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: .85rem;
  font-family: var(--cat-mono);
  font-size: .62rem;
  letter-spacing: .06em;
  color: var(--cat-text-3);
}
.shot-cap .live {
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: .38rem;
  white-space: nowrap;
  color: var(--cat-good);
  text-transform: uppercase;
  letter-spacing: .14em;
}
.shot-cap .live::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--cat-good);
}
.shot-cap .url {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.shot:hover .url { color: var(--cat-text-2); }

section { padding: clamp(2.5rem, 6vw, 3.5rem) 0; }
.sec-head { display: flex; flex-direction: column; gap: .55rem; margin-bottom: 1.9rem; }

/* ── The tear: a ticket perforation instead of a rule ── */
.tear {
  height: 13px;
  background: radial-gradient(6.5px at 6.5px 50%, var(--cat-bg) 98%, transparent 100%) 0 0/26px 13px repeat-x;
  border-top: 1px dashed var(--cat-line-2);
}

/* ── "What you get" rows ── */
dl.rows { display: grid; margin: 0; }
dl.rows > div {
  display: grid;
  grid-template-columns: 10.5rem 1fr;
  gap: 1.5rem;
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--cat-line);
  align-items: baseline;
}
dl.rows > div:last-child { border-bottom: none; }
dt { font-weight: 600; letter-spacing: -.01em; margin: 0; }
dd { color: var(--cat-text-2); font-size: .96rem; margin: 0; }

/* ── Price stub. Shows numbers, argues nothing. ── */
.receipt-grid {
  display: grid;
  grid-template-columns: minmax(0, 415px) 1fr;
  gap: clamp(2rem, 4.5vw, 3rem);
  align-items: start;
}
.receipt {
  background: var(--cat-paper);
  color: #17170F;
  font-family: var(--cat-mono);
  padding: 1.5rem 1.4rem 1.15rem;
  margin: 0;
  transform: rotate(-1.1deg);
  filter: drop-shadow(0 16px 30px rgba(0, 0, 0, .55));
  -webkit-mask:
    radial-gradient(6px at 6px 50%, transparent 98%, #000) -6px 0/12px 100% repeat-y,
    linear-gradient(#000 0 0) 0 0/100% 100% no-repeat;
  mask:
    radial-gradient(6px at 6px 50%, transparent 98%, #000) -6px 0/12px 100% repeat-y,
    linear-gradient(#000 0 0) 0 0/100% 100% no-repeat;
}
.r-head { text-align: center; border-bottom: 2px dashed rgba(0,0,0,.24); padding-bottom: .7rem; margin-bottom: .3rem; }
.r-title { font-weight: 700; letter-spacing: .15em; font-size: .71rem; text-transform: uppercase; }
.r-sub { font-size: .67rem; color: #5C5A4F; margin-top: .25rem; }
.receipt table { width: 100%; border-collapse: collapse; font-size: .78rem; font-variant-numeric: tabular-nums; }
.receipt th {
  font-size: .63rem; letter-spacing: .07em; text-transform: uppercase;
  color: #5C5A4F; font-weight: 500; text-align: right; padding: .75rem 0 .4rem;
}
.receipt th:first-child { text-align: left; }
.receipt td { padding: .32rem 0; text-align: right; }
.receipt td:first-child { text-align: left; font-weight: 600; }
.receipt .us { color: #A32B34; font-weight: 700; }
.receipt tbody tr + tr td { border-top: 1px solid rgba(0,0,0,.07); }
.receipt .muted td { color: #5C5A4F; font-size: .72rem; }
.receipt .tot td { border-top: 2px dashed rgba(0,0,0,.24); padding-top: .55rem; font-weight: 700; color: #A32B34; }
.r-foot { font-size: .64rem; color: #5C5A4F; margin-top: .85rem; border-top: 2px dashed rgba(0,0,0,.24); padding-top: .65rem; line-height: 1.55; }

/* ── Limits: information, never a warning ── */
.limits dt { color: var(--cat-text-2); }
.limits dd { color: var(--cat-text-3); }

/* ── Previews ── */
.preview {
  background: var(--cat-panel-2);
  border: 1px solid var(--cat-line-2);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 22px 44px rgba(0,0,0,.55);
  margin: 0;
  font-size: .82rem;
}
.pv-cover { height: 86px; position: relative; }
.pv-cover span {
  position: absolute; left: 12px; bottom: 9px;
  font-family: var(--cat-mono); font-size: .58rem; letter-spacing: .13em;
  text-transform: uppercase; color: rgba(255,255,255,.85);
}
.pv-body { padding: .95rem 1rem 1.1rem; display: flex; flex-direction: column; gap: .8rem; }
.pv-title { font-weight: 700; font-size: 1rem; letter-spacing: -.02em; line-height: 1.25; }
.pv-meta { color: var(--cat-text-3); font-size: .74rem; line-height: 1.5; }
.pv-rows { display: flex; flex-direction: column; gap: .4rem; }
.pv-row {
  display: flex; justify-content: space-between; gap: .75rem;
  padding: .5rem .6rem; border: 1px solid var(--cat-line); border-radius: 7px;
  background: rgba(255,255,255,.022);
}
.pv-row .n { color: var(--cat-text-2); }
.pv-row .p { font-family: var(--cat-mono); font-variant-numeric: tabular-nums; }
.pv-row.sold .n, .pv-row.sold .p { color: var(--cat-text-3); text-decoration: line-through; }
.pv-buy { background: var(--cat-accent); color: #fff; text-align: center; font-weight: 600; padding: .55rem; border-radius: 7px; font-size: .84rem; }
.pv-foot { text-align: center; color: var(--cat-text-3); font-size: .68rem; }
.pv-items { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--cat-line); }
.pv-item { background: var(--cat-panel-2); padding: .7rem .75rem .8rem; display: flex; flex-direction: column; gap: .45rem; }
.pv-swatch { height: 54px; border-radius: 6px; }
.pv-label { font-size: .72rem; color: var(--cat-text-2); line-height: 1.35; }
.pv-price { font-family: var(--cat-mono); font-size: .74rem; font-variant-numeric: tabular-nums; }
.pv-top { display: flex; gap: .65rem; align-items: center; padding: .85rem .9rem; border-bottom: 1px solid var(--cat-line); }
.pv-avatar { width: 34px; height: 34px; border-radius: 50%; flex: none; }

/* ── Game chips ── */
.chips { display: flex; flex-wrap: wrap; gap: .4rem; }
.chip {
  font-family: var(--cat-mono); font-size: .72rem; padding: .3rem .6rem;
  border: 1px solid var(--cat-line); border-radius: 5px;
  color: var(--cat-text-2); background: rgba(255,255,255,.022);
}

footer {
  border-top: 1px solid var(--cat-line);
  padding: 2rem 0 3rem;
  color: var(--cat-text-3);
  font-size: .84rem;
}
footer a { color: var(--cat-text-2); }

@media (max-width: 760px) {
  .hero-grid { grid-template-columns: 1fr; }
  .receipt-grid { grid-template-columns: 1fr; }
  .receipt { transform: none; }
  dl.rows > div { grid-template-columns: 1fr; gap: .3rem; }
  /* A phone rendered life-size on a phone reads as a bug, not a product
     shot. Hold it to something you'd hold at arm's length. */
  .shot { max-width: 268px; margin: 0 auto; }
  .shot-crop { height: 470px; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
