/* CUTE KITTY WAR COMMAND — the house style.
   A war-room dossier that stayed cozy: deep plum-charcoal (the game's
   own storm dark), warm off-white type, and RARITY COLORS LIFTED
   STRAIGHT FROM THE GAME (data/items.gd TIER_COLORS) so even the
   palette is authoritative. Dark by default; one stylesheet, no fonts
   to fetch, no build step. */

:root {
  --bg:        #17131e;   /* storm dark, a hint of plum */
  --bg-2:      #1f1929;   /* raised surface */
  --bg-3:      #2a2136;   /* rows, chips */
  --line:      #3a2f4a;   /* hairlines */
  --ink:       #ece7f2;   /* primary text */
  --ink-dim:   #a294b4;   /* secondary text */
  --ink-faint: #6f6280;   /* labels, meta */
  /* THE PERIWINKLE ACCORD (2026-07-27, Tom's eye + measured color
     theory): the banner texture is hue 243° (blue-violet); the old
     purples sat at 272-275° — a 30° near-miss that never gelled. The
     accents now live at 250-255°, analogous to the banner's own family,
     every pairing WCAG-checked (links 5.8:1 on the dark ground; white
     text 6.6:1 on the highlight). */
  --plum:      #9b7ef1;   /* the Altered accent / links */
  --plum-soft: #5d4db2;
  --gold:      #e8b64a;   /* command gold — coins, highlights */

  /* the game's TIER_COLORS, converted 1:1 from the .gd source */
  --t1: #bfbfbf;  --t2: #66a6ff;  --t3: #bf73ff;  --t4: #ff5959;

  /* THE TYPE SCALE (2026-07-27, Tom's GO): a rem ladder whose display
     steps are fluid — body never moves; headings breathe with the
     viewport. Every middle term carries rem so browser zoom and user
     font preferences keep working (the pure-vw trap). */
  --fs-1s: clamp(1.05rem, .98rem + .3vw, 1.28rem);   /* ledes, h3 */
  --fs-2s: clamp(1.3rem, 1.16rem + .6vw, 1.75rem);   /* section h2 */
  --fs-3s: clamp(1.7rem, 1.44rem + 1.1vw, 2.5rem);   /* page titles */
  --fs-4s: clamp(2.1rem, 1.7rem + 1.9vw, 3.4rem);    /* hero display */

  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 6px 22px rgba(0,0,0,.34);
  --mono: ui-monospace, "Cascadia Code", "Consolas", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font-family: var(--sans); line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--plum); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---- top banner + nav ---- */
/* THE LAVENDER BANNER (2026-07-27, Tom's pick from the menu-strip
   mockups): the game's own menu backdrop — lavender-navy variant,
   cropped to its doodle band — dresses the top bar in BOTH themes.
   Standard practice for fixed-dark banner art: the header is
   permanently dark furniture; only its text is forced light (below,
   in the light-theme block). The bevel: inner top highlight + inner
   bottom highlight + hard dark edge + drop shadow, so the bar reads
   substantial, a shelf the page hangs from (Tom's ask). */
header.command {
  position: sticky; top: 0; z-index: 10;
  /* WIDTH-PROOF (Tom's squish test 2026-07-27: cover zoomed the art
     with window width and fullscreen landed between doodles): the band
     scales to the bar's own height and TILES horizontally — every
     window width shows the same parade. */
  background: #2a2550 url("banner_lavender.0eb2a6f3.jpg") repeat-x center top;
  background-size: auto 100%;
  border-bottom: 1px solid rgba(10, 8, 16, .85);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .07),
    inset 0 -1px 0 rgba(236, 231, 242, .14),
    0 8px 22px rgba(0, 0, 0, .52);
}
.command-inner {
  max-width: 1180px; margin: 0 auto;
  /* the bar breathes with the viewport (Tom 2026-07-27: "small at full
     screen") — fluid height, and the doodle band (auto 100%) grows with
     it, so fullscreen gets a proud banner, laptops stay trim. */
  padding: clamp(12px, 1.6vw, 34px) 20px;
  display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
}
.brand {
  font-weight: 800; font-size: clamp(1.18rem, 1rem + .9vw, 1.7rem);
  letter-spacing: .3px;
  color: var(--ink); white-space: nowrap;
}
.brand .paw { color: var(--gold); }
.brand small { display: block; font-size: .62rem; font-weight: 600;
  letter-spacing: 2.5px; color: var(--ink-faint); text-transform: uppercase; }
/* the toggle rides the brand row, top-right (Tom 2026-07-27); the nav
   takes its own full row beneath, centered under the banner */
nav.sections { display: flex; gap: 4px; flex-wrap: wrap;
  order: 3; flex-basis: 100%; justify-content: center; }
nav.sections a, nav.sections span {
  padding: 6px 11px; border-radius: var(--radius-sm); font-size: .9rem;
  font-weight: 600; color: var(--ink-dim);
}
nav.sections a:hover { background: var(--bg-3); color: var(--ink); text-decoration: none; }
nav.sections a.active { background: var(--plum-soft); color: #fff; }
nav.sections span.soon { color: var(--ink-faint); cursor: not-allowed; }
nav.sections span.soon::after { content: " ·soon"; font-size: .62rem; color: var(--plum-soft); }

/* ---- page frame ---- */
main { max-width: 1180px; margin: 0 auto; padding: 28px 20px 80px; }
.page-title { font-size: var(--fs-3s); font-weight: 800; margin: 0 0 2px; }
.page-sub { color: var(--ink-dim); margin: 0 0 22px; }
.page-sub .count { color: var(--gold); font-weight: 700; }

/* ---- control bar (search + filter chips) ----
   Tom's comb 2026-07-27 ("the ovals don't share space well"): the
   search used to stretch while the chip groups stacked raggedly in the
   leftover corner. Now the search keeps its own measured line and the
   facet groups flow BENEATH it, left-aligned, side by side — calm at
   every width, on every dossier page at once. */
.controls {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 10px; margin-bottom: 18px;
}
.search {
  width: 100%; max-width: 620px;
  background: var(--bg-2); border: 1px solid var(--line); color: var(--ink);
  padding: 10px 14px; border-radius: var(--radius-sm); font-size: .95rem;
}
/* every chip group rides ONE line under the bar (Tom 2026-07-27: the
   beside-the-bar straddle flooded differently per page — under the bar,
   always, deterministically) */
.chipline { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; }
#facets { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; }
.search:focus { outline: 2px solid var(--plum-soft); border-color: transparent; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  padding: 7px 12px; border-radius: 999px; font-size: .82rem; font-weight: 600;
  background: var(--bg-3); color: var(--ink-dim); border: 1px solid transparent;
  cursor: pointer; user-select: none;
}
.chip:hover { color: var(--ink); }
.chip.on { background: var(--plum-soft); color: #fff; }
.chip[data-tier="1"].on { background: var(--t1); color: #111; }
.chip[data-tier="2"].on { background: var(--t2); color: #111; }
.chip[data-tier="3"].on { background: var(--t3); color: #111; }
.chip[data-tier="4"].on { background: var(--t4); color: #111; }

/* ---- the dossier table ---- */
.table-wrap { overflow-x: auto; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--bg-2); }
table.dossier { width: 100%; border-collapse: collapse; font-size: .93rem; }
table.dossier thead th {
  text-align: left; padding: 12px 14px; position: sticky; top: 0;
  /* THE HEADER OUTRANKS THE ROWS (2026-07-28, Tom's comb: creature art
     scrolled UP OVER the heading bar). The plate cells carry
     `position: relative`, so with the header at z-index auto both are
     positioned boxes at layer 0 and the LATER one in DOM order wins —
     the sprite painted over the header. An explicit rank settles it;
     it stays below the site header's own 10. */
  z-index: 3;
  background: var(--bg-3); color: var(--ink-dim); font-weight: 700;
  font-size: .78rem; letter-spacing: .5px; text-transform: uppercase;
  cursor: pointer; white-space: nowrap; border-bottom: 1px solid var(--line);
}
table.dossier thead th:hover { color: var(--ink); }
table.dossier thead th .arrow { color: var(--plum); font-size: .8rem; }
table.dossier tbody td { padding: 11px 14px; border-bottom: 1px solid var(--line); vertical-align: top; }
table.dossier tbody tr:last-child td { border-bottom: none; }
table.dossier tbody tr:hover { background: rgba(184,119,230,.06); }
/* THE DOT STAYS WITH THE NAME (2026-07-26, Tom's comb): the first column pairs
   a colored dot + the name; as inline-block the dot was a wrap point, so long
   names (Apurrentice, Chef Whiskers, Cobblepaws) broke to a line BELOW a
   stranded dot. Flex keeps the dot beside the name's first line; multi-word
   names wrap within their own column with the dot still top-left. */
/* THE CELL IS A CELL AGAIN (2026-07-28, Tom's comb: "a line that breaks
   for warped" + "long names center up different than short names").
   `display:flex` on a <td> stops being a table-cell — the browser wraps
   it in an anonymous cell, so the td paints its own border-bottom at its
   CONTENT height while its neighbours paint at the ROW height (the
   broken separator on tall folklore rows), and any centring measures the
   content box instead of the row (plates drifting by name length). The
   flex moves to an inner .ncell; the cell stays a cell and both faults
   close at the root, with the dot-beside-the-name law untouched. */
.ncell { display: flex; align-items: baseline; gap: 8px; }
.ncell .tier-dot,
.ncell .kind-dot { flex: 0 0 auto; margin: 0; position: relative; top: -1px; }
/* plates and portrait stacks centre in the ROW, so every creature sits at
   the same height whatever its name's length */
table.dossier tbody td:first-child:has(.plate),
table.dossier tbody td:first-child:has(.cat-stack) { vertical-align: middle; }
.ncell:has(.plate), .ncell:has(.cat-stack) { align-items: center; justify-content: center; }

/* CAT NAMES STAY LEGIBLE (2026-07-26, Tom's comb): each cat's name used its raw
   signature color, so pale cats (The Commodore #f0f0ed, Chef Whiskers) were all
   but invisible on parchment — contrast ~1.0:1 — and dark cats (Count Catula)
   would vanish on the dark theme. The dot keeps the TRUE hue (identity), with a
   hairline ring so near-background swatches still read; the name mixes that hue
   toward the theme's own --ink, which flips per theme, so every name clears the
   contrast floor on BOTH backgrounds while keeping a clear tint of its cat. */
.cat-dot { background: var(--cat); box-shadow: 0 0 0 1px rgba(120,110,130,.5); }
.cat-name { color: var(--ink); /* fallback for no color-mix() */
  color: color-mix(in srgb, var(--cat) 45%, var(--ink)); }

/* THE GAME'S OWN ART ON THE ROWS (P1a, 2026-07-26): each entity's icon,
   mirrored by the generator from the game tree (rarity-framed for
   weapons). Pixelated to honor the sprite work; self-centered inside
   the baseline-aligned first cell so multi-line names keep the comb's
   dot-beside-first-line law while the icon sits vertically centered. */
/* FULL IN-GAME SIZE (2026-07-27, Tom's ruling after the reference wiki:
   icons carry their native game dimensions — 96px weapons, 96/64 items,
   96 cat portraits — never squeezed. The generator emits each icon's
   true width/height attributes; CSS deliberately does NOT size these
   (auto would defeat the attributes and collapse lazy images). */
.dossier-icon { flex: 0 0 auto;
  align-self: center; image-rendering: pixelated; border-radius: 6px;
  /* the icon bed: a soft neutral backing so light sprites (Coffee's
     near-white cup) read on parchment and dark sprites read on the
     dark theme — one fix for the whole class, both directions */
  background: rgba(127,110,140,.14); padding: 2px;
  /* P1b: creature sprites aren't square like the framed icons —
     contain, never crop or squash a cryptid */
  object-fit: contain; }
/* P1b, the two arts: items/weapons/cat portraits are chunky 96px pixel
   icons (pixelated is faithful); CREATURE SPRITES are high-res painted
   art — nearest-neighbor at ~9:1 turned owls to noise, so the .sprite
   variant renders smooth and larger (the Bestiary's tall prose rows
   afford 56px without adding height). */
.dossier-icon.sprite { width: auto; height: auto;
  max-width: 110px; max-height: 96px; image-rendering: auto; }

/* P2a — ADDRESSABILITY (2026-07-26): every row linkable, every pill a road.
   The copy-link affordance reveals on row hover (always faintly present on
   touch, where hover doesn't exist); the arrival spotlight marks a
   deep-linked row in both themes; pill-links never underline their pill. */
.rowlink { margin-left: auto; flex: 0 0 auto; align-self: center;
  background: none; border: none; cursor: pointer;
  /* a fair seat (Tom's catch: it was cramped to near-invisibility):
     fixed 24px square, breathing room, never squeezed by the pills */
  width: 24px; height: 24px; min-width: 24px; padding: 4px;
  border-radius: 6px; display: inline-flex; align-items: center;
  justify-content: center; color: var(--ink-faint);
  opacity: 0; transition: opacity .12s, color .12s; }
.rowlink svg { display: block; }
tr:hover .rowlink { opacity: .85; }
.rowlink:hover { opacity: 1; color: var(--plum); background: rgba(184,119,230,.12); }
.rowlink.copied { opacity: 1; color: #3fae63; font-size: .95rem; line-height: 1; }
@media (hover: none) { .rowlink { opacity: .5; } }
tr.row-hit td { background: rgba(184,119,230,.14); }
tr.row-hit td:first-child { box-shadow: inset 3px 0 0 var(--plum); }
a.pill-link { text-decoration: none; }
/* P7: a cell-link wraps a whole first-cell entity as one road while
   display:contents keeps the flex layout exactly as if unwrapped */
a.cell-link { display: contents; color: inherit; }
/* P7: linked names keep their identity colors, brighten on hover */
a.pill-link:hover .item-name, a.pill-link:hover .name-pest,
a.pill-link:hover .name-warped, a.pill-link:hover .name-terror,
a.pill-link:hover .name-boss { filter: brightness(1.25); text-decoration: underline; }
a.pill-link:hover { text-decoration: none; }
a.pill-link:hover .pill { filter: brightness(1.22); }

/* P2b — THE PEEK CARD (2026-07-26): hover a pill, meet the entity —
   the game's own shop-card grammar. Variables keep it right in both
   themes; the weapon card's tier ribbon reuses the chip language. */
.peek-card { position: fixed; z-index: 60; width: 264px;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 12px 14px; font-size: .88rem; }
.peek-head { display: flex; align-items: center; gap: 10px; }
.peek-name { font-weight: 800; font-size: .98rem; }
.peek-sub { margin-top: 6px; display: flex; flex-wrap: wrap; gap: 4px; }
.peek-ribbon { margin-top: 10px; display: flex; gap: 4px; }
.peek-ribbon .chip { padding: 3px 9px; font-size: .74rem; }
.peek-stats { display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 6px; margin-top: 10px; }
.peek-stats .ps { background: var(--bg-3); border-radius: var(--radius-sm);
  padding: 5px 4px; text-align: center; }
.peek-stats .ps b { display: block; font-family: var(--mono);
  font-size: .92rem; color: var(--ink); }
.peek-stats .ps span { font-size: .6rem; letter-spacing: .6px;
  color: var(--ink-faint); text-transform: uppercase; }
.peek-text { margin-top: 9px; color: var(--ink-dim); line-height: 1.45; }
/* the cat's full body on its peek card — a little stage, pixel-crisp
   (74px source upscaled: the two-arts law says pixelated) */
.peek-body { text-align: center; margin-top: 8px; }
.peek-body img { width: 96px; height: 96px; image-rendering: pixelated;
  object-fit: contain; }
.peek-open { display: inline-block; margin-top: 10px; font-weight: 700;
  font-size: .82rem; }

/* the CLASS column (Tom's catch): pills flow in tidy reading order with
   an even gap — never floating around a name again */
.pill-cell { display: flex; flex-wrap: wrap; gap: 4px; max-width: 150px; }

/* THE MUSTER (Tom's charm question, 2026-07-26): game art earns a seat
   when REFERENTIAL (shows the very thing the text names) or FUNCTIONAL
   (each face is a road + peek card). A fixed-size flex-wrap strip under
   the heading — never overlapping text, wraps gracefully on a phone. */
.muster { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 14px; }
.muster-cat { width: 44px; height: 44px; border-radius: 8px;
  image-rendering: pixelated; background: rgba(127,110,140,.14);
  padding: 2px; transition: transform .12s; }
a:hover .muster-cat { transform: translateY(-3px); }
@media (max-width: 640px) { .muster-cat { width: 38px; height: 38px; } }

/* the chair strip: the porch's shape, visible from every chair */
.porch-strip { display: flex; flex-wrap: wrap; gap: 4px 10px;
  margin: 2px 0 18px; font-size: .85rem; color: var(--ink-faint); }
.porch-strip .here { font-weight: 700; color: var(--ink); }

/* P9 THE PORCH: the welcome register — a touch more air, a softer
   lede; the coach never shouts */
.porch .lede { font-size: var(--fs-1s); }
.porch section p { max-width: 660px; }
/* style sub-headers must OUTRANK the links beneath them (Tom's catch:
   bold lead-ins read as body text while plum links read as headers) */
.porch h3 { font-size: var(--fs-1s); font-weight: 800; margin: 22px 0 2px;
  color: var(--ink); }

/* P3 THE LADDER: the deed reads in the game's own card voice */
.deed { font-style: italic; color: var(--ink); }

/* THE FIELD-GUIDE PLATE (Tom's call, 2026-07-26): the Bestiary's tall
   prose rows left the creature column mostly air — now the creature
   stands as a plate with its name captioned beneath, the bestiary
   tradition. The copy-link moves to the cell's top corner like a
   card's pin. Only rows bearing a .plate change; every other dossier
   keeps the compact row grammar. */
.plate { display: flex; flex-direction: column; align-items: center;
  gap: 8px; text-align: center; }
.plate .dossier-icon.sprite { width: 190px; height: 190px;
  border-radius: 10px; }
/* the two-arts law, per source (Tom's haze report): small pixel-art
   sprites upscale nearest-neighbor — crisp chunk, never haze;
   the big paintings keep their smooth downscale */
.dossier-icon.sprite.pix { image-rendering: pixelated; }
.plate-cap { display: flex; align-items: baseline; gap: 7px;
  justify-content: center; }
table.dossier tbody td:first-child:has(.plate) { position: relative;
  min-width: 214px; }
td:first-child:has(.plate) .rowlink { position: absolute; top: 8px;
  right: 8px; margin-left: 0; }
@media (max-width: 640px) {
  .plate .dossier-icon.sprite { width: 120px; height: 120px; }
  table.dossier tbody td:first-child:has(.plate) { min-width: 144px; }
}

.item-name { font-weight: 700; }
.tier-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-right: 8px; vertical-align: middle; }
.t1 .item-name, .name-t1 { color: var(--t1); } .tier-dot.t1 { background: var(--t1); }
.t2 .item-name, .name-t2 { color: var(--t2); } .tier-dot.t2 { background: var(--t2); }
.t3 .item-name, .name-t3 { color: var(--t3); } .tier-dot.t3 { background: var(--t3); }
.t4 .item-name, .name-t4 { color: var(--t4); } .tier-dot.t4 { background: var(--t4); }

.num { font-family: var(--mono); color: var(--ink); }
.price { color: var(--gold); font-family: var(--mono); }
.effect { color: var(--ink); max-width: 560px; }
.effect .stat { color: var(--plum); font-weight: 600; }
.effect .altered { color: var(--t3); font-weight: 600; }
.effect br { content: ""; display: block; margin: 2px 0; }

.pill { display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: .7rem; font-weight: 700; margin: 2px 4px 0 0;
  background: var(--bg-3); color: var(--ink-dim); }
.pill.coop { background: #24506e; color: #bfe3ff; }
.pill.crossing { background: #3a2456; color: #d9b6ff; }
.pill.firstwin { background: #4a3a1e; color: #f3d79a; }
.pill.withdrawn { background: #4a2224; color: #ffb0b0; text-decoration: line-through; }

.empty { padding: 40px; text-align: center; color: var(--ink-faint); }

/* ---- home ---- */
.hero { padding: 40px 0 24px; }
.hero h1 { font-size: var(--fs-4s); margin: 0 0 6px; }
.hero p { color: var(--ink-dim); font-size: 1.08rem; max-width: 640px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px,1fr)); gap: 16px; margin-top: 20px; }
.card { display: block; background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px 20px; color: var(--ink); }
.card:hover { border-color: var(--plum-soft); text-decoration: none; transform: translateY(-2px);
  transition: .15s; }
.card.soon { opacity: .5; }
.card h3 { margin: 0 0 4px; font-size: var(--fs-1s); }
.card p { margin: 0; color: var(--ink-dim); font-size: .9rem; }

/* home — live-count strip, the "why it's different" band, section heading */
.hstrip { display: flex; flex-wrap: wrap; gap: 12px 28px; align-items: baseline; margin-top: 22px;
  padding-top: 20px; border-top: 1px solid var(--line); }
.hstat { display: flex; flex-direction: column; }
.hstat b { font-size: var(--fs-2s); line-height: 1; color: var(--gold); font-family: var(--mono); }
.hstat span { margin-top: 4px; font-size: .74rem; letter-spacing: .6px; text-transform: uppercase;
  color: var(--ink-faint); }
.why { display: grid; grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); gap: 14px;
  margin: 34px 0 6px; }
.whycard { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px; }
.whycard h4 { margin: 0 0 6px; color: var(--plum); font-size: 1.02rem; }
.whycard p { margin: 0; color: var(--ink-dim); font-size: .9rem; }
.home-h2 { font-size: .95rem; text-transform: uppercase; letter-spacing: 1.2px;
  color: var(--ink-faint); font-weight: 700; margin: 36px 0 4px; }

footer { max-width: 1180px; margin: 0 auto; padding: 28px 20px; color: var(--ink-faint);
  font-size: .82rem; border-top: 1px solid var(--line); }
footer .gen { color: var(--plum-soft); }

@media (max-width: 640px) {
  .command-inner { gap: 12px; }
}

/* weapon class pills (The Armory) */
/* Tom's catch (2026-07-26, mobile roster): this was the ONE pill mixing a
   hardcoded dark oval with VARIABLE text — in light theme --ink-dim goes
   dark, giving dark-on-dark. Now self-consistent like its four siblings
   (hardcoded pastel on hardcoded dark, readable in BOTH themes). */
.pill.wclass { background: #2c2740; color: #d6cbe8; }

/* Bestiary — names colored by KIND, and the dossier prose */
.name-pest { color: var(--ink-dim); } .kind-dot.k-pest { background: var(--ink-dim); }
.name-warped { color: var(--plum); } .kind-dot.k-warped { background: var(--plum); }
.name-terror { color: var(--gold); } .kind-dot.k-terror { background: var(--gold); }
.name-boss { color: var(--t4); } .kind-dot.k-boss { background: var(--t4); }
.kind-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-right: 8px; vertical-align: middle; }
.pattern { color: var(--ink-dim); font-size: .88em; margin-top: 3px; }
.taunt { color: var(--gold); font-style: italic; font-size: .88em; margin-top: 3px; }

/* Bestiary — the real-world folklore behind a Warped creature (authored) */
.folklore { margin-top: 7px; padding: 8px 12px; font-size: .88em; color: var(--ink-dim);
  background: rgba(232,182,74,.06); border-left: 3px solid var(--gold); border-radius: 4px; }
.folklore .fk-tag { display: block; font-size: .68rem; letter-spacing: .6px;
  text-transform: uppercase; color: var(--gold); font-weight: 700; margin-bottom: 3px; }

/* The Roster — signed stat-mod pills + lore prose */
.pill.mod { font-family: var(--mono); font-weight: 600; }
.pill.mod.up { background: #1f3d2a; color: #8fe3a6; }
.pill.mod.down { background: #45222a; color: #ff9aa6; }
/* Tom's catch (2026-07-26): "general pool" as a faint pill read like a
   blurred smudge beside crisp kit pills — pill-shaped-but-faint scans as
   a focus error. It is a NOTE, not kit data: quiet italic text, no chip
   costume, honest contrast (ink-dim, fine in both themes). */
.pill.mod.none { background: none; padding: 2px 0; color: var(--ink-dim);
  font-family: var(--sans); font-style: italic; font-weight: 500; }
.lore { color: var(--ink-dim); font-style: italic; }

/* ---- authored pages (Past the Fence, the Field Manual): essay + codex ---- */
.essay { max-width: 840px; }
.essay .lede { font-size: var(--fs-1s); line-height: 1.6; color: var(--ink-dim); margin: 0 0 30px; }
.essay .lede b { color: var(--ink); }
.essay section { margin: 0 0 36px; }
.essay h2 { font-size: var(--fs-2s); margin: 0 0 12px; color: var(--ink);
  border-bottom: 1px solid var(--line); padding-bottom: 7px; }
.essay h2 .step { color: var(--plum); font-family: var(--mono); font-size: .82rem;
  margin-right: 10px; letter-spacing: 1px; }
.essay p { margin: 0 0 12px; }
.essay .quote { color: var(--gold); font-style: italic; }
.essay a { border-bottom: 1px dotted var(--plum-soft); }

.callout { background: var(--bg-2); border-left: 3px solid var(--plum-soft);
  border-radius: var(--radius-sm); padding: 12px 16px; margin: 4px 0 14px; color: var(--ink-dim); }
.callout strong { color: var(--ink); }

.postures { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px,1fr));
  gap: 12px; margin: 8px 0 6px; }
.posture { background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; }
.posture h4 { margin: 0 0 5px; color: var(--plum); font-size: 1rem; }
.posture p { margin: 0; font-size: .88rem; color: var(--ink-dim); }

.thing-card { background: linear-gradient(160deg, #2a1030, #17131e); border: 1px solid var(--t3);
  border-radius: var(--radius); padding: 20px 22px; margin: 6px 0 10px; box-shadow: var(--shadow); }
.thing-card h3 { margin: 0 0 4px; font-size: var(--fs-2s); color: var(--t3); }
.thing-card .whatfor { color: var(--gold); font-style: italic; margin: 0 0 14px; }
.thing-stats { display: flex; flex-wrap: wrap; gap: 8px; }
.thing-stats .sp { background: rgba(0,0,0,.32); border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 12px; font-family: var(--mono); font-size: .84rem; color: var(--ink-dim); }
.thing-stats .sp b { color: var(--t4); }

.endings { display: grid; grid-template-columns: repeat(auto-fit, minmax(232px,1fr)); gap: 12px; }
.ending { background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; }
.ending.held { border-color: var(--gold); }
.ending.trueend { border-color: var(--t3); }
.ending h4 { margin: 0 0 5px; font-size: 1rem; }
.ending.held h4 { color: var(--gold); }
.ending.trueend h4 { color: var(--t3); }
.ending p { margin: 0; font-size: .87rem; color: var(--ink-dim); }

.danger-ladder { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 6px; }
.danger-row { display: flex; gap: 12px; align-items: baseline;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 9px 14px; }
.danger-row .dlabel { font-weight: 800; font-family: var(--mono); min-width: 34px; }
.danger-row .ddesc { color: var(--ink-dim); font-size: .92rem; }

/* reference table (The Field Manual's stat vocabulary) */
.reftable { width: 100%; border-collapse: collapse; font-size: .93rem; }
.reftable th { text-align: left; background: var(--bg-3); color: var(--ink-dim);
  font-size: .74rem; letter-spacing: .5px; text-transform: uppercase; padding: 10px 14px;
  position: sticky; top: 0; }
.reftable td { padding: 9px 14px; border-top: 1px solid var(--line); vertical-align: top; }
.reftable td.num { font-family: var(--mono); color: var(--ink); white-space: nowrap; }
.reftable td.fm-stat { font-family: var(--mono); color: var(--t2); font-weight: 600; white-space: nowrap; }
.reftable tr:hover td { background: rgba(184,119,230,.05); }

/* ======================================================================
   LIGHT THEME (parchment) — opt-in via <html data-theme="light">.
   The header sets data-theme before paint; the toggle button flips it.
   Only the variables + the few HARDCODED-dark surfaces need overriding;
   everything else is already painted from the variables above.
   ====================================================================== */
.theme-toggle {
  order: 2; margin-left: auto; flex-shrink: 0; width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-3); border: 1px solid var(--line); color: var(--ink-dim);
  border-radius: 999px; cursor: pointer; font-size: 1rem; line-height: 1;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--plum-soft); }
.theme-toggle::after { content: "\2600"; }                         /* ☀ in dark mode → click for light */
:root[data-theme="light"] .theme-toggle::after { content: "\263E"; } /* ☾ in light mode → click for dark */

:root[data-theme="light"] {
  /* Tom's call 2026-07-27: the light layout wears the SAME periwinkle
     accents as dark — one voice across both themes (links measure
     2.8:1 on parchment; flagged, his eye rules) */
  --bg:        #f4efe6;   /* warm parchment */
  --bg-2:      #fbf8f2;   /* raised, near-white */
  --bg-3:      #ece4d6;   /* rows, chips */
  --line:      #ddd2c0;   /* hairlines */
  --ink:       #2b2333;   /* dark plum-charcoal type */
  --ink-dim:   #5b5068;
  --ink-faint: #8f8499;
  --gold:      #a9781a;   /* darker gold, readable on parchment */
  --t1: #8a8a8a;  --t2: #2f6fd0;  --t3: #9b30d8;  --t4: #d22f2f;
  --shadow: 0 6px 22px rgba(80,60,40,.14);
}
/* hardcoded-dark surfaces that variables don't reach: */
/* The banner is fixed-dark art, so the header stays dark furniture in
   the light theme — its text is forced to the dark theme's ink here
   (Tom's catch 2026-07-27: the brand vanished on parchment ink). */
:root[data-theme="light"] header.command .brand { color: #ece7f2; }
:root[data-theme="light"] header.command .brand small { color: #a294b4; }
:root[data-theme="light"] header.command nav.sections a { color: #c9bfd6; }
:root[data-theme="light"] header.command nav.sections a:hover {
  background: rgba(42, 33, 54, .7); color: #fff; }
:root[data-theme="light"] header.command nav.sections a.active {
  background: var(--plum-soft); color: #fff; }
:root[data-theme="light"] header.command .theme-toggle {
  background: rgba(42, 33, 54, .65); border-color: rgba(120, 105, 140, .55);
  color: #cfc6dc; }
:root[data-theme="light"] .pill.mod.up   { background: #d8f0dd; color: #1c7a3a; }
:root[data-theme="light"] .pill.mod.down { background: #f6dce0; color: #b02a3a; }
/* Tom's question 2026-07-26, my call: common practice (and our own
   mod-pill precedent) is chips that FOLLOW the theme — pale tinted
   chip + dark text on parchment; the dark oval stays dark-theme-only.
   One line to revert if the eye disagrees. */
:root[data-theme="light"] .pill.wclass { background: #e7dff2; color: #4a3a63; }
:root[data-theme="light"] .thing-card {
  background: linear-gradient(160deg, #f3e3f6 0%, #fbf8f2 100%);
}
:root[data-theme="light"] .thing-stats .sp { background: rgba(0,0,0,.05); }

/* ---- mobile density: tighten the data tables + spacing on small screens
   (appended last so it wins the cascade; the layout already reflows with no
   horizontal page overflow — this only makes the dense dossiers breathe less
   wastefully on a phone) ---- */
@media (max-width: 640px) {
  main { padding: 20px 14px 60px; }
  .hero { padding: 26px 0 14px; }
  table.dossier { font-size: .88rem; }
  table.dossier thead th { padding: 10px 10px; font-size: .72rem; }
  table.dossier tbody td { padding: 9px 10px; }
  .dossier-icon { width: 48px; height: auto; }   /* phone rows stay dense (P1a);
     aspect held by the emitted width/height attributes */
  .dossier-icon.sprite { width: 56px; height: auto; }  /* creature art keeps identity (P1b) */
  .reftable th, .reftable td { padding: 8px 10px; }
  .hstrip { gap: 10px 20px; }
  .hstat b { font-size: 1.45rem; }
  .theme-toggle { width: 30px; height: 30px; }
}

/* ---- THE RAIL (2026-07-27): the wide-screen left map. Below the
   breakpoint it does not exist and the top sections nav owns
   navigation, unchanged. At width the whole Command unfolds in the
   house's own rooms, current page dressed in the same active plum the
   top nav has always worn — one voice per verb. ---- */
aside.rail { display: none; }
@media (min-width: 1240px) {
  /* Tom's comb 2026-07-27: the page never sprawls — rail and body travel
     together as one centered unit (empty gutters take the slack on wide
     screens), while header and footer still run edge to edge. */
  body.with-rail { display: grid;
    grid-template-columns: 1fr 232px minmax(0, 1180px) 1fr; }
  body.with-rail > header.command { grid-column: 1 / -1; }
  /* the footer centers under the CONTENT column, not the viewport —
     the rail shifts main's center, and a viewport-centered footer read
     as drifting left (Tom's catch 2026-07-27) */
  body.with-rail > footer { grid-column: 3; }
  body.with-rail > main { grid-column: 3; }
  /* the top nav stays in the banner even at rail widths (Tom
     2026-07-27: the proud bar was standing empty-handed) — quick
     sections up top, the full grouped map in the rail, both alive. */
  aside.rail {
    display: block; grid-column: 2; grid-row: 2;
    position: sticky; top: 62px; align-self: start;
    max-height: calc(100vh - 62px); overflow-y: auto;
    padding: 22px 12px 40px 20px;
    border-right: 1px solid var(--line);
    font-size: .9rem;
  }
  .rail a { display: block; padding: 5px 10px; border-radius: var(--radius-sm);
            color: var(--ink-dim); line-height: 1.35; }
  .rail a:hover { background: var(--bg-3); color: var(--ink);
                  text-decoration: none; }
  .rail a.on, .rail a.rail-title.on { background: var(--plum-soft); color: #fff; }
  .rail-home { font-weight: 600; }
  .rail-group { margin-top: 18px; }
  .rail-title { display: block; padding: 5px 10px;
                font-size: .68rem; font-weight: 700; letter-spacing: .09em;
                text-transform: uppercase; color: var(--ink-faint); }
  a.rail-title:hover { background: var(--bg-3); color: var(--ink); }
  .rail-group a:not(.rail-title) { margin-left: 6px; }
}

/* ---- THE FOOTER PROCESSION (2026-07-27, Tom's pick from the mockups:
   "the quiet ground" — no sky texture, just the world underfoot). The
   splash project's own distant-landscape plate, cropped to its measured
   opaque band, marches full-width above the footer on every page:
   houses to the left, the parade through the middle, pines to the
   right. Both themes wear it as-is — it read well on parchment too. ---- */
footer { position: relative; padding-top: 132px; }
footer::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 132px;
  background: url("footer_skyline.0eb2a6f3.png") no-repeat center bottom;
  background-size: min(1920px, 100%) auto;
  pointer-events: none;
}

/* ---- THE FRONT DOOR (2026-07-27, Tom's GO: trailer slot + news cards,
   the official-site pattern at our size). The poster frame RECEIVES the
   trailer someday; until then it shows the neighborhood honestly — no
   dead play button, no broken promise. ---- */
.hero2 { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 28px; align-items: center; margin: 6px 0 30px; }
.poster { position: relative; border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line); box-shadow: var(--shadow); }
.poster img { display: block; width: 100%; height: auto; }
.poster-label { position: absolute; left: 0; right: 0; bottom: 0;
  padding: 8px 14px; font-size: .78rem; letter-spacing: .08em;
  text-transform: uppercase; color: #d9d2e4;
  background: linear-gradient(180deg, transparent, rgba(12, 9, 18, .82)); }
.pitch h1 { margin: 0 0 6px; font-size: var(--fs-3s); }
.pitch .tagline { font-size: var(--fs-1s); font-weight: 700; color: var(--ink);
  margin: 0 0 10px; }
.pitch p { color: var(--ink-dim); }
@media (max-width: 900px) { .hero2 { grid-template-columns: 1fr; } }

.latest { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px; margin-bottom: 30px; }
@media (max-width: 900px) { .latest { grid-template-columns: 1fr; } }
.bulletin-card { display: block; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; color: inherit; }
.bulletin-card:hover { text-decoration: none; border-color: var(--plum-soft);
  background: var(--bg-3); }
.bulletin-card .bc-art { display: flex; align-items: center; justify-content: center;
  height: 120px; background: rgba(127, 110, 140, .10); overflow: hidden; }
.bulletin-card .bc-art img { max-height: 100%; max-width: 100%; object-fit: cover;
  width: 100%; height: 100%; }
/* THE STORM LOOP (2026-07-29): a muted palindrome video wears the card's
   art strip the way the cover-fit image did — the portrait clip is
   cropped to the landscape window, centred on the action. */
.bulletin-card .bc-art .bc-video { width: 100%; height: 100%;
  object-fit: cover; object-position: center 42%; display: block; }
.bulletin-card .bc-art img.pixsprite,
.bulletin-card .bc-art img[src*="icons/"] { width: auto; height: 88px;
  image-rendering: pixelated; object-fit: contain; }
.bulletin-card .bc-art img[src*="sprites/"] { width: auto; height: 104px;
  image-rendering: auto; object-fit: contain; }
.bulletin-card h3 { margin: 12px 14px 4px; font-size: var(--fs-1s); }
.bulletin-card p { margin: 0 14px 14px; font-size: .88rem; color: var(--ink-dim); }

/* the bulletin entries themselves */
article.bulletin { border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-2); padding: 22px 26px; margin: 0 0 26px; }
.b-date { font-size: .72rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--gold); margin-bottom: 2px; }
article.bulletin h2 { margin: 0 0 12px; font-size: var(--fs-2s); }
.b-art { display: flex; gap: 18px; align-items: center; margin: 0 0 14px; }
.b-icon { width: auto; height: auto; max-width: 96px; image-rendering: pixelated;
  background: rgba(127, 110, 140, .14); border-radius: 8px; padding: 4px; }
.b-sprite { height: 96px; width: auto; }
.b-wide { width: 100%; max-width: 560px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); }
/* the storm loop on the bulletin page: a tall clip in a calm letterbox,
   full frame visible (contain), never cropping the lightning */
.b-video.b-wide { max-width: 340px; aspect-ratio: 704 / 1280;
  object-fit: contain; background: #0c0a12; display: block; }
/* THE MOTION LAW (the site honours prefers-reduced-motion elsewhere; a
   looping storm is exactly the motion it protects against — the poster
   frame stands in, the video simply doesn't autoplay-animate) */
@media (prefers-reduced-motion: reduce) {
  .bc-video, .b-video { animation: none; }
}
article.bulletin p { max-width: 720px; }

/* ---- THE CARD GRAMMAR (2026-07-27, Tom's ruling: the game's stat-table
   character on the site — icons as the badge of primacy, signed numbers
   judged, and stat icons that answer on hover like the in-game tips). */
.stat-ico { width: 16px; height: 16px; image-rendering: pixelated;
  vertical-align: -3px; display: inline-block; }
.stat-ico.big { width: 28px; height: 28px; }
.stat-ref { cursor: help; display: inline-block; padding: 0 1px; }
.stat-ref:hover .stat-ico { transform: scale(1.15); }
.v-up   { color: #7fd68b; font-weight: 600; }
.v-down { color: #ff8585; font-weight: 600; }
:root[data-theme="light"] .v-up   { color: #1c7a3a; }
:root[data-theme="light"] .v-down { color: #b02a3a; }
.peek-dim { color: var(--ink-faint); font-size: .8em; }

/* row-peek (2026-07-27, Tom's armory catch): the weapon name is a hover
   trigger for its full card — dressed as a name, not a pill; the tier
   ribbon on the card carries what no table column shows. */
a.row-peek { color: inherit; cursor: help; }
a.row-peek:hover { text-decoration: underline dotted; }
[data-peek] { cursor: help; }
.peek-text.wcard { white-space: normal; line-height: 1.5; }

/* THE PORTRAIT STACK (2026-07-27, Tom's read): roster and ladder cats
   stand full-size with the dot+name captioned centered beneath. */
.cat-stack { display: inline-flex; flex-direction: column; align-items: center;
  gap: 6px; text-align: center; }
.cat-stack .cat-caption { display: inline-flex; align-items: baseline; gap: 6px; }

/* the between-page strobe, part two (2026-07-27): scrollbars follow the
   theme — a white Windows scrollbar column flashes as hard as a white
   canvas. color-scheme also darkens the browser's own default canvas. */
:root { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* the strobe, part three (2026-07-27, Tom: "still happens on rapid
   clicks"): same-origin page navigations crossfade instead of blanking
   (MPA view transitions, progressive — browsers without it lose
   nothing). The frame-zero canvas itself is pinned dark by the
   color-scheme meta in the shell. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: 90ms;
}
