/* lifelist.fish — "Specimen Drawer: ink, paper, and one earned foil"
   Overhaul per the design synthesis (2026-07-12). Restraint everywhere; the only
   flourish is the holographic caught-star. Depth = luminance + hairlines, never shadows. */

@font-face {
  font-family: "Fraunces"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("fonts/fraunces-latin-var.woff2") format("woff2");
}
@font-face {
  font-family: "Fraunces"; font-style: italic; font-weight: 100 900; font-display: swap;
  src: url("fonts/fraunces-latin-italic-var.woff2") format("woff2");
}
@font-face {
  font-family: "Hanken"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("fonts/hanken-latin-var.woff2") format("woff2");
}

:root {
  /* tinted-neutral ramp — no pure white/black, no cold grey */
  --canvas: #F6F1E7;
  --surface: #FBF7EE;           /* +luminance step, not a shadow */
  --sink: #EFE8D8;
  --ink: #2A2622;
  --ink-70: #5E564B;
  --ink-45: #736A57;            /* 4.75:1 on canvas — WCAG AA for the app's pervasive secondary text */
  --ink-30: #8C826A;            /* 3.38:1 — clears non-text (1.4.11) for the row chevron affordance */
  --hairline: color-mix(in oklab, var(--ink) 13%, transparent);
  --hairline-strong: color-mix(in oklab, var(--ink) 22%, transparent);
  --accent: #4E5A38;            /* default; per-species overrides inline */
  --elev: 0 10px 34px -14px color-mix(in oklab, var(--ink) 20%, transparent);

  --serif: "Fraunces", Iowan Old Style, Palatino, Georgia, serif;
  --sans: "Hanken", ui-sans-serif, system-ui, -apple-system, sans-serif;

  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-6: 24px; --sp-8: 32px; --sp-12: 48px; --sp-16: 64px;
  --r-control: 10px; --r-card: 14px; --r-pill: 999px;

  --dur-fast: 120ms; --dur: 240ms; --dur-slow: 360ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --spring: linear(0, 0.006, 0.033 2.9%, 0.126 6%, 0.298, 0.535 15.5%, 0.75 21%, 0.898, 1.006 30%, 1.049, 1.077, 1.083, 1.07, 1.04 48%, 1.007, 0.99, 0.984, 0.99, 1.001 76%, 1.005, 1.001, 0.999, 1);
  --dock-h: 66px;
  --page: 34rem;
}
:root[data-theme="sun"] { --canvas: #FCF8EC; --surface: #FFFDF5; --ink: #17130C; --ink-70: #3F3626; --ink-45: #6E6449; --hairline: color-mix(in oklab, var(--ink) 20%, transparent); }

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--canvas); color: var(--ink);
  font-family: var(--sans); font-size: calc(16px * var(--fs, 1)); line-height: 1.5;
  font-optical-sizing: auto; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
  padding-bottom: calc(var(--dock-h) + env(safe-area-inset-bottom));
}
/* one faint whole-page grain overlay — never per-card */
.grain { position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background: url("grain.png") repeat; background-size: 220px; mix-blend-mode: multiply; opacity: 0.04; }

h1, h2, h3, .serif { font-family: var(--serif); }
.eyebrow { font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-45); }
.tnum { font-variant-numeric: tabular-nums lining-nums; }

/* ---------- Masthead ---------- */
.top { position: relative; z-index: 2; display: flex; align-items: baseline; gap: var(--sp-3);
  max-width: var(--page); margin: 0 auto;
  padding: calc(env(safe-area-inset-top) + var(--sp-4)) var(--sp-4) var(--sp-2); }
.wordmark { margin: 0; font-family: var(--serif); font-size: calc(34px * var(--fs, 1)); font-weight: 520; letter-spacing: -0.02em;
  font-variation-settings: "opsz" 144, "SOFT" 15, "WONK" 1; line-height: 1; }
.wordmark .dot { color: var(--accent); }
.collection { margin-left: auto; align-self: center; font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-45); }
.sun-toggle { flex: none; width: 40px; height: 40px; border-radius: var(--r-pill); border: 1px solid var(--hairline);
  background: transparent; color: var(--ink-45); font-size: calc(15px * var(--fs, 1)); cursor: pointer; display: grid; place-items: center; }
:root[data-theme="sun"] .sun-toggle { color: var(--ink); border-color: var(--hairline-strong); }

/* progress meter — hairline, no fill-bar-as-hero */
.ribbon { position: relative; z-index: 2; max-width: var(--page); margin: 0 auto; padding: 0 var(--sp-4) var(--sp-3); display: flex; align-items: center; gap: var(--sp-3); }
.ribbon-num { font-family: var(--serif); font-size: calc(30px * var(--fs, 1)); font-weight: 500; font-variation-settings: "opsz" 96;
  font-variant-numeric: tabular-nums lining-nums; line-height: 1; }
.ribbon-num b { font-weight: 560; }
.ribbon-num span { color: var(--ink-45); }
.ribbon-meta { font-size: calc(12px * var(--fs, 1)); color: var(--ink-45); letter-spacing: 0.02em; }
.ribbon-track { flex: 1; height: 2px; background: var(--hairline); border-radius: 2px; overflow: hidden; }
.ribbon-fill { height: 100%; width: 0; background: var(--accent); transition: width var(--dur-slow) var(--ease-out); }

/* ---------- Guide ---------- */
.guide { position: relative; z-index: 2; max-width: var(--page); margin: 0 auto; padding: var(--sp-2) 0 calc(var(--sp-6) + 56px); }
.fam-head { position: sticky; top: 0; z-index: 3; display: flex; align-items: baseline; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4) var(--sp-2);
  /* fully opaque + a hairline: the gradient's transparent tail let scrolling rows ghost
     through the family name. Depth by hairline is the canon's own answer. */
  background: var(--canvas); border-bottom: 1px solid var(--hairline); }
.fam-name { font-family: var(--serif); font-size: calc(22px * var(--fs, 1)); font-weight: 480; font-variation-settings: "opsz" 60; letter-spacing: -0.01em; }
.fam-common { font-size: calc(12px * var(--fs, 1)); color: var(--ink-45); letter-spacing: 0.02em; }
.fam-count { margin-left: auto; font-size: calc(12px * var(--fs, 1)); color: var(--ink-45); font-variant-numeric: tabular-nums; }
.fam-rule { height: 1px; background: var(--hairline); margin: 0 var(--sp-4); }

.row { display: flex; align-items: center; gap: var(--sp-4); width: 100%; text-align: left; border: none;
  background: transparent; color: var(--ink); font-family: var(--sans); cursor: pointer;
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--hairline); }
.row:last-child { border-bottom: none; }
.row:active { background: color-mix(in oklab, var(--ink) 4%, transparent); }
.plate { flex: none; width: 108px; height: 72px; border-radius: var(--r-card); overflow: hidden;
  background: var(--sink); display: grid; place-items: center; position: relative; }
/* PAPER TONING (DESIGN §4). The plate set is sourced from many archives: some come on
   pure white, some near-black, some cold. Untoned they read as a photo dump, not one
   cabinet. The atlas canvas already tones its coins; this is the same treatment for the
   DOM tier — a whisper of warmth and a hair off pure saturation, enough to seat every
   plate on the same paper without muddying the good engravings. */
.plate img, .fm-plate img, .td-plate img, .detail-hero img {
  filter: sepia(0.14) saturate(0.88) contrast(0.97) brightness(0.99); }
.plate img { width: 100%; height: 100%; object-fit: contain; }
.plate.silh img { opacity: 0.9; }
/* NEVER ghost — all plates full strength; caught differ by the star + glint only */
.row-main { flex: 1; min-width: 0; }
.row-name { display: block; font-family: var(--serif); font-size: calc(19px * var(--fs, 1)); font-weight: 500; font-variation-settings: "opsz" 40; letter-spacing: -0.005em; line-height: 1.2; }
.row-latin { display: block; font-family: var(--serif); font-style: italic; font-size: calc(15px * var(--fs, 1)); color: var(--ink-45); margin-top: 1px; }
.pick-name, .pick-latin { display: block; }
.row-status { color: var(--ink-45); margin-left: 0.2rem; font-family: var(--sans); }
.row-chev { flex: none; color: var(--ink-30); }

.empty { text-align: center; color: var(--ink-45); font-style: italic; font-family: var(--serif); padding: var(--sp-12) var(--sp-4); }

/* ---------- Holographic caught-star ---------- */
@property --mx { syntax: "<number>"; inherits: true; initial-value: 50; }
@property --my { syntax: "<number>"; inherits: true; initial-value: 40; }
@property --tilt { syntax: "<number>"; inherits: true; initial-value: 0; }

/* Bespoke emblems — avatar options + the 'collected' marker. Masked by the foil layer.
   Replaces the old 4-point sparkle (too close to the Gemini star). */
:root {
  --emblem-seal: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20100%20100%27%3E%3Cpath%20d%3D%27M50.0%2C3.0%20L57.8%2C10.8%20L68.0%2C6.6%20L72.2%2C16.7%20L83.2%2C16.8%20L83.3%2C27.8%20L93.4%2C32.0%20L89.2%2C42.2%20L97.0%2C50.0%20L89.2%2C57.8%20L93.4%2C68.0%20L83.3%2C72.2%20L83.2%2C83.2%20L72.2%2C83.3%20L68.0%2C93.4%20L57.8%2C89.2%20L50.0%2C97.0%20L42.2%2C89.2%20L32.0%2C93.4%20L27.8%2C83.3%20L16.8%2C83.2%20L16.7%2C72.2%20L6.6%2C68.0%20L10.8%2C57.8%20L3.0%2C50.0%20L10.8%2C42.2%20L6.6%2C32.0%20L16.7%2C27.8%20L16.8%2C16.8%20L27.8%2C16.7%20L32.0%2C6.6%20L42.2%2C10.8%20Z%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E");
  --emblem-compass: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20100%20100%27%3E%3Cpath%20d%3D%27M50.0%2C2.0%20L54.6%2C38.9%20L71.2%2C28.8%20L61.1%2C45.4%20L98.0%2C50.0%20L61.1%2C54.6%20L71.2%2C71.2%20L54.6%2C61.1%20L50.0%2C98.0%20L45.4%2C61.1%20L28.8%2C71.2%20L38.9%2C54.6%20L2.0%2C50.0%20L38.9%2C45.4%20L28.8%2C28.8%20L45.4%2C38.9%20Z%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E");
  --emblem-star: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20100%20100%27%3E%3Cpath%20d%3D%27M50.0%2C2.0%20L61.8%2C33.8%20L95.7%2C35.2%20L69.0%2C56.2%20L78.2%2C88.8%20L50.0%2C70.0%20L21.8%2C88.8%20L31.0%2C56.2%20L4.3%2C35.2%20L38.2%2C33.8%20Z%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E");
  --emblem-hook: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20100%20100%27%3E%3Cpath%20d%3D%27M62%2014%20a6%206%200%201%201%20-0.1%200%20M60%2022%20v30%20a18%2018%200%201%201%20-30%2013%20l7%20-5%20a10%2010%200%201%200%2015%20-8%20V22%20z%20M35%2063%20l-9%205%20l11%204%20z%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E");
  --emblem-fish: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20100%20100%27%3E%3Cpath%20d%3D%27M91%2050%20C80%2037%2050%2034%2033%2047%20L14%2039%20L21%2050%20L14%2061%20L33%2053%20C50%2066%2080%2063%2091%2050%20Z%20M74%2047%20a3%203%200%201%201%20-0.1%200%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E");
  --star: var(--emblem-seal);   /* default 'collected' marker */
}
.star-badge { position: absolute; display: block; pointer-events: none; --mx: 50; --my: 40; --tilt: 0; }
.star-badge .layer { position: absolute; inset: 0;
  -webkit-mask: var(--star) center/contain no-repeat; mask: var(--star) center/contain no-repeat; }
.star-badge .ink { background: var(--ink); opacity: 0.9; }
.star-badge .foil {
  background:
    repeating-linear-gradient(115deg, transparent 0 6%, oklch(0.86 0.14 20) 8%, oklch(0.83 0.15 140) 10%, oklch(0.86 0.14 260) 12%, transparent 14% 20%),
    conic-gradient(from calc(var(--tilt) * 1deg), oklch(0.82 0.13 30), oklch(0.8 0.14 150), oklch(0.82 0.13 270), oklch(0.82 0.13 30));
  background-blend-mode: color-dodge; background-size: 300% 300%;
  background-position: calc(var(--mx) * 1%) calc(var(--my) * 1%);
  mix-blend-mode: color-dodge; filter: brightness(0.85) contrast(1.4) saturate(1.3);
  opacity: 0.9;
}
.star-badge .glare {
  background: radial-gradient(circle at calc(var(--mx) * 1%) calc(var(--my) * 1%), oklch(1 0 0/.85) 0%, oklch(1 0 0/.12) 26%, transparent 56%);
  mix-blend-mode: overlay;
}
@keyframes idleFoil { from { --mx: 34; --my: 30; } to { --mx: 66; --my: 58; } }
.star-badge.live .foil { animation: idleFoil 9s ease-in-out infinite alternate; }
@keyframes starBloom { 0% { transform: scale(0.2); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
.star-badge.bloom { animation: starBloom var(--dur-slow) var(--spring) both; }
/* list-card star */
.row .star-badge { width: 26px; height: 26px; right: 6px; top: 6px; }
/* detail-hero star */
.detail-hero .star-badge { width: 46px; height: 46px; right: 16px; top: 16px; }

/* ---------- Bottom search ---------- */
.searchbar { position: fixed; z-index: 5; left: 0; right: 0; bottom: calc(var(--dock-h) + env(safe-area-inset-bottom));
  padding: var(--sp-2) var(--sp-4); background: linear-gradient(0deg, var(--canvas) 72%, transparent); }
.searchbar input { display: block; width: 100%; max-width: var(--page); margin: 0 auto; font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); color: var(--ink);
  background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-pill); padding: 10px 18px; outline: none; }
.searchbar input::placeholder { color: var(--ink-45); font-style: italic; }
.searchbar input:focus { border-color: var(--accent); }

/* ---------- Dock ---------- */
.dock { position: fixed; z-index: 7; left: 0; right: 0; bottom: 0;
  height: calc(var(--dock-h) + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom);
  display: grid; grid-template-columns: 1fr 1fr 82px 1fr 1fr; align-items: center; justify-items: center;
  background: var(--surface); border-top: 1px solid var(--hairline); }
.dock button { border: none; background: transparent; cursor: pointer; font-family: var(--sans); font-size: calc(10px * var(--fs, 1));
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-45); display: flex; flex-direction: column;
  align-items: center; gap: 3px; padding: 8px 6px; min-height: 48px; justify-content: center; }
.dock button .ic { width: 22px; height: 22px; }
.dock button.active { color: var(--ink); }
.dock-log { grid-column: 3; width: 62px; height: 62px; border-radius: var(--r-pill) !important;
  background: var(--ink) !important; color: var(--canvas) !important; font-size: calc(11px * var(--fs, 1)) !important; font-weight: 600;
  letter-spacing: 0.12em; transform: translateY(-14px); border: 4px solid var(--canvas) !important; }
.dock-log:active { transform: translateY(-11px) scale(0.97); }

/* ---------- Specimen detail ---------- */
.detail { position: fixed; inset: 0; z-index: 15; background: var(--canvas); overflow-y: auto;
  -webkit-overflow-scrolling: touch; padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
.detail.dragging { overflow: hidden; }
.detail-sheet { will-change: transform; }
.detail-grab { width: 38px; height: 5px; border-radius: 3px; background: var(--hairline-strong);
  margin: calc(env(safe-area-inset-top) + 8px) auto 0; }
/* A specimen page opens with its IDENTITY, the way a museum label heads its case —
   name and binomial above the plate, so nothing important starts mid-screen. */
.detail-head { max-width: var(--page); margin: 0 auto; padding: var(--sp-2) var(--sp-4) 0; }
.detail-head .detail-name { margin: 2px 0 0; }
/* 3:2 matches the plates' own ratio, so `contain` produces no letterbox bands — the old
   fixed height left two near-equal beiges meeting on a hard edge, reading as a seam. */
.detail-hero { position: relative; margin: var(--sp-3) auto 0; width: calc(100% - 2 * var(--sp-4)); max-width: var(--page);
  aspect-ratio: 3 / 2; max-height: 42vh;
  border-radius: var(--r-card); overflow: hidden; background: var(--sink); display: grid; place-items: center; }
.detail-hero::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 44%, transparent 60%, color-mix(in oklab, var(--ink) 8%, transparent)); }
.detail-hero img { width: 100%; height: 100%; object-fit: contain; }
.plate-forthcoming { position: absolute; bottom: 10px; right: 12px; z-index: 2; font-family: var(--sans);
  font-size: calc(10px * var(--fs, 1)); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-45); }
/* Tap the plate to open the full-screen zoomable view — a discoverable magnifier corner. */
.detail-hero.zoomable { cursor: zoom-in; }
.detail-hero.zoomable::before { content: ""; position: absolute; z-index: 3; right: 12px; bottom: 12px; width: 34px; height: 34px;
  border-radius: var(--r-pill); background: color-mix(in oklab, var(--canvas) 82%, transparent); border: 1px solid var(--hairline);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23736A57' stroke-width='1.75'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='M16 16l4.5 4.5M11 8.5v5M8.5 11h5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: center; background-size: 18px; }
.zoomable-img { cursor: zoom-in; }

/* The image lightbox — full-screen, pinch / scroll / double-tap to zoom, drag to pan. */
.lightbox { position: fixed; inset: 0; z-index: 30; display: grid; place-items: center; overflow: hidden;
  background: color-mix(in oklab, var(--ink) 90%, transparent); touch-action: none; }
.lightbox[hidden] { display: none; }
.lightbox img { max-width: 100vw; max-height: 100vh; width: auto; height: auto; object-fit: contain;
  transform-origin: center center; will-change: transform; user-select: none; -webkit-user-drag: none; }
.lightbox-close { position: fixed; top: calc(env(safe-area-inset-top) + 10px); right: 14px; width: 44px; height: 44px;
  border-radius: var(--r-pill); border: 1px solid color-mix(in oklab, var(--canvas) 40%, transparent);
  background: color-mix(in oklab, var(--ink) 40%, transparent); color: var(--canvas); font-size: 24px; line-height: 1; cursor: pointer; }
.lightbox-zoom { position: fixed; top: calc(env(safe-area-inset-top) + 10px); left: 14px; display: flex; gap: 8px; }
.lightbox-zoom button { width: 44px; height: 44px; border-radius: var(--r-pill);
  border: 1px solid color-mix(in oklab, var(--canvas) 40%, transparent);
  background: color-mix(in oklab, var(--ink) 40%, transparent); color: var(--canvas);
  font-size: calc(20px * var(--fs, 1)); line-height: 1; cursor: pointer; }
.lightbox-hint { position: fixed; bottom: calc(env(safe-area-inset-bottom) + 18px); left: 50%; transform: translateX(-50%);
  font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); letter-spacing: 0.06em; text-transform: uppercase;
  color: color-mix(in oklab, var(--canvas) 70%, transparent); opacity: 0; transition: opacity 0.4s; pointer-events: none; }
.lightbox-hint.show { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .lightbox-hint { transition: none; } }

/* per-plate credit — a museum-caption whisper, not a disclaimer. Full statement lives on the
   credits page; this keeps attribution at the point of use without stealing the hero's stage. */
.plate-credit { max-width: var(--page); margin: 6px auto 0; padding: 0 var(--sp-4);
  font-family: var(--serif); font-style: italic; font-size: calc(12px * var(--fs, 1)); line-height: 1.45;
  color: var(--ink-45); text-align: right; }   /* no opacity: --ink-45 IS the AA floor; dimming it broke 4.5:1 */
.plate-credit a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--hairline); }
.plate-credit a:hover { color: var(--ink); border-bottom-color: var(--hairline-strong); }

.detail-body { max-width: var(--page); margin: 0 auto; padding: var(--sp-6) var(--sp-4) 0; }
.detail-eyebrow { margin: 0 0 var(--sp-2); }
.detail-name { font-family: var(--serif); font-size: calc(32px * var(--fs, 1)); font-weight: 480; font-variation-settings: "opsz" 110, "SOFT" 20;
  letter-spacing: -0.015em; line-height: 1.06; margin: 0; }
.detail-latin { font-family: var(--serif); font-style: italic; font-size: calc(17px * var(--fs, 1)); color: var(--ink-45); margin: var(--sp-1) 0 0; }
.accent-rule { height: 2px; width: 46px; border-radius: 2px; background: var(--accent); margin: var(--sp-3) 0 var(--sp-6); }

/* rarity meter */
.rarity { margin: var(--sp-6) 0; }
.rarity-head { position: relative; height: 30px; margin-bottom: var(--sp-2); }
.rarity-pill { position: absolute; transform: translateX(-50%); top: 0; display: flex; flex-direction: column; align-items: center; }
.rarity-code { font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); font-weight: 700; letter-spacing: 0.06em; color: var(--rc, var(--ink)); }
.rarity-caret { width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent;
  border-top: 6px solid var(--rc, var(--ink)); margin-top: 3px; }
.rarity-track { display: flex; gap: 3px; }
.rarity-track span { flex: 1; height: 8px; border-radius: 4px; background: color-mix(in oklab, var(--ink) 10%, transparent); }
.rarity-def { margin: var(--sp-3) 0 0; font-family: var(--serif); font-style: italic; font-size: calc(15px * var(--fs, 1)); color: var(--ink-70); }
.rarity-off { font-family: var(--serif); font-style: italic; color: var(--ink-45); font-size: calc(15px * var(--fs, 1)); }

/* stat row */
.stat-row { display: flex; gap: var(--sp-4); margin: var(--sp-6) 0; }
.stat { flex: 1; padding-left: var(--sp-4); border-left: 1px solid var(--hairline); }
.stat:first-child { padding-left: 0; border-left: none; }
.stat-k { display: block; font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-45); margin-bottom: 3px; }
.stat-v { font-family: var(--serif); font-size: calc(17px * var(--fs, 1)); }

.detail-desc { font-family: var(--sans); font-size: calc(16px * var(--fs, 1)); line-height: 1.6; color: var(--ink); margin: var(--sp-6) 0; max-width: 34em; }

.fieldnote { position: relative; padding-left: var(--sp-4); margin: var(--sp-6) 0; border-left: 2px solid var(--accent); }
.fieldnote-k { font-family: var(--sans); font-size: calc(10px * var(--fs, 1)); font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-45); }
.fieldnote-t { font-family: var(--serif); font-style: italic; font-size: calc(18px * var(--fs, 1)); line-height: 1.45; color: var(--ink); margin: var(--sp-2) 0 0; }

.detail-sec { margin: var(--sp-8) 0 0; }
.detail-sec h3 { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-45); margin: 0 0 var(--sp-3); }
.enc { display: flex; gap: var(--sp-3); padding: var(--sp-3) 0; border-bottom: 1px solid var(--hairline); }
.enc img { width: 68px; height: 68px; object-fit: cover; border-radius: var(--r-control); flex: none; background: var(--sink); }
.enc-date { font-family: var(--serif); font-size: calc(17px * var(--fs, 1)); }
.enc-place { color: var(--ink-45); font-size: calc(14px * var(--fs, 1)); }
.enc-story { margin: var(--sp-1) 0 0; font-size: calc(15px * var(--fs, 1)); }
.enc-del { border: none; background: transparent; color: var(--ink-45); text-decoration: underline; font-size: calc(12px * var(--fs, 1)); cursor: pointer; padding: 8px 0; min-height: 44px; display: inline-flex; align-items: center; }
.enc-del.armed { color: var(--ink); font-weight: 600; }
.no-enc { font-family: var(--serif); font-style: italic; color: var(--ink-45); }

.lineage { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-6) 0 0; }
.chip { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-70); border: 1px solid var(--hairline); border-radius: var(--r-pill); padding: 5px 12px; cursor: pointer; background: transparent; }

/* fixed thumb-zone action bar (dismiss + primary action); swipe-down also dismisses */
.detail-actions { position: fixed; z-index: 16; left: 0; right: 0; bottom: 0;
  display: flex; gap: var(--sp-2); align-items: center; max-width: var(--page); margin: 0 auto;
  padding: var(--sp-2) var(--sp-4) calc(env(safe-area-inset-bottom) + var(--sp-2));
  background: linear-gradient(0deg, var(--canvas) 70%, transparent); }
.da-close { flex: none; min-height: 48px; padding: 0 18px; border-radius: var(--r-control);
  border: 1px solid var(--hairline-strong); background: var(--surface); color: var(--ink);
  font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.04em; cursor: pointer; }
.da-share { flex: none; min-height: 48px; padding: 0 15px; border-radius: var(--r-control); display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--hairline-strong); background: var(--surface); color: var(--ink);
  font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.04em; cursor: pointer; }
.da-share svg { flex: none; }
.da-log { flex: 1; min-height: 48px; border: none; border-radius: var(--r-control);
  background: var(--ink); color: var(--canvas); font-family: var(--sans); font-size: calc(14px * var(--fs, 1)); font-weight: 600;
  letter-spacing: 0.06em; cursor: pointer; }
.da-log:active { transform: scale(0.99); }

/* ---------- Simple screens ---------- */
.screen { position: relative; z-index: 2; max-width: var(--page); margin: 0 auto; padding: var(--sp-4) var(--sp-4) var(--sp-12); }
.screen h2 { font-family: var(--serif); font-size: calc(26px * var(--fs, 1)); font-weight: 460; font-variation-settings: "opsz" 72; margin: var(--sp-2) 0; }
.screen p { color: var(--ink-70); }
.big-btn { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; margin-top: var(--sp-4); border: 1px solid var(--hairline-strong); background: var(--surface);
  color: var(--ink); border-radius: var(--r-control); padding: 12px 18px; font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); font-weight: 600;
  letter-spacing: 0.04em; cursor: pointer; }

/* ---------- Quick-log sheet ---------- */
.scrim { position: fixed; inset: 0; z-index: 20; background: color-mix(in oklab, var(--ink) 42%, transparent); opacity: 0; transition: opacity var(--dur) ease; }
.scrim.on { opacity: 1; }
.sheet { position: fixed; z-index: 21; left: 0; right: 0; bottom: 0; max-height: 92vh; background: var(--surface);
  border-radius: 22px 22px 0 0; box-shadow: var(--elev); transform: translateY(100%);
  padding-bottom: env(safe-area-inset-bottom); overflow: hidden; display: flex; flex-direction: column; }
.sheet.on { transform: translateY(0); transition: transform var(--dur) var(--spring); }
.sheet.drag { transition: none; will-change: transform; }
.sheet-grab { width: 38px; height: 5px; background: var(--hairline-strong); border-radius: 3px; margin: 10px auto 4px; flex: none; }
.sheet-head { display: flex; align-items: center; gap: var(--sp-2); padding: 6px var(--sp-4); }
.sheet-title { font-family: var(--sans); text-transform: uppercase; letter-spacing: 0.1em; font-size: calc(12px * var(--fs, 1)); font-weight: 700; color: var(--ink-45); }
.sheet-close { margin-left: auto; border: 1px solid var(--hairline); background: transparent; color: var(--ink-45);
  width: 44px; height: 44px; border-radius: var(--r-pill); font-size: calc(18px * var(--fs, 1)); cursor: pointer; }
.sheet-body { overflow-y: auto; padding: var(--sp-2) var(--sp-4) var(--sp-4); }

.pick-search-wrap { padding: 0 var(--sp-4); }
.pick-search { width: 100%; font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); color: var(--ink); background: var(--canvas);
  border: 1px solid var(--hairline); border-radius: var(--r-control); padding: 11px 13px; outline: none; }
.pick-search::placeholder { color: var(--ink-45); font-style: italic; }
.pick-search:focus { border-color: var(--accent); }
.pick { display: flex; align-items: center; gap: var(--sp-3); width: 100%; text-align: left; border: none; background: transparent;
  color: var(--ink); font-family: var(--sans); padding: var(--sp-2) 0; border-bottom: 1px solid var(--hairline); cursor: pointer; }
.pick .plate { position: relative; }
.pick .star-badge { width: 20px; height: 20px; right: 4px; top: 4px; }
.pick .plate { width: 64px; height: 43px; }
.pick-name { font-family: var(--serif); font-size: calc(17px * var(--fs, 1)); }
.pick-latin { font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); }

.log-hero { display: flex; align-items: center; gap: var(--sp-3); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--hairline); margin-bottom: var(--sp-3); }
.log-hero .plate { width: 96px; height: 64px; }
.log-hero-name { font-family: var(--serif); font-size: calc(20px * var(--fs, 1)); font-weight: 500; }
.log-hero-latin { font-family: var(--serif); font-style: italic; font-size: calc(14px * var(--fs, 1)); color: var(--ink-45); }
.log-back { border: none; background: transparent; color: var(--ink-45); font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); letter-spacing: 0.04em; cursor: pointer; padding: 4px 0; min-height: 44px; display: inline-flex; align-items: center; }
.field { margin-bottom: var(--sp-3); }
.field label { display: block; font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-45); margin-bottom: 5px; }
.field input, .field textarea { width: 100%; font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); color: var(--ink); background: var(--canvas);
  border: 1px solid var(--hairline); border-radius: var(--r-control); padding: 11px 13px; outline: none; }
.field input:focus, .field textarea:focus { border-color: var(--accent); }
.field textarea { resize: vertical; min-height: 3rem; }
.row2 { display: flex; gap: var(--sp-2); }
.row2 .field { flex: 1; }
.photo-drop { display: grid; place-items: center; min-height: 88px; border: 1.5px dashed var(--hairline-strong); border-radius: var(--r-card);
  color: var(--ink-45); cursor: pointer; overflow: hidden; font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); letter-spacing: 0.04em; }
.photo-drop img { width: 100%; max-height: 12rem; object-fit: cover; }
.photo-drop input { display: none; }
.log-commit { width: 100%; height: 56px; margin-top: var(--sp-2); border: none; border-radius: var(--r-control); background: var(--ink);
  color: var(--canvas); font-family: var(--sans); font-size: calc(14px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.08em; cursor: pointer; }
.log-commit:active { transform: scale(0.98); }

/* ---------- Toast ---------- */
.toast { position: fixed; z-index: 30; left: 50%; bottom: calc(var(--dock-h) + 78px); transform: translateX(-50%) translateY(14px);
  opacity: 0; display: flex; align-items: center; gap: var(--sp-3); background: var(--ink); color: var(--canvas);
  border-radius: var(--r-control); padding: 10px 16px; box-shadow: var(--elev); transition: opacity 200ms ease, transform var(--dur) var(--ease-out); max-width: 88vw; }
.toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast img { width: 34px; height: 34px; border-radius: 6px; object-fit: contain; background: var(--sink); }
.toast b { display: block; font-family: var(--serif); font-size: calc(15px * var(--fs, 1)); }
.toast span { font-family: var(--sans); font-size: calc(10px * var(--fs, 1)); letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.75; }

/* ---------- Atlas (HUD refresh; canvas unchanged) ---------- */
/* host ends above the dock so the camera math frames only the VISIBLE viewport — nothing hides under the bar */
.atlas { position: fixed; inset: 0; bottom: calc(var(--dock-h) + env(safe-area-inset-bottom)); z-index: 2; overflow: hidden; background: var(--canvas); }
.atlas canvas { position: absolute; inset: 0; display: block; }
.atlas-sheen { position: absolute; inset: 0; z-index: 2; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(120% 80% at 50% 40%, oklch(1 0 0/.28), transparent 60%); }
.atlas-hud { position: absolute; z-index: 3; left: 0; right: 0; top: calc(env(safe-area-inset-top) + var(--sp-2)); padding: 0 var(--sp-3); display: flex; align-items: flex-start; gap: var(--sp-2); pointer-events: none; }
.atlas-hint { position: absolute; z-index: 4; left: 50%; bottom: calc(var(--dock-h) + 24px); transform: translateX(-50%);
  pointer-events: none; font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); letter-spacing: 0.04em;
  color: var(--ink-70); background: color-mix(in oklab, var(--surface) 88%, transparent); border: 1px solid var(--hairline);
  border-radius: var(--r-pill); padding: 7px 15px; -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  opacity: 0; transition: opacity 0.4s ease; }
.atlas-hint.show { opacity: 1; }
.atlas-hint[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .atlas-hint { transition: none; } }
.atlas-crumb { font-family: var(--sans); text-transform: uppercase; letter-spacing: 0.12em; font-size: calc(11px * var(--fs, 1)); font-weight: 700;
  color: var(--ink-70); background: color-mix(in oklab, var(--canvas) 72%, transparent); backdrop-filter: blur(3px); padding: 6px 11px; border-radius: var(--r-pill); }
.atlas-hud-btns { margin-left: auto; display: flex; gap: var(--sp-2); pointer-events: auto; }
.atlas-hud-btns button { width: 40px; height: 40px; border-radius: var(--r-pill); border: 1px solid var(--hairline); background: color-mix(in oklab, var(--canvas) 82%, transparent); color: var(--ink); cursor: pointer; display: grid; place-items: center; backdrop-filter: blur(3px); }
.atlas-hud-btns button svg { width: 18px; height: 18px; }
.atlas-searchbar { position: absolute; z-index: 4; left: 50%; transform: translateX(-50%); bottom: 12px;   /* host already ends above the dock */
  width: min(28rem, 92vw); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-card); box-shadow: var(--elev); padding: 10px; pointer-events: auto; }
.atlas-searchbar input { width: 100%; font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); color: var(--ink); background: var(--canvas); border: 1px solid var(--hairline); border-radius: var(--r-control); padding: 10px 13px; outline: none; }
.atlas-results { max-height: 40vh; overflow-y: auto; margin-top: 6px; }
.atlas-results button { display: flex; align-items: center; width: 100%; min-height: 44px; text-align: left; border: none; background: transparent; color: var(--ink); font-family: var(--serif); padding: 8px 8px; cursor: pointer; border-bottom: 1px solid var(--hairline); font-size: calc(15px * var(--fs, 1)); }
.atlas-results i { color: var(--ink-45); }

.credits { margin-top: var(--sp-4); border-top: 1px solid var(--hairline); padding-top: var(--sp-3); }
.credits summary { font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-45); cursor: pointer; }
.credits > p { font-size: calc(13px * var(--fs, 1)); color: var(--ink-70); margin: var(--sp-2) 0; }
.credit-list { list-style: none; padding: 0; margin: var(--sp-2) 0 0; columns: 1; }
.credit-list li { font-size: calc(12px * var(--fs, 1)); color: var(--ink-70); padding: 3px 0; border-bottom: 1px solid var(--hairline); }
.credit-list a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--hairline-strong); }
.credit-list .cl { color: var(--ink-45); }
.credit-list .cl a { color: var(--ink-45); border-bottom: 1px solid var(--hairline); }
.credit-foot { font-size: calc(12px * var(--fs, 1)); color: var(--ink-45); margin-top: var(--sp-3); font-style: italic; }

[hidden] { display: none !important; }

/* pause the holographic foil shimmer when the tab/app is backgrounded (saves the blend-mode repaint) */
.bg-hidden .star-badge.live .foil { animation-play-state: paused; }

/* stack the specimen stats on narrow phones so long habitat text wraps to ~2 lines instead of ~8 */
@media (max-width: 460px) {
  .stat-row { flex-direction: column; gap: 0; }
  .stat, .stat:first-child { padding: var(--sp-3) 0 0; margin-top: var(--sp-3); border-left: none; border-top: 1px solid var(--hairline); }
  .stat:first-child { margin-top: 0; padding-top: 0; border-top: none; }
}

/* ---------- Angler Profile (see DESIGN.md §8) ---------- */
.pf-head { display: flex; align-items: flex-start; gap: var(--sp-4); flex-wrap: wrap; margin-top: var(--sp-2); }
.pf-sigil { flex: none; position: relative; width: 56px; height: 56px; border: none; background: transparent; padding: 0; cursor: pointer; border-radius: var(--r-pill); }
.pf-sigil .star-badge { position: relative; display: block; width: 100%; height: 100%; }
.pf-sigil::after { content: ""; position: absolute; right: -2px; bottom: -2px; width: 16px; height: 16px; border-radius: var(--r-pill);
  background: var(--surface) center/9px no-repeat; border: 1px solid var(--hairline);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23736A57' stroke-width='2.4'%3E%3Cpath d='M6 12h12M12 6v12'/%3E%3C/svg%3E"); }
/* Avatar emblem picker — revealed by tapping the sigil */
.avatar-picker { margin: var(--sp-2) 0 var(--sp-3); padding: var(--sp-3) var(--sp-4); background: var(--surface);
  border: 1px solid var(--hairline); border-radius: var(--r-card); }
.avatar-picker[hidden] { display: none; }
.avatar-picker .eyebrow { display: block; margin-bottom: var(--sp-2); }
.ap-row { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.ap-swatch { position: relative; width: 44px; height: 44px; flex: none; border-radius: var(--r-pill); cursor: pointer;
  border: 1px solid var(--hairline); background: var(--canvas); padding: 7px; }
.ap-swatch .star-badge { position: relative; display: block; width: 100%; height: 100%; }
.ap-swatch.on { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.pf-id { flex: 1; min-width: 220px; }
.pf-name { margin: 2px 0 4px; font-family: var(--serif); font-size: calc(30px * var(--fs, 1)); font-weight: 490; font-variation-settings: "opsz" 96, "SOFT" 18;
  letter-spacing: -0.01em; line-height: 1.1; outline: none; border-bottom: 1px dashed var(--hairline-strong); display: inline-block; min-width: 3ch; }
.pf-name:focus { border-bottom-style: solid; border-bottom-color: var(--accent); }
.pf-rank { font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); color: var(--ink-70); }
.pf-rank-n { font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
.pf-pts { color: var(--ink-45); margin-left: var(--sp-2); }
.pf-rankbar { height: 2px; background: var(--hairline); border-radius: 2px; overflow: hidden; margin-top: 7px; }
.pf-rankbar i { display: block; height: 100%; background: var(--accent); transition: width var(--dur-slow) var(--ease-out); }
.pf-next { margin: 6px 0 0; font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); }
.pf-switch { margin: 8px 0 0; padding: 4px 0; border: none; background: none; cursor: pointer;
  min-height: 40px; display: inline-flex; align-items: center;
  font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); color: var(--ink-45); letter-spacing: 0.02em; }
.pf-switch u { text-underline-offset: 2px; text-decoration-color: var(--hairline-strong); }
.pf-switch:hover { color: var(--ink); }
.pf-prof-list { display: flex; flex-direction: column; gap: var(--sp-2); margin: var(--sp-3) 0; }
.pf-prof { margin: 0; text-align: left; }
.pf-prof.on { border-color: var(--accent); color: var(--ink); }

/* GPS is an explicit choice, never a silent capture (privacy posture, ADR-001) */
.geo-chip { display: inline-flex; align-items: center; gap: 7px; margin: 0 0 var(--sp-3); padding: 8px 13px; min-height: 44px;
  border: 1px solid var(--hairline); border-radius: var(--r-pill); background: transparent; cursor: pointer;
  font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.03em; color: var(--ink-45); }
.geo-chip[aria-pressed="true"] { border-color: var(--accent); color: var(--ink); background: var(--canvas); }
.geo-chip svg { width: 14px; height: 14px; }
/* The Spoken Entry mic (SPEC §7.12) — a quiet, elder-facing affordance in the log
   sheet; the "on" state is a hushed accent, no confetti. */
.mic-btn { display: inline-flex; align-items: center; gap: 8px; width: 100%; justify-content: center;
  min-height: 44px; margin: 0 0 var(--sp-3); padding: 10px 14px;
  border: 1px solid var(--hairline); border-radius: var(--r-pill); background: transparent; cursor: pointer;
  font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.03em; color: var(--ink-45); }
.mic-btn svg { width: 17px; height: 17px; }
.mic-btn[aria-pressed="true"] { border-color: var(--accent); color: var(--ink); background: var(--canvas); }
.mic-btn.on svg { animation: mic-pulse 1.6s ease-in-out infinite; }
@keyframes mic-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) { .mic-btn.on svg { animation: none; } }
.pf-share { margin: 0; align-self: flex-start; }

.pf-heroes { display: flex; margin: var(--sp-6) 0; }
.pf-heroes div { flex: 1; padding-left: var(--sp-4); border-left: 1px solid var(--hairline); }
.pf-heroes div:first-child { padding-left: 0; border-left: none; }
.pf-heroes b { display: block; font-family: var(--serif); font-size: calc(34px * var(--fs, 1)); font-weight: 520; font-variation-settings: "opsz" 96; line-height: 1.05; }
.pf-heroes span { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-45); }

.pf-sec { margin-top: var(--sp-8); }
.pf-sec h3 { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-45); margin: 0 0 var(--sp-3); display: flex; align-items: baseline; gap: var(--sp-3); }
.pf-cnt { margin-left: auto; font-weight: 600; color: var(--ink-45); letter-spacing: 0.03em; }
.pf-sub { margin: calc(-1 * var(--sp-2)) 0 var(--sp-3); font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); }
.pf-empty { font-family: var(--serif); font-style: italic; color: var(--ink-45); }

/* medal drawer — canonical fixed order, hex seals; onyx alone earns the foil */
.medals { display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 10px; }
.medal { position: relative; padding: 0; border: none; background: transparent; cursor: pointer; aspect-ratio: 0.9; }
.medal-in { position: absolute; inset: 0; clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; overflow: hidden; }
.medal-ic { width: 46%; aspect-ratio: 1; position: relative; z-index: 2; }
.medal-ic svg { width: 100%; height: 100%; }
.pips { display: flex; gap: 3px; position: relative; z-index: 2; }
.pips i { width: 4px; height: 4px; border-radius: 50%; background: currentColor; opacity: 0.28; }
.pips i.on { opacity: 0.95; }
.medal.locked .medal-in, .pf-pop-medal.locked .medal-in { background: color-mix(in oklab, var(--ink) 5%, transparent); outline: 1px solid var(--hairline); outline-offset: -1px; color: var(--ink-30); }
.medal.t0 .medal-in, .pf-pop-medal.t0 .medal-in { background: linear-gradient(160deg, #C98F5B, #8E5C33 58%, #B27947); color: #FBF3E4; }
.medal.t1 .medal-in, .pf-pop-medal.t1 .medal-in { background: linear-gradient(160deg, #DDD8CC, #9E998D 58%, #C9C4B7); color: #2A2622; }
.medal.t2 .medal-in, .pf-pop-medal.t2 .medal-in { background: linear-gradient(160deg, #E8C568, #A97F2B 58%, #D9B254); color: #2A2622; }
.medal.t3 .medal-in, .pf-pop-medal.t3 .medal-in { background: linear-gradient(160deg, #322C24, #120F0B 60%, #221E19); color: #F6F1E7; }
.medal-foil { position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    repeating-linear-gradient(115deg, transparent 0 6%, oklch(0.86 0.14 20) 8%, oklch(0.83 0.15 140) 10%, oklch(0.86 0.14 260) 12%, transparent 14% 20%),
    conic-gradient(from calc(var(--tilt) * 1deg), oklch(0.82 0.13 30), oklch(0.8 0.14 150), oklch(0.82 0.13 270), oklch(0.82 0.13 30));
  background-blend-mode: color-dodge; background-size: 300% 300%;
  background-position: calc(var(--mx) * 1%) calc(var(--my) * 1%);
  mix-blend-mode: color-dodge; opacity: 0.5; filter: saturate(1.25) brightness(0.9);
  animation: idleFoil 11s ease-in-out infinite alternate;
}
.bg-hidden .medal-foil { animation-play-state: paused; }
.medal:active { transform: scale(0.96); }

/* the catch record — chronological, immutable */
.mdl-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; }
.mdl { aspect-ratio: 1; border-radius: 50%; overflow: hidden; padding: 0; cursor: pointer;
  border: 1px solid var(--hairline-strong); background: var(--sink); }
.mdl img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mdl:active { transform: scale(0.95); }

/* ledger */
.pf-ledger .eyebrow { margin: var(--sp-4) 0 var(--sp-1); }
.pf-ledger div { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3);
  padding: 7px 0; border-bottom: 1px solid var(--hairline); font-size: calc(14px * var(--fs, 1)); color: var(--ink-70); }
.pf-ledger b { font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); font-weight: 540; color: var(--ink); }
.pf-archive { margin-top: var(--sp-8); }

/* profile popover — focus-managed floating card */
.pf-scrim { position: fixed; inset: 0; z-index: 59; background: color-mix(in oklab, var(--ink) 42%, transparent); opacity: 0; transition: opacity 200ms ease; pointer-events: none; }
.on > .pf-scrim { pointer-events: auto; }   /* the fading-out scrim must never eat taps */
.pf-pop { position: fixed; z-index: 60; left: 50%; top: 50%; transform: translate(-50%, -46%) scale(0.97); opacity: 0;
  transition: opacity 200ms ease, transform 220ms var(--ease-out);
  width: min(26rem, 92vw); max-height: 84vh; overflow-y: auto; background: var(--surface);
  border: 1px solid var(--hairline-strong); border-radius: var(--r-card); padding: var(--sp-6); box-shadow: var(--elev); }
.on > .pf-scrim { opacity: 1; }
.on > .pf-pop { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.pf-pop-x { position: absolute; top: 10px; right: 10px; width: 40px; height: 40px; border-radius: var(--r-pill);
  border: 1px solid var(--hairline); background: transparent; color: var(--ink-45); font-size: calc(18px * var(--fs, 1)); cursor: pointer; z-index: 2; }
.pf-pop-medal { position: relative; width: 96px; aspect-ratio: 0.9; margin-bottom: var(--sp-3); }
.pf-pop-medal .medal-in { border-radius: 0; }
.pf-pop-name { margin: 2px 0 2px; font-family: var(--serif); font-size: calc(24px * var(--fs, 1)); font-weight: 500; }
.pf-pop-latin { margin: 0 0 var(--sp-3); font-family: var(--serif); font-style: italic; font-size: calc(15px * var(--fs, 1)); color: var(--ink-45); }
.pf-pop-desc { margin: 0 0 var(--sp-3); font-size: calc(14px * var(--fs, 1)); color: var(--ink-70); }
.pf-pop-prog { font-family: var(--serif); font-size: calc(18px * var(--fs, 1)); margin-bottom: var(--sp-2); }
.pf-pop-prog span { font-family: var(--sans); font-size: calc(12px * var(--fs, 1)); color: var(--ink-45); text-transform: uppercase; letter-spacing: 0.05em; }
.pf-pop-nxt { color: var(--ink-45); }
.pf-pop-tiers { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-3); }
.pf-pop-tiers span { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); letter-spacing: 0.04em; color: var(--ink-45);
  border: 1px solid var(--hairline); border-radius: var(--r-pill); padding: 3px 10px; }
.pf-pop-tiers span.on { color: var(--ink); border-color: var(--hairline-strong); background: var(--canvas); }
.pf-pop-fish { width: calc(100% + 2 * var(--sp-6)); margin: calc(-1 * var(--sp-6)) calc(-1 * var(--sp-6)) var(--sp-4);
  height: 200px; background: var(--sink); display: grid; place-items: center; }
.pf-pop-fish img { width: 100%; height: 100%; object-fit: contain; }
.pf-pop-encs { margin: var(--sp-2) 0 var(--sp-4); }
.pf-enc { display: flex; gap: var(--sp-3); padding: var(--sp-3) 0; border-bottom: 1px solid var(--hairline); font-size: calc(14px * var(--fs, 1)); color: var(--ink-70); }
.pf-enc b { font-family: var(--serif); color: var(--ink); font-weight: 540; }
.pf-enc-place { display: block; color: var(--ink-45); }
.pf-enc-story { margin: 4px 0 0; font-size: calc(13.5px * var(--fs, 1)); }
.pf-enc-photo { flex: none; width: 64px; height: 64px; border-radius: var(--r-control); object-fit: cover; background: var(--sink); }

@media (min-width: 840px) {
  .medals { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 12px; }
  .mdl-grid { grid-template-columns: repeat(10, 1fr); }
  .pf-heroes b { font-size: calc(44px * var(--fs, 1)); }
}

/* ---------- Device-native presentation ----------
   Same specimen drawer, laid out for the machine it's on. Mobile keeps the
   one-handed layout untouched; pointers that can hover get hover; wide screens
   get a two-column catalogue, a floating pill dock, and a specimen spread. */

@media (hover: hover) and (pointer: fine) {
  .row:hover, .pick:hover { background: color-mix(in oklab, var(--ink) 4%, transparent); }
  .chip:hover, .big-btn:hover, .da-close:hover { border-color: var(--ink-45); }
  .dock button:hover, .enc-del:hover, .log-back:hover { color: var(--ink); }
  .dock-log:hover { opacity: 0.92; }
  .atlas-hud-btns button:hover, .sun-toggle:hover, .sheet-close:hover { color: var(--ink); border-color: var(--hairline-strong); background: var(--surface); }
  .credit-list a:hover { border-bottom-color: var(--ink); }
}

@media (min-width: 840px) {
  .top, .ribbon, .guide, .screen { max-width: 62rem; }
  .top { padding-top: var(--sp-8); }

  /* the guide becomes a two-column plate catalogue */
  .fam-group { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--sp-8); }
  .fam-head, .fam-rule { grid-column: 1 / -1; }
  /* grid flows row-wise, so the LAST GRID ROW is the final one or two items — clear the
     hairline under both column bottoms (last-child alone left a stray rule on one side) */
  .fam-group .row:nth-last-child(-n+2) { border-bottom: none; }
  .guide { padding-bottom: 190px; }              /* clear the floating search + dock pills */

  /* dock: a floating pill, not a phone tab bar */
  .dock {
    left: 50%; right: auto; bottom: 14px; transform: translateX(-50%);
    display: flex; align-items: center; gap: 2px; height: auto; width: auto;
    padding: 6px 10px; border: 1px solid var(--hairline-strong); border-radius: var(--r-pill);
    box-shadow: var(--elev);
  }
  .dock button { flex-direction: row; gap: 7px; min-height: 44px; padding: 8px 14px; }
  .dock button .ic { width: 18px; height: 18px; }
  .dock-log { width: auto !important; height: 44px; padding: 0 22px !important; transform: none; border: none !important; margin: 0 6px; }
  .dock-log:active { transform: scale(0.97); }
  body { padding-bottom: 120px; }

  /* search floats just above the dock pill */
  .searchbar { bottom: 84px; padding: 0; background: none; }
  .searchbar input { max-width: 30rem; border-color: var(--hairline-strong); box-shadow: var(--elev); }

  /* quick-log: a centered bottom card instead of a full-width sheet */
  .sheet { left: 50%; right: auto; width: min(37rem, 94vw); transform: translate(-50%, 105%); }
  .sheet.on { transform: translate(-50%, 0); }

}

/* the specimen page becomes a two-column spread: plate left (sticky), reading column right */
@media (min-width: 1080px) {
  .detail-sheet {
    display: grid; grid-template-columns: minmax(360px, 44%) minmax(0, 1fr);
    gap: var(--sp-12); max-width: 74rem; margin: 0 auto;
    padding: var(--sp-12) var(--sp-8) 0; align-items: start;
  }
  .detail-grab { display: none; }
  /* EVERY child needs explicit placement. .detail-head had none, so auto-placement took
     row 1 col 1 and pushed the plate to a third row — a fish app whose species page
     opened with no fish above the fold on a laptop. */
  .detail-head { grid-column: 2; grid-row: 1; padding: 0; margin: 0; }
  .detail-hero { grid-column: 1; grid-row: 1 / span 2; position: sticky; top: var(--sp-12); width: 100%; max-width: none;
    margin: 0; height: auto; aspect-ratio: 3 / 2; max-height: 62vh; }
  .plate-credit { grid-column: 1; grid-row: 3; margin: var(--sp-2) 0 0; padding: 0; align-self: start; }
  .detail-body { grid-column: 2; grid-row: 2; max-width: 38rem; margin: 0; padding: 0; }
  .detail-actions { max-width: 74rem; padding-inline: var(--sp-8); justify-content: flex-end; }
  .da-log { flex: none; padding: 0 28px; }
}

/* ---------- Phase A: GPS surfacing + backup nudge (museum-caption whisper, DESIGN §1/§4) ---------- */
.enc-gps { color: var(--ink-45); font-size: calc(13px * var(--fs, 1)); font-family: var(--serif); font-style: italic; }
.enc-gps .tnum { font-style: normal; font-family: inherit; }
.enc-gps-del { border: none; background: transparent; color: var(--ink-45); text-decoration: underline;
  font: inherit; font-size: calc(12px * var(--fs, 1)); cursor: pointer; padding: 8px 0 8px 10px; min-height: 44px;
  display: inline-flex; align-items: center; }
.enc-gps-del:hover { color: var(--ink); }
.pf-nudge { font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); margin: var(--sp-2) 0 var(--sp-3); }

/* ---------- Today's Drawer: the guide's daily snap-scroll rail ---------- */
.td-rail-wrap { padding: var(--sp-3) 0 var(--sp-2); }
/* two horizontal rails back-to-back read as duplicates — a hairline + air separates the
   drifting cabinet (browse) from Today's Drawer (your day's editorial picks) */
.fish-marquee + .td-rail-wrap { border-top: 1px solid var(--hairline); margin-top: var(--sp-4); padding-top: var(--sp-4); }
.td-eyebrow { display: block; padding: 0 var(--sp-4); margin-bottom: var(--sp-2); }
.td-rail { display: flex; gap: var(--sp-3); overflow-x: auto; padding: 2px var(--sp-4) var(--sp-2);
  scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  /* cards must fade at the edges, never be guillotined mid-word */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 22px, #000 calc(100% - 22px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 22px, #000 calc(100% - 22px), transparent); }
.td-rail::-webkit-scrollbar { display: none; }
.td-card { flex: 0 0 88%; max-width: 21rem; scroll-snap-align: start; text-align: left; cursor: pointer;
  border: 1px solid var(--hairline-strong); border-radius: var(--r-card); background: var(--surface);
  box-shadow: inset 0 0 0 4px var(--surface), inset 0 0 0 5px var(--hairline);
  padding: 5px; display: flex; flex-direction: column; color: var(--ink); font-family: var(--sans); }
.td-card:active { transform: scale(0.985); }
.td-plate { position: relative; display: grid; place-items: center; height: 132px; border-radius: calc(var(--r-card) - 4px);
  background: var(--sink); overflow: hidden; }
.td-plate img { width: 100%; height: 100%; object-fit: contain; }
.td-plate .star-badge { width: 26px; height: 26px; right: 8px; top: 8px; }
.td-body { display: block; padding: var(--sp-3) var(--sp-3) var(--sp-2); }
.td-body .eyebrow { font-size: calc(10px * var(--fs, 1)); letter-spacing: 0.1em; }
.td-name { display: block; font-family: var(--serif); font-size: calc(19px * var(--fs, 1)); font-weight: 500; letter-spacing: -0.005em; margin: 3px 0 2px; }
.td-line { display: block; font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); line-height: 1.4; color: var(--ink-45); }

/* The drifting cabinet — a slow, continuous marquee of plates, reshuffled each load.
   A learning band; motion pauses on hover/focus and stops entirely under reduced-motion.
   Edges fade to canvas (mask) so plates enter and leave like a specimen tray sliding past. */
.fish-marquee { padding: var(--sp-3) 0 var(--sp-2); }
.fm-eyebrow { display: block; padding: 0 var(--sp-4); margin-bottom: var(--sp-2); }
.fm-viewport { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
.fm-track { display: flex; gap: var(--sp-3); width: max-content; padding: 2px var(--sp-4); will-change: transform; }
.fm-viewport { cursor: grab; }
.fm-viewport.dragging { cursor: grabbing; }
.fm-viewport.dragging .fm-card { pointer-events: none; }   /* mid-drag, cards must not swallow the gesture */
.fm-eyebrow { display: flex; align-items: center; gap: var(--sp-2); }
.fm-pause { flex: none; width: 30px; height: 30px; border-radius: var(--r-pill); border: 1px solid var(--hairline);
  background: transparent; color: var(--ink-45); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  font-size: calc(11px * var(--fs, 1)); line-height: 1; padding: 0; }
.fm-pause.on { border-color: var(--accent, var(--ink-45)); color: var(--ink); background: var(--canvas); }
.fm-card { flex: 0 0 auto; width: 9.5rem; text-align: left; cursor: pointer; color: var(--ink); font-family: var(--sans);
  border: 1px solid var(--hairline-strong); border-radius: var(--r-card); background: var(--surface);
  box-shadow: inset 0 0 0 4px var(--surface), inset 0 0 0 5px var(--hairline); padding: 5px; display: flex; flex-direction: column; }
.fm-card:active { transform: scale(0.985); }
.fm-plate { display: grid; place-items: center; height: 96px; border-radius: calc(var(--r-card) - 4px); background: var(--sink); overflow: hidden; }
.fm-plate img { width: 100%; height: 100%; object-fit: contain; }
.fm-name { display: block; font-family: var(--serif); font-size: calc(15px * var(--fs, 1)); font-weight: 500; letter-spacing: -0.005em; margin: var(--sp-2) var(--sp-2) 0; }
.fm-latin { display: block; font-family: var(--serif); font-style: italic; font-size: calc(11.5px * var(--fs, 1)); color: var(--ink-45); margin: 0 var(--sp-2) var(--sp-2); }
/* reduced-motion: the JS never auto-drifts; the cabinet stays fully draggable */

/* The rivers right now — a live gage ticker that rotates through random rivers (no setup).
   One card at a time, a hushed cross-fade between them; pauses on hover so a reader can Watch. */
.river-now { margin-bottom: var(--sp-4); }
.rn-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--sp-2); }
.rn-live { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-45); }
.rn-stage { min-height: 118px; }
.rn-card { transition: opacity 0.5s ease; }
.rn-card.rn-in { opacity: 0; }
.rn-name { display: block; font-family: var(--serif); font-size: calc(20px * var(--fs, 1)); font-weight: 500; letter-spacing: -0.01em; }
/* The name binds the instruments to this river, so it is a real target: the text sits on its
   own line but the tappable box is padded out to the 44px floor. A dotted underline says
   "this does something" without borrowing the link colour. */
.rn-name[role="button"] { cursor: pointer; min-height: 44px; display: flex; align-items: center;
  text-decoration: underline dotted var(--hairline-strong); text-underline-offset: 5px; }
.rn-name[role="button"]:hover { text-decoration-color: var(--ink-45); }
.rn-stats { display: flex; gap: var(--sp-6); margin: var(--sp-2) 0; }
.rn-stat { font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); }
.rn-stat b { font-family: var(--serif); font-size: calc(26px * var(--fs, 1)); font-weight: 500; color: var(--ink); margin-right: 3px; }
.rn-word { margin: 0 0 var(--sp-3); font-family: var(--serif); font-style: italic; font-size: calc(14px * var(--fs, 1)); color: var(--ink-70); }
.rn-headright { display: inline-flex; align-items: center; gap: var(--sp-2); }
.rn-pause { flex: none; width: 30px; height: 30px; border-radius: var(--r-pill); border: 1px solid var(--hairline);
  background: transparent; color: var(--ink-45); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  font-size: calc(11px * var(--fs, 1)); line-height: 1; padding: 0; }
.rn-pause.on { border-color: var(--accent, var(--ink-45)); color: var(--ink); background: var(--canvas); }
.rn-dots { display: flex; gap: 5px; margin-top: var(--sp-3); }
.rn-dot { width: 5px; height: 5px; border-radius: var(--r-pill); background: var(--hairline-strong); transition: background 0.3s; }
.rn-dot.on { background: var(--ink-45); }
@media (prefers-reduced-motion: reduce) { .rn-card { transition: none; } }

/* Blocked-on-owner features: visible but greyed, so the angler knows it's coming and it
   lights up automatically once the owner's setup fills config.js. Never a working-looking dead button. */
/* Mute via COLOR, not opacity — a parent opacity would cap the note's legibility too.
   The label reads as secondary (--ink-45, AA) and the "coming soon" note stays legible. */
.is-locked { cursor: not-allowed !important; color: var(--ink-45); border-color: var(--hairline) !important; background: var(--canvas) !important; }
.is-locked:active { transform: none; }
.lock-note { display: inline-block; margin-left: var(--sp-2); font-family: var(--sans); font-size: calc(10px * var(--fs, 1));
  font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-45); }

/* ---------- Phase B surfaces, set to the canon: engraved plaques, never documents ----------
   One shared material — .plaque — carries the specimen-label feel everywhere: a surface
   card with a double hairline (border + inset line), depth by luminance only (DESIGN §1). */
.plaque { background: var(--surface); border: 1px solid var(--hairline-strong); border-radius: var(--r-card);
  box-shadow: inset 0 0 0 4px var(--surface), inset 0 0 0 5px var(--hairline);
  padding: calc(var(--sp-4) + 5px); }
.sec-h { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-45); margin: var(--sp-8) 0 var(--sp-3); display: flex; align-items: baseline; gap: var(--sp-3); }
.sec-h:first-child { margin-top: var(--sp-2); }
.sec-cnt { margin-left: auto; font-weight: 600; color: var(--ink-45); letter-spacing: 0.03em; }
.sec-sub { margin: calc(-1 * var(--sp-2)) 0 var(--sp-3); font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); }
.chip-quiet { color: var(--ink-45); }
/* the genus is a LABEL, not a control: no pill, no press, no pointer */
.chip-static { cursor: default; border-color: transparent; background: transparent; color: var(--ink-45); padding-inline: 0; }
.atlas-crumb:empty { display: none; }   /* an empty translucent pill on the chart border read as a defect */
.chip[aria-pressed="true"], .chip.on { border-color: var(--accent); color: var(--ink); background: var(--canvas); }
/* chips doing real work meet the touch floor (DESIGN §5) — decorative lineage chips opt out */
.nw-chips .chip, .pf-vol-chips .chip, .lineage .chip, .rn-card .chip, .pf-prefs .chip, #consultBtn { min-height: 44px; display: inline-flex; align-items: center; }
.pf-prefs { margin: 0 0 var(--sp-4); }

/* The waters room speaks in river slate — the per-surface accent override the canon
   already grants species pages; the ledger wash, chips, and rules all pick it up. */
#waters { --accent: #3E5F6B; }
.waters-heroes { margin: var(--sp-2) 0 var(--sp-4); }
.waters-intro { margin: var(--sp-2) 0 var(--sp-4); }
/* Dashboard condition tiles — live sources, museum-set: hero numeral + one quiet line */
/* THE RADAR. A raw NEXRAD loop is a rainbow pasted onto paper; toned down it reads as an
   ink weather chart and belongs in the drawer. The mat + hairline frame it like a plate. */
.radar-wrap { margin-bottom: var(--sp-4); }
.radar-frame { margin-top: var(--sp-2); border-radius: calc(var(--r-card) - 4px); overflow: hidden;
  background: var(--sink); border: 1px solid var(--hairline); aspect-ratio: 1 / 1; display: grid; place-items: center; }
.radar-frame img { width: 100%; height: 100%; object-fit: cover;
  filter: sepia(0.22) saturate(0.78) contrast(1.04) brightness(0.98); }
.radar-wrap .dt-sub { margin-top: var(--sp-2); }
/* Instrument slots — each tile injects its own styles; the slot only owns rhythm. */
.dash-slot:not(:empty) { display: block; margin-bottom: var(--sp-4); }
.ambient-launch { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.ambient-launch .chip { min-height: 44px; display: inline-flex; align-items: center; }
.dash-bind { margin: var(--sp-3) 0 var(--sp-2); font-family: var(--serif); font-style: italic;
  font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); }
.dash-bind b { font-style: normal; font-weight: 500; color: var(--ink-70); }
.dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.dt { margin: 0; }
.dt-big { display: block; font-family: var(--serif); font-size: calc(24px * var(--fs, 1)); font-weight: 500; letter-spacing: -0.01em; margin: var(--sp-1) 0 2px; text-wrap: balance; }
.dt-big.dt-big-sm { font-size: calc(18px * var(--fs, 1)); letter-spacing: -0.005em; }
.dt-sub { margin: 0; font-family: var(--serif); font-style: italic; font-size: calc(12px * var(--fs, 1)); line-height: 1.4; color: var(--ink-45); }
@media (min-width: 840px) { .dash-grid { grid-template-columns: repeat(3, 1fr); } }
/* SELECTION DISCIPLINE — the app chrome is not a document. A drag/double-tap-drag
   anywhere must never light the page up blue (the iOS whole-page highlight). Selection
   is OFF by default and re-enabled ONLY on prose a reader might genuinely want to copy. */
body { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.detail-desc, .fieldnote-t, .enc-story, .nw-story, .suite-essay, .alm-line, .creel-text,
.detail-name, .detail-latin, .rn-name, .pf-name, .dt-sub, .credits, .credits * {
  -webkit-user-select: text; user-select: text; }
/* canvas + gesture surfaces stay hard-off even if nested inside the above */
#atlas, #atlas *, .lightbox, .lightbox *, .fm-viewport, .fm-viewport * {
  -webkit-user-select: none !important; user-select: none !important; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }
.waters-intro .wi-line { margin: var(--sp-1) 0 0; font-family: var(--serif); font-style: italic; font-size: calc(16px * var(--fs, 1)); color: var(--ink-70); line-height: 1.4; }

/* The Water Ledger — an instrument plate: the flow is the hero numeral (DESIGN: data is
   set in tabular lining numerals; big numbers are serif and quiet, not neon). */
.wl-card { margin: var(--sp-2) 0 var(--sp-3); }
.wl-follow { margin-top: var(--sp-3); }
.wl-follow .eyebrow { display: block; margin-bottom: var(--sp-2); }
.wl-top { display: flex; align-items: baseline; gap: var(--sp-3); }
.wl-name { font-family: var(--serif); font-size: calc(19px * var(--fs, 1)); font-weight: 500; letter-spacing: -0.005em; }
.wl-gage { margin-left: auto; font-family: var(--sans); font-size: calc(10px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-45); text-align: right; }
.wl-hero { display: flex; align-items: flex-end; gap: var(--sp-4); margin-top: var(--sp-3); }
.wl-stat b { display: block; font-family: var(--serif); font-size: calc(34px * var(--fs, 1)); font-weight: 520;
  font-variation-settings: "opsz" 96; line-height: 1; }
.wl-stat span { font-family: var(--sans); font-size: calc(10px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-45); }
.wl-stat + .wl-stat { padding-left: var(--sp-4); border-left: 1px solid var(--hairline); }
.wl-word { flex: 1; margin: 0 0 2px; font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1));
  color: var(--ink-45); text-align: right; align-self: flex-end; }
.wl-spark { width: 100%; height: 34px; margin-top: var(--sp-3); display: block; }
.wl-sparkmeta { display: flex; justify-content: space-between; margin-top: 4px;
  font-family: var(--sans); font-size: calc(10px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-45); }
/* locked = structural (sink step, no inner line), never a legibility haircut (§5) */
.wl-locked { background: var(--sink); box-shadow: none; }
.wl-locked .wl-word { text-align: left; }

/* Named Waters — specimen labels in the gazetteer */
.nw-card { margin: var(--sp-2) 0 var(--sp-3); }
.nw-top { display: flex; align-items: baseline; gap: var(--sp-3); }
.nw-name { font-family: var(--serif); font-size: calc(20px * var(--fs, 1)); font-weight: 500; letter-spacing: -0.005em; }
.nw-tally { margin-left: auto; font-family: var(--sans); font-size: calc(10px * var(--fs, 1)); font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-45); white-space: nowrap; }
.nw-story { font-family: var(--serif); font-style: italic; font-size: calc(14px * var(--fs, 1)); line-height: 1.45;
  color: var(--ink-70); margin: var(--sp-2) 0 0; }
.nw-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
/* the water's own catch record — full-color species coins, the earned life of the card */
.nw-coins { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: var(--sp-3); }
.nw-coin { width: 44px; height: 44px; border-radius: 50%; overflow: hidden; padding: 0; cursor: pointer;
  border: 1px solid var(--hairline-strong); background: var(--sink); }
.nw-coin img { width: 100%; height: 100%; object-fit: cover; display: block; }
.nw-coin:active { transform: scale(0.94); }
.nw-gagepick { margin-top: var(--sp-3); }
.nw-gagesearch { font-family: var(--serif); font-size: calc(15px * var(--fs, 1)); background: var(--canvas); color: var(--ink);
  border: 1px solid var(--hairline); border-radius: var(--r-control); padding: 10px 13px; outline: none; width: 100%; }
.nw-gagesearch:focus { border-color: var(--accent); }
.nw-gagehits { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-2); }
.nw-gagehits .chip { min-height: 44px; text-align: left; text-transform: none; letter-spacing: 0.02em;
  font-family: var(--serif); font-size: calc(14px * var(--fs, 1)); font-weight: 500; }
.nw-christen .eyebrow { display: block; margin-bottom: var(--sp-3); }
.nw-commit { width: 100%; min-height: 48px; margin-top: var(--sp-1); border: none; border-radius: var(--r-control);
  background: var(--ink); color: var(--canvas); font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); font-weight: 600;
  letter-spacing: 0.06em; cursor: pointer; }
.nw-commit:active { transform: scale(0.99); }

/* first-encounters chronology — plate-thumbed rows, not a text list */
.fe-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--hairline); }
.fe-row .plate { width: 64px; height: 43px; flex: none; }
.fe-date { font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); }
.fe-place { color: var(--ink-45); font-size: calc(13px * var(--fs, 1)); }

/* anniversaries — a quiet plaque with the plate present, not a bare sentence */
.anniv { margin: var(--sp-3) var(--sp-4) 0; }
.anniv .eyebrow { display: block; margin-bottom: var(--sp-2); }
.anniv-row { display: flex; align-items: center; gap: var(--sp-3); }
.anniv-row + .anniv-row { margin-top: var(--sp-2); }
.anniv-row .plate { width: 84px; height: 56px; flex: none; }
.anniv-line { font-family: var(--serif); font-style: italic; font-size: calc(15px * var(--fs, 1)); line-height: 1.4; color: var(--ink); margin: 0; }

/* The First Haul — an engraved invitation, the guide's opening moment */
.haul-card { margin: var(--sp-3) var(--sp-4); text-align: center; }
.haul-card .eyebrow { display: block; margin-bottom: var(--sp-2); }
.haul-card .haul-lede { font-family: var(--serif); font-size: calc(24px * var(--fs, 1)); font-weight: 480;
  font-variation-settings: "opsz" 72, "SOFT" 18; letter-spacing: -0.01em; margin: 0 0 var(--sp-2); }
.haul-card .haul-sub { font-family: var(--serif); font-style: italic; font-size: calc(14px * var(--fs, 1)); color: var(--ink-45); margin: 0 auto var(--sp-4); max-width: 26em; }
.haul-cta { display: inline-block; min-height: 48px; padding: 0 26px; border: none; border-radius: var(--r-control);
  background: var(--ink); color: var(--canvas); font-family: var(--sans); font-size: calc(13px * var(--fs, 1)); font-weight: 600;
  letter-spacing: 0.06em; cursor: pointer; }
.haul-cta:active { transform: scale(0.98); }
.sample-link { display: block; margin: var(--sp-3) auto 0; border: none; background: transparent; cursor: pointer;
  font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); min-height: 40px;
  text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--hairline-strong); }
.sample-link:hover { color: var(--ink); }
.sample-banner { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  margin: var(--sp-3) var(--sp-4) 0; padding: var(--sp-3) var(--sp-4);
  background: color-mix(in oklab, var(--accent) 7%, var(--surface)); border: 1px solid var(--hairline);
  border-left: 2px solid var(--accent); border-radius: var(--r-control); }
.sample-banner span { flex: 1; min-width: 12rem; font-family: var(--serif); font-size: calc(13px * var(--fs, 1)); color: var(--ink-70); }
.sample-banner .chip { min-height: 40px; }
.haul-lede { font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); line-height: 1.5; }
.haul-note { font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); }
.haul-pick { display: inline-block; cursor: pointer; }
.haul-photo { border-radius: var(--r-card); overflow: hidden; background: var(--sink); position: relative; }
.haul-photo::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 44%, transparent 62%, color-mix(in oklab, var(--ink) 7%, transparent)); }
.haul-photo img { width: 100%; max-height: 12rem; object-fit: cover; display: block; }
.haul-picklist .pick { min-height: 44px; }
.haul-picklist .pick.on { box-shadow: inset 3px 0 0 var(--accent); background: color-mix(in oklab, var(--accent) 5%, transparent); }
.haul-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); align-items: center; }
.haul-actions .log-commit { flex: 1; margin-top: 0; }

/* seals & whispers */
.holotype { margin-left: 8px; font-size: calc(10px * var(--fs, 1)); font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-45); border: 1px solid var(--hairline-strong); border-radius: 3px; padding: 2px 6px; vertical-align: 2px;
  font-family: var(--sans); }
.enc-memory { font-family: var(--serif); font-style: italic; font-size: calc(12.5px * var(--fs, 1)); color: var(--ink-45); font-variant-numeric: tabular-nums lining-nums; }
.pf-arc-badge { font-style: italic; font-family: var(--serif); color: var(--ink-45); font-size: calc(12px * var(--fs, 1)); text-transform: none; letter-spacing: 0; }

/* Suites — specimen-drawer shelves: the year's coins in miniature; missing species sit
   as ghost engravings awaiting ink (the atlas precedent — the guide itself never ghosts) */
.pf-suites { display: grid; gap: var(--sp-4); }
.pf-suite-head { display: flex; justify-content: space-between; align-items: baseline; }
.pf-suite-head b { font-family: var(--serif); font-size: calc(17px * var(--fs, 1)); font-weight: 500; }
.pf-suite-head .tnum { font-family: var(--sans); font-size: calc(11px * var(--fs, 1)); font-weight: 600; letter-spacing: 0.06em; color: var(--ink-45); }
.suite-shelf { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--sp-2) 0; align-items: center; min-width: 0; }
/* the slot is a 44×44 touch target (§5); the plate sits 44×30 within it */
.suite-slot { flex: none; width: 44px; height: 44px; border: none; padding: 7px 0; cursor: pointer;
  background: transparent; display: grid; place-items: center; }
.suite-slot:active { transform: scale(0.94); }
.suite-slot img { width: 44px; height: 30px; object-fit: contain; border-radius: 6px;
  background: var(--sink); outline: 1px solid var(--hairline); outline-offset: -1px; }
.suite-slot.got img { outline-color: var(--hairline-strong); }
.suite-slot:not(.got) img { opacity: 0.3; filter: grayscale(0.85); }
.suite-slot.got { outline-color: var(--hairline-strong); }
.suite-more { font-family: var(--sans); font-size: calc(10px * var(--fs, 1)); font-weight: 700; color: var(--ink-45); letter-spacing: 0.04em; }
.pf-suite-essay { font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); margin: var(--sp-1) 0 0; }
.pf-vol-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* The Almanac teaser + The Prospect List (§7.2 / §7.5) */
.alm-line { font-family: var(--serif); font-size: calc(18px * var(--fs, 1)); line-height: 1.45; margin: 0 0 var(--sp-2); }
.alm-locked { font-family: var(--serif); font-style: italic; font-size: calc(13px * var(--fs, 1)); color: var(--ink-45); margin: 0; }
.pr-controls { margin-bottom: var(--sp-3); }
.pr-select { width: 100%; font-family: var(--serif); font-size: calc(16px * var(--fs, 1)); color: var(--ink); background: var(--canvas);
  border: 1px solid var(--hairline); border-radius: var(--r-control); padding: 11px 13px; outline: none; min-height: 44px; }
.pr-select:focus { border-color: var(--accent); }
.pr-months { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--sp-2); }
.pr-m { min-height: 40px; padding: 5px 10px; }
.pr-row { border: none; background: transparent; width: 100%; text-align: left; cursor: pointer; color: var(--ink); font-family: var(--sans); }
.pr-row:active { background: color-mix(in oklab, var(--ink) 4%, transparent); }
/* the ghosted plate awaiting ink — the atlas precedent, deliberate here */
.plate.ghost img { opacity: 0.38; filter: grayscale(0.8); }

/* The Catch Map — a chart in a chart frame; third-party chrome restyled to the paper
   palette (default library controls read as another app's furniture — DESIGN §1) */
.catch-map { height: 62vh; min-height: 320px; border-radius: calc(var(--r-card) - 4px); overflow: hidden; margin-top: var(--sp-3); background: var(--canvas); }
.map-frame { padding: 5px; margin-top: var(--sp-3); }
.map-frame .catch-map { margin-top: 0; }
.catch-map .maplibregl-ctrl-group { background: color-mix(in oklab, var(--canvas) 85%, transparent);
  border: 1px solid var(--hairline); border-radius: var(--r-control); box-shadow: none; backdrop-filter: blur(3px); overflow: hidden; }
.catch-map .maplibregl-ctrl-group button { width: 40px; height: 40px; background: transparent; }
.catch-map .maplibregl-ctrl-group button + button { border-top: 1px solid var(--hairline); }
.catch-map .maplibregl-ctrl-group button .maplibregl-ctrl-icon { filter: opacity(0.72); }
/* attribution: nothing third-party renders in the tile-less era (attributionControl:false
   already governs) — when tiles.lifelist.fish lands, add the museum-caption attribution
   whisper here rather than suppressing it (Protomaps/OSM credit will be owed then). */

/* The Creel Card — one quiet line of law, set like a stat, whispered like a caption */
.creel-line { margin: var(--sp-6) 0; padding: var(--sp-3) var(--sp-4); background: var(--surface);
  border-radius: var(--r-control); border-left: 2px solid var(--accent); border-top: 1px solid var(--hairline); border-right: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }
.creel-line .eyebrow { font-size: calc(10px * var(--fs, 1)); letter-spacing: 0.12em; }
.creel-text { margin: var(--sp-1) 0 2px; font-family: var(--serif); font-size: calc(15px * var(--fs, 1)); line-height: 1.45; }
.creel-whisper { margin: 0; font-family: var(--serif); font-style: italic; font-size: calc(11.5px * var(--fs, 1)); color: var(--ink-45); }
/* Larger-type comfort mode (SPEC §12, elder-facing pillar): scales the WHOLE type
   ramp ~1.2×. Every px font-size in this sheet is `calc(Npx * var(--fs, 1))`, so
   flipping --fs here enlarges all text proportionally — species names, family
   headers, the ribbon count, buttons, waters, profile, detail, not just a handful
   of paragraphs. Layout widths and spacing are untouched (only the font multiplier
   moves); unitless line-heights scale with the font so nothing clips. */
:root.comfort { --fs: 1.2; }

/* ---------- Platform baseline (2026 table stakes — touch, focus, scroll) ----------
   From the interaction/motion/a11y research pass: tap-delay + double-tap-zoom killed on
   every control; a pressed state on everything tappable (press lands fast, release
   springs back); a real focus ring; no body rubber-band / pull-to-refresh; and
   content-visibility so 288 rows cost nothing off-screen. */
html, body { overscroll-behavior-y: none; }
button, a, [role="button"], .chip, .row, .pick, .medal, .mdl, .td-card, .fm-card, .nw-coin {
  touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
button, .chip, .row, .pick, .td-card, .fm-card { user-select: none; -webkit-user-select: none; }
:where(button, .chip:not(.chip-static), .pick, .td-card, .fm-card, .nw-coin, .mdl, .medal, .big-btn, .haul-cta):active {
  transform: scale(0.97); transition: transform 90ms cubic-bezier(0.25, 1, 0.5, 1); }
:where(.row):active { transform: scale(0.99); transition: transform 90ms cubic-bezier(0.25, 1, 0.5, 1); }
:where(button, .chip, .row, .pick, .td-card, .fm-card) { transition: transform 300ms cubic-bezier(0.25, 1, 0.5, 1); }
/* Focus Appearance at the AAA bar: a two-tone halo — a paper gap ring under the accent
   outline — so the indicator clears 3:1 on EVERY surface, light panels and dark plates alike. */
:focus-visible { outline: 2px solid var(--accent, #3E5F6B); outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--canvas); border-radius: 2px; }

/* Scroll-driven masthead: the wordmark quietly recedes as the collection scrolls under it —
   compositor-thread (transform only), Chrome 115+/Safari 26; elsewhere it simply stays. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .wordmark { transform-origin: left center; animation: mast-recede linear both; animation-timeline: scroll(); animation-range: 0 140px; }
    @keyframes mast-recede { to { transform: scale(0.82); } }
  }
}
.row { content-visibility: auto; contain-intrinsic-size: auto 96px; }   /* off-screen rows: zero layout/paint */
@media (prefers-reduced-motion: reduce) { :where(button, .chip, .row, .pick, .td-card, .fm-card):active { transform: none; } }

/* Boot skeleton — holds the guide's shape (card, rail, rows) for the beat before data
   lands. Same materials as the real surfaces: sink panels, hairlines, a quiet pulse. */
.skel-wrap { padding: var(--sp-3) var(--sp-4); }
.skel { background: var(--sink); border-radius: var(--r-card); animation: skel-pulse 1.4s ease-in-out infinite; }
.skel-card { height: 200px; margin-bottom: var(--sp-4); }
.skel-rail { display: flex; gap: var(--sp-3); margin-bottom: var(--sp-4); overflow: hidden; }
.skel-coin { flex: 0 0 9.5rem; height: 128px; }
.skel-row { height: 56px; border-radius: var(--r-control); margin-bottom: var(--sp-2); }
@keyframes skel-pulse { 0%, 100% { opacity: 0.55; } 50% { opacity: 0.95; } }

@media (prefers-reduced-motion: reduce) { *, ::before, ::after { animation: none !important; transition: none !important; } }
