/* ---------- port overrides ----------
   Deliberate deviations from the design kit, kept OUT of the kit's own files so
   `site.css`, `note.css` and `tokens/` stay diff-able against the next export.
   The contract lists site.css as must-ship-byte-identical, so anything that
   would edit it lands here instead.

   Every rule in this file is a bug the kit has, not a taste change, and each one
   is owed back to Claude Design. Loaded last, after every kit stylesheet.
   ==================================================================== */

/* THE STAGE KEY'S KIND ROWS INHERIT A FILL THEY WERE MEANT TO REFUSE.
   `--lvl` is registered with `inherits: true`, and `.hkey` carries this page's
   `data-stage`, so every `.mk` inside the panel that does NOT set a stage of its
   own inherits the page's level. The four rows under "What it keeps" therefore
   render part-filled (26% on a steeping note, 100% on a poured one) when the
   kit's own comment beside them says the opposite: "THE CUPS ON THIS SIDE ARE
   EMPTY, and that is the point: kind and stage are different questions, and a
   filled cup beside Musing would answer the one this section is not asking."

   Measured before fixing: hkey at 26%, and all four kind marks at 26% with no
   `data-stage` on any of them. The kit's preview has the same structure, so this
   is a kit bug and not a port slip. Chris read it as the panel looking busy,
   which is exactly what a second axis leaking into the first looks like.

   Scoped with the kit's own idiom for "the kind side, not the ladder", the same
   selector shape it uses to kill the hover pour there. */
.sksecw:not(.stages) .skr .mk { --lvl: 0%; }

/* THE COLOPHON RULE IS SHORTER THAN EVERY OTHER RULE ON THE NOTE PAGE.
   `--measure: 70ch` is declared once on `.note`, but a custom property is
   substituted and only THEN computed on the element using it, so `ch` resolves
   against that element's own font. Measured: 70ch is 421px on `.ncolo` (10px
   mono) against 589px for the prose column, so the one element on the page whose
   font is smallest gets the narrowest cap, and its border-top is a visible rule
   that stops 168px short of the one below it.

   Every other user of the token hides the same bug: `.ntitle`, `.prose > *`,
   `.fnotes` and `.src` all have fonts large enough that 70ch exceeds the column,
   so the column governs and nothing shows. `.nrestate` is the one to watch, for
   the same reason as this.

   The column is a fixed 589px at every desktop width (the article is capped at
   920 by `.wrap`), so it is always the narrower constraint for prose. Dropping
   the cap here lets the line track the column exactly, which is what makes its
   rule the same width as the one above Connected. */
.ncolo { max-width: none; }

/* THE CONNECTED COUNT WRAPS ON A PHONE BECAUSE OF A HINT NOBODY CAN SEE THERE.
   The kit already intends one row on mobile: it turns `.nconn` into a flex row
   and lays the breakdown out horizontally beside the count. It wraps anyway, so
   "1 point here" and "2 in the text" drop onto their own line under the numeral.

   Measured at 320px, where the column is 288: the count block wants 191px and
   the breakdown 90px stacked, which overflows by 9. Of that 191, **54px is
   `.ncjt`** — the "(Jump↓)" hint, which is `opacity:0` and revealed only on
   hover or focus. A phone has no hover, so on mobile it is 54px of layout
   holding space for something that can never appear.

   Dropping it from the layout below 861px leaves 137 + 16 + 90 = 243, which
   fits with room to spare, and the breakdown sits to the right of the count the
   way the kit meant it to. Stacked rather than side by side, because two short
   lines in a narrow right-hand column read better than one long line, and it
   keeps working when a note has all three relationships.

   AND THE KIT'S MOBILE RULE NEVER APPLIED. `.nconn{display:flex}` inside the
   860px query is (0,1,0), while `.page a.nconn{display:block}` earlier in
   note.css is (0,2,1) and wins on specificity regardless of order. So the block
   stayed `display:block` on every phone and the two halves were never flex items
   at all. Measured `display: block` on a 320px viewport with the query active.
   This is the same trap the contract documents for `site.css`'s base link rule,
   which is why the `.page ` prefix is repeated below.

   The context strip's copy of `.ncjt` has the same hover problem and is left
   alone: it is a different control and not what was being looked at. */
@media (max-width: 860px) {
  .page a.nconn { display: flex; flex-wrap: nowrap; align-items: baseline; }
  .page a.nconn .ncjt { display: none; }
  .page a.nconn .nch { flex: none; }
  .page a.nconn .ncb { grid-auto-flow: row; gap: 3px; margin: 0 0 0 auto; }
}

/* THE PALETTE FIELD OVERFLOWS ITS OWN ROW ON A PHONE.
   Measured at 320px: the field is 318px, and after 32px of padding, the 18px
   magnifier, two 9px gaps and the 115px "Pour me one" pill, the input is left
   with 135px. "Search the notebook" needs 186px at --text-lg, so the placeholder
   is clipped to "Search the note".

   Type size cannot fix it. 16px is the floor, because iOS Safari auto-zooms the
   page when a focused input is smaller, and even at 16px the placeholder still
   needs 149px against the same 135.

   So the space comes off the pill, which is the move the contract already makes
   on the note header's share button: the word comes off because the row is
   already full. Glyph-only is about 33px, which hands the input 217px and leaves
   the placeholder 31px of slack at the kit's own type size. It stays in the
   field row rather than moving to the foot, so it is still the second way to use
   the panel and not a footnote to the typing one.

   Scoped to the kit's own phone breakpoint (640px), where the palette already
   becomes a bottom sheet, so this does not introduce a new one. */
@media (max-width: 640px) {
  .jrand .jrandw {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  /* The pill's horizontal padding is sized for a word beside the cup. With the
     word gone it reads as a lopsided box, so it squares up around the glyph. */
  .jrand {
    position: relative;
    gap: 0;
    padding: 5px 7px;
  }
  /* THE DRAWN BOX IS 29x25 AND A THUMB NEEDS 44. Rather than inflate the button
     until it competes with the field it sits beside, the HIT AREA is expanded
     on its own: the field row is 59px tall with 17px spare above and 18px
     below, so a 44px target fits vertically without touching anything, and the
     horizontal reach lands in the slack the shortened pill just freed. Visual
     weight unchanged, target meets the 44px guidance. */
  .jrand::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: max(100%, 44px);
    height: 44px;
    transform: translate(-50%, -50%);
  }
}

/* ---------- 5. the timeline's note is a sentence, not a label ----------
   `.tlsum` is written for the short mono labels the kit imagined on that row:
   uppercase, micro tracking, 2xs. The home page's timeline needs one sentence
   there instead, explaining that the record is new, and a full sentence in
   uppercase mono reads as shouting rather than as an aside.

   Matched to `.streamnote`, the notebook's own note under its bench, so the two
   places on the property where a figure explains itself sound the same.

   CENTRED AND UNCAPPED, at Chris's direction, which is a real departure from
   `.streamnote`: that one is a left-ranged paragraph under a left-ranged bench,
   whereas this sits under a plot and reads as its caption. So it takes no
   measure at all and centres in column 2, the plot's own column, rather than
   across the whole figure, where the label column would pull it off the graph's
   centre. It holds one line at desktop and wraps at narrow widths, which is the
   only thing 320px allows.

   Owed back to Claude Design along with the rest of this file: the class wants
   either a sentence variant or a second class. */
.page .tlsum.tlnote {
  display: block;
  margin: var(--space-4) 0 0;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  letter-spacing: normal;
  text-transform: none;
  color: var(--color-text-faint);
  max-width: none;
  text-align: center;
  text-wrap: pretty;
}

/* ---------- 6. the connections stats bar overflows a phone ----------
   MEASURED: at a 320px viewport the page's own scrollWidth is 365 against a
   301px client width, so the document scrolls sideways and success criterion 8
   fails. The kit's mobile rule takes `.cnstats` to three equal columns below
   760px, which is right down to about 400px and wrong under it: `.cnstatl` is
   `white-space:nowrap` and the widest label, "musings / borrowed", is 124.6px,
   while three columns at 301px leave 92px each. The number above it is exactly
   as wide, so the column cannot give either of them less.

   Two columns leave 144.5px, which clears the widest label with room. Dropping
   the nowrap instead was tried on paper and rejected: it splits "musings /
   borrowed" across two lines and makes the bar's rows different heights, and
   the label is a unit rather than a phrase.

   The kit's own 320px claim ("document scrollWidth equals clientWidth") was
   verified against `components.html`, which does not carry this bar. Same class
   of bug as the jump palette's clipped placeholder in section 1, found the same
   way, and owed back to Claude Design with the rest of this file. */
@media (max-width: 420px) {
  .page .cnstats {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* THE BENCH KNOBS SHED WORDS BEFORE THEY WRAP.
   Not a kit bug: the kit never had four types, and the row got wider than the
   column it sits in. Measured 2026-08-10 before any of this was written: the
   three knobs need 754px of `.benchctl` and the column caps at exactly 754, so
   the row wrapped the instant the viewport left the desktop.

   A CONTAINER QUERY, NOT A MEDIA QUERY, because the thing that runs out of room
   is the column and not the screen. `.benchctl` sits inside a capped `.sec` and
   loses width to page gutters at rates that change across two existing
   breakpoints, so a viewport number would be a guess about a chain of parents.
   The container knows its own width and that is the number that decides whether
   a word fits.

   Each chip carries its icon AND its word at every width; these rules only
   choose which is painted. The word is visually hidden rather than removed
   (same technique as `.sr`), so the label keeps its accessible name and the
   control is reachable by screen reader at every width. `title` hands the
   pointer the same word back on hover.

   ⚠️ THE CONTAINER IS `.bench`, NOT `.benchctl`, AND THAT IS NOT A PREFERENCE.
   A container query styles the container's DESCENDANTS and can never style the
   container itself: an element's own size cannot depend on a rule its own size
   selected, so the browser drops it silently rather than erroring. With
   `container-type` on `.benchctl`, every `.knob` rule below worked and the one
   rule that targeted `.benchctl`'s own gap did nothing, which is the hardest
   version of this to spot because most of the block behaves. Caught by reading
   `columnGap` back off the element and finding 12px where the rule said 8.

   Moving it up one box costs nothing structurally, `.bench` has no padding of
   its own, and it shifts every threshold by exactly the 32px of `.benchctl`
   padding, which is why the numbers below are 32 larger than the content widths
   they are derived from. */
.bench { container-type: inline-size; container-name: bench; }
.knob .track label .ki { display: none; align-items: center; }
.knob .track label .ki svg { display: block; }

/* ORDER IS CHRIS'S, AND IT MATCHES WHAT A READER CAN AFFORD TO LOSE. Sort goes
   first: its three words are the most guessable from a calendar, a pencil and
   an Aa, and sort is the knob a reader touches last. Stage second, because its
   markers were already beside the words and are the property's most taught
   glyph. Shown last, because the four type icons are the four cards sitting
   directly above the bench and losing those words costs the most.

   ⚠️ EVERY THRESHOLD BELOW IS MEASURED, NOT CHOSEN. Each is the width at which
   the CURRENT step stops fitting, so the next step fires one pixel before the
   row would break rather than at a round number that looks tidy. The knobs
   need, as content: 676px with every word, 601 once Sort is icons, 459 once
   Stage joins it, 366 once Shown does. Add 24px of gaps to each. A first pass
   used round numbers and left two live wrap points, at 640 and 420, which is
   why these read as they do. Re-measure before editing any of them: they are
   downstream of the mono font's metrics and of the four type labels. */
@container bench (max-width: 732px) {
  .knob-sort .track label:not(.dirchip) .kw {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .knob-sort .track label:not(.dirchip) .ki { display: inline-flex; }
}

@container bench (max-width: 657px) {
  .knob-stage .track label .kw {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}

@container bench (max-width: 515px) {
  .knob:not(.knob-stage):not(.knob-sort) .track label .kw {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .knob:not(.knob-stage):not(.knob-sort) .track label .ki { display: inline-flex; }
  /* THE LAST FEW PIXELS, and they are a real wrap rather than a rounding
     artefact. With all three knobs reduced the row is 366px of content, and the
     gaps are what decide whether it fits. Tightening them is the honest lever:
     the chips are already icon-only, so there is nothing left to shorten.

     ⚠️ SIZED AGAINST A REAL DEVICE, not against a round number. Without the
     last two rules the row still broke between roughly 421 and 479 CSS pixels
     of viewport, and a 430px phone lands inside that band. Below 421 the kit's
     own query stacks the knobs into columns, which is a deliberate layout and
     not a wrap, so this band was the only place left where the row broke by
     accident. Measured after: one line from 800 down to the point the kit takes
     over. */
  .benchctl { column-gap: var(--space-2); }
  .benchctl .knob { gap: 3px; }
  .benchctl .knob-sort { gap: var(--space-1); }
}

/* THE MOBILE NAV RAIL SITS ON THE FLOOR OF THE HEADER.
   Below 760 the nav becomes a pill rail with `.mainnav{padding:9px 0 0}`, which
   is 9px above the pills and nothing below them. Measured at 600px: 10px from
   the rule to the top of a pill (1px border plus 9px padding) against 0px from
   the bottom of a pill to the edge of the header. Chris read it as the pills
   sitting off-centre in their strip, which is exactly what they are doing.

   The same zero is the second half of it. The header ends at the pill's own
   bottom edge, so the page's eyebrow begins 1px under the rail with nothing
   between the site's navigation and the page's first word. Measured: header
   bottom 100, eyebrow top 100.

   Two rules, because they are two faults that happen to share an edge: one
   centres the pills in their own strip, the other puts air under the strip.
   `--space-6` matches what `.mast` already takes at this width, so a page that
   opens on `.phead` and one that opens on `.mast` start at the same height. */
@media (max-width: 760px) {
  .page .mainnav { padding-block: 9px; }
  .page .phead { padding-top: var(--space-6); }
}

/* AND WHEN THE ROW FINALLY GIVES OUT, THE CAPTIONS GO ABOVE THE TRACKS.
   The kit already owns this treatment: below 420px of VIEWPORT it turns each
   knob into a column, so SHOWN / STAGE / SORT sit over their own chips instead
   of beside them, which is narrower and reads better. The trouble was purely
   one of timing. The icon ladder above pushed the single-line row down to 408px
   of container, but the kit's stack was still keyed to a viewport number it
   would not reach until later, so between the two there was a band where the
   knobs had already broken onto two lines while the captions were still sitting
   inline. Chris called it the awkward phase, and it was: a layout waiting for
   permission it had already earned.

   Measured to the pixel: the inline row holds at 408 and breaks at 407, so the
   stack takes over at exactly the width the row stops working. Stacking is a
   net saving rather than a cost, because a column knob is only as wide as the
   wider of its caption and its track, so the three fit side by side again well
   past the point the inline row could not.

   The kit's own 420px media query stays and is now simply redundant on this
   page, which is correct: it still covers any narrow viewport the container
   query cannot see. */
@container bench (max-width: 407px) {
  .benchctl .knob { align-items: flex-start; flex-direction: column; gap: 5px; }
  /* AND THE CAPTIONS HAVE TO SIT ON ONE LINE, which centring will not give
     them. `.benchctl` is `align-items:center`, and once the knobs are columns
     they no longer have equal heights, so each caption floats to its own
     baseline: measured 630 / 628 / 629, a 2px stagger across three words that
     are meant to read as one row of headings. `align-self` rather than changing
     the container's `align-items`, because the search field and the reset
     button are siblings in the same flex row and neither should be moved to
     straighten a caption. */
  .benchctl .knob { align-self: flex-start; }
}
