/* 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;
}

* { 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 {
  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; }
.nav__brand { margin-right: auto; padding: 9px 0; display: flex; align-items: center; flex: none; }
.nav__brand img { display: block; height: 26px; width: auto; }
/* 22px line + 11px top and bottom = a 44px target, the floor for a thumb. */
.nav__link {
  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); }
/* 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);
}

/* ---------- hero ---------- */
.hero { padding-top: 84px; padding-bottom: 12px; }
/* The masthead IS the logo: the h1 holds the lockup and nothing else, so the
   mark has to sit on the same optical left edge and vertical rhythm as the
   prose beneath it. Its own box does not give you that, because the SVG carries
   3.5/373 of empty bearing to the left of the icon's stroked rect and 13.5/373
   above and below it. The negative margins cancel exactly those bearings, which
   is why they are ratios of --lockup-w and not fixed pixels: they have to track
   the mark as it scales. */
.hero__title {
  --lockup-w: min(540px, 92vw);
  --lockup-bleed: calc(var(--lockup-w) * 0.0362);
  line-height: 0;
  margin: calc(0px - var(--lockup-bleed)) 0 calc(30px - var(--lockup-bleed));
}
.hero__lockup {
  display: block;
  width: var(--lockup-w);
  max-width: 100%;
  height: auto;
  margin-left: calc(var(--lockup-w) * -0.00938);
}
.hero__lede { font-size: clamp(19px, 2.2vw, 23px); line-height: 1.45; color: var(--ink-mid); margin: 0 0 14px; max-width: var(--measure); text-wrap: pretty; }
.hero__note { font-size: 16px; color: var(--ink-dim); margin: 0; max-width: var(--measure); }

/* 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; }

/* ---------- 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)); }

/* 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; }
/* 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); }

/* ---------- 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 ---------- */
.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: baseline; gap: 12px; flex-wrap: wrap; }
.footer__p { font-size: 15.5px; color: var(--ink-dim); margin: 0; }
.footer__stamp { font-size: 14px; color: var(--warn); opacity: 0.75; }

/* ---------- 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; }
  /* 100% is the 350px measure the lede wraps to at a 390px viewport, so the
     mark never outruns the text block it heads. */
  .hero__title { --lockup-w: min(380px, 100%); margin-bottom: calc(24px - var(--lockup-bleed)); }
  .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; }
  .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; }
  .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) {
  .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, .log__toggle, .log__toggle::after, .fold__caret, .fold__caret::after { 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 lockup is white-on-transparent and would print as nothing at all.
     Inverting alone turns the brand blue orange, so the hue-rotate puts the hue
     back where it started and only the lightness flips. */
  .hero__lockup { filter: invert(1) hue-rotate(180deg); }
  .hero { padding-top: 0; display: block; }
  .hero__shot { margin-top: 24px; }
  .section { padding-top: 28px; }
  .card, .notes, .fab { border: 1px solid #c8c8c8; }
  .card, .notes { background: #fff; }
  .shot, .hero__shot, .card, .notes, .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; }
}
