/* ==========================================================================
   Chrome — the surfaces a reader reaches for before they reach the content.

   The skip link, the top bar, the theme toggle, the settings toggle, the
   settings dialog, the segmented groups inside it, the switches, and the
   pinned footer they all sit on.

   Loaded LAST, after styles.css, guide.css, llm-guide.css and theme.css. That
   order is not a preference: the two legacy guide stylesheets are hand-written
   and the shared one still sets `body { margin-left: var(--nav-w) }` and
   `#site-nav { position: fixed; inset: 0 auto 0 0 }` for a left sidebar that
   no longer exists, and this file is the one allowed to say so. Every rule
   that has to beat one of those carries `#site-nav` so it wins on specificity
   rather than on source order, because on the 16 LLM pages guide.css is linked
   AFTER this file and would otherwise take the last word.

   EVERY VALUE BELOW IS A TOKEN. No raw hex, no bare `rem` used as a spacing
   step, no bare `ms`. The values that are not spacing tokens are structural —
   a control box, a hairline, a thumb — and each is named in section 1 with the
   reason it is not on the scale.

   NO `backdrop-filter` APPEARS IN THIS FILE, and that is the point rather than
   an oversight. The previous design ran a liquid-glass blur through the nav,
   the cards and the buttons; the token layer has already re-pointed every
   `--glass-*` name at a flat plate, and the chrome that would have wanted a
   blur is the chrome that has a number sitting under it. A blur under a value
   makes the value harder to read, which is the one thing an instrument panel
   must not do.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Chrome-local geometry

   Not site tokens, and deliberately not in theme.css: they describe THIS bar
   and THIS dialog, and a reader who never opens the settings panel should not
   be able to move them.

   They are rem, so they scale with the text-size preference — a px height is
   short by a fifth at 130% text — and they are NOT multiplied by
   `--pref-space`, so the Compact density preference cannot shrink the box a
   finger has to find. That asymmetry is the same one theme.css makes for
   `--space-*`, and it is the same reason.
   -------------------------------------------------------------------------- */
:root {
  /* The site bar. 52px at the default text size. */
  --chrome-nav-h: 3.25rem;
  /* The series ribbon. Deliberately the shortest thing on the site: it holds a
     pill row that never wraps, and a taller ribbon is a taller band pinned to
     the top of every screen. */
  --chrome-series-h: 2.375rem;
  /* The two bars together. theme.css parks a #fragment heading at
     `--read-anchor-offset` (7rem) and that offset is in rem for exactly this
     reason; 5.75rem of bar under a 7rem offset leaves the heading clear with
     room to spare at every text size. If you change --chrome-nav-h or
     --chrome-series-h, this is the number to change with it. */
  --chrome-bars-h: 5.75rem;
  /* A control a finger has to find. 36px clears WCAG 2.5.8, and section 3
     buys the rest of the reach without the drawn box growing. */
  --chrome-control: 2.25rem;
  --chrome-control-sm: 1.75rem;
  --chrome-prefs-w: 26rem;
}

/* --------------------------------------------------------------------------
   2. Focus, and the one control that only exists with JavaScript

   `:where()` holds this at specificity 0, so it is a floor and never an
   override: the per-component rings further down still win. styles.css owns
   the site's global focus ring today; this is the same recipe as a belt to
   braces on, because the controls in this file are the ones a keyboard reader
   is most likely to be on when a stylesheet is mid-rewrite, and a missing
   outline is not a cosmetic regression.
   -------------------------------------------------------------------------- */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}

/* The theme toggle, the settings toggle and the footer's settings button all
   open or edit something that only exists once assets/js/preferences.js has
   run. They are hidden by DEFAULT rather than shown and then repaired, so a
   reader whose JavaScript never runs is not handed three buttons that do
   nothing — and preferences.js adds `.ic-js` in a few milliseconds, which is
   what brings them back. theme.css's own `prefers-color-scheme` block is what
   decides the mode for that reader, so they lose nothing but the ability to
   change a preference they have not expressed. */
.nav-icon-btn,
.site-footer-prefs-btn {
  display: none;
}

.ic-js .nav-icon-btn { display: inline-flex; }
.ic-js .site-footer-prefs-btn { display: inline-flex; }

/* --------------------------------------------------------------------------
   3. The skip link

   The first focusable thing on the page, and invisible until it is focused.
   The offset that hides it and the padding that sizes it are ONE relationship:
   `translateY(-250%)` is computed against the link's own box, so changing the
   padding would leave a sliver of it on screen.

   `position: fixed` rather than absolute, and the z-index above both bars: it
   is the one element here that must not move, and it is most often needed by
   a reader who has just arrived on a page with the bar pinned over the top of
   it.
   -------------------------------------------------------------------------- */
.skip-link {
  position: fixed;
  left: var(--space-3);
  top: var(--space-3);
  z-index: 600;
  transform: translateY(-250%);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  background-color: var(--c-fg);
  color: var(--c-bg);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: var(--text-sm-lh);
  text-decoration: none;
  box-shadow: var(--shadow-3);
  transition: transform var(--dur-base) ease;
  -webkit-tap-highlight-color: transparent;
}

.skip-link:focus {
  transform: translateY(0);
  text-decoration: none;
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}

.skip-link:active {
  background-color: var(--c-fg-muted);
}

/* --------------------------------------------------------------------------
   4. Reach without size

   A 44x44 target and a 36x36 control are two different designs, and the bar
   holds three controls in a 0.5rem row. The third option is that the box a
   reader sees and the box a finger gets do not have to be the same size: a
   transparent pseudo-element centred on the control, sized `max(100%, 44px)`
   on both axes. It paints nothing, it is not in the accessibility tree, and a
   pointer event on it is delivered to the element that generated it — so the
   drawn control, its border and every neighbour's position are unchanged.

   `:where()` on the positioning declaration holds specificity at 0, so an
   element that is already positioned keeps its own position; `max(100%, …)`
   leaves a control that is already 44px alone, so applying this to a row of
   mixed sizes cannot stack two pseudo-elements on one element. The same care
   is why this is NOT on the skip link: it is `position: fixed` and full width,
   and a `position: relative` demotion would put it back in the flow.
   -------------------------------------------------------------------------- */
:where(.chrome-hit-44, .hit-44) {
  position: relative;
}

:where(.chrome-hit-44, .hit-44)::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/* --------------------------------------------------------------------------
   5. The site bar

   A sticky plate: opaque, one hairline along the bottom, no blur. The z-index
   is one step above the series ribbon, so the ribbon slides UNDER the bar when
   the two overlap — which is what makes `top: var(--chrome-nav-h)` on the
   ribbon a real relationship rather than a decorative number.
   -------------------------------------------------------------------------- */
body {
  /* The left-sidebar reservation, neutralised. styles.css USED to set
     `margin-left: var(--nav-w)` for the fixed 220px sidebar this bar replaced,
     and `html.nav-collapsed body { margin-left: 0 }` above it at (0,1,1); with
     the bar across the top there is nothing left to reserve, and leaving
     either in place indents the whole site by 220px for a bar 52px tall.

     Both the plain and the `html.`-prefixed forms are written out, because
     (0,0,1) does not out-rank (0,1,1). styles.css no longer declares the
     offset at all, so these are currently belt on braces — kept rather than
     deleted because a `--nav-w` declaration reappearing in styles.css is
     exactly the edit that would silently re-indent every page, and these two
     rules are the ones that would stop it. */
  margin-left: 0;
}

html.nav-collapsed body,
html.nav-open body {
  margin-left: 0;
}

#site-nav {
  position: sticky;
  inset: auto;
  top: 0;
  z-index: 400;
  width: auto;
  height: var(--chrome-nav-h);
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-4);
  margin: 0;
  padding: 0 var(--space-5);
  overflow: visible;
  background: var(--c-surface);
  border-right: none;
  border-bottom: 1px solid var(--c-border);
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  transition: none;
  font-family: var(--font-body);
  font-size: var(--text-sm);
}

.nav-head {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
}

.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-weight: var(--font-heading-weight);
  font-size: var(--text-base);
  line-height: var(--text-base-lh);
  letter-spacing: -0.01em;
  color: var(--c-fg);
  text-decoration: none;
  white-space: nowrap;
}

/* "AI · Vision · Math". Decorative, and the first thing to go when the bar
   runs out of room: at 130% text it is a fifth of the width the six links
   need. It is a `title` on the bar rather than visible text on a phone, and
   it disappears entirely below 1440px rather than being the thing that pushes
   `About` off the end. */
.nav-brand-sub {
  color: var(--c-fg-subtle);
  font-size: var(--text-label-sm);
  font-weight: 400;
  letter-spacing: 0;
}

@media (max-width: 1439px) {
  .nav-brand-sub { display: none; }
}

.nav-brand-dot {
  width: var(--space-2);
  height: var(--space-2);
  border-radius: var(--radius-pill);
  flex: 0 0 auto;
  background: var(--c-accent);
  /* A colour-mix rather than a second literal, so the ring cannot drift from
     the accent it is announcing. */
  box-shadow: 0 0 0 var(--space-1) rgb(var(--c-accent-ch) / 0.16);
}

/* ---- the primary links -------------------------------------------------- */

/* A scroller rather than a clipper, and that distinction is the whole reason
   this row is not `overflow: hidden`. At 130% text the six links need more
   width than a 1200px viewport gives them, and a link clipped by an overflow
   is a link a reader cannot know exists. Scrolling is the honest failure: it
   costs a horizontal gesture in a band that has nothing else to scroll. */
.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.nav-links::-webkit-scrollbar {
  display: none;
}

#site-nav .nav-links a {
  flex: 0 0 auto;
  padding: var(--space-tight) var(--space-2);
  border-radius: var(--radius-control);
  color: var(--c-fg-muted);
  font-size: var(--text-label-sm);
  line-height: var(--text-label-sm-lh);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
}

#site-nav .nav-links a:hover {
  background: var(--c-surface-2);
  color: var(--c-fg);
}

#site-nav .nav-links a[aria-current='page'] {
  background: rgb(var(--c-accent-ch) / 0.1);
  color: var(--c-accent-ink);
  font-weight: 600;
}

/* Collapse. `nav-collapsed` means "the links are out of the way", which on a
   bar is hiding them rather than shrinking a rail — and the control that brings
   them back is the one the reader just used, so the state reveals itself. The
   localStorage key and the aria semantics are unchanged from the sidebar. */
html.nav-collapsed #site-nav .nav-links {
  display: none;
}

/* ---- the reading controls ----------------------------------------------- */

.nav-controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
  margin-left: auto;
}

.nav-icon-btn {
  align-items: center;
  justify-content: center;
  width: var(--chrome-control);
  height: var(--chrome-control);
  padding: 0;
  color: var(--c-fg-muted);
  background: var(--c-surface-2);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: background-color var(--dur-fast) ease,
              border-color var(--dur-fast) ease,
              color var(--dur-fast) ease;
  -webkit-tap-highlight-color: transparent;
}

.nav-icon-btn:hover {
  color: var(--c-fg);
  border-color: var(--c-border-strong);
}

.nav-icon-btn:active {
  background: var(--c-surface);
}

/* `aria-expanded` IS this control's selected state — the panel is open — so the
   fill says so. The accent is not used for it: a full-strength `--c-fg` over
   `--c-surface-2` is what an open control looks like everywhere else on the
   site. */
#ic-prefs-toggle[aria-expanded='true'] {
  color: var(--c-fg);
  border-color: var(--c-border-strong);
}

.nav-icon {
  display: block;
  flex: 0 0 auto;
}

/* The theme toggle shows the PREFERENCE, not the mode in force, so a reader who
   chose System can see that they have: a moon here would claim an explicit
   choice they did not make. `data-pref-theme` is written by the boot script
   before first paint and again by preferences.js. */
.nav-icon--light,
.nav-icon--dark,
.nav-icon--system {
  display: none;
}

html[data-pref-theme='light'] .nav-icon--light,
html[data-pref-theme='dark'] .nav-icon--dark,
html[data-pref-theme='system'] .nav-icon--system {
  display: block;
}

/* ---- the two bar buttons, and the drawer below 1000px --------------------- */

/* 1000px, not 860px, and the reason is the text-size preference rather than
   the screen. At 130% text the six primary links need about 690px once their
   padding is trimmed; with the brand and the two reading controls the bar
   needs a shade under 1000px to hold them on one line. Below that the links
   become a drawer, which is a better failure than a scrollable strip. */

.nav-collapse-toggle,
.nav-mobile-toggle {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  width: var(--chrome-control-sm);
  height: var(--chrome-control-sm);
  padding: 0;
  margin: 0;
  color: var(--c-fg-muted);
  background: transparent;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
  -webkit-tap-highlight-color: transparent;
}

.nav-collapse-toggle:hover,
.nav-mobile-toggle:hover {
  background: var(--c-surface-2);
  color: var(--c-fg);
}

/* The collapse control and the mobile hamburger are the same three bars, so
   they read as the same control. Only one of the two is ever shown. */
.nav-collapse-toggle .nav-mobile-toggle-bar,
.nav-mobile-toggle .nav-mobile-toggle-bar {
  width: var(--space-4);
  height: 1px;
  margin: 0;
  background: currentColor;
  border-radius: 0;
}

.nav-scrim {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 380;
  background: var(--c-scrim);
}

@media (min-width: 1001px) {
  .nav-collapse-toggle { display: flex; }
  .nav-mobile-toggle { display: none !important; }
}

@media (max-width: 1000px) {
  /* styles.css reserves body padding for a floating hamburger that used to sit
     over a page with no sidebar. The bar is in the flow now, so that
     reservation is a gap at the top of every narrow page. Same specificity as
     the rule it cancels and later in the cascade, which is why it has to be
     written out at all rather than left to `body { margin: 0 }`. */
  body { padding-top: 0; }

  /* The hamburger is a sibling of the bar, not a child of it, so it is
     `fixed` and vertically centred on the bar's height; the bar's own
     left padding reserves exactly the space it occupies, which is why the
     two numbers are the same expression. */
  .nav-mobile-toggle {
    display: flex;
    position: fixed;
    z-index: 410;
    top: calc((var(--chrome-nav-h) - var(--chrome-control-sm)) / 2);
    left: var(--space-3);
  }

  #site-nav {
    padding-left: calc(var(--space-3) + var(--chrome-control-sm) + var(--space-2));
    padding-right: var(--space-3);
  }

  html.nav-open .nav-scrim {
    display: block;
  }

  /* `hidden` is what the script actually toggles, and the UA rule for it is
     weaker than the rule above, so the two are reconciled explicitly. */
  html.nav-open .nav-scrim[hidden] {
    display: none;
  }

  /* The links drop to a panel that opens UNDER the bar. The bar is
     `position: sticky`, which also makes it the containing block for this
     absolute child — that is why the offset is measured from
     `--chrome-nav-h` and not from the viewport. */
  #site-nav .nav-links,
  html.nav-collapsed #site-nav .nav-links {
    display: none;
    position: absolute;
    top: var(--chrome-nav-h);
    left: 0;
    right: 0;
    z-index: 390;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-2) var(--space-3) var(--space-3);
    background: var(--c-surface-raised);
    border-bottom: 1px solid var(--c-border);
    box-shadow: var(--shadow-2), var(--elev-inset);
    overflow: visible;
  }

  html.nav-open #site-nav .nav-links {
    display: flex;
  }

  #site-nav .nav-links a {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-base);
  }

  .nav-collapse-toggle { display: none; }
}

/* --------------------------------------------------------------------------
   6. The series ribbon

   The second bar, parked directly under the site one. `nowrap` with a
   horizontal scroller rather than a wrapping row is a deliberate choice, not a
   default: a 20-part series wrapped to two rows is a 5rem band pinned to the
   top of every screen, which would eat the offset the whole design budgeted
   for the two bars and force `--read-anchor-offset` to grow.
   -------------------------------------------------------------------------- */
.nav--series {
  position: sticky;
  top: var(--chrome-nav-h);
  z-index: 300;
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: var(--space-1);
  min-height: var(--chrome-series-h);
  margin: 0;
  padding: 0 var(--space-5);
  background: var(--c-surface);
  border-bottom: 1px solid var(--c-border);
  font-family: var(--font-body);
  font-size: var(--text-label-sm);
  line-height: var(--text-label-sm-lh);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
}

.nav--series a {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  background: var(--c-surface-2);
  color: var(--c-fg-muted);
  font-size: var(--text-label-sm);
  line-height: var(--text-label-sm-lh);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
}

.nav--series a:hover {
  background: var(--c-surface);
  color: var(--c-fg);
}

.nav--series a[aria-current='page'] {
  background: rgb(var(--c-accent-ch) / 0.1);
  border-color: rgb(var(--c-accent-ch) / 0.35);
  color: var(--c-accent-ink);
  font-weight: 600;
}

.nav--series-home {
  color: var(--c-fg) !important;
  font-weight: 600;
}

.nav--series-title { display: none; }
.nav--series-group { display: contents; }

.nav--series-act {
  display: inline-flex;
  align-items: center;
  align-self: center;
  flex: 0 0 auto;
  margin: 0 var(--space-2) 0 var(--space-4);
  color: var(--c-fg-subtle);
  font-size: var(--text-micro);
  line-height: var(--text-micro-lh);
  letter-spacing: var(--text-micro-ls);
  text-transform: uppercase;
  white-space: nowrap;
}

/* On a narrow screen the ribbon is hidden outright and the part list reappears
   as a vertical run inside the drawer above. Twenty horizontally-scrolling
   pills is a poor way to browse a series on a phone, and the drawer is already
   a vertical list — the same reason the script in series-nav.html used to move
   the list into the sidebar. */
@media (max-width: 1000px) {
  .nav--series { display: none; }
}

/* --------------------------------------------------------------------------
   7. Anchors

   `--read-anchor-offset` is the offset theme.css parks a `#fragment` heading
   at, and both bars above are sized to stay inside it. `scroll-padding` is the
   property that actually does the parking for a reader following a table of
   contents or a skip link; the `scroll-padding-top: 64px` in styles.css is a
   px guess at the same thing and is a fifth short at 130% text.
   -------------------------------------------------------------------------- */
html {
  scroll-padding-top: var(--read-anchor-offset, 7rem);
}

/* --------------------------------------------------------------------------
   8. The settings dialog

   The one surface on the site that sits above everything else, so it is the
   one honest user of `--shadow-4`, the modal step of the elevation scale. It
   is tall enough to be usable at every text size and it scrolls internally
   with the head and the foot pinned: a preference list that pushes its own
   Reset button off the bottom of a phone is not a control surface.
   -------------------------------------------------------------------------- */
.prefs {
  width: min(var(--chrome-prefs-w), calc(100vw - var(--space-8)));
  max-width: none;
  /* The `vh` line is the fallback and the `dvh` line is the truth: a `vh` box
     on a phone with the URL bar showing is taller than the screen is. */
  max-height: calc(100vh - var(--space-16));
  max-height: calc(100dvh - var(--space-16));
  padding: 0;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-plate);
  background: var(--c-surface-raised);
  color: var(--c-fg);
  font-family: var(--font-body);
  overflow: hidden;
  /* The modal step, composed the way every other raised surface is: the
     elevation and the lit top edge are two separate custom properties
     combined in ONE box-shadow, so a future state change here cannot drop the
     edge the way a bare `var(--c-elev-4)` would. See theme.css section 13.

     This was previously absent altogether, which is why the one surface that
     sits above everything else — above a scrim, above a drawer, above the
     sticky header — rendered flat and read as a hole rather than a dialog. */
  --elev-shadow: var(--c-elev-4);
  --elev-inset: inset 0 1px 0 var(--c-elev-inset-hi);
  box-shadow: var(--elev-shadow), var(--elev-inset);
  animation: chrome-prefs-in var(--dur-fast) ease-out;
}

/* The UA default for a modal dialog is `inset: 0; margin: auto`, which centres
   it; the explicit pair is here so the centering does not depend on the UA
   stylesheet staying that way. */
.prefs[open] {
  inset: 0;
  margin: auto;
}

/* `--c-scrim` is already the ink at the alpha the active mode wants: 0.5 in
   light, 0.62 in dark, because a near-black canvas has almost no luminance to
   push the page under with. */
.prefs::backdrop {
  background: var(--c-scrim);
}

/* The dialog takes focus programmatically on open so focus lands inside it,
   and it is not in the tab ring. The global `:focus-visible` rule would still
   paint a two-pixel azure frame around the whole dialog, which reads like a
   selection error; the ring the reader actually needs appears on the first
   control they reach. */
.prefs:focus,
.prefs:focus-visible {
  outline: none;
}

@keyframes chrome-prefs-in {
  from { opacity: 0; transform: translateY(calc(-1 * var(--space-1))); }
  to   { opacity: 1; transform: translateY(0); }
}

.prefs__sheet {
  display: flex;
  flex-direction: column;
  max-height: inherit;
  min-height: 0;
  border-radius: inherit;
  overflow: hidden;
}

.prefs__head,
.prefs__foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--c-surface-raised);
}

.prefs__head {
  border-bottom: 1px solid var(--c-border);
}

.prefs__foot {
  border-top: 1px solid var(--c-border);
}

.prefs__head-icon {
  display: inline-flex;
  flex: 0 0 auto;
  color: var(--c-fg-subtle);
}

.prefs__title {
  margin: 0;
  color: var(--c-fg);
  font-family: var(--font-body);
  font-size: var(--text-label-sm);
  font-weight: 600;
  line-height: var(--text-label-sm-lh);
}

.prefs__close {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--chrome-control-sm);
  height: var(--chrome-control-sm);
  padding: 0;
  color: var(--c-fg-muted);
  background: transparent;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
  -webkit-tap-highlight-color: transparent;
}

.prefs__close:hover {
  background: var(--c-surface-2);
  color: var(--c-fg);
}

.prefs__body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* ---- one group ---------------------------------------------------------- */

/* `display: block` on the fieldset, not `flex`: a `<legend>` is not a flex
   item in any browser that follows the HTML rendering rules, and making the
   fieldset a flex container drops the legend out of the flow entirely. The
   group still lays out as a column, because each child is a block with its own
   top margin and the fieldset's height is the sum of them. */
.prefs__group {
  display: block;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: none;
}

/* The legend is the group's real, native label and the first thing a screen
   reader reads. It is a flex container of its own so the live readout can sit
   at the right of the label row — which is what makes the segmented control
   below it reversible in the reader's head — and `width: 100%` because a
   legend shrink-wraps inside a block fieldset otherwise. */
.prefs__label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: 0;
  color: var(--c-fg);
  font-size: var(--text-label-sm);
  font-weight: 600;
  line-height: var(--text-label-sm-lh);
}

.prefs__label--row {
  justify-content: flex-start;
}

.prefs__readout {
  flex: 0 0 auto;
  color: var(--c-fg-subtle);
  font-size: var(--text-micro);
  font-weight: 600;
  line-height: var(--text-micro-lh);
  font-variant-numeric: tabular-nums;
}

.prefs__desc {
  margin: var(--space-1) 0 0;
  color: var(--c-fg-muted);
  font-size: var(--text-sm);
  line-height: var(--text-sm-lh);
}

.prefs__note {
  margin: var(--space-2) 0 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  background: var(--c-surface-2);
  color: var(--c-fg-muted);
  font-size: var(--text-sm);
  line-height: var(--text-sm-lh);
}

.prefs__note strong { color: var(--c-fg); }

/* ---- the segmented control ---------------------------------------------- */

/* The row's flex children are the CLIPPED inputs and their labels, in pairs.
   The inputs are `position: absolute` at 1px rather than `display: none`,
   because a `display: none` input is removed from the accessibility tree
   entirely and a radio group a screen reader cannot walk is not a radio group. */
.prefs__segment {
  display: flex;
  align-items: stretch;
  gap: var(--space-1);
  margin-top: var(--space-2);
}

.prefs__radio,
.prefs__check {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.prefs__cell {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1 1 0;
  min-width: 0;
  padding: var(--space-2) var(--space-1);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  background: var(--c-surface);
  color: var(--c-fg-muted);
  font-size: var(--text-label-sm);
  font-weight: 500;
  line-height: var(--text-label-sm-lh);
  text-align: center;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--dur-fast) ease,
              border-color var(--dur-fast) ease,
              color var(--dur-fast) ease;
  -webkit-tap-highlight-color: transparent;
}

.prefs__cell:hover {
  background: var(--c-surface-2);
  color: var(--c-fg);
}

/* The press state moves the BORDER on a selected cell and the FILL on an
   unselected one. There is no "darker than selected" fill to reach for, and
   inventing one would make a press look like a selection. */
.prefs__cell:active {
  background: var(--c-surface-2);
}

.prefs__radio:checked + .prefs__cell {
  background: rgb(var(--c-accent-ch) / 0.1);
  border-color: rgb(var(--c-accent-ch) / 0.45);
  color: var(--c-accent-ink);
  font-weight: 600;
}

.prefs__radio:checked + .prefs__cell:active {
  border-color: var(--c-fg-subtle);
}

/* A 1px-clipped input has nowhere to draw a focus ring, so the ring is moved
   onto the label. `:focus-visible` rather than `:focus`, so a pointer press
   does not leave a frame behind on a control the reader has just answered. */
.prefs__radio:focus-visible + .prefs__cell,
.prefs__check:focus-visible + .prefs__switch-track {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}

/* ---- the switches ------------------------------------------------------- */

.prefs__switches {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--c-border);
}

/* The whole row is the label, so the description is part of the hit area. The
   negative margin and equal padding keep the row's own box the size of its
   content while still giving the pointer a larger target. */
.prefs__switch {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin: calc(-1 * var(--space-1));
  padding: var(--space-1);
  border-radius: var(--radius-control);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.prefs__switch:active {
  opacity: 0.8;
}

.prefs__switch-track {
  position: relative;
  flex: 0 0 auto;
  width: var(--space-8);
  height: var(--space-5);
  margin-top: var(--space-hair);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-pill);
  background: var(--c-surface-2);
  transition: background-color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.prefs__switch:hover .prefs__switch-track {
  border-color: var(--c-fg-subtle);
}

/* The thumb is sized off the track, and its travel is the difference between
   the two — written as a subtraction rather than a bare `50%` so it stays
   correct if the track's height changes. */
.prefs__switch-thumb {
  position: absolute;
  top: 1px;
  left: 1px;
  width: calc(var(--space-5) - 2px);
  height: calc(var(--space-5) - 2px);
  border-radius: var(--radius-pill);
  background: var(--c-fg-muted);
  transition: transform var(--dur-fast) ease, background-color var(--dur-fast) ease;
}

.prefs__check:checked + .prefs__switch-track {
  background: var(--c-accent);
  border-color: var(--c-accent);
}

.prefs__check:checked + .prefs__switch-track .prefs__switch-thumb {
  background: var(--c-accent-fg);
  transform: translateX(var(--space-3));
}

.prefs__switch-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-hair);
  min-width: 0;
}

/* ---- the footer --------------------------------------------------------- */

.prefs__count {
  margin: 0;
  color: var(--c-fg-subtle);
  font-size: var(--text-micro);
  line-height: var(--text-micro-lh);
  letter-spacing: var(--text-micro-ls);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.prefs__reset {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--c-fg);
  font-family: var(--font-body);
  font-size: var(--text-label-sm);
  font-weight: 600;
  line-height: var(--text-label-sm-lh);
  cursor: pointer;
  transition: background-color var(--dur-fast) ease;
  -webkit-tap-highlight-color: transparent;
}

.prefs__reset:hover:not(:disabled) {
  background: var(--c-surface-2);
}

/* A disabled control must not answer the pointer. The `:hover` reset is the
   part that matters: without it a disabled button still reacts. */
.prefs__reset:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.prefs__reset:disabled:hover {
  background: transparent;
}

/* --------------------------------------------------------------------------
   9. The footer's settings entry point

   The same dialog, reached from the end of the page. See
   _includes/guide-footer.html for why there is a second way in and why it is
   not a second settings surface.
   -------------------------------------------------------------------------- */
.site-footer-prefs {
  margin: var(--space-4) 0 0;
}

.site-footer-prefs-btn {
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--c-fg-muted);
  font-family: var(--font-body);
  font-size: var(--text-label-sm);
  line-height: var(--text-label-sm-lh);
  cursor: pointer;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
  -webkit-tap-highlight-color: transparent;
}

.site-footer-prefs-btn:hover {
  background: var(--c-surface-2);
  color: var(--c-fg);
}

/* --------------------------------------------------------------------------
   10. Focus mode, applied to the chrome

   theme.css owns the mechanism — `.focus-dim` dims to 40% and restores on
   hover or `:focus-within` — but the chrome needs its own reading of it. The
   bar and the ribbon recede rather than disappear, because a reader who has
   just turned focus mode on because they lost their place needs the
   navigation to still be visibly there. 55%, not 40%: this is chrome the
   reader may have to reach for mid-sentence, and the one thing focus mode
   must never do is make a control hard to find.
   -------------------------------------------------------------------------- */
:root[data-focus-mode='on'] .nav-links,
:root[data-focus-mode='on'] .nav-controls,
:root[data-focus-mode='on'] .nav-collapse-toggle {
  opacity: 0.55;
  transition: opacity var(--dur-base) ease;
}

:root[data-focus-mode='on'] .nav-links:hover,
:root[data-focus-mode='on'] .nav-links:focus-within,
:root[data-focus-mode='on'] .nav-controls:hover,
:root[data-focus-mode='on'] .nav-controls:focus-within,
:root[data-focus-mode='on'] .nav-collapse-toggle:hover {
  opacity: 1;
}
