/* ============================================================================
   INSATIABLE — style.css, RE-SKINNED onto the Unspeakably Horrible Games system.

   This is a DROP-IN replacement for Insatiable/css/style.css. It is a PURELY
   VISUAL port: every selector, class, id, structural rule, and behavioral hook
   from the shipping stylesheet is preserved 1:1 — only colors, fonts, and a few
   additive treatments (grain, vignette, gilt hairline, glow) change. Nothing
   that JS or event handling depends on was renamed, removed, or restructured:
     • cursor:help + body.helpmode (right-click / inspect help) — preserved
     • .card h3.toggle + .caret, h4.bestrat.toggle — collapse affordances preserved
     • .organgrid / .organrow / .oicon / .elembox — compact organ view preserved
     • data-arg / .active / .full / .satfull / .owned state classes — preserved
     • @keyframes awaken, pulse — preserved (pulse retuned to absinthe)
     • .speedbadge, .vmismatch, .fresh, .stars — preserved

   The ONLY variable values changed are in :root (repointed to UHG hues) plus new
   font + texture tokens. Because the game's existing var names (--bg, --card,
   --goo, --blood, --mana, --gold, --line, --ink, --dim) are kept, no JS/HTML that
   reads them needs to change.

   FONTS: self-hosted OFL .woff2 (latin subset) in assets/fonts/ — no CDN, fully
   self-contained for desktop packaging. The @font-face rules are inlined just
   below (they replaced a Google Fonts @import). Metrics are unchanged.
   ========================================================================== */

/* Fonts: self-hosted OFL woff2, latin subset (assets/fonts/) - no CDN,
   fully self-contained for desktop packaging. See VISUAL-SYSTEM.md section 3. */
@font-face { font-family: 'Archivo'; font-style: normal; font-weight: 400; font-display: swap; src: url('../assets/fonts/archivo-400-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Archivo'; font-style: normal; font-weight: 500; font-display: swap; src: url('../assets/fonts/archivo-500-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Archivo'; font-style: normal; font-weight: 600; font-display: swap; src: url('../assets/fonts/archivo-600-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Archivo'; font-style: normal; font-weight: 700; font-display: swap; src: url('../assets/fonts/archivo-700-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'IM Fell English'; font-style: italic; font-weight: 400; font-display: swap; src: url('../assets/fonts/imfell-400-italic.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'IM Fell English'; font-style: normal; font-weight: 400; font-display: swap; src: url('../assets/fonts/imfell-400-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('../assets/fonts/jetbrains-400-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('../assets/fonts/jetbrains-500-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 700; font-display: swap; src: url('../assets/fonts/jetbrains-700-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Metamorphous'; font-style: normal; font-weight: 400; font-display: swap; src: url('../assets/fonts/metamorphous-400-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Spectral'; font-style: italic; font-weight: 400; font-display: swap; src: url('../assets/fonts/spectral-400-italic.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Spectral'; font-style: normal; font-weight: 300; font-display: swap; src: url('../assets/fonts/spectral-300-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Spectral'; font-style: normal; font-weight: 400; font-display: swap; src: url('../assets/fonts/spectral-400-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Spectral'; font-style: normal; font-weight: 500; font-display: swap; src: url('../assets/fonts/spectral-500-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Spectral'; font-style: normal; font-weight: 600; font-display: swap; src: url('../assets/fonts/spectral-600-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Spectral'; font-style: normal; font-weight: 700; font-display: swap; src: url('../assets/fonts/spectral-700-normal.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

:root {
  /* --- Surfaces (warm mahogany darks, UHG) --- */
  --bg: #100A0C;      /* void — page */
  --bg2: #160F12;     /* ink-900 — sunken wells: log, chips, textareas */
  --card: #241820;    /* ink-700 — panels */
  --card2: #2E1F29;   /* ink-600 — nested / buttons */

  /* --- Text (parchment / bone, UHG) --- */
  --ink: #DCD1BE;     /* body text */
  --dim: #B9AC97;     /* bone — muted */

  /* --- Accents --- */
  --goo: #6F9E4F;     /* the blob — cooler in-game green */
  --goo2: #8FCA63;    /* goo bright */
  --blood: #C6485F;   /* danger / can't-afford / death (oxblood-400) */
  --mana: #9A72B5;    /* arcane — cosmic violet (was blue) */
  --gold: #C8A24C;    /* gilt — rare / premium / insight */
  --order: #3FA39B;   /* banner-teal — a named Order's reserved identity hue (#rank-vs-order, Mark 2026-08-27).
                         Held apart from the blob green, the rarity rungs, blood and mana. Provisional hex → WATCHLIST. */
  --line: #3A2833;    /* ink-500 — borders */
  --line-gilt: rgba(200, 162, 76, 0.35);  /* gilt hairline */

  /* --- Loot rarity ladder (#rarity) — colour-only grade; internal keys, never named in-world.
     Draft hexes (tunable, WATCHLIST), tuned apart from the semantic accents above. --- */
  --rar-scrap: #6E655C;    /* grey */
  --rar-common: #EDE4D2;   /* parchment white */
  --rar-uncommon: #4FAE6E; /* colder emerald — apart from the goo green */
  --rar-rare: #5B8FC9;     /* blue — free, mana vacated it for violet */
  --rar-epic: #E4B33A;     /* hot amber — brighter than the gilt --gold */
  --rar-unique: #E2601F;   /* orange — hotter than the ember log category */
  --rar-mythic: #DE4747;   /* crimson — RESERVED, retune at first use */

  /* --- Fonts (UHG stack; all OFL/embeddable) --- */
  --font-display: "Metamorphous", Georgia, serif;             /* wordmark, titles, DEVOUR */
  --font-grimoire: "IM Fell English", "Cormorant Garamond", Georgia, serif; /* static lore/flavor */
  --font-body: "Spectral", Georgia, "Times New Roman", serif; /* running text */
  --font-ui: "Archivo", "Helvetica Neue", Arial, sans-serif;  /* buttons, tabs, values, labels */
  --font-mono: "JetBrains Mono", "SF Mono", ui-monospace, monospace; /* readouts, kickers */

  /* --- Textures (procedural, data-URI; no rasters) --- */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  --leather: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='lb'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.04' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23lb)'/%3E%3C/svg%3E");

  /* --- Elevation (warm-black shadows) --- */
  --shadow-card: 0 4px 14px rgba(6, 3, 5, 0.5), 0 1px 3px rgba(6, 3, 5, 0.4);
  --vignette-card: inset 0 0 34px 2px rgba(0, 0, 0, 0.26);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--bg);
  /* warm halo (was cool #1c1428) */
  background-image: radial-gradient(ellipse at 50% -20%, #1c1216 0%, var(--bg) 60%);
  color: var(--ink);
  font-family: var(--font-body);
  min-height: 100vh;
  transition: background-color 0.3s;
}
body.awakening { animation: awaken 2.5s ease-out; }
@keyframes awaken {
  0% { filter: invert(1) brightness(2); }
  12% { filter: invert(0) brightness(1.8); }
  100% { filter: none; }
}

/* The top bar — title, resources, chapters, tabs — stays pinned while the page scrolls under it
   (Dr. Darkhorse). Opaque page bg so content never shows through; z below the modal overlay (10),
   above normal content, and a soft shadow gives it lift once content slides beneath. */
#topbar { position: sticky; top: 0; z-index: 5; background: var(--bg); box-shadow: 0 5px 13px rgba(0, 0, 0, 0.34); }

/* Header — a leather bookend (warm gradient + procedural grain), gilt underline. */
header {
  padding: 12px 18px 6px; border-bottom: 1px solid var(--line-gilt);
  background: radial-gradient(130% 110% at 30% 18%, #34251c, #1e130e 72%);
  background-image: var(--leather), radial-gradient(130% 110% at 30% 18%, #34251c, #1e130e 72%);
  background-blend-mode: overlay, normal; background-size: 300px 300px, cover;
}
h1 { font-family: var(--font-display); font-size: 22px; letter-spacing: 3px; color: var(--ink); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); }
/* Wordmark accent: only the A's carry the absinthe glow (spacing unchanged). */
h1 b { color: var(--goo2); font-weight: inherit; text-shadow: 0 0 16px rgba(143, 202, 99, 0.55); }
h1 span { font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; color: var(--dim); font-style: normal; }
h1 .ver { font-style: normal; color: var(--goo); }

#locsel { margin-left: 14px; font-family: var(--font-mono); font-size: 12px; letter-spacing: 1px; color: var(--dim); }
#locsel .locsel.plain { font-style: italic; }
#locsel select {
  font-family: var(--font-ui); font-size: 12px; margin-left: 6px;
  background: var(--card); color: var(--goo2); border: 1px solid var(--line);
  border-radius: 5px; padding: 3px 6px; cursor: pointer;
}
#locsel select:hover { border-color: var(--goo); }

#helpbtn {
  margin-left: 12px; width: 24px; height: 24px; border-radius: 50%;
  background: var(--card); color: var(--dim); border: 1px solid var(--line);
  font-family: var(--font-ui); font-size: 14px; cursor: help; vertical-align: middle;
}
#helpbtn:hover { color: var(--goo2); border-color: var(--goo); }
#helpbtn.active { color: var(--goo2); border-color: var(--goo); box-shadow: 0 0 10px rgba(143, 202, 99, 0.5); }
body.helpmode, body.helpmode * { cursor: help !important; }

#speedctl { margin-left: 12px; display: inline-flex; gap: 2px; vertical-align: middle; }
#speedctl button {
  font-family: var(--font-mono); font-size: 12px; min-width: 26px; height: 24px; padding: 0 6px;
  background: var(--card); color: var(--dim); border: 1px solid var(--line); cursor: pointer;
}
#speedctl button:first-child { border-radius: 5px 0 0 5px; }
#speedctl button:last-child { border-radius: 0 5px 5px 0; }
#speedctl button:hover { color: var(--ink); }
#speedctl button.active { color: var(--goo2); border-color: var(--goo); background: var(--card2); }
body.paused #speedctl button[data-arg="0"].active { color: var(--blood); border-color: var(--blood); }

/* Speed badge (JS-driven): persistent for pause / slow, a 5s transient on 1x. */
.speedbadge {
  position: fixed; bottom: 10px; left: 50%; transform: translateX(-50%) translateY(8px);
  color: #fff; font-family: var(--font-mono); font-size: 11px; letter-spacing: 2px; padding: 4px 14px; border-radius: 12px;
  z-index: 9; pointer-events: none; opacity: 0; transition: opacity 0.4s ease, transform 0.4s ease;
}
.speedbadge.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.speedbadge.paused { background: rgba(168, 48, 72, 0.92); text-align: center; padding: 6px 18px; line-height: 1.3; }  /* oxblood */
/* #pause-law: the paused badge carries a second line — the hands are stopped too. */
.speedbadge.paused small { display: block; font-size: 8px; letter-spacing: 2.5px; font-weight: 700; opacity: 0.92; margin-top: 1px; }
.speedbadge.slow   { background: rgba(110, 74, 134, 0.92); }   /* cosmic violet */
.speedbadge.normal { background: rgba(111, 158, 79, 0.9); }    /* goo green */

.modal.help { text-align: left; max-width: 520px; }
.modal.help h2 { font-family: var(--font-display); font-size: 18px; letter-spacing: 2px; }
/* Codex: fixed screen-relative width so the accordion never jumps sideways. */
.modal.codex { text-align: left; width: min(640px, 92vw); max-width: none; max-height: 82vh; display: flex; flex-direction: column; }
.modal.codex .codexbody { overflow-y: auto; margin: 8px 0 12px; padding-right: 8px; }
/* Compact (collapsed) organ view: a grid of icon tiles with periodic-table cost
   badges. PRESERVED — this is the space-conserving alternative to the text cards. */
.organs-head { margin-top: 4px; }
.organgrid { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 4px; }
.organrow {
  display: flex; align-items: center; gap: 7px;
  background: var(--card2); border: 1px solid var(--line); border-radius: 8px; padding: 6px 9px;
}
.oicon { width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; color: var(--goo2); flex: none; }
.oicon svg { width: 34px; height: 34px; fill: currentColor; }
/* Glyphs are inline single-path SVGs (js/icons.js) — .oicon svg above sizes and
   colors them, so they need no rule of their own. They inherit currentColor, which
   is what lets the affordability state reach the glyph rather than stopping at the
   surrounding badge (see .elembox.lack below). */
.ocount { font-family: var(--font-ui); font-size: 17px; color: var(--ink); min-width: 26px; text-align: center; }
.ocosts { display: inline-flex; gap: 5px; }
.elembox {
  width: 34px; height: 34px; box-sizing: border-box; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 2px solid var(--line); border-radius: 6px;
  font-family: var(--font-mono); font-size: 16px; font-weight: 700; letter-spacing: 0; line-height: 1;
}
.elembox.ok { color: var(--goo2); border-color: var(--goo); background: rgba(111, 158, 79, 0.1); }
.elembox.lack { color: var(--blood); border-color: var(--blood); background: rgba(198, 72, 95, 0.1); }
.elembox.bio svg { width: 24px; height: 24px; fill: currentColor; }
/* The lack state needs no glyph rule: .elembox.lack sets color: var(--blood) and the
   inline SVG inherits it, so the glyph goes red with its box. The old raster needed
   a grayscale+dim filter here because a baked PNG could not take the color. */
.obuy {
  width: 34px; height: 34px; flex: none; padding: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-ui); font-size: 22px; line-height: 1; border-radius: 7px;
  background: var(--card); border: 1px solid var(--line);
}
.obuy.ok { color: var(--goo2); border-color: var(--goo); }
.obuy.ok:hover { background: rgba(111, 158, 79, 0.18); }
.obuy.lack { color: var(--blood); border-color: var(--blood); cursor: not-allowed; }
/* shed / soften buttons: neutral until hovered, then a soft destructive red. */
.obuy.shed { color: var(--ink); border-color: var(--line-gilt); }
.obuy.shed:hover:not(:disabled) { background: rgba(198, 72, 95, 0.14); border-color: var(--blood); color: var(--blood); }
.obuy:disabled, .obuy[disabled] { opacity: 0.35; cursor: not-allowed; }
/* Flesh square glyph — a goo-green boxed square, like an element box but empty. */
.fleshsq { width: 26px; height: 26px; box-sizing: border-box; border-radius: 6px; border: 2px solid var(--goo); background: rgba(111, 158, 79, 0.2); }
/* Reserves compact view: element-square badges stacking symbol over amount. */
.rvgrid { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 4px; }
.rvbox { width: auto; min-width: 40px; height: 34px; padding: 2px 6px; flex-direction: column; gap: 0; line-height: 1.05; }
.rvbox b { font-size: 14px; font-weight: 700; }
.rvbox i { font-style: normal; font-size: 9px; opacity: 0.85; letter-spacing: 0; }
.rvbox.satfull { color: var(--blood); border-color: var(--blood); background: rgba(198, 72, 95, 0.1); }
.codextopic { font-size: 13px; line-height: 1.55; margin-bottom: 8px; }
.codextopic b { color: var(--goo2); font-weight: normal; }
.codexsearch { width: 100%; box-sizing: border-box; margin: 4px 0 6px; padding: 8px 10px; background: var(--bg2); border: 1px solid var(--line); border-radius: 6px; color: var(--ink); font-family: var(--font-ui); font-size: 13px; }
.codexsearch:focus { border-color: var(--goo); outline: none; }
.codexsearch::placeholder { color: var(--dim); }
h4.bestrat.codexgroup { cursor: pointer; user-select: none; padding: 3px 4px; border-radius: 4px; }
h4.bestrat.codexgroup:hover { color: var(--goo2); background: rgba(58, 40, 51, 0.5); }
h4.bestrat.codexgroup .count { color: var(--dim); letter-spacing: 0; }
.codextopic.acc { cursor: pointer; margin: 0 0 1px; padding: 3px 8px; border-left: 2px solid transparent; border-radius: 0 4px 4px 0; }
.codextopic.acc:hover { background: rgba(58, 40, 51, 0.4); border-left-color: var(--line); }
.codextopic.acc.open { border-left-color: var(--goo); background: rgba(58, 40, 51, 0.28); }
.codextopic.acc b { cursor: pointer; }
/* Static lore body — the grimoire face is fine here (it does not move). */
.codextopic.acc .cxbody { display: block; font-family: var(--font-grimoire); color: var(--ink); font-weight: normal; margin: 3px 0 6px; }
/* #codex-links: cross-reference and go-to links inside Codex prose. A subtle accent + underline,
   deliberately NOT all-caps — caps now mean emphasis only. */
.codexlink { color: var(--goo2); cursor: pointer; border-bottom: 1px solid rgba(127, 174, 92, 0.45); }
.codexlink:hover { color: #fff; border-bottom-color: #fff; }
/* Codex emphasis is <strong>/<em>, NOT <b> — <b> is the topic-title accent (--goo2) and would read
   as a link. Emphasis stays the body ink, just bolder/slanted, so it can't be mistaken for one. */
.codextopic strong, .modal.help strong { font-weight: 700; color: inherit; }
.codextopic em, .modal.help em { font-style: italic; color: inherit; }

.vmismatch {
  background: var(--blood); color: #fff; text-align: center; padding: 8px 12px;
  font-family: var(--font-ui); font-size: 13px; letter-spacing: 1px;
}

.resrow { display: flex; gap: 8px; align-items: flex-start; padding: 10px 0 4px; }
#resbar { display: flex; flex-wrap: wrap; gap: 8px; flex: 1; }
.res { background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: 4px 10px; min-width: 86px; text-align: center; }
.res b { display: block; font-family: var(--font-ui); font-weight: 600; font-size: 15px; color: #fff; }
.res span { font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: var(--dim); }
.res em { display: block; font-family: var(--font-mono); font-size: 10px; color: var(--goo); font-style: normal; }
.res.bio b { color: var(--goo2); }
.res.ap b { color: var(--gold); }
.res.mana b { color: var(--mana); }
.res.hp b { color: var(--blood); }
.res.stage b { color: var(--ink); font-size: 13px; }
.res.min.full { border-color: var(--blood); }
.res.min.full span { color: var(--blood); }
/* Analysis & mana are capped too, but they aren't waste-red — border each in its own
   colour so a capped pool reads at a glance without miscolouring it as spoiled (Mark). */
.res.ap.full { border-color: var(--gold); }
.res.mana.full { border-color: var(--mana); }
/* Biomass chip at the flesh's limit — soft-capped (streaming income now sloughs off) or gorged
   past the cap on a gulp (bleeding the overflow). Overrides the green "gathering" tint: at the
   cap you are wasting, not gaining. Gorged adds a red glow + reddens the number. (KyrosKrane) */
.res.bio.full { border-color: var(--blood); box-shadow: none; }
.res.bio.full span { color: var(--blood); }
.res.bio.gorged { box-shadow: 0 0 11px rgba(198, 72, 95, 0.4); }
.res.bio.gorged b { color: var(--blood); }
/* "gathering" — materials actively drawn from the stratum you feed on now. A lighter,
   goo-tinted chip so your current income reads at a glance (no tab-hopping). The .full
   red border out-specifies this, so a saturated chip still shows its waste warning. */
.res.gathering { background: var(--card2); border-color: rgba(111, 158, 79, 0.55); box-shadow: inset 0 1px 0 rgba(143, 202, 99, 0.14), 0 0 10px rgba(111, 158, 79, 0.12); }
.res.gathering span { color: var(--goo2); }
.res.hp { transition: box-shadow 0.12s linear; }

/* ---- row 1: the chapter bar. Owns the full-width rule the tabs hang from (#spine 1.9). ---- */
#chapterbar { border-bottom: 1px solid var(--line); }
#chapters { display: flex; align-items: center; gap: 6px; padding: 8px 18px 7px; overflow-x: auto; }
.gchip {
  font-family: var(--font-display); font-size: 12px; letter-spacing: 0.06em;
  text-transform: uppercase; background: none; color: var(--dim);
  border: 1px solid transparent; border-radius: 5px; padding: 4px 10px;
  cursor: pointer; white-space: nowrap; display: inline-flex; align-items: center; gap: 6px;
}
.gchip:hover { color: var(--ink); border-color: var(--line); }
.gchip .cnt { font-family: var(--font-mono); font-size: 9.5px; opacity: 0.7; }
/* open, and closable */
.gchip.open { color: var(--goo2); border-color: var(--line-gilt); background: rgba(111, 158, 79, 0.08); }
/* the last open group — locked, not clickable */
.gchip.pinned { color: var(--goo2); border-color: var(--goo); cursor: default; }
/* propagated signals (closed groups only) */
.gchip.throb { color: var(--gold); border-color: var(--gold); animation: tabthrob 1.4s ease-in-out infinite; }
.gchip.bleeding { color: var(--blood); border-color: var(--blood); }
.gchip.learnable { color: var(--goo2); border-color: var(--goo); }

/* ---- row 2: tabs DESCEND from the rule above ---- */
nav#tabs { display: flex; align-items: flex-start; gap: 6px; padding: 0 18px 10px; border-bottom: none; overflow-x: auto; }
.tabbtn {
  background: var(--card); color: var(--dim); border: 1px solid var(--line); border-top: none;
  border-radius: 0 0 6px 6px; padding: 8px 18px; cursor: pointer;
  font-family: var(--font-ui); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; font-size: 13px;
}
.tabbtn.active { background: var(--card2); color: var(--goo2); }
.tabbtn:hover { color: var(--ink); }
/* Skills tab tints green when a skill is affordable & unlocked and you're on another
   tab — a quiet nudge, gentler than the Hunt throb (no animation). */
.tabbtn.learnable { color: var(--goo2); border-color: var(--goo); box-shadow: 0 0 6px rgba(111, 158, 79, 0.35); }
/* While UNDERSTANDING is bleeding (#21 bloat), the Skills tab glows RED instead of
   green. Same nudge, same place — the colour carries the urgency. Declared AFTER
   .learnable so red wins when both apply, and deliberately not animated (the signal
   is already right; motion would only add noise). */
.tabbtn.bleeding { color: var(--blood); border-color: var(--blood); box-shadow: 0 0 8px rgba(198, 72, 95, 0.45); }
/* Hunt tab throbs like the heartbeat while a party descends and you're on another tab
   — a gilt pull toward the incursion, not a harsh flash. */
.tabbtn.throb { color: var(--gold); border-color: var(--gold); animation: tabthrob 1.4s ease-in-out infinite; }
@keyframes tabthrob {
  0%, 100% { box-shadow: 0 0 3px rgba(224, 191, 108, 0.2); }
  50%      { box-shadow: 0 0 15px rgba(224, 191, 108, 0.55); }
}
@media (prefers-reduced-motion: reduce) {
  .tabbtn.throb { animation: none; box-shadow: 0 0 10px rgba(224, 191, 108, 0.45); }
  .gchip.throb { animation: none; box-shadow: 0 0 10px rgba(224, 191, 108, 0.45); }
}
/* group separator inside row 2 (#spine 1.9) */
nav#tabs .gdiv {
  width: 2px; align-self: stretch; margin: 0 8px 4px; flex: none;
  border-radius: 1px; background: rgba(200, 162, 76, 0.6);
}

main { display: grid; grid-template-columns: 1fr 320px; gap: 0; min-height: calc(100vh - 140px); }
#content { padding: 16px 18px; }
#logpanel {
  border-left: 1px solid var(--line); padding: 12px; font-size: 12.5px; line-height: 1.5;
  background: var(--bg2); overflow-y: auto; max-height: calc(100vh - 140px);
}
#logpanel .entry { padding: 5px 6px 5px 10px; border-bottom: 1px solid rgba(58, 40, 51, 0.5); color: var(--dim); border-left: 2px solid transparent; display: flex; align-items: baseline; gap: 10px; }
#logpanel .entry .logmsg { flex: 1 1 auto; min-width: 0; }
/* #log-volume timestamps: a muted mono label pinned to the right, aging in place. */
#logpanel .entry .logtime { flex: 0 0 auto; margin-left: auto; font-family: var(--font-mono, monospace); font-style: normal; font-size: 10.5px; letter-spacing: 0.02em; color: var(--dim); opacity: 0.5; white-space: nowrap; -webkit-user-select: none; user-select: none; }
#logpanel .entry.major { color: var(--goo2); }
#logpanel .entry.warn { color: var(--gold); }
#logpanel .entry.bad { color: var(--blood); }
/* The log is MOVING text — keep it in the clean body italic, not the grimoire face. */
#logpanel .entry.thought { color: var(--mana); font-family: var(--font-body); font-style: italic; }

/* CATEGORY GUTTER (0.29.80). Subject lives in the left stripe, severity in the text
   color — two channels that can't collide. Before this, .cat-raid recolored the whole
   line and beat .bad on declaration order, so a raid that killed you looked exactly
   like one that warned you.
   Urgency is carried by the stripe's WEIGHT, not only its hue: the two threads that
   can end a life (raids, the hunt) get a wider, glowing stripe and read as loud even
   at a glance; the quiet threads sit thin and recede. */
:root {
  /* Raid and hunt are the two highest-traffic threads AND the two that sit side by
     side in the same moments, so they get the widest hue separation in the set —
     gold against blood. They were ember-vs-blood at first and read as near-identical
     in play (both orange-red); the ember moved to Milestones, which fires rarely
     enough late-game that sharing a neighbourhood with blood costs nothing. */
  --cat-raid:    #C8A24C;  /* torchlight gold — the loudest thing in the log */
  --cat-records: #6E86A8;  /* cold steel — the ledger of ranks you have learned to weigh */
  --cat-hunt:    #C6485F;  /* blood — the other way a life ends */
  --cat-body:    #6F9E4F;  /* the blob's own green */
  --cat-find:    #4E9E9E;  /* eye-teal — cold, watchful, distinct from the goo */
  --cat-fossil:  #A98B6B;  /* old bone — dry and mineral, apart from the living colours */
  --cat-growth:  #E0713C;  /* ember — advancement */
  --cat-rebirth: #9C8FA8;  /* grave-ash violet-grey */
  --cat-thought: #9A72B5;  /* arcane */
  --cat-world:   #6B5C55;  /* housekeeping — deliberately recedes */
}
#logpanel .entry.cat-raid    { border-left-color: var(--cat-raid); }
#logpanel .entry.cat-records { border-left-color: var(--cat-records); }
#logpanel .entry.cat-hunt    { border-left-color: var(--cat-hunt); }
#logpanel .entry.cat-body    { border-left-color: var(--cat-body); }
#logpanel .entry.cat-find    { border-left-color: var(--cat-find); }
#logpanel .entry.cat-fossil  { border-left-color: var(--cat-fossil); }
#logpanel .entry.cat-growth  { border-left-color: var(--cat-growth); }
#logpanel .entry.cat-rebirth { border-left-color: var(--cat-rebirth); }
#logpanel .entry.cat-thought { border-left-color: var(--cat-thought); }
#logpanel .entry.cat-world   { border-left-color: var(--cat-world); }
/* The two threads that can end a life read as loud: wider stripe plus a lit bleed
   into the row. The glow takes the CATEGORY color, not currentColor — currentColor
   is the severity text color, so a `warn` raid and a `warn` hunt used to glow the
   same gold and undid exactly the raid/hunt separation the hues are chosen for. */
#logpanel .entry.cat-raid, #logpanel .entry.cat-hunt { border-left-width: 4px; padding-left: 8px; }
#logpanel .entry.cat-raid { box-shadow: inset 6px 0 8px -6px var(--cat-raid); }
#logpanel .entry.cat-hunt { box-shadow: inset 6px 0 8px -6px var(--cat-hunt); }

/* The settings list doubles as the log's legend, so it uses the same swatches. */
.logcat { margin-bottom: 4px; }
.catswatch {
  display: inline-block; width: 4px; height: 0.9em; margin-right: 7px;
  vertical-align: -1px; border-radius: 1px; background: var(--cat-world);
}
.catswatch.cat-raid    { background: var(--cat-raid); }
.catswatch.cat-records { background: var(--cat-records); }
.catswatch.cat-hunt    { background: var(--cat-hunt); }
.catswatch.cat-body    { background: var(--cat-body); }
.catswatch.cat-find    { background: var(--cat-find); }
.catswatch.cat-fossil  { background: var(--cat-fossil); }
.catswatch.cat-growth  { background: var(--cat-growth); }
.catswatch.cat-rebirth { background: var(--cat-rebirth); }
.catswatch.cat-thought { background: var(--cat-thought); }
.catswatch.cat-world   { background: var(--cat-world); }

/* Panels: warm mahogany, gilt-tinted line, film grain + inset vignette (UHG cards). */
.card {
  background-color: var(--card); background-image: var(--grain); background-blend-mode: soft-light;
  border: 1px solid var(--line); border-radius: 8px;
  padding: 12px 14px; margin-bottom: 12px;
  box-shadow: var(--shadow-card), var(--vignette-card);
}
.card h3 { font-family: var(--font-display); font-size: 16px; color: var(--goo2); margin-bottom: 6px; font-weight: normal; letter-spacing: 0.5px; }
.card h3.toggle { cursor: pointer; user-select: none; }
.card h3.toggle:hover { color: #fff; }
.card h3.toggle .caret { display: inline-block; width: 12px; color: var(--goo); }
.card p { font-size: 13px; line-height: 1.5; margin-bottom: 6px; }
/* Static flavor/lore — grimoire face (does not move), sized up slightly. */
.card .flavor { font-family: var(--font-grimoire); color: var(--dim); font-style: italic; font-size: 14px; }

/* THE RECKONING (#the-reckoning) — the raider knowledge-ladder panel in the Archive */
table.reckoning { width: 100%; border-collapse: collapse; margin: 4px 0 2px; font-size: 13px; }
table.reckoning th { text-align: left; font-weight: 600; color: var(--dim); font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; padding: 2px 10px 3px 0; border-bottom: 1px solid var(--line); }
table.reckoning td { padding: 3px 10px 3px 0; border-bottom: 1px solid rgba(58, 40, 51, 0.5); vertical-align: top; color: var(--ink); }
table.reckoning td:nth-child(2), table.reckoning td:nth-child(3) { font-variant-numeric: tabular-nums; }
table.reckoning .rank { font-style: italic; color: var(--ink); }  /* #rank-vs-order: rank = lowercase italic, no colour */
table.reckoning .unmet { color: var(--dim); opacity: 0.5; letter-spacing: 1px; }
table.reckoning tr.unmetrow td { color: var(--dim); }
table.reckoning .dim { color: var(--dim); opacity: 0.5; }

/* #rank-vs-order VISUAL GRAMMAR (Mark 2026-08-27): an ORDER is a named faction — flag glyph + bold +
   the reserved banner-teal; a RANK is a plain lowercase-italic adjective, no colour, no glyph. The four
   channels (case / weight / slant / colour-vs-none) keep a hardened company under no colours from ever
   reading as an Order with a missing chronicle. Used in the incursion warning; the Reckoning rank cells
   already followed the rule (scoped above). */
.rank { font-style: italic; }
.ord-name { color: var(--order); font-weight: 600; font-style: normal; white-space: nowrap; }
.ord-name::before { content: "\2691\00a0"; }  /* ⚑ — the colours a company marches under */
h4.recksub { margin: 14px 0 2px; color: var(--dim); font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; }
.card.corpse { border-color: var(--blood); }
.card.incursion { border-color: var(--gold); }
.count { color: var(--dim); font-family: var(--font-mono); font-size: 12px; }
/* Bloat bar (#21) — sits under the maw on the Feed tab, present ONLY while a window
   is open. The fill tracks TIME REMAINING and drains left, so the urgency is the
   emptying rather than a number ticking down in the header chips (which the decided
   UI language explicitly rules out as the signal). No animation: the bar is already
   moving every frame, and the reduced-motion precedent is to let colour carry it. */
.bloatbar { border: 1px solid var(--blood); border-radius: 6px; padding: 8px 10px; margin: 8px 0 4px;
  background: rgba(198, 72, 95, 0.09); }
.bloatlabel { display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  font-size: 13px; color: var(--blood); margin-bottom: 6px; }
.bloatlabel b { letter-spacing: 0.08em; }
.bloattrack { height: 8px; border-radius: 4px; background: rgba(198, 72, 95, 0.18); overflow: hidden; }
.bloatfill { height: 100%; background: var(--blood); border-radius: 4px; transition: width 0.12s linear; }
.bloatbar .mutter { margin: 6px 0 0; }
@media (prefers-reduced-motion: reduce) { .bloatfill { transition: none; } }
/* Preferred-Prey stance selector (#16): its own row under the prey-roster header,
   matching the compact-row idiom of .rvgrid / .organgrid (same 34px cells, same
   spacing) so it reads as part of the established vocabulary rather than a new one.
   Stays put when the panel collapses — it is a control, not a summary. */
.stancebar { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 4px; }
.stancebtn {
  width: 34px; height: 34px; padding: 4px; flex: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 1px solid transparent; border-radius: 6px;
  color: var(--dim); line-height: 0;
}
.stancebtn:hover { color: var(--ink); border-color: var(--line); background: rgba(58, 40, 51, 0.4); }
/* The chosen stance stays lit and boxed — the one state that must survive a glance. */
.stancebtn.on { color: var(--goo2); border-color: var(--goo); background: rgba(111, 158, 79, 0.12); }
/* Idle = this stance has nothing left to prefer here and degrades to Random
   (I.stanceIdle). Dimmed, not disabled: it remains a legal, selectable choice. */
.stancebtn.idle { opacity: 0.4; }
.stancebtn.idle.on { opacity: 0.65; }
.stancebtn svg { width: 100%; height: 100%; fill: currentColor; display: block; }
.mutter { color: var(--dim); font-style: italic; font-size: 13px; margin: 8px 0; }
.warn { color: var(--gold); }
.ok { color: var(--goo); }
.lack { color: var(--blood); }

button.buy, button.bigbuy, button.devour, button.strat {
  font-family: var(--font-ui); cursor: pointer; border-radius: 6px;
  background: var(--card2); color: var(--ink); border: 1px solid var(--line-gilt);
}
button.buy { padding: 6px 12px; font-size: 13px; font-weight: 600; margin: 2px 2px 2px 0; }
button.buy small, button.bigbuy small { display: block; font-family: var(--font-mono); font-size: 11px; font-weight: 400; color: var(--dim); margin-top: 2px; font-variant-numeric: tabular-nums; line-height: 1.5; }
button.buy:hover, button.bigbuy:hover, button.strat:hover { border-color: var(--goo); }
button.buy:disabled { opacity: 0.4; cursor: not-allowed; }
button.buy:disabled:hover { border-color: var(--line); }
button.danger { border-color: var(--blood); color: var(--blood); }

.devourwrap { text-align: center; margin: 10px 0 18px; }
/* The caustic gullet — a wide "throat" you look into: breathing glow + a
   procedural feTurbulence acid froth that boils in time with the breath, pooled
   low by a CSS mask. ::before only, so button.devour stays a single stable node
   (matters — the Feed panel re-renders ~4x/s and must not rebuild this button).
   All effects are composited (box-shadow / transform / opacity); no layout. */
button.devour {
  position: relative; overflow: hidden;
  /* isolate: own stacking context so the z-index:-1 ::before froth paints ABOVE the
     background gradient (not occluded behind it) and its mix-blend-mode:screen blends
     against the button's own gradient. Without this the froth renders only in flashes
     (during :active/animation frames that briefly form a context). */
  isolation: isolate;
  font-family: var(--font-display); font-size: 26px; letter-spacing: 6px; color: var(--goo2);
  width: 300px; height: 148px; padding: 0;
  border: 2px solid var(--goo); border-radius: 50% / 46%;
  background: radial-gradient(ellipse 120% 130% at 50% 6%, #24301c 0%, #1F2C15 26%, #120a09 74%);
  text-shadow: 0 0 14px rgba(143, 202, 99, 0.5), 0 2px 3px #000;
  animation: devourbreathe 3s ease infinite;
  transition: transform 0.06s, filter 0.2s;
  /* outer gilt ring — follows the border-radius, not clipped by overflow, no
     markup change. A restrained gilt halo just outside the green rim. */
  outline: 1px solid rgba(200, 162, 76, 0.6);
  outline-offset: 6px;
}
/* the procedural acid, above the gradient (z-index:-1) but below the label.
   Contained BY CONSTRUCTION so it can't spill in browsers that fail to clip a
   composited/blended pseudo-element against overflow+border-radius (Safari/WebKit
   did exactly that — the froth rectangle poured out the bottom of the maw):
     • inset:0, not -25% → the layer never exceeds the button box; and
     • the mask fades fully to transparent WELL inside the ellipse (radii keep the
       opaque froth away from every edge), so even with no rounded-rect clip at all
       the acid stays pooled inside the visible maw.
   Texture motion is a background-position scroll (repeat), not a transform on the
   whole element — moving the element would re-expose the edges we just contained. */
button.devour::before {
  content: ""; position: absolute; inset: 0; z-index: -1; mix-blend-mode: screen;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.48  0 0 0 0 0.7  0 0 0 0 0.26  0 0 0 1 -0.22'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  background-size: 150px 150px; background-repeat: repeat;
  -webkit-mask: radial-gradient(ellipse 76% 62% at 50% 66%, #000 0%, #000 24%, transparent 72%);
          mask: radial-gradient(ellipse 76% 62% at 50% 66%, #000 0%, #000 24%, transparent 72%);
  animation: devourdrift 9s linear infinite, devourboil 3s ease infinite;
}
button.devour:active { transform: scale(0.96); }
button.devour:hover { filter: brightness(1.12); }
button.devour small { display: block; position: relative; z-index: 1; font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; color: var(--dim); margin-top: 6px; }
@keyframes devourbreathe {
  0%, 100% { box-shadow: 0 0 22px rgba(143,202,99,0.22), inset 0 -22px 40px 6px rgba(0,0,0,0.7), inset 0 10px 22px -6px rgba(143,202,99,0.28); }
  50%      { box-shadow: 0 0 44px rgba(143,202,99,0.42), inset 0 -20px 38px 6px rgba(0,0,0,0.66), inset 0 12px 26px -6px rgba(143,202,99,0.42); }
}
@keyframes devourboil  { 0%, 100% { opacity: 0.52; } 50% { opacity: 0.74; } }
@keyframes devourdrift { 0% { background-position: 0 0; } 100% { background-position: -44px -18px; } }
@media (prefers-reduced-motion: reduce) {
  button.devour, button.devour::before { animation: none; }
}

/* Feed "maw" row: the current stratum framed around the Devour button — identity on
   the left, the mouth in the middle, its makeup on the right. Equal side columns keep
   the button centered; they stack (flavor → button → stats) on a narrow viewport. */
.mawrow { display: flex; align-items: center; gap: 18px; }
.mawrow > button.devour { flex: 0 0 auto; }
.mawcol { flex: 1 1 0; min-width: 0; }
.mawleft { text-align: left; }
.mawright { text-align: right; }
.mawcol :last-child { margin-bottom: 0; }
/* Right-column stats as stacked mini-panels — hardness / gnaw / yields. fit-content
   + stretch makes every panel the width of the widest; margin-left:auto keeps the
   stack pinned to the column's right edge. */
.statstack { display: flex; flex-direction: column; gap: 6px; width: fit-content; margin-left: auto; }
.statpanel {
  background: var(--card2); border: 1px solid var(--line); border-radius: 6px;
  padding: 6px 12px; text-align: center;
}
.statlabel { font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--dim); margin-bottom: 2px; }
.statval { font-family: var(--font-ui); font-size: 13px; color: var(--ink); line-height: 1.4; }
@media (max-width: 700px) {
  .mawrow { flex-direction: column; }
  .mawleft, .mawright { text-align: center; }
  .statstack { margin: 0 auto; }
}

.awakenprompt { text-align: center; margin: 14px 0; }
.awakenprompt p { color: var(--dim); font-family: var(--font-grimoire); font-style: italic; font-size: 14px; margin-top: 6px; }
button.bigbuy { font-family: var(--font-display); font-size: 17px; letter-spacing: 3px; padding: 14px 30px; color: var(--goo2); }
button.bigbuy.pulse { animation: pulse 1.4s ease-in-out infinite; }
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(143, 202, 99, 0.22); }
  50% { box-shadow: 0 0 26px rgba(143, 202, 99, 0.55); }
}

.bar { position: relative; background: var(--bg); border: 1px solid var(--line); border-radius: 4px; height: 22px; margin: 6px 0; overflow: hidden; }
.bar .fill { height: 100%; background: linear-gradient(90deg, #3F5C2E, var(--goo)); transition: width 0.25s; }
.bar.prey .fill { background: linear-gradient(90deg, #45121F, var(--blood)); }

/* Prey card: text on the left, a portrait mini-card pinned to the right. */
.preywrap { display: flex; gap: 12px; align-items: flex-start; }
.preymain { flex: 1 1 auto; min-width: 0; }
/* Pin the specimen heading's line box so the rare "✦" prefix (a taller display-font
   glyph) can't stretch it — otherwise the whole card grows ~2px the instant a rare
   spawns. 1.25 reproduces the normal-glyph line box exactly, so nothing else shifts. */
.preymain h3 { line-height: 1.25; }
.portrait {
  position: relative; flex: 0 0 auto; width: 104px; height: 104px;
  border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
  background: radial-gradient(ellipse at 50% 38%, #241820 0%, #0A0608 75%);
}
.portrait.rare { border-color: var(--gold); box-shadow: 0 0 10px rgba(224, 191, 108, 0.3); }
.portrait img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.portrait-ph {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center; color: var(--dim);
}
.portrait-ph .pglyph { font-family: var(--font-display); font-size: 26px; opacity: 0.4; line-height: 1; }
.portrait.rare .portrait-ph .pglyph { color: var(--gold); opacity: 0.6; }
.portrait-ph small { font-family: var(--font-mono); font-size: 9px; letter-spacing: 1px; text-transform: uppercase; margin-top: 5px; opacity: 0.6; line-height: 1.3; }
@media (max-width: 480px) { .portrait { width: 76px; height: 76px; } }

/* Faction guild crest — shown on the death screen once you've met the faction. */
.sigil {
  position: relative; width: 72px; height: 72px; flex: 0 0 auto;
  border: 1px solid var(--blood); border-radius: 8px; overflow: hidden;
  background: radial-gradient(ellipse at 50% 38%, #2A0C13 0%, #0A0608 75%);
}
.sigil img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.sigil-ph {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center; color: var(--dim);
}
.sigil-ph .sglyph { font-family: var(--font-display); font-size: 24px; opacity: 0.5; line-height: 1; color: var(--blood); }
.sigil-ph small { font-family: var(--font-mono); font-size: 8px; letter-spacing: 1px; text-transform: uppercase; margin-top: 4px; opacity: 0.6; line-height: 1.3; }
.deathmath.hassigil { position: relative; }
.deathmath.hassigil .sigil { float: right; margin: 0 0 6px 10px; }
/* Chronicles (1c): faction report cards; the crest floats to the right. */
.card.chron { position: relative; }
.card.chron .sigil { float: right; margin: 2px 0 8px 12px; }
/* Dossier notes: long-form reading, so the legible Spectral face (not the decorative
   grimoire), at a comfortable size; a hairline separates each accumulated dispatch. */
.card .chron-note { font-family: var(--font-body); color: var(--ink); font-size: 14.5px; line-height: 1.6; margin-bottom: 0; }
.chron-note + .chron-note { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--line); }
.bar.mana .fill { background: linear-gradient(90deg, #3D2A57, var(--mana)); }
.bar span { position: absolute; inset: 0; text-align: center; font-family: var(--font-mono); font-size: 12px; line-height: 22px; color: #fff; text-shadow: 0 1px 2px #000; }

.stratalist { display: flex; flex-wrap: wrap; gap: 6px; }
button.strat { padding: 8px 12px; font-size: 13px; font-weight: 600; }
button.strat small { display: block; font-family: var(--font-mono); font-size: 10px; font-weight: 400; color: var(--dim); }
button.strat.active { border-color: var(--goo); color: var(--goo2); }

.organs, .skills, .spells { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 10px; }
/* Equal-height spell cards: Deep Hunger has no material component, so its Cast line is a
   row shorter than the others — 1fr auto-rows makes every row (and thus every card) the
   height of the tallest, so the four chips match regardless of how they wrap. */
.spells { grid-auto-rows: 1fr; }
/* Organ cards stretch to equal height per grid row; make each a column so the Grow
   button drops to the CARD bottom (margin-top:auto) instead of hugging the text —
   the buttons line up across cards of differing text length. */
.card.organ { display: flex; flex-direction: column; }
.card.organ button.buy { display: block; width: 100%; text-align: center; margin-top: auto; }
/* Skill / Archive cards get the same bottom-drop, but the Learn/Deepen button is
   centered at its natural width (margin-top:auto = bottom, align-self:center = h-center). */
.card.skill { display: flex; flex-direction: column; }
.card.skill button.buy { margin-top: auto; align-self: center; }
.card.skill.owned { opacity: 0.55; }
.card.skill.azothlocked { opacity: 0.65; border-style: dashed; }
.card.skill.azothlocked h3 { color: var(--mana); }

/* Skill tree: root columns, nested children with a connector line. */
.skilltree { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; }
.skgroup { min-width: 190px; flex: 0 1 auto; }
.sknode {
  border: 1px solid var(--line); border-radius: 6px; background: var(--card);
  padding: 6px 10px; font-size: 12.5px; margin-bottom: 5px; max-width: 240px;
}
.sknode b { font-weight: normal; color: var(--ink); display: block; letter-spacing: 0.5px; }
.sknode small { display: block; font-family: var(--font-mono); color: var(--dim); font-variant-numeric: tabular-nums; line-height: 1.45; }
.sknode.avail { cursor: pointer; border-color: var(--goo); }
.sknode.avail:hover { box-shadow: 0 0 10px rgba(111, 158, 79, 0.35); }
.sknode.owned { opacity: 0.6; border-color: rgba(111, 158, 79, 0.5); }
.sknode.owned b { color: var(--goo2); }
.sknode.future { opacity: 0.45; }
.sknode.azlocked { border-style: dashed; opacity: 0.65; }
.sknode.azlocked b { color: var(--mana); }
.skchildren { margin-left: 11px; padding-left: 11px; border-left: 1px solid var(--line); }
.card.spell.activebuff { border-color: var(--mana); box-shadow: 0 0 14px rgba(110, 74, 134, 0.35); }

ul.roster { list-style: none; font-size: 13px; }
ul.reserves li.satfull b { color: var(--blood); }
.bar.thin { height: 6px; margin: 3px 0 4px; }
.bar.thin span { display: none; }
ul.roster li { padding: 5px 2px; border-bottom: 1px solid rgba(58, 40, 51, 0.5); }
ul.roster li.locked { color: var(--dim); }
ul.roster li.rare b { color: var(--gold); text-shadow: 0 0 8px rgba(224, 191, 108, 0.4); }
ul.roster li.unmet b { color: #5a4a52; letter-spacing: 2px; }

/* Spoils (#22): a grid of panels, one per piece of gear (mirrors the achievements grid),
   each three stacked rows — name + rarity, materials, then the Render-down button. */
.spoilsgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 8px; }
.spoilpanel { background: var(--bg2); border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; display: flex; flex-direction: column; gap: 6px; }
.spoilpanel .sp-name b { letter-spacing: 0.5px; }
.spoilpanel .sp-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 8px; font-size: 11.5px; }
.spoilpanel .sp-rar { text-transform: uppercase; letter-spacing: 1px; font-family: var(--font-mono); color: var(--dim); }
.spoilpanel .sp-mats { font-family: var(--font-mono); }
.spoilpanel button { align-self: flex-start; }
/* Rarity tint — clearly visible: the accent colour on the border plus a soft glow, not a
   near-transparent wash. Common keeps the default line colour. */
.spoilpanel.rar-fine { border-color: var(--goo2); box-shadow: 0 0 6px rgba(143, 202, 99, 0.3); }
.spoilpanel.rar-fine .sp-rar { color: var(--goo2); }
.spoilpanel.rar-magic { border-color: var(--gold); box-shadow: 0 0 7px rgba(224, 191, 108, 0.35); }
.spoilpanel.rar-magic .sp-rar { color: var(--gold); }
/* Nobles: gold, and unmistakably so — the one thing you cannot eat. */
.spoilpanel.rar-shiny { border-color: var(--gold); box-shadow: 0 0 9px rgba(224, 191, 108, 0.45); }
.spoilpanel.rar-shiny .sp-name b, .spoilpanel.rar-shiny .sp-rar { color: var(--gold); }
.spoilpanel.rar-shiny .mutter { font-size: 11px; }
/* Kept gems: the count on the left, one dot per gem down the right (colour = kind, I.GEMS_META).
   The dot column wraps into a second column past a dozen so a big pile stays a chip, not a tower
   (Mark, 2026-08-10 — a stand-in for the Hoard's per-gem ledger). */
.spoilpanel.gem { flex-direction: row; align-items: flex-start; justify-content: space-between; gap: 10px; border-color: #6f6a86; }
.spoilpanel.gem .gem-body { flex: 1 1 auto; min-width: 0; }
.spoilpanel.gem .sp-name b { color: #b9b3d6; }
.gem-dots { display: flex; flex-direction: column; flex-wrap: wrap; align-content: flex-end; gap: 4px; max-height: 104px; flex: 0 0 auto; }
.gem-dots i { width: 7px; height: 7px; border-radius: 50%; display: block; box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.45), 0 0 2px rgba(255, 255, 255, 0.15); }
/* #hoard: the deposited pile — one row per gem kind (coloured dot + name + count), then the shine. */
/* #gems: the Hoard pile is bordered CHIPS on a uniform grid — every chip the same width (the
   column, sized to the widest), several per row (Mark). Grid items stretch to fill their column. */
.hoardpile { display: grid; grid-template-columns: repeat(auto-fill, minmax(135px, 1fr)); gap: 8px; margin: 4px 0 12px; align-items: start; }
.hoardrow { display: flex; align-items: center; gap: 7px; background: var(--card2); border: 1px solid var(--line); border-radius: 8px; padding: 5px 10px; }
.hoardrow b { color: #b9b3d6; font-weight: 600; }
/* Each chip's border takes its kind's colour (gems set it inline from GEMS_META; shine and amber
   get their own here), so the frame reinforces the pip (Mark). */
.hoardrow.gem2.shine { border-color: #c9a24a; }
.hoardrow.gem2.amber { border-color: #D98E2A; }
.hoardrow.gem2 { flex-direction: column; align-items: flex-start; gap: 2px; }
.hoardrow.gem2 .hgemhead { display: flex; align-items: center; gap: 7px; }
/* #gems: keep a two-word gem name (e.g. "smoky quartz") on ONE line rather than breaking at the
   space — it fits the 135px chip; without this it wraps right at the edge. */
.hoardrow.gem2 .hgemhead b { white-space: nowrap; }
.hoardrow.gem2 .hbreak { font-size: 10px; line-height: 14px; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Cold shine carries one quantity, not the gems' Uncut/Cut pair, but should stand as tall as a
   three-line gem chip: give its lone breakdown the height of the two gem lines (14 + 2 gap + 14)
   and center the ×N within it. */
.hoardrow.gem2 .hbreak.qtycenter { min-height: 30px; display: flex; align-items: center; }
.gemdot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.45), 0 0 3px rgba(255, 255, 255, 0.15); }
.gemdot.shine { background: linear-gradient(135deg, #f4d97a, #b98f2e); }
/* Amber in the Hoard keeps the honey identity it wore as a field find (Mark): honey pip + name. */
.gemdot.amber { background: #D98E2A; }
.hoardrow.gem2.amber b { color: #D98E2A; }
/* THE RARITY LADDER (#rarity): grade shows ONLY as a border colour + a pip strip (the
   colourblind-safe second channel), never a word. The rar-fine/rar-magic rules above are KEPT
   for the fossils card + museum frames, which are never graded — finds keep their own grammar. */
.spoilpanel.rar-scrap    { border-color: var(--rar-scrap);    --pip: var(--rar-scrap); }
.spoilpanel.rar-common   { border-color: var(--rar-common);   --pip: var(--rar-common); }
.spoilpanel.rar-uncommon { border-color: var(--rar-uncommon); --pip: var(--rar-uncommon); }
.spoilpanel.rar-rare     { border-color: var(--rar-rare);     --pip: var(--rar-rare);   box-shadow: 0 0 6px rgba(91, 143, 201, 0.28); }
.spoilpanel.rar-epic     { border-color: var(--rar-epic);     --pip: var(--rar-epic);   box-shadow: 0 0 7px rgba(228, 179, 58, 0.32); }
.spoilpanel.rar-unique   { border-color: var(--rar-unique);   --pip: var(--rar-unique); box-shadow: 0 0 8px rgba(226, 96, 31, 0.38); }
.spoilpanel.rar-mythic   { border-color: var(--rar-mythic);   --pip: var(--rar-mythic); box-shadow: 0 0 9px rgba(222, 71, 71, 0.42); }
/* the pip strip — one pip per tier rank; the ladder survives colourblindness once the words go.
   Laid out VERTICALLY, centred on the RIGHT of the spoils chip (Mark, 2026-08-10). Scoped to
   .pipd so it never reserves space on fossil/noble/museum panels, which carry no pips. */
.spoilpanel.pipd { position: relative; padding-right: 26px; }
.spoilpanel.pipd .sp-pips {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 3px;
}
.sp-pips i { width: 5px; height: 5px; border-radius: 50%; background: var(--pip, var(--dim)); }
/* the azoth sigil — the fifth essence's mark in arcane violet (v1 text placeholder, brief-to-Basil) */
.azsigil { font-family: var(--font-display); color: var(--mana); font-weight: 700; letter-spacing: -0.03em; }
.azbadge { font-size: 0.92em; margin-left: 4px; }
/* azoth SHIMMER — a felt cue on azoth-bearing rows, an overlay so it never clobbers the tier
   border glow; honours prefers-reduced-motion. */
.spoilpanel.azbearing { position: relative; }
.spoilpanel.azbearing::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 11px rgba(154, 114, 181, 0.20); animation: azshimmer 3.2s ease-in-out infinite;
}
@keyframes azshimmer { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .spoilpanel.azbearing::after { animation: none; opacity: 0.8; } }
/* Prey roster (Hunt tab): two aligned columns — name | stats — each left-aligned.
   Subgrid maps every row's cells onto the parent tracks so the stat blocks line up
   down the list; name column caps at 13em and wraps past it. */
/* Three columns: name | stars | stats. max-content on the first two + nowrap on the name
   keeps a long name on one line (its own column, not sharing width with the stars).
   NOTE: intentionally not yet responsive — a narrow window will overflow; mobile is later. */
/* Six aligned columns — thumb | name | stars | size | hp | the rest (yields, bite, notes).
   Size and hp get their own columns so they line up down the list instead of shoving the yields
   around; a tiny art thumbnail leads each line (Mark, 2026-08-10). Rows that know less span the
   data columns: a sighted-but-unstudied shape knows its size but not its hp (.rspanhp), an unmet
   one knows neither (.rspanrest). */
ul.preyroster { display: grid; grid-template-columns: max-content max-content max-content max-content max-content 1fr; }
ul.preyroster li { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; column-gap: 14px; align-items: baseline; }
.preyroster .rname, .preyroster .rsize, .preyroster .rhp { white-space: nowrap; }
.preyroster .rspanhp { grid-column: 5 / -1; }
.preyroster .rspanrest { grid-column: 4 / -1; }
/* Tiny roster art box — kept small on purpose so it doesn't grow the line; centred against the
   text rather than baseline-aligned. .noart shows an ✕ where art isn't drawn yet. Rare shapes
   get the gold edge they wear everywhere else. */
.preyroster .rthumb { align-self: center; position: relative; width: 24px; height: 24px; border-radius: 5px;
  border: 1px solid rgba(150, 140, 150, 0.28); background: rgba(0, 0, 0, 0.25); display: inline-flex;
  align-items: center; justify-content: center; flex: 0 0 auto;
  /* Eye-tuned seating (Mark): sits the box just above geometric center against the
     roster name (art/✕ ride along). Tuned by eye, not metrics. */
  transform: translateY(-1.5px); }
.preyroster .rthumb img { width: 100%; height: 100%; object-fit: cover; border-radius: 4px; display: block; }
/* The ✕ glyph's ink sits entirely above the baseline (zero descent), so flex-centering
   the line box leaves it riding ~1px high; nudge it down to true optical center. */
.preyroster .rthumb.noart::after { content: "\2715"; color: var(--dim); font-size: 12px; line-height: 1; transform: translateY(1px); }
.preyroster li.rare .rthumb { border-color: var(--gold); }
/* Hover the tiny box to float the full 104px portrait (the art, or the "coming soon" card) — the
   same portrait the specimen box shows. Offset to the right so the leftmost column has room;
   #content and .card don't clip, so it shows whole. pointer-events:none — it's a passive preview. */
.preyroster .rthumb-pop { position: absolute; left: calc(100% + 8px); top: -6px; z-index: 60;
  display: none; pointer-events: none; filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.55)); }
.preyroster .rthumb:hover .rthumb-pop { display: block; }
/* Museum frames: four aligned columns — name | native rock | fitted | spaces unfilled —
   the same subgrid trick as the prey roster so the numbers line up down the list. */
ul.museumroster { display: grid; grid-template-columns: max-content max-content max-content 1fr; }
ul.museumroster li { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; column-gap: 14px; align-items: baseline; }
.museumroster .rname, .museumroster .mnative { white-space: nowrap; }
/* Native rock in the yields-green (matches the prey roster's "yields" text); spaces still
   unfilled in the rare-gold (matches a rare specimen), so the frame is not a wall of one colour. */
.museumroster .mnative { color: var(--goo); }
.museumroster .mgap { text-align: center; }
.museumroster .munfit { color: var(--gold); }
/* Column headers (Mark): the repeated per-row labels ("spaces unfilled", "fitted", "laid out")
   collapse into one header line, so each cell below can hold only its value. */
.museumroster .mhead span { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--dim); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
/* Laid-out-but-not-yet-fitted backlog — "bone", so ready-to-fit reads distinct from the
   green (native/fitted) and the gold (still to find). */
.museumroster .mlaid { color: var(--dim); }

/* CORPSE roster (#pilgrimage): location · freshness · what it holds · action, aligned via
   subgrid like the prey and museum rosters. Action right-justified; holdings wrap. */
ul.corpseroster { display: grid; grid-template-columns: max-content max-content 1fr max-content; }
ul.corpseroster li { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; column-gap: 12px; align-items: center; row-gap: 4px; }
.corpseroster .cloc { white-space: nowrap; }
.corpseroster .cholds { display: flex; flex-wrap: wrap; gap: 3px; }
.corpseroster .cact { justify-self: end; }

/* THE STUDIES sliders (Mark, 2026-08-01) — title + flavour on one line, then a 0..total-power
   range on the next. accent-color themes the native track/thumb to the blob green. */
.studyrow { margin: 10px 0 12px; }
.study-head b { color: var(--goo2); }
.studyrow.blocked .study-head b { color: var(--dim); }
.study-head span { font-size: 12px; }
.study-slide { display: flex; align-items: center; gap: 10px; margin-top: 4px; }
/* Range sliders, made grabbable (Mark, 2026-08-10): a tall invisible hit strip, a visible thin
   track, and a BIG round thumb — the old 4px slider was near-impossible to catch, and fumbling
   for it selected the text around it instead. user-select is killed on the row so a miss never
   highlights. Clicking the track still jumps the thumb toward the click (native behaviour kept). */
.studyslider { flex: 1; min-width: 0; cursor: pointer; -webkit-appearance: none; appearance: none;
  height: 24px; background: transparent; margin: 0; touch-action: none; }
.studyslider::-webkit-slider-runnable-track { height: 6px; border-radius: 3px; background: rgba(180, 170, 180, 0.18); }
.studyslider::-moz-range-track { height: 6px; border-radius: 3px; background: rgba(180, 170, 180, 0.18); }
.studyslider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px;
  border-radius: 50%; background: var(--goo); border: 2px solid #0a0608; margin-top: -7px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); }
.studyslider::-moz-range-thumb { width: 20px; height: 20px; border-radius: 50%; background: var(--goo);
  border: 2px solid #0a0608; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); }
.studyslider:active { cursor: grabbing; }
.studyrow, .study-slide { -webkit-user-select: none; user-select: none; }
.studyval { min-width: 62px; text-align: right; white-space: nowrap; }
/* The AWARENESS track (#awareness): the protected row that holds your stage — set apart in gilt,
   with a gold thumb, so it reads as the one thing studies can never take. */
.studyrow.aware { border-left: 2px solid var(--gold); padding-left: 9px; margin-bottom: 14px; }
.studyrow.aware .study-head b { color: var(--gold); }
.studyslider.awareslider::-webkit-slider-thumb { background: var(--gold); }
.studyslider.awareslider::-moz-range-thumb { background: var(--gold); }
/* Comprehension-exhausted prey: struck-through AP + a gilt "understood" state tag. */
.spent { text-decoration: line-through; color: var(--dim); }
.apfloor { color: var(--dim); }
/* Prey-roster yields, each in its own colour so the two resources read apart (Mark, 2026-08-10):
   flesh in goo-green, analysis in gold (its res-bar colour). Both stay full-strength — the falling
   number and rate show a shape tapping out on their own; a dimmed figure would only read worse. */
.bioyield { color: var(--goo); }
.apyield { color: var(--gold); }
.understood { color: var(--gold); font-style: italic; cursor: help; }
h4.bestrat { color: var(--dim); font-family: var(--font-mono); font-weight: normal; letter-spacing: 2px; font-size: 12px; text-transform: uppercase; margin: 10px 0 2px; }
h4.bestrat.toggle { cursor: pointer; user-select: none; padding: 3px 4px; border-radius: 4px; }
h4.bestrat.toggle:hover { color: var(--goo2); background: rgba(58, 40, 51, 0.5); }
h4.bestrat .caret { display: inline-block; width: 12px; color: var(--goo); }

.res.clickable { cursor: pointer; }
.res.clickable:hover { border-color: var(--goo); }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.chip {
  background: var(--bg2); border: 1px solid var(--line); border-radius: 12px;
  padding: 3px 10px; font-family: var(--font-ui); font-size: 12px; color: var(--dim); cursor: help;
}
.chip:hover { color: var(--goo2); border-color: var(--goo); }
/* Cured chip (#ouroboros): a positive-state pill on the Flesh header — goo-green so it reads as
   a held boon, its full description on hover. */
.chip.cured { color: var(--goo2); border-color: var(--goo); }
.card.learned h3 button { margin-left: 8px; }

.thoughts { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px; }
.thought {
  background: var(--bg2); border: 1px solid var(--line); border-radius: 6px;
  padding: 8px 10px; font-size: 12.5px; cursor: pointer;
}
.thought b { color: var(--mana); font-weight: normal; letter-spacing: 1px; }
.thought.locked b { color: #5a4a52; }
.thought.open { grid-column: 1 / -1; }
/* Expanded Dark Thought lore is STATIC — grimoire face is welcome here. */
.thought.open p { margin-top: 6px; font-family: var(--font-grimoire); color: var(--ink); font-style: italic; font-size: 15px; line-height: 1.65; }
.thought:hover { border-color: var(--mana); }
.thought.locked:hover { border-color: var(--line); cursor: default; }
.thought.ach { cursor: default; }
.thought.ach p { margin-top: 4px; color: var(--dim); font-size: 11.5px; line-height: 1.4; }
.thought.ach.got b { color: var(--gold); }
.thought.ach.got { border-color: rgba(224, 191, 108, 0.45); }
.thought.ach.locked { opacity: 0.55; }
.thought.ach:hover { border-color: var(--line); }
.thought.ach.got:hover { border-color: var(--gold); }

.stars { color: var(--gold); font-size: 11px; letter-spacing: 1px; cursor: help; }

.fresh {
  display: inline-block; font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: 1px;
  border: 1px solid; border-radius: 10px; padding: 1px 8px; cursor: help; vertical-align: middle;
}
.fresh.fresh { color: var(--goo2); border-color: var(--goo); }
.fresh.decaying { color: var(--gold); border-color: var(--gold); }
.fresh.skeletal { color: var(--blood); border-color: var(--blood); opacity: 0.85; }

/* The two Settings wells: Persistence's save box and Measure's clipboard fallback. Same
   treatment, so a second one cannot ship unstyled the way an id-only selector invites. */
textarea#savetext, textarea#spectext {
  width: 100%; height: 70px; margin-top: 8px; background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-radius: 4px; font-size: 11px; padding: 6px; font-family: var(--font-mono);
}

.overlay {
  position: fixed; inset: 0; background: rgba(8, 4, 6, 0.86); z-index: 10;
  display: flex; align-items: center; justify-content: center;
}
.modal {
  background-color: var(--card); background-image: var(--grain); background-blend-mode: soft-light;
  border: 1px solid var(--line-gilt); border-radius: 10px;
  max-width: 460px; padding: 28px 32px; text-align: center;
  box-shadow: 0 30px 80px rgba(2, 1, 2, 0.7), var(--vignette-card);
}
.modal h2 { font-family: var(--font-display); color: var(--goo2); letter-spacing: 3px; margin-bottom: 12px; font-weight: normal; }
.modal.death h2 { color: var(--blood); }
.modal.death { border-color: var(--blood); }
.modal p { font-size: 14px; line-height: 1.6; margin-bottom: 10px; }
.modal .flavor { font-family: var(--font-grimoire); color: var(--dim); font-style: italic; }
.modal button { margin-top: 10px; }

/* #35 — first-open intro splash. Leather ground like the header, the wordmark in
   the display face, the tagline in the grimoire face, Eldy peering in from the
   lower-right. Content is centered; Eldy is decorative and sits behind it. */
.modal.splash {
  max-width: none; width: min(72vw, 684px); min-height: min(78vh, 600px);
  padding: 0; overflow: hidden; position: relative; text-align: center;
  background-color: #1e130e;
  background-image: var(--leather), radial-gradient(130% 110% at 30% 18%, #34251c, #1e130e 72%);
  background-blend-mode: overlay, normal;
}
.splash-inner {
  position: relative; z-index: 2;
  min-height: inherit; display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: clamp(8px, 1.6vh, 18px);
  padding: clamp(22px, 4vh, 46px) clamp(24px, 5vw, 60px);
}
.modal.splash .wordmark {
  font-family: var(--font-display); font-weight: normal; line-height: 0.95;
  color: var(--ink); margin: 0; letter-spacing: 0.02em;
  font-size: clamp(34px, 6vw, 66px);
  text-shadow: 0 2px 0 rgba(0,0,0,0.5), 0 0 26px rgba(143,202,99,0.10);
}
.modal.splash .wordmark b { font-weight: normal; color: var(--goo2); }
.modal.splash .splash-sub {
  font-family: var(--font-mono); font-size: clamp(10px, 1.2vw, 13px);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim); margin: 0;
}
.splash-sub .v { color: var(--gold); }
.modal.splash .gilt-rule {
  width: min(340px, 60%); height: 1px; border: 0; margin: clamp(2px, 1vh, 8px) 0;
  background: linear-gradient(90deg, transparent, var(--line-gilt) 20%, var(--gold) 50%, var(--line-gilt) 80%, transparent);
  opacity: 0.8;
}
.modal.splash .splash-tag {
  font-family: var(--font-grimoire); font-style: italic; color: var(--ink);
  font-size: clamp(18px, 2.4vw, 27px); line-height: 1.6; margin: 0;
  max-width: 26ch; text-wrap: balance;
}
.splash-tag .become {
  display: block; margin-top: 0.55em; font-style: normal; color: var(--goo2);
  letter-spacing: 0.02em; text-shadow: 0 0 18px rgba(143,202,99,0.18);
}
.splash-help {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  font-family: var(--font-ui); font-size: clamp(11px, 1.1vw, 13px); color: var(--dim);
}
.splash-help b { color: var(--ink); }
.splash-help .k {
  font-family: var(--font-mono); font-size: 0.86em; color: var(--gold);
  border: 1px solid var(--line-gilt); border-radius: 4px; padding: 1px 6px;
  background: rgba(0,0,0,0.22);
}
.splash-cta {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  margin-top: clamp(4px, 1.4vh, 12px);
}
.modal.splash .begin {
  font-family: var(--font-display); font-weight: normal; letter-spacing: 0.06em;
  text-transform: uppercase; font-size: clamp(15px, 1.7vw, 19px); color: var(--bg);
  cursor: pointer; border: 1px solid rgba(0,0,0,0.35); border-radius: 6px;
  margin: 0; padding: clamp(9px, 1.2vh, 12px) clamp(28px, 4vw, 46px);
  background: linear-gradient(180deg, var(--goo2), var(--goo));
  box-shadow: 0 3px 0 #4f7338, 0 6px 16px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.25);
}
.modal.splash .begin:hover { filter: brightness(1.06); }
.modal.splash .begin:active { transform: translateY(2px); box-shadow: 0 1px 0 #4f7338, 0 3px 10px rgba(0,0,0,0.4); }
.splash-recur {
  font-family: var(--font-ui); font-size: 11.5px; color: var(--dim);
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer; user-select: none;
}
.splash-recur .cbox {
  width: 13px; height: 13px; border: 1px solid var(--dim); border-radius: 3px;
  display: inline-block; position: relative; flex: none;
}
.splash-recur .cbox.on { border-color: var(--goo2); }
.splash-recur .cbox.on::after {
  content: "✓"; position: absolute; left: 1px; top: -4px; color: var(--goo2); font-size: 12px;
}
.splash-eldy {
  position: absolute; right: clamp(4px, 1.4vw, 16px); bottom: clamp(0px, 0.8vh, 10px);
  z-index: 1; width: clamp(92px, 19%, 168px); pointer-events: none;
}
.splash-eldy img { display: block; width: 100%; height: auto; filter: drop-shadow(0 6px 14px rgba(0,0,0,0.5)); opacity: 0.96; }
@media (max-width: 520px) { .splash-eldy { opacity: 0.7; width: 84px; } }

/* Credits modal — leather/gilt like the splash, laid out as an honor roll. p-based
   rows are scoped under .modal.credits so `.modal p{font-size:14px}` can't win. */
.modal.credits {
  max-width: 520px; text-align: center; overflow: hidden;
  background-color: #1e130e;
  background-image: var(--leather), radial-gradient(130% 110% at 30% 18%, #34251c, #1e130e 72%);
  background-blend-mode: overlay, normal;
}
.modal.credits .wordmark { font-family: var(--font-display); font-weight: normal; line-height: 1; color: var(--ink); font-size: 34px; letter-spacing: 0.02em; margin: 0 0 4px; }
.modal.credits .wordmark b { font-weight: normal; color: var(--goo2); }
.modal.credits .credits-sub { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim); margin: 0; }
.modal.credits .gilt-rule { width: min(320px, 70%); height: 1px; border: 0; margin: 14px auto; background: linear-gradient(90deg, transparent, var(--line-gilt) 20%, var(--gold) 50%, var(--line-gilt) 80%, transparent); opacity: 0.8; }
.credits-sec { margin: 14px 0; text-align: left; }
.credits-sec h3 { font-family: var(--font-mono); font-weight: normal; font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--gold); margin: 0 0 8px; text-align: center; }
.credits-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.credits-list li { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding-bottom: 5px; border-bottom: 1px solid rgba(200, 162, 76, 0.12); }
.credits-list b { font-family: var(--font-display); font-weight: normal; color: var(--ink); font-size: 16px; }
.credits-list span { font-family: var(--font-ui); font-size: 12px; color: var(--dim); }
.modal.credits .credits-testers,
.modal.credits .credits-authors { font-family: var(--font-grimoire); font-style: italic; color: var(--ink); font-size: 15px; text-align: center; margin: 0; }
/* Torpor: the header clamor orb + the dreaming-dark overlay. The orb's colour/glow is
   driven inline by the 100ms pulse loop (red & quick when loud → deep-green & slow when
   torpid); CSS only sizes it and sets a fallback fill. */
/* the orb floats bare on the header leather — no chip box, vertically centred in the row. */
.res.clamor { min-width: 0; width: 50px; padding: 0; display: flex; align-items: center; justify-content: center; cursor: help;
  background: none; border: 0; box-shadow: none; align-self: stretch; }
/* a sphere, not a flat disc: an inset dark underside + a faint top-left highlight give it
   volume; the JS sets the radial-gradient colour (steady, no pulse). */
.res.clamor .orb { width: 29px; height: 29px; border-radius: 50%; background: rgb(198, 72, 95);
  box-shadow: inset -2px -3px 5px rgba(0, 0, 0, 0.5), inset 2px 2px 3px rgba(255, 255, 255, 0.22); }
/* Dream screen: a centred panel (~splash size) over a dimming scrim — not full-bleed. */
.torpor-overlay { position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center; cursor: pointer;
  background: rgba(4, 7, 5, 0.72); }
.torpor-dream { width: min(80vw, 760px); height: min(78vh, 600px); border-radius: 10px; overflow: hidden;
  border: 1px solid var(--line-gilt); box-shadow: 0 24px 64px rgba(0, 0, 0, 0.6);
  background: radial-gradient(130% 110% at 50% 34%, #15230e, #060b06 74%);
  text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; padding: 40px; }
.torpor-art svg { width: min(240px, 46vw); height: auto; filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.6)); }
.torpor-ph { font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--gold); opacity: 0.55; margin-top: 4px; }
.torpor-tag { font-family: var(--font-display); font-weight: normal; font-size: clamp(22px, 4vw, 40px); color: var(--goo2); letter-spacing: 1px; margin: 0; text-shadow: 0 0 30px rgba(143, 202, 99, 0.28), 0 2px 4px #000; text-wrap: balance; }
.torpor-hint { font-family: var(--font-mono); font-size: 11px; letter-spacing: 2px; text-transform: uppercase; color: var(--dim); margin: 0; }

.deathmath {
  text-align: left; margin: 14px 0; padding: 12px 16px;
  background: var(--bg2); border: 1px solid var(--line); border-left: 3px solid var(--blood);
  border-radius: 6px;
}
.deathmath p { font-size: 13px; line-height: 1.55; margin-bottom: 7px; }
.deathmath p:last-child { margin-bottom: 0; }
.deathmath .bad { color: var(--blood); }
.deathmath b { font-weight: normal; color: var(--goo2); }
.deathmath b.lack, .deathmath b.bad { color: var(--blood); }

/* Open Reserves: aligned columns — [seek badge] element | totals | formula (right),
   capacity bar beneath spanning the text columns. Badge spans both rows. */
ul.reserves { display: grid; grid-template-columns: max-content max-content max-content 1fr; }
ul.reserves li.rrow { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; column-gap: 12px; align-items: center; row-gap: 4px; }
ul.reserves .rrow .elembox { grid-row: 1 / span 2; }
ul.reserves .rname { white-space: nowrap; }
ul.reserves .rtotal { font-family: var(--font-mono); white-space: nowrap; }
ul.reserves .rmath { text-align: right; }
ul.reserves .rbar { grid-column: 2 / -1; margin: 0; }
/* Over-capacity "bleeding away" now rides the material's own totals cell: the held value
   turns blood while a drain window is open, the cap stays bone, and a literal "bleeding
   out" tag appears — one fact in one place, no separate list to duplicate the rows. */
ul.reserves .rtotal .bleedtag { display: none; }
ul.reserves .rtotal.bleeding .rval { color: var(--blood); }
ul.reserves .rtotal.bleeding .bleedtag { display: inline; color: var(--blood); }
.elembox.satfull { color: var(--blood); border-color: var(--blood); background: rgba(198, 72, 95, 0.1); }
.elembox.clickable, .rvbox.clickable { cursor: pointer; }
.elembox.clickable:hover { border-color: var(--gold); }

/* GLOW chip in the Craft-of-the-kill header: visible (and clickable) even when the
   card is collapsed. Lit = shining, plain = banked; .locked (Glow I) is not a control. */
.glowbtn {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 2px;
  background: none; border: 1px solid var(--line); border-radius: 4px;
  color: var(--dim); padding: 1px 7px; cursor: pointer; vertical-align: 1px;
}
.glowbtn:hover { border-color: var(--gold); }
.glowbtn.on {
  color: var(--gold); border-color: var(--gold);
  text-shadow: 0 0 8px rgba(212, 175, 90, 0.75);
  box-shadow: 0 0 8px rgba(212, 175, 90, 0.3), inset 0 0 5px rgba(212, 175, 90, 0.12);
}
.glowbtn.locked { cursor: default; }

@media (max-width: 900px) {
  main { grid-template-columns: 1fr; }
  #logpanel { border-left: none; border-top: 1px solid var(--line); max-height: 200px; }
}
