/* roomboard.app/info — the public widget guide. Standalone stylesheet: it uses
   the Momentum tokens from the app but NOT main.css, which locks html/body to
   the 1920x1080 signage viewport. Desktop-first, readable down to phone. */

:root {
  --bg: #000;
  --bg-card: #121212;
  --bg-card-2: rgba(255, 255, 255, 0.11);
  --ink: rgba(255, 255, 255, 0.95);
  --ink-mid: rgba(255, 255, 255, 0.84);
  --ink-dim: rgba(255, 255, 255, 0.72);
  --ink-faint: rgba(255, 255, 255, 0.56);
  --accent: #64b4fa;
  --good: #3cc29a;
  --warn: #f2990a;
  --radius: 24px;
  --gap: 20px;
  --pad: 28px;
  /* One reading measure for every long-form block on the page. 68ch keeps a
     line at the 45-75 character range where the eye finds the next line without
     hunting; the old 760px lede ran past 90 characters at desktop sizes. */
  --measure: 68ch;
  /* The page's ONLY monospace, and it is spent on device configuration lines
     and nothing else: an xConfiguration is a value the reader retypes exactly,
     so the alignment and the unambiguous glyphs are load-bearing. Mono as a
     costume for "technical" is how a guide ends up with three voices. */
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'CiscoSansTT', 'Cisco SansTT', -apple-system, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover { color: #8ec7fb; }
img { max-width: 100%; }

/* One focus vocabulary for the whole page. The screenshot buttons had earned a
   deliberate 3px accent ring while every other focusable fell back to Chrome's
   1px default; the ring is the page's, so every focusable gets it. Radius is
   inherited from whatever the element already has, so pills stay pills. */
a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.wrap { max-width: 1240px; margin: 0 auto; padding-left: var(--pad); padding-right: var(--pad); }

/* ---------- sticky nav with scroll-spy ---------- */
.nav { position: sticky; top: 0; z-index: 50; background: #000; border-bottom: 1px solid var(--bg-card-2); }
.nav__inner {
  position: relative; /* the glide pill positions against the scrolling row */
  max-width: 1240px; margin: 0 auto; padding: 10px var(--pad);
  display: flex; align-items: center; gap: 4px; overflow-x: auto;
  scrollbar-width: none;
}
.nav__inner::-webkit-scrollbar { display: none; }
/* margin-right: auto separates brand from pills only while the rail has slack;
   on a phone the rail overflows and scrolls, the auto margin collapses to
   nothing, and the lockup sat one 4px gap from the first pill (Sean's catch,
   2026-08-18). The padding is the floor the auto margin cannot go below,
   sized to the pills' own 14px inset. */
.nav__brand { margin-right: auto; padding: 9px 18px 9px 0; display: flex; align-items: center; flex: none; }
/* 22px line + 11px top and bottom = a 44px target, the floor for a thumb. */
.nav__link {
  position: relative; z-index: 1; /* labels ride above the glide pill */
  font-size: 15px; line-height: 22px; padding: 11px 14px; border-radius: 999px; white-space: nowrap;
  color: var(--ink-dim); background: transparent; flex: none;
  transition: color 150ms cubic-bezier(0.22, 1, 0.36, 1), background 150ms cubic-bezier(0.22, 1, 0.36, 1);
}
.nav__link:hover { color: var(--ink); }
.nav__link.is-active { background: var(--bg-card-2); color: var(--ink); }
/* The active highlight, as one element that GLIDES between labels (info.js
   builds it and stamps nav--glide in the same breath). It scrolls with the
   rail because it is positioned inside the scrolling row, and the edge fade
   masks it exactly as it masks the labels. left/width are layout properties,
   but this is a single out-of-flow element the size of a word; nothing else
   reflows. JS owns top/height too, so the taller brand can never misalign it. */
.nav__pill {
  position: absolute; z-index: 0; width: 0;
  border-radius: 999px; background: var(--bg-card-2);
  transition: left 260ms cubic-bezier(0.22, 1, 0.36, 1), width 260ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* With the pill carrying the highlight, the per-link background retires; the
   rule above it stays as the no-script fallback. */
.nav--glide .nav__link.is-active { background: transparent; }
/* Scrolled-off pills were invisible on a phone: the row just looked truncated.
   info.js sets these classes from the scroll position, so the fade appears only
   on the side that actually has more nav to reach. */
.nav--fade-right .nav__inner {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent);
}
.nav--fade-left .nav__inner {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 48px), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 48px), transparent);
}
.nav--fade-left.nav--fade-right .nav__inner {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent);
}

/* ---------- the wordmark ----------
   idlescreen is set as live text, one family, two weights, and the word
   carries its own meaning in the weight: "idle" is the half held back at 50%
   ink, "screen" is the semibold half that stays lit. Two plain spans holding
   the exact word, so find, copy, and screen readers all get "idlescreen" —
   one word, never divided, never title-cased.
   Nothing here is a glyph substitution, and that is the load-bearing part.
   The brand sheet drew the accent tittle over a DOTLESS ı (U+0131), which
   copies out of the page as "ıdlescreen" and reads that way aloud; this repo
   has already paid for that class of trick twice (the qmark's aria-hidden
   twin, then the four iterations its glyph-cover took to stop clipping). The
   accent form below instead COVERS the letter's own tittle with an opaque
   disc, so the DOM keeps the plain word and nothing is drawn twice.
   The brand rule: lowercase, always. Never title-case it in copy or CSS.
   These class names and values are shared verbatim with the app shell's
   lockup: change one, change both. */
.imark {
  line-height: 1; letter-spacing: -0.03em; white-space: nowrap;
  /* Optical centring, the brand sheet's own numbers: -0.03em tracking hangs
     off the LAST letter as well as between them, so the ink sits a hair right
     of the box it is centred in. These cancel that trailing space and pull the
     left sidebearing onto the same optical edge. */
  margin-left: -0.0152em; margin-right: -0.0148em;
}
.imark__idle { font-weight: 300; color: rgba(255, 255, 255, 0.50); }
.imark__screen { font-weight: 600; color: var(--ink); }

/* The standalone display form, and the only place the word may carry blue.
   THE ACCENT APPEARS ONCE PER SURFACE: wherever the mark is on the surface it
   is the mark's lit card that carries the accent, and the word beside it wears
   its own plain tittle at every size, including the largest. Two saturated
   things on one surface read as decoration; one reads as a signal. So the nav
   brand and the footer lockup stay the plain form, and this modifier is for a
   surface that shows the word with no mark and no lit card anywhere on it: on
   either sheet that is exactly one element, the /info masthead h1.

   THE TITTLE IS THE IEC 5009 POWER SYMBOL (Sean's pick, 2026-08-21, after a
   mockup round). The product's whole subject is a screen that refuses to go
   dark, and the one glyph every reader already parses as "awake" happens to be
   the shape that fits where the i's dot goes. It is DRAWN, never typed: the
   markup stays two plain spans whose textContent is exactly "idlescreen", and
   the ring is an SVG mask on a pseudo-element (the same idiom --cog uses
   further down this sheet), so the ink rides background-color and stays
   themable while copy, find and screen readers are untouched.

   THE COVER DISC IS MANDATORY, AND IT WELDS THIS MODIFIER TO KNOWN-SOLID
   GROUND. The ring is hollow, so the letter's own tittle would show straight
   THROUGH it; ::before paints it out first with an OPAQUE disc in the colour of
   whatever the mark is standing on. That colour cannot be derived from anything
   (the disc sits over text, not over a box whose background it could inherit),
   so the surface has to declare it: --im-cover, set by the element that owns
   the background, with this sheet's own masthead panel as the fallback because
   /info is where the modifier was born. Naming it does not loosen the coupling,
   only makes it portable: the modifier may still only be worn where the ground
   really is one flat opaque colour, because on anything else the disc reads as
   a fleck beside the blue. Two surfaces wear it today and they are not the same
   colour, which is the whole reason the constant became a variable (2026-08-22):
   the guide's masthead panel (#05070a, .hero__screen) and the board's welcome
   card (--bg-card, #121212, set on .welcome__brand in main.css). The retired
   accent-dot form needed no cover at all, being opaque itself, which is the
   freedom this construction spends.

   THE GEOMETRY IS FACE-DEPENDENT, AND IS PROBED AT RUNTIME. Three different
   static baselines were each confidently wrong during the mockup round, for
   the plain reason that every number here moves with whichever face the stack
   above resolves to (all in em, all read off an ink-scan of "i" at weight 300,
   y stated as height above the baseline):
     Helvetica Neue    baseline 0.965, tittle (0.090, 0.665), box y 0.610-0.720, stem top 0.520
     generic sans      baseline 0.920, tittle (0.113, 0.675), box y 0.625-0.725, stem top 0.525
     SF (system-ui)    baseline unprobed, box y 0.5975-0.68875 (measured in Safari, 2026-08-18)
   "baseline" is the distance from this inline box's content-box top down to
   the text baseline, which is what an absolutely positioned child's top:0 is
   measured from. Chrome does not support -apple-system and falls through to
   Helvetica Neue (the first row, and what /info actually renders in Chrome on
   a Mac), Safari takes SF, and a Windows or Android box lands somewhere in
   Segoe UI or Roboto. Note the SECOND row is not a theoretical case: it is
   what the mockup round measured while believing it had CiscoSansTT, since
   this sheet loads NO webfont at all and the board face is only ever there if
   a visitor happens to have it installed. Two faces one stack apart, and the
   baseline alone moves 0.045em, which is 2.9px of misplacement at 64px.
   So info.js measures the live box after document.fonts.ready and publishes
   the answer as custom properties on the h1: --im-base, --im-tx / --im-ty
   (tittle centre), --im-tb (tittle bottom), --im-st (stem top), --im-td (cover
   diameter), --im-sx (stem centre). Every var() below carries the Helvetica
   Neue number as its fallback, so a page with no script at all is still placed
   correctly, just not per-face.

   PLACEMENT, Sean's pick "2", the midway one: the ring's outer bottom, which
   is 21.9/24 of the way down the glyph box, sits HALFWAY between the measured
   tittle bottom and the measured stem top. Hanging it at the tittle bottom
   (placement 1) is the air the font's own dot keeps, but the ring is more than
   twice the dot's height, so at that anchor the whole glyph rides up over the
   ascender line; splitting the gap settles it back into the word. Both ends of
   that gap are per-face measurements, which is why --im-st is probed and not
   assumed. The glyph is centred on the STEM and the cover on the TITTLE,
   because those are not the same x in every face, and the cover is 1.3x the
   tittle's larger dimension so it clears the antialiased edge.
   These class names and values are shared verbatim with main.css: change one,
   change both. */
.imark--led .imark__idle {
  position: relative;
  --im-power: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M12 4.5 V12.6'/%3E%3Cpath d='M7.76 8.94 A6.6 6.6 0 1 0 16.24 8.94'/%3E%3C/svg%3E");
  /* One constant, because it is the only number here that is not a property of
     the face: the glyph's own box, in em. */
  --im-glyph: 0.26em;
}
/* The cover: an opaque disc in the surface's own colour, centred on the
   measured tittle. */
.imark--led .imark__idle::before {
  content: '';
  position: absolute;
  left: calc(var(--im-tx, 0.09) * 1em - var(--im-td, 0.143) * 0.5em);
  top: calc((var(--im-base, 0.965) - var(--im-ty, 0.665)) * 1em - var(--im-td, 0.143) * 0.5em);
  width: calc(var(--im-td, 0.143) * 1em); height: calc(var(--im-td, 0.143) * 1em);
  border-radius: 50%;
  background: var(--im-cover, #05070a);
}
/* The power symbol, drawn as a mask so the ink is a background-color. The top
   term is the midway anchor: half of (tittle bottom + stem top) is where the
   ring's outer bottom goes, and 21.9/24 of the box is how far that is from the
   box's own top. */
.imark--led .imark__idle::after {
  content: '';
  position: absolute;
  left: calc(var(--im-sx, 0.09) * 1em - var(--im-glyph) * 0.5);
  top: calc((var(--im-base, 0.965) - (var(--im-tb, 0.61) + var(--im-st, 0.52)) * 0.5) * 1em - var(--im-glyph) * 21.9 / 24);
  width: var(--im-glyph); height: var(--im-glyph);
  background-color: var(--accent);
  -webkit-mask: var(--im-power) center / contain no-repeat;
  mask: var(--im-power) center / contain no-repeat;
}
/* THE SMALL-SIZE FALLBACK, and the threshold is in DEVICE pixels, not CSS
   ones. Rasterised at 1x and read back, the ring needs about 11 device pixels
   across before its hole survives: at the h1's 38px floor the glyph box is
   9.9px and comes out a mushy lozenge with a stub on top, which reads as a
   dirty dot rather than as the mark; by 44px (11.4px of box) the hole is open
   and the stem separates. On a 2x or 3x display the same 38px is 19.8 or 29.6
   device pixels and the ring is crisp, and a 2x display is the only kind of
   thing that reaches this width in practice. So the cutoff is keyed on BOTH
   conditions, and the mark only stands down where it actually breaks down.
   The h1 is clamp(38px, 6.4vw, 64px), so 6.4vw crosses 44px at 688px of
   viewport; below that it is pinned at the 38px floor anyway.
   What it falls back TO is the accent DOT this modifier wore until 2026-08-21,
   on the same measured geometry: ::before is already a disc centred on the
   measured tittle at the covering diameter, so it only has to change colour,
   and an opaque disc covers the letter's own tittle by being opaque, the way
   the dot always did. A browser too old to know max-resolution fails the whole
   query and keeps the ring, which is the right way round: every browser that
   old, at this width, is on a retina phone. */
@media (max-width: 687px) and (max-resolution: 1.5dppx) {
  .imark--led .imark__idle::before { background: var(--accent); }
  .imark--led .imark__idle::after { display: none; }
}

/* ---------- hero ---------- */
.hero { padding-top: 84px; padding-bottom: 12px; }
/* The masthead is the product's own subject at poster scale: one landscape
   screen, awake, with four cards on its ruled grid and the name read across
   the clear middle band. The accent marks what is awake: exactly one card is
   lit, the other three sit at descending light, which is the system rule the
   whole palette runs on. Nothing sits BEHIND the letters except the ruling
   itself, which is the precedent the previous masthead set: the faint grid
   may run under the word, placed cards never do.
   (The ruling came back at Sean's call 2026-08-18: under the old name it drew
   the name's meaning; under this one it draws the BOARD, the grid the ghost
   cards actually live on. Every geometric rule below is inherited verbatim
   from the retired field, learned defects and all.) */
.hero__screen {
  --cell: 30px;
  /* The gutter a placed module keeps from the rules around it — the same idea
     as the icon masters' constant gutter, and the edit view's card inset. */
  --g: 3px;
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  /* Landscape at every width, and tall enough that the word's own band stays
     clear of the card rows. The snap in info.js rounds the rendered box to
     whole cells, so these bounds are starting points, not the final size. */
  min-height: clamp(180px, 26vw, 260px);
  /* Two cells of vertical padding, the retired field's own number: the top
     and bottom card rows live inside it, so the centered title-and-sub stack
     can never enter their rows; when the sub wraps taller the panel grows
     and the snap rounds the growth to whole cells. */
  padding: calc(var(--cell) * 2) calc(var(--cell) * 1.5);
  background-color: #05070a;
  /* The corner radius is exactly ONE CELL: the arc's endpoints land on the
     first interior rules, so each corner cell is a quarter-round bounded by
     the arc and two rules, a corner OF the grid rather than a curve clipping
     through it. An arbitrary radius cuts cells mid-way. */
  border-radius: var(--cell);
  /* The keyline is the outermost rule: firmer than the interior ruling (.085)
     because anti-aliasing feathers the corner arcs and dilutes their apparent
     ink; equal alpha would read fainter on the curves than on the straights.
     background-position hides the gradient's own first line under the keyline
     so the left and top edges are never drawn twice. */
  border: 1px solid rgba(255, 255, 255, 0.13);
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.085) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.085) 1px, transparent 1px);
  background-size: var(--cell) var(--cell);
  background-position: -1px -1px;
}
/* Cell units, not percentages: cards on a visible ruling must LAND on it, the
   same discipline the dashboard itself and the icon masters keep. ONE rule
   for every card, lit and ghost alike: occupy a whole-cell span, inset by
   the gutter from the four rules that bound it. And every card is OPAQUE
   (the ghost tints are pre-blended against the panel's #05070a): a
   translucent card lets the ruling show through its body, which reads as a
   card that does not fit its cells (Sean's catch on beta review). A real
   card covers the cells it occupies; these do too. */
.hero__card { position: absolute; border-radius: 3px; }
.hero__card--lit { left: calc(var(--cell) + var(--g)); top: calc(var(--cell) + var(--g)); width: calc(var(--cell) * 3 - var(--g) * 2); height: calc(var(--cell) - var(--g) * 2); background: #64b4fa; }
.hero__card--b { right: calc(var(--cell) + var(--g)); top: calc(var(--cell) + var(--g)); width: calc(var(--cell) * 2 - var(--g) * 2); height: calc(var(--cell) - var(--g) * 2); background: #182a3a; }
.hero__card--c { right: calc(var(--cell) + var(--g)); bottom: calc(var(--cell) + var(--g)); width: calc(var(--cell) * 2 - var(--g) * 2); height: calc(var(--cell) - var(--g) * 2); background: #101c27; }
.hero__card--d { left: calc(var(--cell) + var(--g)); bottom: calc(var(--cell) + var(--g)); width: calc(var(--cell) * 2 - var(--g) * 2); height: calc(var(--cell) - var(--g) * 2); background: #182a3a; }
/* position:relative is paint-order clarity only; the panel is one stacking
   context and the word is the last thing in it either way. */
.hero__title { position: relative; margin: 0; font-size: clamp(38px, 6.4vw, 64px); line-height: 1; }
/* The sub lives INSIDE the panel under the wordmark (Sean's call on beta
   review, restoring the old masthead's arrangement); the note stays below.
   position: relative is the same paint-order clarity the title carries, and
   the measure is tighter than the page's because the panel's own padding is
   what frames it now. */
.hero__sub { position: relative; font-size: clamp(15px, 1.6vw, 17px); line-height: 1.45; color: var(--ink-mid); margin: 14px 0 0; max-width: 48ch; text-align: center; text-wrap: pretty; }
.hero__note { font-size: 16px; color: var(--ink-dim); margin: 18px 0 0; max-width: var(--measure); }
/* Nav brand is the mark and the wordmark at rail scale. min-height holds the
   same 44px thumb target the pills beside it keep, and it is a BORDER-box 44
   (the sheet sets box-sizing globally), so the 9px padding is inside it:
   .imark sets line-height:1, which collapses the flex row to the em box and
   would otherwise leave the brand a 39px target next to 44px neighbours.
   Mark 18, wordmark 21, gap 10 — the brand sheet's rail metrics. */
.nav__brand { font-size: 21px; color: var(--ink); gap: 10px; min-height: 44px; }
.nav__mark { flex: none; display: block; }

/* The hero shows the product: the board sits beside the lede once there is room
   for both to stay legible, and drops below it before either gets squeezed.
   The picture is deliberately compact here, which is why it is a shot__btn like
   the section screenshots — the full board is one tap away in the lightbox. */
.hero__shot { margin: 34px 0 0; }
.hero__shot img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius); border: 1px solid var(--bg-card-2);
}
@media (min-width: 1100px) {
  .hero {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    align-items: center; column-gap: 48px;
  }
  .hero__shot { margin-top: 0; }
}

/* ---------- sections ---------- */
.section { padding-top: 72px; scroll-margin-top: 76px; }
.section:first-of-type { padding-top: 56px; }
.h2 { font-size: 30px; font-weight: 700; margin: 0 0 26px; letter-spacing: -0.01em; }
.h2--tight { margin-bottom: 6px; }
/* .h2--flush, .head and .count are gone with the per-group sections: a count
   chip beside every heading was a third uppercase register saying what the list
   under it already said, and the one on Screensavers had drifted (it claimed
   six sources; there are seven). */
.section__sub { font-size: 17px; color: var(--ink-dim); margin: 0 0 26px; max-width: var(--measure); }
.section__lede { font-size: 17px; line-height: 1.5; color: var(--ink-dim); margin: 0 0 26px; max-width: var(--measure); text-wrap: pretty; }
/* A section's trailing quiet line (the relocated footer sentence): the old
   footer__p's own size and ink, so the sentence reads exactly as it always
   did, just standing where its subject lives. The stamp beside it is the
   sentence's own demonstration: the amber "as of" treatment a stale card
   wears, in miniature. */
.section__aside { font-size: 15.5px; color: var(--ink-dim); margin: 22px 0 0; max-width: var(--measure); }
.aside__stamp { font-size: 14px; color: var(--warn); opacity: 0.75; margin-left: 6px; white-space: nowrap; }

/* ---------- tile grid (display modes, screensaver sources) ----------
   A grid only. Both grids hold .card, so the page has exactly one card
   surface: the tinted 12px .tile that display modes used to get is gone,
   because two different card treatments inside one section read as two
   unrelated things. */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--gap); }
.tiles--cards { margin-bottom: 14px; }

/* ---------- cards ---------- */
.card {
  background: var(--bg-card); border-radius: var(--radius); padding: 24px 26px;
  display: flex; flex-direction: column; overflow: hidden;
}
.card--pad { padding: 18px 20px; }
.card--row { padding: 22px 24px; flex-direction: row; gap: 18px; align-items: flex-start; }
.card__stack { display: flex; flex-direction: column; gap: 8px; }
.card__h { font-size: 18px; font-weight: 600; margin: 0 0 8px; }
.card--row .card__h, .card--pad .card__h { margin: 0 0 8px; }
.card--row .card__h { margin: 0; }
.card__p { font-size: 16px; line-height: 1.5; color: var(--ink-mid); margin: 0; }
.card__note { font-size: 15px; color: var(--ink-dim); margin-top: auto; padding-top: 14px; }
/* .card__fine retired 2026-07-29 with its only user, the "Tap anywhere to
   close" fine print under Tap a card. Left as a note rather than silently
   dropped: this file has grown orphaned declarations before. */
.duo { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: var(--gap); }
/* "Making it yours" grew a third control — the cards themselves — so the pair
   becomes a trio. 300px is the floor at which a 56px FAB plus its copy still
   reads; below it the row-cards stack, as they already did at 560px. */
.duo--trio { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

/* ---------- getting it on a board ----------
   Three doors in the tile-card grammar Display Modes and Screensavers already
   use. Deliberately NO icon badge: the .fab circles below mean "this is one of
   the board's three buttons", and borrowing them for device names would spend
   a meaningful component on decoration. A door's own name is the whole label
   it needs. */
.doors { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
/* The one string that tells a door apart from the other two, pinned to the
   card's foot by the same margin-top:auto .card__note uses — so three cards of
   unequal prose still line their values up on one baseline. The full set of
   configurations lives once, in the .conf block below; this is an identifier,
   not a copy of it. */
.card__code {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--bg-card-2);
  font-size: 14px;
  line-height: 1.5;
}
.card__code code { background: none; padding: 0; color: var(--ink-dim); white-space: normal; word-break: break-word; }
/* The macro is the one door whose artifact is a FILE rather than a value, so
   its foot is a link and reads like one. */
.card__code a { color: var(--accent); }
.card__code a code { color: inherit; }

/* A configuration value, inline in prose. */
code {
  font-family: var(--mono);
  font-size: 0.9em;
  color: var(--ink);
  background: var(--bg-card-2);
  border-radius: 6px;
  padding: 1px 6px;
  white-space: nowrap;
}
/* The device's own lines, quoted verbatim and set as one well. */
.conf {
  font-family: var(--mono);
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink-mid);
  background: var(--bg-card-2);
  border-radius: 12px;
  margin: 0;
  padding: 14px 18px;
}
/* A hanging indent rather than a horizontal scrollbar: a wrapped
   xConfiguration still reads as one setting on a phone, and nothing in a guide
   should have to be dragged sideways. It needs a block per line — text-indent
   on the <pre> only ever catches the first — which is why info.html writes
   each line as its own span. */
.conf__l { display: block; padding-left: 1.6em; text-indent: -1.6em; white-space: pre-wrap; }
/* An annotation on a line meant to be retyped, so it must not travel with a
   copy: user-select:none drops it from the selection, and a paste gets the
   configuration alone. --ink-dim rather than --ink-faint because this sits at
   14px, below the size where faint still clears AA. */
.conf__note { color: var(--ink-dim); user-select: none; -webkit-user-select: none; }
.conf__after { font-size: 15.5px; line-height: 1.5; color: var(--ink-dim); margin: 14px 0 0; max-width: var(--measure); }

/* the two round board buttons, rendered calm like they are on the device */
.fab {
  width: 56px; height: 56px; border-radius: 999px; background: var(--bg-card-2);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0; color: var(--ink);
}

/* ---------- the folded index ----------
   One disclosure per product group. What folds is the PROSE; the inventory
   never folds, so all 33 widget names are on screen at rest and the reader
   opens only the group they came for. No script: <summary> is natively
   focusable and keyboard-operable, and the print block at the foot of this
   file forces every group open. */
.folds { display: flex; flex-direction: column; margin-top: 8px; }
/* scroll-margin because each fold is a link target in its own right: the ids
   are the ones the old per-group sections carried, so /info#commute still
   lands, and the sticky nav would otherwise cover it. */
.fold { border-top: 1px solid var(--bg-card-2); scroll-margin-top: 76px; position: relative; }
/* Which rows belong to the open group? The spine answers: a rule that grows
   down the left gutter, header through last row (Sean's pick, B of three
   mockups, 2026-08-13). It floats OUTSIDE the text column so nothing indents
   when a group opens, and it is deliberately brighter than the row hairlines:
   figure, not furniture. Its growth keeps time with the unfold in info.js. */
.fold::before {
  content: ""; position: absolute; left: -20px; top: 14px; bottom: 14px;
  width: 1px; background: rgba(255, 255, 255, 0.38);
  transform: scaleY(0); transform-origin: top;
  transition: transform 300ms cubic-bezier(0.22, 1, 0.36, 1);
}
.fold[open]::before { transform: scaleY(1); }
/* No closing rule: the "On a board" subhead below carries its own border-top,
   and two hairlines 40px apart read as a mistake. */
/* 150px + a 20px gutter puts the dek on the same optical left edge as the
   .row__desc inside the group, so opening one does not shift the reading
   column. Every child is placed explicitly: the caret spans both rows, and
   auto-placement around a row-spanning item is not worth guessing at. */
.fold__sum {
  list-style: none; cursor: pointer;
  display: grid; grid-template-columns: 150px minmax(0, 1fr) 1.1em;
  gap: 6px 20px; align-items: baseline;
  padding: 16px 2px;
}
.fold__sum::-webkit-details-marker { display: none; }
.fold__sum:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
.fold__name { grid-column: 1; grid-row: 1; font-size: 15px; font-weight: 600; margin: 0; text-transform: uppercase; letter-spacing: 0.09em; color: var(--ink); }
.fold__dek { grid-column: 2; grid-row: 1; font-size: 16px; line-height: 1.45; color: var(--ink-mid); }
/* The inventory line: quiet, but present at rest — this is the part a scanner
   is actually looking for. It goes away once the group is open, because every
   name is then a row heading two lines below. */
.fold__ids { grid-column: 2; grid-row: 2; font-size: 15px; line-height: 1.5; color: var(--ink-dim); }
.fold[open] .fold__ids { display: none; }
/* Calm at rest, ignites only on press — the page's own control idiom. */
.fold__caret { grid-column: 3; grid-row: 1 / span 2; justify-self: end; align-self: center; color: var(--ink-dim); transition: color 150ms; }
.fold__sum:hover .fold__caret { color: var(--ink); }
.fold__sum:active .fold__caret { color: var(--accent); }
.fold__caret::after {
  content: ""; display: block; width: 0.55em; height: 0.55em;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-0.12em) rotate(45deg);
  transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
.fold[open] .fold__caret::after { transform: translateY(0.12em) rotate(-135deg); }
.fold > .list { padding-bottom: 14px; }

/* ---------- widget rows ---------- */
.list { display: grid; grid-template-columns: repeat(auto-fit, minmax(470px, 1fr)); column-gap: 56px; }
/* An odd number of widgets in a two-column list leaves the last cell empty, and
   with it a visibly missing hairline at the foot of the right column. A grid
   ::after lands in exactly that cell, and only draws its rule when the count is
   odd, so an even group gains a zero-height row that draws nothing. */
.list:has(.row:nth-child(odd):last-child)::after { content: ""; border-top: 1px solid var(--bg-card-2); }
.row { display: flex; flex-wrap: wrap; gap: 4px 20px; padding: 15px 2px; border-top: 1px solid var(--bg-card-2); }
.row__name { font-size: 17px; font-weight: 600; margin: 0; flex: 0 0 150px; }
.row__desc { font-size: 16px; line-height: 1.5; color: var(--ink-mid); margin: 0; flex: 1 1 260px; }
.row__note { color: var(--ink-dim); display: block; margin-top: 4px; }

/* Settings hint marker. The app's own cog (icons.js) drawn as a mask in
   currentColor — NOT the "⚙" character, which platforms render as a colour
   emoji that clashes with the type. */
.row__note::before,
.card__note::before,
.notes__p::before {
  content: "";
  display: inline-block;
  width: 1.05em; height: 1.05em;
  margin-right: 0.45em;
  vertical-align: -0.17em;
  background-color: currentColor;
  -webkit-mask: var(--cog) center / contain no-repeat;
  mask: var(--cog) center / contain no-repeat;
}
:root {
  --cog: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'/%3E%3C/svg%3E");
}

/* ---------- board screenshots ---------- */
.shot { margin: 34px 0 0; border-radius: var(--radius); border: 1px solid var(--bg-card-2); overflow: hidden; }
.shot img { display: block; width: 100%; height: auto; cursor: zoom-in; }
/* Each screenshot is a real button, so the lightbox opens from the keyboard
   (Enter or Space) as well as a tap. Stripped to nothing visually; the focus
   ring is the only thing it draws, and it sits inside the figure's clip so it
   follows the rounded corner. */
.shot__btn {
  display: block; width: 100%; padding: 0; margin: 0; border: 0;
  background: none; color: inherit; font: inherit; cursor: zoom-in;
}
.shot__btn:focus { outline: none; }
.shot__btn:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; border-radius: var(--radius); }
.shots { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: var(--gap); margin-top: var(--gap); }
.shot--half { margin: 0; position: relative; }
.shot__cap {
  position: absolute; top: 14px; left: 14px; background: var(--bg-card-2);
  border-radius: 10px; padding: 5px 11px; font-size: 14px; font-weight: 600; color: var(--ink);
}

/* ---------- the contact sheet ----------
   The four board captures that used to interrupt four sections, gathered into
   one block a reader passes once: 1,332px instead of 2,664px, and on a phone
   one block to scroll past instead of four ambushes.
   A contact sheet labels its plates underneath. The .shots chip overlay works
   on the two screensaver captures (dark, empty top-left corner); on a dashboard
   capture it lands squarely on the greeting and reads louder than the board it
   is naming, which is the wrong way round. */
.gal { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); gap: 22px var(--gap); margin-top: 26px; }
.gal .shot--half { margin: 0; position: static; border: 0; border-radius: 0; overflow: visible; }
.gal .shot--half img { border: 1px solid var(--bg-card-2); border-radius: 14px; }
.gal .shot__cap {
  position: static; display: block; background: none; padding: 9px 2px 0;
  font-size: 15px; font-weight: 600; color: var(--ink-dim);
}

/* ---------- subheads ---------- */
/* scroll-margin because a subhead can be a link target in its own right:
   /info#modes lands on one, and the sticky nav would otherwise cover it. */
.subhead { display: flex; align-items: baseline; gap: 14px; padding-top: 22px; border-top: 1px solid var(--bg-card-2); margin-bottom: 20px; flex-wrap: wrap; scroll-margin-top: 76px; }
/* A subhead that follows a card grid or a list has to bring its own breathing
   room; the hairline alone lands too close to what it is separating. */
.subhead--gap { margin-top: 40px; }
.subhead__title { font-size: 20px; font-weight: 600; margin: 0; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-dim); }
.subhead__note { font-size: 15px; color: var(--ink-dim); }
/* Two short notes stacked left in a full-width tinted well left the right half
   of the well empty. Capping the prose is right; stacking it was not. They sit
   side by side and each column lands inside the measure on its own. */
.notes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 34ch), 1fr));
  gap: 10px 28px; margin-top: var(--gap);
  background: var(--bg-card-2); border-radius: 12px; padding: 16px 18px;
}
.notes__p { font-size: 15px; line-height: 1.45; color: var(--ink-dim); margin: 0; max-width: var(--measure); }

/* ---------- terms ----------
   The same row rhythm the widget list and the changelog keep: a quiet label
   column, prose on the right. A terms page that invents its own type and
   spacing reads as some other product's terms; this one is the guide in a
   plainer mood. Only the container is new, and .row does the rest. */
.section--terms { padding-bottom: 8px; }
/* The container stops where the prose does. A hairline that runs 600px past
   the last word of every clause reads as an unfinished table; the label
   column (150px) plus its gutter plus the measure is the real width of the
   thing being ruled. */
.terms { display: flex; flex-direction: column; margin-top: 26px; max-width: calc(170px + var(--measure)); }
.terms .row { padding: 18px 2px; }
/* The widget list gets its measure from being two columns; a single-column
   clause list has to bring its own, or the prose runs to ~100 characters and
   the eye starts hunting for the next line. */
.terms .row__desc { max-width: var(--measure); }
/* A clause's trailing caveat: quieter than the clause, still above the
   small-text contrast floor (--ink-faint fails AA below 18px; --ink-dim
   does not). No cog marker — .row__note carries one, and nothing here
   happens behind the gear. */
.row__fine { display: block; margin-top: 10px; font-size: 15px; line-height: 1.45; color: var(--ink-dim); }
/* When the page last changed, which a terms page has to say. */
.section__stamp { font-size: 15px; color: var(--ink-dim); margin: 0 0 4px; }
.footer__link { font-size: 15px; color: var(--ink-dim); }
.footer__link:hover { color: var(--ink); }

/* ---------- what's new (built by info.js) ----------
   Deliberately the same geometry as the widget rows above: hairline per group,
   a quiet label column, prose on the right. A changelog is a list, not a set of
   cards, and reusing the row rhythm keeps it from becoming its own little
   design. */
.log { display: flex; flex-direction: column; }
.log__group { display: flex; flex-wrap: wrap; gap: 4px 20px; padding: 15px 2px; border-top: 1px solid var(--bg-card-2); }
.log__date { font-size: 16px; font-weight: 600; color: var(--ink-dim); margin: 0; flex: 0 0 150px; }
/* The items flow into as many measure-sized columns as the row can hold rather
   than running a single 68ch strip down the left of a 1,184px row. CSS COLUMNS,
   not grid (Sean, 2026-08-02): the grid's shared row heights parked a short
   entry beside a long one and left its whole cell-mate's height as dead space.
   Columns give every entry its own height and fill down-then-over, which is
   also the newest-first reading order the page promises. One column is what a
   narrow row gets. */
.log__items {
  columns: 44ch; column-gap: 28px; flex: 1 1 260px; min-width: 0;
}
.log__item { font-size: 16px; line-height: 1.5; color: var(--ink-mid); margin: 0 0 10px; text-wrap: pretty; max-width: var(--measure); break-inside: avoid; }
.log__item:last-child { margin-bottom: 0; }
.log__lead { font-weight: 600; color: var(--ink); margin-right: 0.4em; }
/* The disclosure for older groups. Calm at rest — it reads as one more quiet
   row in the list, not a button competing with the copy — and only ignites on
   press. 20px line + 12px top and bottom = a 44px target. */
.log__toggle {
  font: inherit; font-size: 15px; line-height: 20px; text-align: left;
  padding: 12px 2px; margin: 0; width: 100%;
  background: none; border: 0; border-top: 1px solid var(--bg-card-2);
  color: var(--ink-dim); cursor: pointer;
  transition: color 150ms cubic-bezier(0.22, 1, 0.36, 1);
}
.log__toggle:hover { color: var(--ink); }
.log__toggle:active { color: var(--accent); }
/* A control has to look like one before it is touched, so the caret carries the
   affordance the calm colour deliberately does not. It points down while there
   is more below, and up once there is not. */
.log__toggle::after {
  content: ""; display: inline-block; width: 0.5em; height: 0.5em;
  margin-left: 0.6em; vertical-align: 0.18em;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
.log__toggle[aria-expanded="true"]::after { transform: translateY(0.1em) rotate(-135deg); }
.log__more { display: flex; flex-direction: column; }
/* Shown when the notes cannot be fetched, and by <noscript> when there is no
   script at all. Quiet on purpose: it is an absence, not an error. */
.log__empty { font-size: 16px; line-height: 1.5; color: var(--ink-dim); margin: 0; padding: 15px 2px; border-top: 1px solid var(--bg-card-2); max-width: var(--measure); }

/* ---------- footer ----------
   The lockup alone signs the page (the brand sheet's own footer context).
   The behavior sentence AND its stale-stamp wink both moved up into Making
   it yours (Sean's calls, 2026-08-18): facts about the product belong with
   the section that explains it, and the wink only reads beside the sentence
   it demonstrates. */
.footer { margin-top: 96px; padding-top: 26px; padding-bottom: 72px; }
.footer__inner { border-top: 1px solid var(--bg-card-2); padding-top: 24px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.footer__brand { display: flex; align-items: center; gap: 10px; }
.footer__brand .imark { font-size: 17px; }

/* ---------- lightbox (built by info.js) ---------- */
.lightbox {
  position: fixed; inset: 0; z-index: 100; background: #000;
  display: flex; align-items: center; justify-content: center; padding: 32px; cursor: zoom-out;
}
.lightbox__img { max-width: 100%; max-height: 100%; width: auto; height: auto; border-radius: var(--radius); border: 1px solid var(--bg-card-2); }
.lightbox__cap {
  position: absolute; top: 24px; left: 28px; font-size: 14px; font-weight: 600;
  color: var(--ink); background: var(--bg-card-2); border-radius: 10px; padding: 5px 11px;
}
.lightbox__hint { position: absolute; bottom: 24px; font-size: 15px; color: var(--ink-dim); }

/* ---------- narrow screens ---------- */
@media (max-width: 900px) {
  :root { --pad: 20px; }
  .hero { padding-top: 56px; }
  /* One knob: the cell. Every card is sized and placed in cell units, so the
     grid, the cards, the corner radius and the padding all shrink together
     and nothing can fall off the ruling. Same step the retired field used. */
  .hero__screen { --cell: 24px; }
  .section { padding-top: 56px; }
  .h2 { font-size: 26px; }
  /* One column: the two-column ::after balancer has no empty cell to fill. */
  .list { grid-template-columns: 1fr; column-gap: 0; }
  .list::after { display: none; }
  /* The fold's three lines stack, and the caret spans all three. */
  .fold__sum { grid-template-columns: minmax(0, 1fr) 1.1em; }
  /* --pad is 20px here; at -20px the spine would kiss the viewport edge. */
  .fold::before { left: -12px; }
  .fold__name { grid-column: 1; grid-row: 1; }
  .fold__dek { grid-column: 1; grid-row: 2; }
  .fold__ids { grid-column: 1; grid-row: 3; }
  .fold__caret { grid-column: 2; grid-row: 1 / span 3; }
  /* A phone renders a 1920px board at 0.18 scale whatever column it sits in,
     so a full-width one buys nothing but scroll. Two up, the four read as one
     contact sheet for half the height, and the lightbox is still one tap. */
  .gal { grid-template-columns: 1fr 1fr; gap: 16px 14px; }
  .gal .shot--half img { border-radius: 12px; }
  .gal .shot__cap { padding-top: 7px; font-size: 13px; font-weight: 500; }
  .conf { font-size: 13px; }
  .terms .row__name { flex: 1 1 100%; }
  .row__name { flex: 1 1 100%; }
  .row__desc { flex: 1 1 100%; }
  .log__date { flex: 1 1 100%; }
  .log__items { flex: 1 1 100%; }
  .footer { margin-top: 64px; }
}
@media (max-width: 560px) {
  /* Horizontal padding gives up half a cell for width; the vertical TWO
     CELLS are load-bearing (the card rows live inside them) and do not
     shrink. A third cell size would make the ruling read as three different
     products in one scroll, so the grid itself stays at the 24px step. */
  .hero__screen { padding: calc(var(--cell) * 2) var(--cell); }
  .hero__card--c, .hero__card--d { height: 28px; }
  .duo { grid-template-columns: 1fr; }
  .card--row { flex-direction: column; gap: 14px; }
  .shots { grid-template-columns: 1fr; }
  .lightbox { padding: 56px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .nav__link, .nav__pill, .log__toggle, .log__toggle::after, .fold__caret, .fold__caret::after, .fold::before { transition: none; }
  html { scroll-behavior: auto; }
}

/* ---------- print ----------
   A document that calls itself a guide has to survive being printed. Same page,
   ink on paper: the screen chrome (sticky nav, overlay, the disclosure the
   reader cannot press) goes away, the palette flips, and nothing that reads as
   one unit is allowed to break across a sheet. */
@media print {
  :root {
    --bg: #fff; --bg-card: #fff; --bg-card-2: #d8d8d8;
    --ink: #000; --ink-mid: #1a1a1a; --ink-dim: #3a3a3a; --ink-faint: #555;
    --accent: #00429d;
  }
  /* info.html carries an inline background on <html> so the page never flashes
     white before this stylesheet lands. The canvas background propagates from the
     ROOT, so without this the black would print as a frame around every sheet.
     !important is load-bearing: an author !important outranks an inline attribute. */
  html { background: #fff !important; }
  body { background: #fff; color: #000; }
  .nav, .lightbox, .log__toggle { display: none !important; }
  /* Paper has no "show more": print the history the toggle was hiding. */
  .log__more[hidden] { display: flex !important; }
  /* Nor a disclosure. A closed <details> hides its content on the
     ::details-content pseudo, NOT on the .list inside it, so overriding the
     child does nothing at all — that mistake prints eight headings and no
     guide. Open the pseudo itself.
     info.js also sets `open` on every fold from beforeprint, which is what
     actually fires on Cmd+P and covers browsers without ::details-content;
     this rule is what Chrome's print PREVIEW and headless print-to-PDF get,
     since neither dispatches that event. Belt and braces on purpose: a guide
     has to survive being printed.
     The inventory line is dropped in exactly the two cases where the rows
     below it replace it: @supports covers the CSS path (the fold has no `open`
     attribute, so the screen rule cannot see it), and the screen rule itself
     covers the script path. A browser with neither still prints every widget
     name rather than a blank page, which is the point of doing both. */
  @supports selector(::details-content) {
    .fold::details-content { content-visibility: visible !important; }
    .fold__ids { display: none !important; }
  }
  .fold__caret { display: none !important; }
  .wrap { max-width: none; padding-left: 0; padding-right: 0; }
  a { color: #000; text-decoration: underline; }
  /* The screen panel is a dark slab and would print as one. On paper the
     masthead is just the name: panel chrome off, cards gone, the word set
     left where a printed heading belongs. "screen" rides var(--ink), which
     the palette flip above turns black; "idle" needs its own ink, because its
     50%-WHITE is invisible on paper, and a mid-gray holds the same two-tone
     reading the screen has. */
  .hero__screen {
    background: none; border: 1px solid #c8c8c8; padding: 18px 22px;
    display: block; min-height: 0;
  }
  .hero__card { display: none; }
  .hero__title, .nav__brand { color: #000; }
  .imark__idle { color: #5a5a5a; }
  /* And the LED tittle goes with the panel that made it possible. Its cover
     disc is painted #05070a because that is the panel's own background; with
     the panel gone that disc is a near-black blot on white paper, with a blue
     ring drawn over it. Both halves stand down and the letter prints its own
     dot, which is the whole point of never having substituted the glyph. */
  .imark--led .imark__idle::before,
  .imark--led .imark__idle::after { display: none; }
  .hero { padding-top: 0; display: block; }
  .hero__shot { margin-top: 24px; }
  .section { padding-top: 28px; }
  .card, .notes, .fab, .conf { border: 1px solid #c8c8c8; }
  .card, .notes { background: #fff; }
  .shot, .hero__shot, .card, .notes, .conf, .row, .log__group, .subhead, .fold { break-inside: avoid; }
  .h2, .subhead__title, .fold__name { break-after: avoid; }
  .footer { margin-top: 36px; padding-bottom: 0; }
  .footer__stamp { color: var(--ink-dim); opacity: 1; }
}
