/* LAYER: page — the interior of each claim band.
 *
 * bands.css owns the FRAME every band shares: the two grounds, the head
 * (figure, unit, statement, lead) and the two-column body. This file owns
 * what is inside each one, and every selector is scoped to its band's id
 * so the four cannot reach into each other.
 *
 * Four sections, in THIS FILE's order: #europe, #portability, #primitives,
 * #free — which is not the page's order, and does not need to be. Nothing in
 * the cascade depends on it: every selector here is scoped to its band's id and
 * none of them is positional. A fifth, #price, was removed; the note where it
 * used to be says what went with it.
 *
 * Each was designed against BRAND.html and the element gallery under
 * brand/experiments/ in internal/hq, and each carries its own reasoning inline.
 */

/* ===========================================================================
 * #price IS GONE — the receipt band, and every rule that drew it.
 *
 * It claimed €5.28 a month against Azure's ~$160 and drew the evidence as a
 * bill: one white cutout on the desk with an ink lip at each end, the drawer
 * between them milled into compartments by gutters of the desk showing through.
 * It was the weakest of the four bands and it was removed whole.
 *
 * WHAT WENT WITH IT, because a removal is only finished when nothing is left
 * pointing at the hole: the markup and its reasoning comment in index.html, the
 * `claim-head--right` mirror that band wore, the handover sentence at the end of
 * #primitives that announced it, and ~250 lines of rules here that no element
 * matched any more. bands.css's `.claim-head--right` stays — it is the shared
 * frame's own modifier and #free may want it — but NOTHING on the page uses it
 * now, which is worth knowing before wondering why it is there.
 *
 * THE STRIPE MOVED. Grounds alternate by POSITION, so taking a band out
 * re-grounds every band after it: #portability went white to desk, #free desk
 * to white, and the closing band lost its `panel` class. See bands.css.
 * ========================================================================= */

/* ===========================================================================
 * #europe
 * ========================================================================= */
/* LAYER: page — #europe, the sealed record.

   THE CLAIM IS A JURISDICTION, so the evidence is a thing with an EDGE. Four
   questions and four answers inside a boundary, and the boundary is drawn by
   the reader: js/eu-border.js runs one continuous stroke round the perimeter as
   they scroll, and the interior is not white until the loop closes.

   THAT IS THE WHOLE IDEA AND IT IS WHY THIS BAND EXISTS. Every other line on
   this page delivers something from one object to another. This one encloses,
   and what it encloses only becomes an inside once it has been all the way
   round. A region is a location; a jurisdiction is a boundary and who can cross
   it, which is the argument /docs/why/made-in-europe/ makes in words.

   THE BORDER IS BOTH A CSS RULE AND AN SVG PATH, and that is not redundancy.
   The rule is what a reader with no JavaScript gets: an ordinary white plate
   with an ordinary 2px ink edge and all four facts visible. The path is what
   replaces it while the line is being drawn — the rule's colour goes
   transparent, never its WIDTH, so the box occupies exactly the same space
   either way and nothing shifts when the script starts or fails to.

   THE ONE EXCEPTION IS DRAWN OUTSIDE IT. The email caveat sits below the seal
   with no edge of its own, in the quieter rank, because that is precisely what
   it is: the thing this band's claim does not cover. Putting it inside the
   boundary would be the page telling a small lie about its own shape.

   Every selector starts #europe. */
@layer page {

/* The seal. `position: relative` is load-bearing: the SVG is absolutely
   positioned against this box and measures itself from it. */
#europe .eu-seal {
  position: relative;
  padding: clamp(1.4rem, 3vw, 2.25rem) clamp(1.5rem, 3.5vw, 2.75rem);
  background: var(--panel);
  border: 2px solid var(--ink);
}
/* WHILE THE LINE IS DRAWING THE BOX, THE LINE IS THE BOX. Colour only — the
   border keeps its 2px, so the plate is the same size whether the script is
   running or not and the perimeter the SVG draws lands exactly on it. */
#europe.is-tracing .eu-seal {
  border-color: transparent;
  background: transparent;
  transition: background 0.5s ease;
}
/* Closed. The inside becomes a surface at the moment it becomes an inside. */
#europe.is-tracing .eu-seal.is-sealed { background: var(--panel); }

#europe .eu-border {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* No viewBox in the markup, so one user unit is one CSS pixel and the path
     can be written in the box's own coordinates. */
  overflow: visible;
  pointer-events: none;
}
/* The page's one stroke: 2px of ink, butt caps, miter joins. The corners are
   square because every corner in this brand is. */
#europe .eu-line {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2;
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

/* ---- The record ------------------------------------------------------------
   Four facts, ruled apart by seams of the DESK showing through the plate —
   #price's receipt drew its compartments the same way, and the idiom outlived
   the band. The seams are invisible until the loop closes, because until then
   there is no white for them to show against. That is correct rather than a
   compromise: an unsealed record is not a document yet. */
#europe .eu-record { margin: 0; }
#europe .eu-fact {
  padding: clamp(1rem, 2vw, 1.5rem) 0;
  border-top: 2px solid var(--bg);
}
#europe .eu-fact:first-child { padding-top: 0; border-top: 0; }
#europe .eu-fact:last-child { padding-bottom: 0; }

/* RANK, NOT A LABEL TREATMENT. The question is a sentence and is set as one:
   11px uppercase here would be a label pretending to be a clause, which is the
   mistake the cue on #primitives records making. The answer carries the weight
   because the answer is the evidence. */
#europe .eu-fact dt {
  font-size: 0.95rem;
  font-weight: 300;
  color: var(--muted);
  margin-bottom: 0.4rem;
}
#europe .eu-fact dd {
  margin: 0;
  max-width: 60ch;
  font-size: clamp(1.05rem, 2vw, 1.35rem);
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}

/* ---- Arriving on the way down ----------------------------------------------
   Each fact is revealed as the stroke draws level with it on the right-hand
   descent. Opacity and transform only, so the box never changes height and the
   distances the script measured stay true while it is using them. */
#europe.is-tracing .eu-fact {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}
#europe.is-tracing .eu-fact.is-in {
  opacity: 1;
  transform: none;
}

/* ---- Outside the seal ------------------------------------------------------
   No border, no fill, the muted rank, and a hairline down its left edge rather
   than a box round it. Everything about it says aside, and the aside is the
   point: this is the one path the claim above does not cover, and the band
   would be dishonest if it were enclosed.
   --ink-subtle is ink at ~46%, the weight the system reserves for a
   de-emphasised rule. */
#europe .eu-outside {
  max-width: 82ch;
  margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;
  padding-left: clamp(1rem, 2vw, 1.5rem);
  border-left: 2px solid var(--ink-subtle);
}
#europe .eu-outside .section-label { margin-bottom: 0.4rem; }
#europe .eu-outside p:last-child {
  margin: 0;
  font-size: 0.92rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--muted);
}
/* The link stays ink rather than muted: it is the one thing in this note the
   reader is meant to be able to act on. */
#europe .eu-outside a { color: var(--ink); }

@media (max-width: 640px) {
  /* The stroke does not thin and the plate does not lose its edge. What gives
     is the air inside it, which is the only thing here a phone is short of. */
  #europe .eu-seal { padding: 1.1rem 1.15rem; }
}

} /* @layer page */

/* ===========================================================================
 * #portability
 * ========================================================================= */
/* LAYER: page — #portability, the portability band on the homepage.

   THE BAND IS PROSE PLUS ONE COMMAND, AND IT IS BUILT THAT SHORT ON PURPOSE.
   Its neighbours carry a pillar readout and a tray; this one carries a date, a
   command and a promise. Padding it to their height would cost the thing that
   makes it read — that it can be taken in at a glance.

   WHY THERE ARE NO CARDS IN IT. The ground is --panel, which the stripe in
   bands.css gives this band for its position rather than for its contents. A
   white cutout has nothing to sit on here, so there is none: the vocabulary is
   ink rules, ink text and one sanctioned dark surface, which is why the
   structure below is drawn entirely with 2px and 4px ink rules and with
   alignment, and why nothing is enclosed.

   THIS BAND HAS NOW BEEN ON BOTH GROUNDS AND NOTHING IN HERE CHANGED. Removing
   the bill above it moved it to the desk; adding #europe moved it back. That is
   the test the vocabulary above was built to pass — rules and alignment read
   the same either way — and it is the reason this band is the cheapest one on
   the page to reorder.

   WHAT CARRIES THE STRUCTURE. One spine. The claim-head's figure column is
   restated at the same 20ch and the same gap by .port-entry, so the band reads
   down its left edge as three answers to one question: 100% PORTABLE,
   12 January 2027 THE LAW, Already DRIFT. The argument of the band — the law
   arrives in 2027, Drift shipped it already — is the vertical relationship
   between two words, not a sentence the reader has to assemble.

   NO TOY AFFORDANCE ANYWHERE IN HERE, and that is a decision. Nothing in this
   band does anything when pressed, and BRAND.html is explicit that a static
   thing which lifts is inviting a click that goes nowhere.

   EVERY SELECTOR STARTS #portability. Four bands are being restyled at once and
   an unscoped class would reach into the others. The one thing this file does
   not restate is `code`: brand.css already paints it as a desk chip with an
   --ink-subtle ring, which is correct on white, and an override would only be a
   second opinion about it. */
@layer page {

/* ---- The ledger: ruled paper, no boxes -------------------------------------
   Three full-bleed 2px ink rules across the content column — above each entry
   and under the last. The rule is the whole separator; there is no fill and no
   frame, because on white a frame would be the only enclosed object in the band
   and would read as a card that had wandered off the desk. */
#portability .port-ledger {
  border-bottom: 2px solid var(--ink);
}

/* The 20ch key column and the clamp() gap are bands.css's .claim-head values,
   restated rather than re-derived: both grids inherit 1rem from the section, so
   20ch resolves to the same pixel in each and the spine actually lines up. If
   .claim-head's track ever changes, this is the second place to change. */
#portability .port-entry {
  display: grid;
  grid-template-columns: minmax(0, 20ch) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
  border-top: 2px solid var(--ink);
  padding: clamp(1.4rem, 2.6vw, 2rem) 0;
}
/* Same breakpoint and the same collapse as .claim-head, so the head and the
   ledger stop being two columns on the same frame rather than 100px apart. */
@media (max-width: 900px) {
  #portability .port-entry {
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    padding: 1.4rem 0;
  }
}

/* ---- The key: when, then who -----------------------------------------------
   The same two-rank object the claim figure is — a display figure with the
   brand's 11px uppercase signpost under it — one size band down, so it reads as
   subordinate to the 100% above it rather than as a second claim.

   A DATE IS A DISPLAY NUMBER, which is what the display face at 700 is for here
   (the claim figure, the bill's total, the free tier's counts). "Already" takes
   the same treatment because it answers the same question the date does, and
   the whole point of the band is that the two answers sit in one column.

   The size tops out at 1.35rem for a measured reason: "12 January 2027" is the
   longest string this column ever holds, and at 1.35rem in Mozilla Text it comes
   to roughly 168px against the track's ~192px. Larger and it wraps. */
#portability .port-mark { min-width: 0; }
#portability .port-when {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.05rem, 1.9vw, 1.35rem);
  line-height: 1.2;
  color: var(--ink);
}
/* .claim-unit's own values — 11px, 600, uppercase, 0.1em, --muted. The unit
   under the figure and the label under the date are the same rank doing the
   same job, so they are the same object rather than two small-caps treatments. */
#portability .port-who {
  display: block;
  font-family: var(--body);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  margin-top: 0.5rem;
}

/* ---- The body of an entry --------------------------------------------------
   bands.css sets .claim p to 70ch with a 1rem bottom margin and zeroes the last
   one. Inside the ledger the spacing belongs to the entry, so the paragraphs
   carry none of their own and the gap between two of them is stated once. */
#portability .port-body { min-width: 0; }
#portability .port-body p {
  max-width: 66ch;
  margin: 0;
  font-weight: 300;
}
#portability .port-body p + p { margin-top: 0.9rem; }

/* ---- The command -----------------------------------------------------------
   brand.css's own pre.code-block: VS Code Dark+ on #1e1e1e, the ONE dark surface
   the brand allows, and the right one here because this band's single piece of
   evidence is a thing you type into a terminal. Nothing is restyled about it
   except its width.

   width: max-content, so the block is the length of the command instead of a
   dark bar ruled across the column — this band was an ink slab once and a
   full-width dark rectangle is how that starts again. Under border-box the
   keyword includes the padding and the 2px border, so the fit is exact.
   max-width keeps it inside a narrow column, where the block's own overflow-x
   from brand.css takes over. */
#portability .port-cmd {
  width: max-content;
  max-width: 100%;
  margin: 0 0 1.1rem;
}
/* The prompt, one rank below the command it introduces. --on-ink-muted is the
   palette's secondary rank for dark grounds and measures 6.8:1 on #1e1e1e;
   --muted is a dark-on-light value and would be 1.4:1 here. Deliberately not
   Atomic orange: the triad names pillars, and a shell prompt is not one. */
#portability .port-prompt { color: var(--on-ink-muted); }

/* ---- The promise -----------------------------------------------------------
   The sentence the band exists for, back at the content column's left edge so
   it closes the band rather than belonging to the last entry.

   The 4px ink rule above it is the mark the claim figure wears at the top of the
   band, spent once more to say "this is the claim, in words" — the hero puts the
   same 4px rule under a headline word. INK AND NOT TRIAD, for the reason
   bands.css gives for the figure's own rule: orange, purple and green name
   Atomic, Backbone and Canvas, and a promise is not a pillar. (This is what
   replaces the .pullout card the band used to close on, whose 6px Backbone
   purple spine was a triad colour spent on something that is not Backbone.)

   600 in the reading face rather than the display face: 700 belongs to display
   numbers and the wordmark, and this is a sentence. It sits well below the h2's
   clamp(1.6rem, 3.2vw, 2.3rem), so the hierarchy is still rank, not size alone. */
#portability .port-promise {
  max-width: 52ch;
  margin: clamp(2.25rem, 4vw, 3rem) 0 0;
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}
#portability .port-promise::before {
  content: "";
  display: block;
  width: 3.5rem;
  height: 4px;
  background: var(--ink);
  margin-bottom: 1rem;
}

} /* @layer page */

/* ===========================================================================
 * #primitives
 * ========================================================================= */
/* LAYER: page — #primitives, "The blocks".
   ==========================================================================

   THE CLAIM: fifteen-plus blocks, four pillars, and you can hold the whole
   catalogue in your head. So the band's job is to SHOW the whole catalogue and
   still look small. It does that with one object — a console: four keys, and
   the white sheet they fill.

   WHAT CHANGED, AND WHY

   1. THE KEYS NOW SIT ON THE THING THEY DRIVE. They used to be buried between
      two paragraphs in the left column while the readout stood in the right
      one, so nothing on the page said the two were connected, and nothing said
      the keys could be pressed at all. The prose moves out and above; the cue,
      the keys and the sheet become one console with one lid.

      THE KEYS ARE A COLUMN BESIDE THE SHEET AGAIN, and that is not the old
      arrangement returning. What was wrong before was not the sides — it was
      that the two sides were tracks of the BAND, holding prose and evidence,
      with a picker dropped into one of them. They are tracks of the CONSOLE
      now: nothing else is in either, the cue spans both and names them, and the
      gap between them is the only thing separating a key from what it prints.
      The sheet still gets ~2x the width it had in the old body column, which is
      what shrinks the reserve: eight Backbone blocks are four rows across
      instead of three rows of a narrow column.

   2. THE RESERVE IS INSIDE A FRAME. The four groups are stacked in ONE grid
      cell (see below), so the column is always as tall as the largest pillar —
      Backbone's eight. Previously that reserve was empty desk with cards
      floating over it, which reads as a hole; now it is white sheet inside a
      2px ink border, which reads as a sheet with room left on it.

   3. THE HUE IS NEVER THE GROUND UNDER A WORD. Every key was filled with its
      pillar's colour, and bands.css recorded the consequence in its own
      comment: Backbone purple takes white at 4.06:1 and ink at 3.61:1, and
      fails AA either way. The colour moves into a fixed 40px cap at the key's
      left edge and the word goes on white at 14.65:1. Nothing is lost by it:
      the cap is a bigger, more comparable block of colour than a tinted word
      was, because it is the same size on "SQL" and on "Backbone".
      (The judged gallery's kill rule cuts the other way too — a hue reduced to
      a 3px foot makes all four badges look alike. A full-height cap is not a
      foot.)

   4. CARDS AFTER ALL, AND THE EDGE IS WHAT MAKES IT SAFE. This was one sheet —
      `.reference-table`'s construction, a white panel behind a 2px ink border
      with rows ruled apart by seams of --bg — chosen because nineteen bordered
      boxes in a grid is a rack of tags.

      It is a grid of cards now, and the thing that was wrong with that is the
      EDGE WEIGHT rather than the count. #free's tray had already answered it:
      many objects sharing one container take --ink-subtle, because "nine at
      full ink would be nine competing edges inside a frame that already draws
      one". At hairline weight the ink plate naming the pillar is the only
      full-strength edge on that side of the console, and the blocks read as its
      contents rather than as nineteen things demanding equal attention.

      The container went with it. There is no frame around the readout at all:
      a plate and its cards sit directly on the band, which is what the two
      argument cards above them already do.

   THE INK PLATE IS NOT A DARK SURFACE. It is a filled label bar naming a set —
   `.reference-table th`, `.alpha-tag`, the announce strip and #price's own
   `table.bill th` are all built exactly this way. The band being an ink slab is
   what was fixed; a 46px plate at the top of a white sheet is the system's
   standing way of marking the active object.

   EVERY SELECTOR STARTS `#primitives`. Four bands are styled by four
   concatenated sheets, and an ID also outranks bands.css's `.claim .prim-*`
   rules (1,0,1 against 0,2,0) without reaching for a layer or !important — so
   everything this band needs is restated here rather than inherited from them.
   ========================================================================== */
@layer page {

/* NO GROUND RULE HERE. bands.css owns it: this band is .claim--panel, first in
   the alternation under the hero, and a second declaration in this file would
   be a rule that has to be found and changed whenever the sequence does. The
   band is white, and its objects are framed rather than tonal (see the sheet
   and the keys below). */


/* ---- The band arrives along the thread --------------------------------------
   Its parts come in one at a time as the reader scrolls, the tag first, at the
   moment the line from the hero reaches it. js/hero-thread.js owns the order and
   the thresholds; this owns what arriving looks like.

   NOTHING IS HIDDEN UNLESS THAT SCRIPT IS RUNNING. Every rule here is under
   `#primitives.is-staged`, and the class is added by the script itself — so a
   page whose JavaScript 404s, is blocked, or throws before this point renders
   the whole band exactly as it would have. Hiding content in a stylesheet and
   revealing it from a script is how a page ends up blank for the readers least
   able to work out why.

   OPACITY AND TRANSFORM, NEVER display OR visibility. Neither of these costs
   layout, so the band occupies its full height from the first paint: the tag
   does not move while the line is aiming at it, the scroll bar does not grow as
   parts arrive, and the thresholds computed from each part's position stay true.

   THE TAG FADES AND DOES NOT RISE, and that is the one exception in here. It is
   no longer load-bearing: js/hero-thread.js measures every landing edge in
   LAYOUT terms, subtracting whatever a part is currently translated by, so a
   line lands on the resting edge whether the part has arrived or not. It used
   not to, and the 8px below was the bug — a line aimed at a box
   getBoundingClientRect reported 8px low ended up 8px inside it.
   The tag stays still because a figure that slides while a line is aiming at it
   reads as a wobble, which is a judgement rather than a constraint. */
#primitives.is-staged .thread-stage:not(.prim-latch) {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}
#primitives.is-staged .claim-stat.thread-stage { transform: none; }
#primitives.is-staged .thread-stage:not(.prim-latch).is-in {
  opacity: 1;
  transform: none;
}

/* ---- The keys break through ------------------------------------------------
   A key is not faded in like the rest of the band. It comes UP THROUGH the
   sheet it sits on: flat and hidden at the surface, punched high above its
   resting height, past it, and settled.

   THE KEYS ARE EXCLUDED FROM THE RULE ABOVE, by :not(.prim-latch), and that is
   load-bearing rather than tidy. A key's resting state IS a transform —
   translateY(-4px) with a 4px shadow under it, the toy affordance — and the
   shared `transform: none` on arrival is a more specific selector than the rule
   that raises it. It would have landed every key flat on the sheet, killing the
   one thing that says they can be pressed.

   FILL MODE IS `backwards`, NOT `both`, for the same reason. `both` holds the
   final frame after the animation ends, which would then outrank :active and
   [aria-pressed="true"] and leave a pressed key still standing up. `backwards`
   only reaches back over the delay; when the animation finishes the key is
   governed by its own rules again, and the last frame matches them exactly so
   nothing jumps. */
@keyframes prim-key-break {
  0%   { opacity: 0; transform: translateY(6px);   box-shadow: 0 0 0 var(--toy-edge); }
  28%  { opacity: 1; }
  55%  { transform: translateY(-15px); box-shadow: 0 15px 0 var(--toy-edge); }
  78%  { transform: translateY(-1px);  box-shadow: 0 1px 0 var(--toy-edge); }
  100% { transform: translateY(-4px);  box-shadow: 0 4px 0 var(--toy-edge); }
}
/* THE ROW IS ONE STAGE AND THE STAGGER IS IN TIME. The picker arrives on a
   single scroll beat and the five keys break through behind it at a fixed
   interval, rather than each waiting for its own scroll. A row of controls is
   one object; assembling it a key at a time by scrolling made it five.

   NO `opacity: 1` ON ARRIVAL, and that is the point rather than an omission.
   The animation carries opacity from 0 to 1 itself, and once it ends the key is
   governed by its own rules again — which is what lets `.picked` dim the keys
   that are not chosen. A staged `opacity: 1` here has the same specificity as
   that rule and would have won or lost on source order, silently, instead of
   the interaction simply working. */
#primitives.is-staged .prim-picker.thread-stage .prim-latch:not(.is-in) { opacity: 0; }

/* NOT CLICKABLE UNTIL IT HAS LANDED. A key that takes a press while it is still
   travelling answers before it looks like it can be answered, and the readout
   changes under a key that has not finished arriving. js/hero-thread.js adds
   .is-settled on that key's own animationend, which is the only thing that
   knows when it is actually down. */
#primitives.is-staged .prim-picker.thread-stage .prim-latch:not(.is-settled) {
  pointer-events: none;
}

/* EACH KEY BREAKS THROUGH AS ITS OWN STUB REACHES IT, and there is no stagger
   here at all any more — not five fixed delays, and not the computed ones that
   replaced them. The bus is scrubbed by scroll (js/hero-thread.js), so the
   moment the line's tip passes a key IS a scroll position, and the script adds
   .is-in to that one key when the reader crosses it. Five separate arrivals,
   paced by the reader.

   THE CLASS IS ON THE KEY, NOT ON THE ROW, which is the whole of the change:
   `.prim-picker.is-in .prim-latch` fired all five off one event and needed a
   delay per key to tell them apart. `.prim-latch.is-in` needs none, because the
   thing that tells them apart is which ones the reader has reached.

   The 110ms is the only number left, and it is not a stagger: it is the head
   start the stub gets, so the line visibly touches the key before the key
   moves. Without it the two start together and the key reads as arriving on its
   own with a line that happens to be nearby. */
#primitives.is-staged .prim-picker.thread-stage .prim-latch.is-in {
  animation: prim-key-break 620ms cubic-bezier(0.2, 0.7, 0.3, 1) 110ms backwards;
}

@media (prefers-reduced-motion: reduce) {
  #primitives.is-staged .prim-picker.thread-stage .prim-latch.is-in {
    animation: none;
    opacity: 1;
  }
}
/* THE LINE ARRIVES FIRST, THEN THE COLUMN IT WAS POINTING AT. Each of the three
   has a branch drawn to its top edge at the same moment it is revealed, and a
   column that fades in alongside its own line reads as two things happening at
   once rather than as one delivering the other. The delay is a little under the
   branch's own 520ms, so the two overlap rather than queue.
   On the way IN only: the rule is on .is-in, and a part is never taken back. */
#primitives.is-staged .prim-lede p.thread-stage.is-in {
  transition-delay: 0.26s;
}


/* ---- The three columns are plates ------------------------------------------
   The argument is drawn as objects, the way the sheet below it already is. It
   is this band's whole job to show a catalogue and still look small, and a
   catalogue drawn as objects reads as one.

   THE PLATES TAKE THE DESK, NOT THE PANEL, and that is the brand's own rule
   rather than a preference. bands.css: a card is a white cutout that needs the
   desk to sit on. This band IS the panel, so a white card on it would be an
   outline around nothing — the fill has to be the other ground. What lands is
   the inverse of #price's receipt: recessed plates on white, instead of white
   cutouts on the desk.

   THE HEAD IS NOT ONE OF THEM, and carries no rule here at all. It takes
   bands.css's shared object unskinned, so its ground is the band's own white
   and it has no edge — the stat's tag is the only object in it, and the thread
   that arrives from the hero lands on that tag rather than on a box around it.
   A transparent background plus a removed border would have been the same
   picture written as two declarations that undo a third; no rule says it once. */
/* MORE AIR UNDER THE HEAD THAN bands.css GIVES IT, because this band's head has
   a line leaving it. The three branches drop out of the tag's bottom edge and
   have to read as a run before they turn; at the shared spacing they were a
   corner with no approach to it. */
#primitives .claim-head { margin-bottom: clamp(3.5rem, 6vw, 5.5rem); }

/* A PLATE AND THE PROSE UNDER IT, not one card with a heading inside it.

   ONLY THE NAME IS AN OBJECT. The head keeps the desk fill and the ink edge; the
   argument gives both up and keeps nothing but its padding, so it reads as
   writing ON the band rather than as a second box. Three plates down the row,
   each naming the text beneath it — which is the band's own vocabulary: the
   sheet below is one ink bar over ruled contents, and #price's receipt is the
   same object again.

   THE PADDING STAYS, AND IT IS WHAT HOLDS THE COLUMN TOGETHER. With the edge
   gone it is the only thing keeping the prose on the plate's own measure; drop
   it and the argument runs wider than the name above it and the card stops
   being one thing.

   The <p> stops being the plate and becomes the pair. It keeps the type — both
   children inherit it — and gives up its fill, its edge and its padding to
   them. */
#primitives .prim-lede p {
  display: flex;
  flex-direction: column;
  /* The seam. 12px, the console's own gap, so every space between two objects
     on this band is one number. */
  gap: 12px;
}
/* The body takes the slack, which is what keeps a row of cards level: the grid
   stretches each <p> to the tallest, and without this the shorter argument
   would leave its gap at the bottom instead of filling its plate. */
#primitives .prim-lede-body { flex: 1; }

/* The name plate. Desk fill and an ink edge, which is bands.css's rule for a
   card on a panel ground and the reason that band's own note gives: this band
   IS the panel, so a white cutout on it would be an outline around nothing. */
#primitives .prim-lede-head {
  background: var(--bg);
  border: 2px solid var(--ink);
  padding: 0.7rem 1.15rem;
  /* brand.css's `.panel-floating`, exactly: 4px 4px 0 var(--ink). A STATIC,
     diagonal, hard-edged shadow, and the brand is explicit that this is the one
     place a horizontal offset is correct — "the toy-raise says press me, this
     says I am on top of the page".
     Which is why it goes on the NAME PLATES and on nothing else here. The keys
     already carry the other vocabulary, `0 4px 0`, directly below them and no
     sideways offset, because they are pressed; a diagonal on those would blur
     two shadows that are saying different things. The argument under each plate
     has no shadow at all, since it is prose on the band rather than an object
     lying on it. */
  box-shadow: 4px 4px 0 var(--ink);
}
/* The argument: padding only, and the 2px is the whole reason it is written as
   a sum rather than as one number. The plate above has a border, so its text
   starts 2px + 1.15rem in from the card's edge; this has no border, and at a
   flat 1.15rem the prose would set two pixels to the LEFT of the name it sits
   under. Adding back the edge it does not draw is what puts the mark, the name
   and the first word of the argument on one left edge. */
#primitives .prim-lede-body {
  padding: 1.05rem calc(1.15rem + 2px);
}
/* ---- Each plate opens with its mark and its name ---------------------------
   The icon and a short title on one line, with the argument starting under
   them. The icon alone said what the plate was about only to a reader who
   already knew; the title says it in words, and the pair reads as the plate's
   own head the way the ink bar is the sheet's.

   FLEX, NOT AN INLINE ICON. The glyph is a 28px block: set inline it would sit
   on the text's baseline, hang below the title's descenders and push the whole
   line down by its own overshoot. A flex row centres the two against each
   other, which is why the icon carries no margin of its own. The space UNDER
   the bar is the card's own gap, not a margin here — a seam between two objects
   belongs to the thing holding both of them. */
#primitives .prim-lede-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
/* A RANK, NOT A HEADING. Same 0.95rem 600 ink as the block names in the sheet
   below, which is the other place this band titles a small thing — so the
   plate's name and a block's name are one object at one size. The band's h2 is
   its heading; three more would be three more claims.
   <b> rather than a heading element for the same reason: this is a span of text
   with a title's typical presentation, not a new section of the document, and
   the plates are paragraphs by construction. */
#primitives .prim-lede-title {
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
}
/* NAMING a term rather than stressing it, which is what <i> is for — the
   argument under it sets the same word in 600 for the opposite reason. Stated
   rather than left to the browser: brand.css ships a reset, so a default is not
   something this file can assume is still there. */
#primitives .prim-lede-title i { font-style: italic; }

/* The object each column's argument is about, at its top left. currentColor, so
   it is the column's ink and follows the theme without this file naming a
   colour. flex-none so a long title cannot squeeze it. */
#primitives .prim-lede-icon {
  display: block;
  flex: none;
  width: 28px;
  height: 28px;
  margin: 0;
  color: var(--ink);
}
#primitives .prim-lede-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}
/* IT ARRIVES WHITE AND SETTLES INTO INK. Fading the whole plate in took the
   icon with it, and a part-faded ink mark on a part-faded desk plate is not a
   quiet icon — it is a washed-out one, which reads as unfinished rather than as
   arriving. Solid --panel on the plate's --bg is a real mark from the first
   frame, and it darkens into place once the plate has landed.

   Only while the band is staged. With no script, or under reduced motion, the
   base rule above stands and the icon is simply ink. */
#primitives.is-staged .prim-lede-icon {
  color: var(--panel);
  transition: color 0.6s ease 0.35s;
}
#primitives.is-staged .thread-stage.is-in .prim-lede-icon { color: var(--ink); }


/* ---- The argument, in two columns of a three-column row ---------------------
   Two paragraphs, no headings and no markers: at the band's full measure each
   column is ~50 characters, which is a reading measure. It collapses to two
   equal columns before the measure gets short, and to one before that.

   THREE TRACKS, TWO PLATES, AND THE EMPTY ONE IS THE POINT. The third column of
   argument was removed and the line the tag sent it was not: it runs down that
   empty cell, past the row, and on to the cue that opens the console. A row of
   three that delivers three things says the band is a list; two plates with a
   line still travelling beside them says it is a route.

   So `repeat(3, ...)` is load-bearing rather than left over. Tightening it to
   two would close the lane and put the line down the margin — js/hero-thread.js
   measures the lane off these two plates and this row's right edge, and gives
   up on it (and routes out of the last plate instead) the moment there is no
   spare cell, which is what the 1100px rule below produces. */
#primitives .prim-lede {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem clamp(1.5rem, 3vw, 3.5rem);
  /* STRETCH, and edited here rather than overridden above. Plates holding
     different lengths of text stop at different heights, which reads as two
     sizes of object instead of one row of them. As `start` this was invisible
     while the columns were bare prose and obvious the moment they got an edge.
     A second rule later in the file would have been the same fix a reader has
     to find twice. */
  align-items: stretch;
  /* The widest gap on the band, and it is carrying two things. The long line
     spends this whole stretch travelling and needs the room to read as a
     journey; and the cue under it opens the console, so it has to read as the
     start of something rather than as one more item in this row. */
  margin-bottom: clamp(4.5rem, 8vw, 7rem);
}
#primitives .prim-lede p {
  max-width: 62ch;
  margin: 0;
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.625;
  color: var(--ink);
}
#primitives .prim-lede strong { font-weight: 600; }
@media (max-width: 1100px) {
  #primitives .prim-lede { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  #primitives .prim-lede { grid-template-columns: minmax(0, 1fr); }
}


/* ---- The console: a lid, a register of keys, and the sheet they fill --------
   Three parts placed on a grid rather than stacked. The cue spans the top; under
   it the five keys stand in ONE COLUMN down the left, and the sheet they fill
   sits beside them, which is where a register's keys are in relation to what
   they print.

   IT WAS A ROW OF KEYS ABOVE A FULL-WIDTH SHEET, and a row across the top of a
   panel reads as a tab bar: five things above the content say "these are
   sections of one document". A column beside it says the keys DRIVE the sheet,
   which is what they do — and pressing one then moves the eye sideways to the
   thing that changed instead of downward past the key that changed it.

   NO WRAPPER IN THE MARKUP. The three are already siblings inside
   .prim-console, so placing them is three `grid-column` declarations rather
   than a div whose only job is to hold two of them. They are stated together,
   here, because the layout is the relationship between all three and reading it
   in one place is the point.

   THE KEY TRACK IS CAPPED, NOT FRACTIONAL. A key is as wide as its longest
   legend needs and no wider; every pixel past that belongs to the sheet, which
   is the object with something to show. The sheet stretches to the taller of
   the two, so the reserve shows as white sheet with room left on it rather than
   as a short panel beside a long row of keys. */
#primitives .prim-console {
  /* THE LANE THE BUS RUNS DOWN, and the one number that opens it. The keys are
     pushed this far right of the console's left edge, which leaves the band's
     own left margin clear for the vertical line from the pillars card — and
     makes every stub off that line exactly this long. The sheet gives up the
     width, which is the trade: the register moves right, the readout narrows. */
  --key-inset: 4rem;
  --key-track: 12rem;

  display: grid;
  /* The first track carries the lane AND the keys, so the two are one
     declaration and cannot drift apart. */
  grid-template-columns:
    minmax(0, calc(var(--key-inset) + var(--key-track))) minmax(0, 1fr);
  /* The row gap is the air under the lid, and it is the widest space inside the
     console on purpose: the cue closes the argument and the register opens the
     demonstration, so the two are separate movements rather than two
     paragraphs. The column gap only has to say "two objects", so it is small. */
  gap: clamp(2.5rem, 5vw, 4rem) clamp(1.25rem, 2.5vw, 2rem);
}
/* THE CARD SPANS BOTH TRACKS AND FILLS NEITHER. It is centred on the band —
   which is centred on the page — and capped well inside it, so there is band
   showing on both sides: the thread arrives on its title bar's right edge and
   the bus leaves from the left, and neither has anywhere to be if the card runs
   the full width.

   Its WIDTH is set in the cue's own block below, not here: this file already
   states `max-width` for it once, and a second copy in a different section is
   how two numbers for one box come to disagree.

   WITHOUT THIS RULE THE CARD IS ONE TRACK WIDE. It is the first child of the
   console, so with no explicit placement it auto-places into the first cell —
   the register's own narrow track — and sits there left-aligned while the keys
   and the sheet arrange themselves in the row beneath. That is not a subtle
   failure, and it is what this rule being dropped looks like. */
#primitives .prim-cue    { grid-column: 1 / -1; justify-self: center; }
/* THE INSET IS NOT SET HERE, and that is the whole reason this note exists. The
   register's own rule further down states `margin`, in shorthand, and a
   shorthand resets every side it does not mention — so a `margin-left` written
   here was silently zeroed by a later rule of equal specificity, the stubs came
   out 0px long, and the bus read as one straight line down the keys' left
   edges. It is part of that shorthand now. */
#primitives .prim-picker { grid-column: 1; }
#primitives .prim-sheet  { grid-column: 2; }


/* ---- The cue: where the long line arrives -----------------------------------
   The same desk fill and ink edge as the plates above it, and the destination
   of the one branch that does not stop in that row. It is the lid on the
   console: what the route was going to all along.

   WIDE, CENTRED, AND STILL INSIDE THE BAND. It used to span the whole content
   column, because a plate narrower than the thing it introduces reads as one
   more item in the row above rather than as the start of the row below. It is
   capped now for a different reason that outranks that one: the thread arrives
   at its title bar from the right and the bus leaves from the left, and neither
   has anywhere to be if the card reaches both margins. It stays far wider than
   a column, so it still cannot be mistaken for one.

   IT HOLDS THE THIRD COLUMN'S ARGUMENT. When that plate was removed the
   sentence in it was not thrown away — primitives talking to each other for you
   is the claim the console then demonstrates, so it belongs on the console's
   own lid rather than in a row the reader leaves behind.

   IT IS THE THIRD CARD, and built as one: the same head, the same fill, the
   same edge and the same body type as the two plates above it, differing only
   in that it spans the band instead of a column. The row of argument is
   therefore three cards in an L rather than a row of three, which is what lets
   the line leave the row and still be going somewhere.

   Nothing leaves its bottom edge, so the space under it is a label's gap and
   not a run for wires. */
#primitives .prim-cue {
  /* THE CARD'S OWN WIDTH, and the one place it is stated. It fills its track up
     to this cap and is centred by the console above, so the band shows on both
     sides of it — which is what the thread arriving on the right edge and the
     bus leaving from the left need in order to exist at all.
     Stated in rem rather than ch, and that is deliberate: a ch cap measures the
     TEXT, and what is being sized here is the plate the text sits on. bands.css
     caps every paragraph in a claim band at 70ch, which is very nearly this
     width by coincidence — leaving it to that rule would make the card's size
     an accident of the reading measure rather than a decision. */
  width: 100%;
  max-width: 64rem;
  /* None of its own: the console's row gap owns the air under the lid, so there
     is one number to change rather than a margin and a gap that have to agree. */
  margin: 0;
  /* THE SAME PAIR THE TWO PLATES ABOVE IT ARE, and by the same rule — the <p>
     is the card, its two children are the objects. It carries no fill, no edge
     and no padding of its own for that reason; .prim-lede-head and
     .prim-lede-body above own all three, for all six plates at once. */
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.625;
  color: var(--ink);
}
/* WHERE THE READING MEASURE LIVES, one level inside the plate rather than on
   it. The plate spans the band, because a lid narrower than the console under
   it reads as one more item in the row above; the TEXT must not, or it sets at
   about 150 characters to the line. Two jobs, two elements.
   78ch is the same cap the codas at the foot of the page take. */
#primitives .prim-cue-lead {
  display: block;
  max-width: 78ch;
}


/* ---- The five keys: THE KEYCAP ---------------------------------------------
   The gallery's `.bdg-key`, at console scale. A moulded coloured cap with a
   hard ink rim, sitting proud of the desk on its own shadow, that goes down
   with a click when you push it — the toy affordance latched, so it STAYS down
   for as long as its pillar is selected, which is the one thing a button does
   not do. Down means selected.

   THE HUE IS THE GROUND UNDER THE WORD NOW, AND THAT IS A REVERSAL. This band
   used to put the colour in a fixed 40px cap at the key's left edge and the
   word on white beside it, on the grounds that white on Backbone purple is
   4.06:1 and fails AA. The keycap's answer is the one the gallery ships with
   the measured numbers attached: the word takes INK on the two fills where ink
   is legible and white on the two where it is not.

     orange  #f1a006   white 2.15   ink 6.82   -> ink
     purple  #8269eb   white 4.06   ink 3.61   -> white
     green   #10b981   white 2.54   ink 5.77   -> ink

   Four of the five clear AA outright. BACKBONE DOES NOT, either way, and no
   arrangement of this key fixes it: brand.css records 3.61/4.06 as "an open
   decision, not something this token settles", and white at 4.06 is what every
   other purple-filled object on the platform already does. It is the same
   divergence the band shipped before, moved from a decorative glyph onto the
   word — which is a real cost and is written down here rather than discovered.
   Colour is never the only channel: the pillar's own icon sits beside the word
   on every key.

   ONE OBJECT, NOT TWO COMPARTMENTS. The cap and the word no longer share a key
   across a 2px rule; the glyph and the name are centred together on one moulded
   face. What still carries across to the plate below is the FILL — press
   Backbone and a purple cap arrives at the head of the sheet — so the
   correspondence is the colour rather than the geometry. */
/* FIVE EQUAL KEYS, STACKED, filling the register's own track. One column of
   identical keys is a keyboard; the flex line this replaces sized each key by
   how long its pillar's name happened to be, which drew five choices of equal
   standing at five different sizes.

   THE REGISTER IS AS TALL AS THE SHEET IT DRIVES. `grid-auto-rows: 1fr` shares
   the column between the five evenly, so the stack ends exactly where the panel
   beside it ends instead of clumping at the top of a taller column with a hole
   underneath. The keys grow; the gaps stay 12px, because a gap is a gap.

   THIS IS SAFE ONLY BECAUSE THE SHEET CANNOT CHANGE HEIGHT, and that is worth
   knowing before anything touches the sheet. Its four groups are stacked in one
   grid cell (see .prim-scroll below), so it is always as tall as the LARGEST
   pillar whichever one is showing. Take that stacking away and the panel starts
   resizing per pillar — and then this rule makes the keys resize with it, so
   pressing one would move the other four under the reader's cursor.

   `1fr` is minmax(auto, 1fr), and the auto floor is each key's own min-height.
   So the taller of the two objects still sets the row: a long register on a
   short pillar list keeps its 52px keys and stretches the sheet instead. */
#primitives .prim-picker {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-auto-rows: 1fr;
  /* THE ROW STILL SPANS THE PANEL; THE KEY NO LONGER FILLS IT. The five rows
     keep dividing the register evenly, so the stack still ends exactly where the
     sheet beside it ends and nothing clumps at the top. What changed is the
     item: `stretch` made every key as tall as its row, so the keys grew with the
     sheet and a key was whatever height the tallest pillar's list happened to
     need. Centred, each key is its own height and the slack becomes air between
     them.
     This is why min-height below is now the height in practice rather than a
     floor that almost never bound. */
  align-items: center;
  gap: 12px;
  /* THE LEFT MARGIN IS THE LANE, and it lives in the shorthand rather than
     beside the placement rules above precisely because it is a shorthand: a
     `margin-left` set anywhere else is reset to zero by this one declaration,
     and the only symptom is that every stub off the bus becomes 0px long. */
  margin: 0 0 0 var(--key-inset);
}
#primitives .prim-latch {
  display: inline-flex;
  align-items: center;
  /* The glyph and the name, centred together on the face. The gap is in em so
     it tracks the key's own type rather than being a pixel that has to be
     re-picked whenever the key is resized — the gallery's `.bdg-key--title`
     sets the same 0.5em for the same reason. */
  justify-content: center;
  gap: 0.5em;
  /* THE HERO CTA'S OWN BOX. brand.css's `.btn-raised` is 52px tall with
     0.75rem/1.25rem of padding, and these keys take both, so a key and the
     button under the headline are the same object at the same size rather than
     two things that merely rhyme.
     It is a real height now rather than the floor it used to be: that 52px was
     a minimum the sheet's own height almost always overrode, so a key was as
     tall as the longest pillar's list made it. The picker centres its items, so
     this is what a key measures.
     TOTAL, border included, and stated as a total because this file sets
     `box-sizing: border-box` nowhere and brand.css's reset does. A height
     written for the content box is the bug that has already cost this codebase
     the navbar CTA and the hero terminal. */
  min-height: 52px;
  padding: 0.75rem 1.25rem;
  font-family: inherit;
  font-size: 0.95rem;
  /* 700 and a whisker of tracking, both the keycap's: a word moulded into a key
     is a legend, not a label, and at 600 on a saturated fill it reads thin. */
  font-weight: 700;
  letter-spacing: 0.01em;
  /* BLANK AT REST, AND THE COLOUR IS WHAT PRESSING ONE BUYS. Every key starts
     as the hero's second button — `.btn-rev`, the "Read the docs" beside "Get
     started" — which is the page's own answer to "a raised button that is not
     the main action". Five identical keys are a keyboard; pressing one is what
     puts a pillar's colour on the console, in two places at once (see the title
     card, which takes the same pair).
     THE LITERAL IS .btn-rev's OWN, not a token, and that file states why: the
     fill is a literal so the label has to be one too, and as var(--ink) this
     read light-on-light at 1.05:1 the moment the palette was re-grounded.
     --on-brand IS that literal, named — ink the colour rather than ink the
     role. */
  background: #f1f1f1;
  color: var(--on-brand);
  border: 2px solid var(--toy-edge);
  border-radius: 0;
  cursor: pointer;
  white-space: nowrap;
  /* Already up, waiting to be pushed. The shadow is hard, directly below and
     --toy-edge; the transform and the shadow are the only two properties that
     move, and neither costs layout, so a press cannot nudge the sheet under
     it.
     6px, THE TOP ROW OF THE SCALE. BRAND.html's toy affordance sets it by the
     object: 6px and a -4px lift for a hero CTA, 4px for cards and selectable
     tiles, 3px for denser chrome and a smaller gesture. These keys are the
     hero CTA's box now, so they take the hero CTA's throw — the same pair
     `.btn-raised` states, rather than a depth picked to look similar.
     6px IS ALSO WHERE THAT SCALE STOPS. Anything deeper is a new tier and
     belongs in BRAND.html before it belongs here. */
  transform: translateY(-4px);
  box-shadow: 0 6px 0 var(--toy-edge);
  transition: transform .07s cubic-bezier(.34, 1.56, .64, 1),
              box-shadow .07s cubic-bezier(.34, 1.56, .64, 1),
              opacity .12s ease;
}
/* The pillar's mark, beside its name on the same face. No cell and no rule
   between the two any more: the key is one moulded object, so the glyph is
   simply the first thing on it.
   Sized in em so it tracks the legend, rather than a pixel that has to be
   re-picked every time the key is resized. */
#primitives .prim-latch .prim-cap {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.35em;
  height: 1.35em;
}
/* THE GLYPH TAKES ITS COLOUR FROM THE KEY, which is the whole reason the icon
   set is drawn in currentColor: one file serves the moulded key and the ink
   plate below without knowing about either. INHERITED rather than set per
   pillar, so a fill that changes cannot leave its icon behind on the old one. */
#primitives .prim-latch .prim-cap svg { width: 100%; height: 100%; }

/* Nothing but a box to stand in. The centring belongs to the key, and a
   `flex: 1` here would hand the label the whole face and push the glyph off
   the centre it shares with it. */
#primitives .prim-latch .prim-label {
  display: flex;
  align-items: center;
}

/* Sized as a share of the cap, for the PLATE — the key's own glyph is set
   above. Kept as the general rule because the plate is where a cap is still a
   compartment with a glyph floated in it. */
#primitives .prim-cap svg {
  display: block;
  width: 58%;
  height: 58%;
}

/* The triad, unreassigned: orange Atomic, purple Backbone, green Canvas. The
   other two are not fourth and fifth hues — they take the two GROUNDS, which is
   the same refusal the file tree makes when it gives Deed no colour. Deed is
   the ink key and Edge the white one, and each takes the other's legend.

   EDGE TAKES THE PANEL: white, the ground the blocks sit on rather than another
   block, fits Edge, which is the surface everything else is reached through.
   On this band, now panel white
   itself, that makes the key the ground with a door drawn on it, held up by the
   2px rim every key wears. BRAND.html is the owner of this mapping and still
   encodes a triad; extending it to five belongs there, and until it does this
   is the page running ahead of the brand document.

   TWO PROPERTIES PER PILLAR, not two rules each: the fill and the colour the
   legend takes on it, from the measured table at the head of this section.

   ON `[data-grp]`, NOT ON THE KEY, and that is what makes one declaration serve
   both halves of the console. The latch in the picker and the group in the
   readout carry the same attribute, so a pillar's pair is stated once and read
   by whichever object needs it — the key when it is pressed, and the title card
   of the pillar that key opened. Writing it on `.prim-latch` meant the card had
   to restate all five, which is the version of this that drifts. */
#primitives [data-grp="a"] { --key-fill: var(--brand-1); --key-ink: var(--ink); }
#primitives [data-grp="b"] { --key-fill: var(--brand-2); --key-ink: var(--panel); }
#primitives [data-grp="c"] { --key-fill: var(--brand-3); --key-ink: var(--ink); }
#primitives [data-grp="d"] { --key-fill: var(--ink);     --key-ink: var(--panel); }
#primitives [data-grp="e"] { --key-fill: var(--panel);   --key-ink: var(--ink); }

/* EDGE'S CARD IS THE DESK WHERE ITS KEY IS THE PANEL, and it is the one pillar
   that needs the two told apart. Edge's colour is a GROUND rather than a hue,
   and the ground it was given is white — which works on a key, a small object
   held up by the 2px rim every key wears among four coloured siblings. A title
   card the width of the console cannot be held up that way: this band IS panel
   white, so a white card on it is an outline around nothing, the same failure
   every other object here takes the desk to avoid.
   So the card takes the desk. It is still the ground rather than a hue, which
   is the whole of what Edge's colour is saying. Scoped to `.prim-grp` so the
   key keeps the panel it is legible on. */
#primitives .prim-grp[data-grp="e"] { --key-fill: var(--bg); }

/* No hover raise: raised-at-rest has exactly two positions, up and pressed, and
   this starts in the first. If height means selected, height must not also mean
   "the pointer is here". */
#primitives .prim-latch:active,
#primitives .prim-latch[aria-pressed="true"] {
  transform: translateY(0);
  box-shadow: 0 0 0 var(--toy-edge);
}
/* THE PRESSED KEY IS THE ONLY COLOURED ONE. Down AND in its pillar's colour,
   where the other four are down in neither — so selection is carried twice over
   by two things that cannot disagree, since the same attribute drives both.
   `:active` is deliberately NOT here. A key flashing its pillar's colour under
   the finger and dropping back to blank on release would promise a selection
   the click then takes away; the colour arrives when the state does. */
#primitives .prim-latch[aria-pressed="true"] {
  background: var(--key-fill, var(--panel));
  color: var(--key-ink, var(--ink));
}
/* NOTHING RECEDES ANY MORE. Four keys used to dim to 0.45 when a fifth was
   chosen, because every key wore its colour at rest and position alone could
   not carry the selection. The unchosen four are blank now, so dimming them
   would say the same thing a second time and read as disabled rather than as
   unselected. js still toggles `.picked` on the picker; no rule reads it. */
#primitives .prim-latch:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 2px;
}


/* ---- The readout: A TITLE CARD, THEN THE BLOCKS AS STAT CARDS ---------------
   Every object here is one this band already owns, reused rather than drawn:

     THE TITLE CARD is the lede plate (.prim-lede-head) at full width — desk
     fill, 2px ink edge, and brand.css's `.panel-floating` diagonal shadow. It
     is the same object "The five pillars" is drawn on directly above, which is
     what makes the pair read as a lid and the thing the lid names. It carries
     the pillar's mark and name, the sentence that says what the pillar is for,
     and a way into that pillar's documentation.

     EACH BLOCK IS THE STAT CARD, bands.css's `.claim-stat` — the one the band's
     own "15+ building blocks" is drawn on. A bordered box with the figure
     centred in it and a filled lip across the bottom carrying a label in the
     brand's 11px uppercase. The mark takes the figure's place and the block's
     name takes the lip's, so the card says what it is the way every other stat
     on this page does.

   ONE DEVIATION FROM .claim-stat, and it is this band's own rule rather than a
   preference: the fill is --bg, not --panel. `#primitives` is `.claim--panel`,
   so the band IS white — a white card on it is an outline around nothing, which
   is what .prim-lede-head's note says in as many words and why every other
   object on this band takes the desk. The border, the lip and the geometry are
   the stat card's unchanged.

   WHAT THIS DROPS is the description that used to sit beside each name. The
   cards are a catalogue of what a pillar HAS; the sentence explaining the
   pillar moved up to the title card, where it is said once instead of nineteen
   times. The per-block text is still in the markup for assistive technology —
   see .prim-desc. */
#primitives .prim-sheet {
  line-height: 1.5;
}

/* IT RESERVES THE TALLEST PILLAR BY STACKING, not by holding a number. All four
   groups sit in one grid cell, so the sheet is always exactly as tall as the
   largest of them and switching pillars moves nothing on the page. Stacking
   cannot go stale either: add a ninth block and the reserve grows with it. */
#primitives .prim-scroll { display: grid; }
#primitives .prim-grp {
  grid-area: 1 / 1;
  display: grid;
  /* AS MANY CARDS AS FIT, and the track decides rather than a column count.
     auto-fill with a floor, so the row reflows on its own when the console
     narrows and no breakpoint has to restate a number that the width already
     knows. 8.5rem is the floor that keeps the longest lip — SCHEDULES, at 11px
     with 0.08em of tracking — on one line inside its card. */
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  /* 12px, the band's one spacing number: the seam between two cards is the seam
     between two keys and between a name plate and its argument. */
  gap: 12px;
  /* The cards sit at the top of the reserved cell. Every pillar shares one grid
     area so the cell is as tall as Backbone's eight; a short pillar leaves that
     space empty rather than stretching four cards down it. */
  align-content: start;
}

/* OFF IS A CLASS, NOT THE `hidden` ATTRIBUTE, and that is load-bearing.
   brand.css declares `[hidden] { display: none !important }` deliberately, so a
   layout rule cannot silently disable the attribute. For IMPORTANT declarations
   the layer order REVERSES, so that rule in @layer brand beats anything this
   file can write in @layer page, `!important` included. An element hidden by
   the attribute is out of flow and cannot hold the reserve, whatever is written
   here — and the sheet would then jump between Backbone's eight blocks and
   Canvas's one.
   `visibility` keeps the box, which IS the reserve, and still keeps the rows
   out of the accessibility tree, which is the half `hidden` was there for. */
#primitives .prim-scroll.off,
#primitives .prim-grp.off { visibility: hidden; }


/* ---- The title card: which pillar, what it is for, and the way in -----------
   THE LEDE PLATE AT FULL WIDTH. Desk fill, 2px ink edge, and the diagonal
   `4px 4px 0` shadow brand.css calls `.panel-floating` — the same object "The
   five pillars" is drawn on at the top of this console, and the brand is
   explicit that the diagonal is the one place a horizontal offset is right:
   "the toy-raise says press me, this says I am on top of the page". A lid and
   the card it names, drawn as the same kind of thing.

   IT IS NOT THE KEYS' VOCABULARY, deliberately. The keys carry `0 6px 0`,
   directly below and no sideways offset, because they are pressed. Giving this
   the same shadow would say it is pressable, which it is not, and blur two
   shadows that mean different things.

   FOUR SLOTS ON TWO ROWS, named rather than counted, because the row is not a
   simple sequence: the mark and the name sit at the left of the first row, the
   way into the docs at its right, and the sentence runs under both. */
#primitives .prim-hdr {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 34px auto minmax(0, 1fr) auto;
  grid-template-areas: "mark name . link";
  align-items: center;
  gap: 0.7rem;
  margin: 0;
  /* 0.7rem/1.15rem, which is .prim-lede-head's own padding. This is that plate
     now: one row naming a thing, with its argument below in a second object. */
  padding: 0.7rem 1.15rem;
  /* THE PILLAR'S OWN COLOUR, the same pair the key that opened it took. One
     press puts a hue in two places at once: under the finger, and on the card
     that answers it across the console. The pair is declared once on
     `[data-grp]` and read here through the group, so the two can never be
     showing different pillars.
     The fallback is the desk, which is what this card was before it carried a
     colour and what an unknown `data-grp` still gets.

     MEASURED, ON THE FILL EACH ONE ACTUALLY TAKES. Normal text wants 4.5:1:

       Atomic    amber  + ink     6.82   AA
       Backbone  purple + white   4.06   UNDER
       Canvas    green  + ink     5.77   AA
       Deed      ink    + white  14.65   AA
       Edge      desk   + ink    11.31   AA

     BACKBONE IS THE ONE TO KNOW ABOUT, and it is BRAND.html's own recorded
     divergence rather than something introduced here: on purple, white is 4.06
     and ink is 3.61, so neither clears and white is the closer of the two. What
     is new is the JOB. That divergence was accepted for a badge — one word, 700,
     on a small fill. This card gives it a whole sentence at 0.92rem, which is
     the same ratio doing harder work. The weight went 300 -> 400 to claw back
     some of it perceptually; the ratio itself cannot move without moving
     --brand-2, which belongs to the brand document and not to this file. */
  background: var(--key-fill, var(--bg));
  border: 2px solid var(--ink);
  box-shadow: 4px 4px 0 var(--ink);
  font-size: 1rem;
  font-weight: 300;
  text-transform: none;
  letter-spacing: normal;
  color: var(--key-ink, var(--ink));
}
/* THE MARK, AND NOTHING UNDER IT. It used to be a filled square carrying the
   pillar's hue, because the card it sat on was the desk and the cap was the one
   thing saying which pillar had opened. The CARD carries the hue now, so a
   filled cap would be the pillar's colour on the pillar's colour — invisible on
   three of the five and a seam on the other two.
   So it is the lede plates' bare glyph after all: a mark in whatever ink the
   surface takes, inherited rather than set, which is what `currentColor` in the
   icon files has been waiting for. */
#primitives .prim-hdr .prim-cap {
  grid-area: mark;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  color: inherit;
}
/* 20px in a 34px cap, which is the lede plates' own ratio of glyph to plate one
   size down. Fixed rather than a percentage so re-sizing the cap does not
   silently re-scale the mark with it. */
#primitives .prim-hdr .prim-cap svg { width: 20px; height: 20px; }

/* THE PILLAR'S NAME, at the lede plates' own title size: 0.95rem 600 ink. The
   same object at the same size as "Back to the basics" and "The five pillars"
   above it, because it is doing the same job on the same kind of plate — and
   the 12px uppercase it used to wear belonged to a filled ink bar, where a name
   is a label on a fill rather than a title on a card. */
#primitives .prim-pillar {
  grid-area: name;
  padding: 0;
  font-size: 0.95rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
  line-height: 1.2;
  /* INHERITED, not stated. The card decides what ink it takes from the pillar
     showing on it; a literal --ink here would be right on three fills and
     unreadable on Deed's. */
  color: inherit;
}
/* ---- The brief: WHAT THE PILLAR IS FOR, on its own card --------------------
   It was the second row of the head card. Two objects now, which is the pair
   this band already draws twice above: .prim-lede-head names a thing and
   .prim-lede-body argues it, and the naming plate is the one that floats.

   SO THE BRIEF TAKES THE DESK, NOT THE PILLAR'S COLOUR, and that is the half of
   this worth arguing. The hue's job is to say WHICH pillar, and the head card
   says that already — mark, name and the way in, all in the pillar's colour.
   Colouring the prose as well spends the hue twice on one answer and puts a
   sentence on a saturated fill for no reading benefit.
   It also settles the one measurement that did not clear. On the joined card
   Backbone's sentence sat on purple at 4.06:1, under AA, carrying a whole
   paragraph on a divergence that BRAND.html accepted for a badge. Here every
   pillar's prose reads ink on desk at 11.31:1, and the 4.06 is back to what it
   was accepted as: a short name on a coloured plate.

   NO SHADOW. .prim-lede-body has none either, and its note gives the reason
   this follows: the diagonal says "I am on top of the page", which is the
   naming plate's claim and not its argument's. The border alone makes it a
   card; the head above it is the one lying on the band. */
#primitives .prim-brief {
  grid-column: 1 / -1;
  /* THE CARD IS A <p>, AND bands.css CAPS EVERY PARAGRAPH IN A CLAIM BAND AT
     70ch. That cap is right for prose sitting directly on a band and wrong for
     a card that happens to be made of a paragraph: it left this one visibly
     narrower than the head card above it, both on `grid-column: 1 / -1` and
     only one of them actually spanning. Nothing announces it — the rule is two
     files away and applies on the element name.
     `none` rather than a number, because the span is the grid's to decide.
     The measure it was protecting is not lost: it moved inside, onto
     .prim-brief-lead, which is the same two-jobs-two-elements split .prim-cue
     makes against the same rule. */
  max-width: none;
  margin: 0;
  /* The 2px is added back for the same reason .prim-lede-body adds it: the card
     above has a border, so its text starts 2px + 1.15rem in from the edge, and
     a flat 1.15rem here would set the prose two pixels to the LEFT of the name
     it sits under. */
  padding: 0.95rem calc(1.15rem + 2px);
  background: var(--bg);
  border: 2px solid var(--ink);
  font-size: 0.92rem;
  font-weight: 300;
  text-transform: none;
  letter-spacing: normal;
  line-height: 1.55;
  color: var(--ink);
}
/* WHERE THE READING MEASURE LIVES, one level inside the card rather than on it,
   exactly as .prim-cue-lead does for the lid. The card spans the readout,
   because a brief narrower than the cards under it would read as one more item
   in the grid; the TEXT must not, or it sets at about 150 characters to the
   line on a wide console. Two jobs, two elements. */
#primitives .prim-brief-lead {
  display: block;
  max-width: 78ch;
}
/* THE WAY IN. A quiet text link rather than a button: the band's one call to
   action is the hero's, and a filled control here would compete with the five
   keys for what to press. The arrow slides on hover, which is the same
   affordance the announce bar's "Read our story" uses — one gesture for "this
   goes somewhere", stated in two places.
   Edge carries no link at all, because it has no docs page yet. See the markup:
   the anchor is simply absent rather than pointing at a 404. */
#primitives .prim-docs {
  grid-area: link;
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  color: inherit;
  text-decoration: none;
}
#primitives .prim-docs .prim-docs-arrow {
  display: inline-block;
  transition: transform 0.2s cubic-bezier(0.2, 0.7, 0.2, 1);
}
#primitives .prim-docs:hover { text-decoration: underline; }
#primitives .prim-docs:hover .prim-docs-arrow,
#primitives .prim-docs:focus-visible .prim-docs-arrow { transform: translateX(4px); }
#primitives .prim-docs:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  #primitives .prim-docs .prim-docs-arrow { transition: none; }
}


/* ---- The blocks: one card each ----------------------------------------------
   A term and its meaning, on the same object the argument above is drawn on:
   desk fill on the band's panel white, which is bands.css's rule for a card
   here and the reason that band's note gives — this band IS the panel, so a
   white cutout would be an outline around nothing.

   THE EDGE IS A HAIRLINE, AND THAT IS THE WHOLE REASON A GRID OF THESE WORKS.
   --ink-subtle is ink at ~46%, the weight #free's tray already reserves for
   exactly this situation: "nine at full ink would be nine competing edges".
   Eight of Backbone's blocks at 2px of solid ink would be a rack of tags, which
   is the failure this band's header note recorded when it chose one sheet over
   nineteen cards. At hairline weight the ink plate above stays the only
   full-strength edge on this side, so it still reads as the thing that names
   the rest.

   Two kinds of text, so a column says so — more quietly than a second font
   would. The name column is fixed so the names line up down each half of the
   grid; the widest of the nineteen ("Schedules") is about 74px in it.

   NO SEAMS ANY MORE. The 2px --bg borders that ruled the old sheet into
   compartments are gone with the sheet: the gap between two cards is the
   separation now, and a drawn line between two objects that already have edges
   is the same division stated twice. */
/* THE BLOCK CARD — bands.css's `.claim-stat`, at catalogue scale.
   The stat card is a bordered box with something large centred in it and a
   filled lip across the bottom naming it. The mark takes the figure's place and
   the block's name takes the lip's, so this band says "Functions" the same way
   it says "15+ building blocks".
   `overflow: hidden` is copied with intent rather than by habit: it is what
   keeps the lip square to the box's own corners. Without it the lip's fill
   paints over them, and a 2px border with a filled strip behind it reads as a
   misprint rather than as a closed edge — which is the stat card's own note. */
#primitives .prim-row {
  display: flex;
  flex-direction: column;
  /* --bg where .claim-stat takes --panel, and that is this band's rule rather
     than a deviation: `#primitives` is `.claim--panel`, so the band is white and
     a white card on it is an outline around nothing. Every other object here
     takes the desk for the same reason. */
  background: var(--bg);
  border: 2px solid var(--ink);
  overflow: hidden;
}
/* THE FIGURE'S PLACE, holding the pillar's mark. It takes the slack so every
   card in a row is the same height however the lips below them wrap, which is
   what `.claim-figure`'s own generous padding does on a card that stands
   alone. */
#primitives .prim-mark {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.15rem 0.75rem;
  /* currentColor, like every other mark on this band, so one icon file serves
     the card without this file naming a colour. */
  color: var(--ink);
}
#primitives .prim-mark svg { display: block; width: 34px; height: 34px; }

/* THE LIP. Every value is .claim-unit's — 11px, 600, uppercase, 0.08em, --panel
   on an ink fill — because it is the same object doing the same job one scale
   down, and the brand's structural signpost is one set of numbers rather than
   an approximation per surface. */
#primitives .prim-name {
  display: block;
  margin: 0;
  background: var(--ink);
  font-family: var(--body);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-align: center;
  color: var(--panel);
  padding: 8px 10px;
}
/* THE DESCRIPTION IS KEPT AND NOT SHOWN. The card is a mark and a name; the
   sentence that explains the pillar is on the title card now, said once. These
   nineteen are still real content though, so rather than delete them they stay
   as each card's accessible text — a screen reader still hears "Functions,
   serverless compute in six languages" where a sighted reader sees the mark and
   the lip.
   The clip pattern rather than `display: none` or `visibility: hidden`, both of
   which take it out of the accessibility tree as well, which is the one thing
   this must not do. */
#primitives .prim-desc {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* ---- The arrival -----------------------------------------------------------
   Revealed lines rise into place, staggered down the sheet. js sets --i on the
   plate and on each row, capped at 8, and adds `.arrives` to the scroller.
   Colourless on purpose: the plate already carries the pillar's colour, and
   tinting the rows as well would say it twice.
   The keyframes are named for this band rather than reusing bands.css's, so the
   animation cannot change under this file when that one does. */
@keyframes prim-blocks-arrive {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* THE CARD IS A BOX AGAIN, so the stagger is back on the row itself — which is
   also where js/hero-primitives.js sets --i, so the two agree without either
   knowing about the other. The brief is a third object in the sequence and
   takes its own place in it; the script hands it an --i between the head card's
   and the first block's. */
#primitives .prim-scroll.arrives .prim-hdr,
#primitives .prim-scroll.arrives .prim-brief,
#primitives .prim-scroll.arrives .prim-row {
  animation-name: prim-blocks-arrive;
  animation-duration: 240ms;
  animation-timing-function: cubic-bezier(.2, .7, .3, 1);
  animation-fill-mode: backwards;
  animation-delay: calc(var(--i, 0) * 32ms);
}


/* ---- Narrower ---------------------------------------------------------------
   Nothing is hidden at any width: every block, every description and every
   pillar's sentence is a fact the band is making a claim about. What changes is
   how many columns carry them. */

/* THE CARD GRID NEEDS NOTHING HERE. `repeat(auto-fill, minmax(8.5rem, 1fr))`
   already reflows on the track it is given, so the number of cards across is a
   consequence of the width rather than a number restated per breakpoint. What
   still has to be said is what the CONSOLE does, which is below. */
@media (max-width: 900px) {
  /* THE CONSOLE STOPS BEING TWO COLUMNS. A 15rem key track beside a sheet is
     most of a phone spent on the keys, so the three parts go back to a stack:
     lid, keys, sheet. The row gap tightens with it — 4rem of air between three
     objects reading down one column is a scroll rather than a separation. */
  #primitives .prim-console {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.75rem;
  }
  #primitives .prim-cue,
  #primitives .prim-picker,
  #primitives .prim-sheet { grid-column: 1; }

  /* AND THE KEYS GO BACK TO A WRAPPING ROW. Stacked, five full-width keys are
     five 52px bars down a phone before the sheet they drive is even on screen.
     Wrapped, they are two lines of content-width keys sitting directly above
     it — the tab-bar reading the column exists to avoid, which is the right
     trade at a width where there is no beside to be. The ragged right edge is
     the honest failure: every key stays legible and stays pressable. */
  #primitives .prim-picker {
    display: flex;
    flex-wrap: wrap;
  }
}

/* The plate stacks: the cap becomes a full-height spine down its left edge and
   the three ranks read down the bar. `span 3` rather than `1 / -1` — with no
   explicit rows declared, `-1` resolves to the first line and the spine would
   cover one rank instead of all three. */
/* THE LINK DROPS TO ITS OWN LINE. Right-aligned beside the name, it and a long
   pillar sentence are competing for a row that is no longer wide enough for
   both — and squeezing "Read the docs" is worse than giving it the line under
   the card's own text, where it reads as the card's closing move. */
@media (max-width: 760px) {
  #primitives .prim-hdr {
    grid-template-columns: 34px minmax(0, 1fr);
    grid-template-areas:
      "mark name"
      "link link";
    align-items: center;
    row-gap: 0.55rem;
  }
  #primitives .prim-docs { justify-self: start; }
}

/* TWO CARDS ACROSS ON A PHONE, and the floor is what decides it. 8.5rem is
   comfortable on a console track and leaves a 320px screen room for one card
   and a wide gutter; 6.5rem fits two, which is what a catalogue wants to look
   like at any width. The mark comes down with the card so the proportion of
   glyph to lip holds. */
@media (max-width: 640px) {
  #primitives .prim-grp {
    grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
  }
  #primitives .prim-mark { padding: 0.9rem 0.5rem; }
  #primitives .prim-mark svg { width: 28px; height: 28px; }
}


@media (prefers-reduced-motion: reduce) {
  #primitives .prim-latch { transition: none; }
  #primitives .prim-scroll.arrives .prim-hdr,
  #primitives .prim-scroll.arrives .prim-brief,
  #primitives .prim-scroll.arrives .prim-row { animation: none; }
}

} /* @layer page */

/* ===========================================================================
 * #free
 * ========================================================================= */
/* LAYER: page — #free, the free-tier band. Scoped to the id throughout, because
   four bands are styled by four sheets that are concatenated: an unscoped
   `.free-tray` here would be a rule about somebody else's band.

   WRAPPED IN @layer page. brand.css declares the order `brand, site, component,
   page` and states the rule this file would otherwise break: UNLAYERED STYLES
   BEAT EVERY LAYER, so a sheet left out of one silently outranks every shared
   component it borrows from.

   WHAT THIS BAND IS MADE OF, AND WHY. Its ground is --bg, the desk, which is
   exactly what a white cutout needs to sit on. The nine allowances sit in a
   TRAY — a 2px ink frame — with each allowance a white ticket lying on it and
   the seams between them the ground showing through. Paper on a desk.

   THE TRAY ITSELF DOES NOT STEP AWAY FROM THE BAND, and that is what the
   positional stripe costs here. The tray's fill is --bg and so is the band, so
   the two are the same value and the ink frame is the only thing saying where
   the tray stops. That is why the frame is load-bearing rather than trim, and
   why it must not be softened to a hairline: take the edge away and the tray is
   not a quieter object, it is no object at all.

   IT SPENT ONE REVISION ON WHITE, while the bill was out of the page and before
   #europe went in, and the debt lifted for exactly as long as that lasted. Do
   not plan around it lifting again. bands.css states the trade in full. */
@layer page {

/* ---- The two columns -------------------------------------------------------
   The band's own split: prose left, the tray right. Slightly wider on the right
   than the shared 1fr / 1.15fr, because three tickets across need the width and
   two paragraphs do not.
   The narrow rule is RESTATED rather than inherited. bands.css collapses
   .claim-cols at 900px with a one-class selector, and an id beats it at every
   width — a media query does not add specificity, so leaving that out would pin
   two columns onto a phone. */
#free .claim-cols { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.25fr); }
@media (max-width: 900px) {
  #free .claim-cols { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Beyond free -----------------------------------------------------------
   The turn in the argument — the Slice you are given, then what happens when it
   is not enough — drawn as the page's own structural line plus the brand's 11px
   signpost. A rule and a label rather than a second heading, because the band
   already has one h2 and this is a division inside a column, not a new claim. */
#free .free-next {
  border-top: 2px solid var(--ink);
  margin-top: 0.75rem;
  padding-top: 1.1rem;
}
/* .section-label is a <p> here, so it arrives carrying .claim p's 1rem of space.
   A label belongs to the thing under it. */
#free .free-next .section-label { margin-bottom: 0.35rem; }

/* ---- The two keys ----------------------------------------------------------
   The toy affordance, latched — the same object the pillar picker uses a band
   above, because these keys do the same job: down means selected.

   Raised at rest with a hard ink shadow directly beneath, and the selected one
   PRESSED FLAT and filled with ink: ink-on-white is how this brand marks the
   active object, so the key you are reading is both the low one and the dark
   one. No hover raise — raised-at-rest has exactly two positions, and spending
   one of them on "the pointer is here" would leave height meaning two things.

   Every property the old plain-text tab set is restated rather than assumed:
   these buttons keep the class js/hero-hacker.js selects on, so bands.css's
   `.claim .hacker-tab` rules still reach them and the id is what wins. */
#free .free-keys {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0 0 1.25rem;
}
#free .hacker-tab {
  display: inline-flex;
  align-items: center;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--panel);
  border: 2px solid var(--toy-edge);
  border-radius: 0;
  padding: 0.5rem 0.85rem;
  cursor: pointer;
  transform: translateY(-4px);
  box-shadow: 0 4px 0 var(--toy-edge);
  transition: transform .07s cubic-bezier(.34, 1.56, .64, 1),
              box-shadow .07s cubic-bezier(.34, 1.56, .64, 1),
              background .08s ease, color .08s ease;
}
/* The "> " marker the plain-text tabs wore is gone with the plain text: the key
   is now a physical object, and an object does not also need a cursor drawn on
   it. Stated explicitly because that content lives on `.claim .hacker-tab.active
   ::before`, which this has to outrank rather than merely follow. */
#free .hacker-tab::before { content: none; }
#free .hacker-tab:active,
#free .hacker-tab.active {
  transform: translateY(0);
  box-shadow: 0 0 0 var(--toy-edge);
}
/* The fill is --ink, so the label is what --ink is not. */
#free .hacker-tab.active {
  background: var(--ink);
  color: var(--panel);
}
#free .hacker-tab:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 2px; }

/* ---- The reserve -----------------------------------------------------------
   Both views occupy the SAME grid cell, so the cell measures the taller of them
   and switching keys cannot move the page. The pillar readout stacks its four
   groups for the same reason, and the reason is that a stack cannot go stale:
   add a tenth idea, or a label that wraps to three lines, and the reserve grows
   with it where a shared min-height would have to be re-measured by hand.

   HIDDEN WITH `visibility`, NEVER WITH `display: none` OR THE `hidden`
   ATTRIBUTE. An element that is display:none is out of flow and cannot hold the
   reserve; brand.css's `[hidden] { display: none !important }` cannot be
   overridden from here at all, because layer order REVERSES for important
   declarations. `visibility: hidden` keeps the box and still takes the rows out
   of the accessibility tree, which is the half the attribute was there for.

   The view is a grid rather than a block so its tray stretches to the full cell
   height without a percentage to resolve — both trays then draw exactly the same
   rectangle whichever key is down. */
#free .free-stack { display: grid; }
#free .hacker-view {
  display: grid;
  grid-area: 1 / 1;
  visibility: hidden;
}
#free .hacker-view.active { visibility: visible; }

/* ---- The tray --------------------------------------------------------------
   A framed patch of the desk with the tickets lying on it. `grid-auto-rows: 1fr`
   rather than a row template: the rows share the cell's height evenly at any
   column count, so the shorter view fills the reserve instead of leaving a gap
   inside its frame, and the two-column layout below needs no second number. */
#free .free-tray {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: 8px;
  padding: 8px;
  margin: 0;
  list-style: none;
  background: var(--bg);
  border: 2px solid var(--ink);
}
@media (max-width: 560px) {
  #free .free-tray { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* One ticket per allowance: white paper on the desk, at the hairline weight the
   system reserves for when many objects share one container. Nine at full ink
   would be nine competing edges inside a frame that already draws one.
   No lift and no shadow — a ticket is read, not pressed, and a static object
   that rises under the cursor is promising a click that goes nowhere. */
#free .free-ticket {
  display: flex;
  /* The <dt> is written first because the label is the term and a mapping reads
     "Atomic functions: 5"; the ticket reverses it so the FIGURE is what the eye
     lands on and the label sits under it. */
  flex-direction: column-reverse;
  justify-content: center;
  gap: 0.25rem;
  background: var(--panel);
  border: 2px solid var(--ink-subtle);
  padding: 0.8rem 0.85rem;
  overflow-wrap: break-word;
}
/* A display number, 700, in the face the brand keeps for them — the same object
   as the claim figure above it and the bill's total in the price band. */
#free .free-num {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.3rem;
  line-height: 1.05;
  color: var(--ink);
}
/* Rank, not hue: 300 muted under 700 ink, both at the ticket's own size. */
#free .free-label {
  font-size: 0.76rem;
  font-weight: 300;
  line-height: 1.35;
  color: var(--muted);
}
/* An idea has no figure, so the ticket holds one line of body text centred in
   the same box. Left-aligned, so both views share one left edge down the tray. */
#free .free-ticket.free-idea {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  font-size: 0.9rem;
  font-weight: 300;
  line-height: 1.35;
  color: var(--ink);
}

@media (prefers-reduced-motion: reduce) {
  #free .hacker-tab { transition: none; }
}

} /* @layer page */

/* ===========================================================================
 * The codas
 * ========================================================================= */
/* LAYER: page — the closing paragraph on the two bands that ended cold.
 *
 * #portability closes on .port-promise; #primitives ended on its readout and
 * #free on its tray, so those two simply stopped where their evidence ran out.
 * These give them a stated point to land on.
 *
 * THE GEOMETRY IS INHERITED FROM A BAND THAT NO LONGER EXISTS. It was #price's
 * .price-coda — full width under a 2px ink rule, 78ch, clamped display size at
 * 300 — and these two were written to carry it exactly rather than invent a
 * third closing treatment. #price is gone and the measurements stay, which is
 * fine: they are the page's closing object now, and this is the only place they
 * are stated.
 *
 * ONE RULE NAMING TWO BANDS, which is the one place in this file a selector
 * reaches outside a single band's block. The alternative is the same six
 * numbers written twice, and two copies of a measurement drift the first time
 * either is touched. It is still scoped by id at both ends, so neither band can
 * reach into the other. */
@layer page {

#primitives .prim-coda,
#europe .eu-coda,
#free .free-coda {
  max-width: 78ch;
  margin: clamp(2rem, 4vw, 3rem) 0 0;
  padding-top: 1.5rem;
  border-top: 2px solid var(--ink);
  font-size: clamp(1.05rem, 1.9vw, 1.3rem);
  font-weight: 300;
  line-height: 1.45;
  color: var(--ink);
}
#primitives .prim-coda strong,
#europe .eu-coda strong,
#free .free-coda strong { font-weight: 600; }

} /* @layer page */

