/* Generated by scripts/gen-site.mjs from src/docs/chrome.ts — do not edit.
   Run `npm run docs` to regenerate. */

/* ---------- the shared header bar ---------- */

/* Full-bleed: the rule under the bar spans the viewport even though the
   row inside it is aligned to the same page the content uses. A bar that
   stopped at 1180px would read as a card, and the site has no cards that
   size. */
.sitehdr {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.sitehdr-row {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 var(--gutter);
  min-height: 48px;
  display: flex;
  align-items: center;
  gap: 16px;
}
.sitehdr-home {
  display: flex;
  align-items: center;
  border: 0;
  color: var(--ink-hi);
  flex: none;
}
.sitehdr-mark { display: block; height: 16px; width: auto; fill: currentColor; }

/* Hovering the mark runs the landing page's glitch rather than tinting
   the link green. It is the same fault the animated lockup draws, cut
   down to what survives at 16px, and it is CSS because the header pulls
   no asset and runs no script -- the lockup's engine is five modules and
   a generated glyph atlas, which is not a thing to load on six reference
   pages for an ornament this size. So the effect is restated in the one
   language the bar already speaks.

   The drop-shadow pair is the channel split, not a shadow: zero blur,
   hard offset, --r trailing the centre and --b leading it, which is the
   order stage.js composites them in. site.css's no-shadow rule is about
   soft UI depth, and this is the opposite of that.

   The offsets are retuned rather than scaled. PARAMS states the hero's
   in logo units against a 1055-wide box; at the 132px this mark is wide
   they all land under a pixel, and a split you cannot see is not one.

   The hero's drop param dims individual displaced slices, which one
   element
   cannot do -- dimming the whole mark instead just fades it to grey and
   reads as a transition, not a fault. So it is spent as a single
   frame of near-blackout at 12% and the rest of the burst stays at full
   white, where the split has something to separate from.

   steps(1, end) is what makes it read as digital: every stop holds until
   the next instead of easing into it. The burst fills the first quarter
   and the rest of the cycle is still, so holding the pointer gives an
   intermittent fault at roughly the lockup's own cadence rather than a
   continuous shake. */
.sitehdr-home:hover .sitehdr-mark {
  animation:
    sitehdr-tear 1.6s steps(1, end) infinite,
    sitehdr-split 1.6s steps(1, end) infinite;
}
@keyframes sitehdr-tear {
  0%   { transform: none; opacity: 1; }
  3%   { transform: translate3d(-3px, 1px, 0); opacity: 1; }
  6%   { transform: translate3d(2px, -1px, 0); opacity: 1; }
  9%   { transform: translate3d(-1px, 0, 0); opacity: 1; }
  12%  { transform: none; opacity: 0.2; }
  15%  { transform: translate3d(3px, 1px, 0); opacity: 1; }
  18%  { transform: translate3d(-2px, 0, 0); opacity: 1; }
  21%  { transform: translate3d(1px, -1px, 0); opacity: 1; }
  24%  { transform: translate3d(-1px, 0, 0); opacity: 1; }
  26%  { transform: none; opacity: 1; }
  100% { transform: none; opacity: 1; }
}
@keyframes sitehdr-split {
  0%   { filter: none; }
  3%   { filter: drop-shadow(-2px 0 0 var(--r)) drop-shadow(2px 0 0 var(--b)); }
  6%   { filter: drop-shadow(1px 0 0 var(--r)) drop-shadow(-1px 0 0 var(--b)); }
  9%   { filter: drop-shadow(-1px 0 0 var(--r)) drop-shadow(1px 0 0 var(--b)); }
  12%  { filter: none; }
  15%  { filter: drop-shadow(-3px 0 0 var(--r)) drop-shadow(3px 0 0 var(--b)); }
  18%  { filter: drop-shadow(1px 1px 0 var(--r)) drop-shadow(-1px -1px 0 var(--b)); }
  21%  { filter: drop-shadow(-1px 0 0 var(--r)) drop-shadow(1px 0 0 var(--b)); }
  24%  { filter: none; }
  26%  { filter: none; }
  100% { filter: none; }
}

/* Where motion is unwelcome the old rule is the fallback, not nothing:
   the link still has to answer the pointer. */
@media (prefers-reduced-motion: reduce) {
  .sitehdr-home:hover .sitehdr-mark { animation: none; }
  .sitehdr-home:hover { color: var(--accent); }
}
.sitehdr-gh { display: block; width: 15px; height: 15px; fill: currentColor; }

/* The mark already spells the name, so the crumb opens on its separator
   rather than repeating it. */
.sitehdr-crumb {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  font: 400 12px/1 var(--mono);
  letter-spacing: 0.06em;
  color: var(--faint);
  white-space: nowrap;
  overflow: hidden;
}
.sitehdr-crumb .sep { color: var(--line-hi); }
.sitehdr-crumb [aria-current="page"] { color: var(--muted); }

/* The section row and the rail are one navigation in two sizes, and the
   rule is: the row shows wherever the rail does not. That is two cases,
   not one. Below the two-column threshold the rail is display:none on
   every page. Above it, the gallery still has no rail — its tile grid
   wants the full width — and without this it would be a page you can
   reach and not leave, which is what a bare crumb and a GitHub icon add
   up to. Hence :has(.rail) rather than a width alone.

   It scrolls rather than wraps: a bar that grew to three rows would push
   the article off the first screen on a phone. */
.sitehdr-sections {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-left: auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  font: 400 12.5px/1 var(--mono);
  white-space: nowrap;
}
.sitehdr-sections::-webkit-scrollbar { display: none; }
.sitehdr-sections a { border: 0; color: var(--muted); }
.sitehdr-sections a:hover { color: var(--accent); }
.sitehdr-sections a.here { color: var(--ink-hi); font-weight: 600; }

/* Where the rail is present and visible, it is the index and the row is
   redundant. */
@media (min-width: 861px) {
  body:has(.rail) .sitehdr-sections { display: none; }
}

@media (max-width: 860px) {
  /* The section row already names the section, and the version and the
     npm link are not what a reader follows from a phone. */
  .sitehdr-crumb { display: none; }
  .sitehdr-ver { display: none; }
  .sitehdr-meta a[href*="npmjs"] { display: none; }
}

.sitehdr-meta {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 16px;
  flex: none;
  font: 400 13px/1 var(--mono);
}
.sitehdr-ver { color: var(--faint); font-variant-numeric: tabular-nums; }
.sitehdr-meta a { border: 0; color: var(--muted); display: flex; align-items: center; }
.sitehdr-meta a:hover { color: var(--accent); }

/* ---------- the shell: rail beside article ---------- */

.shell {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.shell > main { min-width: 0; padding-top: 30px; }

@media (min-width: 861px) {
  .shell {
    display: grid;
    grid-template-columns: 228px minmax(0, 1fr);
    gap: 44px;
    align-items: start;
  }
}

/* ---------- the site index ---------- */

.rail {
  padding-top: 30px;
  font-family: var(--mono);
}
/* Below the two-column threshold the rail is removed rather than stacked:
   a 30-item index unstacked above the article is a page of navigation
   before a word of prose. The header bar is what carries the reader
   there instead. */
@media (max-width: 860px) { .rail { display: none; } }
@media (min-width: 861px) {
  .rail {
    position: sticky;
    top: 64px;
    max-height: calc(100vh - 80px);
    overflow-y: auto;
    padding-bottom: 24px;
  }
}
.rail-grp { margin-bottom: 22px; }
.rail-grp:last-child { margin-bottom: 0; }
.rail-lbl {
  margin: 0 0 10px;
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
}
.rail ul { list-style: none; margin: 0; padding: 0; }
.rail li a {
  display: block;
  border: 0;
  padding: 4px 0;
  font: 400 13px/1.45 var(--mono);
  color: var(--muted);
}
.rail li a:hover { color: var(--ink-hi); }

/* The green bullet is the only hue in the rail, and it marks a position
   rather than a link — hence a marker glyph, not a colour on the text. */
.rail li a.here { color: var(--ink-hi); }
.rail li a.here::before { content: "\2022\00a0"; color: var(--accent); }

/* Five of the reference documents are markdown with no HTML page. The
   badge says so on the way out rather than after the click. */
.rail .md {
  margin-left: 7px;
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  vertical-align: 1px;
}
.rail li a:hover .md { color: var(--muted); }

.rail-toc li a { color: var(--faint); }

/* A sticky bar means an in-page anchor would otherwise land under it. */
:target { scroll-margin-top: 64px; }

/* The footer is outside the shell, so it keeps site.css's 960px .wrap
   while the header and the article are on the 1180px page. That is a
   110px inset per side under a full-width hairline that lines up with
   the header's — which reads as a mistake rather than as a narrower
   band. Put it on the same page as everything above it. */
body:has(.shell) footer .wrap { max-width: 1180px; }

/* ---------- skip link ---------- */

/* The rail puts 19-36 links between the top of the page and the first
   word of it. Without this, reaching the article by keyboard means
   tabbing through the whole site index on every page. */
.skip-to-main {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 30;
  border: 0;
}
.skip-to-main:focus {
  left: var(--gutter);
  top: 8px;
  padding: 8px 12px;
  background: var(--accent);
  color: #000;
  font: 600 12px/1 var(--mono);
  letter-spacing: 0.06em;
}

/* ---------- the dev grid overlay ---------- */

/* site.css draws the overlay's twelve tracks inside .wrap, which is 960px.
   A chrome page's article lives in the 1180px shell instead, so the ruler
   was measuring a column that is no longer there — and a ruler that is
   wrong is worse than no ruler. Re-key it onto the shell.

   What it still does NOT show: the rail's 228px and the 44px gap are part
   of the shell's width but hold no track, so tracks 1-2 fall behind the
   rail. Deciding whether the page grid should start at the article rather
   than at the shell is a site.css question, and it is deliberately not
   answered here. Dev-only either way: the overlay needs a "show-grid" class on
   <html>, which the g key sets. */
body:has(.shell) .grid-guide .wrap { max-width: 1180px; }
