/* chrome.css — styles for the site chrome shared by EVERY surface: the
   full-screen menu ([data-menu]), the desktop drawer ([data-drawer]), and the
   footer ([data-footer-cta]/[data-footer-meta]). Loaded by both shells (see fragments.mjs)
   so there is one copy. The masthead is NOT here — its markup + CSS differ
   between the shells (index uses <header id="masthead">, the article wraps it
   in a .stack with the reading-morph header), so it stays per-shell.

   Base geometry for [data-menu], [data-drawer], [data-footer-cta], [data-footer-meta] lives
   inline on the markup (see tools/build/chrome.mjs); this file holds the
   responsive tweaks + the desktop drawer's full styling. */

/* ---- --tileborder ----
   The drawer draws every one of its dividers with this token, and it was
   defined only in index.css, on #site-root. Article pages have no #site-root,
   so on an article the var() was invalid, the whole border-top declaration was
   dropped, and the drawer opened with no rules at all — the divider between
   the Latest column and the nav, the lines between entries, the rules above
   the social row and the theme toggle. Nothing failed; the lines were simply
   absent.

   It is a deliberately stronger line than --border, which is why it cannot
   just fall back to it. Defined here at :root because chrome.css is what
   consumes it; index.css's #site-root block is more specific, so the homepage
   keeps its own values and the [data-tilestroke="prev"] variant still works. */
:root { --tileborder: #CCCCCC; }
:root[data-theme="dark"] { --tileborder: rgba(255,255,255,0.24); }
:root[data-theme="paper"] { --tileborder: #C6B591; }

/* ---- selection ----
   The site never defined one, so every selection anywhere — body copy, a
   headline, text inside the search field — painted in the browser's default
   blue. That blue belongs to no palette on this page. A wash of the accent at
   low alpha reads as ours and still clears the AA contrast bar against the
   text it sits behind, in either theme. Kept out of the per-shell sheets so
   articles and index pages cannot drift apart on it. */
::selection { background: rgba(227, 66, 52, 0.20); color: var(--fg); }
:root[data-theme="dark"] ::selection { background: rgba(227, 66, 52, 0.38); color: #FFFFFF; }

/* ---- search fields ----
   input[type=search] keeps its native appearance in Chromium and Safari, which
   adds a clear button drawn in the OS accent colour — another blue we do not
   own, sitting inside a field we drew ourselves. The field is styled end to
   end here; Escape still clears it. */
input[type="search"] { appearance: none; -webkit-appearance: none; }
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }

/* ---- autofill ----
   Picking a remembered query from the browser's own dropdown does not just put
   text in the field: Chrome repaints it. A pale blue ground, its own glyph
   colour and its own face — none of them ours, and all of it landing on the one
   control the reader types their own words into.
   background-color cannot take it back; the UA style outranks an author one. So
   the ground is masked with an inset shadow the width of any field, the glyph
   colour goes through -webkit-text-fill-color (which autofill does honour), and
   the family is restated because autofill drops to a UA default.
   The 5000s transition is the known trick, not an accident: Chrome applies the
   autofill background through a transition, so giving ours one that effectively
   never arrives keeps our shadow on top. */
input[type="search"]:-webkit-autofill,
input[type="search"]:-webkit-autofill:hover,
input[type="search"]:-webkit-autofill:focus,
input[type="search"]:-webkit-autofill:active {
  -webkit-text-fill-color: var(--fg);
  -webkit-box-shadow: 0 0 0 100px var(--bg) inset;
  box-shadow: 0 0 0 100px var(--bg) inset;
  caret-color: var(--fg);
  font-family: 'Newsreader', Georgia, serif;
  transition: background-color 5000s ease-in-out 0s;
}

/* ---- search fields, all five ----
   The drawer, the full-screen menu, both header bars and /search/. Written once
   against [data-search-form] rather than five times against five layouts,
   because the behaviour is the field's, not the panel's.

   The magnifier is BLACK and goes accent once there is a query. It used to be
   accent unconditionally, which spends the colour on nothing and leaves it
   saying nothing when it matters. Keyed to content rather than focus: an empty
   field you happen to be in is not a state worth marking, and the signal earns
   its keep exactly when you have looked AWAY with something typed and
   unsubmitted — the moment a focus-keyed one would have gone out.

   :has(), because /search/ puts its icon BEFORE the input while the others put
   it after; a sibling selector can only reach one of those. Where :has() is
   missing the icon simply stays black, which is the old behaviour and not a
   broken one.

   The placeholder clears when you focus an untouched field. Left up, it sits at
   exactly the x the caret does, so the bar lands against the S of "Search" with
   nothing between them.

   It comes back once you have typed something and deleted it again: an emptied
   field otherwise reads as broken rather than empty, and by then the caret is
   established — knowing where you are is what the blank was buying. The flag is
   set on the first keystroke in chrome.js; :placeholder-shown cannot tell the
   two blanks apart, and :user-valid, which would have said "touched" here, is
   only applied by Chrome to inputs carrying an actual constraint. With no
   script the placeholder stays hidden while focused, as it did before. */
[data-search-form] input:focus::placeholder { color: transparent; }
[data-search-form][data-search-touched] input:focus::placeholder { color: var(--faded); }
[data-search-form] [type="submit"],
[data-search-form] .search-lead-icon { color: var(--fg); transition: color 0.16s ease; }
[data-search-form]:has(input[type="search"]:not(:placeholder-shown)) [type="submit"],
[data-search-form]:has(input[type="search"]:not(:placeholder-shown)) .search-lead-icon { color: var(--accent); }

/* Clear. Shown only once there is something to clear — :placeholder-shown is
   true exactly while the field is empty, so it keeps in step with no script.
   type="reset" empties the form, and every one of these forms is a single
   field. --faded so the accent stays with the primary action; tabindex -1 keeps
   it out of the path from the field to Submit, where Escape already clears. */
[data-search-form] [data-search-clear] { display: inline-flex; align-items: center; flex: none; padding: 4px; margin: 0; appearance: none; background: none; border: none; cursor: pointer; color: var(--faded); transition: color 0.16s ease; }
[data-search-form] input[type="search"]:placeholder-shown ~ [data-search-clear] { display: none; }
@media (hover: hover) { [data-search-form] [data-search-clear]:hover { color: var(--fg); } }
[data-search-form] [data-search-clear]:active { color: var(--fg); }

/* ---- top nav ----
   Three items: Search, Subscribe, About. Archive and Topics used to sit here
   too, and the four-item set collided with the centred wordmark below 1440 —
   Archive was hidden under a breakpoint to buy room. Three items clear the
   wordmark at every width, so that breakpoint is gone, and both routes are
   still one click away in the desktop drawer.

   Subscribe carries no box. The bordered call-to-action was the convention
   for a nav whose job was conversion; this nav's job is navigation.

   It is "Subscribe" and not "Newsletter" because the drawer and the footer
   both already say Subscribe, and the page it opens is /subscribe/ titled
   Subscribe. One destination, one name, in all three places. */
@media (hover: hover) {
  [data-site] .topnav-link:hover { color: var(--accent) !important; }
}
[data-site] .topnav-link:active { color: var(--accent) !important; }
[data-site] .topnav-link { transition: color 0.18s ease; }

/* Optical alignment with the wordmark, and the 40px before the hamburger.

   The nav's ink sat 2px BELOW the wordmark's ink centre. That is not the nav's
   fault: the wordmark carries line-height:1 while its ink measures 55px at
   45px type, so its ink overflows its own line box and its optical centre is
   not its box centre. The two are centred independently by the header, so the
   discrepancy shows up as a 2px drop on the nav.

   line-height CANNOT fix it — the ink stays centred in whatever line box it is
   given, so changing the nav's line-height moves box and ink together. Measured:
   normal -> 2.0, 1.1 -> 1.95, 1.0 -> 2.0, 0.9 -> 1.05. Hence a measured nudge.
   Re-measure if the wordmark's size or line-height changes; this number belongs
   to the wordmark's metrics, not the nav's.

   inline-block because a transform does not apply to a non-replaced inline box,
   which is what an <a> is by default.

   SCOPED TO header#masthead, i.e. the index-family shell, because the article
   masthead is a different structure (its links sit inside <nav data-top-nav>)
   and measured a native offset of 0 — applying the same nudge there pushed it
   2px the WRONG way. The number belongs to one shell's wordmark, not to the nav.

   The gap: items sit 24px apart, and the hamburger sat at 48 — exactly double,
   which read as detached rather than as the end of the row. 40 separates it as a
   different kind of control without stranding it. -16px against the button's own
   margin:-8px, i.e. 40 - 56. !important because that margin is an INLINE style
   on the button, which outranks a stylesheet rule. */
[data-site] header#masthead .topnav-link { display: inline-block; transform: translateY(-2px); }
[data-site] .mast-right [data-menu-toggle] { margin-left: -16px !important; }

/* ---- full-screen menu overlay: responsive type + single-column topics ---- */
@media (max-width: 759.98px) { [data-site] [data-menu] { padding-left: 22px !important; padding-right: 22px !important; padding-bottom: 30px !important; } }
@media (max-width: 759.98px) { [data-site] [data-menu] nav button, [data-site] [data-menu] nav > a { font-size: 2.5rem !important; } }
@media (max-width: 759.98px) { [data-site] [data-menu] [data-panel] > div { grid-template-columns: 1fr !important; gap: 12px !important; } }
@media (max-width: 759.98px) { [data-site] [data-menu] [data-panel] [data-label] { font-size: 1.15rem !important; } }

/* ---- the phone menu's social row ----
   Full --fg, matching [data-drawer] .drawer-social, which has always been --fg.
   These were --faded from when the row was pinned to the bottom of the panel as
   a footer; sitting with the nav list they are links like the rest of it, and
   two rows of the same four icons in two different colours was a difference
   with no reason behind it.

   SIZES ARE PER GLYPH AND UNEQUAL ON PURPOSE. A square viewBox is not a square
   drawing, so one px size does not buy one apparent size. Rasterised at 200px
   and measured, the four ink boxes fill their viewBox by:

     X        0.90 x 0.82      LinkedIn  0.90 x 0.69
     Email    0.90 x 0.65      RSS       0.65 x 0.65   (a corner-anchored mark)

   Sizing them all the same left RSS reading 24% small — as it still would at
   any uniform number. Each size here is set so sqrt(inkW * inkH) * size lands
   near 24.5, which brings the spread from 1.32 to 1.02:

     X 29 -> 24.91   LinkedIn 31 -> 24.43   Email 32 -> 24.48   RSS 38 -> 24.70

   Re-derive rather than nudge if a glyph is ever redrawn. */
[data-menu] .menu-icons { display: flex; align-items: center; flex: none;
  /* 16 gap + 8 padding either side = the 32 of visual air the row reads as,
     while each target grows to ~45px — these are the menu's touch items now. */
  gap: 16px; padding: 18px 0 0; margin-left: -8px; }
[data-menu] .menu-icons a { display: inline-flex; align-items: center; padding: 8px;
  color: var(--fg); text-decoration: none; transition: color 0.18s ease; }
@media (hover: hover) { [data-menu] .menu-icons a:hover { color: var(--accent); } }
[data-menu] .menu-icons a:active { color: var(--accent); }

/* The rule above the theme toggle. It was a --border hairline inset inside the
   panel's gutter, which read as a faint box edge rather than as the division it
   is: everything above is navigation, below is a setting. Now --fg, and bled to
   the panel edges so it reads as a rule across the sheet.

   The negative margin MUST equal the panel's own horizontal padding, which is
   30 at base and 22 below 760 (the rule above). Matched exactly, the element's
   border box lands flush on the scroll container's padding-box edge, which is
   also the edge of its scrollable overflow region — so this bleeds without
   creating horizontal scroll. Overshoot it and [data-menu]'s overflow-y:auto
   (which computes overflow-x to auto too) would start scrolling sideways. */
[data-menu] .menu-foot {
  border-top: 1px solid var(--fg);
  margin-left: -30px; margin-right: -30px;
  padding-left: 30px; padding-right: 30px;
}
@media (max-width: 759.98px) {
  [data-site] [data-menu] .menu-foot {
    margin-left: -22px !important; margin-right: -22px !important;
    padding-left: 22px !important; padding-right: 22px !important;
  }
}

/* Desktop/tablet: the top-nav "Search" already unfolds a search bar, so the
   search field inside the hamburger menu is redundant — hide it. Phone keeps it
   (no top-nav, so the menu is the only place to search). The form[data-menu-search]
   re-show rule out-specifies this on the in-menu search when it is wanted. */
@media (min-width: 760px) and (max-width: 1023.98px) { [data-site] [data-menu] [data-menu-search] { display: none !important; } }
@media (min-width: 1024px) { [data-site] [data-menu] [data-menu-search] { display: none !important; } }
@media (min-width: 760px) and (max-width: 1023.98px) { [data-site] [data-menu] form[data-menu-search] { display: flex !important; max-width: none !important; } }
@media (min-width: 1024px) { [data-site] [data-menu] form[data-menu-search] { display: flex !important; max-width: none !important; } }

@media (hover: hover) { [data-menu] a[href="/feed.xml"]:hover { color: var(--accent) !important; } }
@media (hover: hover) { [data-site] .footer-nav-link:hover { color: var(--accent) !important; } }
[data-site] .footer-nav-link:active { color: var(--accent) !important; }
[data-menu] a[href="/feed.xml"]:active { color: var(--accent) !important; }

/* The menu's own five links answered to nothing. They carry a
   `transition:color 0.2s` inline and always had, but no rule ever changed the
   colour, so on a phone — where the menu IS the navigation — pressing a
   destination gave back nothing at all until the next page painted.
   !important because the colour is inline on each link, and an inline
   declaration outranks a plain rule.
   :active, so it holds for as long as the finger is down and drops on release.
   iOS only applies :active to an element carrying cursor:pointer or sitting
   under a touch handler; these set cursor:pointer inline already. */
@media (hover: hover) { [data-site] [data-menu] nav > a:hover, [data-site] [data-menu] nav button:hover { color: var(--accent) !important; } }
[data-site] [data-menu] nav > a:active,
[data-site] [data-menu] nav button:active { color: var(--accent) !important; }

/* ---- footer / subscribe ---- */
@keyframes footerRingSpin { to { transform: rotate(360deg); } }
/* MCF stamp invert. :hover for real pointers, :active for touch. */
@media (hover: hover) {
  .mcf-mini:hover { background: var(--fg) !important; color: var(--bg) !important; }
  .mcf-mini:hover [data-sigil] { background: var(--bg) !important; }
}
.mcf-mini:active { background: var(--fg) !important; color: var(--bg) !important; }
.mcf-mini:active [data-sigil] { background: var(--bg) !important; }

@media (min-width: 760px) and (max-width: 1023.98px) { [data-site] [data-footer-cta], [data-site] [data-footer-meta] { padding-left: 50px !important; padding-right: 50px !important; } }
@media (min-width: 1024px) { [data-site] [data-footer-cta], [data-site] [data-footer-meta] { padding-left: 50px !important; padding-right: 50px !important; } }

@media (max-width: 759.98px) { [data-site] [data-footer-cta] { padding: 30px 8px !important; gap: 22px !important; } }
/* The orbital ring is a desktop-only flourish; on tablet it floats in a large
   empty gap beside the subscribe form, so hide it below the 1024 desktop
   boundary (not just on phones). */
@media (max-width: 1023.98px) { [data-site] [data-footer-ring] { display: none !important; } }
@media (max-width: 759.98px) { [data-site] [data-subscribe-row] { flex-direction: column !important; } }
@media (max-width: 759.98px) { [data-site] [data-subscribe-row] button { width: 100% !important; justify-content: center !important; } }
@media (max-width: 759.98px) { [data-site] [data-footer-meta] { padding: 34px 8px 22px !important; flex-wrap: nowrap !important; gap: 16px !important; min-height: 150px !important; } }
@media (max-width: 759.98px) { [data-site] #globe-footer-desktop { display: none !important; } }
/* stack the footer's left group (globe + nav) vertically on phones, nav centered
   under the globe */
@media (max-width: 759.98px) { [data-site] [data-footer-meta-left] { flex-direction: column !important; align-items: center !important; gap: 18px !important; } }
@media (max-width: 759.98px) { [data-site] [data-footer-meta-left] nav { align-items: center !important; } }
@media (max-width: 759.98px) { [data-site] #globe-footer-mobile { display: inline-flex !important; align-self: center !important; margin-left: 0 !important; margin-bottom: 0 !important; } }
/* centre the back-to-top button in the right column, and bottom-align the
   credits with the footer nav */
@media (max-width: 759.98px) { [data-site] [data-footer-meta-right] [data-backtotop] { width: 28px !important; height: 34px !important; margin-top: 0 !important; transform: translateY(110px) !important; } }
@media (max-width: 759.98px) { [data-site] [data-footer-copy] { margin-bottom: 0 !important; } }

/* ===== Desktop menu panel (data-drawer) =====
   Compact two-column panel that unfolds from the masthead rule on desktop,
   replacing the full-screen overlay there (the overlay remains the mobile/
   tablet menu). Geometry (top offset, width, utility-column centering) is
   measured from the live masthead at open time by chrome.js; colors ride the
   theme tokens, so dark mode inverts the panel automatically. */
@media (max-width: 759.98px) {
  [data-drawer] { display: none !important; }
}
@media (min-width: 760px) {
  [data-drawer] {
    position: fixed; right: 0; z-index: 3200; background: var(--bg);
    border: 1px solid var(--fg); border-top: none; border-right: none;
    box-sizing: border-box;
    /* Vertical only. The horizontal 20 moves onto each section below, so a rule
       on a section spans the drawer instead of stopping 20px short — the same
       shape .share-topbar and .settings-row have. Faking it with negative
       margins was the alternative and it makes every future padding change a
       two-place edit. */
    padding: 14px 0 12px;
    display: flex; flex-direction: column;
    opacity: 0; visibility: hidden;
    /* Unfold downward from the masthead rule instead of sliding into place from
       above it. The panel is positioned with its top ON that rule, so a
       translateY(-10px) start put it 10px INSIDE the header — and since it fades
       in over the same 280ms, its left border was visible crossing the header
       for the first ~150ms of every open and close. Measured before: 10px of
       overlap at t=0, still 2.2px at t=120ms and already 78% opaque.

       clip-path reveals it from its own top edge, so nothing is ever painted
       above the rule and there is no border to catch. Visibility is switched,
       not interpolated — instant on open, held until the fade finishes on
       close — because a transitioned visibility is still hidden on the tick the
       attribute lands. */
    clip-path: inset(0 0 100% 0);
    transition: opacity 0.24s ease, clip-path 0.3s cubic-bezier(.22, 1, .36, 1), visibility 0s linear 0.3s;
  }
  [data-drawer][data-open="1"] {
    opacity: 1; visibility: visible; clip-path: inset(0 0 0 0);
    transition: opacity 0.24s ease, clip-path 0.3s cubic-bezier(.22, 1, .36, 1), visibility 0s;
  }

  /* the top-nav swaps out while the panel is open (class set on the header) */
  [data-top-nav] { transition: opacity 0.2s ease; }
  [data-site] header#masthead.drawer-navhide [data-top-nav],
  #stage[data-site] .masthead.drawer-navhide [data-top-nav],
  .drawer-navhide [data-top-nav] { opacity: 0; visibility: hidden; pointer-events: none; }
  [data-site] header#masthead.drawer-navhide,
  #stage[data-site] .masthead.drawer-navhide { z-index: 3300 !important; }

  /* No gap. The gap left the Latest rules stopping 18px short of the divider,
     which is the one place they most obviously want to meet — the columns abut
     and the divider IS the join. */
  [data-drawer] .drawer-cols { display: flex; gap: 0; }
  [data-drawer] .drawer-topics { flex: 0 0 190px; box-sizing: border-box; display: flex; flex-direction: column; }
  /* The three mono lines below each state line-height. Left unstated they
     inherit it, and the two shells hand down different values — an index page
     resolved 1.5, an article `normal` — so the same drawer stood 11px shorter
     on an article, with the Latest entries visibly tighter. A shared component
     cannot take a typographic metric from whatever it happens to sit inside. */
  /* The share panel's topbar label, in the drawer: accent square, black italic
     display type, black rule under it. Was 11.5px accent mono — a quiet eyebrow
     where the panels put a heading. The square is the mark this site already
     uses to point at a heading (see .share-topbar-dot), and the black rule is
     what closes a section rather than dividing one. */
  [data-drawer] .drawer-label {
    display: flex; align-items: center; gap: 10px;
    font-family: 'Cormorant Garamond', Georgia, serif; font-weight: 600;
    font-size: 20px; line-height: 1; letter-spacing: 0; color: var(--fg);
    margin: 0; padding: 15px 20px 11px; border-bottom: 1px solid var(--fg);
  }
  [data-drawer] .drawer-label::before { content: ""; flex: none; width: 10px; height: 10px; background: var(--accent); }
  /* Each head aligns with the column it heads: "Latest" left over left-aligned
     titles, "Explore" centred over centred links. Left-aligning it left a short
     word stranded against a centred column — which reads as a mistake, and no
     amount of lengthening it ("Site menu", "Site navigation") fixes that, it
     only fills the gap the mismatch was showing through. The squares no longer
     line up across the two columns, which is correct: each marks its own. */
  [data-drawer] .drawer-right .drawer-label { justify-content: center; }
  /* The three entries divide the column instead of stacking under the head and
     leaving a void beneath — the right column is the taller of the two and sets
     the height. Equal rows with the text centred in each is also the rhythm the
     black rules are asking for; ragged rows under full-width rules read as an
     unfinished table. */
  [data-drawer] .drawer-chips { display: flex; flex-direction: column; flex: 1 1 auto; }
  /* Latest column. Three headlines, so the tiles are rules rather than boxes —
     four bordered chips holding one word each could carry a border; three
     holding a full headline cannot, and the panel would read as a form. */
  [data-drawer] .drawer-tile { border-top: 1px solid var(--fg); padding: 11px 0 11px 20px; flex: 1 1 0; display: flex; flex-direction: column; justify-content: center; position: relative; text-decoration: none; cursor: pointer; }
  /* Every rule in here is black and reaches its edges. Grey hairlines inside a
     black frame read as a hedge; the panels this drawer now matches commit to
     one weight and let position do the work. The head's rule is the label's
     border-bottom above, so the first tile does not draw its own. */
  [data-drawer] .drawer-chips > .drawer-tile:first-child { border-top: 0; }
  [data-drawer] .drawer-dot { position: absolute; left: 20px; top: 18px; width: 6px; height: 6px; background: var(--accent); opacity: 0; transform: translateX(-4px); transition: opacity 0.18s ease, transform 0.18s ease; }
  [data-drawer] .drawer-tile-label { display: block; transition: transform 0.18s ease; }
  [data-drawer] .drawer-tile-title { display: block; font-family: 'Newsreader', Georgia, serif; font-size: 0.98rem; line-height: 1.3; color: var(--fg); }
  [data-drawer] .drawer-tile-date { display: block; margin-top: 5px; font-family: 'Fragment Mono', monospace; font-size: 10.5px; line-height: 1.5; letter-spacing: 0.04em; color: var(--faded); }
  /* Same rule as the utility links: the tile is the hit target and never moves,
     only its label slides, so resting the pointer inside cannot start a
     hover/unhover loop. */
  /* The tiles answer in COLOUR; the nav links opposite keep the dot and the
     slide. Three stacked headlines all sliding is a lot of movement for a list
     you are scanning, and the two columns are different things — these are
     content, those are destinations. The motion suits 34px display type; the
     title going accent is the quieter, more usual affordance for a headline. */
  @media (hover: hover) {
    [data-drawer] .drawer-tile:hover .drawer-tile-title { color: var(--accent); }
  }
  [data-drawer] .drawer-tile:active .drawer-tile-title { color: var(--accent); }
  [data-drawer] .drawer-tile-title { transition: color 0.16s ease; }

  [data-drawer] .drawer-right { flex: 1 1 0; min-width: 0; border-left: 1px solid var(--fg); display: flex; flex-direction: column; box-sizing: border-box; }
  /* A bordered bar, the shape the header search already uses, sitting at the top
     of the panel with the rule under it belonging to the table below.

     This was a bled row before, on the argument that a bordered field inside a
     bordered panel stacks two framing systems. What settled it the other way is
     that the cells now carry the table: "Latest" and "Explore" read as column
     heads because of their own rules, not because the search reaches the edges,
     so the search is free to be a control again rather than a first row.

     50px and inset 20px, which is the drawer's horizontal padding, so it lines
     up with everything below it. */
  [data-drawer] .drawer-search { display: flex; align-items: center; gap: 8px; height: 50px; border: 1px solid var(--fg); background: var(--bg); padding: 0 10px 0 15px; margin: 0 20px 18px; box-sizing: border-box; flex: none; }
  /* Back to the header's sizes. At 24/22 they were set against 26px type; at 16
     they would be larger than the words beside them. The clear runs 17 rather
     than 15 because its ring needs the room the bare cross did not. */
  [data-drawer] .drawer-search [type="submit"] svg { width: 18px; height: 18px; }
  [data-drawer] .drawer-search [data-search-clear] svg { width: 17px; height: 17px; }
  /* The bled rule the Latest/Explore heads hang from moves here, since the
     search no longer draws it. */
  [data-drawer] .drawer-cols { border-top: 1px solid var(--fg); }
  /* Newsreader, not the site's mono. The mono is the voice of METADATA here —
     kickers, dates, "Latest", the theme label, the results count on /search/.
     A query is not metadata: it is the reader's own words, and what they type is
     prose they expect to find in prose. Set in mono, "How does Starlink work?"
     reads as a command; set in the body face it reads as a question. Mono also
     costs width, fitting fewer characters in the same field. Newsreader's
     x-height is smaller than the mono's, so matching a size number between the
     two shrinks it optically.
     16px, down from 26. 26 was sized for a query standing on an open rule as
     the panel's opening statement; inside a 50px bar it is a control's label,
     and the box is what gives it presence now. */
  [data-drawer] .drawer-search input { flex: 1; min-width: 0; border: none; outline: none; background: transparent; height: 100%; padding: 0; font-family: 'Newsreader', Georgia, serif; font-size: 16px; letter-spacing: 0; color: var(--fg); }
  /* The placeholder goes when you focus an untouched field, and comes back once
     you have typed and deleted — see the [data-search-form] block above, which
     is where both halves of that live. */
  [data-drawer] .drawer-search button { appearance: none; background: none; border: none; cursor: pointer; padding: 4px; margin: 0; display: inline-flex; align-items: center; flex: none; }


  /* utility column: centered stack, positioned on the close button's axis by JS */
  /* flex:1 so the column owns the full height of .drawer-right, which lets the
     icons below take margin-top:auto and settle on the bottom edge — level with
     the last entry in Latest rather than floating above it. */
  /* margin-top:auto on both columns' content: the labels sit under the search
     field and everything else settles on the bottom rule, so the two columns
     end level however tall the drawer is. */
  [data-drawer] .drawer-wrap { display: flex; flex-direction: column; align-items: center; width: 100%; box-sizing: border-box; padding: 0 10px; margin-top: auto; }
  /* The five links are the whole column now that the social row has moved to the
     bottom band, so they take all of it and spread across it. Left to their own
     line height they cluster at the top and leave a hole. */
  [data-drawer] .drawer-links { display: flex; flex-direction: column; align-items: center; width: 100%; }
  /* The link slides right on hover and an accent square appears in the space it
     leaves. The <a> itself used to be what moved — which meant the hover target
     slid out from under a stationary cursor, unhovered, slid back under it,
     rehovered, and did that for as long as the pointer rested in the 17px band
     it was vacating. Held perfectly still, the item oscillated across 13px and
     never settled.

     So the box no longer moves: the padding reserves the travel on both sides,
     which keeps the label centred in the column exactly as before, and only the
     inner <span> slides. The hit area is constant, so hover is a single state
     change however long you rest there. */
  [data-drawer] .drawer-links a, [data-drawer] .drawer-disabled { font-family: 'Cormorant Garamond', Georgia, serif; font-weight: 600; font-size: 2.4rem; line-height: 1.2; padding: 11px 12px; }
  [data-drawer] .drawer-links a { color: var(--fg); text-decoration: none; position: relative; width: fit-content; }
  [data-drawer] .drawer-links a > span { display: inline-block; transition: transform 0.18s ease; }
  [data-drawer] .drawer-links a::before { content: ""; position: absolute; left: 12px; top: 50%; width: 7px; height: 7px; background: var(--accent); opacity: 0; transform: translate(-6px, -50%); transition: opacity 0.18s ease, transform 0.18s ease; }
  @media (hover: hover) {
    [data-drawer] .drawer-links a:hover > span { transform: translateX(17px); }
    [data-drawer] .drawer-links a:hover::before { transform: translate(0, -50%); opacity: 1; }
  }
  [data-drawer] .drawer-links a:active > span { transform: translateX(17px); }
  [data-drawer] .drawer-links a:active::before { transform: translate(0, -50%); opacity: 1; }
  [data-drawer] .drawer-disabled { color: var(--faded); opacity: 0.55; cursor: default; }

  /* The social row sits in the bottom band with the theme toggle, not in the nav
     column. It is chrome about the publication, the same register as the theme
     switch — and out of the column it frees the whole height for the five links,
     which is what the column is actually for. Smaller here too: down in a
     utility strip these are a footnote, not a destination, and at 23px they
     out-weighed the 16px toggle they now sit beside.
     No border-top or margin-top:auto any more; the band draws the rule and
     space-between places the group. */
  /* The social row moved OUT of the bottom band and into the Explore column,
     under Subscribe, where Contact used to sit. Contact's page said only "write
     to the editor, or DM us on X" — two links wearing a page — so the two links
     take the slot directly and the page goes.
     Bigger than they were in the band: they are a destination in a column of
     destinations now, not a utility strip. */
  [data-drawer] .drawer-social { display: flex; align-items: center; justify-content: center; gap: 22px; padding: 14px 12px 4px; }
  [data-drawer] .drawer-social a { display: inline-flex; align-items: center; color: var(--fg); text-decoration: none; transition: color 0.18s ease; }
  [data-drawer] .drawer-social svg { width: 27px; height: 27px; display: block; }
  /* RSS is a corner-anchored mark filling 0.65 of its viewBox against ~0.79 for
     the other three, so the uniform 27 above left it reading 24% small here for
     the same reason it did in the phone menu. 33 puts its optical box at 21.45
     against a 21.71 mean for X, LinkedIn and Email. Same derivation as the
     [data-menu] .menu-icons note below — one measurement, two surfaces. */
  [data-drawer] .drawer-social a[href="/feed.xml"] svg { width: 33px; height: 33px; }
  /* The same answer the footer links and the menu's RSS already give. No dot and
     no slide: those belong to text, where there is a baseline for a dot to sit
     on and a word to slide. Each icon carries a title, so hovering names it. */
  @media (hover: hover) { [data-drawer] .drawer-social a:hover { color: var(--accent); } }
  [data-drawer] .drawer-social a:active { color: var(--accent); }

  /* RSS is in the row too, rather than alone in the band. Grouping by KIND
     would have kept it with the theme toggle — a feed is machinery, not an
     account — but grouping by "ways to follow this" is the shelf a reader
     actually looks on, and that is the one they get.
     It settles a smaller thing as well: alone in the band beside a labelled
     toggle, RSS read as the one item nobody bothered to name. In a row where
     nothing is labelled, nothing is conspicuously unlabelled.
     Four at 27px need the gap at 22, not 30 — measured, the row comes to 222px
     against a 217px column at 30, which overflows. At 22 it is 198.
     The band keeps the toggle at the left and leaves its right cell empty. This
     drawer is a table with bled dividers; an empty cell is ordinary in one, and
     centring the toggle across the band is the move that would opt the band out
     of the structure everything else is built on.
     The .drawer-icons rules that dressed the band's row went with it — nothing
     carries that class any more. */

  /* Mirrors .drawer-cols: the toggle takes the Latest column's 184px + its 18px
     gap, the icons take the rest and centre in it — so they sit under the middle
     of the nav column, which is centred, exactly as the toggle sits under the
     left edge of a left-aligned column. Right-aligning them put them under
     nothing. Stated as the same numbers .drawer-topics uses, so the two stay in
     step. */
  [data-drawer] .drawer-bottom { margin-top: 0; padding: 12px 0 0; border-top: 1px solid var(--fg); display: flex; align-items: center; gap: 0; }
  [data-drawer] .drawer-bottom > button { flex: 0 0 190px; box-sizing: border-box; }
  /* The 20px inset lives HERE, in the same declaration as the reset, not in the
     rule above. `> button` and ` button` have identical specificity, so the
     later `padding: 0` silently won and the moon sat at 1px — out in the gutter,
     while the accent square and every article title started at 21. */
  [data-drawer] .drawer-bottom button { appearance: none; background: none; border: none; padding: 0 0 0 20px; display: inline-flex; align-items: center; gap: 10px; cursor: pointer; color: var(--fg); transition: color 0.2s; font: inherit; }
  @media (hover: hover) { [data-drawer] .drawer-bottom button:hover { color: var(--accent); } }
  [data-drawer] .drawer-bottom button:active { color: var(--accent); }
  [data-drawer] .drawer-theme-icon { display: inline-flex; width: 18px; height: 18px; align-items: center; justify-content: center; }
  [data-drawer] [data-theme-label] { font-family: 'Fragment Mono', monospace; font-size: 12px; line-height: 1.5; letter-spacing: 0.04em; }
}

/* Visually hidden, still announced.
   For headings that the page's structure needs but its design does not show —
   the homepage h1, whose visible counterpart is the masthead wordmark (an <a>,
   which cannot carry the heading without nesting one inside a link).
   Not `display:none` and not `visibility:hidden`: both remove the element from
   the accessibility tree, which is the opposite of the point. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ==========================================================================
   Skip link — see skipLink() in tools/build/chrome.mjs for why it exists.

   Parked off the top of the viewport rather than display:none, because
   display:none removes it from the tab order and a skip link that cannot be
   tabbed to is not a skip link. It comes back on :focus only.

   z-index sits above the sticky masthead (100) and below the menu overlay
   (2000): it must not be painted under the header it is helping you leave.
   ========================================================================== */
.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 1500;
  padding: 10px 16px;
  background: var(--bg, #fff);
  color: var(--fg, #060606);
  border: 1px solid var(--fg, #060606);
  font-family: 'Fragment Mono', ui-monospace, monospace;
  font-size: 13px;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: top 0.16s ease;
}
.skip-link:focus { top: 12px; }
/* The target takes tabindex="-1" so focus can land on it; that makes it
   focusable, and a focus ring around the whole article is noise. The skip
   already moved the reader where they asked to go. */
#main-content:focus { outline: none; }
#main-content:focus-visible { outline: none; }

/* ==========================================================================
   Focus floor.

   Most interactive things here already draw their own focus state, and several
   are better than a generic ring — the footnote reference opens its panel, the
   TOC strip expands, the share buttons raise their tooltip. What was missing
   was a FLOOR: anything that defines nothing was showing nothing, and which
   controls those are is not knowable by reading the CSS, only by tabbing
   through every page.

   :where() has zero specificity, so this loses to every existing rule,
   including the ones that deliberately say outline:none. It only ever applies
   where nothing else does. That is the point — it cannot regress a considered
   focus style, and it cannot be forgotten by the next control someone adds.

   :focus-visible, not :focus, so a mouse click does not leave a ring behind.
   ========================================================================== */
:where(a[href], button, input, select, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid var(--accent, #D12B1D);
  outline-offset: 2px;
}

/* ==========================================================================
   Touch targets.

   The category eyebrow ("Finance", "Infrastructure") is 11-12px type, which
   makes the link box about 14px tall. WCAG 2.5.8 asks for 24x24 CSS px, and on
   a phone this is a real miss rather than a technicality: it is the one control
   in a card that is not the headline, and it sits directly above one, so a
   near-miss lands on the article instead of the topic.

   Padding grows the hit area; the negative margin gives the space back to the
   layout, so nothing moves. Applied to the link only — the row keeps its
   spacing, and the text keeps its position to the pixel.
   ========================================================================== */
[data-site] .catlink,
[data-site] .row-eyebrow > a {
  display: inline-block;
  padding-block: 5px;
  margin-block: -5px;
}

/* ==========================================================================
   Search fields.

   These are composed controls: a frame around an icon, a borderless input and a
   button. The input carries an inline `outline:none` so no ring draws inside
   that frame — a fair visual call, but inline styles beat the focus floor
   above, so tabbing into search showed nothing at all.

   Two channels, not one: the line goes accent AND it doubles in weight, because
   colour alone is a colour-only cue (WCAG 1.4.1) and the resting line is
   already strong.

   The ring is drawn INSIDE the frame. Outside, it landed 2px clear of a line
   that was already there, so the field wore two rectangles — and in the header
   .searchfield is the wrapper around the form AND the close X, not the field,
   so the outer rectangle enclosed the X as well and did not line up with the
   black frame it was meant to mark. That is the red box. Drawn inset, the
   field's own frame is what thickens and reddens, and the header rule targets
   the form, which is the element that actually carries the border.

   Keyboard only, via the flag chrome.js sets on Tab. A mouse user has just
   clicked the field and can see the caret in it; the frame is for the reader
   who arrived without a pointer and has no other way to tell. :focus-visible
   would not have expressed this — a text input matches it on a plain click too.
   With no script the flag never appears and no frame draws, which is where this
   started; the caret remains, as it does for every mouse user now.

   The drawer is in this list rather than handled apart: now that it is a
   bordered bar it has a frame of its own to mark, so it takes the same inset
   ring as the other four. Reddening its old bled rule was what could not be
   done — a line spanning the whole panel going accent as a headline below it
   does is two red things competing — and that line is now the table's, not the
   field's. */
:root[data-kbd-nav] .searchfield:not([data-header-searchbar]):focus-within,
:root[data-kbd-nav] [data-drawer] [data-search-form]:focus-within,
:root[data-kbd-nav] [data-header-searchbar] > [data-search-form]:focus-within {
  border-color: var(--accent) !important;
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* ==========================================================================
   Remaining sub-24px hit targets, by rule rather than by instance.

   Same padding/negative-margin trade as the category eyebrow: the touchable box
   grows, the layout does not move. Listed individually because each one had a
   different reason for being small, and a blanket min-height on every link
   would wreck the prose.
   ========================================================================== */

/* Footer credit, on all ten routes — the smallest persistent link on the site.
   min-height rather than padding: both of these are already flex containers
   with their own padding, so a padding-block declaration REPLACED what they
   had and made the box smaller. min-height cannot do that.

   border-box, or the 24 is a floor on the CONTENT and the stamp comes out at
   36 — 24 plus its own 10px of padding and 2px of border. That is what shipped:
   a chip half again as tall as the 24px target it was aiming at, towering over
   the 15px credit line beside it. .kicker below already had the box-sizing for
   this reason; this rule was written without it. */
[data-site] .mcf-mini { min-height: 24px; box-sizing: border-box; align-items: center; }

/* Article byline: the author link and the share button sit on one baseline. */
[data-site] .author-link { display: inline-block; padding-block: 4px; margin-block: -4px; }
[data-site] .byline-share { min-height: 24px; align-items: center; }

/* The article kicker is already a bordered chip; it just sits 3px short. */
[data-site] .kicker { min-height: 24px; box-sizing: border-box; }

/* The heading anchor was 9x9 — a quarter of the minimum, and the hardest thing
   on the site to hit. It is absolutely positioned beside its heading, so
   padding grows the box without moving the icon or reflowing the heading. */
[data-site] .heading-anchor {
  padding: 8px;
  margin: -8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* The "(opens in a new tab)" note on links whose accessible name comes from
   their own text. Clipped rather than display:none so screen readers still
   reach it — and, as a side effect, reader modes that strip the clip show it in
   plain sight, which is a fair outcome for a warning. */
.vh-newtab {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
