/* JFSN rooms — the homepage's design language as a shared grammar (2026-09-15).

   The site-wide theme (theme-unbuilt-archive.css) swaps colours; every page
   under it still wore the old light site's composition: italic grey titles
   with a red ink-stamp box, drones, archery targets, dimmed random hero
   photographs. This file carries what actually makes the homepage work —
   mono eyebrows, upright serif headlines with one italic phrase in the
   accent, hairline rules, tiered near-black surfaces, the matted vitrine,
   dashed frames for what is missing — and retires the old ornament.

   Opt-in per page: <html data-room="…">. A page joins only once it has been
   redesigned as a room and verified, so nothing changes on pages that
   haven't been (CLAUDE.md: prototype on one or two routes before rolling
   out). Grammar is shared; composition is not — each room gets one
   signature drawn from its own content, below its own section.

   Colour values are the homepage's own compiled roles
   (_shared/homepage-tailwind.css), not new ones. */

html[data-room]{
  --ua-s0:#0e0e10;      /* surface-container-lowest — mats, vitrines */
  --ua-s1:#131315;      /* surface — page */
  --ua-s2:#1b1b1d;      /* surface-container-low — quiet panels */
  --ua-text:#e5e1e4;    /* on-surface */
  --ua-text-2:#d0c5af;  /* on-surface-variant */
  --ua-muted:#99907c;   /* outline — labels, 5.9:1 on --ua-s1 */
  --ua-line:#4d4635;    /* outline-variant — every hairline */
  --ua-gold:#f2ca50;    /* primary */
  --ua-loss:#ff8040;    /* the homepage's Register of Loss badge */
  /* One accent per room, drawn from what the room holds. */
  --room-accent:var(--ua-gold);
}
html[data-room="loss"]{--room-accent:var(--ua-loss)}
html[data-room="last"]{--room-accent:var(--ua-loss)}

/* ── retired ornament ──
   Drones, the archery target, the dimmed random header photograph and the
   corner closeup were the light site's PRESS layer. On the dark ground they
   read as murk competing with the text, and the random header image put an
   unrelated work above every page's title.
   NOT retired: .brand-mark-anchor. Parking the mark on the back-to-top
   button (About, Stories) and its scroll exit (Register) are Jeff's call,
   2026-09-09, asserted by smoke check 36. */
html[data-room] .roamer,
html[data-room] .mast-bay,
html[data-room] .target-clip,
html[data-room] .page-visual,
html[data-room] .corner-closeup,
html[data-room] .drone-container-loss,
html[data-room] .drone-berth{display:none}

/* ── the bar: one row, like the homepage's dock ──
   .section-label and the imprint duplicated what aria-current already
   shows and forced a second row at 1440px (measured 115px tall). */
html[data-room] .runhead .section-label,
html[data-room] .runhead .who .imprint{display:none}
html[data-room] .runhead .who{font-style:normal;color:var(--ua-text);white-space:nowrap}
html[data-room] .runhead .who img{width:28px !important;height:28px !important}
html[data-room] .runhead .nav{font-size:11px;letter-spacing:.06em;color:var(--ua-muted)}
html[data-room] .runhead .nav a,
html[data-room] .runhead .nav a:visited{color:var(--ua-muted)}
html[data-room] .runhead .nav a:hover{color:var(--ua-text)}
html[data-room] .runhead .nav a[aria-current="page"]{color:var(--room-accent)}
html[data-room] .runhead::after{background:var(--room-accent);box-shadow:none}
html[data-room] .runhead .nav a{white-space:nowrap}
@media(min-width:1100px){
  html[data-room] .runhead{flex-wrap:nowrap}
}
/* 11px labels wrapped inside themselves at 1100 ("Register of / Loss");
   nav.js already steps its gap down across this same band. */
@media(min-width:1100px) and (max-width:1279px){
  html[data-room] .runhead .nav{font-size:10px;letter-spacing:.02em}
}

/* base.css parks the skip link at top:-40px, but it renders 44px tall, so a
   14px gold sliver showed at the top-left of every themed page (measured
   top:-30px on About). Unfocused it now sits fully out of view; base.css's
   own :focus{top:0} still brings it in, untouched. */
html[data-room] .skip-link:not(:focus){top:-80px}

/* ── eyebrow ── */
html[data-room] .breadcrumb{
  font-family:var(--mono);font-size:11px;letter-spacing:.12em;
  color:var(--ua-muted);margin-top:clamp(20px,3vw,36px)
}
html[data-room] .breadcrumb a,
html[data-room] .breadcrumb a:visited{color:var(--ua-muted)}
html[data-room] .breadcrumb a:hover{color:var(--ua-text)}
html[data-room] .breadcrumb [aria-current="page"]{color:var(--room-accent)}
/* header-enhancements.js injects a second trail (.breadcrumb-nav) into
   <main> on every page that already has this static one — two identical
   "Home / Stories" lines, measured on both rooms. The static trail is the
   one in the eyebrow position above the title, so the injected copy goes. */
html[data-room] .breadcrumb-nav{display:none}

/* ── headline: upright, one italic phrase in the accent ── */
html[data-room] .mast h1,
html[data-room] .ledger h1{
  font-style:normal;font-weight:400;letter-spacing:-.022em;line-height:1.02;
  color:var(--ua-text);padding:0;text-wrap:balance
}
html[data-room] .mast h1 em,
html[data-room] .ledger h1 em{font-style:italic;font-weight:400;color:var(--room-accent)}
/* Titles do not slide in. Each page's own titleSlideIn (100px from the right)
   is the generic entrance the homepage never uses. Scoped to above 700px on
   .mast h1 because below it motion.css replaces it with the approved
   "opening" exit (title and meta leave at different speeds; smoke-asserted).
   The Register's .ledger h1 has no primitive at any width. */
@media(min-width:701px){
  html[data-room] .mast h1{animation:none;will-change:auto}
}
html[data-room] .ledger h1{animation:none;will-change:auto}
html[data-room] .ink-stamp{
  display:inline;background:none;color:inherit;padding:0;box-shadow:none;animation:none
}

/* ── hairlines ── */
html[data-room] section h2{
  font-style:normal;font-weight:400;letter-spacing:-.015em;line-height:1.1;
  color:var(--ua-text);border-bottom:0;border-top:1px solid var(--ua-line)
}

/* ── page opening: title holds the left edge, the facts ledger sits right ── */
html[data-room] header.mast{
  border-bottom:1px solid var(--ua-line);
  padding:clamp(40px,7vw,104px) 0 clamp(28px,3vw,44px)
}
html[data-room] header.mast::after{display:none}   /* About's 3px drifting rule */
html[data-room] .mast h1{font-size:clamp(44px,6.4vw,96px)}
html[data-room] .mast .meta{
  font-size:11px;letter-spacing:.12em;color:var(--ua-muted);margin-top:22px
}
@media(min-width:940px){
  html[data-room] header.mast{
    display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:48px
  }
  html[data-room] .mast .meta{margin:0;text-align:right}
}
/* .standfirst is itself a <section>, so a room's section rhythm would open a
   hole between the title and the first paragraph (~220px measured on Stories). */
html[data-room] section.standfirst{margin:0;border-bottom:1px solid var(--ua-line);padding:40px 0 44px}
html[data-room] .standfirst::after{display:none}   /* About's drifting 1px rule */
html[data-room] .standfirst p{color:var(--ua-text-2)}
html[data-room] .standfirst p .drop{color:var(--room-accent);font-weight:400}

/* One progress indicator: the runhead's own underline already tracks the
   scroll, and a second 2px bar at the very top duplicated it. */
html[data-room] .read-progress{display:none}


/* ═══ READING ROOM — stories.html ═══
   Signature: Jeff's own words are the architecture. The page already
   separates his verbatim quotes (large) from software-written connective
   prose (small, grey); the room makes that the whole composition — title
   flush left, testimony in an inset column, a numbered chapter ledger in
   the margin that tracks where you are. Absent: any image above the title,
   any motion beyond the section reveal already on the page. */

html[data-room="reading"] .note{border-top:1px solid var(--room-accent);color:var(--ua-muted);font-size:11px}

html[data-room="reading"] section{margin:clamp(88px,10vw,150px) 0}
html[data-room="reading"] section h2{
  font-size:clamp(28px,3.4vw,46px);padding-top:28px;margin-bottom:24px
}
html[data-room="reading"] section h2::before{
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  color:var(--room-accent);margin-bottom:16px
}
html[data-room="reading"] .dateline{color:var(--ua-muted);margin:-8px 0 34px}

/* His words: the loudest thing in the building. */
html[data-room="reading"] .quote{
  font-size:clamp(26px,3.4vw,46px);line-height:1.2;letter-spacing:-.016em;
  max-width:24ch;color:var(--ua-text);
  border-left:1px solid var(--room-accent);
  padding-left:clamp(20px,2.4vw,36px);margin:clamp(44px,5vw,76px) 0
}
html[data-room="reading"] .attrib{font-size:11px;letter-spacing:.1em;color:var(--ua-muted);margin-top:18px}
/* Everything that is not his: quieter, narrower, never competing. */
html[data-room="reading"] .prose{font-size:15.5px;color:var(--grey);max-width:54ch}

html[data-room="reading"] .dialogue{
  background:var(--ua-s2);border-left:1px solid var(--ua-line);
  padding:clamp(20px,2.4vw,32px) clamp(20px,2.6vw,36px)
}
html[data-room="reading"] .dialogue .q{color:var(--ua-muted)}
html[data-room="reading"] .dialogue .a{color:var(--ua-text);font-size:clamp(19px,2.2vw,26px)}

/* Plates named in the testimony sit in the homepage's tactile mat, not on
   white card stock. */
html[data-room="reading"] .pb-frame{
  background:var(--ua-s0);border:1px solid var(--ua-line);
  box-shadow:inset 0 2px 12px rgba(0,0,0,.95)
}
html[data-room="reading"] .pb-plate:hover .pb-frame{border-color:var(--ua-muted);box-shadow:inset 0 2px 12px rgba(0,0,0,.95)}
html[data-room="reading"] .pb-note{border-top-color:var(--ua-line)}

/* Inset testimony column: the title holds the left edge, his words step in. */
@media(min-width:1100px){
  html[data-room="reading"] main > section:not(.standfirst){
    max-width:860px;margin-left:clamp(0px,7vw,120px)
  }
}

/* Chapter ledger. It is position:fixed at the right edge from 1400px, and
   the mast's right-aligned meta ran straight under it at 1440 (measured).
   Reserve its gutter only as far as the viewport actually lacks room: 260px
   at 1440, ~20px at 1920 where the centred column already clears it. */
@media(min-width:1400px){
  html[data-room="reading"] main{padding-right:max(0px,calc(300px - (100vw - 1360px) / 2))}
}
html[data-room="reading"] nav.toc{
  counter-reset:ch;top:112px;max-width:232px;
  font-family:var(--mono);font-size:11px;letter-spacing:.02em;
  border-left:1px solid var(--ua-line);padding-left:16px
}
html[data-room="reading"] nav.toc a{
  counter-increment:ch;position:relative;display:grid;grid-template-columns:2.6em 1fr;
  margin:0;padding:6px 0;max-width:none;color:var(--ua-muted)
}
html[data-room="reading"] nav.toc a::before{content:counter(ch,decimal-leading-zero);color:var(--ua-line)}
html[data-room="reading"] nav.toc a:hover{color:var(--ua-text)}
html[data-room="reading"] nav.toc a.active{color:var(--room-accent);font-weight:400}
html[data-room="reading"] nav.toc a.active::before{color:var(--room-accent)}
html[data-room="reading"] nav.toc a.active::after{
  content:"";position:absolute;left:-17px;top:6px;bottom:6px;width:1px;background:var(--room-accent)
}


/* ═══ THE EMPTY VITRINE — register-of-loss.html ═══
   Signature: the homepage's vitrine with nothing in it. A solid outer
   frame (the record exists) around a dashed inner frame (the object does
   not), held in view beside the ledger while its rows of "Not recorded"
   pass. On the dark ground the old faint-bordered void measured ~1000px of
   near-black at 1440px and read as a page that failed to load; absence has
   to be visibly built to be read as absence. Absent: drones, the random
   header photograph. */

html[data-room="loss"] .plate .void-mount{
  background:var(--ua-s0);
  border:1px dashed rgba(255,128,64,.45);
  outline:1px solid var(--ua-line);outline-offset:clamp(10px,1.3vw,16px);
  box-shadow:inset 0 2px 12px rgba(0,0,0,.95)
}
html[data-room="loss"] .plate{padding:clamp(10px,1.3vw,16px)}
html[data-room="loss"] .plate .plate-no{
  color:var(--room-accent);background:var(--ua-s1);
  top:calc(clamp(10px,1.3vw,16px) - 8px);left:calc(clamp(10px,1.3vw,16px) + 24px)
}
html[data-room="loss"] .plate .void-mount .vtext{color:var(--ua-text-2);font-size:clamp(16px,1.5vw,20px)}
html[data-room="loss"] .plate .void-mount .vtext small{color:var(--ua-muted)}
html[data-room="loss"] .plate .sig{color:var(--ua-muted);margin-top:22px}
@media(min-width:940px){
  html[data-room="loss"] .plate{position:sticky;top:88px;align-self:start}
  html[data-room="loss"] .plate .void-mount{
    width:min(100%,calc((100vh - 190px) * .8));margin-inline:auto
  }
}

html[data-room="loss"] .ledger h1{font-size:clamp(36px,3.8vw,58px);margin-bottom:10px}
html[data-room="loss"] .ledger .yr{color:var(--ua-muted)}
html[data-room="loss"] dl.rows{border-top:1px solid var(--ua-line)}
html[data-room="loss"] dl.rows div{border-bottom:1px solid var(--ua-line);padding:12px 0}
html[data-room="loss"] dl.rows div.absent{border-bottom-style:dashed}
html[data-room="loss"] dl.rows dt{color:var(--ua-muted);letter-spacing:.14em}

/* Counts as display type, as on the homepage's ledger row. */
html[data-room="loss"] .tally{background:var(--ua-s0);border:1px solid var(--ua-line);padding:18px 20px}
html[data-room="loss"] .tally .tally-label{color:var(--ua-muted)}
html[data-room="loss"] .tally .n{border-bottom-color:var(--ua-line);padding:10px 0}
html[data-room="loss"] .tally .n b{font-size:clamp(24px,2.2vw,32px);color:var(--ua-text);letter-spacing:-.01em}
html[data-room="loss"] .tally .n .r{color:var(--ua-loss)}
/* The lost population in the drawn ratio takes the room's accent. */
html[data-room="loss"] #ratio-field{--accent:var(--ua-loss)}
/* A ~70-word explanation set in uppercase mono read as a wall of caps on a
   phone (measured at 375px); keep the mono, drop the capitals. */
html[data-room="loss"] .ratio-caption{color:var(--ua-muted);text-transform:none;letter-spacing:.02em;line-height:1.7}

html[data-room="loss"] .story-link{border-left:1px solid var(--room-accent)}
html[data-room="loss"] .story-link .lbl{color:var(--room-accent)}

html[data-room="loss"] .named-losses h2{
  font-size:clamp(28px,3.2vw,44px);border-top:1px solid var(--ua-line);padding-top:28px
}
html[data-room="loss"] .named-entry{
  border:1px dashed var(--ua-line);border-color:rgba(255,128,64,.32);
  background:var(--ua-s0);padding:22px 22px 24px
}
html[data-room="loss"] .named-entry h3{font-size:clamp(18px,1.6vw,21px);color:var(--ua-text)}
html[data-room="loss"] .named-entry dl,
html[data-room="loss"] .named-entry dl div{border-color:var(--ua-line)}
html[data-room="loss"] .named-entry dt{color:var(--ua-muted)}
html[data-room="loss"] .named-entry dd{color:var(--ua-text-2)}
html[data-room="loss"] .named-entry .quote{border-left:1px solid var(--room-accent)}
html[data-room="loss"] .named-entry .confirm-note{color:var(--ua-muted)}

html[data-room="loss"] .desc{border-top:1px solid var(--ua-line);padding-top:24px}
html[data-room="loss"] .desc h3{color:var(--room-accent)}
html[data-room="loss"] .desc p{color:var(--ua-text-2)}
html[data-room="loss"] .desc .quote{border-left:1px solid var(--room-accent);font-size:18px;color:var(--ua-text)}
html[data-room="loss"] .prov{border-top:1px solid var(--ua-line)}
html[data-room="loss"] nav.plates a{border-top-color:var(--ua-line)}
html[data-room="loss"] nav.plates a:hover{border-top-color:var(--room-accent)}


/* ═══ THE LETTER — about.html ═══
   Signature: his voice, then his words. The recording is the one object in
   the room — a matted vitrine — and directly beneath it the transcript Jeff
   verified against it on 2026-09-15, set as his words are set everywhere
   (large, italic), lighting the sentence being spoken during playback. It
   was also the missing text alternative for the site's only audio of him.
   Around it, a single reading column and the "Five parts" note as a
   location ledger. Absent: drones, the archery target, the header photo,
   the drifting rules, gold on every <strong>.

   The native <audio controls> is a decided, Jeff-approved choice (see the
   comment above .audio-block in about.html): its control is not restyled
   here, and keeps the light system skin it had, even though the page now
   declares color-scheme:dark. The card's heavy accent edge — also Jeff's
   call — is kept at its weight. */

html[data-room="letter"] section{margin:clamp(72px,8vw,120px) 0}
html[data-room="letter"] section h2{font-size:clamp(28px,3.2vw,42px);padding:28px 0 0;margin-bottom:22px}
html[data-room="letter"] section h2::after{display:none}
html[data-room="letter"] section h3{color:var(--room-accent);font-weight:500;letter-spacing:.14em;margin-top:40px}
html[data-room="letter"] .standfirst p{font-size:clamp(19px,1.9vw,24px);line-height:1.5;color:var(--ua-text)}
html[data-room="letter"] .content-main p{color:var(--ua-text-2);font-size:17px;line-height:1.7;max-width:62ch}
html[data-room="letter"] .content-main strong{color:var(--ua-text);font-weight:600}
html[data-room="letter"] .content-main p a{
  color:var(--ua-gold);text-decoration:underline;
  text-decoration-color:rgba(242,202,80,.4);text-underline-offset:3px
}

html[data-room="letter"] .audio-block{
  background:var(--ua-s0);border:1px solid var(--ua-line);border-left:4px solid var(--room-accent);
  box-shadow:inset 0 2px 12px rgba(0,0,0,.95);
  padding:24px 26px 26px 24px;margin-top:44px;max-width:65ch
}
html[data-room="letter"] .audio-block .lbl{color:var(--room-accent)}
html[data-room="letter"] .audio-block .ttl{font-size:22px;color:var(--ua-text)}
html[data-room="letter"] .audio-block audio{color-scheme:light}

html[data-room="letter"] .voice-transcript{margin:24px 0 0;padding:22px 0 0;border-top:1px solid var(--ua-line)}
html[data-room="letter"] .content-main .voice-transcript p{
  font-style:italic;font-size:clamp(20px,2vw,26px);line-height:1.42;letter-spacing:-.01em;
  color:var(--ua-text-2);max-width:none;margin:0
}
html[data-room="letter"] .transcript-seg{transition:color .35s ease}
html[data-room="letter"] .transcript-seg.active{color:var(--ua-gold)}
html[data-room="letter"] .content-main .voice-transcript .src{
  font-family:var(--mono);font-style:normal;font-size:11px;letter-spacing:.08em;
  color:var(--ua-muted);margin-top:16px
}
@media(prefers-reduced-motion:reduce){
  html[data-room="letter"] .transcript-seg{transition:none}
}

html[data-room="letter"] .next-steps{background:var(--ua-line);border-color:var(--ua-line)}
html[data-room="letter"] .next-step{background:var(--ua-s1);padding:22px 20px}
html[data-room="letter"] .next-step:hover,
html[data-room="letter"] .next-step:focus-visible{background:var(--ua-s2)}
html[data-room="letter"] .ns-label{color:var(--ua-text);font-weight:400;font-size:19px}
html[data-room="letter"] .ns-desc{color:var(--ua-muted)}
html[data-room="letter"] .next-step:hover .ns-label,
html[data-room="letter"] .next-step:focus-visible .ns-label{color:var(--room-accent)}
html[data-room="letter"] .next-step:hover .ns-desc,
html[data-room="letter"] .next-step:focus-visible .ns-desc{color:var(--ua-text-2)}

html[data-room="letter"] #commits-toggle{border-color:var(--ua-line);color:var(--ua-muted)}
html[data-room="letter"] .commit-entry{border-bottom-color:var(--ua-line)}

html[data-room="letter"] .page-nav{top:96px}
html[data-room="letter"] .page-nav .note,
html[data-room="letter"] body.principles-active .page-nav .note{
  border-top:1px solid var(--ua-line);font-size:11px;line-height:2.1;color:var(--ua-muted)
}
html[data-room="letter"] .page-nav .note a{color:var(--ua-muted)}
html[data-room="letter"] .page-nav .note a:hover{color:var(--ua-text)}
html[data-room="letter"] .page-nav .note a.active{color:var(--room-accent)}



/* ═══ THE MATTED GALLERY — favorites.html (generated by gen-favorites.py) ═══
   Signature: the one human judgement in a machine-written catalogue. Every
   plate hangs in the homepage's tactile mat at a generous size, three to a
   row at most, in its true proportion (the masonry never crops). The page's
   own "Show only what is his" switch is the room's single control: it lifts
   the software-written titles and estimated dates off the wall and leaves
   only what he did, which is the choosing. Estimated dates sit quieter than
   plate numbers, which are exact. Absent: white card stock, red hover glow,
   a fourth column that shrank each plate to thumbnail size.

   Untouched on purpose: every animation on .frame, its img, figcaption and
   the figures themselves. motion.css drives the phone plate crop, caption
   lag and tile rhythm here, and smoke asserts all four at 390px. */

html[data-room="gallery"] .claim{border-color:var(--ua-line);padding:40px 0 44px;margin:0 0 36px}
html[data-room="gallery"] .claim p{font-size:clamp(18px,1.7vw,22px);line-height:1.55;color:var(--ua-text-2)}
html[data-room="gallery"] .claim p .drop{color:var(--room-accent);font-weight:400}
html[data-room="gallery"] .claim b{color:var(--room-accent);font-weight:500}
html[data-room="gallery"] .ledger{color:var(--ua-muted);letter-spacing:.12em;margin-bottom:48px}

/* The switch: hairline and mono like every control; pressed reads as the
   accent, not as a white block (honesty.js paints --ink behind --paper text,
   which on this ground is a bright slab). */
html[data-room="gallery"] .honesty{color:var(--ua-muted);margin-top:22px}
html[data-room="gallery"] .honesty button{border-color:var(--ua-line);color:var(--ua-text)}
html[data-room="gallery"] .honesty button:hover{border-color:var(--ua-muted);color:var(--ua-text)}
html[data-room="gallery"] .honesty button[aria-pressed="true"]{
  background:var(--ua-s2);border-color:var(--room-accent);color:var(--room-accent)
}
html[data-room="gallery"] .honesty-preview{color:var(--ua-muted)}
html[data-room="gallery"] .honesty-note{
  background:var(--ua-s2);border-left:1px solid var(--room-accent);color:var(--ua-text-2)
}
html[data-room="gallery"] .honesty-note b{color:var(--ua-text)}

html[data-room="gallery"] .grid{column-gap:clamp(24px,3vw,48px)}
@media(min-width:1000px){
  html[data-room="gallery"] .grid{column-count:3}
}
html[data-room="gallery"] .grid > figure{margin-bottom:clamp(32px,4vw,60px)}

html[data-room="gallery"] .frame{
  background:var(--ua-s0);border:1px solid var(--ua-line);
  padding:clamp(14px,1.6vw,24px);
  box-shadow:inset 0 2px 12px rgba(0,0,0,.95)
}
html[data-room="gallery"] figure a:hover .frame{
  border-color:var(--ua-muted);box-shadow:inset 0 2px 12px rgba(0,0,0,.95)
}
/* Imagined, not documentary: the mat itself breaks. */
html[data-room="gallery"] .frame:has(.stamp){border-style:dashed;border-color:rgba(255,107,107,.55)}

html[data-room="gallery"] figcaption{margin-top:14px;gap:5px}
html[data-room="gallery"] .cap-t{font-style:italic;font-size:17px;line-height:1.3;color:var(--ua-text)}
html[data-room="gallery"] figure a:hover .cap-t{color:var(--room-accent)}
html[data-room="gallery"] .cap-n{color:var(--ua-muted);letter-spacing:.1em}
html[data-room="gallery"] .cap-n .est{color:var(--faint)}
html[data-room="gallery"] .plate-link:focus-visible{outline-color:var(--room-accent)}

html[data-room="gallery"] nav.plates{border-top-color:var(--ua-line)}
html[data-room="gallery"] nav.plates a{color:var(--ua-muted)}
html[data-room="gallery"] nav.plates a:hover{color:var(--room-accent)}


/* ═══ THE EIGHT ROOMS BEFORE THIS ONE — working-history.html ═══
   Signature: each preserved site as a framed threshold -- a real sandboxed
   iframe behind a solid hairline, its year in mono, "Enter site ↗"
   (docs/current/LINK-BUTTON-GRAMMAR.md's own external-link verb, which
   this page's generated markup never actually used -- it said "Open").
   The strata/marginalia/generation-diff features are real, substantive
   organization (a technology timeline, dated annotations, an old-vs-new
   comparison), not decoration -- kept and re-skinned into the room's
   hairline/mono language rather than removed. Absent: drones, the
   ink-stamp box, the pure #0f0/#f00 status dot (softened to the room
   accent so it doesn't clash with the gold palette). */

/* This page's drones live under their own class names (.drone-seam/
   .drone-craft in marginalia and apparatus), not .mast-bay, so the shared
   retirement rule at the top of this file never reached them. */
html[data-room="history"] .drone-seam{display:none}

html[data-room="history"] .standfirst p .drop{color:var(--room-accent)}
html[data-room="history"] .note{border-top:1px solid var(--room-accent);color:var(--ua-muted)}

html[data-room="history"] .spatial-breadcrumb .label{color:var(--ua-muted)}
html[data-room="history"] .spatial-breadcrumb .location{color:var(--room-accent)}

html[data-room="history"] .sites-head{
  border-bottom:1px solid var(--ua-line);color:var(--ua-muted);font-weight:400
}
html[data-room="history"] .sites-head span:last-child{color:var(--ua-muted)}
html[data-room="history"] .sites-layout-toggle button{
  border-color:var(--ua-line);color:var(--ua-text-2);background:transparent
}
html[data-room="history"] .sites-layout-toggle button:hover,
html[data-room="history"] .sites-layout-toggle button.active{
  background:var(--ua-s2);color:var(--room-accent)
}

/* the threshold */
html[data-room="history"] .site{border-bottom-color:var(--ua-line)}
html[data-room="history"] .site:hover{box-shadow:none;background:var(--ua-s0)}
html[data-room="history"] .site .thumb{
  border-color:var(--ua-line);background:var(--ua-s0);
  box-shadow:inset 0 2px 12px rgba(0,0,0,.95)
}
html[data-room="history"] .site .yr{color:var(--ua-muted)}
html[data-room="history"] .site .yr.absent{color:var(--room-accent)}
html[data-room="history"] .site:hover .yr{color:var(--ua-text)}
html[data-room="history"] .site h2{font-style:italic;font-weight:400;color:var(--ua-text)}
html[data-room="history"] .site:hover h2{color:var(--room-accent);text-shadow:none}
html[data-room="history"] .site .what{color:var(--ua-text-2)}
html[data-room="history"] .site dl{color:var(--ua-muted)}
html[data-room="history"] .site dl b{color:var(--ua-text)}
html[data-room="history"] .site:hover dl b{color:var(--room-accent)}
html[data-room="history"] .site .why{color:var(--ua-muted);border-left-color:var(--ua-line)}
html[data-room="history"] .site:hover .why{color:var(--ua-text-2);border-left-color:var(--room-accent)}
/* Real, not decorative: a live status pulse on each preserved site. The
   original #0f0/#f00 read as debugger-console green/red against gold and
   near-black; the room accent for online, --ua-muted (no alarm colour,
   since "offline" here always means "intentionally retired", not an
   error) for offline. */
html[data-room="history"] .site-status.online{background:var(--room-accent);box-shadow:0 0 6px var(--room-accent)}
html[data-room="history"] .site-status.offline{background:var(--ua-muted);box-shadow:none}

html[data-room="history"] .site .open{
  border-color:var(--ua-line);color:var(--ua-text);width:auto;padding:12px 18px
}
html[data-room="history"] .site .open:hover{background:var(--ua-s2);color:var(--room-accent)}
html[data-room="history"] .site .open:focus-visible{outline-color:var(--room-accent)}

html[data-room="history"] .site-preview-frame{border-color:var(--ua-line)}
html[data-room="history"] .site-preview-frame.active{border-color:var(--room-accent);box-shadow:none}
html[data-room="history"] .site-open-full{background:rgba(14,14,16,.9);color:var(--ua-text)}
html[data-room="history"] .site-open-full:hover{background:var(--room-accent);color:var(--ua-s0)}
html[data-room="history"] .site-preview-label{background:rgba(14,14,16,.9);color:var(--ua-text-2)}

/* the timeline */
html[data-room="history"] .strata{border-top-color:var(--ua-line);border-bottom-color:var(--ua-line)}
html[data-room="history"] .strata-layer{
  border-left-color:var(--room-accent);background:var(--ua-s0) !important
}
html[data-room="history"] .strata-label{color:var(--ua-muted)}
html[data-room="history"] .strata-year{color:var(--ua-muted)}
html[data-room="history"] .strata-layer p{color:var(--ua-text-2)}
html[data-room="history"] .strata-layer:focus-visible{outline-color:var(--room-accent)}

/* the annotations */
html[data-room="history"] .marginalia{border-top-color:var(--ua-line);border-bottom-color:var(--ua-line)}
html[data-room="history"] .marginalia-year{color:var(--ua-muted)}
html[data-room="history"] .marginalia-text{color:var(--ua-muted)}
html[data-room="history"] .marginalia-entry:hover .marginalia-text{color:var(--ua-text-2)}
html[data-room="history"] .marginalia-text strong{color:var(--ua-text)}

/* the diff slider */
html[data-room="history"] .generation-diff-handle{background:var(--room-accent)}
html[data-room="history"] .generation-diff-slider:hover .generation-diff-handle{
  box-shadow:-2px 0 8px rgba(242,202,80,.4)
}

/* the technical apparatus */
html[data-room="history"] .apparatus{border-top-color:var(--ua-line)}
html[data-room="history"] .apparatus-head{color:var(--ua-muted)}
html[data-room="history"] .apparatus-list a{color:var(--room-accent);border-bottom-color:transparent}
html[data-room="history"] .apparatus-list a:hover{border-bottom-color:var(--room-accent);color:var(--ua-text)}
html[data-room="history"] .apparatus-list a:focus-visible{outline-color:var(--room-accent);background:none}

html[data-room="history"] .colophon a{border-bottom-color:var(--room-accent);color:var(--room-accent)}
html[data-room="history"] .colophon a:hover{border-bottom-color:var(--ua-text);color:var(--ua-text)}

html[data-room="history"] .gen-standfirst{color:var(--ua-muted)}


/* ═══ THE CONTACT SHEET — motif-recurrence.html ═══
   Signature: dense strips, one per motif, each a horizontal filmstrip of
   real thumbnails sorted oldest to newest. The count sits at the strip's
   own head as display type (already how the lede reads: "in 600 works" —
   the room just gives every row that same weight). Half of this page's
   CSS was for a filter/vocabulary system with no matching markup left
   anywhere (.vocab/.m/.status/.bars/.decades/.anachron/.field/.w) --
   confirmed dead by querying the live DOM, not left alone as unknown; not
   styled here since nothing renders it. Absent: interpretation of what a
   motif "means" -- the page's own disclose text already says these are a
   machine's reading, checkable by looking, and the room adds nothing to
   that claim. */

/* This page's <header> never carried class="mast" -- the shared headline
   rule (html[data-room] .mast h1) never reached it, so "Recurrence" would
   otherwise still render at its old unthemed default. Not added here:
   the shared grammar itself doesn't need forcing on. This page's own
   pattern -- a small label over the room's real signature line -- fits
   "dense reference page" better than a full-width hero would, so it is
   restyled in place rather than restructured to match. */
html[data-room="motifs"] h1{
  color:var(--ua-muted);font-family:var(--mono);font-weight:600;
  letter-spacing:.22em
}
html[data-room="motifs"] .lede{color:var(--ua-text);font-size:clamp(20px,2.2vw,28px)}
html[data-room="motifs"] .lede b{color:var(--room-accent)}
html[data-room="motifs"] .sub{color:var(--ua-muted)}
html[data-room="motifs"] .disclose{border-left-color:var(--room-accent);color:var(--ua-muted)}
html[data-room="motifs"] .disclose strong{color:var(--ua-text)}

html[data-room="motifs"] .motif-label .name{color:var(--ua-text)}
html[data-room="motifs"] .motif-label .count{color:var(--room-accent);font-weight:600}
html[data-room="motifs"] .motif-item{background:var(--ua-s0)}
html[data-room="motifs"] .motif-item::after{box-shadow:inset 0 0 0 0 var(--room-accent)}
html[data-room="motifs"] .motif-item:hover::after{box-shadow:inset 0 0 0 2px var(--room-accent)}
html[data-room="motifs"] .motif-item:focus-visible{outline-color:var(--room-accent)}
html[data-room="motifs"] .motif-item.comp::before{background:var(--room-accent)}
html[data-room="motifs"] .motif-strip{scrollbar-color:var(--ua-line) transparent}
html[data-room="motifs"] .motif-strip::-webkit-scrollbar-thumb{background:var(--ua-line)}
html[data-room="motifs"] .motif-strip::-webkit-scrollbar-thumb:hover{background:var(--ua-muted)}

html[data-room="motifs"] .named-groups{border-top-color:var(--ua-line)}
html[data-room="motifs"] .named-groups h2{color:var(--ua-text);font-style:italic;font-weight:400}
html[data-room="motifs"] .ng{border-top-color:var(--ua-line)}
html[data-room="motifs"] .ng-t{font-style:italic}
html[data-room="motifs"] .ng-t a{color:var(--ua-text);border-bottom-color:var(--room-accent)}
html[data-room="motifs"] .ng-t a:hover{color:var(--room-accent);border-bottom-color:var(--room-accent)}
html[data-room="motifs"] .ng-t a:focus-visible{outline-color:var(--room-accent)}
html[data-room="motifs"] .ng-n{color:var(--ua-muted)}
html[data-room="motifs"] .ng-d{color:var(--ua-text-2)}
html[data-room="motifs"] .ng-plate{
  background:var(--ua-s0);border-color:var(--ua-line);
  box-shadow:inset 0 2px 12px rgba(0,0,0,.95)
}
html[data-room="motifs"] .ng-plate:hover{border-color:var(--ua-muted);opacity:1}
html[data-room="motifs"] .ng-plate:focus-visible{outline-color:var(--room-accent)}

html[data-room="motifs"] .colophon h4{color:var(--ua-muted)}
html[data-room="motifs"] .colophon p{color:var(--ua-muted)}
html[data-room="motifs"] .colophon a{color:var(--room-accent)}

/* Second drone container, its own id rather than .mast-bay -- effects.js
   still populates it at runtime, so hiding late (display:none, not
   removing the element) is what keeps that script harmless here. */
html[data-room="motifs"] #drone-recurrence-container{display:none}


/* ═══ THE MEASURED WALL — to-scale.html (generated by gen-to-scale.py) ═══
   Signature: one shared baseline (pixels per inch) and nothing else decides
   a plate's size on this page -- every proportion is the proportion of the
   real object. No "1:1" or true-size claim (screens differ; the room
   doesn't add one). This is the cleanest page yet: no drones, no ink-stamp,
   no archery target to retire.

   2026-09-15, Jeff's rule stated directly: every dimension on this site is
   an estimate, full stop -- even these 21, despite being real work (the
   CD-reference method), are not tape-measured figures. The generator's own
   copy called them "measured" more than a dozen times, in direct tension
   with catalog.json's own field name (dimensions_estimated) and its own
   "approx." prefix on every value. Corrected in the generator itself
   (measured -> estimated throughout; the per-plate caption, which had no
   qualifier of any kind, now carries "approx." matching the record pages'
   own convention) -- a content fix, not a visual one, but load-bearing for
   what this room is honestly showing. */

html[data-room="scale"] .mast{border-bottom:0;padding:clamp(28px,5vw,64px) 0 0}
html[data-room="scale"] .mast .lede{color:var(--ua-text-2)}
html[data-room="scale"] .mast .sub{color:var(--room-accent)}

html[data-room="scale"] .shelf-row{border-bottom-color:var(--ua-line)}
html[data-room="scale"] .tw-plate{
  background:var(--ua-s0);box-shadow:inset 0 2px 12px rgba(0,0,0,.95)
}
html[data-room="scale"] .tw-plate:focus-visible{outline-color:var(--room-accent)}
html[data-room="scale"] .tw-title{color:var(--ua-text)}
html[data-room="scale"] .tw-cap{color:var(--ua-muted)}
html[data-room="scale"] .gauge{color:var(--ua-muted)}
html[data-room="scale"] .gauge .foot,
html[data-room="scale"] .gauge .disc{border-color:var(--ua-muted)}

html[data-room="scale"] .pair-text h2,
html[data-room="scale"] .section > h2{color:var(--room-accent);font-style:italic;font-weight:400}
html[data-room="scale"] .pair-text p,
html[data-room="scale"] .section > p{color:var(--ua-text-2)}
html[data-room="scale"] .pair-note{color:var(--ua-text)}
html[data-room="scale"] .hint{color:var(--ua-muted)}

html[data-room="scale"] .absent{border-top-color:var(--ua-line)}
html[data-room="scale"] .absent h2{color:var(--ua-text);font-style:italic;font-weight:400}
html[data-room="scale"] .absent p{color:var(--ua-text-2)}
/* The 1,066-with-no-size-at-all number takes the loss-register colour --
   this is the same absence Register of Loss makes, not a coincidence. */
html[data-room="scale"] .absent .n{color:var(--ua-loss)}
html[data-room="scale"] .absent a{color:var(--room-accent)}

/* ═══ THE WORKING ARCHIVE — catalogue.html, D-record-page.html,
   F-record-composite.html (generated by gen-artwork-pages.py) ═══
   Purpose: find and examine works. Signature: the homepage's own
   vitrine (plate + ledger) IS the record page already, unchanged here —
   this room only carries the shared grammar (eyebrow, headline,
   hairlines) onto pages that already had the right bones. */
html[data-room="archive"] { --room-accent: var(--ua-gold); }

/* catalogue.html's ink-stamp box is a NAMED Jeff decision (2026-09-09,
   in-file comment: "same ink-stamp treatment as index.html's Never
   Existed"), reaffirmed by a contrast fix this same session
   (JEFF-DECISIONS-2026-09-15.md item 1). The shared grammar's reset
   (html[data-room] .ink-stamp) is more specific than catalogue's own
   .ink-stamp rule (attribute selector beats none), so it silently won
   and flattened the box to plain italic text before this override was
   added -- caught by comparing the live render against the documented
   decision, not by reading the CSS. Restored explicitly rather than
   letting a generic reset overrule a dated, named call. */
html[data-room="archive"] .ink-stamp{
  display:inline-block;background:var(--accent);color:var(--paper);padding:0 12px;
  box-shadow:0 12px 36px rgba(0,0,0,.75);animation:inkStamp .5s cubic-bezier(.2,1.6,.4,1) both .6s
}
