/* halls.css — the four hall pages (/tests/ /modeling/ /games/ /study/).
   Shared page layer after frame.css; same Obys grammar as home.css, one
   markup two ways: no-JS / reduced-motion -> .hall-stage hidden, .hall-static
   stacked rows (the complete page); html.hall-live (added by halls.js) ->
   (N+1)*100svh scroll track + sticky 100svh stage, N derived from the DOM
   and written as --n, one translate3d per frame, states via class toggles.
   Composition (2026-10-15a, home intro2 parity): a wider centered strip
   (26vw), ONE left info column per item (index number / category / intro /
   CTA as stacked variants), giant SQUARE brackets bracketing the current
   frame, and the FULL item index (.hall-next) hugging the right edge — one
   scrollable slot per hall item, 01..N, the on-screen item carrying .is-cur.
   The stack is display:none without JS/RM; under 768px it docks as a
   horizontal snap filmstrip above the bottom band. Hall-specific: pinned
   giant hall head, mobile top band (name + back link), bottom paper band,
   .hall-tbd-tag chip (linkless placeholders). Footer clock styles here
   (hall pages do not load home.css/home.js). */

.hall {
  /* The strip geometry, echoed by every anchored sibling (home parity).
     --hall-paren-fs feeds both the bracket glyphs and the info column's
     standoff (0.44em clears the bracket ink — 0.389em advance box minus
     the ink's left bearing — with air to spare; CDP-measured 2026-10-15);
     --hall-info-gap parks the info column just left of the left bracket.
     --hall-next-* size the full index stack (home parity: is-1 base card
     + the uniform small card from slot 4 on). */
  --hall-w: clamp(260px, 26vw, 520px);
  --hall-paren-fs: min(34vh, calc(var(--hall-w) * 0.78));
  --hall-info-gap: calc(6vw + var(--hall-paren-fs) * 0.44);
  --hall-next-w: clamp(110px, 13vw, 190px);
  --hall-next-small: clamp(72px, calc(var(--hall-next-w) * 0.58), 170px);
}

/* ---- Hall head: static intro block; live: zero-height sticky shim, inner
   box pinned top-left under the header (mobile: top paper band). ------------ */
.hall-head {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--space-4);
  padding-block: var(--space-6);
}

@media (min-width: 720px) {
  .hall-head {
    padding-inline: var(--space-6);
    padding-block: var(--space-8);
  }
}

.hall-head-in {
  display: grid;
  gap: var(--space-3);
  justify-items: start;
}

.hall-back {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
}

.hall-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.5rem, 1.5rem + 4.5vw, 5rem); /* 40 -> 80px */
  line-height: 1.02;
  text-wrap: balance;
  color: var(--text);
}

.hall-intro {
  max-width: 36em;
  color: var(--text-dim);
  text-wrap: pretty;
}

/* ---- Static state: stacked rows (no JS / reduced motion) ------------------ */
.hall-static .hs-row {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--space-4);
  padding-block: var(--space-6);
  border-bottom: 1px solid var(--border-color);
  display: grid;
  gap: var(--space-4) var(--space-8);
  align-items: center;
}

@media (min-width: 720px) {
  .hall-static .hs-row {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    padding-inline: var(--space-6);
    padding-block: var(--space-8);
  }
}

/* Placeholder rows recede; they carry no link at all. */
.hall-static .hs-row.is-tbd {
  opacity: 0.62;
}

.hs-window {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
}

.hs-window::after,
.hall-item::after,
.hall-next-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  box-shadow: inset 0 0 0 1px oklch(1 0 0 / 0.08); /* pure-white image edge */
}

.hs-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Hover zoom is static-state only: live mode owns the strip transform. */
html:not(.hall-live) .hs-img {
  transition: transform var(--dur-base) var(--ease-out);
}

@media (hover: hover) {
  html:not(.hall-live) .hs-window:hover .hs-img {
    transform: scale(1.03);
  }
}

/* One whole-block hit area on linked rows: the CTA is a stretched link. */
.hs-info {
  position: relative;
  display: grid;
  gap: var(--space-2);
  justify-items: start;
}

.hs-meta {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
}

.hs-tags {
  color: var(--text-faint);
  text-transform: uppercase;
}

.hs-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.75rem, 1.1rem + 2.6vw, 3.25rem); /* 28 -> 52px */
  line-height: 1.05;
  text-wrap: balance;
  color: var(--text);
}

.hs-desc {
  max-width: 36em;
  color: var(--text-dim);
  text-wrap: pretty;
}

.hs-cta {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hs-cta::after {
  content: "";
  position: absolute;
  inset: 0;
}

.hs-cta:focus-visible {
  outline: none;
}

.hs-cta:focus-visible::after {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

@media (hover: hover) {
  .hs-info:hover .hs-name {
    text-decoration: underline;
    text-decoration-color: var(--accent);
    text-decoration-thickness: 2px;
    text-underline-offset: 6px;
  }
}

/* Shared arrow nudge (static rows + live info column). */
.hall-arr {
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease-out);
}

@media (hover: hover) {
  .hall-cta:hover .hall-arr {
    transform: translateX(3px);
  }
}

/* ---- Under-construction chip: inline in meta rows; centered on plates. --- */
.hall-tbd-tag {
  display: inline-block;
  padding: var(--space-1) var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  white-space: nowrap;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
}

.hall-item .hall-tbd-tag,
.hs-window .hall-tbd-tag,
.hall-next-frame .hall-tbd-tag {
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
}

/* HALL LIVE — the pinned Obys stage (html.hall-live, added by halls.js):
   the current item parks dead center, the strip travels between parks;
   per-frame motion is halls.js's one translate3d, the rest is CSS toggles. */

.hall-stage {
  display: none; /* the pinned stage exists only when halls.js succeeds */
}

html.hall-live .hall {
  height: calc((var(--n, 2) + 1) * 100vh); /* (N+1)*100svh; --n set by JS */
  height: calc((var(--n, 2) + 1) * 100svh);
}

html.hall-live .hall-stage {
  display: block;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: clip;
}

html.hall-live .hall-static {
  display: none;
}

html.hall-live .hall-head {
  position: sticky;
  top: 0;
  height: 0; /* zero-height shim: pins without shifting the scroll math */
  max-width: none;
  margin: 0;
  padding: 0;
  overflow: visible;
  z-index: var(--z-raised);
}

html.hall-live .hall-head-in {
  position: absolute;
  top: calc(var(--header-height) + var(--space-3));
  left: clamp(var(--space-4), 4vw, var(--space-12));
  max-width: 30rem;
}

/* ---- The strip: centered filmstrip via left + negative margin, so the
   transform stays free for halls.js's Y-only translate3d. ------------------- */
html.hall-live .hall-strip {
  position: absolute;
  left: 50%;
  top: 0;
  width: var(--hall-w);
  margin-left: calc(var(--hall-w) / -2);
  display: flex;
  flex-direction: column;
  gap: var(--space-2); /* 8px, the obys inter-image gap */
  will-change: transform; /* per-frame rAF transform: the justified case */
}

.hall-item {
  position: relative;
  display: block;
  flex: none;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--surface-2);
}

.hall-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  outline: 1px solid var(--border-color); /* pale cards stay legible dimmed */
  outline-offset: -1px;
  background: var(--surface-2);
  opacity: 0.45; /* neighbors recede; the current frame carries */
  transition: opacity 200ms var(--ease-out);
}

.hall-item.is-cur img {
  opacity: 1;
}

/* Placeholder items never fully arrive: they stay receded even as current. */
.hall-item.is-tbd img {
  opacity: 0.38;
}

.hall-item.is-tbd.is-cur img {
  opacity: 0.55;
}

/* ---- Left edge: the vertical list of item names ---------------------------- */
html.hall-live .hall-names {
  position: absolute;
  left: clamp(var(--space-2), 1vw, var(--space-4));
  top: 50%;
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  z-index: var(--z-raised);
  /* Never reach into the info column: name list width < (its left edge -
     the names' own left offset). Long hall names wrap instead. The clamp
     mirrors .hall-info's width below — keep the two in sync. */
  max-width: calc(50% - var(--hall-w) / 2 - var(--hall-info-gap)
              - clamp(120px, 13.5vw, 260px)
              - clamp(var(--space-2), 1vw, var(--space-4)) - var(--space-2));
}

.hall-name {
  padding: var(--space-1) 0; /* a touch of hit area on the small mono text */
  font-family: var(--font-mono);
  font-size: 15px; /* 2026-10-15a: 13 -> 15px, the index is first-class */
  line-height: 1.7;
  letter-spacing: 0.04em;
  text-align: left;
  color: var(--text-dim);
  transition: color 200ms var(--ease-out);
  overflow-wrap: anywhere; /* last resort for long latin-only names */
}

.hall-name.is-on {
  color: var(--text);
}

@media (hover: hover) {
  .hall-name:hover {
    color: var(--accent-dim);
  }
}

/* ---- Stacked variant chunks (the left info column): one grid cell, the
   visible state fades in, hidden ones are visibility:hidden (no ghost
   links in tab order / a11y tree). 180ms = the spec's 150-200ms band. ------ */
.hall-chunk {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-out),
              visibility 0s var(--dur-base);
}

.hall-chunk.is-on {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s;
}

/* ---- Left info column: number / category / intro / CTA, vertically
   centered, left-aligned; its right edge parks just left of the left
   bracket's ink (home parity: gap = 6vw + 0.44em of the bracket size). ---- */
html.hall-live .hall-info {
  position: absolute;
  right: calc(50% + var(--hall-w) / 2 + var(--hall-info-gap));
  top: 50%;
  translate: 0 -50%;
  width: clamp(120px, 13.5vw, 260px);
  display: grid;
  z-index: var(--z-raised);
}

.hall-chunk {
  display: grid;
  gap: 14px; /* spec row rhythm (home parity) */
  justify-items: start;
  align-content: start; /* variants share a cell: top-align, never jump */
}

.hall-num {
  font-family: var(--font-mono);
  font-size: clamp(21px, 2vw, 30px); /* 2026-10-15a: 18-24 -> 21-30px */
  line-height: 1;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--accent-dim); /* body-size orange-red, AA safe on paper */
}

.hall-tags {
  font-family: var(--font-mono);
  font-size: 17px; /* 2026-10-15a: 14 -> 17px */
  line-height: var(--leading-mono);
  letter-spacing: 0.06em;
  color: var(--text);
}

.hall-desc {
  font-size: 18px; /* 2026-10-15a: 15 -> 18px (home works-desc parity) */
  line-height: 1.75;
  color: var(--text-dim);
  text-wrap: pretty;
}

.hall-cta {
  font-family: var(--font-mono);
  font-size: 16px; /* 2026-10-15a: 14 -> 16px */
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Placeholder chunks carry this mono note where linked ones carry the CTA. */
.hall-tbd-note {
  font-family: var(--font-mono);
  font-size: 16px; /* 2026-10-15a: 14 -> 16px */
  letter-spacing: 0.08em;
  color: var(--text-dim);
}

/* ---- Right edge: the full item index (home works-next parity) --------------
   One slot per hall item, in hall order (01..N; halls.js builds the slots).
   The first three keep the receding stagger (0.9 / 0.55 / 0.32 opacity,
   100% / 78% / 60% of the base width), slot 4+ shrink to the uniform small
   card with a .55 -> .45 opacity tail (per-slot --slot-o set inline by
   halls.js). The slot matching the item on screen carries .is-cur: full
   opacity + a 1px accent edge. The whole column scrolls (thin ink scrollbar
   on transparent track, paper base) and stays inside the viewport safe
   zone. Each slot is a real link (tabindex -1: decorative index, the strip
   and the CTA take navigation; nav.js owns the page transition). Display
   gates: none by default (no JS / reduced motion), flex only under
   html.hall-live from 768px up (phones get the horizontal filmstrip — see
   the <768px block). */
.hall-next {
  display: none;
}

@media (min-width: 768px) {
  html.hall-live .hall-next {
    display: flex;
    position: absolute;
    /* Centered, capped at ~86svh: clears the header on top and the page
       chrome at the bottom at common window heights. */
    right: clamp(2rem, 6vw, 6rem);
    top: 50%;
    translate: 0 -50%;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
    max-height: 86svh;
    overflow-y: auto;
    overscroll-behavior: contain; /* wheel over the stack scrolls the stack */
    padding: var(--space-2) 0 var(--space-2) var(--space-2);
    background: var(--bg); /* paper base behind the scrolling thumbnails */
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
    z-index: var(--z-raised);
  }

  /* WebKit: thin ink thumb on a transparent track */
  html.hall-live .hall-next::-webkit-scrollbar {
    width: 4px;
  }

  html.hall-live .hall-next::-webkit-scrollbar-track {
    background: transparent;
  }

  html.hall-live .hall-next::-webkit-scrollbar-thumb {
    background: var(--border-strong);
  }
}

.hall-next-slot {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-1);
  text-decoration: none;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.hall-next-slot.is-1 { width: var(--hall-next-w); opacity: 0.9; }
.hall-next-slot.is-2 { width: calc(var(--hall-next-w) * 0.78); opacity: 0.55; }
.hall-next-slot.is-3 { width: calc(var(--hall-next-w) * 0.6); opacity: 0.32; }

/* Slots 4+: the uniform small card. Its opacity is a per-slot custom
   property (set inline by halls.js, .55 declining to .45 across the tail)
   so the hover step-forward below can still win the cascade. */
.hall-next-slot.is-small {
  width: var(--hall-next-small);
  opacity: var(--slot-o, 0.5);
}

.hall-next-slot.is-small .hall-next-img {
  max-height: 88px; /* keeps the tail compact; object-fit crops the rest */
}

/* A linkless placeholder item renders dead — visible, not clickable. */
.hall-next-slot.is-dead { pointer-events: none; cursor: default; }

/* The item on screen: full opacity + a 1px accent edge over the stagger. */
.hall-next-slot.is-cur { opacity: 1; }

.hall-next-slot.is-cur .hall-next-img {
  outline: 1px solid var(--accent);
  outline-offset: -1px;
}

@media (hover: hover) {
  .hall-next-slot.is-1:hover,
  .hall-next-slot.is-2:hover,
  .hall-next-slot.is-3:hover,
  .hall-next-slot.is-small:hover {
    opacity: 1; /* the receding stack steps forward on approach */
  }

  .hall-next-slot:hover .hall-next-num {
    color: var(--accent-dim);
  }
}

.hall-next-frame {
  position: relative;
  display: block;
}

.hall-next-frame .hall-tbd-tag {
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
}

.hall-next-img {
  display: block;
  width: 100%;
  height: auto; /* the HTML height attribute would pin 450px and kill 4/3 */
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--surface-2);
  outline: 1px solid var(--border-color); /* pale cards stay legible dimmed */
  outline-offset: -1px;
  border: 1px solid var(--border-strong); /* the ink hairline */
}

.hall-next-num {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: var(--leading-mono);
  letter-spacing: 0.08em;
  text-align: right;
  font-variant-numeric: tabular-nums; /* 01..N never shifts */
  color: var(--text-dim);
}

/* Swap fade: animates opacity from 0 up to each slot's OWN base value
   (0.9 / 0.55 / 0.32 / tail) — a `from`-only keyframe. halls.js retriggers
   the .is-swap class per item change, same pattern as the bracket pulse. */
html.hall-live .hall-next.is-swap .hall-next-slot {
  animation: hall-next-fade 160ms var(--ease-out);
}

@keyframes hall-next-fade {
  from { opacity: 0; }
}

/* ---- The giant square brackets framing the current frame (home parity) ---- */
html.hall-live .hall-paren {
  position: absolute;
  top: 50%;
  /* Optical: line-height:0 box has no height, so compensate Archivo ink
     hanging low of the box top in em instead of a % translate. Measured on
     the shipped woff2 (canvas pixel scan, line-height:0 box model): [ ] ink
     boxes are IDENTICAL to ( ) — center 0.0725em below the box top, ink
     height 0.897em — unified with home.css measured value -0.0725em.
     unchanged; ink height ~93% of the current frame, as before. */
  translate: 0 -0.0725em;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--hall-paren-fs);
  line-height: 0;
  color: var(--text);
  user-select: none;
  pointer-events: none;
}

html.hall-live .hall-paren--l {
  right: calc(50% + var(--hall-w) / 2 + 6vw);
}

html.hall-live .hall-paren--r {
  left: calc(50% + var(--hall-w) / 2 + 6vw);
}

/* Index change: one quick 0.92 -> 1 pulse (retriggered by halls.js). The
   individual `scale` property composes with the centering `translate`. */
html.hall-live .hall-paren.is-pulse {
  animation: hall-paren-pulse 240ms var(--ease-out);
}

@keyframes hall-paren-pulse {
  from { scale: 0.92; }
  to { scale: 1; }
}

/* ---- Scroll affordance, bottom left -------------------------------------------- */
html.hall-live .hall-hint {
  position: absolute;
  left: clamp(var(--space-2), 1vw, var(--space-4));
  bottom: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  color: var(--text-dim);
}

/* Below ~1100px the name list no longer shares the left edge (the wider
   26vw strip needs the room; the strip, CTA and full index carry
   navigation instead). */
@media (max-width: 1099.98px) {
  html.hall-live .hall-names {
    display: none;
  }
}

/* ---- Narrow screens: full-width paper bands. Hall name docks top, the info
   column docks as one bottom band, and the index becomes a horizontal snap
   filmstrip docked above that band; the strip slides behind all of it.
   z-index: 2 keeps the bands above the transformed strip (translate3d stacks
   it late). ---------------------------------------------------------------- */
@media (max-width: 767.98px) {
  html.hall-live .hall {
    --hall-w: 60vw; /* the spec'd mobile strip width */
  }

  html.hall-live .hall-names,
  html.hall-live .hall-paren,
  html.hall-live .hall-hint {
    display: none; /* side chrome cannot fit; the bands carry it */
  }

  /* The index becomes a horizontal snap filmstrip in the safe zone: docked
     directly on top of the bottom info band (whose min-height below pins
     its top edge to this strip's bottom:180px — no air, so a passing strip
     card can never peek through the seam), thumb width ~68px, touch scroll
     on x, no scrollbar (touch affordance). Opaque paper base + a 1px ink
     hairline on top close the strip off from the film behind it. */
  html.hall-live .hall-next {
    display: flex;
    position: absolute;
    left: 0;
    right: 0;
    top: auto;
    bottom: 180px; /* = the info band's min-height below: flush seam */
    translate: 0 0;
    flex-direction: row;
    align-items: flex-end;
    gap: var(--space-2);
    max-height: none;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior: contain;
    scroll-snap-type: x proximity;
    padding: var(--space-2) 12px; /* 12pxinline: the first card keeps air */
    scroll-padding: var(--space-2) 12px; /* snapped cards keep it too */
    background: var(--bg); /* opaque paper: nothing shows through */
    border-top: 1px solid var(--border-color); /* the finish line */
    scrollbar-width: none;
    z-index: 2; /* the strip slides behind, like through a film gate */
  }

  html.hall-live .hall-next::-webkit-scrollbar {
    display: none;
  }

  html.hall-live .hall-next-slot,
  html.hall-live .hall-next-slot.is-1,
  html.hall-live .hall-next-slot.is-2,
  html.hall-live .hall-next-slot.is-3,
  html.hall-live .hall-next-slot.is-small {
    flex: none;
    width: 68px;
    scroll-snap-align: start;
    opacity: 0.75;
  }

  html.hall-live .hall-next-slot.is-1 {
    opacity: 0.9; /* keep one anchor card carrying */
  }

  html.hall-live .hall-next-slot.is-cur {
    opacity: 1; /* the on-screen item still reads at full strength */
  }

  html.hall-live .hall-next-slot.is-small .hall-next-img {
    max-height: none; /* uniform 68px cards: plain 4:3 */
  }

  html.hall-live .hall-next-num {
    font-size: 10px; /* the xs label shrinks for the 68px card */
  }

  /* The desktop-enlarged 18px desc wraps to three lines here and would push
     the bottom band into the filmstrip — fall back to 15px, as home does. */
  html.hall-live .hall-desc {
    font-size: 15px;
  }

  /* Top band: hall name left, the way back right. */
  html.hall-live .hall-head-in {
    top: var(--header-height);
    left: 0;
    right: 0;
    max-width: none;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    height: 52px;
    padding-inline: var(--space-4);
    background: var(--bg);
    z-index: 2;
  }

  html.hall-live .hall-title {
    font-size: var(--text-md);
    line-height: 1;
  }

  html.hall-live .hall-intro {
    display: none;
  }

  /* Bottom band: the whole info column (number / category / intro / CTA),
     centered content. Replaces the old credits + index band pair. The
     min-height pins the band's top edge to the filmstrip's bottom:180px
     above — the seam stays closed at every viewport height and for every
     item's desc length (content sits at the top, slack stays below). */
  html.hall-live .hall-info {
    left: 0;
    right: 0;
    top: auto;
    bottom: 0;
    translate: 0 0;
    width: auto;
    max-width: none;
    min-height: 180px;
    background: var(--bg);
    padding: var(--space-2) var(--space-4) var(--space-3);
    z-index: 2;
  }

  html.hall-live .hall-chunk {
    justify-items: center;
    text-align: center;
    gap: var(--space-2); /* tighter rhythm inside the band */
  }
}

/* ---- Footer clock: Chengdu time, 1s tick (information, not motion — runs
   under RM). Without JS the digits hide. Hall pages get styles here. -------- */
.footer-clock {
  margin-left: auto; /* the right end of the footer row */
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: rgba(242, 240, 234, 0.64); /* same voice as .footer-sign */
}

.footer-clock-time {
  color: var(--bg); /* the payload reads brightest, like .footer-sign .out */
  font-variant-numeric: tabular-nums; /* ticking digits never shift layout */
}

html:not(.js) .footer-clock-time {
  display: none;
}

/* ---- Nav link underline reveal (same addon home.css applies; frame.css's
   solid active-page rule wins on specificity). ------------------------------- */
.site-nav-link {
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: color var(--dur-fast) var(--ease-out),
              text-decoration-color var(--dur-fast) var(--ease-out);
}

.site-nav-link:hover,
.site-nav-link:focus-visible {
  text-decoration-color: var(--accent-dim);
}

/* ---- Dense variant: halls with many items (games hall, N=21). A long name
   list would run under the pinned hall head (title + intro), so dense halls
   shrink the names and park the column below the head zone. Only pages that
   opt in via .hall--dense are affected. ------------------------------------- */
html.hall-live .hall--dense .hall-names {
  top: calc(50% + 110px);
}

.hall--dense .hall-name {
  padding: 1px 0;
  font-size: 13px; /* 2026-10-15a: 12 -> 13px; 21 names still clear the head */
  line-height: 1.45; /* 21 x ~21px ~= 440px: fits windows down to ~710px tall */
}
