/* INK TIDE — the page's single stylesheet (SPEC §10 HUD and build drawer, §9.4 report, §13 accessibility, §17 CH-04 gate, §19.3, D.9; CONTRACT §0.8 theme tokens, §8 UI). Dark glass and white sans text over the paper-and-ink room. */

/* ---- tokens (light) ---- */
:root {
  --ink: #0b0e14;
  --paper: rgba(0, 0, 0, 0.2);
  --paper-2: rgba(255, 255, 255, 0.08);
  --fg: #ffffff;
  --bg: #14161a;
  --line: rgba(255, 255, 255, 0.6);
  --accent: #e3934f;
  --accent-2: #9db58c;
  --accent-soft: rgba(227, 147, 79, 0.34);
  --accent-ink: #fde6cf;
  --on-accent: #0b0e14;
  --muted: #e2e2e2;
  --ok: #a8d095;
  --fail: #f09a76;
  --halo: rgba(0, 0, 0, 0.2);
  --scrim: rgba(11, 14, 20, 0.55);
  --scrim-strong: rgba(11, 14, 20, 0.86);
  --hud-ink: #ffffff;
  --hud-halo: rgba(0, 0, 0, 0.2);
  --hud-accent: #e3934f;
  /* the dial's and the pose badges' halo: dark enough that white ink holds 3:1 over the brightest paper wall (owner, 2026-10-22) */
  --dial-halo: rgba(11, 14, 20, 0.62);
  /* one light sans for everything (owner: dark glass, white sans text); numbers keep tabular figures */
  --font-body: 'Atkinson Hyperlegible', 'Segoe UI', Roboto, 'Helvetica Neue', system-ui, sans-serif;
  --font-display: var(--font-body);
  --font-data: var(--font-body);
  --radius: 14px 18px 12px 16px;
  --radius-sm: 10px 13px 9px 12px;
  --radius-xs: 7px 9px 6px 8px;
  --border: 1.5px solid var(--line);
  /* the app frame (owner, 2026-10-21: everything fits in 100dvh on a phone). The root never scrolls, so the toolbar never collapses
     and the page is laid out for the small viewport. --app-h follows the dynamic viewport where the browser has it, and is the
     frame's own 100% where it does not. Never 100vh: that is the large viewport, taller than the screen while the toolbar shows */
  --app-h: 100%;
  /* the safe areas, once: .ui, .boot and the holders read these, so an e2e test can fake a notch by setting them on :root */
  --inset-t: env(safe-area-inset-top, 0px);
  --inset-r: env(safe-area-inset-right, 0px);
  --inset-b: env(safe-area-inset-bottom, 0px);
  --inset-l: env(safe-area-inset-left, 0px);
  --gutter-l: max(16px, var(--inset-l));
  --gutter-r: max(16px, var(--inset-r));
  /* the space between a card and its holder, the card's padding, and the gap between its cards and rows; the height tiers tighten these */
  --frame-gap: 12px;
  --pad-y: 18px;
  --pad-x: 20px;
  --gap: 10px;
  /* touch targets: 40 px buttons and 30 px small controls with a mouse; 40 px for every control on a coarse pointer (below) */
  --tap: 40px;
  --tap-sm: 30px;
  /* the phone sheets (build drawer) take a share of the fixed frame; the folded drawer's strip sits above the home indicator */
  --sheet-h: min(64%, 520px);
  --peek: calc(33px + var(--inset-b));
  /* the room kept above the touch dial for the thermostat's chip (SPEC §5.5 TH-11): 0 until that chip shows. The subtitle
     floors below add it (and input.js's dial-menu badge is to), so the chip, the badge and the lines stack, never collide */
  --dial-chip-h: 0px;
  /* the thermostat's sweet spot (SPEC §5.5 TH-12): the comfortable range's slice, at fill-opacity 0.3; the same in both themes, as
     it sits over the room (no theme block below redefines it) */
  --thermo-band: #ffd400;
  --ease: cubic-bezier(0.33, 0.9, 0.4, 1);
  /* menus are frosted glass: a 4 px backdrop blur under a 20 % black tint, lifted by a soft two-layer shadow (owner, 2026-10-21) */
  --glass: rgba(0, 0, 0, 0.2);
  --glass-blur: 4px;
  --glass-shadow: 0 18px 44px rgba(0, 0, 0, 0.22), 0 4px 12px rgba(0, 0, 0, 0.12);
  color-scheme: dark;
}
/* a dv* length only behind @supports: an unknown unit in a custom property would drop the whole declaration */
@supports (height: 100dvh) { :root { --app-h: 100dvh; } }
@media (pointer: coarse) { :root { --tap-sm: 40px; --peek: calc(44px + var(--inset-b)); } }
@media (max-width: 480px) { :root { --pad-y: 14px; --pad-x: 14px; --gap: 8px; } }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: rgba(0, 0, 0, 0.2);
    --paper-2: rgba(255, 255, 255, 0.08);
    --fg: #ffffff;
    --bg: #14161a;
    --line: rgba(255, 255, 255, 0.6);
    --accent: #e3934f;
    --accent-2: #9db58c;
    --accent-soft: rgba(227, 147, 79, 0.34);
    --accent-ink: #fde6cf;
    --on-accent: #0b0e14;
    --muted: #e2e2e2;
    --ok: #a8d095;
    --fail: #f09a76;
    --halo: rgba(0, 0, 0, 0.2);
    --scrim: rgba(11, 14, 20, 0.55);
    --scrim-strong: rgba(11, 14, 20, 0.86);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --paper: rgba(0, 0, 0, 0.2);
  --paper-2: rgba(255, 255, 255, 0.08);
  --fg: #ffffff;
  --bg: #14161a;
  --line: rgba(255, 255, 255, 0.6);
  --accent: #e3934f;
  --accent-2: #9db58c;
  --accent-soft: rgba(227, 147, 79, 0.34);
  --accent-ink: #fde6cf;
  --on-accent: #0b0e14;
  --muted: #e2e2e2;
  --ok: #a8d095;
  --fail: #f09a76;
  --halo: rgba(0, 0, 0, 0.2);
  --scrim: rgba(11, 14, 20, 0.55);
  --scrim-strong: rgba(11, 14, 20, 0.86);
  color-scheme: dark;
}

/* ---- page: one screen, the canvas fixed behind the UI layers ---- */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: var(--app-h); margin: 0; overscroll-behavior: none; }   /* no rubber band or pull-to-refresh behind the app */
html { background: var(--bg); }
body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.4;
  overflow: hidden;
  -webkit-text-size-adjust: 100%;
}
[hidden] { display: none !important; }
#view { position: fixed; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; background: var(--bg); }
.ui {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: grid;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  padding-left: var(--gutter-l);
  padding-right: var(--gutter-r);
  pointer-events: none;
  /* clip, where the browser has it, so .ui is no scroll container: a focus() or scrollIntoView can never slide the UI off the
     canvas (the closed side drawer made #ui 1221 px wide at 844) */
  overflow: hidden;
  overflow: clip;
}
.layer { grid-area: 1 / 1; position: relative; min-width: 0; min-height: 0; pointer-events: none; }
/* menus scroll but never pinch- or double-tap-zoom (owner) */
.ui, .ui .panel, .menu, .report, .a11y, .gate, .drawer, .hud, .screen-body { touch-action: pan-x pan-y; }
/* stacking: each layer is its own context, so fixed children (the touch controls) stay under the menus */
#hud { z-index: 2; }
#studio { z-index: 3; }
#subtitles { z-index: 4; }
#touch { z-index: 5; }
#drawer { z-index: 6; }
#report { z-index: 7; }
#menu { z-index: 8; }
#a11y { z-index: 9; }
#tests { z-index: 10; }
#gate { z-index: 11; }
#boot { z-index: 12; }
/* under a full-screen card the touch layer stands down (its dial wheel showed through the scrim under set and pause on phones) */
.ui:has(> #menu:not([hidden]) > .menu:not([hidden]), > #report:not([hidden]) > .report:not([hidden]), > #a11y:not([hidden]) > .a11y:not([hidden]), > #gate:not([hidden]) > .gate:not([hidden]), > #tests:not([hidden]), > #ending:not([hidden])) > #touch { visibility: hidden; }
/* a card opened over another (settings over a menu or the report, the tests over anything, field notes over the report, the
   ending card over spend, set or the report): the one underneath steps out while it is open and is back as it was when it
   closes, so two layers of white text never read through each other's 20 % glass; the paused sitting's HUD chips and line
   cards step out under settings too. visibility, not hidden: the screen under it keeps its state, and nothing in it takes
   focus (the spend screen's put-in buttons stayed focusable under the ending's scrim) */
.ui:has(> #a11y:not([hidden]) > .a11y:not([hidden])) > :is(#hud, #subtitles, #menu, #report, #ending),
.ui:has(> #ending:not([hidden])) > :is(#hud, #subtitles, #menu, #report),
.ui:has(> #tests:not([hidden])) > :is(#hud, #subtitles, #drawer, #studio, #menu, #report, #ending, #wardrobe, #a11y),
.ui:has(> #tests:not([hidden])) .drawer.open,
.ui:has(> #menu:not([hidden]) > .menu:not([hidden])) > #report { visibility: hidden; }
/* the build sheet over the touch dial wheel (a phone: the wheel shows through its glass, and the dial does nothing in build) */
.ui:has(> #drawer .drawer.open) > #touch .dial-wheel { visibility: hidden; }
/* Make Art keeps the wheel: the dial still turns the sitting's gain at the easel (main.js passes it through, and the ghost reads
   it; SPEC D.4.3), so a phone's wheel stays live there (a laptop's art-only layer has none) */
/* the HUD's buttons step out under a menu card and under Make Art, so Tab never lands behind the scrim or the desk (the view
   switch, make art and heat took focus under pause, pose and the studio); the ring, the clock and the pose glyph still read
   through. The build drawer is no .menu, so heat stays live beside it */
.ui:has(> #menu:not([hidden]) > .menu:not([hidden]), > #studio:not([hidden])) > #hud :is(.hud-view, .hud-actions) { visibility: hidden; }
.boot {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 0 var(--gutter-r) 0 var(--gutter-l);
  background: var(--bg);
  color: var(--muted);
  font-family: var(--font-display);
  font-size: 20px;
  text-align: center;
  pointer-events: auto;
  transition: opacity 0.4s var(--ease);
}
.boot.done { opacity: 0; pointer-events: none; }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

/* ---- type ---- */
h1, h2, h3 { font-family: var(--font-display); font-weight: 600; margin: 0 0 8px; line-height: 1.15; }
h1 { font-size: 30px; }
h2 { font-size: 22px; }
h3 { font-size: 17px; margin-top: 12px; }
p { margin: 0 0 10px; }
.muted { color: var(--muted); }
.small { font-size: 13px; }
.num, .budget, .cost, .countdown, .tally, .totals, .hud-clock, .test-detail, .test-summary, .remap-key, .range-val, .tally-chip { font-variant-numeric: tabular-nums; }
.data { font-family: var(--font-data); font-size: 13px; }
.lede { font-family: var(--font-display); font-size: 18px; line-height: 1.3; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* cards that take focus only so screen readers land inside them: no ring around the whole card, controls keep theirs */
.panel:focus, .panel:focus-visible { outline: none; }

/* ---- menu cards: frosted glass (4 px blur, 20 % black) with a 1.5 px ink border, a faint second pen line and a soft shadow ---- */
.panel {
  position: relative;
  background: var(--glass);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  box-shadow: var(--glass-shadow);
  /* inside the glass the palette is light on dark in either theme (the 20 % black tint reads as a dark surface) */
  --fg: #ffffff;
  --muted: #e2e2e2;
  --line: rgba(255, 255, 255, 0.6);
  --border: 1.5px solid var(--line);
  --paper-2: rgba(255, 255, 255, 0.08);
  --accent: #e3934f;
  --accent-2: #9db58c;
  --accent-soft: rgba(227, 147, 79, 0.34);
  --accent-ink: #fde6cf;
  --on-accent: #0b0e14;
  --ok: #a8d095;
  --fail: #f09a76;
  color-scheme: dark;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  color: var(--fg);
  border: var(--border);
  border-radius: var(--radius);
  padding: var(--pad-y) var(--pad-x);
  pointer-events: auto;
  max-width: 100%;
  min-width: 0;
}
.panel::after {
  content: '';
  position: absolute;
  inset: 2px 3px 3px 2px;
  border: 1px solid var(--line);
  border-radius: 12px 16px 10px 14px;
  opacity: 0.18;
  pointer-events: none;
}
.panel > header { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 10px; }
.panel > header h2 { margin: 0; flex: 1 1 auto; min-width: 0; }

/* full-screen holders for the cards: a paper scrim over the room, the card centred and scrollable */
.menu, .report, .a11y, .gate {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  overflow: auto;
  overscroll-behavior: contain;
  padding: calc(var(--frame-gap) + var(--inset-t)) 0 calc(var(--frame-gap) + var(--inset-b));
  pointer-events: auto;
}
.menu::before, .report::before, .a11y::before, .gate::before { content: ''; position: fixed; inset: 0; background: var(--scrim); pointer-events: auto; }
.gate::before { background: var(--scrim-strong); }
.menu > .panel, .report > .panel, .a11y > .panel, .gate > .panel { max-height: 100%; overflow: auto; overscroll-behavior: contain; }
/* every menu screen, the report and settings are one frame (owner, 2026-10-21) once their render builds header / .screen-body /
   .screen-foot: the header stays put, the body scrolls only when its list is long, and the foot holds the status line and the
   screen's actions and never scrolls away. DOM order is header, body, foot, so Tab order follows what you see. Without :has()
   the card scrolls as one block, as before */
.menu > .panel.screen:has(> .screen-body), .report > .panel.postcard:has(> .screen-body), .a11y > .panel:has(> .screen-body) { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; }
/* the same frame by class, for Firefox < 121 and Safari < 15.4: its own rule, as one unknown :has() would drop a whole selector list */
.menu > .panel.screen.framed, .report > .panel.postcard.framed, .a11y > .panel.framed { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; }
/* scroll-padding: a Tab or a gamepad focus() into the body never stops flush against its clipped edge */
.screen-body { min-height: 0; overflow: auto; overscroll-behavior: contain; scroll-padding-block: 8px; margin: 0 calc(-1 * var(--pad-x)); padding: 2px var(--pad-x); }
.screen-body > :first-child { margin-top: 0; }
.screen-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px 10px; margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--muted); }
.screen-foot > .menu-status { flex: 1 1 100%; min-height: 0; margin: 0; }
.screen-foot > .row, .screen-foot > .tools { margin: 0; padding: 0; border: 0; }
/* a 'more' row: a native details, so its summary takes Enter and Space with no script; refresh() keeps it open or closed (data-disclosure) */
details.more { margin: var(--gap) 0 0; }
details.more > summary { list-style: none; display: flex; align-items: center; gap: 8px; min-height: var(--tap-sm); cursor: pointer; color: var(--muted); font-size: 14px; }
details.more > summary::-webkit-details-marker { display: none; }
details.more > summary::before { content: '▸'; }
details.more[open] > summary::before { content: '▾'; }
/* the extra words of a label: always in the text (tests read /back to rooms/) and read aloud, but shown only on wider screens */
@media (max-width: 400px) { .lbl-x { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } }
/* a foot's actions keep one row up to 560 px wide and on a landscape phone ('rooms', 'building', 'start': with every word they
   took two rows at 412 px and at 667 x 375) */
@media (max-width: 560px), (orientation: landscape) and (max-height: 500px) { .screen-foot .lbl-x { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } }

/* ---- buttons, chips, fields ---- */
.btn {
  font: inherit;
  font-family: var(--font-body);
  background: var(--paper-2);
  color: var(--fg);
  border: var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  min-height: 40px;
  cursor: pointer;
  pointer-events: auto;
  transition: background 0.15s var(--ease), transform 0.15s var(--ease);
}
.btn:hover { background: var(--accent-soft); }
.btn:active { transform: translateY(1px); }
.btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--line); font-weight: 700; }
/* hover keeps the dark text on the full accent (white on accent-soft was 2.64:1 over a lit room) and adds a soft ring */
.btn.primary:hover { background: var(--accent); color: var(--on-accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.btn.ghost { background: transparent; border-color: var(--muted); color: var(--fg); }
.btn.ghost:hover { border-color: var(--line); background: var(--paper-2); }
.btn.small { min-height: 30px; padding: 3px 10px; font-size: 14px; }
.btn.link { background: none; border: none; min-height: 0; padding: 2px 0; color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
.btn.link:hover { color: var(--fg); background: none; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.5; cursor: default; transform: none; }
.btn[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }
.row { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; }
.row.end { justify-content: flex-end; margin-top: 10px; }
.chip {
  display: inline-block;
  font-family: var(--font-data);
  font-size: 11px;
  line-height: 1.5;
  padding: 0 6px;
  border: 1px solid var(--muted);
  border-radius: var(--radius-xs);
  color: var(--muted);
  white-space: nowrap;
}
.chip.accent { border-color: var(--accent); color: var(--accent-ink); }
.chip.lock { border-style: dashed; }
.field { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; padding: 7px 0; border-bottom: 1px dashed var(--muted); }
.field:last-child { border-bottom: none; }
.field > label { min-width: 0; }
.field .hint { grid-column: 1 / -1; font-size: 13px; color: var(--muted); }
.field.note-row .note-label { grid-column: 1 / -1; font-size: 14px; }
/* settings: a group's notes under its controls as quiet hint lines, 'colour: the palettes are checked …' (a11y.js) */
.a11y .field.note-row { display: block; padding: 3px 0; border-bottom: 0; font-size: 13px; color: var(--muted); }
.a11y .field.note-row .note-label { font-size: 13px; color: var(--fg); }
.a11y .field.note-row .note-label::after { content: ': '; }
.field input[type="checkbox"] { width: 22px; height: 22px; accent-color: var(--accent); }
.field input[type="range"] { width: min(100%, 160px); accent-color: var(--accent); }
select { font: inherit; font-size: 14px; background: var(--paper-2); color: var(--fg); border: var(--border); border-radius: var(--radius-xs); padding: 4px 8px; min-height: 30px; max-width: 100%; }
.range { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 10px; align-items: center; padding: 5px 0; font-size: 14px; }
.range .range-val { font-family: var(--font-data); font-size: 12px; color: var(--muted); }
.range input { grid-column: 1 / -1; width: 100%; accent-color: var(--accent); }
.range input:disabled { opacity: 0.4; }
/* the pose screen's sitting depth (Appendix G.2): full width up to 360 px with a 44 px touch target; pan-y keeps a vertical
   swipe scrolling the menu while a horizontal drag moves the thumb, and still no pinch zoom */
.range.depth { padding: 6px 0 0; }
.range.depth > :not(label):not(output) { grid-column: 1 / -1; }
.range.depth input[type="range"] { max-width: 360px; height: 44px; margin: 0; touch-action: pan-y; }
.range.depth .depth-presets { justify-self: start; flex-wrap: nowrap; }   /* the five presets on one line (5 x 44 px fits a 320 px phone) */
.range.depth .depth-presets .btn { min-width: 44px; padding: 4px 8px; }
.range.depth .depth-words { margin: 4px 0 0; min-height: 2.7em; }   /* two lines held, so the frame does not jump while the thumb moves */
.range.depth .muted.small { margin: 0; }
.seg { display: inline-flex; flex-wrap: wrap; border: var(--border); border-radius: var(--radius-sm); overflow: hidden; max-width: 100%; }
.seg .btn { border: none; border-radius: 0; min-height: 36px; background: transparent; }
.seg .btn + .btn { border-left: var(--border); }
.seg .btn[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }
.tabs { display: flex; flex-wrap: wrap; gap: 4px 6px; margin: 8px 0; }
.tab { font: inherit; font-size: 14px; background: transparent; color: var(--muted); border: 1px solid transparent; border-radius: var(--radius-sm); padding: 4px 10px; min-height: 32px; cursor: pointer; }
.tab:hover { color: var(--fg); }
.tab[aria-selected="true"] { color: var(--fg); border-color: var(--line); background: var(--paper-2); }
/* the drawer's tabs over the live room (no scrim): white labels, the chosen one marked by its border and fill (muted ones read
   3.75 to 4.45:1 in the side drawer) */
.drawer-tabs .tab { color: var(--fg); }

/* ---- cards (shells, rooms, poses, items, tiers) ---- */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: var(--gap); margin: var(--gap) 0; }
.card {
  position: relative;
  font: inherit;
  text-align: left;
  background: var(--paper-2);
  color: var(--fg);
  border: var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  cursor: pointer;
  pointer-events: auto;
  display: grid;
  align-content: start;
  gap: 4px;
  min-width: 0;
}
button.card:hover { background: var(--accent-soft); }
.card[aria-pressed="true"], .card.selected { outline: 2px solid var(--accent); outline-offset: -2px; }
.card.locked { background: transparent; border-style: dashed; color: var(--muted); }
button.card.locked:hover { background: var(--paper-2); }
/* the build drawer has no scrim over the live room: a locked card there takes a darker local glass, so its muted name and chips
   hold 4.5:1 over a lamp-lit wall (3.3 to 3.6 on a transparent card) */
.drawer .card.locked, .drawer button.card.locked:hover { background: rgba(0, 0, 0, 0.35); }
.drawer button.card.locked:hover { border-color: var(--fg); }
.card.armed { outline: 2px dashed var(--accent); outline-offset: -2px; color: var(--fg); }
.card-title { font-family: var(--font-display); font-size: 17px; line-height: 1.2; overflow-wrap: anywhere; }
.card-read { font-family: var(--font-display); font-style: italic; font-size: 14px; line-height: 1.3; color: var(--muted); overflow-wrap: anywhere; }
.card-meta { font-size: 13px; color: var(--muted); display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; }
.card > .chip, .card > .btn { justify-self: start; }
.card svg { width: 32px; height: 32px; }
.tier-card { cursor: default; }
.tier-card.open { border-color: var(--accent); }

/* ---- HUD (SPEC §10): almost nothing ---- */
.hud { position: absolute; inset: 0; pointer-events: none; color: var(--hud-ink); }
.hud.build .hud-dial, .hud.build .hud-pose { opacity: 0; }
.hud-dial { position: absolute; left: 50%; bottom: calc(18px + var(--inset-b)); width: 96px; height: 96px; transform: translateX(-50%); overflow: visible; transition: opacity 0.4s var(--ease); }
/* one dial on phones (owner, 2026-10-22): the touch wheel carries the gain face (ui/dialface.js), so this read-only ring stands
   down whenever that wheel shows; with no face docked it is lifted clear of the wheel as before. One-hand mode keeps its
   rules: the wheel hides there, and the ring shows */
:root:has(#touch.ink-touch:not(.art-only)) .hud-dial { bottom: calc(116px + var(--inset-b)); }
:root:has(#touch.ink-touch:not(.art-only):not(.one-hand) .dial-wheel.has-gain) .hud-dial { display: none; }
/* in one-hand mode, with no wheel under it, the ring takes the wheel's low slot: lifted, it ran into the dial-menu badge at 120 px
   (96 x 41 px in portrait, 96 x 26 in landscape). Moved, never hidden: it is the one dial there */
:root:has(#touch.ink-touch.one-hand:not(.art-only)) .hud-dial { bottom: calc(18px + var(--inset-b)); }
/* the laptop ring is the touch wheel's gain face (ui/dialface.js) in this 96 px slot: its parts are the .dial-gain-* rules below */
.hud-dial { shape-rendering: geometricPrecision; }
.hud-pose { position: absolute; left: 0; bottom: calc(26px + var(--inset-b)); width: 44px; height: 44px; overflow: visible; transition: opacity 0.4s var(--ease); }
.hud-pose-path { fill: none; stroke: var(--hud-ink); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; transition: d 1.2s var(--ease), opacity 1.2s var(--ease); }
.hud-pose-halo { fill: none; stroke: var(--hud-halo); stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; transition: d 1.2s var(--ease), opacity 1.2s var(--ease); }
/* the view filter badges over the pose glyph (ui/filterbadges.js): laid over it in its own 24-unit space, never taking its
   pointer events; each eases (opacity, transform) between the 4 Hz redraws, so nothing steps or flashes (CH-05) */
.hud-badges { position: absolute; left: 0; bottom: calc(26px + var(--inset-b)); width: 44px; height: 44px; overflow: visible; pointer-events: none; transition: opacity 0.6s var(--ease), visibility 0s linear 0s; }
.hud-badges.off { opacity: 0; visibility: hidden; transition: opacity 0.6s var(--ease), visibility 0s linear 0.6s; }
.hud.build .hud-badges { opacity: 0; }
.hud-badge { opacity: 0; transition: opacity 0.35s linear; }
.hud-badge * { transition: transform 0.35s linear, opacity 0.35s linear; transform-box: view-box; }
.hud-badge-disc { fill: var(--dial-halo); }
.hud-badge-ring, .hud-badge-arc { fill: none; stroke: var(--hud-ink); stroke-width: 0.7; stroke-linecap: round; }
.hud-badge-ring { stroke-width: 0.6; stroke-dasharray: 0.1 1.5; }
.hud-badge-arc-halo { fill: none; stroke: var(--dial-halo); stroke-width: 1.9; stroke-linecap: round; }
.hud-badge-arcs { transform-origin: 12px 12.5px; }
.hud-badge-haze { fill: var(--hud-ink); transform-origin: 21.8px 2.2px; }
/* the vignette's light rim: it holds where the frame is black and the dark ring would vanish into it */
.hud-badge-vig-edge { fill: none; stroke: var(--hud-ink); stroke-width: 0.5; opacity: 0.7; }
.hud-badge-core { fill: var(--hud-ink); }
.hud-badge-moon { fill: rgba(255, 255, 255, 0.82); }
.hud-badge-shade { fill: #0b0e14; }
.hud-badge-moon-rim { fill: none; stroke: var(--hud-ink); stroke-width: 0.6; }
/* reduced visual noise: no haze, a crisp ring for the blur; the words are on the badges either way (CH-06) */
.hud-badges.reduced .hud-badge-haze { filter: none; fill: none; stroke: var(--hud-ink); stroke-width: 0.6; stroke-dasharray: 0.8 0.8; }
.hud-meter { position: absolute; left: 50%; top: 56%; width: 28px; height: 28px; margin: -14px 0 0 -14px; overflow: visible; }
.hud-meter-track { fill: none; stroke: var(--hud-halo); stroke-width: 4; }
.hud-meter-arc { fill: none; stroke: var(--hud-ink); stroke-width: 2; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 14px 14px; transition: stroke-dashoffset 0.2s linear; }
.hud-meter.lovely .hud-meter-arc { stroke: var(--hud-accent); stroke-width: 2.5; }
.hud-clock { position: absolute; right: 0; top: calc(12px + var(--inset-t)); font-family: var(--font-data); font-size: 14px; color: var(--hud-ink); background: var(--hud-halo); padding: 2px 8px; border-radius: var(--radius-xs); transition: opacity 0.4s var(--ease); }
.hud-clock.faint { opacity: 0.38; }
/* top right, under the clock: the view toggle, make art (a sitting only) and heat (3P) */
.hud-actions { position: absolute; right: 0; top: calc(44px + var(--inset-t)); display: flex; flex-direction: column; align-items: flex-end; gap: 8px; pointer-events: none; }
.hud-actions > * { pointer-events: auto; }
/* top left, floating: the view switch (1P, 3P, ISO); the debug stats readout moves below it when shown */
.hud-view { position: absolute; left: 0; top: calc(12px + var(--inset-t)); display: inline-flex; border: 1.5px solid var(--hud-ink); border-radius: var(--radius-sm); overflow: hidden; background: var(--hud-halo); pointer-events: auto; }
.hud-view:not([hidden]) ~ .hud-stats { top: calc(var(--tap-sm) + 26px + var(--inset-t)); }   /* under the switch, 30 or 40 px tall */
.hud-view-btn { font: 600 12px/1 var(--font-data); min-width: 40px; min-height: 30px; padding: 2px 10px; border: 0; background: transparent; color: var(--hud-ink); cursor: pointer; }
.hud-view-btn + .hud-view-btn { border-left: 1.5px solid var(--hud-ink); }
.hud-view-btn[aria-pressed="true"] { background: var(--hud-accent); }
.hud-view-btn:focus-visible { outline: 2px solid var(--hud-accent); outline-offset: -4px; }
.hud-art { font-size: 12px; min-height: 30px; padding: 2px 10px; color: var(--hud-ink); background: var(--hud-halo); border-color: var(--hud-ink); opacity: 0.85; }
.hud-art:hover { background: var(--hud-halo); opacity: 1; }
.hud-heat { font-size: 12px; min-height: 30px; padding: 2px 10px; color: var(--hud-ink); background: var(--hud-halo); border-color: var(--hud-ink); opacity: 0.75; }
/* laptop key legend: bottom left when a sitting starts, then it fades; it sits above the pose glyph (bottom 26–70 px) and
   stops 16 px short of the dial ring (centred, 96 px wide), wrapping onto more lines in a narrow window */
.hud-keys { position: absolute; left: 0; bottom: calc(80px + var(--inset-b)); max-width: min(100%, 520px, calc(50% - 64px)); font-family: var(--font-data); font-size: 12px; line-height: 1.5; color: var(--hud-ink); background: var(--hud-halo); padding: 4px 10px; border-radius: 8px; opacity: 0; transition: opacity 0.8s var(--ease); pointer-events: none; }
.hud-keys.on { opacity: 0.92; }
.hud.build .hud-keys { display: none; }
.hud-heat:hover { background: var(--hud-halo); opacity: 1; }
.hud-heat[aria-pressed="true"] { opacity: 1; background: var(--hud-accent); color: var(--hud-ink); }
/* build mode, desktop: the open drawer fills the right-hand 400 px, so the heat toggle sits just left of it (SPEC §10) */
.hud.build .hud-actions { right: calc(min(100%, 400px) + 12px); }
.hud-notice, .hud-toast { position: absolute; left: 50%; transform: translateX(-50%); top: calc(14px + var(--inset-t)); width: max-content; max-width: min(100%, 420px); text-align: center; font-family: var(--font-display); font-size: 16px; color: var(--hud-ink); background: var(--hud-halo); padding: 3px 12px; border-radius: 10px 14px 9px 12px; opacity: 0; transition: opacity 0.5s var(--ease); }
.hud-toast { top: calc(48px + var(--inset-t)); font-family: var(--font-body); font-size: 14px; }
.hud-notice.on, .hud-toast.on { opacity: 0.92; }
.hud-stats { position: absolute; left: 0; top: calc(12px + var(--inset-t)); max-width: 100%; overflow: hidden; font-family: var(--font-data); font-size: 11px; color: var(--hud-ink); background: var(--hud-halo); padding: 2px 6px; border-radius: 6px; white-space: pre; }
/* the event notice and the toast in one stack (hud.js div.hud-stack), so a two-line notice pushes the toast down instead of
   running under it (it did at 719 px or less). Each still fades on its own; an empty one takes no room */
.hud-stack { position: absolute; left: 50%; transform: translateX(-50%); top: calc(14px + var(--inset-t)); display: grid; justify-items: center; gap: 6px; width: max-content; max-width: min(100%, 420px); pointer-events: none; }
.hud-stack > .hud-notice, .hud-stack > .hud-toast { position: static; transform: none; width: auto; max-width: 100%; }
/* an empty line takes no room yet stays rendered (no padding, and the line after it closes the gap): the two are aria-live, and a
   live region that is display: none when notice() writes into it may never be announced (VoiceOver) */
.hud-stack > :empty { padding: 0; }
.hud-stack > :empty + * { margin-top: -6px; }
/* in a sitting the centred stack keeps clear of the view switch (top left) and the clock and make art (top right): a 420 px
   toast ran 7 px into the switch at 750 x 342. Under 720 px it drops under the switch instead (below) */
.hud-view:not([hidden]) ~ .hud-stack { max-width: min(100% - 300px, 420px); }

/* ---- subtitles (SPEC §10, §13): bottom third, speaker colour as a left rule ---- */
.subs { position: absolute; left: 0; right: 0; bottom: calc(26% + var(--inset-b)); display: grid; justify-items: center; gap: 6px; pointer-events: none; }
:root:has(#touch.ink-touch:not(.art-only)) .subs { bottom: calc(max(26%, 236px + var(--dial-chip-h)) + var(--inset-b)); }
/* one dial on phones: with the HUD ring stood down, the subtitles only need to clear the wheel (bottom 16 px, 88 px tall).
   236 px put them over the view switch and the clock on a landscape phone */
:root:has(#touch.ink-touch:not(.art-only):not(.one-hand) .dial-wheel.has-gain) .subs { bottom: calc(max(26%, 116px + var(--dial-chip-h)) + var(--inset-b)); }
/* one-hand mode: the ring in its low slot (18 to 114 px) and the dial-menu badge over it (120 to 146 px); 236 px rode the
   lines up over the toast and make art on a landscape phone */
:root:has(#touch.ink-touch.one-hand:not(.art-only)) .subs { bottom: calc(max(26%, 156px + var(--dial-chip-h)) + var(--inset-b)); }
/* a narrow phone wraps the badge onto two lines (120 to 161 px at 320 px wide): the lines wait above it (they ran 5 px into it) */
@media (max-width: 359px) { :root:has(#touch.ink-touch.one-hand:not(.art-only)) .subs { bottom: calc(max(26%, 170px + var(--dial-chip-h)) + var(--inset-b)); } }
/* a landscape phone in one-hand mode: the lines ride up level with make art and heat (top right), 4 px into heat at 750 x 342,
   so they keep clear of both top corners */
@media (orientation: landscape) and (max-height: 500px) { :root:has(#touch.ink-touch.one-hand:not(.art-only)) .subs { padding: 0 104px; } }
/* Make Art open: the lines dock over the tray, never over the sheet (they take no pointer, so a tap still reaches the tray):
   at the top on a phone, where the tray is on top, and at the bottom elsewhere. A laptop's art stick and A / B sit in the
   bottom corners there, so the lines keep the tray's 128 px clear of each side */
.ui:has(> #studio:not([hidden])) > #subtitles .subs { top: auto; bottom: calc(8px + var(--inset-b)); }
.ui:has(> #studio:not([hidden]) .art-mobile) > #subtitles .subs { top: calc(8px + var(--inset-t)); bottom: auto; }
:root:has(#touch.ink-touch.art-only.art) .ui:has(> #studio:not([hidden])) > #subtitles .subs { padding: 0 128px; }
.sub {
  width: min(100%, 640px);
  background: var(--paper);
  color: var(--fg);
  border: var(--border);
  border-left: 5px solid var(--sub-colour, var(--accent));
  border-radius: var(--radius-sm);
  padding: 6px 12px;
  font-size: 17px;
  line-height: 1.35;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
  transition: opacity 0.4s var(--ease);
}
.sub.fade { opacity: 0; }
.sub-name { font-family: var(--font-display); font-weight: 600; }
.sub-name::before { content: ''; display: inline-block; width: 8px; height: 8px; margin-right: 6px; border-radius: 50%; background: var(--sub-colour, var(--accent)); border: 1px solid var(--line); vertical-align: 1px; }
.sub-text { flex: 1 1 200px; min-width: 0; overflow-wrap: anywhere; }
.sub-tags { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.chip.said { color: var(--fg); }
.chip.ask { color: var(--accent-ink); border-color: var(--accent); }
.chip.real { font-size: 10px; opacity: 0.85; border-style: dotted; }

/* ---- build drawer (SPEC §10) ---- */
.drawer {
  position: absolute;
  top: calc(12px + var(--inset-t));
  right: 0;
  bottom: calc(12px + var(--inset-b));
  width: min(100%, 400px);
  display: grid;
  grid-template-rows: auto auto auto minmax(0, 1fr) auto auto;
  gap: 6px;
  padding: 14px 16px;
  transform: translateX(calc(100% + 24px));
  visibility: hidden;
  transition: transform 0.35s var(--ease), visibility 0s linear 0.35s;
  /* the drawer floats over the live room with no dim behind it, so its glass also darkens what it blurs, keeping the text legible */
  -webkit-backdrop-filter: blur(var(--glass-blur)) brightness(0.6);
  backdrop-filter: blur(var(--glass-blur)) brightness(0.6);
}
.drawer.open { transform: none; visibility: visible; transition: transform 0.35s var(--ease), visibility 0s; }
.drawer-toggle { display: none; }
.ui:has(> #studio:not([hidden])) .drawer { visibility: hidden; }
.drawer .read { font-family: var(--font-display); font-size: 19px; line-height: 1.25; margin: 0; overflow-wrap: anywhere; }
.drawer .budget { font-family: var(--font-data); font-size: 12px; color: var(--muted); margin: 0; }
.drawer .budget.full { color: var(--fail); }
.drawer-tabs { margin: 0; }
.drawer-body { min-height: 0; overflow: auto; overscroll-behavior: contain; padding-right: 2px; }
.drawer-status { margin: 0; min-height: 1.3em; font-size: 13px; }
.drawer-foot { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
.drawer-art { gap: 6px; }
.drawer-art:empty { display: none; }   /* an empty art row no longer takes a flex slot and pushes back and done onto two lines */
.drawer-art select { max-width: 150px; }
.drawer-go { gap: 8px; margin-left: auto; justify-content: flex-end; }
/* once the status line and the budget share one row (catalogue.js div.drawer-meta), the drawer has five rows, not six */
.drawer:has(> .drawer-meta) { grid-template-rows: auto auto minmax(0, 1fr) auto auto; }
.drawer-meta { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 2px 10px; }
.drawer-meta .drawer-status { flex: 1 1 12em; }
.items { display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 8px; }
.item { padding: 8px 10px; }
.item .card-title { font-size: 15px; }
.placed-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px 8px; align-items: center; padding: 6px 0; border-bottom: 1px dashed var(--muted); }
.placed-row.selected { background: var(--accent-soft); border-radius: 8px; padding-left: 6px; padding-right: 6px; }
.placed-row .placed-name { justify-self: start; text-align: left; color: var(--fg); }
.placed-row .nudge { gap: 4px; }
.placed-row .nudge .btn { min-width: 32px; }
.tagsliders-wrap { border: 1px dashed var(--line); border-radius: var(--radius-sm); padding: 6px 10px 8px; margin: 2px 0 8px; }
.tagsliders { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0 14px; }
.sel-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 2px 8px; margin: 2px 0 4px; }
@media (max-width: 719px) {
  /* a full-width bottom sheet: left 0 / right 0 give the width (100vw counted the scrollbar), and its height is a share of the
     fixed frame. Folded, it peeks 33 px (44 px on touch) above the home indicator, not inside it (it lay at y 814-843 of 844) */
  .drawer { position: fixed; top: auto; left: 0; right: 0; bottom: 0; width: auto; max-width: none; height: var(--sheet-h); border-radius: 18px 18px 0 0; border-left: 0; border-right: 0; border-bottom: 0; transform: translateY(calc(100% + 24px)); padding: 8px var(--gutter-r) calc(12px + var(--inset-b)) var(--gutter-l); }
  .drawer::after { display: none; }
  .drawer.open { transform: none; }
  .drawer.open.collapsed { transform: translateY(calc(100% - var(--peek))); cursor: pointer; }
  .drawer .read { padding-right: 56px; min-height: 25px; }
  /* the read line whole while the sheet is open (SPEC §10: the tutorial for the whole puzzle; two lines cut a pinned drawing's
     line short): the list under it is the part that scrolls, so a line more only shortens the list. Folded, the strip shows
     its first line */
  .drawer.collapsed .read { display: block; -webkit-line-clamp: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* and only that line and the chevron: the top of the tab strip showed under it, sliced by the home indicator */
  .drawer.collapsed > :not(.read):not(.drawer-toggle) { visibility: hidden; }
  .drawer-toggle { display: grid; place-items: center; position: absolute; top: 2px; right: calc(var(--gutter-r) - 6px); width: 48px; height: 29px; padding: 0; border: 1px solid var(--line); border-radius: 10px; background: var(--paper-2); color: var(--fg); cursor: pointer; z-index: 1; }
  .drawer-toggle svg { transition: transform 0.25s var(--ease); }
  .drawer.collapsed .drawer-toggle svg { transform: rotate(180deg); }
  .drawer .read { font-size: 17px; }
  .hud.build .hud-actions { right: 0; } /* the drawer is a bottom sheet here, the top-right corner is free */
  /* in a sitting the view switch (top left) and the clock (top right) leave no room for a centred notice: it and the toast
     drop under the switch, left-aligned, and stop short of the make art / heat column on the right */
  .hud-view:not([hidden]) ~ :is(.hud-notice, .hud-toast) { left: 0; transform: none; max-width: calc(100% - 104px); text-align: left; }
  .hud-view:not([hidden]) ~ .hud-notice { top: calc(var(--tap-sm) + 24px + var(--inset-t)); }   /* the switch is 30 px tall, 40 on touch */
  .hud-view:not([hidden]) ~ .hud-toast { top: calc(var(--tap-sm) + 58px + var(--inset-t)); }
  .hud-view:not([hidden]) ~ .hud-stack { left: 0; transform: none; top: calc(var(--tap-sm) + 24px + var(--inset-t)); max-width: calc(100% - 104px); justify-items: start; }
  .hud-view:not([hidden]) ~ .hud-stack > * { text-align: left; }
}
/* phones, and every landscape phone: the tabs as one scrolling strip (they wrapped onto 2 to 4 lines, 68 to 140 px of the sheet) */
@media (max-width: 719px), (orientation: landscape) and (max-height: 500px) {
  .drawer-tabs { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; touch-action: pan-x; padding: 4px; margin: -4px; }   /* room for the focus ring inside the clip */
  .drawer-tabs::-webkit-scrollbar { display: none; }
  .drawer-tabs .tab { flex: 0 0 auto; }
  /* more tabs off an edge: the strip fades out on that side, once catalogue.js sets more-left / more-right as the wardrobe's tabs do */
  .drawer-tabs.more-right { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); }
  .drawer-tabs.more-left { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); }
  .drawer-tabs.more-left.more-right { -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); }
}
/* a landscape phone, below and above 720 px wide: a full-height side sheet inside the gutters that folds sideways to a 48 px
   strip, with the fold control at its top left. The 400 px desktop drawer left a 35 to 83 px list there and had no fold control,
   and the bottom sheet left 22 px */
@media (orientation: landscape) and (max-height: 500px) {
  .drawer { position: absolute; top: calc(6px + var(--inset-t)); right: 0; bottom: calc(6px + var(--inset-b)); left: auto; width: min(400px, 52%); height: auto; padding: 8px 12px 8px 52px; border-radius: var(--radius); border: var(--border); transform: translateX(calc(100% + 24px)); }
  .drawer.open { transform: none; }
  .drawer.open.collapsed { transform: translateX(calc(100% - 48px)); cursor: pointer; }
  .drawer.collapsed .read { display: block; -webkit-line-clamp: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .drawer-toggle { display: grid; place-items: center; position: absolute; top: 6px; left: 4px; right: auto; width: 40px; height: 44px; padding: 0; border: 1px solid var(--line); border-radius: 10px; background: var(--paper-2); color: var(--fg); cursor: pointer; z-index: 1; }
  .drawer-toggle svg { transform: rotate(-90deg); transition: transform 0.25s var(--ease); }
  .drawer.collapsed .drawer-toggle svg { transform: rotate(90deg); }
  .drawer .read { padding-right: 0; min-height: 0; font-size: 16px; }
  /* the side sheet is 400 px or less on a wider screen: the foot's labels drop their extra words as they do under 400 px
     ('rooms', 'done'); the read line stays whole, as on the bottom sheet */
  .drawer .lbl-x { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  /* the HUD's heat and make art column follows the sheet's edge */
  .hud.build .hud-actions { right: calc(min(400px, 52%) + 12px); }
  .ui:has(.drawer.open.collapsed) .hud.build .hud-actions { right: 60px; }
}

/* ---- menu screens ---- */
.screen { position: relative; width: min(100%, 760px); }
.shells .card-title { font-size: 16px; }
.shells .card-read { font-size: 13px; }
.room-card .card-title { font-size: 16px; }
/* set: the lede as one quiet line; 'dev mode on' sits in the header while it is on, so the state shows when its toggle is behind 'more' */
.screen[data-screen="set"] .lede { font-size: 14px; color: var(--muted); margin: 0 0 4px; }
.screen-body > .marketing { margin: var(--gap) 0 0; }
.chip.dev { border-color: var(--accent); color: var(--accent-ink); }
/* set, once its render builds the frame: compact cards. A shell's name and its chips share the first line (wrapping only when
   they must) and its read line goes under them. On a phone (and a window 560 px tall or less) that line stops at two lines,
   and the whole of it shows once under the cards (p.shell-read) for the card with focus or the mouse on it and for a locked
   card just tapped; it stays in the card's text and a locked card's label. The shells' 661 to 694 px came from read lines on
   2 to 4 lines; a laptop keeps them whole (a 1280 x 720 window has room for them) */
.screen-body .shell-card { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; padding: 6px 10px; }
.screen-body .shell-card > .card-title { flex: 0 1 auto; min-width: 0; }
.screen-body .shell-card > .card-meta { order: 1; min-width: 0; max-width: 100%; }
.screen-body .shell-card .chip { max-width: 100%; white-space: normal; }   /* 'every surface draws' ran past a 144 px card */
.screen-body .shell-card > .card-read { order: 2; flex: 1 1 100%; min-width: 0; }
.shells > .shell-read { display: none; grid-column: 1 / -1; margin: 0; font-size: 13px; color: var(--muted); }
/* only a locked card's line stops at two (a tap on it says the whole line in the status line, menu.js): an open card's tap
   opens the room, so on a touch screen its line was never shown whole; it wraps in full, the body scrolls */
@media (max-width: 480px), (max-height: 760px) and (pointer: coarse), (max-height: 560px) {
  .screen-body .shell-card.locked > .card-read { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
  .shells > .shell-read:not(:empty) { display: block; }
}
.screen-body .room-card { gap: 2px; padding: 6px 10px; }
/* set's foot: the doors (spend, wardrobe, notes, settings) as a 2 x 2 grid on a phone, one row where they fit */
@media (max-width: 480px) {
  .screen[data-screen="set"] .screen-foot > :is(.row, .tools) { flex: 1 1 100%; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 8px; }
}
/* a note's date and room share one line with its copy button (the button had a line of its own, about 40 px a note); the text
   goes under them. The ending note at the top takes the same shape, 'see it again' on the right */
.note { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0 10px; }
.note > .text { grid-area: 2 / 1 / auto / -1; }
.note > .btn { grid-area: 1 / 2; justify-self: end; }
.pose-card { grid-template-columns: 36px minmax(0, 1fr); align-items: center; }
.pose-card svg { width: 36px; height: 36px; stroke: currentColor; fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.pose-card .card-meta { grid-column: 1 / -1; }
/* pose, once its render wraps the grid in div.pose-pick: compact cards, the glyph and the name on one line and the lock chip at
   the end. Each card's reveals stay in its text for screen readers, and show once under the grid (p.pose-reveals): the chosen
   pose's, or the card's with focus or the mouse on it, or a locked card's just tapped (menu.js). This scales past 8 poses */
.pose-pick .cards.poses { grid-template-columns: repeat(auto-fill, minmax(min(100%, 120px), 1fr)); gap: 6px; }   /* two columns down to 320 px */
.pose-pick .pose-card { grid-template-columns: 28px minmax(0, 1fr); gap: 2px 6px; min-height: var(--tap); padding: 6px 8px; }
.pose-pick .pose-card svg { width: 28px; height: 28px; }
.pose-pick .pose-card .card-title { font-size: 15px; }
/* a locked pose's cost goes under its name: beside it, in a 144 px card, it squeezed the name to a letter a line */
.pose-pick .pose-card .card-meta { grid-column: 2; }
.pose-card .pose-reveal { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.pose-reveals { margin: 6px 0 0; font-size: 13px; color: var(--muted); }
.row.options { gap: 8px 6px; margin: var(--gap) 0 4px; }
.row.options .seg .btn { min-width: 42px; padding-left: 10px; padding-right: 10px; }   /* 1P | 3P and 10 | 20 | 30, then 'min', on one line at 320 px */
/* the quiet unit after a short seg (the length seg's 10 | 20 | 30, then 'min'); the group's aria-label keeps the full words */
.row.options .seg-unit { margin-left: -4px; font-size: 13px; color: var(--muted); }
.pose-length-note { margin: 0 0 4px; }   /* 'shorter sittings cost nothing', on screen under the length choice (SPEC §13 Time) */
.pose-company { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; margin-top: var(--gap); }
.pose-company > details.more { flex: 1 1 14em; min-width: 0; margin: 0; }
.pose-company .companions { margin: 6px 0 2px; }
/* a landscape phone: the poses on the left, how you sit on the right (two wrappers in DOM order, so Tab goes down the left, then the right) */
@media (orientation: landscape) and (max-height: 500px) {
  .screen[data-screen="pose"] .screen-body:has(> .pose-pick) { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 16px; align-items: start; }
  .screen[data-screen="pose"] .pose-pick .cards.poses { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* the same two columns for set (the shells | div.set-rooms: your rooms, the lede, the marketing line, 'more') and for spend
     (div.spend-main: the muted line, the afterglow row, the tiers | div.spend-lists) */
  .screen[data-screen="set"] .screen-body:has(> .set-rooms), .screen[data-screen="spend"] .screen-body:has(> .spend-main) { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 16px; align-items: start; }
  .screen-body > .set-rooms > :first-child, .screen-body > .spend-lists { margin-top: 0; }
}
.companions { display: flex; flex-wrap: wrap; gap: 8px; }
.tools { margin-top: 14px; padding-top: 10px; border-top: 1px dashed var(--muted); }
.menu-status { min-height: 1.3em; margin: 8px 0 0; font-size: 14px; }
.marketing { color: var(--muted); font-size: 13px; margin: 10px 0 0; }
.tally { font-family: var(--font-display); font-size: 22px; margin-bottom: 4px; }
.spend details { border: 1px dashed var(--muted); border-radius: var(--radius-sm); padding: 6px 10px; margin: 8px 0; }
.spend summary { cursor: pointer; font-family: var(--font-display); font-size: 15px; padding: 2px 0; }
/* the five lists' summaries in a grid of buttons once the render wraps them in div.spend-lists; an open list takes the full width
   under them (same DOM order) */
.spend-lists { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr)); gap: 6px; margin: var(--gap) 0; }
.spend-lists > details { margin: 0; }
.spend-lists > details[open] { grid-column: 1 / -1; }
.spend-lists > details > summary { list-style: none; display: flex; align-items: center; gap: 6px; min-height: var(--tap-sm); }
.spend-lists > details > summary::-webkit-details-marker { display: none; }
.spend-lists > details > summary::before { content: '▸'; color: var(--muted); }
.spend-lists > details[open] > summary::before { content: '▾'; }
.screen[data-screen="spend"] > p.muted:not(.menu-status), .screen[data-screen="spend"] .spend-main > p.muted:first-child { font-size: 13px; margin-bottom: 6px; }
/* phones: the tiers as one line each (the name, the fee and badges, then the open chip or the button), the reason line under it */
@media (max-width: 599px) {
  .spend .cards.tiers { grid-template-columns: 1fr; gap: 6px; }
  .spend .tier-card { grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; column-gap: 10px; padding: 6px 10px; }
  .spend .tier-card > .card-title { grid-area: 1 / 1; }
  .spend .tier-card > .card-meta { grid-area: 1 / 2; }
  .spend .tier-card > .btn, .spend .tier-card > .chip.accent { grid-area: 1 / 3; justify-self: end; }
  .spend .tier-card > .muted.small { grid-area: 2 / 1 / auto / -1; }
}
.spend-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 4px 10px; align-items: center; padding: 6px 0; border-bottom: 1px dashed var(--muted); font-size: 15px; }
.spend-row:last-child { border-bottom: none; }
.spend-name { min-width: 0; overflow-wrap: anywhere; }
.spend-row .cost { font-family: var(--font-data); font-size: 13px; color: var(--muted); }
.spend-row .state { font-size: 13px; color: var(--muted); text-align: right; }
.spend-row .state.owned { color: var(--ok); }
.spend-row.unbuilt .spend-name, .spend-row.unbuilt .cost { color: var(--muted); }
/* the afterglow row (Appendix G.4.2): one line and a bar, in the same glass; the text beside the bar carries the value */
.spend-row.afterglow-row { display: block; }
.afterglow-row .ag-line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.afterglow-row .ag-line .spend-name { flex: 1 1 12em; min-width: 0; }
.afterglow-row .ag-controls { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; max-width: 100%; }
.afterglow-row .ag-controls .seg .btn { min-height: 30px; padding: 3px 10px; font-size: 14px; }
.afterglow-row .ag-confirm { flex: 1 1 100%; }
.afterglow-row .ag-split { margin: 2px 0 0; }
.ag-bar { height: 6px; margin: 6px 0 2px; border: 1px solid var(--line); border-radius: 4px; overflow: hidden; background: var(--paper-2); }
.ag-bar .ag-fill { display: block; height: 100%; background: var(--accent); transition: width 0.6s var(--ease); }
/* the ending card (Appendix G.4a): its own layer above the menus and the report; fades in over 1.2 s, at once under reduced motion */
#ending { z-index: 8; }
.ending { position: absolute; inset: 0; display: grid; place-items: center; overflow: auto; overscroll-behavior: contain; padding: calc(var(--frame-gap) + var(--inset-t)) 0 calc(var(--frame-gap) + var(--inset-b)); pointer-events: auto; touch-action: pan-x pan-y; }
.ending::before { content: ''; position: fixed; inset: 0; background: var(--scrim); pointer-events: auto; }
.ending > .panel { width: min(560px, 100%); max-height: 100%; overflow: auto; animation: ending-in 1.2s var(--ease) both; }
.ending .ending-text { margin: 8px 0 12px; }
@keyframes ending-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .ending > .panel { animation: none; } .ag-bar .ag-fill { transition: none; } }
.report .notes-extra { margin-top: 4px; }
.deep-row { margin-top: 8px; border-top: 1px dashed var(--muted); }
.notes-list { display: grid; gap: var(--gap); }
.note { border: 1px dashed var(--muted); border-radius: var(--radius-sm); padding: 10px 12px; }
.note .when { font-family: var(--font-data); font-size: 12px; color: var(--muted); }
.note .text { font-family: var(--font-display); font-size: 17px; margin: 4px 0 6px; }
.screen.deepwater { width: min(100%, 460px); }
.deepwater .lede { font-size: 20px; margin: 6px 0 4px; }
/* pause: resume, then settings / wardrobe / field notes, then the two ways out, a row each */
.pause-actions { display: grid; gap: 8px; margin-top: var(--gap); }
/* in its frame's foot (menu.js), with no rule over it: the card looks as it did, and only the words scroll on a 256 px screen */
.screen[data-screen="pause"] .screen-foot { border-top: 0; padding-top: 0; }
.screen-foot > .pause-actions { flex: 1 1 100%; margin-top: 0; }

/* ---- report card: a postcard ---- */
.postcard { width: min(100%, 700px); padding-top: calc(var(--pad-y) + 4px); }
.postcard .stamp {
  position: absolute;
  top: 14px;
  right: 14px;
  font-family: var(--font-data);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent-ink);
  border: 1.5px dashed var(--accent);
  border-radius: 6px 8px 5px 7px;
  padding: 8px 10px;
  transform: rotate(4deg);
  max-width: 42%;
  overflow-wrap: anywhere;
}
.postcard > h2 { padding-right: 44%; }
/* once show() builds header / body / foot: the header is not positioned, so the stamp stays at the card's corner */
.postcard > header { margin-bottom: 4px; }
.postcard > header h2 { margin: 0; padding-right: 44%; }
.postcard > header .muted { flex: 1 1 100%; margin: 2px 0 0; }
.postcard .notes { font-family: var(--font-display); font-size: 19px; line-height: 1.45; max-width: 56ch; margin: 8px 0 8px; }
.postcard .thumb-wrap { float: right; margin: 0 0 8px 12px; }
.postcard-thumb { width: 112px; height: 112px; object-fit: cover; border: var(--border); border-radius: var(--radius-xs); display: block; }
@media (max-width: 480px) {
  .postcard-thumb { width: 72px; height: 72px; }
  .postcard .notes { font-size: 17px; }
}
.achievements { clear: both; margin-top: 8px; }
.ach-family { margin: 6px 0; }
.ach-family h3 { display: flex; justify-content: space-between; gap: 8px; margin: 8px 0 2px; font-size: 15px; color: var(--muted); border-bottom: 1px dashed var(--muted); }
.ach-row { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; font-size: 15px; }
.ach-row > span:first-child { min-width: 0; overflow-wrap: anywhere; }
.ach-row .desc { color: var(--muted); font-size: 13px; }
.totals { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; margin: 10px 0; font-family: var(--font-data); font-size: 14px; border-top: var(--border); padding-top: 8px; }
.totals dt, .totals dd { margin: 0; }
.totals dd { text-align: right; }
.totals .total { font-size: 18px; font-family: var(--font-display); }
.totals dd.badges { grid-column: 1 / -1; text-align: left; font-family: var(--font-body); font-size: 15px; overflow-wrap: anywhere; }
.ach-row .chip.new { border-color: var(--accent); color: var(--accent-ink); }
.postcard details { margin-top: 10px; }
.postcard details summary { cursor: pointer; color: var(--muted); }
/* the sitting's cuddles folded into one row, "Cuddles · n", that opens to their names (SPEC-E E.5.10 CUD-10) */
.postcard details.ach-fold { margin-top: 0; }
.postcard details.ach-fold > summary { color: inherit; list-style: none; }
.ach-fold > summary::-webkit-details-marker { display: none; }
.ach-fold > summary > span:first-child::before { content: '▸ '; color: var(--muted); }
.ach-fold[open] > summary > span:first-child::before { content: '▾ '; }
.ach-fold > div.ach-row { padding-left: 14px; }
.postcard-img { width: 100%; height: auto; border: var(--border); border-radius: var(--radius-sm); display: block; margin-top: 8px; }

/* ---- a11y panel (SPEC §13, D.9) ---- */
.a11y > .panel { width: min(100%, 640px); }
.a11y fieldset { border: 1px dashed var(--muted); border-radius: var(--radius-sm); padding: 6px 12px 8px; margin: 10px 0; min-width: 0; }
.a11y legend { font-family: var(--font-display); font-size: 16px; padding: 0 6px; }
.a11y .field .row { flex-wrap: nowrap; }
/* once a11y.js turns the seven fieldsets into tab panels behind one scrolling tab strip; each legend stays for screen readers
   (its tab names it on screen) */
.a11y .a11y-intro { font-size: 13px; color: var(--muted); margin: 0 0 6px; }
.a11y-tabs { display: flex; gap: 4px; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; touch-action: pan-x; margin: 0 0 6px; padding: 0 0 6px; border-bottom: 1px dashed var(--muted); }
.a11y-tabs::-webkit-scrollbar { display: none; }
.a11y-tabs .tab { flex: 0 0 auto; }
.a11y fieldset[role="tabpanel"] { margin: 0; padding: 0; border: 0; }
.a11y fieldset[role="tabpanel"] > legend { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* a landscape phone: two columns of rows, row by row in DOM order (an inner div, as a grid fieldset has old Safari quirks); the keys table stays one column */
@media (min-width: 600px) and (max-height: 500px) {
  .a11y .a11y-rows { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 18px; }
}
.remap { width: 100%; border-collapse: collapse; font-size: 14px; table-layout: fixed; }
.remap th { text-align: left; font-weight: normal; color: var(--muted); padding: 4px 6px; border-bottom: 1px dashed var(--muted); }
.remap th:nth-child(2) { width: 28%; }
.remap th:nth-child(3) { width: 30%; }
.remap td { padding: 4px 6px; border-bottom: 1px dashed var(--muted); vertical-align: middle; overflow-wrap: anywhere; }
.remap td .btn { width: 100%; white-space: normal; }
.remap-key { font-family: var(--font-data); font-size: 12px; }
.remap-row.custom .remap-key { color: var(--accent-ink); }
.remap-row.listening .btn { background: var(--accent); color: var(--on-accent); }

/* ---- gate card (SPEC §17 CH-04, CH-08) ---- */
.gate > .panel { width: min(100%, 480px); text-align: center; padding: 28px 24px 22px; }
.gate-title { font-size: 40px; letter-spacing: 0.04em; margin-bottom: 6px; overflow-wrap: break-word; }   /* last resort before cqi (Safari < 16): break the word, never clip it */
/* the title's one long word (17 letters, 9.8 em with its letter-spacing) takes its size from the card's
   width: a tenth of it, 24 to 40 px, so it never runs past the card (it did by 63 px at 320, 23 at 360 and 8 at 375, and the card
   scrolled sideways). The owner's title and its spacing are unchanged */
.gate > .panel { container-type: inline-size; }
@supports (font-size: 1cqi) { .gate > .panel > .gate-title { font-size: clamp(24px, 10cqi, 40px); } }
.gate-line { font-family: var(--font-display); font-size: 19px; }
.gate .marketing { margin: 4px 0 18px; font-size: 14px; }
.gate .row { justify-content: center; }
.gate .countdown { color: var(--muted); font-family: var(--font-data); font-size: 12px; margin: 10px 0 0; }

/* ---- touch layer (lane I builds and positions it; these only soften it) ---- */
:where(#touch) .stick { opacity: 0.5; }
:where(#touch) .stick-ring, :where(#touch) .stick-knob { border-width: 1.5px; }
:where(#touch) .btn-a, :where(#touch) .btn-b { font-family: var(--font-display); border-width: 1.5px; opacity: 0.72; }
:where(#touch) .btn-a:active, :where(#touch) .btn-b:active { opacity: 1; }

/* ---- test panel (CONTRACT §10) ---- */
/* the menus' scrim under it too: over a lamp-lit wall its 20 % glass left the renderer line and run all / close at 2.5:1 */
#tests::before { content: ''; position: fixed; inset: 0; background: var(--scrim); pointer-events: auto; }
.panel.tests { position: absolute; inset: calc(10px + var(--inset-t)) 0 calc(10px + var(--inset-b)); overflow: auto; display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 8px; }
.panel.tests > header .btn { min-height: 32px; }
.test-body { overflow: auto; min-height: 0; }
.test-row { display: grid; grid-template-columns: 3.2em minmax(0, 1fr); gap: 2px 8px; padding: 6px 0; border-bottom: 1px dashed var(--muted); font-size: 14px; }
.test-mark { font-family: var(--font-data); font-size: 12px; text-transform: uppercase; }
.test-row.ok .test-mark { color: var(--ok); }
.test-row.fail .test-mark { color: var(--fail); }
.test-row.fail .test-name { color: var(--fail); }
.test-name { overflow-wrap: anywhere; }
.test-detail { grid-column: 2; font-family: var(--font-data); font-size: 12px; color: var(--muted); overflow-wrap: anywhere; }
.test-summary { font-family: var(--font-data); font-size: 13px; color: var(--muted); }

/* ---- motion and noise preferences ---- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}
:root[data-reduced-noise="1"] .panel::after { display: none; }
@media (max-width: 480px) {
  /* the panel padding and the card gap are the --pad-* and --gap tokens here (top of the file) */
  .gate > .panel { padding: 22px 16px 18px; }
  .gate-title { font-size: 34px; }
  h2 { font-size: 20px; }
  /* two columns down to a 320 px phone: 128 px cards dropped to one column there (a 257 px box needs 264 px for two) */
  .cards { grid-template-columns: repeat(auto-fill, minmax(min(120px, 100%), 1fr)); }
}

/* ---- height tiers: width-only breakpoints miss landscape phones. These tighten the padding, the gaps and the type; text never
   goes under 13 px and no target shrinks ---- */
/* compact: 760 px tall or less, which is most phones in portrait */
@media (max-height: 760px) {
  :root { --frame-gap: 8px; --pad-y: 12px; --pad-x: 14px; --gap: 8px; }
  h2 { font-size: 20px; }
  .lede { font-size: 16px; }
  .panel > header { margin-bottom: 6px; }
  .card { padding: 8px 10px; }
  .field { padding: 5px 0; }
  .field .hint { line-height: 1.3; }
  /* settings: each group keeps its visible legend, a size smaller, in a closer box */
  .a11y fieldset { margin: 8px 0; padding: 4px 10px 6px; }
  .a11y legend { font-size: 15px; }
}
/* short: 560 px tall or less, which is an iPhone SE with its toolbars (375 x 547) and every phone in landscape */
@media (max-height: 560px) {
  :root { --frame-gap: 4px; --pad-y: 10px; --pad-x: 12px; --gap: 6px; }
  h2 { font-size: 18px; }
  h3 { font-size: 15px; margin-top: 8px; }
  .lede, .gate-line { font-size: 15px; }
  .gate > .panel { padding: 14px 16px 12px; }
  .gate .marketing { margin: 2px 0 10px; }
  .field { padding: 3px 0; }
  .field .hint { line-height: 1.3; }
  .postcard .notes { font-size: 17px; line-height: 1.35; }
}
/* landscape compact: a phone on its side, 480 px tall or less (667 x 375, 844 x 390, and an iPhone 13 with its toolbars). The
   header and the foot close up, the status line shares the action row instead of taking one of its own, and the title steps
   down; the two-column bodies are with each screen's own rules. Padding and type tighten here, targets never shrink */
@media (orientation: landscape) and (max-height: 480px) {
  .panel > header { margin-bottom: 4px; }
  .screen-foot { margin-top: 4px; padding-top: 4px; }
  .screen-foot > .menu-status { flex: 1 1 12em; }
  h2 { font-size: 17px; }
}
/* the floor: 300 px tall or less (640 x 256, a phone on its side in split screen). The gate's card closes up and its title
   steps down, so it fits whole (it scrolled 27 px as one block); nothing in it is dropped */
@media (max-height: 300px) {
  .gate > .panel { padding: 8px 16px; }
  .gate > .panel > .gate-title { font-size: 28px; margin-bottom: 2px; }
  .gate-line { margin-bottom: 4px; }
  .gate .marketing { margin: 0 0 6px; }
  .gate .countdown { margin-top: 4px; }
}

/* the OS asks for less transparency: menus go back to solid paper, no blur */
@media (prefers-reduced-transparency: reduce) {
  .panel { background: #1b2336; -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* ---- every other panel-like surface is the same dark glass with white sans text ---- */
.card-read { font-style: normal; }
.sub { background: var(--glass); -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); box-shadow: var(--glass-shadow); color: #fff; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); }
/* HUD text sits straight over the live room with only the 20 % tint behind it, so it takes a stronger halo than the menus'
   to stay legible over bright cel-shaded walls (the tint and blur stay the owner's) */
.hud-clock, .hud-notice, .hud-toast, .hud-stats, .hud-keys, .hud-heat, .hud-art, .hud-view {
  -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); box-shadow: var(--glass-shadow); text-shadow: 0 0 3px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.5);
}
.hud-heat, .hud-art, .hud-view { border-color: var(--line); }
.hud-view-btn + .hud-view-btn { border-left-color: var(--line); }
.hud-heat[aria-pressed="true"], .hud-view-btn[aria-pressed="true"] { color: #0b0e14; text-shadow: none; }
.boot { color: #fff; }
/* touch controls: glass buttons, white glyphs */
#touch.ink-touch button, #touch.ink-touch .dial-wheel { -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); box-shadow: var(--glass-shadow); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); }
#touch.ink-touch .stick-ring, #touch.ink-touch .stick-knob { -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); }
/* the one-hand dial-menu badge (input.js): white on the dial's dark halo at 13 px, as the HUD's labels (the theme's --line and
   --paper made it dark-20 % text on a white-60 % pill, about 1.5:1), and one line wide: left 50 % halved its shrink-to-fit
   width, so it wrapped at every portrait width and ran 5 px into the lines above it (max-content, still capped by its max-width) */
#touch.ink-touch .dial-menu-badge { width: max-content; background: var(--dial-halo); color: #fff; font-size: 13px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); }
/* the one dial on phones: the touch wheel with the gain face (ui/dialface.js, hud.dockDial) in place of the HUD ring. At full
   strength, as the ring it stands in for (the quiet layer softens only its glass); crisp SVG grip marks that turn with your
   finger instead of the conic ticks and the pointer; every mark white ink over a dark halo, so it reads on a bright wall and a
   dark one. One stroke family: 1 px hairline (the travel arc), 2 px lines (rim, grip marks, the ring at rest), a 3 px pointer,
   each halo 3 px wider than its ink. The rim is an inset shadow with a 1 px dark keyline, not a border (a 1.5 px border rounds
   to 1 px at 1x and shrinks the face's box), so both SVGs fill the 88 px wheel and 1 user unit is 1 CSS px at 1x to 3x */
#touch.ink-touch .dial-wheel.has-gain { --wheel-rim: inset 0 0 0 2px var(--line), 0 0 0 1px var(--dial-halo); opacity: 1; border: 0; background: var(--glass); box-shadow: var(--wheel-rim), var(--glass-shadow); }
#touch.ink-touch .dial-wheel.has-gain .dial-ticks, #touch.ink-touch .dial-wheel.has-gain .dial-mark { display: none; }
#touch.ink-touch .dial-wheel.has-gain.pressed { box-shadow: var(--wheel-rim), var(--glass-shadow), 0 0 0 4px var(--accent-soft); }
.dial-gain, .dial-knurl { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; shape-rendering: geometricPrecision; }
.dial-gain { transition: opacity 0.4s var(--ease); }
.dial-gain.off { opacity: 0; }
.dial-gain-halo { fill: none; stroke: var(--dial-halo); transition: stroke-width 0.3s var(--ease); }
.dial-gain-ring { fill: none; stroke: var(--hud-ink); transition: stroke-width 0.3s var(--ease); }
.dial-gain-track { fill: none; stroke: rgba(255, 255, 255, 0.75); stroke-width: 1; stroke-linecap: round; }
.dial-gain-track-halo { fill: none; stroke: var(--dial-halo); stroke-width: 4; stroke-linecap: round; opacity: 0.7; }
.dial-gain-tick { stroke: var(--hud-ink); stroke-width: 3; stroke-linecap: round; }
.dial-gain-tick-halo { stroke: var(--dial-halo); stroke-width: 6; stroke-linecap: round; }
.dial-knurl line { stroke-linecap: round; }
.dial-knurl-halo line { stroke: var(--dial-halo); stroke-width: 5; opacity: 0.7; }
.dial-knurl-ink line { stroke: rgba(255, 255, 255, 0.7); stroke-width: 2; }
#touch.ink-touch .dial-wheel.has-gain.pressed .dial-knurl-ink line { stroke: var(--hud-ink); }
/* the docked wheel's keyboard focus: the thermostat chip's two-tone ring (a white outline over a dark keyline) in place of the
   touch layer's single orange one, which all but vanishes on a wall lit orange (1.09:1 over the lit Studio; WCAG 1.4.11) */
#touch.ink-touch .dial-wheel.has-gain:focus-visible { outline: 2px solid #fff; outline-offset: 2px; box-shadow: var(--wheel-rim), 0 0 0 4px #0b0e14, var(--glass-shadow); }
/* ---- the thermostat (SPEC §5.5 TH-10 to TH-13; ui/thermoface.js, hud.thermo) ----
   The chip: above the dial while it is aimed at, 30 px to look at with a 44 px hit area, the HUD view switch's glass. On a laptop
   it sits over the 96 px ring (18 to 114 px); on a phone over the docked wheel (16 to 104 px); where the ring is lifted to 116 px
   (a touch layer with no face docked) above that ring; in one-hand mode, where the ring takes the wheel's low slot, over the ring
   as on a laptop, the dial-menu badge and the lines rising by --dial-chip-h above it. While it shows, --dial-chip-h is its 44 px */
.hud-thermo-chip { position: absolute; left: 50%; bottom: calc(122px + var(--inset-b)); transform: translateX(-50%); min-height: 30px; padding: 2px 12px; font: 600 12px/1 var(--font-data); white-space: nowrap; color: var(--hud-ink); background: var(--dial-halo); border: 1.5px solid var(--line); border-radius: var(--radius-sm); pointer-events: auto; cursor: pointer; -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); box-shadow: var(--glass-shadow); text-shadow: 0 0 3px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.5); }
.hud-thermo-chip::before { content: ''; position: absolute; left: -4px; right: -4px; top: -7px; bottom: -7px; }   /* the 44 px hit area */
.hud-thermo-chip[hidden] { display: none; }
/* a tap paints no square browser highlight over the rounded glass and the pressed ring (the touch layer's own controls do the
   same, input.js TOUCH_CSS); the chips and the HUD's other buttons have their own pressed and focus states */
.hud-thermo-chip, .hud-view-btn, .hud-art, .hud-heat { -webkit-tap-highlight-color: transparent; }
/* pressed (the face is open) it keeps the dark glass, so it never melts into a lit wall the colour of the accent, and gains a
   2 px inset ring in the wedge's yellow; the text says the state too ('thermostat · warming') */
.hud-thermo-chip[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--thermo-band), var(--glass-shadow); }
/* the dial halo's navy under the white label holds 4.5:1 over the brightest wall (WCAG 1.4.3; 5.96:1 over the Studio's base
   #f4efe4); the focus ring is two-tone, a dark keyline inside a white one, so one of them holds 3:1 over any wall (WCAG 1.4.11) */
.hud-thermo-chip:focus-visible { outline: 2px solid #fff; outline-offset: 2px; box-shadow: 0 0 0 4px #0b0e14, var(--glass-shadow); }
.hud-thermo-chip[aria-pressed="true"]:focus-visible { box-shadow: inset 0 0 0 2px var(--thermo-band), 0 0 0 4px #0b0e14, var(--glass-shadow); }
@media (pointer: coarse) { .hud-thermo-chip { font-size: 13px; } }   /* nothing under 13 px on a coarse pointer, as the HUD's other labels */
:root:has(#touch.ink-touch:not(.art-only)) .hud-thermo-chip { bottom: calc(220px + var(--inset-b)); }
:root:has(#touch.ink-touch:not(.art-only):not(.one-hand) .dial-wheel.has-gain) .hud-thermo-chip { bottom: calc(114px + var(--inset-b)); }
:root:has(#touch.ink-touch.one-hand:not(.art-only)) .hud-thermo-chip { bottom: calc(122px + var(--inset-b)); }
:root:has(.hud:not([hidden]) .hud-thermo-chip:not([hidden])) { --dial-chip-h: 44px; }
/* a laptop's lines clear the chip (it ends at 152 px) */
:root:has(.hud:not([hidden]) .hud-thermo-chip:not([hidden])) .subs { bottom: calc(max(26%, 166px) + var(--inset-b)); }
/* the face: one in the HUD ring's slot (88 px, centred where the 96 px ring sits, following it as it moves) and one in a docked
   wheel; .thermo (open) cross-fades the gain face out and this one in over 0.3 s, so one dial face shows */
.hud-thermo { position: absolute; left: 50%; bottom: calc(22px + var(--inset-b)); width: 88px; height: 88px; transform: translateX(-50%); overflow: visible; opacity: 0; pointer-events: none; shape-rendering: geometricPrecision; transition: opacity 0.3s var(--ease); }
:root:has(#touch.ink-touch:not(.art-only)) .hud-thermo { bottom: calc(120px + var(--inset-b)); }
:root:has(#touch.ink-touch:not(.art-only):not(.one-hand) .dial-wheel.has-gain) .hud-thermo { display: none; }
:root:has(#touch.ink-touch.one-hand:not(.art-only)) .hud-thermo { bottom: calc(22px + var(--inset-b)); }
.hud:not(.build) .hud-dial { transition-duration: 0.3s; }
.hud.thermo .hud-dial { opacity: 0; }
.hud.thermo:not(.build) .hud-thermo { opacity: 1; }
.dial-thermo { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; opacity: 0; pointer-events: none; shape-rendering: geometricPrecision; transition: opacity 0.3s var(--ease); }
#touch.ink-touch .dial-wheel .dial-gain { transition-duration: 0.3s; }
#touch.ink-touch .dial-wheel.thermo .dial-gain { opacity: 0; }
#touch.ink-touch .dial-wheel.thermo .dial-thermo { opacity: 1; }
#touch.ink-touch .dial-wheel .dial-thermo.off { opacity: 0; }
/* the wheel's grip marks step back under the thermostat's face, so its 15, 20, 25 and 30 ticks read; still there as a drag cue */
#touch.ink-touch .dial-wheel .dial-knurl { transition: opacity 0.3s var(--ease); }
#touch.ink-touch .dial-wheel.thermo .dial-knurl { opacity: 0.35; }
/* its parts: the gain face's stroke family, white ink over the dark halo; the slice is the one colour, at fill-opacity 0.3 */
.thermo-face-back { fill: var(--dial-halo); }
.thermo-face-band { fill: var(--thermo-band); fill-opacity: 0.3; stroke: none; }
.thermo-face-rim { fill: none; stroke: var(--thermo-band); stroke-width: 1.5; stroke-linecap: butt; }
.thermo-face-tick line, .thermo-face-spoke { stroke: var(--hud-ink); stroke-width: 1.5; stroke-linecap: round; }
.thermo-face-tick-halo line, .thermo-face-spoke-halo { stroke: var(--dial-halo); stroke-width: 4.5; stroke-linecap: round; }
.thermo-face-hand { stroke: var(--hud-ink); stroke-width: 3; stroke-linecap: round; }
.thermo-face-hand-halo { stroke: var(--dial-halo); stroke-width: 6; stroke-linecap: round; }
.thermo-face-hand-g { transform-origin: 44px 44px; transition: transform 0.15s var(--ease); }
/* the hub and the hollow bead are opaque (the reduced-transparency disc colour), so the wedge's tip and the hand under them never
   show through and a hollow bead never reads half filled */
.thermo-face-hub { fill: #1b2336; stroke: var(--hud-ink); stroke-width: 1.5; }
.thermo-face-bead-halo { fill: none; stroke: var(--dial-halo); stroke-width: 4.5; }
.thermo-face-bead { fill: #1b2336; stroke: var(--hud-ink); stroke-width: 1.5; }
.thermo-face-bead.cosy { fill: var(--hud-ink); }
/* the build drawer's thermostat block (ui/catalogue.js): the face as a slider, 'cooler' and 'warmer' */
.drawer .thermo-block { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 6px 12px; margin: 0 0 12px; }
.drawer .thermo-block > .thermo-label { grid-column: 1 / -1; }
.drawer .thermo-slider { position: relative; width: 88px; height: 88px; border-radius: 50%; margin-left: 4px; }   /* room for its 4 px ring inside the scroller */
.drawer .thermo-slider .thermo-face { width: 88px; height: 88px; display: block; }
/* the chip's two-tone ring (TH-11, TH-13): a white outline over a dark keyline, so one of them holds 3:1 over the drawer glass
   on any wall, where the accent alone sinks under 3:1 over the brighter ones */
.drawer .thermo-slider:focus-visible { outline: 2px solid #fff; outline-offset: 2px; box-shadow: 0 0 0 4px #0b0e14; }
.drawer .thermo-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.drawer .thermo-buttons .btn { min-height: 44px; min-width: 44px; }
.drawer .thermo-block > .muted { grid-column: 1 / -1; margin: 0; }
@media (prefers-reduced-motion: reduce) {
  .hud .hud-dial, .hud-thermo, #touch.ink-touch .dial-wheel .dial-gain, .dial-thermo, .thermo-face-hand-g, #touch.ink-touch .dial-wheel .dial-knurl { transition: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .thermo-face-back { fill: #1b2336; }
  .hud-thermo-chip { background: #1b2336; -webkit-backdrop-filter: none; backdrop-filter: none; }
}
:root.no-glass .hud-thermo-chip { -webkit-backdrop-filter: none; backdrop-filter: none; }
@media (forced-colors: active) {
  /* the face draws in the theme's own pair, light or dark: the disc, the hub, the hollow bead and every halo in Canvas, the
     ink in CanvasText, the wedge and its rim in Highlight, exactly (forced-color-adjust: none) */
  .thermo-face { forced-color-adjust: none; }
  .thermo-face-back, .thermo-face-hub, .thermo-face-bead { fill: Canvas; }
  .thermo-face :is(.thermo-face-tick-halo line, .thermo-face-spoke-halo, .thermo-face-hand-halo, .thermo-face-bead-halo, .dial-gain-track-halo) { stroke: Canvas; }
  .thermo-face-band { fill: Highlight; fill-opacity: 0.6; }
  .thermo-face-rim { stroke: Highlight; }
  .thermo-face :is(.thermo-face-tick line, .thermo-face-spoke, .thermo-face-hand, .thermo-face-hub, .thermo-face-bead, .dial-gain-track) { stroke: CanvasText; }
  .thermo-face-bead.cosy { fill: CanvasText; }
}
/* the art studio: a dark glass desk over the room, white controls; the sheet stays paper and the brush cursor stays ink */
#studio { --ink: #ffffff; --paper: #0b0e14; --bg: var(--glass); }
#studio .art-studio { -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); color: #fff; }
/* .ui pads every layer by the 16 px gutters; the desk's blur and tint reach back out over them to the screen edges, and its
   content pads in by the same amount, so nothing inside moves */
#studio .art-studio { left: calc(-1 * var(--gutter-l)); right: calc(-1 * var(--gutter-r)); padding-left: var(--gutter-l); padding-right: var(--gutter-r); }
#studio .art-studio button, #studio .art-studio select { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); }
#studio .art-studio button[aria-pressed="true"] { text-shadow: none; }
#studio .art-scrub, #studio .art-toast { color: #fff; -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); box-shadow: var(--glass-shadow); }
#studio .art-cursor { border-color: #0b0e14; }
#studio .art-sheet { box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.6), var(--glass-shadow); }
/* a laptop's art stick (bottom left, up to 130 px in) and A / B (bottom right, up to 136 px in) sit on the touch layer above the
   studio while it is open; the studio keeps its tray at the bottom there, so the tray keeps clear of both sides */
:root:has(#touch.ink-touch.art-only.art) #studio .art-tray { padding-left: 128px; padding-right: 128px; }
@media (prefers-reduced-transparency: reduce) {
  .sub, .hud-clock, .hud-notice, .hud-toast, .hud-stats, .hud-keys, .hud-heat, .hud-art, .hud-view, #studio .art-studio { -webkit-backdrop-filter: none; backdrop-filter: none; }
  :root { --hud-halo: #1b2336; --dial-halo: #0b0e14; }
  .sub { background: #1b2336; }
  #studio { --bg: #14161a; }
  #touch.ink-touch .dial-wheel.has-gain { background: #1b2336; }
}

/* ---- the 3D boots before the glass (main.js): no backdrop blur until the first room frame is up (gl-booting, unseen under
   the gate's scrim and over a canvas that is still one flat colour), and #noglass keeps it off for an A/B test on a phone.
   Only the blur goes: the 20 % tint and the shadows stay, so the panels read the same ---- */
:root.gl-booting :is(.panel, .drawer, .sub, .hud-clock, .hud-notice, .hud-toast, .hud-stats, .hud-keys, .hud-heat, .hud-art, .hud-view, #touch button, #touch .dial-wheel, #touch .stick-ring, #touch .stick-knob, #studio .art-studio, #studio .art-scrub, #studio .art-toast, #studio .art-radial),
:root.no-glass :is(.panel, .drawer, .sub, .hud-clock, .hud-notice, .hud-toast, .hud-stats, .hud-keys, .hud-heat, .hud-art, .hud-view, #touch button, #touch .dial-wheel, #touch .stick-ring, #touch .stick-knob, #studio .art-studio, #studio .art-scrub, #studio .art-toast, #studio .art-radial, .boot.wake) {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}
/* the wake chip: #boot shrunk to one small glass chip at the top, shown only when the watchdog could not bring the room back */
.boot.wake {
  inset: auto;
  left: 50%;
  top: calc(84px + var(--inset-t));
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 32px);
  padding: 8px 16px;
  font-family: var(--font-body);
  font-size: 15px;
  color: #fff;
  background: var(--glass);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  box-shadow: var(--glass-shadow);
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.5);
  border: 1.5px solid rgba(255, 255, 255, 0.6);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
/* the art studio covers the room and the watchdog does not watch it, so a chip raised before it opened waits until it closes */
#studio:not([hidden]) ~ .boot.wake { visibility: hidden; }
/* the test panel's renderer line: backend, GPU, frames, and whether a kick or the watchdog stepped in */
.test-diag { flex: 1 0 100%; margin: 0; font-family: var(--font-data); font-size: 12px; color: var(--muted); overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }

/* ---- wardrobe (Appendix E.4) ---- */
/* an overlay of its own over the live room (no scrim: the 3P preview is the game's camera); desktop: the preview hit area
   beside a dark-glass panel; phone (≤ 719 px, or .sheet on a coarse pointer): the preview above a bottom sheet */
#wardrobe { z-index: 8; }
.ui:has(> #wardrobe:not([hidden])) > #touch, .ui:has(> #wardrobe:not([hidden])) > #subtitles, .ui:has(> #wardrobe:not([hidden])) > #hud { visibility: hidden; }
.wardrobe-wrap {
  position: absolute; inset: 0;
  display: grid; grid-template-columns: minmax(0, 1fr) min(460px, 44%); grid-template-rows: minmax(0, 1fr); gap: 16px;
  padding: calc(12px + var(--inset-t)) 0 calc(12px + var(--inset-b));
  pointer-events: none; min-width: 0;
}
.ward-preview { grid-area: 1 / 1; min-width: 0; min-height: 0; pointer-events: auto; touch-action: none; cursor: grab; border-radius: var(--radius); }
.ward-preview.dragging { cursor: grabbing; }
.ward-preview-bar {
  grid-area: 1 / 1; align-self: end; justify-self: start; z-index: 1; max-width: 100%;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 6px 8px;
  /* the panel's darker local glass and its halo on the type: the bar sits over the brightest part of the room (the lamp
     and the lit floor), where the plain 20 % glass left its labels at 2.8–3.4:1 */
  background: rgba(8, 10, 14, 0.6); -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); box-shadow: var(--glass-shadow);
  border: 1.5px solid rgba(255, 255, 255, 0.6); border-radius: 999px; color: #fff; pointer-events: auto;
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.85), 0 1px 2px rgba(0, 0, 0, 0.6);
}
.ward-preview-bar .btn { min-height: 32px; color: #fff; border-color: rgba(255, 255, 255, 0.6); }
.ward-pose { display: inline-flex; align-items: center; gap: 6px; }
.ward-pose select { color: #fff; border-color: rgba(255, 255, 255, 0.6); background: rgba(255, 255, 255, 0.08); }
.panel.wardrobe {
  grid-area: 1 / 2; align-self: stretch; min-width: 0; min-height: 0; max-height: 100%;
  display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto; padding: 14px 16px;
  /* no scrim over the room (the preview is the room), so the panel carries its own: a darker local glass, and a halo on
     the type, keep its small text ≥ 4.5:1 even over the brightest lamp-lit wall (the menus get this from their scrim) */
  background: rgba(8, 10, 14, 0.6);
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.85), 0 1px 2px rgba(0, 0, 0, 0.6);
}
.ward-handle { display: none; }
/* the title and the status line share one line (they took two, 48 px) */
.panel.wardrobe > header { margin-bottom: 6px; gap: 2px 12px; flex-wrap: nowrap; }
.panel.wardrobe > header h2 { flex: 0 1 auto; }
.panel.wardrobe > header .menu-status { flex: 1 1 0; min-width: 0; margin: 0; font-size: 13px; }
.ward-tabs { display: flex; gap: 4px; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; padding: 0 0 6px; margin: 0 0 6px; border-bottom: 1px dashed var(--muted); touch-action: pan-x; }
.ward-tabs::-webkit-scrollbar { display: none; }
/* more tabs off the edge (a phone): the bar fades out on that side */
.ward-tabs.more-right { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent); }
.ward-tabs.more-left { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent); }
.ward-tabs.more-left.more-right { -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); }
.ward-tabs .tab { flex: 0 0 auto; }
.ward-panel { min-height: 0; overflow: auto; overscroll-behavior: contain; padding: 2px 4px 2px 2px; }
.ward-h { display: flex; align-items: baseline; gap: 8px; font-size: 14px; margin: 12px 0 6px; color: var(--muted); }
.ward-panel > .ward-h:first-child { margin-top: 2px; }
.ward-note { margin: 4px 0 6px; }
.ward-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.ward-filters .seg { margin: 0; }
/* the style heading row; its filter summary chip shows only on the phone sheet, where the chips fold away behind it */
.ward-style-head { display: flex; align-items: baseline; justify-content: space-between; gap: 6px 10px; flex-wrap: wrap; }
.ward-style-head .ward-h { margin-bottom: 4px; }
.ward-filter-toggle { display: none; }
.ward-panel .seg { margin: 2px 0; }
.ward-panel .seg .btn { min-height: 32px; padding: 3px 10px; font-size: 14px; }
.ward-grid { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 8px; margin: 6px 0; }
.ward-card { padding: 8px 10px; }
.ward-card .card-title { font-size: 15px; }
/* the selected style is filled and ticked; keyboard focus is a separate white ring, so the two never look alike */
.ward-card[aria-pressed="true"] { background: rgba(227, 147, 79, 0.32); outline: 2px solid var(--accent); outline-offset: -2px; padding-right: 28px; }
.ward-card[aria-pressed="true"]::before { content: '✓'; position: absolute; top: 6px; right: 7px; width: 18px; height: 18px; display: grid; place-items: center; border-radius: 50%; background: var(--accent); color: #0b0e14; font-size: 12px; font-weight: 700; line-height: 1; text-shadow: none; }
.ward-card:focus-visible { outline: 2px solid #fff; outline-offset: 2px; box-shadow: 0 0 0 4px rgba(11, 14, 20, 0.9); }
.ward-card[aria-pressed="true"]:focus-visible { outline: 2px solid #fff; outline-offset: 2px; box-shadow: 0 0 0 4px rgba(11, 14, 20, 0.9), inset 0 0 0 2px var(--accent); }
.ward-quick-card { border-style: dashed; }
.ward-row { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 8px; align-items: center; margin: 6px 0; }
.ward-row-label { color: var(--muted); font-weight: 700; }
.ward-swatches { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 7px; min-width: 0; padding: 3px; }
.ward-break { flex-basis: 100%; height: 0; }
.ward-swatch {
  position: relative; flex: 0 0 auto; width: 32px; height: 32px; padding: 0; border-radius: 50%;
  background: var(--sw, #888); border: 1.5px solid var(--line); cursor: pointer; pointer-events: auto;
  transition: box-shadow 0.15s var(--ease), transform 0.15s var(--ease);
}
.ward-swatch:hover { transform: scale(1.08); }
.ward-swatch[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--accent); }
.ward-swatch[aria-pressed="true"]::after { content: '✓'; position: absolute; inset: 0; display: grid; place-items: center; font-size: 15px; font-weight: 700; line-height: 1; color: #0b0e14; text-shadow: none; }
.ward-swatch[data-tone="dark"][aria-pressed="true"]::after { color: #fff; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); }
.ward-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (pointer: coarse) { .ward-swatch { width: 40px; height: 40px; } }
.ward-tone { display: inline-grid; justify-items: center; gap: 3px; }
.ward-cap { font-size: 12px; color: var(--muted); white-space: nowrap; }
.ward-caption { margin: 6px 0 2px; color: var(--muted); }
.ward-paws-row { margin: 10px 0 4px; }
.ward-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin-top: 8px; padding-top: 10px; border-top: 1px dashed var(--muted); }
.ward-actions [data-action="done"] { margin-left: auto; }
.ward-glyph { display: inline-block; min-width: 1em; text-align: center; }
/* the chosen colour as it really is, beside the lamp-lit preview */
.ward-now { display: inline-flex; align-items: center; gap: 6px; padding: 0 4px; font-size: 13px; white-space: nowrap; }
.ward-now[hidden] { display: none; }
.ward-now-dot { width: 18px; height: 18px; border-radius: 50%; background: var(--sw, #888); border: 1.5px solid rgba(255, 255, 255, 0.8); box-shadow: 0 0 0 1px rgba(11, 14, 20, 0.6); }
/* phone: the preview above, the panel as a bottom sheet rounded only at the top; nothing scrolls sideways but the tab bar */
@media (max-width: 719px) {
  /* the sheet's row is a share of the wrap (inset 0 of the fixed frame); 58vh was the large viewport, taller than the screen while the toolbar shows */
  .wardrobe-wrap { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) var(--sheet-h, min(58%, 520px)); gap: 8px; padding-bottom: 0; }
  .ward-preview, .ward-preview-bar { grid-area: 1 / 1; }
  .panel.wardrobe { grid-area: 2 / 1; border-radius: 18px 18px 0 0; border-bottom: 0; padding: 4px 12px calc(8px + var(--inset-b)); grid-template-rows: auto auto auto minmax(0, 1fr) auto; }
  .ward-handle { display: block; justify-self: center; width: 64px; height: 22px; margin: 0 0 2px; padding: 0; border: 0; background: transparent; cursor: ns-resize; touch-action: none; position: relative; }
  .ward-handle::after { content: ''; position: absolute; left: 14px; right: 14px; top: 8px; height: 5px; border-radius: 3px; background: rgba(255, 255, 255, 0.75); }
  .panel.wardrobe > header h2 { font-size: 18px; }
  /* every tab in view (4 + 3): a sideways-scrolling bar hid Layer and cut Socks at 400 and 360 px */
  .ward-tabs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); overflow: visible; touch-action: auto; -webkit-mask-image: none; mask-image: none; }
  .ward-tabs .tab { min-width: 0; padding-left: 4px; padding-right: 4px; text-align: center; overflow: hidden; text-overflow: ellipsis; }
  /* the set chips on one row, the texture chips wrapping under them: nothing scrolls sideways or is cut off */
  .ward-filters { flex-wrap: wrap; overflow: visible; padding-bottom: 2px; }
  .ward-filters .seg { flex: 0 1 auto; flex-wrap: wrap; max-width: 100%; }
  .ward-panel > .ward-h-show { display: none; }
  /* the set and texture chips fold behind one summary chip, and the note goes to screen readers: two rows of style cards
     show in the default sheet instead of the tops of two */
  .ward-filter-toggle { display: inline-flex; align-items: center; gap: 4px; margin: 6px 0 2px; min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ward-filter-block:not(.open) { display: none; }
  .ward-filter-block .ward-note { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .ward-actions { flex-wrap: nowrap; margin-top: 4px; padding-top: 6px; }
  .ward-actions .ward-word { display: none; }
  .ward-actions .btn.small { min-width: 44px; }
  .panel.wardrobe::after { display: none; }
  .ward-preview-bar { border-radius: 16px; flex-wrap: nowrap; gap: 4px; padding: 4px 6px; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
  /* the colour chip goes on a phone: the header's status line names the colour, and the bar must fit 360 px */
  .ward-preview-bar .ward-now { display: none; }
  .ward-preview-bar .btn { min-height: 30px; padding: 2px 9px; }
  .ward-preview-bar .ward-word, .ward-pose > .small { display: none; }
  .ward-pose select { max-width: 9.5em; min-height: 30px; }
  .ward-grid { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
  .ward-actions { gap: 6px; }
}
.wardrobe-wrap.sheet { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) var(--sheet-h, min(58%, 520px)); gap: 8px; padding-bottom: 0; }
.wardrobe-wrap.sheet .ward-preview, .wardrobe-wrap.sheet .ward-preview-bar { grid-area: 1 / 1; }
.wardrobe-wrap.sheet .panel.wardrobe { grid-area: 2 / 1; border-radius: 18px 18px 0 0; border-bottom: 0; padding: 4px 12px calc(8px + var(--inset-b)); grid-template-rows: auto auto auto minmax(0, 1fr) auto; }
.wardrobe-wrap.sheet .ward-handle { display: block; justify-self: center; width: 64px; height: 22px; margin: 0 0 2px; padding: 0; border: 0; background: transparent; cursor: ns-resize; touch-action: none; position: relative; }
.wardrobe-wrap.sheet .ward-handle::after { content: ''; position: absolute; left: 14px; right: 14px; top: 8px; height: 5px; border-radius: 3px; background: rgba(255, 255, 255, 0.75); }
.wardrobe-wrap.sheet .ward-filters { flex-wrap: wrap; overflow: visible; padding-bottom: 2px; }
.wardrobe-wrap.sheet .ward-filters .seg { flex: 0 1 auto; flex-wrap: wrap; max-width: 100%; }
.wardrobe-wrap.sheet .ward-filter-toggle { display: inline-flex; align-items: center; gap: 4px; margin: 6px 0 2px; min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wardrobe-wrap.sheet .ward-filter-block:not(.open) { display: none; }
.wardrobe-wrap.sheet .ward-filter-block .ward-note { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.wardrobe-wrap.sheet .ward-actions { flex-wrap: nowrap; }
.wardrobe-wrap.sheet .panel.wardrobe::after { display: none; }
.wardrobe-wrap.sheet .ward-preview-bar { border-radius: 16px; }
/* the sheet's surprise / undo / swap / lock show their glyph alone once glyphButton puts the word in span.ward-word (the words stay
   in their aria-labels), so the actions take one row with done, not two */
.wardrobe-wrap.sheet .ward-actions .ward-word { display: none; }
.wardrobe-wrap.sheet .ward-actions .btn.small { min-width: 40px; }
/* the preview bar fits a 320 px phone: the pose select narrower (the bar scrolled sideways by 5 to 45 px and cut it) */
@media (max-width: 400px) {
  .ward-preview-bar [data-preview="closer"] .ward-word, .ward-preview-bar [data-preview="further"] .ward-word { display: none; }
  .ward-pose select { max-width: 7em; }
}
/* a landscape phone (or any short window): the preview beside a full-height panel. The 58 % sheet left 4 to 42 px of
   options there, and cropped the head off the top of the preview */
@media (orientation: landscape) and (max-height: 540px) {
  .wardrobe-wrap .ward-handle, .wardrobe-wrap.sheet .ward-handle { display: none; }
  .wardrobe-wrap, .wardrobe-wrap.sheet { grid-template-columns: minmax(0, 1fr) min(400px, 52%); grid-template-rows: minmax(0, 1fr); padding: calc(6px + var(--inset-t)) 0 calc(6px + var(--inset-b)); }
  .wardrobe-wrap .panel.wardrobe, .wardrobe-wrap.sheet .panel.wardrobe { grid-area: 1 / 2; border-radius: var(--radius); border-bottom: var(--border); padding: 8px 12px; grid-template-rows: auto auto minmax(0, 1fr) auto; }
  .wardrobe-wrap .ward-preview, .wardrobe-wrap .ward-preview-bar, .wardrobe-wrap.sheet .ward-preview, .wardrobe-wrap.sheet .ward-preview-bar { grid-area: 1 / 1; }
}
@media (prefers-reduced-transparency: reduce) {
  .ward-preview-bar { background: #1b2336; -webkit-backdrop-filter: none; backdrop-filter: none; }
}
/* coarse pointers: the wardrobe's touch targets are 44 px (swatches, chips, tabs, actions, the preview bar) */
@media (pointer: coarse) {
  .wardrobe-wrap .ward-swatch { width: 44px; height: 44px; }
  .wardrobe-wrap .ward-panel .seg .btn, .wardrobe-wrap .ward-actions .btn, .wardrobe-wrap .ward-tabs .tab, .wardrobe-wrap .ward-preview-bar .btn, .wardrobe-wrap .ward-pose select { min-height: 44px; }
  /* the preview bar's glyph buttons were 34 px wide (their words go on a phone); 40 still fits the bar in 320 px */
  .wardrobe-wrap .ward-preview-bar .btn { min-width: 40px; }
  /* the sheet's handle a 40 px target in the room its 22 px took (the .sheet rule's height won over the 30 px asked here): it
     reaches 8 px up into the gap over the sheet and 8 px down over the title, and its bar stays where it was */
  .wardrobe-wrap .ward-handle, .wardrobe-wrap.sheet .ward-handle { height: 40px; margin: -8px 0 -8px; }
  .wardrobe-wrap .ward-handle::after, .wardrobe-wrap.sheet .ward-handle::after { top: 16px; }
}
/* and on its side, where the preview column is 250 to 300 px and the bar's words are gone: four 40 px buttons and the 9.5em
   pose select ran 10 px past the bar at 667 x 375 and 23 at 640 x 360 (it scrolled sideways and cut the select). The select
   as narrow as on a 320 px phone, the gaps closer, and where even that is too wide (568 x 320) the select wraps under them */
@media (pointer: coarse) and (orientation: landscape) and (max-height: 540px) and (max-width: 719px) {
  .wardrobe-wrap .ward-preview-bar { gap: 2px; flex-wrap: wrap; }
  .wardrobe-wrap .ward-pose select { max-width: 7em; }
}

/* ---- coarse pointers: every control at least 40 px tall and nothing under 13 px. Last in the file, so it wins over each
   component's own size at the same specificity ---- */
@media (pointer: coarse) {
  .btn.small, .seg .btn, .tab, select, .ward-pose select, .hud-view-btn, .hud-art, .hud-heat, .panel.tests > header .btn, .ward-preview-bar .btn, .ward-panel .seg .btn, .afterglow-row .ag-controls .seg .btn, .remap td .btn { min-height: var(--tap-sm); }
  .placed-row .nudge .btn { min-width: 40px; }
  .drawer-toggle { min-height: 40px; }
  /* the gate's skip (a link-style button, 29 x 26), the report's folded rows ('Cuddles · n', 'keep this postcard') and the range
     sliders (16 px tall); a settings checkbox's label takes its taps (for=), its hit area grown to 40 px without growing the row */
  .btn.link { min-height: var(--tap-sm); min-width: var(--tap-sm); }
  .postcard details > summary.ach-row { min-height: var(--tap-sm); align-items: center; }
  .postcard details > summary:not(.ach-row) { padding: 10px 0; }
  input[type="range"] { height: 40px; }
  .field > label { padding: 9px 0; margin: -9px 0; }
  /* chips, data lines and the HUD's small labels; the debug stats line stays 11 px (an owner tool) */
  .chip, .chip.real, .range .range-val, .remap-key, .note .when, .postcard .stamp, .gate .countdown, .drawer .budget, .ward-cap, .hud-view-btn, .hud-art, .hud-heat, .test-mark, .test-detail, .test-diag { font-size: 13px; }
  /* the settings' seg rows (depth view, depth motion, sitting length): 44 px touch targets (Appendix G.3.10 MOT-23, G.6) */
  .a11y .seg .btn { min-height: 44px; }
}
