/* nf-layout.css — the page layout of /lab/neural-familiar/ (wave 3, D19:
   "a calm scientific instrument"). The world is the specimen under glass: the
   canvas runs full-bleed behind every piece of chrome. Readouts above, controls
   below:

     [nav: brand · Lab▾ · Menu▾ · ☾]                       one row on phones
     [plate: name · temperament · age · ?  / the learning line]
                    the world (a camera onto it)
     [map]                                  [− 1.0× +] [◎ Follow]
     [sheet: grabber · Energy | Mood | Doing (· tabs · panel when open)]
     [dock: Feed · + Praise · − Scold · ⋯]                   thumb zone

   Sheet states (scripts/neural-familiar/sheet.js → body[data-nf-sheet]):
   peek | half | full on a portrait phone; a landscape phone is one bottom bar
   at rest and a right-hand panel when open ('side'); desktop is the same
   instrument docked right ('side'). body[data-nf-card] mirrors the first-run
   card. sheet.js publishes --nf-sheet-h / --nf-card-h (where the camera chrome
   and the card sit) and the safe rect --nf-frame-* the camera reads.

   One stylesheet, every selector page-scoped (body.neural-familiar-page):
   js/site-nav.js and the other pages are untouched. Linked after
   labs-modern.css, so .lab-btn / .lab-chip lose without !important.
   Quiet (D11): nothing here animates on its own; the only transition is the
   sheet answering a visitor's gesture, and reduced motion drops even that. */

/* ───────────────────────── tokens ───────────────────────── */
:root {
  --nf-sa-t: env(safe-area-inset-top, 0px);
  --nf-sa-r: env(safe-area-inset-right, 0px);
  --nf-sa-b: env(safe-area-inset-bottom, 0px);
  --nf-sa-l: env(safe-area-inset-left, 0px);
  --nf-gutter: 16px;
  --nf-tap: 44px;
  --nf-dock-pad: 8px;
  --nf-dock-h: calc(var(--nf-tap) + 2 * var(--nf-dock-pad) + var(--nf-sa-b));
  --nf-map: 132px;
  --nf-side: 400px;
  --nf-sans: 'Source Sans 3', 'Inter', system-ui, sans-serif;
  --nf-mono: 'Share Tech Mono', ui-monospace, 'SF Mono', monospace;
  /* the sheet, strip, dock and chat composer are OPAQUE and unblurred (P5:
     a blur over a 60 fps canvas is redone every frame; at 96-97 % the moving
     world and the scrolled log shimmered through them, V2); only the small
     chips stay translucent and blur */
  --nf-sheet-bg: var(--nf-surface-solid);
  --nf-chip-bg: rgba(246, 249, 252, 0.9);
  --nf-chip-border: rgba(60, 100, 140, 0.24);
  --nf-chip-shadow: 0 6px 18px rgba(20, 40, 60, 0.12);
  --nf-chrome-shadow: 0 -8px 28px rgba(20, 40, 60, 0.12);
  --nf-chip-blur: blur(14px) saturate(1.15);
  --nf-map-bg: #d3dfea;
  --nf-map-grid: rgba(60, 100, 140, 0.12);
  /* detent heights (sheet.js measures them for drag snapping). Half leaves
     the sheet's top edge max(320px, 52svh) above the screen's bottom, dock
     included, so the world keeps ~48% of a phone (judge graft). */
  --nf-half-h: calc(max(320px, 52svh) - var(--nf-dock-h));
  --nf-full-h: calc(100svh - var(--header-height, 44px) - 8px - var(--nf-dock-h));
}

body.dark-mode {
  /* re-declared so it resolves against the dark --nf-surface-solid */
  --nf-sheet-bg: var(--nf-surface-solid);
  --nf-chip-bg: rgba(6, 14, 22, 0.8);
  --nf-chip-border: rgba(120, 232, 255, 0.2);
  --nf-chip-shadow: 0 8px 22px rgba(0, 0, 0, 0.35);
  --nf-chrome-shadow: 0 -10px 32px rgba(0, 0, 0, 0.45);
  --nf-map-bg: #08121e;
  --nf-map-grid: rgba(120, 232, 255, 0.1);
}

/* Opaque fallbacks: reduced transparency asked for, or the renderer shed
   effects to hold its frame budget (body[data-nf-lowfx]). */
@media (prefers-reduced-transparency: reduce) {
  :root { --nf-chip-bg: var(--nf-surface-solid); --nf-sheet-bg: var(--nf-surface-solid); --nf-chip-blur: none; --nf-bubble-bg: var(--nf-surface-solid); }
  body.dark-mode { --nf-chip-bg: var(--nf-surface-solid); --nf-sheet-bg: var(--nf-surface-solid); --nf-bubble-bg: var(--nf-surface-solid); }
}

body.neural-familiar-page[data-nf-lowfx] {
  --nf-chip-bg: var(--nf-surface-solid);
  --nf-chip-blur: none;
}

/* ───────────────────────── the page and the world ───────────────────────── */
body.neural-familiar-page {
  overscroll-behavior: none;
}

/* Full-bleed: lvh, so the canvas never resizes when a phone's toolbar shows
   or hides (no backing-store churn, no jump); what the toolbar covers is
   just world. The camera keeps the creature inside --nf-frame-*. */
body.neural-familiar-page #familiarWorld {
  top: 0;
  height: 100vh;
  height: 100lvh;
  touch-action: none;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  outline: none;
}

/* The world is focusable (arrow keys look around): an inset ring, since the
   canvas is the whole screen and an outside ring would be off it. */
body.neural-familiar-page #familiarWorld:focus-visible {
  outline: 2px solid var(--nf-cyan);
  outline-offset: -4px;
  border-radius: 0;
}

/* ───────────────────────── the site nav (this page only) ───────────────────────── */
body.neural-familiar-page .ds-sitenav {
  position: relative;
  z-index: 33;
  padding: var(--nf-sa-t) var(--nf-sa-r) 0 var(--nf-sa-l);
  background: var(--nf-chip-bg);
  -webkit-backdrop-filter: var(--nf-chip-blur);
  backdrop-filter: var(--nf-chip-blur);
  border-bottom: 1px solid var(--nf-hairline);
}

body.neural-familiar-page .ds-sitenav-inner {
  max-width: none;
  min-height: var(--nf-tap);
  padding: 0 8px 0 var(--nf-gutter);
  flex-wrap: nowrap;
  gap: 4px;
}

body.neural-familiar-page .ds-sitenav-brand {
  display: flex;
  align-items: center;
  min-height: var(--nf-tap);
  margin-right: auto;
  font-size: 1rem;
}

body.neural-familiar-page .ds-sitenav-links {
  flex-wrap: nowrap;
  gap: 2px;
}

/* no opacity on the links: 0.82 took the muted ink under 4.5:1 */
body.neural-familiar-page details.ds-nav-dd > summary,
body.neural-familiar-page .ds-sitenav-link {
  display: flex;
  align-items: center;
  min-height: var(--nf-tap);
  padding: 0 0.6rem;
  font-size: 0.875rem;
  opacity: 1;
  white-space: nowrap;
}

/* a 44 px target; the pill (34 px) is drawn inside it */
body.neural-familiar-page .ds-sitenav-subscribe {
  position: relative;
  display: flex;
  align-items: center;
  min-height: var(--nf-tap);
  padding-top: 0;
  padding-bottom: 0;
  border-color: transparent;
  background: none;
  white-space: nowrap;
}

body.neural-familiar-page .ds-sitenav-subscribe::before {
  content: '';
  position: absolute;
  inset: 5px 0;
  border: 1.5px solid currentColor;
  border-radius: 999px;
  pointer-events: none;
}

body.neural-familiar-page .ds-sitenav-subscribe:hover { background: none; }
body.neural-familiar-page .ds-sitenav-subscribe:hover::before { background: rgba(128, 128, 160, 0.14); }

body.neural-familiar-page details.ds-nav-dd.active > summary {
  background: none;
  font-weight: 700;
}

/* The menus escape the row: their containing block is the nav itself. */
body.neural-familiar-page details.ds-nav-dd {
  position: static;
}

body.neural-familiar-page .ds-nav-dd-menu {
  left: auto;
  right: calc(8px + var(--nf-sa-r));
  top: 100%;
  max-height: calc(100svh - var(--header-height, 44px) - 16px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

body.neural-familiar-page .ds-nav-dd-menu a {
  display: flex;
  align-items: center;
  min-height: var(--nf-tap);
  padding: 0 0.85rem;
  font-size: 0.9375rem;
  opacity: 1;
}

body.neural-familiar-page .nf-nav-more { display: none; }

body.neural-familiar-page .nf-nav-more-h {
  display: block;
  padding: 0.6rem 0.85rem 0.15rem;
  border-top: 1px solid var(--nf-hairline);
  font: 600 0.75rem/1.2 var(--nf-sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--nf-muted);
}

/* The theme toggle is a 44 px icon; dark-mode-toggle.js still owns its text
   and aria-label (the label is what assistive tech reads). */
/* flex, not grid: the zero-size label text would take a second grid row and
   push the icon above the row's centre */
body.neural-familiar-page #darkModeToggle {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--nf-tap);
  height: var(--nf-tap);
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  font-size: 0;
  color: var(--nf-text);
  opacity: 1;
  overflow: hidden;
}

body.neural-familiar-page #darkModeToggle::before {
  content: '\263E\FE0E';
  font: 400 1.2rem/1 var(--nf-sans);
}

body.neural-familiar-page.dark-mode #darkModeToggle::before {
  content: '\2600\FE0E';
}

/* Hover feedback only where there is a real hover: on a touch screen :hover
   sticks to the last thing tapped and left it looking selected. */
@media (hover: hover) {
  body.neural-familiar-page #darkModeToggle:hover { background: rgba(var(--nf-cyan-rgb), 0.1); }

  body.neural-familiar-page .nf-plate .nf-guide-btn:hover > span[aria-hidden] {
    border-color: var(--nf-cyan);
    color: var(--nf-cyan);
  }

  body.neural-familiar-page .nf-cam-btn:hover,
  body.neural-familiar-page .nf-cam-follow:hover { background-color: rgba(var(--nf-cyan-rgb), 0.1); }

  body.neural-familiar-page #nfHud .nf-tabs .nf-tab:hover { color: var(--nf-text); }

  body.neural-familiar-page .nf-dock .nf-dock-btn:hover,
  body.neural-familiar-page .nf-dock .nf-dock-more:hover { border-color: var(--nf-cyan); }
}

/* ───────────────────────── the plate (specimen label) ───────────────────────── */
body.neural-familiar-page .nf-plate {
  position: fixed;
  z-index: 26;
  top: calc(var(--header-height, 50px) + 14px);
  left: calc(16px + var(--nf-sa-l));
  width: fit-content;
  max-width: 420px;
  padding: 10px 4px 11px 14px;
  border: 1px solid var(--nf-chip-border);
  border-radius: 14px;
  background: var(--nf-chip-bg);
  -webkit-backdrop-filter: var(--nf-chip-blur);
  backdrop-filter: var(--nf-chip-blur);
  box-shadow: var(--nf-chip-shadow);
  color: var(--nf-text);
}

body.neural-familiar-page .nf-plate .nf-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) var(--nf-tap);
  align-items: center;
  margin: 0;
}

body.neural-familiar-page .nf-plate .panel-header-row { display: contents; }

body.neural-familiar-page .nf-plate .panel-title {
  grid-column: 1 / 3;
  grid-row: 1;
  font: 700 0.75rem/1.2 'Orbitron', var(--nf-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nf-cyan);
}

/* 18 px: an input under 16 px makes iOS zoom the whole page on focus */
body.neural-familiar-page .nf-plate .familiar-name-input {
  grid-column: 1;
  grid-row: 2;
  flex: none;
  width: 7.5em;
  min-width: 3.5em;
  max-width: 11em;
  margin: -10px 0 -10px -0.3rem;
  padding: 10px 0.3rem;
  font: 600 1.125rem/1.3 var(--nf-sans);
  letter-spacing: 0.01em;
  color: var(--nf-mint);
}

@supports (field-sizing: content) {
  body.neural-familiar-page .nf-plate .familiar-name-input { width: auto; field-sizing: content; }
}

body.neural-familiar-page .nf-plate .nf-guide-btn {
  grid-column: 3;
  grid-row: 1 / span 2;
  justify-self: center;
  display: grid;
  place-items: center;
  width: var(--nf-tap);
  height: var(--nf-tap);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
}

body.neural-familiar-page .nf-plate .nf-guide-btn > span[aria-hidden] {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 1px solid var(--nf-input-border);
  border-radius: 50%;
  font: 700 0.875rem/1 var(--nf-sans);
  color: var(--nf-text);
}

body.neural-familiar-page .nf-plate .panel-subtitle {
  grid-column: 2;
  grid-row: 2;
  min-width: 0;
  margin: 0 0 0 0.4rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font: 600 0.8125rem/1.3 var(--nf-sans);
  letter-spacing: 0.01em;
  color: var(--nf-muted);
}

/* The one honest line: it may wrap, it is never cut mid-claim (D19). */
body.neural-familiar-page .nf-plate .nf-learning-line {
  grid-column: 1 / -1;
  grid-row: 3;
  margin: 6px 10px 0 0;
  padding-top: 6px;
  border-top: 1px solid var(--nf-hairline);
  /* one face on every screen: the same claim read as small mono on desktop
     and as sans on a phone (V14) */
  font: 600 0.8125rem/1.35 var(--nf-sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.005em;
  color: var(--nf-text);
}

body.neural-familiar-page .nf-plate .nf-learning-line::before {
  width: 6px;
  height: 6px;
}

/* ───────────────────────── camera chrome (the camera wires it) ───────────────────────── */
body.neural-familiar-page .nf-cam-map,
body.neural-familiar-page .nf-cam-ctrl {
  position: fixed;
  z-index: 27;
}

body.neural-familiar-page .nf-cam-map {
  left: calc(16px + var(--nf-sa-l));
  bottom: calc(16px + var(--nf-sa-b));
  width: var(--nf-map);
  height: var(--nf-map);
  padding: 4px;
  border: 1px solid var(--nf-chip-border);
  border-radius: 14px;
  background: var(--nf-chip-bg);
  -webkit-backdrop-filter: var(--nf-chip-blur);
  backdrop-filter: var(--nf-chip-blur);
  box-shadow: var(--nf-chip-shadow);
  cursor: pointer;
  touch-action: none;
}

/* the world's own tone and an 8 × 8 graticule under the canvas, so the map
   reads as a map before (or without) the camera's first paint */
body.neural-familiar-page .nf-cam-map canvas {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  background:
    linear-gradient(90deg, var(--nf-map-grid) 1px, transparent 1px) 0 0 / 12.5% 12.5%,
    linear-gradient(var(--nf-map-grid) 1px, transparent 1px) 0 0 / 12.5% 12.5%,
    var(--nf-map-bg);
}

body.neural-familiar-page .nf-cam-ctrl {
  right: calc(var(--nf-side) + 12px + 16px + var(--nf-sa-r));
  bottom: calc(16px + var(--nf-sa-b));
  display: flex;
  align-items: center;
  gap: 8px;
}

body.neural-familiar-page .nf-cam-zoom,
body.neural-familiar-page .nf-cam-follow {
  display: flex;
  align-items: center;
  height: var(--nf-tap);
  border: 1px solid var(--nf-chip-border);
  border-radius: 999px;
  background: var(--nf-chip-bg);
  -webkit-backdrop-filter: var(--nf-chip-blur);
  backdrop-filter: var(--nf-chip-blur);
  box-shadow: var(--nf-chip-shadow);
  color: var(--nf-text);
}

body.neural-familiar-page .nf-cam-btn {
  display: grid;
  place-items: center;
  width: var(--nf-tap);
  height: var(--nf-tap);
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--nf-text);
  font: 400 1.3rem/1 var(--nf-sans);
  cursor: pointer;
}

body.neural-familiar-page .nf-cam-btn:disabled,
body.neural-familiar-page .nf-cam-btn[aria-disabled="true"] {
  color: var(--nf-muted);
  cursor: default;
  background: none;
}

/* camera C10: the map never hides what it maps — app.js toggles .is-under
   while the creature's screen point is within the map + 24 px. No transition
   (D11: nothing in the chrome animates on its own). */
body.neural-familiar-page .nf-cam-map.is-under {
  opacity: 0.25;
  transition: none;
}

/* ...but never while it holds keyboard focus: its focus ring would fade with
   it (RH6) */
body.neural-familiar-page .nf-cam-map.is-under:focus-visible { opacity: 1; }

body.neural-familiar-page .nf-cam-zoomval {
  min-width: 2.7rem;
  text-align: center;
  font: 400 0.8125rem/1 var(--nf-mono);
  font-variant-numeric: tabular-nums;
  color: var(--nf-text);
}

/* Follow: a reticle plus the word; cyan, ring filled, while following. */
body.neural-familiar-page .nf-cam-follow {
  gap: 7px;
  min-width: var(--nf-tap);
  padding: 0 14px 0 12px;
  font: 700 0.875rem/1 var(--nf-sans);
  letter-spacing: 0.02em;
  cursor: pointer;
}

/* "◎ <familiar>" while following another: a long name never pushes the
   pill into the zoom pill at 393 px */
body.neural-familiar-page .nf-cam-follow-word {
  max-width: 8em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.neural-familiar-page .nf-cam-follow-ico {
  flex: none;
  width: 18px;
  height: 18px;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  background: radial-gradient(circle, currentColor 0 2.5px, transparent 3px);
}

body.neural-familiar-page .nf-cam-follow[aria-pressed="true"] {
  color: var(--nf-cyan);
  border-color: rgba(var(--nf-cyan-rgb), 0.6);
}

body.neural-familiar-page .nf-cam-follow[aria-pressed="true"] .nf-cam-follow-ico {
  background: radial-gradient(circle, currentColor 0 4px, transparent 4.5px);
}

/* ───────────────────────── the first-run / return card ───────────────────────── */
body.neural-familiar-page .nf-float {
  position: fixed;
  z-index: 27;
  left: calc(16px + var(--nf-map) + 16px + var(--nf-sa-l));
  bottom: calc(16px + var(--nf-tap) + 12px + var(--nf-sa-b));
  width: min(440px, calc(100vw - var(--nf-side) - 12px - var(--nf-map) - 64px));
}

body.neural-familiar-page[data-nf-card="none"] .nf-float {
  display: none;
}

body.neural-familiar-page .nf-float > .nfc {
  margin: 0;
  padding: 12px 14px 10px;
  border: 1px solid var(--nf-chip-border);
  border-radius: 16px;
  background: var(--nf-chip-bg);
  -webkit-backdrop-filter: var(--nf-chip-blur);
  backdrop-filter: var(--nf-chip-blur);
  box-shadow: var(--nf-chip-shadow);
}

body.neural-familiar-page .nf-float > .nfc[data-kind="first-run"] {
  border-color: rgba(var(--nf-cyan-rgb), 0.38);
  background:
    linear-gradient(180deg, rgba(var(--nf-cyan-rgb), 0.06), rgba(var(--nf-cyan-rgb), 0) 70%),
    var(--nf-chip-bg);
}

body.neural-familiar-page #nfFirstRun .nfc-lead { font-size: 0.9375rem; line-height: 1.35; }
body.neural-familiar-page #nfFirstRun .nfc-line { font-size: 0.875rem; line-height: 1.42; margin-top: 3px; }
body.neural-familiar-page #nfFirstRun .nfc-actions { margin-top: 6px; gap: 4px 16px; }
body.neural-familiar-page #nfFirstRun .nfc-ok,
body.neural-familiar-page #nfFirstRun .nfc-link { min-height: var(--nf-tap); }
body.neural-familiar-page #nfFirstRun .nfc-ok { min-width: 6rem; }
body.neural-familiar-page #nfFirstRun .nfc-close { width: var(--nf-tap); height: var(--nf-tap); margin: -8px -8px -8px 0; }

/* The family's cards (wave 4, D39: the tap card, the nest, the memorial and
   heir list, the extinction; family-panel.js, styled in nf-family.css) share
   the float with the first-run card, one at a time: a family card outranks
   it, so the first-run card steps aside while one shows (it comes back when
   the family card closes). Tall cards scroll inside themselves rather than
   push the world off the screen. */
body.neural-familiar-page .nf-float > .nff {
  margin: 0;
  padding: 12px 14px 10px;
  border: 1px solid var(--nf-chip-border);
  border-radius: 16px;
  background: var(--nf-surface-solid);
  box-shadow: var(--nf-chip-shadow);
  max-height: calc(100vh - var(--header-height, 50px) - 220px);
  max-height: calc(100svh - var(--header-height, 50px) - 220px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

body.neural-familiar-page .nf-float > #nfFamilyFloat:not([hidden]) ~ #nfFirstRun { display: none; }

/* the card's tail points at Feed: the first-run and return cards' only */
body.neural-familiar-page:not([data-nf-card="first-run"]):not([data-nf-card="return"]) .nf-float::after { display: none; }

/* ── the plate's family words (wave 4): "· gen 5" / "· season-born", and a
   running season's "· season · gen 4 of 18" (seasons-panel.js) ── */
body.neural-familiar-page .nf-plate .nf-plate-gen[hidden],
body.neural-familiar-page .nf-plate .nf-plate-season[hidden] { display: none; }
body.neural-familiar-page .nf-plate .nf-plate-season::before { content: ' · '; }
/* while a season runs its words get their own line: the one-line subtitle
   cut "season · gen N of G" to "sea…" at 393 px (seasons-panel sets the flag) */
body.neural-familiar-page[data-nf-season] .nf-plate .nf-plate-season:not([hidden]) { display: block; overflow: hidden; text-overflow: ellipsis; }
body.neural-familiar-page[data-nf-season] .nf-plate .nf-plate-season::before { content: none; }

/* Vitals › Details: the family's one row spans both columns */
body.neural-familiar-page .nf-details .nf-detail-wide { grid-column: 1 / -1; }

/* ── Family: the Journal (wave 3's letters, lineage, keepsakes and
   milestones, folded under one heading) ── */
body.neural-familiar-page .nf-journal {
  margin: 14px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--nf-hairline);
}

body.neural-familiar-page .nf-journal-h {
  display: block;
  margin: 0 0 4px;
  font: 600 0.75rem/1.2 var(--nf-sans);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--nf-muted);
}

/* while a creature's full card is open, the Family tab is that card */
body.neural-familiar-page #nfPanel-family[data-view="card"] #nfFamily,
body.neural-familiar-page #nfPanel-family[data-view="card"] .nf-journal { display: none; }

/* Tune › Start over: what Clear Memory does, under its button (§7.11) */
body.neural-familiar-page .nf-danger-hint { margin: 0.5rem 0 0; }

/* ── Seasons: one quiet line until seasons-panel.js mounts ── */
body.neural-familiar-page .nf-seasons-wait { margin: 4px 0; }
body.neural-familiar-page #nfSeasons:not([hidden]) + .nf-seasons-wait { display: none; }

/* ───────────────────────── the sheet: desktop = a docked column ───────────────────────── */
body.neural-familiar-page #nfHud {
  position: fixed;
  z-index: 30;
  top: calc(var(--header-height, 50px) + 12px);
  right: calc(12px + var(--nf-sa-r));
  bottom: calc(12px + var(--nf-dock-h));
  left: auto;
  width: var(--nf-side);
  height: auto;
  max-height: none;
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--nf-panel-border);
  border-bottom: 0;
  border-radius: 16px 16px 0 0;
  background:
    linear-gradient(var(--nf-time-tint), var(--nf-time-tint)),
    var(--nf-sheet-bg);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18);
}

body.neural-familiar-page #nfHud > * { flex: none; }

/* the one scroller takes what is left and scrolls (flex:none above would let
   it grow past the sheet, and the sheet's overflow would slice it) */
body.neural-familiar-page #nfHud > .nf-sheet-body { flex: 1 1 auto; min-height: 0; }

body.neural-familiar-page #nfHud.is-dragging { transition: none; }

body.neural-familiar-page .hud-drawer-handle { display: none; }

/* ── the status strip: three ruled readouts, no boxes ── */
body.neural-familiar-page .nf-strip {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1fr) minmax(0, 1.3fr);
  gap: 0;
  margin: 0;
  padding: 14px calc(var(--nf-gutter) + var(--nf-sa-r)) 12px calc(var(--nf-gutter) + var(--nf-sa-l));
}

body.neural-familiar-page .nf-strip .nf-glance-card {
  min-width: 0;
  padding: 0 0 0 12px;
  border: 0;
  border-left: 1px solid var(--nf-hairline);
  border-radius: 0;
  background: none;
}

body.neural-familiar-page .nf-strip .nf-glance-card:first-child {
  padding-left: 0;
  border-left: 0;
}

body.neural-familiar-page .nf-strip .stat-label {
  margin: 0 0 3px;
  font: 600 0.75rem/1.2 var(--nf-sans);
  letter-spacing: 0.09em;
}

body.neural-familiar-page .nf-strip .stat-value {
  font: 400 1.0625rem/1.25 var(--nf-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

body.neural-familiar-page .nf-strip .energy-bar-container {
  height: 3px;
  margin: 6px 12px 0 0;
}

/* readouts snap; nothing in the instrument eases on its own (D11) */
body.neural-familiar-page .nf-strip .energy-bar-fill,
body.neural-familiar-page #nfHud .xp-bar-fill,
body.neural-familiar-page #nfHud .bond-bar-fill,
body.neural-familiar-page #nfHud .brain-stage-fill { transition: none; }

/* the mood is a question you can ask: a 44 px target around the word */
body.neural-familiar-page .nf-strip .nf-mood-chip {
  width: auto;
  max-width: 100%;
  /* V16: while no one is kept it reads "—", which left a 9 px target */
  min-width: var(--nf-tap);
  min-height: var(--nf-tap);
  margin: -12px 0;
  padding: 12px 0;
  text-underline-offset: 4px;
}

/* R21(d): while the bar is red the Energy cell says "Feed helps" on the
   value's own line, so the strip keeps its height; static, never animated
   (app.js _updateStripCues writes it only when the band changes) */
body.neural-familiar-page .nf-strip .nf-energy-cell {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 6px;
  align-items: baseline;
}
body.neural-familiar-page .nf-strip .nf-energy-cell > .stat-label,
body.neural-familiar-page .nf-strip .nf-energy-cell > .energy-bar-container { grid-column: 1 / -1; }
body.neural-familiar-page .nf-strip .nf-energy-hint {
  min-width: 0;
  overflow: hidden;
  font: 600 0.75rem/1.2 var(--nf-sans);
  color: var(--nf-text);
  white-space: nowrap;
}
body.neural-familiar-page .nf-strip .nf-energy-hint[hidden] { display: none; }

/* P3-S1: after a death, until a keep, one cue takes the dashes' place —
   who died and a 44 px door to the Family tab, where the memorial leads
   while the sheet is open. Same row height as the readouts it replaces. */
body.neural-familiar-page .nf-strip.is-dead > .nf-glance-card { display: none; }
body.neural-familiar-page .nf-strip .nf-strip-cue {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  min-width: 0;
  min-height: 48px;
  margin: 0;
  padding: 0 12px;
  border: 1px solid var(--nf-chip-border);
  border-radius: 12px;
  background: none;
  color: var(--nf-text);
  font: 600 0.875rem/1.25 var(--nf-sans);
  text-align: left;
  cursor: pointer;
}
body.neural-familiar-page .nf-strip .nf-strip-cue[hidden] { display: none; }
body.neural-familiar-page .nf-strip .nf-strip-cue-words { min-width: 0; }
body.neural-familiar-page .nf-strip .nf-strip-cue-go { flex: none; font-size: 1.125rem; }
body.neural-familiar-page .nf-strip .nf-strip-cue:focus-visible { outline: 2px solid var(--nf-text); outline-offset: 2px; }

/* ── tabs: text, and a 2 px rule under the active one ──
   Six since wave 4 (Vitals · Mind · Family · Seasons · Chat · Tune, D39):
   each takes its own width plus an equal share of the rest (flex-basis
   auto), so "Seasons" never truncates where "Mind" has room to give; they
   fit 375 px at 0.875rem (A33). Should a larger text size overflow the row,
   it scrolls sideways (no bar) with an end fade, and sheet.js keeps the
   selected tab in view (data-overflow: end | start | both). */
body.neural-familiar-page #nfHud .nf-tabs {
  display: flex;
  gap: 0;
  margin: 0;
  padding: 0 calc(8px + var(--nf-sa-r)) 0 calc(8px + var(--nf-sa-l));
  border-top: 1px solid var(--nf-hairline);
  border-bottom: 1px solid var(--nf-hairline);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}

body.neural-familiar-page #nfHud .nf-tabs::-webkit-scrollbar { display: none; }

body.neural-familiar-page #nfHud .nf-tabs[data-overflow="end"] {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
}

body.neural-familiar-page #nfHud .nf-tabs[data-overflow="start"] {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent);
}

body.neural-familiar-page #nfHud .nf-tabs[data-overflow="both"] {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 32px, #000 calc(100% - 32px), transparent);
}

body.neural-familiar-page #nfHud .nf-tabs .nf-tab {
  position: relative;
  flex: 1 0 auto;
  justify-content: center;
  min-width: 0;
  min-height: var(--nf-tap);
  padding: 0 7px;
  white-space: nowrap;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  transform: none;
  font: 600 0.875rem/1 var(--nf-sans);
  letter-spacing: 0.02em;
  color: var(--nf-muted);
}

body.neural-familiar-page #nfHud .nf-tabs .nf-tab.is-active { color: var(--nf-text); }

body.neural-familiar-page #nfHud .nf-tabs .nf-tab.is-active::after {
  content: '';
  position: absolute;
  left: 20%;
  right: 20%;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--nf-cyan);
}

body.neural-familiar-page #nfHud .nf-tabs .nf-tab:focus-visible { outline-offset: -3px; }

/* ── the scroller ── */
body.neural-familiar-page .nf-sheet-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 14px calc(var(--nf-gutter) + var(--nf-sa-r)) 8px calc(var(--nf-gutter) + var(--nf-sa-l));
  scroll-padding-top: 12px;
  scroll-padding-bottom: 32px;
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--nf-cyan-rgb), 0.25) transparent;
  /* a column, so the fade below can sit at the panel's bottom when the tab
     is shorter than the panel (it drew a band mid-panel, V6) */
  display: flex;
  flex-direction: column;
}

body.neural-familiar-page .nf-sheet-body > * { flex: none; }

/* Nothing is sliced at the bottom edge: the last row fades out above the
   dock and the panel's end scrolls clear of the fade. It ends in exactly the
   panel's own colour — the time tint over the sheet — so it never reads as a
   darker band. */
body.neural-familiar-page .nf-sheet-body::after {
  content: '';
  position: sticky;
  bottom: -8px;
  display: block;
  flex: none;
  height: 28px;
  margin: auto calc(-1 * (var(--nf-gutter) + var(--nf-sa-r))) -8px calc(-1 * (var(--nf-gutter) + var(--nf-sa-l)));
  background:
    linear-gradient(rgba(0, 0, 0, 0), var(--nf-time-tint, rgba(0, 0, 0, 0)) 85%),
    linear-gradient(rgba(0, 0, 0, 0), var(--nf-sheet-bg) 85%);
  pointer-events: none;
}

body.neural-familiar-page .nf-tab-panel { padding-bottom: 4px; }

/* section headers (collapsible) are 44 px rows with a hairline */
body.neural-familiar-page .training-viz-header {
  min-height: var(--nf-tap);
  margin: 0;
  padding: 0 0.1rem;
}

body.neural-familiar-page .training-viz-section { margin-bottom: 1rem; }

body.neural-familiar-page .nf-details { margin: 0 0 1.1rem; }

body.neural-familiar-page .nf-detail { min-height: 40px; }

/* A place name is a claim: "the north-west thicket" wraps rather than being
   cut to "the north-west th…" in a 103-px phone cell (V3, D20). */
body.neural-familiar-page #regionValue {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.25;
}

/* Vitals' second care group: the experiments, then quiet utilities */
body.neural-familiar-page .nf-care {
  gap: 8px;
  margin: 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--nf-hairline);
}

body.neural-familiar-page .nf-care-h { margin: 0 0 2px; }

body.neural-familiar-page .nf-care .nf-btn-care,
body.neural-familiar-page .nf-care .nf-btn-quiet {
  min-height: var(--nf-tap);
  font-size: 0.875rem;
}

/* ── Chat: the log first, the composer sticky at the panel's bottom ── */
body.neural-familiar-page .nf-chat-compose {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin: 12px calc(-1 * (var(--nf-gutter) + var(--nf-sa-r))) 0 calc(-1 * (var(--nf-gutter) + var(--nf-sa-l)));
  padding: 8px calc(var(--nf-gutter) + var(--nf-sa-r)) 8px calc(var(--nf-gutter) + var(--nf-sa-l));
  border-top: 1px solid var(--nf-hairline);
  background: var(--nf-sheet-bg);
}

body.neural-familiar-page .nf-chat-compose .chat-hints {
  flex-wrap: nowrap;
  gap: 6px;
  margin: 0 calc(-1 * (var(--nf-gutter) + var(--nf-sa-r))) 8px 0;
  padding-right: 32px;
  overflow-x: auto;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  /* the row runs on past the edge: say so with a fade, not a cut word */
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 32px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 32px), transparent);
}

body.neural-familiar-page .nf-chat-compose .chat-hints::-webkit-scrollbar { display: none; }

body.neural-familiar-page .nf-chat-compose .chat-hint { flex: none; }

body.neural-familiar-page .nf-chat-compose .chat-form { margin: 0; }

/* 48 px field at 16 px text: below 16 px iOS zooms the page on focus */
body.neural-familiar-page .chat-form input {
  min-height: 48px;
  font-size: 1rem;
}

body.neural-familiar-page .chat-form button { min-height: 48px; min-width: 64px; }

body.neural-familiar-page [data-nf-panel="chat"] .activity-log { margin-bottom: 0.6rem; }
body.neural-familiar-page [data-nf-panel="chat"] .nf-instinct:empty { display: none; }

/* ───────────────────────── the dock ───────────────────────── */
body.neural-familiar-page .nf-dock {
  position: fixed;
  z-index: 31;
  right: calc(12px + var(--nf-sa-r));
  bottom: 12px;
  left: auto;
  width: var(--nf-side);
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 1fr) var(--nf-tap);
  gap: 8px;
  padding: var(--nf-dock-pad) var(--nf-gutter) calc(var(--nf-dock-pad) + var(--nf-sa-b));
  border: 1px solid var(--nf-panel-border);
  border-top-color: var(--nf-hairline);
  border-radius: 0 0 16px 16px;
  background: var(--nf-sheet-bg);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18);
}

body.neural-familiar-page .nf-dock > button {
  min-width: 0;
  min-height: var(--nf-tap);
  margin: 0;
  padding: 0 0.5rem;
  border-radius: 12px;
  font: 700 0.9375rem/1 var(--nf-sans);
  letter-spacing: 0.02em;
  white-space: nowrap;
  transform: none;
}

body.neural-familiar-page .nf-dock > button:hover,
body.neural-familiar-page .nf-dock > button:active { transform: none; }

body.neural-familiar-page .nf-dock #feedBtn {
  width: auto;
  border: 0;
  color: #07131c;
  background: linear-gradient(135deg, var(--lab-accent, #67efff), var(--lab-accent-2, #6ef6a2));
  box-shadow: none;
}

body.neural-familiar-page .nf-dock .nf-dock-btn,
body.neural-familiar-page .nf-dock .nf-dock-more {
  border: 1px solid var(--nf-input-border);
  background: transparent;
  color: var(--nf-text);
  box-shadow: none;
}


/* the sign carries the meaning (a reward up / a reward down), not the colour */
body.neural-familiar-page .nf-dock-sign {
  display: inline-block;
  margin: 0 0 1px;
  font: 700 1.1rem/1 var(--nf-mono);
}

/* the sign and its word read as one: "+ Praise", not "+    Praise" */
body.neural-familiar-page .nf-dock .nf-dock-btn { gap: 5px; }

body.neural-familiar-page #praiseBtn .nf-dock-sign { color: var(--nf-mint); }
body.neural-familiar-page #scoldBtn .nf-dock-sign { color: var(--nf-warn); }

body.neural-familiar-page .nf-dock .nf-dock-more {
  padding: 0;
  font-size: 1.3rem;
  color: var(--nf-text);
}

body.neural-familiar-page .nf-dock > button:disabled { opacity: 0.55; }

/* ───────────────────────── the speech bubble ───────────────────────── */
body.neural-familiar-page .speech-bubble {
  z-index: 28;
  max-width: min(280px, 72vw);
  padding: 9px 12px 10px;
  border-radius: 14px;
  font: 500 0.9375rem/1.4 var(--nf-sans);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.22);
}

body.neural-familiar-page:not(.dark-mode) .speech-bubble {
  --nf-bubble-bg: rgba(250, 253, 251, 0.98);
}

/* the safe rect is shorter than the bubble (app.js updateBubblePosition):
   it would hang over the chrome, so it waits — the words are in the log */
body.neural-familiar-page .speech-bubble.visible.nf-nofit { visibility: hidden; }

/* ───────────────────────── targets: 44 px, real boxes ───────────────────────── */
body.neural-familiar-page .reward-preset-btn,
body.neural-familiar-page .log-filter-btn,
body.neural-familiar-page .chat-hint,
body.neural-familiar-page .reward-reset-btn,
body.neural-familiar-page .danger-zone-actions button,
body.neural-familiar-page .toggle-row {
  min-height: var(--nf-tap);
}

body.neural-familiar-page .log-filter-btn,
body.neural-familiar-page .reward-preset-btn { min-width: var(--nf-tap); }

body.neural-familiar-page .chat-hint,
body.neural-familiar-page .reward-preset-btn { display: inline-flex; align-items: center; }

body.neural-familiar-page .toggle-row input { width: 20px; height: 20px; }

/* the Training chart's series chips: real 44 px boxes (the audit counts boxes) */
body.neural-familiar-page .nf-chart-chip {
  min-height: var(--nf-tap);
  min-width: var(--nf-tap);
}

/* disclosure rows across the features: a 44 px hit row, ~28 px of layout */
body.neural-familiar-page .nf-mind-summary,
body.neural-familiar-page .nf-voice-summary,
body.neural-familiar-page .nfi-summary,
body.neural-familiar-page .nfch-summary,
body.neural-familiar-page .nfch-death-summary,
body.neural-familiar-page .nfch-letter-summary,
body.neural-familiar-page .nf-rcpt-summary,
body.neural-familiar-page .nfsc-summary,
body.neural-familiar-page .nfpg-slots-box > summary,
body.neural-familiar-page .nfc-summary,
body.neural-familiar-page .nfc-link {
  min-height: var(--nf-tap);
  margin-top: -8px;
  margin-bottom: -8px;
}

/* the features' small buttons inside the panel (Run now, Hold this move,
   Download the voice / the instinct, Promote, the brain file buttons) and
   the soundscape's switch row: real 44 px boxes */
body.neural-familiar-page #nfHud .lab-btn-sm,
body.neural-familiar-page .nf-mind-hold,
body.neural-familiar-page .nfi-load,
body.neural-familiar-page .nf-voice-btn,
body.neural-familiar-page .nfsc-head {
  min-height: var(--nf-tap);
}

/* range inputs: a 44 px row with the 4 px track drawn inside it */
body.neural-familiar-page .reward-slider {
  height: var(--nf-tap);
  background: linear-gradient(rgba(var(--nf-cyan-rgb), 0.22), rgba(var(--nf-cyan-rgb), 0.22)) center / 100% 4px no-repeat;
}

body.neural-familiar-page .reward-slider::-webkit-slider-thumb { width: 22px; height: 22px; }
body.neural-familiar-page .reward-slider::-moz-range-thumb { width: 22px; height: 22px; }

/* ───────────────────────── overlays (all sizes) ───────────────────────── */
/* death: "Start a new life" last, full width, 54 px (in thumb reach on a phone) */
body.neural-familiar-page .death-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

body.neural-familiar-page .death-actions button { min-height: var(--nf-tap); }

body.neural-familiar-page .death-actions .primary-btn {
  order: 3;
  grid-column: 1 / -1;
  min-height: 54px;
  font-size: 1rem;
}

body.neural-familiar-page .settings-guide-close,
body.neural-familiar-page .nfc-sheet .nfc-close {
  width: var(--nf-tap);
  height: var(--nf-tap);
}

/* ═════════════════ Phones (the drawer breakpoint, HUD_DRAWER_QUERY) ═════════════════ */
@media (max-width: 900px), (orientation: landscape) and (max-height: 520px) {
  :root {
    --nf-map: 88px;
  }

  /* nav: brand · Lab▾ (where we are) · Menu▾ (the rest) · the theme icon */
  body.neural-familiar-page .ds-sitenav-inner { padding: 0 4px 0 calc(var(--nf-gutter) - 2px); gap: 2px; }

  body.neural-familiar-page .ds-sitenav-links > a.ds-sitenav-link,
  body.neural-familiar-page .ds-sitenav-links > a.ds-sitenav-subscribe,
  body.neural-familiar-page .ds-sitenav-links > details.ds-nav-dd:not(.active):not(.nf-nav-more) {
    display: none;
  }

  body.neural-familiar-page .nf-nav-more { display: block; }

  body.neural-familiar-page details.ds-nav-dd > summary { padding: 0 0.55rem; font-size: 0.9375rem; }

  body.neural-familiar-page .ds-nav-dd-menu { min-width: 13rem; }

  /* the plate: fit to its words, ≤ 320 px, no eyebrow; the top-right of the
     world stays world */
  body.neural-familiar-page .nf-plate {
    top: calc(var(--header-height, 44px) + 8px);
    left: calc(12px + var(--nf-sa-l));
    max-width: min(320px, calc(100vw - 24px - var(--nf-sa-l) - var(--nf-sa-r)));
    padding: 6px 2px 8px 12px;
  }

  body.neural-familiar-page .nf-plate .panel-title { display: none; }
  body.neural-familiar-page .nf-plate .nf-guide-btn { grid-row: 2; }

  /* the text face holds the line to two rows in a 320 px plate */
  body.neural-familiar-page .nf-plate .nf-learning-line {
    margin-top: 4px;
    padding-top: 5px;
    font: 600 0.8125rem/1.35 var(--nf-sans);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.005em;
  }

  /* open: the plate keeps its name row; full: the sheet covers the world */
  body.neural-familiar-page[data-nf-sheet="half"] .nf-plate .nf-learning-line { display: none; }
  body.neural-familiar-page[data-nf-sheet="half"] .nf-plate { padding-top: 0; padding-bottom: 0; }
  body.neural-familiar-page[data-nf-sheet="full"] .nf-plate { visibility: hidden; }

  /* the sheet: an edge-to-edge bottom sheet resting on the dock */
  body.neural-familiar-page #nfHud {
    top: auto;
    left: 0;
    right: 0;
    bottom: var(--nf-dock-h);
    width: auto;
    height: var(--nf-half-h);
    border-left: 0;
    border-right: 0;
    border-radius: 20px 20px 0 0;
    box-shadow: var(--nf-chrome-shadow);
  }

  /* the sheet eases only in answer to a gesture: sheet.js adds the class
     after the first paint, so a remembered half sheet does not slide up on
     its own at load (D11) */
  body.neural-familiar-page.nf-sheet-anim #nfHud { transition: height 0.3s var(--nf-ease); }
  body.neural-familiar-page.nf-sheet-anim #nfHud.is-dragging { transition: none; }

  body.neural-familiar-page #nfHud.nf-full { height: var(--nf-full-h); }

  /* lowered: grabber + strip. sheet.js measures that natural height into
     --nf-peek-px, so peek <-> half eases between two definite heights (auto
     until the first measure, which snaps rather than eases) */
  body.neural-familiar-page #nfHud.is-peek {
    height: var(--nf-peek-px, auto);
    cursor: pointer;
  }

  body.neural-familiar-page #nfHud.is-peek .nf-tabs,
  body.neural-familiar-page #nfHud.is-peek .nf-sheet-body {
    display: none;
  }

  /* while lowered a tap anywhere on the strip opens the sheet */
  body.neural-familiar-page #nfHud.is-peek .nf-mood-chip { pointer-events: none; }

  /* the grabber: 24 px drawn, a real 44 px box reaching into the strip's
     label row (labels are not controls) */
  /* flex-start: a button centres its content, which dropped the pill onto
     the labels' row */
  body.neural-familiar-page .hud-drawer-handle {
    position: relative;
    z-index: 2;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    width: 100%;
    height: var(--nf-tap);
    margin: 0 0 -20px;
    padding: 0;
    border: 0;
    border-radius: 20px 20px 0 0;
    background: none;
    cursor: grab;
    touch-action: none;
  }

  body.neural-familiar-page .hud-drawer-handle::before {
    content: '';
    display: block;
    width: 36px;
    height: 4px;
    margin: 10px auto 0;
    border-radius: 999px;
    background: var(--nf-muted);
    opacity: 0.55;
  }

  body.neural-familiar-page .nf-strip {
    padding-top: 2px;
    touch-action: none;
  }

  /* the dock: full width at the very bottom, safe-area aware */
  body.neural-familiar-page .nf-dock {
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    padding: var(--nf-dock-pad) calc(var(--nf-gutter) + var(--nf-sa-r)) calc(var(--nf-dock-pad) + var(--nf-sa-b)) calc(var(--nf-gutter) + var(--nf-sa-l));
    border: 0;
    border-top: 1px solid var(--nf-hairline);
    border-radius: 0;
    box-shadow: none;
  }

  /* camera chrome: the band just above the sheet */
  body.neural-familiar-page .nf-cam-map {
    left: calc(12px + var(--nf-sa-l));
    bottom: calc(var(--nf-sheet-h, 148px) + 12px);
  }

  body.neural-familiar-page .nf-cam-ctrl {
    right: calc(12px + var(--nf-sa-r));
    bottom: calc(var(--nf-sheet-h, 148px) + 12px);
  }

  /* half: the band is short — keep zoom + Follow riding the sheet's edge,
     drop the map; full: no world band at all */
  body.neural-familiar-page:not([data-nf-sheet="peek"]) .nf-cam-map,
  body.neural-familiar-page[data-nf-sheet="full"] .nf-cam-ctrl {
    visibility: hidden;
  }

  /* the card floats above the strip, its tail pointing down at Feed; the
     map steps aside for the first minute and the controls rise above it */
  body.neural-familiar-page .nf-float {
    left: calc(12px + var(--nf-sa-l));
    right: calc(12px + var(--nf-sa-r));
    bottom: calc(var(--nf-sheet-h, 148px) + 10px);
    width: auto;
    max-width: 560px;
  }

  body.neural-familiar-page .nf-float::after {
    content: '';
    position: absolute;
    /* over Feed's centre: the dock's first column is 1.3 / 3.3 of its free width */
    left: calc(4px + (100vw - 100px) * 0.197 - 7px);
    bottom: -8px;
    width: 14px;
    height: 14px;
    border: 1px solid var(--nf-chip-border);
    border-top: 0;
    border-left: 0;
    background: var(--nf-sheet-bg);
    transform: rotate(45deg);
  }

  body.neural-familiar-page:not([data-nf-sheet="peek"]) .nf-float { display: none; }

  /* a family card fills the band between the plate and the strip: it may
     take what the plate's learning line and the camera pill leave (the
     card itself scrolls past that) */
  body.neural-familiar-page .nf-float > .nff {
    max-height: calc(100vh - var(--nf-sheet-h, 148px) - var(--header-height, 50px) - 160px);
    max-height: calc(100svh - var(--nf-sheet-h, 148px) - var(--header-height, 50px) - 160px);
  }

  /* the memorial, the extinction and the nest are the moment's subject: the
     plate keeps its name row while one is up (as on a short phone with any
     card, below) */
  body.neural-familiar-page[data-nf-sheet="peek"][data-nf-card="memorial"] .nf-plate .nf-learning-line,
  body.neural-familiar-page[data-nf-sheet="peek"][data-nf-card="extinct"] .nf-plate .nf-learning-line,
  body.neural-familiar-page[data-nf-sheet="peek"][data-nf-card="nest"] .nf-plate .nf-learning-line {
    display: none;
  }

  body.neural-familiar-page:not([data-nf-card="none"]) .nf-cam-map { visibility: hidden; }

  body.neural-familiar-page[data-nf-sheet="peek"]:not([data-nf-card="none"]) .nf-cam-ctrl {
    bottom: calc(var(--nf-sheet-h, 148px) + 10px + var(--nf-card-h, 0px) + 10px);
  }

  /* at full the world is gone: its words go to the log and the announcer */
  body.neural-familiar-page[data-nf-sheet="full"] .speech-bubble.visible { visibility: hidden; }

  /* the old drawer's lesson dock (nf-lesson-book.css sized it to the 86 px
     peek at bottom 10 px) sits on the new dock, over the strip */
  body.neural-familiar-page .nflb-dock {
    left: 0;
    right: 0;
    bottom: var(--nf-dock-h);
    height: auto;
    min-height: var(--nf-peek-h, 86px);
    border-radius: 20px 20px 0 0;
    border-bottom: 0;
  }

  /* dialogs become bottom sheets */
  body.neural-familiar-page .death-overlay {
    align-items: flex-end;
    padding: 0;
  }

  body.neural-familiar-page .death-card {
    width: 100%;
    max-height: calc(100svh - var(--nf-sa-t) - 16px);
    padding: 22px calc(var(--nf-gutter) + var(--nf-sa-r)) 0 calc(var(--nf-gutter) + var(--nf-sa-l));
    border-radius: 22px 22px 0 0;
    border-bottom: 0;
    text-align: left;
  }

  body.neural-familiar-page .death-card h2 { font-size: 1.375rem; }

  body.neural-familiar-page .death-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
    margin: 0 0 1rem;
    border-top: 1px solid var(--nf-hairline);
  }

  body.neural-familiar-page .death-stat {
    padding: 8px 0 9px;
    border: 0;
    border-bottom: 1px solid var(--nf-hairline);
    border-radius: 0;
    background: none;
  }

  body.neural-familiar-page .death-stat:not(:nth-child(3n + 1)) {
    padding-left: 12px;
    border-left: 1px solid var(--nf-hairline);
  }

  body.neural-familiar-page .death-stat .stat-value { font-size: 1rem; }

  body.neural-familiar-page .death-actions {
    position: sticky;
    bottom: 0;
    margin: 0 calc(-1 * (var(--nf-gutter) + var(--nf-sa-r))) 0 calc(-1 * (var(--nf-gutter) + var(--nf-sa-l)));
    padding: 12px calc(var(--nf-gutter) + var(--nf-sa-r)) calc(12px + var(--nf-sa-b)) calc(var(--nf-gutter) + var(--nf-sa-l));
    background: var(--nf-surface-solid);
    border-top: 1px solid var(--nf-hairline);
  }

  body.neural-familiar-page .settings-guide-modal {
    align-items: flex-end;
    padding: 0;
  }

  body.neural-familiar-page .settings-guide-card {
    width: 100%;
    max-height: calc(100svh - var(--nf-sa-t) - 12px);
    padding: 0 calc(var(--nf-gutter) + var(--nf-sa-r)) calc(16px + var(--nf-sa-b)) calc(var(--nf-gutter) + var(--nf-sa-l));
    border-radius: 22px 22px 0 0;
    border-bottom: 0;
  }

  body.neural-familiar-page .settings-guide-header {
    position: sticky;
    top: 0;
    z-index: 1;
    min-height: 56px;
    margin: 0 calc(-1 * (var(--nf-gutter) + var(--nf-sa-r))) 0 calc(-1 * (var(--nf-gutter) + var(--nf-sa-l)));
    padding: 6px calc(8px + var(--nf-sa-r)) 0 calc(var(--nf-gutter) + var(--nf-sa-l));
    background: var(--nf-surface-solid);
    border-bottom: 1px solid var(--nf-hairline);
  }

  body.neural-familiar-page .settings-guide-close { border: 0; font-size: 1.5rem; }

  body.neural-familiar-page .settings-guide-list li,
  body.neural-familiar-page .settings-guide-intro { font-size: 0.9375rem; }

  body.neural-familiar-page .ambient-widget {
    bottom: calc(10px + var(--nf-sa-b));
    right: calc(10px + var(--nf-sa-r));
    width: 110px;
  }

  /* V11: "Even-tempered · gen 1 · 11m 34s old" ran past the plate on a
     phone and was cut mid-age; it wraps to a second line instead */
  body.neural-familiar-page .nf-plate .panel-subtitle {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }

  /* L2: the upgrade card with "What changed" open is ~494 px tall on a
     phone; the zoom/Follow pill rode up over the plate. It steps aside
     until the card goes (as for the memorial). */
  body.neural-familiar-page[data-nf-sheet="peek"][data-nf-card="upgrade"] .nf-cam-ctrl { visibility: hidden; }
}

/* short phones (SE class): a smaller map; with the first-run card up the
   plate keeps only its name row (the card already says what the line says) */
@media (max-width: 900px) and (max-height: 740px) and (orientation: portrait) {
  :root { --nf-map: 76px; }

  body.neural-familiar-page[data-nf-sheet="peek"]:not([data-nf-card="none"]) .nf-plate .nf-learning-line {
    display: none;
  }

  body.neural-familiar-page[data-nf-sheet="peek"]:not([data-nf-card="none"]) .nf-plate {
    padding-top: 0;
    padding-bottom: 0;
  }

  /* the memorial is the moment's one subject: zoom and Follow step aside so
     it fits with its heirs (they are back with "Choose on the map") */
  body.neural-familiar-page[data-nf-sheet="peek"][data-nf-card="memorial"] .nf-cam-ctrl { visibility: hidden; }
  /* V4: the first-run card is wave 4's tallest (five lines); on a short
     phone the zoom/Follow pill sat on the familiar's name tag in half the
     samples. It steps aside until the card goes, as for the memorial. */
  body.neural-familiar-page[data-nf-sheet="peek"][data-nf-card="first-run"] .nf-cam-ctrl { visibility: hidden; }
  body.neural-familiar-page[data-nf-card="memorial"] .nf-float > .nff {
    max-height: calc(100vh - var(--nf-sheet-h, 148px) - var(--header-height, 50px) - 96px);
    max-height: calc(100svh - var(--nf-sheet-h, 148px) - var(--header-height, 50px) - 96px);
  }
}

/* ═════════════════ Landscape phones ═════════════════
   Height is the scarce axis: at rest ONE bottom bar (strip left, dock
   right); open, the sheet is a right-hand panel above the dock, so the world
   keeps its width. */
@media (orientation: landscape) and (max-height: 520px) {
  :root {
    --nf-side: min(400px, 48vw);
    --nf-map: 72px;
    --nf-dock-pad: 6px;
  }

  body.neural-familiar-page .nf-plate {
    top: calc(var(--header-height, 44px) + 6px);
    max-width: min(440px, calc(100vw - var(--nf-side) - 36px - var(--nf-sa-l)));
    padding: 4px 2px 6px 10px;
  }

  body.neural-familiar-page[data-nf-sheet] .nf-plate { visibility: visible; }
  body.neural-familiar-page .nf-plate .nf-learning-line { margin-top: 2px; padding-top: 4px; }

  /* the dock: bottom-right, as wide as the panel it sits under */
  body.neural-familiar-page .nf-dock {
    left: auto;
    right: 0;
    width: calc(var(--nf-side) + var(--nf-sa-r));
    padding-left: 12px;
    border-left: 1px solid var(--nf-hairline);
  }

  /* open: a right-hand panel from under the nav to the dock */
  body.neural-familiar-page #nfHud,
  body.neural-familiar-page #nfHud.nf-full {
    top: calc(var(--header-height, 44px) + 6px);
    right: 0;
    bottom: var(--nf-dock-h);
    left: auto;
    width: calc(var(--nf-side) + var(--nf-sa-r));
    height: auto;
    border-right: 0;
    border-left: 1px solid var(--nf-panel-border);
    border-radius: 18px 0 0 0;
    transition: none;
  }

  body.neural-familiar-page.nf-sheet-anim #nfHud { transition: none; }

  /* The bar's left half is the status strip, in BOTH states (pinned, D19):
     fixed to the bottom-left beside the dock, so it never moves when the
     panel opens, and the panel's height goes to the tabs and the body.
     (#nfHud has no transform or filter, so its fixed child escapes its
     overflow.) */
  body.neural-familiar-page #nfHud .nf-strip {
    position: fixed;
    z-index: 31;
    left: 0;
    right: calc(var(--nf-side) + var(--nf-sa-r));
    bottom: 0;
    height: var(--nf-dock-h);
    align-content: center;
    padding: 0 12px var(--nf-sa-b) calc(var(--nf-gutter) + var(--nf-sa-l));
    border-top: 1px solid var(--nf-hairline);
    background: var(--nf-sheet-bg);
  }

  body.neural-familiar-page[data-nf-sheet="peek"] #nfHud .nf-strip { cursor: pointer; touch-action: none; }
  /* at rest the folded panel's grabber sat wholly below the screen (V15): the
     bar opens it instead — a tap, an upward swipe (sheet.js) or the dock's ⋯ */
  body.neural-familiar-page #nfHud.is-peek .hud-drawer-handle { display: none; }
  /* the longest readouts ('melancholy', 'hunting food') fit even beside a
     59 px notch inset: a narrower Energy cell and 15 px values */
  body.neural-familiar-page #nfHud .nf-strip { grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.05fr) minmax(0, 1.3fr); }
  body.neural-familiar-page #nfHud .nf-strip .stat-value { font-size: 0.9375rem; }
  body.neural-familiar-page #nfHud .nf-strip .stat-label { margin-bottom: 1px; }
  body.neural-familiar-page #nfHud .nf-strip .energy-bar-container { margin-top: 3px; }

  /* at rest the panel itself folds away: only its strip shows, in the bar */
  body.neural-familiar-page #nfHud.is-peek {
    top: auto;
    bottom: 0;
    height: 0;
    border: 0;
    background: none;
    box-shadow: none;
  }

  /* open, the grabber is a fold chevron at the start of the tab row (tap
     or Esc folds the panel away; a 44 px box that overlaps no tab) */
  body.neural-familiar-page #nfHud .hud-drawer-handle {
    position: absolute;
    z-index: 3;
    top: 0;
    left: 0;
    width: var(--nf-tap);
    height: var(--nf-tap);
    margin: 0;
    align-items: center;
    border-radius: 18px 0 0 0;
    cursor: pointer;
  }

  body.neural-familiar-page #nfHud .hud-drawer-handle::before {
    width: 9px;
    height: 9px;
    margin: 0 0 0 -4px;
    border: solid var(--nf-text);
    border-width: 2px 2px 0 0;
    border-radius: 1px;
    background: none;
    opacity: 0.8;
    transform: rotate(45deg);
  }

  body.neural-familiar-page #nfHud .nf-tabs {
    padding-left: calc(var(--nf-tap) + 2px);
    border-top: 0;
  }

  /* open: the plate keeps its name row (as on a portrait phone at half) */
  body.neural-familiar-page[data-nf-sheet="side"] .nf-plate .nf-learning-line { display: none; }
  body.neural-familiar-page[data-nf-sheet="side"] .nf-plate { padding-top: 0; padding-bottom: 0; }

  /* camera chrome: in the band above the bar — the map bottom-left, zoom and
     Follow above the dock at rest, left of the panel when it is open */
  body.neural-familiar-page .nf-cam-map {
    left: calc(12px + var(--nf-sa-l));
    bottom: calc(var(--nf-sheet-h, 57px) + 10px);
  }

  body.neural-familiar-page .nf-cam-ctrl {
    right: calc(12px + var(--nf-sa-r));
    bottom: calc(var(--nf-sheet-h, 57px) + 10px);
  }

  body.neural-familiar-page[data-nf-sheet="side"] .nf-cam-map,
  body.neural-familiar-page[data-nf-sheet="side"] .nf-cam-ctrl {
    visibility: visible;
  }

  body.neural-familiar-page[data-nf-sheet="side"] .nf-cam-ctrl {
    right: calc(var(--nf-side) + var(--nf-sa-r) + 12px);
  }

  /* typing in a short panel: the suggestions step aside for the log */
  body.neural-familiar-page .nf-chat-compose:focus-within .chat-hints { display: none; }

  /* first visit: the card sits on the dock (bottom-right) in two columns, and
     the camera chrome steps aside for that minute */
  body.neural-familiar-page .nf-float {
    left: auto;
    right: calc(12px + var(--nf-sa-r));
    bottom: calc(var(--nf-dock-h) + 10px);
    width: min(520px, calc(100vw - 24px - var(--nf-sa-l) - var(--nf-sa-r)));
  }

  /* over Feed's centre: Feed is the dock's first column, ~60 px in from
     the dock's 12 px pad; the card ends 12 px from the edge, as the dock */
  body.neural-familiar-page .nf-float::after { left: auto; right: calc(var(--nf-side) - 91px); }

  /* a family card sits BESIDE the plate (as wide as the plate leaves), so it
     may use the whole height above the bar; it scrolls inside itself */
  body.neural-familiar-page:not([data-nf-card="first-run"]):not([data-nf-card="return"]) .nf-float {
    width: max(320px, calc(100vw - min(440px, calc(100vw - var(--nf-side) - 36px)) - 48px - var(--nf-sa-l) - var(--nf-sa-r)));
  }

  body.neural-familiar-page .nf-float > .nff,
  body.neural-familiar-page[data-nf-card="memorial"] .nf-float > .nff {
    max-height: calc(100vh - var(--header-height, 44px) - var(--nf-dock-h) - 28px);
    max-height: calc(100svh - var(--header-height, 44px) - var(--nf-dock-h) - 28px);
  }

  body.neural-familiar-page[data-nf-sheet="peek"]:not([data-nf-card="none"]) .nf-cam-ctrl { visibility: hidden; }

  body.neural-familiar-page .nf-float #nfFirstRun.nfc[data-kind="first-run"] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 14px;
    align-items: center;
    /* V1: wave 4's card has five lines; it scrolls inside itself instead of
       running off the top of a 393 px tall screen */
    max-height: calc(100vh - var(--header-height, 44px) - var(--nf-dock-h) - 28px);
    max-height: calc(100svh - var(--header-height, 44px) - var(--nf-dock-h) - 28px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* every line in the text column (auto-placement dropped the 4th line into
     the buttons' column, which widened to 429 px: V1) */
  body.neural-familiar-page .nf-float #nfFirstRun[data-kind="first-run"] > :not(.nfc-actions) { grid-column: 1; }

  body.neural-familiar-page .nf-float #nfFirstRun[data-kind="first-run"] .nfc-actions {
    grid-column: 2;
    grid-row: 1 / span 5; /* lead, body, keep, try, view: the text column's rows */
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    margin: 0;
  }

  body.neural-familiar-page .nf-float #nfFirstRun .nfc-lead { font-size: 0.875rem; }
  body.neural-familiar-page .nf-float #nfFirstRun .nfc-line { font-size: 0.8125rem; }

  body.neural-familiar-page .nflb-dock {
    right: calc(var(--nf-side) + var(--nf-sa-r));
    bottom: 0;
    border-radius: 0;
  }

  /* dialogs: centred cards, the height is too short for a sheet */
  body.neural-familiar-page .death-overlay,
  body.neural-familiar-page .settings-guide-modal {
    align-items: center;
    padding: 8px;
  }

  body.neural-familiar-page .death-card,
  body.neural-familiar-page .settings-guide-card {
    width: min(620px, 100%);
    max-height: calc(100svh - 16px);
    border-radius: 18px;
    border-bottom: 1px solid var(--nf-panel-border);
  }

  body.neural-familiar-page .death-card { padding-top: 16px; }

  body.neural-familiar-page .death-actions {
    grid-template-columns: 1fr 1fr 2fr;
    padding-bottom: 12px;
  }

  body.neural-familiar-page .death-actions .primary-btn { grid-column: auto; }

  body.neural-familiar-page .ds-nav-dd-menu {
    max-height: calc(100svh - var(--header-height, 44px) - 12px);
  }

  /* the Menu in three columns, so the whole list fits a short screen (it
     showed 7 of 13 links, the last one sliced, with no sign of more — V7;
     two columns still left the last row 13 px short on 852×393) */
  body.neural-familiar-page .nf-nav-more-menu {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-content: start;
    min-width: min(38rem, calc(100vw - 24px - var(--nf-sa-l) - var(--nf-sa-r)));
  }

  body.neural-familiar-page .nf-nav-more-menu .nf-nav-more-h { grid-column: 1 / -1; }
}

/* Typing in Chat with the keyboard up (interactive-widget=resizes-content
   shrinks the layout viewport): a portrait screen this short left ~2 lines
   of log under the nav, strip, tabs, filters, composer and dock (V9). While
   the field has focus the dock and the log filters step aside; they are
   back the moment it blurs. */
@media (orientation: portrait) and (max-height: 560px) and (max-width: 900px) {
  body.neural-familiar-page[data-nf-typing] {
    --nf-dock-h: 0px;
    /* re-declared here so they resolve against this --nf-dock-h */
    --nf-half-h: calc(max(320px, 52svh) - var(--nf-dock-h));
    --nf-full-h: calc(100svh - var(--header-height, 44px) - 8px - var(--nf-dock-h));
  }
  body.neural-familiar-page[data-nf-typing] .nf-dock,
  body.neural-familiar-page[data-nf-typing] .log-filters,
  body.neural-familiar-page[data-nf-typing] .nf-chat-compose .chat-hints { display: none; }
}

/* ═════════════════ calm ═════════════════ */
@media (prefers-reduced-motion: reduce) {
  body.neural-familiar-page.nf-sheet-anim #nfHud,
  body.neural-familiar-page #nfHud,
  body.neural-familiar-page .nf-dock,
  body.neural-familiar-page .speech-bubble,
  body.neural-familiar-page .nf-cam-map,
  body.neural-familiar-page .nf-cam-ctrl {
    transition: none;
  }
}

/* Ambient mode: app.js hides the panel and the world; the chrome goes too. */
body.neural-familiar-page #ambientWidget:not([hidden]) ~ .nf-plate,
body.neural-familiar-page #ambientWidget:not([hidden]) ~ .nf-cam,
body.neural-familiar-page #ambientWidget:not([hidden]) ~ .nf-float,
body.neural-familiar-page #ambientWidget:not([hidden]) ~ .nf-dock {
  display: none;
}
