/* Purpose: the live stylesheet, design direction C, "Orientation". Its widths and breakpoint
   are arithmetic rather than taste: they are what lets an 80-column code line sit beside the
   contents list without scrolling. */
/* DIRECTION C: "Orientation"
 *
 * Theory: the reported failure modes of API documentation are dominated by incomplete
 * and ambiguous information and unexplained examples, and by fragmentation across
 * sources. Underneath all of those is one reader question the page never answers: am I
 * in the right place, and is the state I am in the state this page assumes?
 *
 * A reader who cannot answer that cannot tell a page that is wrong from a page that is
 * right about a situation they are not in -- and that ambiguity is what sends them to a
 * colleague instead. This direction promotes orientation to the top of the visual
 * hierarchy: where you are, what must already be true, and where you go next are
 * structural furniture rather than links buried in flow.
 */
/* Colors and type come from philhwagner.com. palette.css and fonts.css are its own files, copied
   in by sync-palette.mjs and linked ahead of this sheet, so the work samples wear the site's
   design in both themes. What stays here is what the portfolio has no word for, named in its
   terms so it follows the theme too. */
:root {
  --rail: var(--edge); --control-shape: 2px;
  --on-accent: var(--paper); --marker: var(--accent);
  --measure: 40rem; --code-width: 50rem; --toc-width: 10rem;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font: 16.5px/1.65 var(--sans, ui-sans-serif, system-ui, sans-serif);
}
/* Two columns: the contents list stays put while the page moves under it. The grid is the
   layout, not a decoration, so it degrades to one column rather than to a broken one. */
.page {
  display: grid; grid-template-columns: var(--toc-width) minmax(0, var(--code-width));
  gap: 0 1.75rem; max-width: calc(var(--toc-width) + var(--code-width) + 4rem);
  margin: 0 auto; padding: 0 1.5rem;
}
/* Main is as wide as code needs. Prose is held to the measure inside it, so a long line of
   code does not drag the reading column out with it. */
main { max-width: var(--code-width); padding: 0 0 6rem; min-width: 0; }
main > *:not(pre):not(figure):not(details):not(.faded):not(.families):not(.positions) {
  max-width: var(--measure);
}

/* The contents list. Sticky rather than fixed: it scrolls with the page until it reaches the
   top, then holds, which keeps it out of the way on a short page. */
.toc {
  position: sticky; top: 0; align-self: start; max-height: 100vh; overflow-y: auto;
  padding: 1.5rem 0 2rem; font-size: .82rem; line-height: 1.45;
}
.toc h2 {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .09em; color: var(--muted);
  margin: 0 0 .6rem; border: 0; padding: 0; font-weight: 700;
}
.toc-list { list-style: none; margin: 0; padding: 0; border-left: 2px solid var(--rule); }
.toc-list a { display: block; padding: .28rem .7rem; text-decoration: none; color: var(--muted); }
.toc-list a:hover, .toc-list a:focus { color: var(--marker); background: color-mix(in srgb, var(--marker) 6%, transparent); }
.toc-h1 > a { color: var(--ink); font-weight: 700; }
.toc-h2 > a { padding-left: 1.2rem; }
.toc-h3 > a { padding-left: 1.85rem; }
/* An icon inside a heading: sits on the text's baseline rather than the line box's. */
.heading-icon { vertical-align: -.1em; margin-right: .3em; }
.toc-list a .heading-icon { width: 12px; height: 12px; margin-right: .35em; }

/* 52rem, down from 64. The old number reserved enough width for an 80-character line at
   every width the sidebar appeared, and 80 is the authoring limit rather than a description
   of the content: the longest line on this site is 52 characters. Reserving the worst case
   everywhere bought 28 characters of width that nothing used, and paid for it by hiding the
   contents list from anybody with a window under 1024px, which is most laptops.

   So the guarantee is now tiered and stated rather than uniform and unexamined. From about
   1020px a full 80-character line still does not scroll. Between 832 and 1020 the sidebar is
   present and a line over roughly 64 characters would scroll, which no line here is, and
   `check_code_width` is what keeps that true. Below 832 the sidebar stacks. */
@media (max-width: 52rem) {
  .page { display: block; max-width: var(--code-width); }
  /* Above the content, collapsed by nothing: it is a short list and hiding it would need
     scripting, which the clean-state rule does not allow for something a reader navigates by. */
  .toc { position: static; max-height: none; border-bottom: 1px solid var(--rule); }
  main > * { max-width: 100%; }
}
header.site, footer.site {
  max-width: calc(var(--toc-width) + var(--code-width) + 4rem); margin: 0 auto; padding: 1.25rem 1.5rem; font-size: .875rem;
}
header.site { border-bottom: 1px solid var(--rule); }
footer.site { border-top: 1px solid var(--rule); margin-top: 4rem; color: var(--muted); }
a { color: var(--accent); }
/* The body is sans-serif, so a heading cannot rely on family to separate itself from the
   text. It has to earn the distinction with size and weight, and the first version did not:
   h2 sat at 1.15rem against 16.5px body, and h3 was the same size as a paragraph. */
h1, h2 { font-family: var(--disp, inherit); font-variation-settings: var(--disp-vf, normal); }
h1 {
  font-size: 2.15rem; line-height: 1.15; letter-spacing: -.022em;
  font-weight: 800; margin-bottom: .4rem;
}
h2 {
  font-size: 1.5rem; font-weight: 700; line-height: 1.25; margin-top: 3rem;
  padding-top: .7rem; border-top: 1px solid var(--rule); letter-spacing: -.012em;
}
h3 {
  font-size: 1.15rem; font-weight: 700; margin-top: 1.9rem; margin-bottom: .35rem;
  letter-spacing: -.005em; color: var(--ink);
}
h4 { font-size: 1rem; font-weight: 700; margin-top: 1.5rem; color: var(--muted); }
code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85em; }
pre { overflow-x: auto; padding: .85rem 1rem; background: color-mix(in srgb, var(--ink) 4%, transparent); border: 1px solid var(--rule); border-radius: 5px; }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: .5rem; top: .5rem; background: var(--paper); padding: .5rem; z-index: 10; }

/* Orientation strip: state before content. Where you are, how current it is, and
   whether anyone has checked -- read as one horizontal band rather than a footnote. */
.provenance {
  display: flex; flex-wrap: wrap; gap: .4rem 1rem; align-items: baseline;
  font-size: .95rem; color: var(--muted);
  border-top: 2px solid var(--marker); border-bottom: 1px solid var(--rule);
  padding: .55rem 0; margin: 0 0 2rem;
}
.state {
  font-weight: 700; text-transform: uppercase; letter-spacing: .06em; font-size: .68rem;
  color: var(--paper); background: var(--marker); padding: .15rem .45rem; border-radius: 3px;
}
.stale { color: #8a4a00; font-weight: 700; }
@media (prefers-color-scheme: dark) { .stale { color: #e8a95e; } }

/* Prerequisites become a preflight: things to confirm, numbered, before starting.
   Next steps become an onward path. Both are furniture, not prose. */
nav.prereq {
  font-size: .95rem;
  background: color-mix(in srgb, var(--marker) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--marker) 20%, transparent);
  border-radius: 6px; padding: .9rem 1.1rem; margin: 1.75rem 0;
}
nav.prereq h2 {
  font-size: .8rem; text-transform: uppercase; letter-spacing: .08em; color: var(--ink);
  margin: 0 0 .5rem; border-top: none; padding-top: 0;
}
/* Styled, not generated. These words used to be a content string, which meant the only
   copy of an instruction a reader is meant to act on lived in a stylesheet: skipped by
   some screen reader configurations, invisible to translation, and absent from an
   export. See 0004 task 12.4. */
nav.prereq h2 .prereq-note { font-weight: 400; color: var(--muted); letter-spacing: 0; text-transform: none; }
nav.prereq ul { list-style: none; padding-left: 0; margin: 0; counter-reset: pre; }
nav.prereq li { counter-increment: pre; padding-left: 1.8rem; position: relative; margin: .3rem 0; font-size: .9rem; }
nav.prereq li::before {
  content: counter(pre); position: absolute; left: 0; top: .05rem;
  width: 1.25rem; height: 1.25rem; border: 1px solid var(--rail); border-radius: 50%;
  font-size: .7rem; display: grid; place-items: center; color: var(--muted);
}
nav.next { border-top: 2px solid var(--marker); margin-top: 3.5rem; padding-top: 1rem; font-size: .95rem; }
nav.next h2 { font-size: .8rem; text-transform: uppercase; letter-spacing: .08em; margin: 0 0 .4rem; border-top: none; padding-top: 0; }
nav.next ul { list-style: none; padding-left: 0; margin: 0; }
nav.next li::before { content: "→ "; color: var(--marker); }

/* Faded stages read as a progression with a position marker rather than three boxes. */
.faded { border: 1px solid var(--rule); border-radius: 6px; padding: 1rem 1.2rem; margin: 2rem 0; }
.faded h3 { margin-top: 0; }
.faded .goal { color: var(--muted); font-size: .92rem; }
details.stage { border-top: 1px solid var(--rule); padding: .65rem 0; }
details.stage summary { cursor: pointer; font-size: .85rem; font-weight: 600; }
details.stage summary::before { content: "◆ "; color: var(--rail); }
details.stage[open] summary::before { content: "◆ "; color: var(--marker); }
details.stage summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.steps { padding-left: 1.1rem; }
.steps li { margin: .7rem 0; }
.steps code { background: color-mix(in srgb, var(--ink) 6%, transparent); padding: .15rem .35rem; border-radius: 3px; }
.steps .why { margin: .25rem 0 0; font-size: .88rem; color: var(--muted); }
.blank { font-size: .8rem; color: var(--muted); border-bottom: 1px dashed var(--rail); }
.prompt { font-size: .9rem; color: var(--muted); }
.provenance-inline { font-size: .78rem; color: var(--muted); }

figure.diagram { margin: 2rem 0; overflow-x: auto; }
figure.diagram:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
figure.diagram figcaption {
  font-size: .85rem; color: var(--muted); background: color-mix(in srgb, var(--ink) 3%, transparent);
  border: 1px solid var(--rule); border-top: none; padding: .6rem .8rem; border-radius: 0 0 5px 5px;
}
figure.diagram svg { width: auto; max-width: none; height: auto; display: block; margin-bottom: 0; }
figure.diagram .diagram-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) figure.diagram .diagram-light { display: none; }
  :root:not([data-theme="light"]) figure.diagram .diagram-dark { display: block; }
}
/* Screenshots are captured at 2x so the callouts stay sharp; the column sets their width. */
figure.shot { margin: 2rem 0; }
figure.shot img {
  display: block; max-width: 100%; height: auto; border: 1px solid var(--rule); border-radius: 5px 5px 0 0;
}
figure.shot figcaption {
  font-size: .85rem; color: var(--muted); background: color-mix(in srgb, var(--ink) 3%, transparent);
  border: 1px solid var(--rule); border-top: none; padding: .6rem .8rem; border-radius: 0 0 5px 5px;
}
table { border-collapse: collapse; width: 100%; font-size: .9rem; margin: 1.4rem 0; }
th, td { text-align: left; padding: .45rem .6rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
th { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); background: color-mix(in srgb, var(--ink) 3%, transparent); }
tbody tr:hover { background: color-mix(in srgb, var(--marker) 4%, transparent); }
/* 15.6. Anything that moves respects the reader's system setting, including the scrolling
   this stylesheet asks for by name. For a reader with a vestibular disorder, a page moving
   under them without their hand on it is the motion that costs most. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------------------
   C: Orientation, applied to the 0007 and help markup.
   The direction's claim is that the unanswered question is "am I in the right place,
   and is this current". So every block below leads with state: which reader an
   explanation is for, which statuses a family covers, where in a sequence a position
   sits. Content follows the band that locates it.
   --------------------------------------------------------------------------- */

.note-marker {
  font-size: .7em; vertical-align: super; text-decoration: none; font-weight: 700;
  font-family: var(--sans, ui-sans-serif, system-ui, sans-serif); color: var(--marker);
  padding: 0 .15em;
}

.notes { border: 1px solid var(--rule); border-radius: 6px; margin: 2rem 0 0; padding: 0; }
.notes h4 {
  font-family: var(--sans, ui-sans-serif, system-ui, sans-serif); font-size: .72rem;
  text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
  margin: 0; padding: .5rem 1rem; border-bottom: 1px solid var(--rule);
  background: color-mix(in srgb, var(--marker) 5%, transparent);
}
.note-list { margin: 0; padding: 0; list-style: none; counter-reset: note; }
.note-list > li {
  counter-increment: note; border-bottom: 1px solid var(--rule);
  padding: .8rem 1rem .8rem 2.6rem; position: relative; margin: 0;
}
.note-list > li:last-child { border-bottom: 0; }
.note-list > li::before {
  content: counter(note); position: absolute; left: .9rem; top: .85rem;
  width: 1.1rem; height: 1.1rem; border-radius: 50%; text-align: center;
  background: var(--marker); color: var(--paper);
  font: 700 .68rem/1.1rem var(--sans, ui-sans-serif, system-ui, sans-serif);
}
.note-list > li > p { margin: .3rem 0 0; font-size: .95rem; }
.note-anchor { display: inline-block; }
/* State first: who this is for, before the explanation itself. */
.note-audience {
  display: block; font-family: var(--sans, ui-sans-serif, system-ui, sans-serif);
  font-size: .7rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin-top: .2rem;
}

.representation { border: 1px solid var(--rule); border-radius: 6px; margin: 1.5rem 0; padding: 0; }
.representation h3 { font-size: 1rem; margin: 0; padding: .7rem 1rem .1rem; }
.register {
  order: -1; font-family: var(--sans, ui-sans-serif, system-ui, sans-serif); font-size: .7rem;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
  margin: 0; padding: .45rem 1rem; border-bottom: 1px solid var(--rule);
  background: color-mix(in srgb, var(--marker) 4%, transparent);
}
.representation > p:not(.register) { padding: 0 1rem .8rem; margin: .4rem 0 0; }
details.criteria {
  border: 1px solid var(--rule); border-radius: 6px; padding: .6rem 1rem; margin: 1.5rem 0;
}
details.criteria > summary {
  cursor: pointer; font-family: var(--sans, ui-sans-serif, system-ui, sans-serif);
  font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted);
}

.family { border: 1px solid var(--rule); border-radius: 6px; margin: 1.5rem 0; padding: 0; }
.family-title { font-size: 1rem; margin: 0; padding: .75rem 1rem .35rem; }
/* The orientation band, the same idea as the provenance strip at the top of the page:
   the facts that locate you, read as one horizontal line before any prose. */
.family-meta {
  display: flex; flex-wrap: wrap; gap: .3rem .8rem; align-items: baseline;
  margin: 0; padding: .45rem 1rem; border-bottom: 1px solid var(--rule);
  background: color-mix(in srgb, var(--marker) 4%, transparent);
  font-family: var(--sans, ui-sans-serif, system-ui, sans-serif); font-size: .72rem;
  text-transform: uppercase; letter-spacing: .05em; color: var(--muted);
}
.statuses { font-weight: 700; color: var(--marker); }
.statuses::before { content: "HTTP "; font-weight: 400; color: var(--muted); }
.retry-no { color: var(--ink); font-weight: 700; }
.family-proves, .family-check, .family-also { padding: 0 1rem; margin: .7rem 0; }
.family-also { padding-bottom: .9rem; }
.label {
  display: block; font-family: var(--sans, ui-sans-serif, system-ui, sans-serif); font-size: .68rem;
  text-transform: uppercase; letter-spacing: .07em; color: var(--muted); margin-bottom: .15rem;
}

/* Gaps the stylesheet contract found. Orientation puts currency in the standing band,
   so the date is set as furniture rather than prose. */
.verified { color: var(--muted); font-variant-numeric: tabular-nums; }
.families { margin: 1.75rem 0; }
.retry { font-weight: 700; }

/* ---------------------------------------------------------------------------
   The worked example: three levels of support over one block of code.
   --------------------------------------------------------------------------- */

/* Links with scripting off, tabs with it on. The static form is a real navigation list, so
   it is useful before any of this is upgraded rather than being an empty shell. */
.stage-nav {
  display: flex; flex-wrap: wrap; gap: .3rem; margin: 1rem 0 .25rem;
  border-bottom: 1px solid var(--rule);
}
.stage-nav a {
  padding: .45rem .85rem; text-decoration: none; font-size: .85rem; color: var(--muted);
  border: 1px solid transparent; border-bottom: 0; border-radius: 5px 5px 0 0;
}
.stage-nav a:hover, .stage-nav a:focus { color: var(--marker); background: color-mix(in srgb, var(--marker) 6%, transparent); }
.stage-nav a[aria-selected="true"] {
  color: var(--ink); font-weight: 700; background: var(--paper);
  border-color: var(--rule); margin-bottom: -1px;
}
.stage { margin: 1.25rem 0 2rem; }
.stage > h4 { font-size: 1rem; margin: 0 0 .5rem; color: var(--ink); }
.prompt { font-size: .9rem; color: var(--muted); margin: 0 0 .6rem; }

/* An ordered list wearing the clothes of a code block. The list semantics are what make a
   screen reader's "item 4" mean line 4; every visual trace of a list is removed, because a
   reader is looking at code and a bulleted list of statements is not what code looks like. */
ol.code {
  list-style: none; margin: 0; padding: .8rem 0; counter-reset: none;
  background: color-mix(in srgb, var(--ink) 4%, transparent);
  border: 1px solid var(--rule); border-radius: 5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85rem;
  line-height: 1.7; overflow-x: auto;
}
.cl { display: grid; grid-template-columns: 2.5rem auto 1fr; margin: 0; padding: 0 1rem 0 0; }
.cl:target { background: color-mix(in srgb, var(--marker) 9%, transparent); }
.src { grid-column: 2; white-space: pre; }
.src.blank { color: var(--muted); font-style: italic; }

/* The line number is an anchor, so a paragraph can cite a line and a reader can link to one.
   It is quiet until pointed at, because eight numbers competing with the code is noise. */
.ln {
  grid-column: 1; text-align: right; padding-right: .9rem; text-decoration: none;
  color: color-mix(in srgb, var(--muted) 65%, transparent); user-select: none;
  font-variant-numeric: tabular-nums;
}
.ln:hover, .ln:focus { color: var(--marker); text-decoration: underline; }

/* The note symbol carries its text in `title`, which hovers natively and is read aloud. */
.sym {
  grid-column: 3; justify-self: start; text-decoration: none; color: var(--marker); font-size: .95rem;
  padding-left: .35rem;
}
.cl .why {
  grid-column: 2 / -1; margin: .15rem 0 .5rem; font-family: var(--sans, ui-sans-serif, system-ui, sans-serif);
  font-size: .88rem; line-height: 1.55; color: var(--muted); white-space: normal;
  border-left: 2px solid var(--rule); padding-left: .7rem;
}

/* Tokens. Contrast checked against both grounds, not chosen for looks. */
.tok-keyword { color: var(--marker); font-weight: 600; }
.tok-string { color: #1f6f4a; }
.tok-comment { color: var(--muted); font-style: italic; }
.tok-number { color: #8a5a00; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tok-string { color: #6fc79b; }
  :root:not([data-theme="light"]) .tok-number { color: #e0b25a; }
}

/* Controls the script adds. Styled here so they match the page rather than arriving unstyled
   a frame after everything else. */
.ex-controls { display: flex; flex-wrap: wrap; gap: .5rem; margin: .5rem 0 0; }
.ex-controls button:hover, .ex-controls button:focus { color: var(--marker); border-color: var(--marker); }

/* What the page is for, and who it recognizes. Both sit above the content because a reader
   deciding whether a page is theirs has not started reading yet. */
.use-cases { font-size: 1.02rem; line-height: 1.6; margin: 0 0 1rem; }
.levels { display: flex; flex-wrap: wrap; gap: .4rem; align-items: baseline; margin: 0 0 1.5rem; }
.levels-label { font: 600 .7rem var(--sans, ui-sans-serif, system-ui, sans-serif); text-transform: uppercase;
                letter-spacing: .07em; color: var(--muted); }
/* Only once the script has made them do something do they look like they do something. */
.js .level { cursor: pointer; }
/* Hover and focus are drawn by the chip block below: a tint behind the label, and a
   focus ring. This rule is what those replaced, and leaving it here outranked them --
   `.js .level:focus` beats `.level[aria-pressed="true"]` on specificity, so clicking a
   chip (which focuses it) repainted the label in the same color the chip had just been
   filled with. Selected chips read as empty. */
.dimmed { opacity: .45; }

/* States the script sets. Without these the buttons toggled classes that styled nothing,
   which looks exactly like a button that does not work, because it is one. */
.cl.collapsed .why { display: none; }
.cl.has-note .ln::after { content: ""; }
.js .cl.has-note .ln:hover::after, .js .cl.has-note .ln:focus::after { content: " \25BE"; }
.js .cl.has-note.collapsed .ln:hover::after,
.js .cl.has-note.collapsed .ln:focus::after { content: " \25B8"; }
.why-list { list-style: none; margin: .75rem 0 0; padding: 0; }
.why-list > li { margin: 0 0 .6rem; font-size: .9rem; }
.why-list .why-line { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
                      font-size: .8rem; text-decoration: none; margin-right: .5rem; }

/* Anchors landed flush against the top edge, with the line a reader had just asked to see
   pressed against the browser chrome and no context above it. A cited line needs the lines
   around it to mean anything. */
.cl, h1, h2, h3, h4, .faded, .stage { scroll-margin-top: 3.5rem; }

/* Orientation for a reader who arrived mid-page. Marked as an aside because it is furniture,
   and quiet because it is furniture a reader who started at the top never sees. */
.orientation {
  border-left: 3px solid var(--rule); padding: .6rem .9rem; margin: 0 0 1.25rem;
  font: .85rem/1.5 var(--sans, ui-sans-serif, system-ui, sans-serif); color: var(--muted);
}
.orientation p { margin: 0 0 .4rem; }
.orientation-top { margin-right: .75rem; }
.orientation-dismiss {
  font: 600 .75rem var(--sans, ui-sans-serif, system-ui, sans-serif); cursor: pointer;
  padding: .15rem .5rem; border-radius: 4px; border: 1px solid var(--rule);
  background: transparent; color: var(--muted);
}

/* The re-check control. A link, because it opens a request rather than performing one. */
.recheck { font-size: .8125rem; white-space: nowrap; }

/* The export control. Created by the script, so a reader without it sees no button and loses
   nothing: the markdown they would have exported is the file the site is built from. */
.export-controls { margin: 2.5rem 0 0; padding-top: 1rem; border-top: 1px solid var(--rule); }

/* The reading helper. Lower corner, present from first paint, and incapable of covering the
   text: it is a button until a reader asks for more, and the panel it opens is bounded so a
   paragraph is never behind it. */
/* The closed helper still sits over the bottom of the viewport. scroll-padding keeps a focused
   field or a jumped-to heading clear of it, and the body padding lets the last line of the page
   scroll above it. Sized to the button plus its gap, with room to spare. */
html { scroll-padding-bottom: 7rem; }
body { padding-bottom: 7rem; }
.helper {
  position: fixed; right: 1rem; bottom: 1rem; z-index: 20; max-width: min(24rem, calc(100vw - 2rem));
  display: flex; flex-direction: column; align-items: flex-end; gap: .4rem;
  /* The container is as wide as the panel it may open, and most of that is empty air sitting
     over the text. Without this it swallows clicks on links underneath, which is gating
     reading with an invisible box. The children take their own clicks back. */
  pointer-events: none;
}
.helper > * { pointer-events: auto; }
.helper-toggle {
  font: 600 .8rem var(--sans, ui-sans-serif, system-ui, sans-serif); cursor: pointer;
  padding: .5rem .9rem; border-radius: 999px; border: 1px solid var(--marker);
  background: var(--paper); color: var(--marker); box-shadow: 0 1px 4px rgba(0,0,0,.12);
}
/* Widening, not flashing. The reader is already moving fast; motion would compete with them. */
.helper-surfaced .helper-toggle { font-weight: 700; padding: .6rem 1.1rem; }
/* Scoped under .helper: .md-button, later in the sheet, resets background at equal weight. */
.helper .helper-dismiss {
  font: .72rem var(--sans, ui-sans-serif, system-ui, sans-serif); cursor: pointer; padding: .2rem .5rem;
  border: 0; border-radius: 999px; color: var(--muted); text-decoration: underline;
  /* Fixed over scrolling prose: transparent, its label printed on top of the body text. */
  background: var(--paper); box-shadow: 0 1px 4px rgba(0,0,0,.12);
}
/* An explicit display beats the browser's [hidden] rule, so the panel has to opt back out
   by name. Without this it was 272px of open panel sitting over the page from first paint,
   with hidden="true" on it the whole time. */
.helper-panel[hidden] { display: none; }
.helper-panel {
  display: flex; flex-direction: column; gap: .5rem; width: min(24rem, calc(100vw - 2rem));
  padding: .9rem; border: 1px solid var(--rule); border-radius: 8px;
  background: var(--paper); box-shadow: 0 2px 12px rgba(0,0,0,.14);
  max-height: min(70vh, 34rem); overflow-y: auto;
}
.helper-input {
  font: .875rem var(--sans, ui-sans-serif, system-ui, sans-serif); padding: .5rem;
  border: 1px solid var(--rule); border-radius: 4px; background: var(--paper); color: var(--ink);
  resize: vertical;
}
.helper-chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.helper-chip {
  font: .72rem var(--sans, ui-sans-serif, system-ui, sans-serif); cursor: pointer; text-align: left;
  padding: .25rem .55rem; border-radius: 999px; border: 1px solid var(--rule);
  background: transparent; color: var(--muted);
}
.helper-chip:hover, .helper-chip:focus { color: var(--marker); border-color: var(--marker); }
.helper-send {
  align-self: flex-start; font: 600 .8rem var(--sans, ui-sans-serif, system-ui, sans-serif); cursor: pointer;
  padding: .4rem .9rem; border-radius: 4px; border: 1px solid var(--marker);
  background: transparent; color: var(--marker);
}
.helper-status { font: .75rem var(--sans, ui-sans-serif, system-ui, sans-serif); color: var(--muted); margin: 0; }
.helper-answer p { font-size: .875rem; line-height: 1.55; margin: 0 0 .4rem; }
.helper-provenance { font-size: .75rem; color: var(--muted); font-style: italic; }
@media (max-width: 40rem) {
  .helper { left: 1rem; right: 1rem; align-items: stretch; }
}
.helper-removed:empty { display: none; }
.helper-removed {
  font: .75rem var(--sans, ui-sans-serif, system-ui, sans-serif); margin: 0;
  padding: .3rem .5rem; border-radius: 4px; color: var(--ink);
  background: rgba(128,128,128,.14);
}

/* The machine's check, said after the person's and quieter than it. Two different claims, and
   a reader weighing the page is weighing the first one. */
.verified-eval { color: var(--muted); }

/* C is the structural direction, so each step is a marked block and the sequence is read from
   the markers rather than from indentation. */
.helper-steps { list-style: none; margin: 0 0 .5rem; padding: 0; counter-reset: step; }
.helper-step {
  counter-increment: step; margin: 0 0 .5rem; padding-left: .6rem;
  border-left: 2px solid var(--rail);
}
.helper-step-heading {
  font-weight: 700; font-size: .78125rem; margin: 0 0 .15rem;
  text-transform: uppercase; letter-spacing: .02em; color: var(--marker);
}
.helper-step-heading::before { content: counter(step) " / "; }
.helper-step a { font-size: .8125rem; color: var(--accent); }
.helper-step-canonical { border-left-color: var(--accent); }
.intake { margin: 1rem 0; max-width: var(--measure); }
.intake-field { display: flex; flex-direction: column; gap: .2rem; margin: 0 0 .6rem; }
/* Browser default is a white box, which on a dark page is a hole in it. */
.intake-input {
  font: inherit;
  padding: .45rem .55rem;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: calc(var(--control-shape) / 4 + 2px);
}
.intake-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.intake-questions[hidden] { display: none; }
/* It is a link, so it looks like every other link on the site. Inheriting the heading's color
   made it underlined text that happened to be clickable, which is the same confusion the other
   way round: the reader was right that a status code should be a link and right again that this
   one did not look like one. */
.status-link { color: var(--accent); text-decoration: underline; text-underline-offset: .18em; }
.intake-out:empty { display: none; }
.intake-shown { border-left: 2px solid var(--rail); padding-left: .6rem; margin: .5rem 0; }
.intake-shown-text { white-space: pre-wrap; margin: .2rem 0; }
.intake-removed { font-size: .8125rem; color: var(--marker); }
.intake-family { border-top: 2px solid var(--accent); padding-top: .5rem; margin-top: .6rem; }

/* ---------------------------------------------------------------- controls
   One button system, applied to every control on the site.

   Before this there were three: the example controls, the export control, and whatever the
   browser does with a bare <button>, which is a white rectangle. A reader met all three on one
   page and had no way to tell which was the action and which was chrome.

   Material's structure is what fixes that, and the parts worth taking are the ones a reader
   feels rather than sees. A control announces its rank: filled for the action a page is asking
   for, outlined for the alternatives, text for the ones that undo. Hover, focus and press are a
   state layer over the same surface rather than a change of border, so nothing resizes or shifts
   under the pointer. And the touch target is larger than the drawn control, which is invisible
   on a mouse and the difference between usable and not on a phone.
*/
.md-button {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  min-height: 40px;
  padding: 0 1rem;
  border: none;
  border-radius: var(--control-shape);
  cursor: pointer;
  font: 500 .875rem/1.25 var(--sans, ui-sans-serif, system-ui, sans-serif);
  letter-spacing: .006em;
  text-align: center;
  background: transparent;
  color: var(--accent);
}

/* The drawn button is 40px because that is a comfortable size to read. The target is 48px
   because that is a fingertip, and the difference is why a small control is not a small
   problem on a phone. */
.md-button::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  min-height: 48px;
  height: 100%;
}

/* The state layer. currentColor means it works on every variant and in both themes without a
   second set of colors to keep in step. */
.md-button::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: currentColor;
  opacity: 0;
  transition: opacity .15s ease;
}
.md-button:hover::before { opacity: .08; }
.md-button:focus-visible::before { opacity: .12; }
.md-button:active::before { opacity: .16; }

.md-button:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.md-button[disabled] { cursor: default; opacity: .38; }
.md-button[disabled]::before { opacity: 0; }

/* Filled: the one thing the page is asking for. At most one per region, or the emphasis is
   spent and none of them reads as the action. */
.md-filled { background: var(--accent); color: var(--on-accent); }
.md-filled::before { background: var(--on-accent); }

/* Outlined: a real alternative, not a lesser one. */
.md-outlined { border: 1px solid var(--rule); }

/* Text: reversible, and the ones that undo. Nothing to draw the eye. */
.md-text { padding: 0 .6rem; }

@media (prefers-reduced-motion: reduce) {
  .md-button::before { transition: none; }
}

/* Existing controls adopt the same system rather than keeping their own. */
.ex-controls button,
.export-controls button,
.helper-chip { border-radius: var(--control-shape); }

/* ------------------------------------------------- where the reader got to
   A route with a rail, drawn after looking at it rather than after reading the stylesheet.

   Three things were wrong in the version this replaces, and all three were visible in a
   screenshot and invisible in the source. The rail was cut into disconnected stubs, because
   each step carried a margin and a border cannot cross a margin. The control was a text button,
   which on a page full of links is not a control at all. And the answer kept a rule down the
   side of every paragraph, so a panel meant to feel like one thought arrived as four fenced
   ones.

   What the rail has to say is simple: you came from up there, you are here, that continues
   downward. Solid accent behind, a thick ring on the current step, and everything below at
   reduced emphasis but still legible, because "what happens next" is the question a stuck
   reader actually has.
*/
/* Flex, and not for layout. The template writes a newline between each section, and in a block
   container a whitespace-only text node becomes an anonymous line box about 30px tall. That is
   what cut the rail into stubs: a border cannot cross a gap it does not own. A flex container
   discards whitespace-only children, so the steps actually touch. */
.positions-stepped { display: flex; flex-direction: column; margin: 1.5rem 0; }

.positions-stepped .position {
  position: relative;
  /* Margin is what broke the rail: a border cannot cross the gap between two boxes. The space
     is padding now, so each segment runs the full height of its step and meets the next one. */
  margin: 0;
  padding: 0 0 1.5rem 2.25rem;
  border: none;
  border-radius: 0;
}
.positions-stepped .position:last-child { padding-bottom: 0; }
.positions-stepped .position-signal { margin-top: 0; }
/* Restored: the stripper that cleared the old position layer took this with it, and the
   style contract noticed. The signal's proof sits tight under it in this design. */
.position-means { margin: 0; }

/* The rail segment. Full height, so consecutive segments touch. */
.positions-stepped .position::before {
  content: "";
  position: absolute;
  left: calc((18px - 2px) / 2);
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--rule);
}
.positions-stepped .position:last-child::before { display: none; }

/* The marker sits on the rail and hides the line behind it. */
.position-marker {
  position: absolute;
  box-sizing: border-box;
  left: 0;
  top: .38rem;
  width: 18px;
  height: 18px;
  padding: 0;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--rule);
  cursor: pointer;
}
/* The drawn circle is small on purpose. The target around it is not. */
.position-marker::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  width: 44px;
  height: 44px;
}
.position-marker:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

/* Behind you. */
.positions-stepped .position-passed::before { background: var(--accent); }
.position-passed .position-marker { background: var(--accent); border-color: var(--accent); }
.positions-stepped .position-passed .position-signal { color: var(--muted); }

/* Here. The thick ring is the only one of its kind in the column. */
.position-chosen .position-marker {
  border-width: 5px;
  border-color: var(--accent);
  background: var(--paper);
}
.positions-stepped .position-chosen .position-signal { color: var(--accent); }

/* Ahead. Quieter, and still readable, because what happens next is the question. */
.positions-stepped .position-ahead { opacity: .68; }

/* A control, not a link. Tonal by default so it reads as pressable on a page of blue text, and
   filled once chosen, which is how a selection shows itself without the label changing. */
.position-report {
  min-height: 36px;
  margin-top: .3rem;
  padding: 0 .9rem;
  font-size: .8125rem;
  font-weight: 500;
  border-radius: var(--control-shape);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}
.position-report:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.position-report[aria-pressed="true"] {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}

/* One surface, no rules. The previous version fenced each paragraph off from the next. */
.position-answer {
  margin-top: .75rem;
  padding: .85rem 1rem;
  border: none;
  border-radius: calc(var(--control-shape) / 2 + 4px);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.position-answer p {
  margin: 0 0 .7rem;
  padding-left: 0;
  border-left: none;
}
.position-answer p:last-child { margin-bottom: 0; }
.position-answer .label {
  display: block;
  margin-bottom: .1rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Only the label is quiet. Dimming the sentence too made the answer read as
   three captions with no prose under them. */
.position-answer p { color: var(--ink); }
.answer-next { font-weight: 600; }

/* The preview of one field, matched to the answer panel: a surface rather than a rule, because
   the same reader met the same pattern forty lines up. */
.intake-shown {
  border-left: none;
  padding: .7rem .85rem;
  margin: .6rem 0;
  border-radius: calc(var(--control-shape) / 4 + 2px);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.intake-shown-text { margin: .25rem 0 .4rem; white-space: pre-wrap; }
.intake-shown-label, .intake-removed { color: var(--muted); }

/* The delete control sits at the end of the line it removes, so a reader who wants a line gone
   points at that line. Quiet until approached, because removing an answer is reversible and
   should not look like the thing to do. */
.intake-shown-label { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.intake-drop {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  min-height: 0;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.intake-drop:hover { color: var(--warn, var(--accent)); background: color-mix(in srgb, currentColor 12%, transparent); }
.intake-drop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Drawn at 30px, reachable at 44. */
.intake-drop::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%; translate: -50% -50%;
  width: 44px; height: 44px;
}
.intake-drop { position: relative; }

/* The fallback path, and the whole feature without scripting. It looks like the action it is. */
.intake-open { text-decoration: none; }

/* An aside is an aside. It answers a question a reader asks only if they are wondering. */
details.aside { margin: 1.25rem 0; }
details.aside > summary { cursor: pointer; color: var(--muted); font-size: .9375rem; }
details.aside[open] > summary { margin-bottom: .5rem; }

/* A hairline, not a rule. It separates the taxonomy note from the preview above it. */
.intake-family {
  margin-top: .9rem;
  padding-top: .7rem;
  border-top: 1px solid var(--rule);
}
.intake-family-title { color: var(--muted); }

/* --------------------------------------- one control language, everywhere
   Found by opening a page that had only ever been read. Three treatments were living on the
   same site: the button system written today, the example controls from before it, and the
   reader-level chips, which are pressable and drawn as tags.

   A reader does not learn three vocabularies. They learn the first one they are shown and then
   miss the controls that do not speak it, which on this page are the two that let them choose
   how much of the example they see.

   Markup is unchanged. These are selection chips in Material's sense, and selection is carried
   by the container filling rather than by a border changing color, so nothing shifts when one
   is chosen. */
.levels { align-items: center; gap: .45rem; }

.level,
.ex-controls button,
.export-controls button {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0 .8rem;
  border: 1px solid var(--rule);
  border-radius: var(--control-shape);
  background: transparent;
  color: var(--muted);
  font: 500 .78rem/1 var(--sans, ui-sans-serif, system-ui, sans-serif);
  cursor: pointer;
}
.level::before,
.ex-controls button::before,
.export-controls button::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: currentColor;
  opacity: 0;
  transition: opacity .15s ease;
}
.level:hover::before,
.ex-controls button:hover::before,
.export-controls button:hover::before { opacity: .08; }
.level:focus-visible,
.ex-controls button:focus-visible,
.export-controls button:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .level::before,
  .ex-controls button::before,
  .export-controls button::before { transition: none; }
}

/* Chosen fills the container rather than recoloring an edge, so nothing shifts when one is
   selected and the state is carried by more than a one-pixel color change. */
.level[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}

/* What the press did. Sits under the chips, empty until one is pressed, so it takes no
   space on a page nobody has interacted with. */
.levels-report { margin: -.9rem 0 1.5rem; font: 400 .82rem/1.5 var(--sans, ui-sans-serif, system-ui, sans-serif);
                 color: var(--muted); }
.levels-report:empty { display: none; }


/* ------------------------------------------------- what this page would send
   Spec 3.7 asks for a panel rather than a setting. A setting is a promise about behavior; this
   is the behavior, shown. It is quiet by default and never in the way, because a privacy panel
   that demands attention is asking to be dismissed rather than read. */
.data-panel { margin: 3rem 0 0; padding-top: 1.25rem; border-top: 1px solid var(--rule); }
.data-panel-body { margin-top: .9rem; }
.data-panel-heading {
  margin: 1.1rem 0 .4rem;
  font: 600 .78rem var(--sans, ui-sans-serif, system-ui, sans-serif);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}
.data-panel-heading:first-child { margin-top: 0; }
.data-panel-empty, .data-panel-note, .data-panel-refused { margin: 0 0 .5rem; font-size: .9375rem; }
.data-panel-refused { color: var(--warn, var(--accent)); }

.data-row {
  margin: .5rem 0;
  padding: .7rem .85rem;
  border-radius: calc(var(--control-shape) / 4 + 2px);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.data-row-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin: 0;
  font: 600 .8125rem ui-monospace, monospace;
}
.data-row-value {
  margin: .35rem 0;
  padding: .45rem .55rem;
  overflow-x: auto;
  white-space: pre-wrap;
  font-size: .8125rem;
  border-radius: 3px;
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}
.data-row-why { margin: .25rem 0 0; font-size: .8125rem; color: var(--muted); }

.data-drop {
  min-height: 30px;
  padding: 0 .7rem;
  border: 1px solid var(--rule);
  border-radius: var(--control-shape);
  background: transparent;
  color: var(--muted);
  font: 500 .75rem var(--sans, ui-sans-serif, system-ui, sans-serif);
  cursor: pointer;
}
.data-drop:hover { color: var(--ink); }
.data-drop:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* The kept-answer layer (0004 section 4). A kept answer is part of the document, so it sits in
   the measure with the prose. It is also generated, so it cannot look identical to prose a
   person checked: a tonal container and an edge marker say "this arrived at runtime" without
   the shouting of a warning box, which is the Material read on the same problem. */
.adaptations[hidden] { display: none; }
.adaptations {
  display: flex; flex-direction: column; gap: 1rem;
  max-width: var(--measure); margin: 2.5rem 0 0;
  padding-top: 1.25rem; border-top: 1px solid var(--rule);
}
.adaptation {
  display: flex; flex-direction: column; gap: .5rem;
  padding: 1rem 1.1rem; border-radius: var(--control-shape, 12px);
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--paper));
}
.adaptation-heading { font-size: 1.05rem; margin: 0 0 .25rem; }
.adaptation-question {
  margin: 0; font-size: .8125rem; color: var(--muted); font-weight: 500;
}
.adaptation-lead { margin: 0; }
.adaptation-rest[hidden] { display: none; }
.adaptation-rest p { margin: .5rem 0 0; }
/* .md-button is inline-flex, which beats the browser default for [hidden]. Every
   button this layer hides needs saying explicitly or it stays on screen. */
.adaptation-more[hidden], .adaptation-expand[hidden], .adaptation-terse[hidden]
  { display: none; }
.adaptation-more { align-self: flex-start; }
.adaptation-provenance {
  margin: 0; font-size: .75rem; color: var(--muted); font-style: italic;
}
.adaptation-controls {
  display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .25rem;
}
.helper-keep { align-self: flex-start; margin-top: .5rem; }

/* The report form (0004 section 10). It sits at the foot of the page and looks like a form,
   because a control that looks like prose does not get used and a control that shouts gets
   ignored. The preview is monospace: it is the literal text that will be sent. */
.report {
  max-width: var(--measure); margin: 3rem 0 0; padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}
.report-heading { font-size: 1.05rem; margin: 0 0 .35rem; }
.report-intro { margin: 0 0 1rem; color: var(--muted); font-size: .875rem; }
.report-field { display: flex; flex-direction: column; gap: .3rem; margin: 0 0 .85rem; }
.report-field label { font-size: .8125rem; font-weight: 500; }
.report-section, .report-text {
  font: inherit; padding: .55rem .6rem; min-height: 48px;
  border: 1px solid var(--rule); border-radius: 4px;
  background: var(--paper); color: var(--ink);
}
.report-text { min-height: 6rem; resize: vertical; }
.report-removed:empty { display: none; }
.report-removed { font-size: .8125rem; color: var(--accent); margin: 0 0 .6rem; }
.report-preview:empty { display: none; }
.report-preview {
  font-size: .8125rem; line-height: 1.5; white-space: pre-wrap; overflow-x: auto;
  padding: .75rem; margin: 0 0 .85rem; border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 4%, var(--paper));
}
.report-open[hidden] { display: none; }
.report-open { display: inline-flex; align-items: center; }

/* The published masthead and footer (ported from philhwagner.com at 23ef89d).

   Prefixed and few, and deliberately on this design system's own tokens rather than a palette
   of its own, so it follows the set into dark mode without a second set of definitions. Only
   the masthead and footer are here; the page body is styled by everything above. */
.ws-wrap { max-width: calc(var(--toc-width) + var(--code-width) + 4rem);
           margin: 0 auto; padding: 0 1.5rem; }
.ws-mast { border-bottom: 1px solid var(--rule); margin: 0 0 1.5rem; }
.ws-mast .ws-wrap { display: flex; align-items: center; gap: 1rem;
                    flex-wrap: wrap; padding-top: 1.15rem; padding-bottom: 1.15rem; }
.ws-pt { width: 60px; height: 60px; border-radius: 50%; flex: none;
         border: 2px solid var(--rule); }
.ws-id { margin-right: auto; }
.ws-nm { font-size: 1.1rem; font-weight: 700; line-height: 1.2; color: var(--ink); margin: 0; }
.ws-nm a { color: inherit; text-decoration: none; }
.ws-nm a:hover { color: var(--marker); }
.ws-ti { font-size: .84rem; color: var(--muted); line-height: 1.5; margin: .2rem 0 0; }
.ws-links { display: flex; align-items: center; gap: .95rem; flex-wrap: wrap; font-size: .85rem; }
/* Icon links sit on the text baseline and take the link color, so the marks stay legible
   in every direction without any of them shipping a second palette. */
.ws-links a { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; min-height: 24px; }
.ws-links svg { display: block; }
/* One footer, not two statements stacked. The colophon used to draw its own rule and a
   3rem gap inside footer.site, which read as a second footer arriving under the first.
   footer.site already has the rule above it and the space around it. */
.ws-foot { margin-top: .9rem; }
/* Inside footer.site, which already constrains and pads itself to the text column.
   Re-applying .ws-wrap's own max-width and side padding inset the name and links a
   further 24px, so they did not line up with the trackers line directly above them.
   The wrap keeps its vertical rhythm and gives up the horizontal, because the element
   around it has already done that. */
.ws-foot .ws-wrap { max-width: none; padding-left: 0; padding-right: 0;
                    padding-top: 0; padding-bottom: 0;
                    font-size: .85rem; color: var(--muted); }
.ws-foot p { margin: 0 0 .6rem; }

/* The lead set's label on the front door. A recommendation rather than a heading: it names no
   content, so it does not belong in the contents list beside the seven sets that do. */
.start-here {
  margin: 0 0 .2rem; font-size: .75rem; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--accent);
}

/* A set's kind, beside its name, when the kind is not a set of documents. The count already
   says "documents", so only a set a reader can use rather than read carries one. */
.set-tag {
  display: inline-block; margin-left: .4rem; padding: .05rem .4rem;
  border: 1px solid var(--accent); border-radius: 4px; white-space: nowrap;
  font-size: .7rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent); vertical-align: .2em;
}

/* The counts the page can send (0005 task 5.2b). Indented like the panel's other lists and set
   at the same size as its prose: this is content a reader is meant to read, not a legend. */
.data-panel-list { margin: 0 0 .6rem; padding-left: 1.15rem; font-size: .9375rem; }
.data-panel-list li { margin: 0 0 .3rem; }

/* The counters on /measurement (0005 task 5.9). A list of totals reads down the numbers, so the
   number is its own column rather than trailing the label. */
.counts { margin: 0 0 1.25rem; }
.counts-fallback, .counts-none, .counts-since { color: var(--muted); font-size: .9375rem; }
.counts-since { margin: .5rem 0 0; }
.counts-list { list-style: none; margin: 0; padding: 0; max-width: var(--measure); }
.counts-row {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: .35rem 0; border-bottom: 1px solid var(--rule);
}
.counts-what { min-width: 0; }
.counts-n { font-variant-numeric: tabular-nums; font-weight: 600; flex: none; }

/* The self-check scoring (0005 task 6.9). The buttons sit under their dimension heading and the
   result is written into the document, so it is styled as prose rather than as a widget. */
.self-check-levels { display: flex; flex-wrap: wrap; gap: .4rem; margin: .5rem 0 1rem; }
.self-check-result { margin: 2rem 0; padding-top: 1.25rem; border-top: 1px solid var(--rule); }
.self-check-result h3 { margin-top: 0; }
.self-check-scores, .self-check-next { max-width: var(--measure); }
.self-check-empty, .self-check-partial { color: var(--muted); font-size: .9375rem; }

/* The RAG demo on /rag/ (rag-demo.js). A chip is a real, checked answer with no call behind it;
   the form beside it is the one control on the page that spends one. Both write into the same
   result panel, so a reader compares a free answer and a live one without the page changing
   shape under them. */
.rag-demo { margin: 1.5rem 0 2rem; padding: 1.25rem; border: 1px solid var(--rule);
  border-radius: var(--control-shape); background: var(--sunk); }
.rag-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1rem; }
.rag-chip { border: 1px solid var(--accent-edge); background: var(--tint); color: var(--ink); font: inherit; cursor: pointer; padding: .4rem .7rem; border-radius: var(--control-shape); }
.rag-ask { display: flex; gap: .5rem; flex-wrap: wrap; margin: 0 0 1rem; }
.rag-ask label { flex-basis: 100%; font-weight: 600; font-size: .9375rem; }
.rag-ask input { flex: 1 1 16rem; font: inherit; padding: .5rem .7rem; border: 1px solid var(--edge);
  border-radius: var(--control-shape); background: var(--paper); color: var(--ink); }
.rag-ask input:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.rag-result { min-height: 1.5rem; }
.rag-result .rag-h3 { font-size: 1rem; margin: 1rem 0 .4rem; }
.rag-result .rag-notice { border-left: 3px solid var(--accent); padding-left: .75rem; color: var(--muted); }
.rag-result ol { padding-left: 1.3rem; }
/* The card's heading inherits the section rule and top spacing every h2 carries, which left
   an empty band above it inside the border. */
.rag-demo h2 { margin-top: 0; padding-top: 0; border-top: 0; }
/* The chip whose answer is showing. Filled, so it reads as chosen without relying on color
   alone: the whole shape changes, not just a hue. */
.rag-chip[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
