/* EZRA SIL — the Hebrew face (Q14, ruled 2026-08-09). Chosen because the WLC's
   POINTING AND CANTILLATION are exactly what a general-purpose face drops or
   misplaces; a system fallback renders the consonants and mangles the marks.

   unicode-range is why this is free until it is needed: the browser fetches
   the file only when a character in these blocks is actually asked for, so a
   Latin or Greek reader never pays for it. U+0590-05FF is Hebrew, U+FB1D-FB4F
   the presentation forms (the pointed ligatures the WLC uses).

   TTF rather than woff2 because that is what the SIL package ships; converting
   it would mean redistributing a derived binary, which is a bigger decision
   than a format. Licences: see NOTICE §1c — the FONT is OFL with Reserved Font
   Names "SIL" and "Ezra", and the Hebrew layout intelligence inside it is
   MIT/X11. Both travel with assets/fonts/Licenses.txt. */
@font-face {
  font-family: 'Ezra SIL';
  src: url('../assets/fonts/EzraSIL.ttf') format('truetype');
  font-display: swap;
  unicode-range: U+0590-05FF, U+FB1D-FB4F;
}

:root {
  /* bridge theme tokens to legacy variables */
  --color-bg: var(--theme-color-bg, #f5f5f5);
  --color-nodes: var(--theme-color-node, #555555);
  /* COLOR = DIRECTION OF TRAVEL (Howell 2026-07-23): ORBITAL movement (the
     focus ring's nodes and the magnifier) wears the band's own gray one
     step darker — applyTheme derives it from the active band, so every
     volume follows. RADIAL movement (the parent vessel, the pyramid stars)
     keeps --color-nodes. The fallback below only fires if applyTheme never
     ran. */
  --color-orbital: var(--theme-color-orbital, #5f5e5e);
  /* On-orbital label ink. DEFAULT = the volume's own text color (Howell
     2026-07-24: no label is ever white outside the search page — the paper
     ink was a relic of the demo red). A volume may still declare
     --theme-color-orbital-label if its orbital goes dark enough to need it;
     search mode's own rules keep search white regardless. */
  --color-orbital-label: var(--theme-color-orbital-label, var(--color-text));
  --color-text: var(--theme-color-text, #111111);
  --color-band: var(--theme-color-band, #7a7979);
  --color-accent: var(--theme-color-accent, #1f6feb);
  --color-magnifier-stroke: var(--theme-color-magnifier-stroke, #000000);
  --focus-node-radius: var(--theme-radius-node, 12px);
  --focus-node-stroke: var(--theme-stroke-node, 1px);
  --focus-node-font: var(--theme-font-label, 'Montserrat'), 'Ezra SIL', sans-serif;
  --magnifier-font: var(--theme-font-magnifier, 'Montserrat'), 'Ezra SIL', sans-serif;
  --focus-label-transform: uppercase;
  --space-2xs: var(--theme-space-2xs, 4px);
  --space-xs: var(--theme-space-xs, 6px);
  --space-sm: var(--theme-space-sm, 8px);
  --space-md: var(--theme-space-md, 12px);
  --space-lg: var(--theme-space-lg, 16px);
  --space-xl: var(--theme-space-xl, 20px);
  --space-2xl: var(--theme-space-2xl, 24px);
  --radius-panel: var(--theme-radius-panel, 14px);
  --radius-card: var(--theme-radius-card, 10px);
  --motion-fast: var(--theme-motion-duration-fast, 120ms);
  --motion-medium: var(--theme-motion-duration-medium, 200ms);
  --motion-slow: var(--theme-motion-duration-slow, 320ms);
  --motion-ease: var(--theme-motion-ease, cubic-bezier(0.33, 1, 0.68, 1));
}

* { box-sizing: border-box; }

/* Lock the page into a fixed, non-scrollable surface. A scrollable page is
   what lets a mobile browser (e.g. DuckDuckGo/Android) treat a vertical scrub
   as page-scroll and toggle its toolbar mid-gesture — our whole navigation is
   vertical swiping, so the page must never scroll. touch-action must sit on
   the SVG itself (the element the finger lands on), not just body — it is not
   inherited. overscroll-behavior kills the rubber-band/pull effects. */
html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  touch-action: none;
  /* Pin text auto-inflation OFF. Chrome-on-iOS "font boosts" a wide text block
     — inflating the RENDERED verse beyond its set px size — while our off-screen
     measure span (absolute, nowrap) escapes the boost, so rendered ran wider
     than measured and crowded the right edge. Only Chrome iOS boosts; Safari and
     DuckDuckGo don't, which is why it was Chrome-iOS-only (Howell 2026-07-22). */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Android Chromium (Chrome, DuckDuckGo) flashes a translucent highlight box
     over any element with a click handler on touch — on an SVG group that
     means its whole bounding rect (seen over the parent button). Not a link,
     not navigation: suppress it, and the text-selection long-press cousin. */
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}
body {
  position: fixed;
  inset: 0;
  background: var(--color-bg);
  font-family: var(--theme-font-body, var(--focus-node-font, 'Montserrat')), sans-serif;
}

svg {
  width: 100vw;
  /* 100vh is the toolbar-HIDDEN height on browsers with dynamic chrome, which
     over-sizes the canvas and crops the bottom; dvh is the dynamic (current)
     height. JS then pins the exact size (main.js). vh first as the fallback
     for browsers without dvh. */
  height: 100vh;
  height: 100dvh;
  touch-action: none;
}
/* Tapping can also FOCUS the handler-bearing element in some browsers, which
   paints a persistent outline box until the next tap. That box is what this
   suppresses, and only that.

   Q12 (0c): this rule used to name `:focus-visible` as well, which removed
   ALL keyboard focus indication in the canvas. The two selectors are not the
   same thing, and `:focus-visible` exists precisely to tell them apart — it
   fires for keyboard and assistive-technology focus and NOT for a tap. So the
   tap box stays suppressed and the keyboard ring comes back.

   This does not contradict THE PREMISE. The premise forbids TYPING — "it will
   never trigger a QWERTY keyboard, no typing, anywhere, ever" — which is about
   text entry, not about whether someone driving the instrument by keyboard or
   screen reader can see where they are. A focus ring nobody can see is not a
   simpler instrument; it is the same instrument with the lights off. */
svg :focus {
  outline: none;
}
svg :focus-visible {
  outline: 2px solid var(--color-nodes, #f2b41c);
  outline-offset: 3px;
}

/* Portrait gate: the wheel's geometry only works in portrait, so on a touch
   device held landscape we cover it with a rotate prompt rather than render it
   broken. Gated on pointer:coarse so desktop (landscape by nature) is never
   affected. Hidden by default. */
#portrait-gate {
  /* The sheet's dress lives OUTSIDE the media query so the engine can hold
     the sheet up in portrait for the frames between a turn and the reboot
     it triggers (O-259: a wheel booted sideways would otherwise show,
     cropped, before the page reloads). Only `display` is the query's. */
  display: none;
  position: fixed;
  inset: 0;
  z-index: 99999;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5vmin;
  padding: 8vmin;
  box-sizing: border-box;
  background: var(--color-bg, #868686);
  color: var(--color-text, #000);
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  text-align: center;
}
@media (orientation: landscape) and (pointer: coarse) {
  #portrait-gate {
    display: flex;
  }
  /* THE LANDSCAPE PORTAL (O-258, Howell 2026-11-01): once the boot has the
     volume in hand, the rotate prompt above becomes the volume's one plain
     page — its name in the splash card's face, the welcome, the house's
     addresses, the door to the other volume, and the turn-it-upright line
     last. Sized in vmin, which in landscape is the phone's HEIGHT, so the
     page fits a short screen without scrolling. The volume's palette
     dresses it: ground and ink are the theme's. */
  #portrait-gate.landscape-portal {
    justify-content: stretch;
    gap: 0;
    padding: 4vmin 6vmin 3vmin;
    text-align: center;
  }
  .portal-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: 88vw;
    height: 100%;
    margin: 0 auto;
  }
  /* The body is centred in what the rotate line leaves. */
  .portal-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2.6vmin;
    width: 100%;
  }
  .portal-title {
    margin: 0;
    /* The card's face unless the volume declares its own (inline). */
    font-family: 'EB Garamond', Georgia, serif;
    --portal-title-size: 6.4vmin;
    font-size: var(--portal-title-size);
    line-height: 1.15;
    letter-spacing: 0.04em;
  }
  /* The volume's mark at the head of the page, centred and large (the
     company's page, Howell 2026-11-02). */
  .portal-emblem {
    height: 27vmin;
    width: auto;
    display: block;
  }
  /* A page headed by an emblem spreads its pieces down the height rather
     than huddling in the middle (Howell 2026-11-02, from his phone, with
     the browser's bar eating the top: "very crowded at the bottom. So
     things need to be distributed vertically, even if it means reducing
     the size of the logo art slightly"). The foot is kept clear for the
     copyright line. */
  .portal-page--emblem .portal-body {
    justify-content: space-evenly;
    gap: 0;
    padding: 1.5vmin 0 10vmin;
    box-sizing: border-box;
  }
  /* ...or in the upper left corner, in capitals, wrapped into a short
     block (Howell 2026-11-02: "Make the descriptive line all caps and move
     it to the upper left corner"); mirrored under rtl. */
  .portal-corner {
    position: absolute;
    top: 10vmin;
    left: 5vw;
    max-width: 23vw;
  }
  [dir="rtl"] .portal-corner {
    left: auto;
    right: 5vw;
  }
  .portal-about.portal-about--corner,
  .portal-place {
    margin: 0;
    font-size: 3.3vmin;
    opacity: 0.85;
    text-align: start;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    line-height: 1.5;
  }
  /* The town under the description, a blank line between (Howell
     2026-11-02, drawn on his screenshot: "Move it over to the left under
     the company description ... a blank line in between"). */
  .portal-about--corner + .portal-place {
    margin-top: 1.5em;
  }
  /* What the business is: one quiet line under the name. */
  .portal-about {
    margin: 0;
    font-size: 3.3vmin;
    letter-spacing: 0.04em;
    opacity: 0.85;
    text-align: center;
    text-wrap: balance;
  }
  .portal-mails {
    display: flex;
    flex-direction: column;
    gap: 1.2vmin;
    font-size: 3.3vmin;
    letter-spacing: 0.03em;
  }
  .portal-mail {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0 1.4em;
    margin: 0;
  }
  /* Purposed rows are two aligned columns, so the gutter runs straight down
     the page instead of zigzagging with each phrase's length; the grid
     mirrors itself under dir=rtl. */
  .portal-mails--purposed {
    display: grid;
    grid-template-columns: auto auto;
    column-gap: 1.4em;
    row-gap: 1.2vmin;
    align-items: baseline;
  }
  .portal-mails--purposed .portal-mail {
    display: contents;
  }
  .portal-mails--purposed .portal-mail-purpose {
    text-align: end;
  }
  .portal-mails--purposed .portal-mail-address {
    text-align: start;
    justify-self: start;
  }
  .portal-mail-purpose {
    opacity: 0.72;
  }
  /* Words alone, in one row (the scripture volume: corrections · info). */
  .portal-mails--words {
    flex-direction: row;
    /* Howell: "put more space between the two email links" (was 2.4em). */
    gap: 0 6em;
    /* Lowered from the name without moving it (Howell: "Keep the ... name
       as is and where is, but lower the two email links slightly"): a
       relative nudge leaves the centred block, and so the name, in place. */
    position: relative;
    top: 3vmin;
    font-size: 3.6vmin;
    letter-spacing: 0.08em;
  }
  .portal-mail-address,
  .portal-door {
    color: inherit;
    text-decoration: none;
  }
  .portal-mail-address {
    border-bottom: 1px solid currentColor;
    padding-bottom: 1px;
  }
  .portal-door {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.6vmin;
  }
  .portal-door-image {
    height: 26vmin;
    width: auto;
    display: block;
  }
  /* Dark line art on a dark ground: drawn in the negative, so the lines
     carry the page as the caption does. */
  .portal-door-image--light {
    filter: invert(1);
  }
  .portal-door-label {
    font-size: 3.1vmin;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }
  /* The door back from the Bible is a name, not an emblem: small, under the
     addresses, in the card's face. */
  .portal-door--name .portal-door-label {
    font-family: 'EB Garamond', Georgia, serif;
    text-transform: none;
    letter-spacing: 0.06em;
    font-size: 3.2vmin;
    opacity: 0.8;
    border-bottom: 1px solid currentColor;
    padding-bottom: 1px;
  }
  /* The door in the lower right corner: the picture alone, no caption. */
  .portal-door--corner {
    position: absolute;
    right: 4vmin;
    bottom: 3.5vmin;
  }
  [dir="rtl"] .portal-door--corner {
    right: auto;
    left: 4vmin;
  }
  .portal-door--corner .portal-door-image {
    height: 13vmin;
    opacity: 0.5;   /* Howell: "give it 50% opacity so it's not so bright" */
  }
  /* The copyright at the foot, in the face and spacing of the link words. */
  .portal-copyright {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 3.5vmin;
    margin: 0 auto;
    max-width: 60vw;
    font-size: 2.6vmin;
    letter-spacing: 0.06em;
    opacity: 0.7;
    pointer-events: none;
  }
  .portal-rotate {
    margin: auto 0 0;
    font-size: 2.7vmin;
    letter-spacing: 0.06em;
    opacity: 0.6;
  }
}

/* Desktop gate: the instrument is a phone instrument — a mouse-driven
   screen gets a card pointing the reader at their phone instead of a
   broken-feeling wheel. The honest desktop signal is a fine primary
   pointer THAT HOVERS (screen size lies: a narrowed desktop window is
   still a desktop; a large phone is still a phone). Touch devices never
   match. Hidden by default, pure CSS like the portrait gate above. */
#desktop-gate {
  display: none;
}
@media (pointer: fine) and (hover: hover) {
  #desktop-gate {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 99999;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    padding: 48px;
    box-sizing: border-box;
    /* The gate is the BRAND'S card, not the volume's: catalog gray on
       every page, matching the gray baked into the QR's quiet zone. */
    background: #868686;
    color: #000;
    font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
    text-align: center;
  }
  #desktop-gate .desktop-gate-qr {
    width: min(280px, 40vmin);
    height: auto;
    /* The QR is a bitmap of hard squares — keep its edges square when scaled */
    image-rendering: pixelated;
  }
  #desktop-gate .desktop-gate-title {
    margin: 0 0 24px;
    font-size: 34px;
    letter-spacing: 0.1em;
    max-width: 90vw;
  }
  /* Case is set in the markup, never transformed: the mark is "MMdM",
     and "delle" rides lowercase inside the full name. */
  #desktop-gate .desktop-gate-text {
    margin: 12px 0 0;
    font-size: 21px;
    letter-spacing: 0.08em;
  }
  #desktop-gate .desktop-gate-sub {
    margin: 0;
    font-size: 15px;
    letter-spacing: 0.06em;
    opacity: 0.75;
  }
  #desktop-gate .desktop-gate-mail {
    margin: 24px 0 0;
    font-size: 14px;
    letter-spacing: 0.06em;
  }
  #desktop-gate .desktop-gate-mail a {
    color: inherit;
    opacity: 0.75;
    text-decoration: none;
    border-bottom: 1px solid currentColor;
    padding-bottom: 1px;
  }
  #desktop-gate .desktop-gate-mail a:hover {
    opacity: 1;
  }
}

/* THE COPYRIGHT LINE MOVED TO THE LANDSCAPE PAGE (O-258, Howell 2026-11-01).
   Hidden, not removed: the detail sector measures its real bottom edge to
   know where the glass's furniture ends (O-115), so it keeps its box and
   the reader's layout does not move by a pixel. */
#copyright-notice {
  visibility: hidden;
}

.copyright-notice {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* Q13 (0c), landed; REVERSED 2026-08-10; and the REMNANT REMOVED
     2026-08-17, because the reason it was kept turned out not to be true.

     Q13 added safe-area insets to this padding. `viewport-fit=cover` was
     landed with it and later removed — the phone was the check and the check
     said no — which left the insets here on the argument that they were
     INERT: without cover, every env() falls back to 0px, so the padding was
     said to compute exactly as it had before.

     THAT WAS MEASURED IN ONE BROWSER AND ASSUMED OF ALL OF THEM. Howell found
     the notice sitting some ninety pixels lower in DuckDuckGo than in Chrome,
     overlapping the leaf text, on the same device and the same page. This
     rule was the only one in the stylesheet using env() — and it was the only
     element that moved, which is what makes the diagnosis more than a story.
     A browser that reports a real inset without being asked to turns an
     "inert" term into a live one, and the notice drops by the status bar.

     So the insets are gone rather than kept. Removing them cannot change the
     browser where it already looks right — there the terms resolve to 0px and
     contribute nothing — and it removes the divergence everywhere else.

     If `viewport-fit=cover` is ever reconsidered, the insets come back WITH
     it, in the same commit, verified on more than one browser. Keeping dead
     arithmetic against a future that may not arrive is how a comment ends up
     asserting something no one has checked lately. */
  padding: calc(6px * var(--iframe-scale, 1))
           calc(10px * var(--iframe-scale, 1))
           calc(6px * var(--iframe-scale, 1))
           calc(10px * var(--iframe-scale, 1));
  color: rgba(255, 255, 255, 0.85);
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  font-size: calc(11px * var(--iframe-scale, 1));
  text-align: center;
  letter-spacing: 0.3px;
  pointer-events: none;
  z-index: 300;
}

.detail-version {
  color: rgba(255, 255, 255, 0.45);
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  font-size: calc(11px * var(--iframe-scale, 1));
  text-transform: uppercase;
  letter-spacing: 0.4px;
  text-align: center;
  padding-top: var(--space-xs, 6px);
}

.focus-ring-node {
  fill: var(--color-orbital); /* orbital travel */
  stroke: none;
}

.focus-ring-label {
  fill: var(--color-text);
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  font-size: clamp(calc(14px * var(--iframe-scale, 1)), 1.6vmin, calc(26px * var(--iframe-scale, 1)));
  text-transform: var(--focus-label-transform, uppercase);
  pointer-events: none;
}

/* The version footnote (Howell 2026-07-20): a factory stamp at the end of
   the manufacturers chain. Text alone — no circle at all (Howell's ruling);
   the numerals hold the chain seat themselves, in the line-work black of
   the boot splash, smaller than a working node's label. The circle element
   still anchors the geometry but never paints; taps pass straight through. */
.focus-ring-node.is-placebo {
  display: none;
  pointer-events: none;
}

.focus-ring-label.is-placebo {
  fill: #000;
  font-size: clamp(calc(10px * var(--iframe-scale, 1)), 1.15vmin, calc(19px * var(--iframe-scale, 1)));
}

/* The dimension button (D.3) — the wireframe globe, parked in a corner.
   A neutral icon (it does not display the current value). Toggles the
   secondary strata; tap-sized for the thumb (Howell 2026-07-21). */
#dimension-button,
#search-button {
  position: fixed;
  right: calc(3% * var(--iframe-scale, 1));
  bottom: calc(13% * var(--iframe-scale, 1)); /* clear of the focus-ring band,
     lifted off it a touch further (Howell 2026-07-22) — still well inside
     the DSUA/CPUA boundaries */
  width: clamp(52px, 13vmin, 96px);
  height: clamp(52px, 13vmin, 96px);
  padding: 0;
  margin: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  z-index: 260; /* above the strata layer so the globe stays tappable */
  opacity: 0.85;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: opacity 0.15s ease, transform 0.15s ease;
}
#dimension-button[hidden],
#search-button[hidden] { display: none; }
#dimension-button svg,
#search-button svg {
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  user-select: none;
  /* The globe's line-work rides currentColor — dark grey, not ink: present
     when sought, quiet when not (Howell 2026-07-22, tuned by eye). In the
     basement it takes the room's ink (O-278): the basement light sets
     --color-globe with the depth and removes it on the floors above. */
  color: var(--color-globe, #363636);
}
#search-button:hover { opacity: 1; }
/* THE GLOBE HAS ONE BRIGHTNESS, AND A FAINT ONE (Howell 2026-09-30: "I really
   don't want the globe to call attention to itself, so it should remain at
   the more faint level and stay there... it can even be slightly dimmer than
   it has been"). No hover, no pressed state, no swell — one size, one light. */
#dimension-button, #dimension-button:hover, #dimension-button[aria-pressed="true"] { opacity: 0.7; }
/* THE WATERMARK (O-246, Howell 2026-10-30: "a persistent watermark boldly
   displayed to alert the user that they are not looking at a Gregorian
   calendar"). The chosen plane's word, as he drew it: huge, translucent,
   running up the glass from lower left to upper right, under nothing and
   over everything, untouchable. Its size is set by the host to the word's
   length, so FRENCH REPUBLICAN fits where JULIAN fills. */
#watermark {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  user-select: none;
  z-index: 255; /* over the strata, under the dimension button */
  font-family: var(--magnifier-font, 'Montserrat'), sans-serif;
  font-weight: 700;
  font-size: var(--watermark-size, 26vmin);
  letter-spacing: 0.06em;
  white-space: nowrap;
  color: var(--color-text);
  opacity: var(--watermark-opacity, 0.05);
  transform: rotate(-60deg);
}
#watermark[hidden] { display: none; }

/* GONE WHILE THE RING TURNS (O-244, Howell 2026-10-30): the host tells the
   button when the ring is moving; it fades out for the turn and back at the
   settle, untouchable in between. */
#dimension-button.is-turning { opacity: 0; pointer-events: none; }

/* ── Search mode: the same room under a different light ───────────────────
   The ground dims for close work (computed from the ACTIVE theme in
   search-mode.js, so every volume dims in its own hue) and the gold ring
   leaps forward against it — the nodes and their on-node labels are
   deliberately left alone, one token doing the work of a repaint.

   But everything styled DARK-ON-LIGHT vanishes on a dark ground, and a
   volume theme outranks a plain .class rule — so these carry
   [data-theme] to sit above the theme's own selectors. Inverted here: the
   completion labels and fan lines, the carriage, the hollow lens, and the
   dividers icon itself, which is the way OUT and must never disappear
   (Howell 2026-07-22). Pyramid NODES are left to the theme: gold stars on a
   dark ground read beautifully; the base rule below only catches volumes
   whose stars are dark-on-light. */
#search-button svg { transition: color 300ms ease; }
:root.search-mode #search-button svg { color: #cfcfcf; }
/* TEMPORARY (until Wilbur declares per-volume travel colors): the demo's
   brick-red orbital measures 1.0:1 against the search ground (the logo-disc
   blue) — invisible. Search keeps the gold for now. The CONTRACT constraint
   this proves: an orbital value must read on BOTH grounds, the theme bg AND
   the detail-sector color the search dims to. */
:root[data-theme].search-mode .focus-ring-node { fill: var(--color-nodes); }
:root[data-theme].search-mode .focus-ring-magnifier-circle { fill: var(--color-nodes); }
:root.search-mode /* A TAP ON A STAR ACKNOWLEDGES AND NOTHING MORE (O-191): the swell it wears
   under the lens, for a beat — "pull me". */
@keyframes star-nudge { 0% { transform: scale(1); } 40% { transform: scale(1.35); } 100% { transform: scale(1); } }
.child-pyramid-node.is-nudged { transform-box: fill-box; transform-origin: center; animation: star-nudge 350ms ease-out; }
.child-pyramid-node {
  fill: rgba(255, 255, 255, 0.14);
  stroke: rgba(255, 255, 255, 0.30);
}
.child-pyramid-label { transition: fill 300ms ease; }
:root[data-theme].search-mode .child-pyramid-label { fill: rgba(255, 255, 255, 0.92); }
/* The fan lines out to the completions — ink connectors, lit for the dark. */
/* The carriage sits on the GROUND (not on a node), so it must be lit. */
:root[data-theme].search-mode .search-carriage { fill: rgba(255, 255, 255, 0.92); }
/* The scope label — the parent button's words without its vessel: what the
   search is filtered to. A statement, never a control. */
.search-scope-label { pointer-events: none; }
:root[data-theme].search-mode .search-scope-label { fill: rgba(255, 255, 255, 0.92); }
/* The lens goes hollow while the chain turns — its dark ring would vanish,
   and the lodestar is the one point that must never be lost. */
:root[data-theme].search-mode .focus-ring-magnifier.rotating .focus-ring-magnifier-circle {
  stroke: rgba(255, 255, 255, 0.78);
}
/* The watermark: the pressed tool, ghosted in the volume's own node colour. */
.search-watermark {
  color: var(--color-nodes);
  pointer-events: none;
}
/* THE GLOBE IS A SLIDER (O-126, Howell 2026-09-14): its vertical position IS
   the stratum — two notches up the languages, one the editions, home the
   text, one down the basement. --thumb-y is written by main.js; the snap to
   a notch rides the transition, a drag sets it per frame with the
   transition off. */
#dimension-button { transform: translateY(var(--thumb-y, 0px)); touch-action: none; /* the slider owns the vertical drag */ }
/* ONE SIZE, ONE LIGHT (Howell 2026-09-30): the globe used to swell to 1.08
   and brighten to full while a stratum was open. Neither now — see the
   brightness rule beside its base rule above. */
#dimension-button.is-sliding { transition: opacity 0.15s ease; }
/* The thumb's springback out of the overrun: eased, a touch longer than the
   snap between stops — the Focus Ring's own feel. */
#dimension-button { transition: opacity 0.15s ease, transform 0.28s cubic-bezier(0.22, 1, 0.36, 1); }
/* A PLACEHOLDER SEAT on the edition ring (O-184): an edition the shelf is
   being built toward, not yet in the corpus — hollow, its name a shade
   lighter, never chosen. */
.secondary-strata-node.is-coming { fill: none; stroke: var(--color-orbital); stroke-width: 1.5; }
/* O-231: an UNCLEARED edition — in the corpus, not yet ours to serve; LAN only, under ?uncleared=true */
.secondary-strata-node.is-uncleared { fill: #e3170a; stroke: #e3170a; }
/* The name wears the seat's class as the disc does — the names stand in a
   group of their own after every disc (O-289), no longer the disc's next
   sibling. */
.secondary-strata-label.is-coming { opacity: 0.62; }
/* AN EDITION THAT IS ELSEWHERE (O-284): real and servable, not holding the
   verse under the reader — hollow like a placeholder, a door and not a page;
   its name at full strength, because it can be chosen, and choosing it leads
   to that edition's shelf. On the language ring, a tongue whose every edition
   is elsewhere wears the same. */
.secondary-strata-node.is-elsewhere { fill: none; stroke: var(--color-orbital); stroke-width: 1.5; }
/* A PROVISIONAL seat on the basement's ring — the verse the reader arrived
   with, not yet kept: hollow, so keeping it visibly fills it. */
.secondary-strata-node.is-provisional { fill: none; stroke: var(--color-orbital); stroke-width: 2; }
/* A GREATEST HIT on the basement's ring (O-135): permanent, in its own fill
   — the Parent Button's — so it is never mistaken for a seat the reader kept.
   Under the lens it wears the lens's look like any other seat. */
.secondary-strata-node.is-hit { fill: var(--color-orbital); }
.secondary-strata-node.is-magnified.is-provisional { fill: none; stroke: #000; stroke-width: 1; stroke-dasharray: 4 3; }
#dimension-button:focus-visible { outline: 2px solid var(--color-nodes, #f2b41c); outline-offset: 3px; border-radius: 50%; }

/* The strata layer sits above the primary and its detail panel, below the
   dimension button. It is click-through except on its nodes, so taps on
   empty space still fall to the (inert) primary. */
/* O-126: while a glide touches the basement, and while the basement is
   front, the layer goes UNDER the primary and its panels — the body is
   position: fixed and so a stacking context, so -1 sits above its ground
   and below everything in it. The basement is under the floor, and is seen
   only as the floor dissolves. */
#strata-layer.is-below { z-index: -1; }
#strata-layer {
  position: fixed;
  inset: 0;
  /* Above the primary's detail panel (200) so a front stratum covers the
     receded primary text; below the copyright strip (300). */
  z-index: 250;
  pointer-events: none;
  overflow: visible;
}

/* The secondary strata (D.3) — identical colors, band, and font to the
   primary strata (Howell 2026-07-21). Color placeholder retired. */
/* NO will-change ON A STRATUM (O-187): composited, a ring flying in from
   six times scale is a layer no phone can tile — the band came up in
   fragments. The recede is an attribute on the inner group, re-rasterised
   each frame into a viewport-sized layer, as the primary's is. */
/* Names on a receding ring do not re-hint at every fractional scale. */
.secondary-strata-label { text-rendering: geometricPrecision; }
/* The basement's legend (O-188): the label's face and size, upright in the
   open ground beside the ring. WHAT TELLS A LANDMARK FROM A BOOKMARK is
   THE SIDE OF THE RING'S LINE (O-275, Howell's sketch 2026-11-08: "the
   landmarks should be shifted far to the left ... mirrored about the focus
   ring line"), which the view places — a bookmark's name outward from its
   disc, a landmark's inward, ending at the disc. Nothing in the basement
   is italic (Howell, the same evening: "remove the italics so nothing is
   italicized in the basement" — the slant tried first did not read). The
   dark red and dark blue of 2026-09-30 are retired: every label is the
   app's ink. Nodes keep their one colour. */
/* The legend's words ride arcs beside the band (O-276), and are WATERMARKS
   (O-277, Howell 2026-11-08: "Much larger letters, as big as they can be and
   still fit on the page ... Similar to the way we did language watermarks"
   in the other volume): the view sizes each word to the stretch of its arc
   the glass shows and draws it under the band and the names; its faintness
   is the band's own tone (below). The font-size here is the fallback for a
   word the view did not measure. */
.secondary-strata-legend {
  /* THE WATERMARK'S TONE IS THE BAND'S (O-278, Howell 2026-11-09: "Perhaps
     the focus ring band should be the same color as the watermarks"). The
     basement light computes the band as the theme's ink laid on the deep
     ground at the watermark's faintness, and the words are painted in that
     very colour, opaque — the same by construction. Upstairs no legend is
     drawn, so the fallback is only for a sheet without a theme. */
  fill: var(--color-band, var(--color-text));
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  font-size: calc(22px * var(--iframe-scale, 1));
  font-weight: 700;
  letter-spacing: 0.08em;
  pointer-events: none;
}
.stratum-legend-arc { fill: none; stroke: none; }
/* THE BARE SPROCKET on a chooser ring (O-272): beyond the chain's first and
   last seat the band is its two edges only, inked like the empty vessel. */
.secondary-strata-band-hollow {
  fill: none;
  stroke: var(--color-magnifier-stroke, #000);
}
.secondary-strata-band {
  fill: none;
  stroke: var(--color-band);
  stroke-linecap: round;
  opacity: 1;
}
.secondary-strata-node {
  fill: var(--color-orbital); /* the chooser rings travel orbitally too */
  stroke: none;
  cursor: pointer;
  pointer-events: auto; /* the layer is click-through; its nodes are not */
}
/* The magnified language wears a 1px black stroke (Howell 2026-07-21). */
.secondary-strata-node.is-magnified {
  stroke: #000;
  stroke-width: 1;
}
/* While the ring rotates the lodestar is a HOLLOW lens: no fill, so the nodes
   stream through it, exactly as the primary magnifier empties (Howell). */
.secondary-strata-node.is-magnified.lens-empty {
  fill: none;
}
.secondary-strata-label {
  fill: var(--color-text);
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  font-size: clamp(calc(14px * var(--iframe-scale, 1)), 1.6vmin, calc(26px * var(--iframe-scale, 1)));
  /* Casing is owned by displayCase() in JS — it uppercases Latin but leaves
     Greek/Cyrillic/Hebrew in their proper form. A CSS text-transform:uppercase
     here re-uppercased the native scripts (Русский → РУССКИЙ) — removed. */
  pointer-events: none;
}
/* The magnified label is larger, as in the primary strata — and NOT bold,
   on every plane (O-254, Howell 2026-10-30: "Nothing should be bold. The
   label for the magnifier in the secondary stratum should not be bold").
   The basement's lens had already been given the plain weight (O-128,
   Howell 2026-09-14: "Look again at the primary stratum magnifier. You'll
   see the font is larger, but it is not bold"); the other planes kept 700
   until tonight. Its anchoring (offset + start) is set in the view. */
.secondary-strata-label.is-magnified {
  font-size: clamp(calc(21px * var(--iframe-scale, 1)), 2.4vmin, calc(39px * var(--iframe-scale, 1)));
  font-weight: 400;
}
/* THE WORD BESIDE THE LENS (O-280, Howell 2026-11-09, his screenshots:
   BOOKMARK or DISCARD drawn upright in the open ground right of the lens):
   the one upright text on the basement's glass, in the lens label's size,
   bold, the room's ink. The view places it at the lens's height and hides
   it while the ring turns; a tap on it is a tap on the lens (the host's
   lensHit). AND IT WEARS THE PARENT LABEL'S HALO (Howell, DISCARD running
   through the name of the seat above the lens: "I'd rather create a halo
   around the discard or bookmark label, the same way we put a halo around
   the parent button label"): the O-233 halo, so a name passing beneath is
   dimmed where it meets the word and nowhere else.
   THE HALO IS A MASK ON THE NAMES, NOT PAINT ON THE WORD (O-289, Howell
   2026-11-10, the word standing in the arc of its own watermark: "That
   watermark should not be affected by the halo. The halo around the
   bookmark label exists only to prevent a collision with adjacent bookmark
   labels"). A stroke in the ground's colour on the word covered whatever
   lay under it — the watermark, the band, a disc. Now the word itself has
   no stroke: the view draws it once more, as a <use>, into a luminance mask
   the names' groups wear — see .caption-halo-cut below, where the copy's
   letters and stroke turn black. The knobs are the parent label's. */
.secondary-strata-caption {
  fill: var(--caption-ink, var(--color-text));
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  font-size: clamp(calc(21px * var(--iframe-scale, 1)), 2.4vmin, calc(39px * var(--iframe-scale, 1)));
  font-weight: 700;
  letter-spacing: 0.06em;
  paint-order: stroke fill;
  stroke: #000;
  stroke-opacity: var(--caption-halo-opacity, 0);
  stroke-width: var(--parent-halo-width, 0.6em);
  stroke-linejoin: round;
  pointer-events: none;
}
/* THE WORD'S COPY IN THE MASK (O-289): black letters, and the black stroke
   at the halo's opacity over the mask's white — so a name under the stroke
   shows through at the remainder (dimmed, not hidden, as O-233 asked) and
   nothing under the letters themselves, where the word's own ink lies. The
   copy inherits these from its <use>; the word on the glass never sees them. */
.caption-halo-cut {
  --caption-ink: #000;
  --caption-halo-opacity: var(--parent-halo-opacity, 0.85);
}

.focus-ring-band {
  /* A stroked centreline now (sprocket chain: arc + straight tangents), not a
     filled annulus. stroke-width is set per-render to the 0.02r band width. */
  fill: none;
  stroke: var(--color-band);
  opacity: 1;
}
/* THE BARE SPROCKET (O-271, Howell 2026-11-06): beyond the chain's first and
   last link the band is hollow — its two edges only, inked like an empty
   vessel — so the chain visibly ends at the first leaf and the last. */
.focus-ring-band-hollow {
  fill: none;
  stroke: var(--color-magnifier-stroke, #000);
  opacity: 1;
}
#app.boot-colorize .focus-ring-band-hollow { opacity: var(--boot-paint, 1); }

/* ── The boot overture's ink (the splash's rotation beat) ─────────────────
   The LIVE wheel performs in wireframe: hollow nodes with black outlines and
   the grey band held back, while the splash's thin arc line stands in for the
   band. Fan lines stay at full strength throughout — their stubs inside the
   hollow circles are the rough-draft look (Howell 2026-07-22); the arriving
   fills obliterate them. Per frame the splash drives --boot-paint 0→1 (the
   colour arriving) and --boot-ink 1→0 (the outlines retiring); the class
   comes off at the settle and these rules vanish with it. */
#app.boot-colorize .focus-ring-band { opacity: var(--boot-paint, 1); }
#app.boot-colorize .focus-ring-node {
  fill-opacity: var(--boot-paint, 1);
  stroke: #000;
  stroke-opacity: var(--boot-ink, 0);
  /* 1px, matching the drawn wireframe beads (the splash inks them at the
     node's COMPUTED stroke-width — the 1px default — so anything heavier
     visibly fattens the outlines at the handoff; Moto G caught it). */
  stroke-width: 1px;
}
#app.boot-colorize .child-pyramid-node { fill-opacity: var(--boot-paint, 1); }
#app.boot-colorize .focus-ring-magnifier-circle { fill-opacity: var(--boot-paint, 1); }

/* diagnostic band removed — was debug scaffolding */

.focus-ring-magnifier-circle {
  fill: var(--color-orbital); /* the lens is the orbital fixed point */
  /* THE STROKE IS PERMANENT (O-84 amendment, Howell 2026-08-22): it used to
     appear only while rotating, which was fine while every settled node sat
     dead-centre — the lens edge had nothing to say. A split verse settles
     OFF-centre now, and the partial eclipse only reads against a lens whose
     edge is always drawn. The parent button's stroke is already permanent,
     so this is the same logic applied to the other fixed circle. */
  stroke: var(--color-magnifier-stroke, #000);
  stroke-width: 1px;
}

/* Labels seated ON orbital surfaces wear the orbital ink: centered node
   numerals/characters, and the magnifier's own label (which sits on the
   lens). The parent label — despite sharing the magnifier label's class —
   sits on the GROUND in its corner and keeps the ground's text color. */
.focus-ring-label.label-on-node { fill: var(--color-orbital-label); }
.focus-ring-magnifier-label { fill: var(--color-orbital-label); }
.focus-ring-parent-label {
  fill: var(--color-text);
  /* THE HALO (O-233, Howell 2026-10-28, a ring label running under "2027":
     "some kind of halo around the parent button that perhaps doesn't mask
     the focus ring label entirely"). A stroke in the GROUND's colour painted
     under the letters: a ring label passing beneath is dimmed where it meets
     the name and nowhere else. A stroke, not a blur — an SVG filter on a
     <text> dies in WebKit (the blur saga, v3.22.0) — and on the label
     itself, so it travels with every flight that moves the label. Two knobs:
     how much it hides, and how far beyond the letters it reaches.
     AND IT IS DRAWN ONLY ON THE HALO COPY (O-257, Howell 2026-10-31: the
     stroke lay across the vessel's own disc — "I only want this glowing
     outline to be visible or work beyond the node itself"). The label's
     stroke is off here and on in the `.label-halo` <use> of it, which sits
     under the disc; see src/view/label-halo.js. */
  paint-order: stroke fill;
  stroke: var(--color-bg);
  stroke-opacity: var(--label-halo-opacity, 0);
  stroke-width: var(--parent-halo-width, 0.6em);
  stroke-linejoin: round;
  fill-opacity: var(--label-ink-opacity, 1);
  /* The corner label is TAPPABLE (its class family disables pointer-events;
     historically the disc sat under it so taps landed anyway — the split
     seat exposed the truth, Howell 2026-07-23). Its onclick is nulled when
     the seat is inert, so this never makes a dead label swallow taps. */
  pointer-events: auto;
}

/* The countries ring's parent seat wears the world globe — the corner
   instruments' grey, tap-sized by its hit disc. */
.world-glyph { color: #363636; }

/* THE PARENT BUTTON WEARS THE MAGNIFIER'S FILL (O-130, Howell 2026-09-14:
   "The Parent Button fill color is wrong. The Parent Button fill should be
   the same color as the Magnifier fill."). It used to keep the radial node
   colour — "the parent vessel moves data RADIALLY... splitting from the
   magnifier class it shares" — and that split is retired: the two fixed
   vessels are one colour, the orbital's. The stroke stays. */
.focus-ring-parent-circle {
  fill: var(--color-orbital);
  stroke: var(--color-magnifier-stroke, #000);
  stroke-width: 1px;
}
/* THE EMPTY VESSEL (O-222, Howell 2026-10-26): at the root nothing sits in
   the parent button, but the vessel stays drawn — the outline alone, as it
   looks mid-flight before a node arrives — so the seat is always on the
   glass and a drill from the lens has a destination. The fill is the data;
   an empty vessel has none. */
.focus-ring-parent-circle.parent-empty { fill: none; }

/* THE WAY BACK TO THE PRESENT (O-243, Howell 2026-10-30): a disc in the
   present moment's colours (the fills are inline, the ring node's own) with
   one word on it, shown only while nothing else on the glass is red. The
   word is the lens label's face at a size that fits the disc. */
.focus-ring-now-circle {
  stroke: var(--color-magnifier-stroke, #000);
  stroke-width: 1px;
  cursor: pointer;
}
/* NOT A DISTRACTION (Howell 2026-10-30): "make it semi-transparent". Both
   the disc and its word, so the two fade as one. */
.focus-ring-now-circle,
.focus-ring-now-label {
  opacity: var(--now-button-opacity, 0.55);
}
.focus-ring-now-label {
  font-family: var(--magnifier-font, 'Montserrat'), sans-serif;
  font-size: clamp(calc(15.75px * var(--iframe-scale, 1)), 1.8vmin, calc(29.25px * var(--iframe-scale, 1)));
  letter-spacing: 0.04em;
  cursor: pointer;
}

.focus-ring-magnifier-label {
  fill: var(--color-text);
  font-family: var(--magnifier-font, 'Montserrat'), sans-serif;
  font-size: clamp(calc(21px * var(--iframe-scale, 1)), 2.4vmin, calc(39px * var(--iframe-scale, 1)));
  text-transform: var(--focus-label-transform, uppercase);
  pointer-events: none;
}
/* THE LEVEL'S CAPTION (O-144): the word before the lens's numeral, in the
   lens label's own face, on the ground's ink — it stands outside the glass.
   THREE QUARTERS OF THE PARENT LABEL'S SIZE (Howell 2026-09-16: "perhaps 75%
   of the parent button label font size. They should be smaller than they
   are now") — every term of the parent label's clamp, times 0.75. */
.focus-ring-magnifier-caption {
  fill: var(--color-text);
  font-family: var(--magnifier-font, 'Montserrat'), sans-serif;
  font-size: clamp(calc(15.75px * var(--iframe-scale, 1)), 1.8vmin, calc(29.25px * var(--iframe-scale, 1)));
  letter-spacing: 0.04em;
  pointer-events: none;
}

/* Calendar and bible parent-button labels arrive display-ready ("MMdM
   CATALOGO", "753 BC", "CAPITULUM XVI") — render them verbatim; the
   lowercase d in MMdM must survive. The catalog's parent labels still rely
   on the uppercase transform (mixed-case manufacturer data). */
:root[data-theme="calendar"] .focus-ring-parent-label,
:root[data-theme="bible"] .focus-ring-parent-label {
  text-transform: none;
}

/* CASING BELONGS TO THE VOLUME, NOT TO CSS (2026-08-02). `text-transform:
   uppercase` cannot tell one script from another: it re-uppercased every
   native form on the ring — the strata ring hit this first (Русский →
   РУССКИЙ) and moved its casing into JS. The focus ring carried the same
   rule and the same bug, and the Bible exposed it the moment it spoke
   Greek: Κεφάλαιον rendered ΚΕΦΆΛΑΙΟΝ, keeping an accent that Greek
   uppercase drops, and ιζʹ rendered ΙΖʹ.
   The Bible's own formatter now decides — Latin-script names and words
   shout, every other script keeps its form, and a numeral or an edition's
   own verse address is never touched. Other volumes keep the transform;
   the catalog in particular relies on it for mixed-case maker data. */
:root[data-theme="bible"] .focus-ring-label,
:root[data-theme="bible"] .focus-ring-magnifier-label {
  text-transform: none;
}
/* THE CALENDAR'S LENS LABEL IS LARGER (O-254, Howell 2026-10-30: "make
   the primary stratum magnifier label much bigger. Not bold, just a larger
   font size... this will only apply to the calendar. None of this has
   anything to do with the Bible") — every term of the lens label's clamp,
   times 1.3. He tried 150% first and took it back: "I had to go a little
   too far. Take it back to 130% of the original size." THE PARENT BUTTON'S
   LABEL IS EXCLUDED: it wears the lens label's class for its face, and the
   first cut grew it too — "I didn't want it to change at all, so put it
   back where it was." */
:root[data-theme="calendar"] .focus-ring-magnifier-label:not(.focus-ring-parent-label) {
  font-size: clamp(calc(27.3px * var(--iframe-scale, 1)), 3.12vmin, calc(50.7px * var(--iframe-scale, 1)));
  /* AND WEARS THE PARENT LABEL'S HALO (O-254, Howell 2026-10-30, the lens
     reading ANNÉES QUATRE-VINGT across a pyramid node's CLXXXIX: "Do you
     want to put some kind of pad around the magnifier label where it
     overlaps child pyramid nodes... It's up to you"). The same stroke in
     the ground's colour, the same two knobs (O-233), so a pyramid name
     passing under the lens's word is dimmed where they meet and nowhere
     else. Calendar only: the Bible's lens is untouched. The stroke is on
     only in the `.label-halo` copy under the glass (O-257). */
  paint-order: stroke fill;
  stroke: var(--color-bg);
  stroke-opacity: var(--label-halo-opacity, 0);
  stroke-width: var(--parent-halo-width, 0.6em);
  stroke-linejoin: round;
  fill-opacity: var(--label-ink-opacity, 1);
}

/* THE HALO COPY (O-257): a <use> of the label, placed before its disc, so
   the disc paints over the glow and under the letters. The copy inherits
   these two values from the <use>; the label itself never sees them, so
   its own stroke stays off and its ink stays on. It is never a tap target. */
.label-halo {
  --label-halo-opacity: var(--parent-halo-opacity, 0.85);
  --label-ink-opacity: 0;
  fill-opacity: 0;   /* a label with no halo rule (the Bible's lens) copies as nothing */
  pointer-events: none;
}
/* The lens label hides while the ring turns; its halo copy, which sits in
   the light DOM beside it, hides by its own rule. */
.focus-ring-magnifier.rotating .label-halo { display: none; }

.focus-ring-magnifier.rotating .focus-ring-magnifier-circle {
  fill: none;
  stroke: var(--color-magnifier-stroke, #000);
  stroke-width: 1px;
}

/* THE ECLIPSED SETTLE (O-84, corrected 2026-08-22 from Howell's screenshot):
   a split verse at rest. The lens goes hollow — the node, in its ordinary
   ring seat at ordinary size, partially covers the empty stroke circle, and
   THAT overlap is the partial eclipse. An opaque lens absorbing the node
   (the whole-verse settle) would hide the very thing this state exists to
   show. */
.focus-ring-magnifier.eclipsed .focus-ring-magnifier-circle {
  fill: none;
  /* AND IT MUST STILL TAKE A TAP. `fill: none` in SVG does not merely paint
     nothing — it makes the INTERIOR transparent to pointer events, leaving
     only the one-pixel stroke hittable. So the lens became almost impossible
     to touch at the exact moment it acquired a job: an eclipsed verse is the
     only state where tapping it does anything, and that is the state that
     turned it off. Howell's taps were landing on the NODE behind it instead,
     which rotates the ring without changing the half — the ring moving to the
     first half while the text stayed on the second, exactly as he reported.

     `pointer-events: all` gives a fill-less shape its interior back. */
  pointer-events: all;
}

/* THE WITHHELD VOLUME (H-14; Howell 2026-08-12, specified from the phone).
   The instrument is present and holds nothing: band, chrome and the volume's
   logo, with no fill on any node and no labels anywhere.

   It borrows the ROTATING magnifier's treatment above rather than inventing
   one, and the borrowing is the argument: that state already means "the lens
   is between things, holding nothing right now", which is exactly what a
   volume with nothing servable is. One visual vocabulary, used twice. */
:root.volume-withheld .focus-ring-magnifier-circle,
:root.volume-withheld .focus-ring-parent-circle {
  fill: none;
  stroke: var(--color-magnifier-stroke, #000);
  stroke-width: 1px;
}

.focus-ring-magnifier.rotating .focus-ring-magnifier-label {
  display: none;
}

/* Child pyramid preview rendering */
.child-pyramid {
  pointer-events: none;
}

/* EVERY NODE WEARS THE SETTLED NODE'S COLOUR (O-164, Howell 2026-09-17:
   "All nodes should be the same color, which is the color of the settled
   nodes"). The sky's stars used to be a wash of black over the ground, a
   different colour from the ring's nodes, so a node changed colour by
   crossing between them — which O-162 forbids. One colour now, the ring's. */
.child-pyramid-node {
  fill: var(--color-orbital);
  stroke: none;
  pointer-events: auto;
}

.child-pyramid-node:hover {
  fill: var(--color-orbital);
}

.child-pyramid-label {
  fill: var(--color-text);
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  font-size: clamp(calc(14px * var(--iframe-scale, 1)), 1.6vmin, calc(26px * var(--iframe-scale, 1)));
  /* Everything in the instrument is ALL CAPS except the d in MMdM (Howell);
     pyramid labels only looked capitalized before because abbreviations and
     numerals already were — full-named Favorites exposed the gap. */
  text-transform: uppercase;
  pointer-events: none;
}
/* The cartographer's stroke (2026-07-19 – 2026-07-25, in memoriam): a halo
   that carved Favorites' names a channel through the fan-line bundles.
   Retired with the fan lines themselves — the Tufte erasure (Howell:
   "if it's too busy for the dance, how is it not too busy when the
   dancers take a seat?"). */
/* The REAL pyramid labels (inside the live pyramid group) are tappable
   exactly like their circles — they carry data-index, and a tap on the word
   used to fall through to the background and get read as a ring near-miss
   (the iOS multi-tap gateway bug). Animation clones share the class but sit
   outside .child-pyramid, so they stay inert. */
.child-pyramid .child-pyramid-label {
  pointer-events: auto;
}

/* Fade child pyramid nodes/labels while the Focus Ring is rotating.
   Blur is applied via SVG filter attribute for iOS WebKit compatibility. */
.child-pyramid.is-rotating .child-pyramid-node,
.child-pyramid.is-rotating .child-pyramid-label {
  opacity: 0.35;
  transition: opacity 80ms linear;
}

/* Migration animation overlay — cloned nodes that travel from pyramid to ring */
.migration-animation-overlay {
  pointer-events: none;
}

.migration-node {
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .migration-node {
    transition: none !important;
  }
}

/* Detail panel — full-screen transparent overlay.
   Arc-following text is positioned in viewport coordinates;
   cards centre themselves within the full-screen container. */
.detail-panel {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: transparent;
  border: none;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease-in;
  z-index: 200;
}

.detail-panel.detail-panel--visible {
  display: block;
  opacity: 1;
  /* pointer-events intentionally remain 'none' — the panel is a transparent
     display overlay.  Only specific interactive children opt-in below. */
}

.detail-content {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  /* Pass events through to the SVG; only opt-in children capture them. */
  pointer-events: none;
  color: rgba(255, 255, 255, 0.92);
  font-family: var(--theme-font-detail, var(--magnifier-font, 'Montserrat')), sans-serif;
  line-height: 1.4;
}

.detail-sector-content {
  color: rgba(255, 255, 255, 0.92);
}

/* ── Plain text fallback ─────────────────────────────────────────────── */
.detail-text {
  white-space: pre-wrap;
  padding: calc(16px * var(--iframe-scale, 1)) calc(24px * var(--iframe-scale, 1));
  font-size: calc(15px * var(--iframe-scale, 1));
}

/* ── Arc-following text layout ───────────────────────────────────────── */
/* Container covers the full detail-content area; lines are absolutely
   positioned using viewport coordinates from the line table. */
.detail-text--arc {
  position: absolute;
  inset: 0;
  white-space: nowrap;
  overflow: hidden;
}

/* Individual arc-positioned text lines */
.detail-text-line {
  display: block;
  position: absolute;
  white-space: nowrap;
  /* NEVER clip or ellipsise a verse line — the wrap is sized so the text fits,
     and a hair of overhang beats truncating scripture (Howell 2026-07-22). */
  overflow: visible;
}

/*
  Font-size tiers expressed as a fraction of SSd.
  --detail-SSd is set by TextDetailPlugin on the container element.
  line-height is unitless so it scales with computed font-size.
*/
.font-tier-1 { font-size: calc(10.5 / 100 * var(--detail-SSd, 650px)); line-height: 1.3;  }
.font-tier-2 { font-size: calc( 8.0 / 100 * var(--detail-SSd, 650px)); line-height: 1.3;  }
.font-tier-3 { font-size: calc( 6.0 / 100 * var(--detail-SSd, 650px)); line-height: 1.35; }
.font-tier-4 { font-size: calc( 4.5 / 100 * var(--detail-SSd, 650px)); line-height: 1.4;  }
.font-tier-5 { font-size: calc( 3.5 / 100 * var(--detail-SSd, 650px)); line-height: 1.4;  }
.font-tier-6 { font-size: calc( 3.0 / 100 * var(--detail-SSd, 650px)); line-height: 1.4;  }

/* W-6, the ruled substitution mark (Howell, bench 2026-07-27): a stood-in
   verse speaks in italic; a small upright right-aligned footer names the
   substitution in the reader's chosen language. Sizes in em ride the
   verse's uniform size. */
.detail-substituted--italic .detail-text-line {
  font-style: italic;
}
.detail-sub-footer {
  font-size: 0.75em; /* 1.5× the first sketch — Howell 2026-07-27 */
  letter-spacing: 0.12em;
  opacity: 0.65;
  font-style: normal; /* the notice speaks upright under the italic verse */
}

/* RTL language support */
.detail-text--arc[lang="he"],
.detail-text--arc[lang="ar"] {
  direction: rtl;
}
.detail-text--arc[lang="he"] .detail-text-line,
.detail-text--arc[lang="ar"] .detail-text-line {
  text-align: right;
}

/* THE LATIN KEEPS ITS U. EB Garamond's `locl` table for lang="la" sets every
   u as v (Dominvs, tvvm) — a classical-inscription conceit of the font, not
   the Clementine's orthography, which prints Deus and tuum. The canvas that
   measures the lines knows no language and measured the u, so the drawn text
   was also narrower than its measurement. Howell caught it in the first
   rehearsal for the film (2026-11-08). */
.detail-text--arc[lang="la"] {
  font-feature-settings: "locl" 0;
}

/* ── Arc-following card layout ───────────────────────────────────────── */
/* Container identical to .detail-text--arc: full-layer, lines are spans
   absolutely positioned by the JS line table. */
.detail-card--arc {
  position: absolute;
  inset: 0;
  white-space: nowrap;
  overflow: hidden;
}

/* Title line — bold, inherits font-tier class for size */
.detail-card-title {
  font-weight: 700;
  color: rgba(255, 255, 255, 0.95);
}

/* Body subtitle line — muted */
.detail-card-body {
  color: rgba(255, 255, 255, 0.65);
}

/* Description lines — italic */
.detail-card-description {
  color: rgba(255, 255, 255, 0.88);
  font-style: italic;
}

/* ── The ephemeris day card (the wall calendar's day cell) ──────────── */
/* The weekday wears the parent button's font (Howell 2026-07-20) — same
   clamp as .focus-ring-magnifier-label. */
.detail-ephemeris-title {
  font-weight: 700;
  color: rgba(255, 255, 255, 0.95);
  font-size: clamp(calc(21px * var(--iframe-scale, 1)), 2.4vmin, calc(39px * var(--iframe-scale, 1)));
}

/* TODAY'S CARD WEARS THE NOW COLOURS (O-247, Howell 2026-10-30): the
   weekday in yellow on a red disc behind it — the fills are inline, the
   ring node's own — the one red thing on the glass at the leaf. The feast
   days' red (the print's) is retired: "there should be no other colored
   label than the one for the current day". */
.detail-ephemeris-title--now .detail-now-word {
  position: relative;
  display: inline-block;
  z-index: 1;
}
.detail-ephemeris-title--now .detail-now-disc {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1.9em;
  height: 1.9em;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  z-index: 0;
}

/* The numbers: twice the old tier-6 (Howell 2026-07-20). */
.detail-ephemeris-row {
  color: rgba(255, 255, 255, 0.88);
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  font-size: calc(6.0 / 100 * var(--detail-SSd, 650px));
  line-height: 1.4;
}
/* FANO'S TABLES AT THE FOOT (O-255, Howell 2026-10-30): half the rows'
   size — the small tier the line table is calibrated for — "It can be
   very small". Placed by the plugin on the last lines above the deck. */
.detail-ephemeris-table {
  color: rgba(255, 255, 255, 0.88);
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  font-size: calc(3.0 / 100 * var(--detail-SSd, 650px));
  line-height: 1.4;
}

/* THE MANIFOLD OF THE DAY (O-256, Howell 2026-10-31): the drawing under
   the weekday, fitted whole and hung from the top of its room — a line
   drawing, white on the ground, so it needs no frame — and its label in
   capitals beneath it, centred on it, at the card tier. A name wider than
   the drawing breaks onto a second line, the two lines kept even (Howell
   2026-10-31: "spread across two lines"); the plugin keeps the room for it. */
.detail-figure-label {
  color: rgba(255, 255, 255, 0.88);
  font-size: calc(4.5 / 100 * var(--detail-SSd, 650px));
  line-height: 1.25;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: normal;
  overflow-wrap: break-word;
  text-wrap: balance;
}
.detail-figure {
  display: block;
  object-fit: contain;
  object-position: center top;
  pointer-events: none;
}

/* The dossier's inline media (the Twin 6 HP film, and photos to come) */
.detail-card-video {
  display: block;
  background: #000;
  border-radius: 2px;
  max-width: 100%;
}

/* ── Fallback card (no line table) ──────────────────────────────────── */
.detail-card {
  position: absolute;
  top: 10%;
  left: 5%;
  width: 90%;
  max-height: 80%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  overflow: hidden;
}

.detail-card > * + * {
  margin-top: var(--space-sm, 8px);
}

.detail-card .detail-card-title {
  font-weight: 700;
  font-size: calc(19px * var(--iframe-scale, 1));
  color: rgba(255, 255, 255, 0.95);
}

.detail-card .detail-card-body {
  font-size: calc(13px * var(--iframe-scale, 1));
  color: rgba(255, 255, 255, 0.65);
}

.detail-card .detail-card-description {
  margin-top: var(--space-md, 12px);
  font-size: calc(14px * var(--iframe-scale, 1));
  line-height: 1.65;
  color: rgba(255, 255, 255, 0.88);
  font-style: italic;
  text-align: left;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  pointer-events: auto;
  max-height: 100%;
}

.detail-card-image {
  width: calc(84px * var(--iframe-scale, 1));
  height: calc(84px * var(--iframe-scale, 1));
  object-fit: contain;
  border-radius: var(--radius-card, 10px);
  background: rgba(255, 255, 255, 0.08);
}

/* The incomplete-translation marker (Howell 2026-07-31) — visible only while
   the LAN certification override is showing an uncertified edition. Deliberately
   plain and unmistakably a dev affordance: this must never be mistaken for a
   reader-facing notice, since the doctrine forbids asterisks in the product. */
/* THE MARK MOVES TO THE TOP AND COVERS THE COPYRIGHT (Howell, 2026-08-27:
   "move the NOT PROOFREAD banner to the top of the screen, overlaying the
   copyright disclaimer"). It rode the lower left from 2026-08-02, which was
   right until the ground beyond the ring started carrying Swete's apparatus:
   the mark then stood in the margin's own territory and was drawn over the
   manuscript names (O-102). The copyright strip is the one piece of furniture
   already occupying a full-width band the reader does not read, so the mark
   takes that band while it is showing — same box, same padding, same centring,
   opaque, so the notice beneath it is covered rather than peeking out at the
   sides. It is still a LAN-only dev affordance and still must never be
   mistaken for a reader-facing notice; the doctrine forbids asterisks in the
   product. */
#incomplete-mark {
  /* THE MARK GOES SMALL, AND TO THE BOTTOM (O-125, Howell 2026-09-02:
     "instead of a big red stripe across the top I'd rather see something
     small at the bottom. Perhaps a simple UR meaning under review"; settled
     2026-10-23: "a more subtle under review down in the lower right near the
     notes section", and the same evening, with a green mark on a photograph,
     the LOWER LEFT corner, under the parent vessel). The red band across the
     top was the editing suite's mark; this is the reader's. It wears the
     margin's own ink and type, sits at the foot of the glass on the left,
     and covers nothing — the copyright line keeps its place. */
  position: fixed;
  left: calc(14px * var(--iframe-scale, 1));
  bottom: calc(4px * var(--iframe-scale, 1));   /* as low as the glass allows (Howell 2026-10-23) */
  z-index: 401;   /* with the margin's marks, above the sector */
  font-family: 'EB Garamond', Georgia, serif;
  font-size: calc(12px * var(--iframe-scale, 1));
  line-height: 1.2;
  letter-spacing: 0.06em;
  color: var(--color-margin-note, rgba(30, 22, 16, 0.82));
  opacity: 0.85;
  /* "chapter" over "under review", two lines by design (Howell 2026-10-23),
     upright, never italic. */
  white-space: nowrap;
  text-align: left;
  pointer-events: none;
}
.incomplete-mark-line { display: block; }

/* THE NOTICE NO LONGER STANDS DOWN BENEATH IT (Howell, 2026-08-29). It used
   to: an opaque mark covered the notice's FIRST line and nothing else — the
   copyright wraps to two lines on a phone, so "riservati." sat below the band
   in plain sight — and hiding the element it replaced could not half-cover.
   With the mark semi-transparent that reasoning inverts: the notice showing
   THROUGH the mark is the point, because the sector now raises its text to
   the notice's own bottom edge and the mark is shorter than the notice. A
   reader never sees either state — the mark is LAN-only — so what this rule
   costs is nothing and what it shows is the geometry under discussion. */

/* THE SECTION LABEL (H-26) — the tradition's own name for the division the
   magnified book belongs to. A NAME, never a colour: a colour asserts nothing
   and so can be quietly wrong, which is exactly what the field does and what
   this ruling refuses.

   IT IS NOT A DEV AFFORDANCE, so it must not look like one. The NOT PROOFREAD
   mark is deliberately plain and alarming because it is scaffolding; this is
   reader-facing and permanent, so it takes the volume's own ink.

   ITS SEAT IS GEOMETRY, NOT CSS (Howell 2026-08-16, drawn on a screenshot):
   outside the arc, radially in line with the magnifier, rotated parallel to
   the ring. All of that is computed in the view from the magnifier's own
   position, because that is where the arc's hub and radius already live — so
   this rule carries ink and type only, and cannot disagree with the ring
   about where the ring is. */
.focus-ring-section-label {
  fill: var(--color-text);
  font-family: var(--focus-node-font, 'Montserrat'), sans-serif;
  /* THE MAGNIFIER LABEL’S SIZE, which is not the ring labels’ size — the
     two differ, and that is why matching the ring exactly still read as
     small. Ring labels are 1.6vmin; the magnified name beside this one is
     2.4vmin, and THAT is the neighbour. Copied whole rather than
     approximated, so it stays matched if that one is retuned. */
  font-size: clamp(calc(21px * var(--iframe-scale, 1)), 2.4vmin, calc(39px * var(--iframe-scale, 1)));
  letter-spacing: 0.08em;
  opacity: 0.8;
  pointer-events: none;
}

/* Off-screen but SPOKEN. display:none and visibility:hidden both remove an
   element from the accessibility tree, which would mute the live region
   entirely — the classic mistake. This keeps it rendered and unreadable. */
.visually-hidden {
  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;
}

/* THE BOOT ERROR'S OWN SEAT (2026-08-12).
   The panel it lives in is full-screen and the copyright is a fixed band at
   top:0, so an unseated message lands under the notice and the two overlap —
   which is what Howell read on the phone. This clears the band and centres
   the message in the space below it.

   Deliberately plain: a boot error is not a designed screen and should not
   pretend to be one. It has to be READABLE, which is the whole complaint. */
.boot-error {
  position: absolute;
  top: 25%;
  left: 0;
  right: 0;
  padding: 0 2rem;
  text-align: center;
  color: var(--theme-color-text, #111);
  font-family: var(--magnifier-font, 'Montserrat'), sans-serif;
  font-size: 1rem;
  line-height: 1.5;
}

/* ── THE MARGIN, BEYOND THE RING (W-127, W-165) ─────────────────────────────
   Swete prints his critical apparatus at the foot of the page, outside the
   block of scripture. Here it sits outside the arc, on the ground the Detail
   Sector's circle does not cover. It is quieter than the text on purpose: it
   is the record of what the manuscripts disagree about, and it must never
   compete with the verse for the eye.

   FIRST LIGHT 2026-08-26 and every value here is provisional. The type size
   is O-91's 5%, ruled before anyone had seen a note. */
.margin-panel {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
  transition: opacity 0.35s ease-in;
  z-index: 190;   /* under the detail panel: the verse is never covered */
}

.margin-panel.margin-panel--visible { opacity: 1; }

.margin-note-line {
  font-family: 'EB Garamond', Georgia, serif;
  color: var(--color-margin-note, rgba(30, 22, 16, 0.72));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
}

/* A corrector's hand, raised by the app in the note's own face. The data
   carries Unicode superscript characters; EB Garamond has no glyphs for them,
   and a device's fallback font once swept a baseline question mark up into
   the raised run (Howell's phone, 2026-08-28). Rendered as plain letters in
   a lifted span, nothing is left to font luck: the hands rise, the queries
   stand on the floor, and both wear Garamond. position:relative rather than
   vertical-align so the fixed line pitch is untouched. */
.margin-sup {
  font-size: 0.62em;
  position: relative;
  top: -0.44em;
}

/* The italic witness: Grabe's pre-fire collation of the Cotton Genesis,
   distinct from a surviving fragment by the slope of the type alone (W-212).
   Styled here, in the note's own face — never the math-alphabet glyph. */
.margin-italic { font-style: italic; }

.margin-note-more {
  font-family: 'EB Garamond', Georgia, serif;
  color: var(--color-margin-note, rgba(30, 22, 16, 0.72));
  opacity: 0.6;
  font-style: italic;
  white-space: nowrap;
}

/* The manuscripts a note cites, named. Quieter than the note, which is itself
   quieter than the verse: three voices, in the order they matter. */
.margin-note-source {
  font-family: 'EB Garamond', Georgia, serif;
  color: var(--color-margin-note, rgba(30, 22, 16, 0.72));
  opacity: 0.72;
  white-space: nowrap;
  overflow: hidden;
}

/* THE MARKS BESIDE THE VERSE (W-176, Howell 2026-08-27: "put them in the
   extreme upper right, near the right end of the NOT PROOFREAD banner").
   They ride the top band because that is where the reader's POSITION is
   stated, and what these say is which manuscripts stand at the position.

   The band has two occupants today and will have one: the proofread mark
   while an uncertified edition is showing, and the copyright notice, which
   Howell has said is going away. So the ink adapts rather than assuming
   either — white over the mark's red, dark over the bare ground — and the
   marks sit above both. */
/* A FULL-VIEWPORT LAYER, not a chip anchored to the corner. It has to recede
   with everything else when a dimension stratum comes forward, and the recede
   is a scale about the VIEWPORT CENTRE — the point the ring and the verse
   panel scale about, so that everything keeps its place relative to the focus
   ring and the magnifier as it travels away. A small box in the corner would
   scale about its own middle and slide out of formation. */
.margin-marks {
  position: fixed;
  inset: 0;
  z-index: 401;
  padding: calc(6px * var(--iframe-scale, 1)) calc(14px * var(--iframe-scale, 1));
  font-family: 'EB Garamond', Georgia, serif;
  font-size: calc(13px * var(--iframe-scale, 1));
  line-height: calc(17px * var(--iframe-scale, 1));
  letter-spacing: 0.06em;
  color: var(--color-margin-note, rgba(30, 22, 16, 0.82));
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease-in;
}

.margin-marks.margin-marks--visible { opacity: 1; }


/* The marks are sigla and nothing else. They were briefly given their names
   underneath, and Howell's answer was that he still could not see the legend
   "in its usual position" — which is the right objection: the legend belongs at
   the margin's foot, where every other manuscript is named, and two places to
   look for one kind of statement is one more than a reader should have to
   learn. The names went back there and these are letters again. */
.margin-marks { text-align: right; }
.margin-marks-sigla { letter-spacing: 0.08em; }

/* The margin's own state, drawn only under ?margin=debug. Deliberately ugly:
   it is an instrument, not part of the reader's page, and must never be
   mistaken for one. */
#margin-debug {
  position: fixed;
  left: 0;
  bottom: 0;
  z-index: 9999;
  padding: 3px 6px;
  background: rgba(0, 0, 0, 0.82);
  color: #6f6;
  font-family: monospace;
  font-size: 10px;
  white-space: nowrap;
  pointer-events: none;
}
