/* Marketing App — production additions on top of the Day Ledger tokens.
   Tokens are never overridden here; this file only adds what the live app
   needs and the static mockups did not (forms, auth pages, htmx states). */

.wordmark a { color: inherit; text-decoration: none; }

/* Rail lockup: mark + wordmark on one centre line, theme toggle at the far
   end. Scoped to the rail — the auth and onboarding wordmarks are bare text
   and must stay inline. */
.rail .wordmark { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.rail .wordmark a { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rail .wordmark .mark { flex: none; }

/* ---------- theme toggle ---------- */

.theme-toggle {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  color: var(--muted); background: none;
  border: 1px solid var(--line); border-radius: 2px;
  cursor: pointer; padding: 0;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink); }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }

/* The switcher posts, so its items are buttons styled as the mockup's links. */
.org-menu form { margin: 0; }
.org-menu .org-item {
  display: block; width: 100%; text-align: left;
  font: 400 13px/1.3 var(--sans);
  color: var(--ink); background: none; border: 0;
  padding: 8px 20px; cursor: pointer;
}
.org-menu .org-item:hover { background: var(--panel); }
.org-menu .org-item[aria-current="true"] {
  font-weight: 600; border-left: 3px solid var(--ink); padding-left: 17px;
}

.rail-foot .signout { margin-top: 8px; }
.rail-foot .signout button {
  font: 400 11px/1.4 var(--mono);
  color: var(--faint); background: none; border: 0; padding: 0;
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.rail-foot .signout button:hover { color: var(--ink); }

/* ---------- messages ---------- */

.messages { margin: 18px 0 0; display: grid; gap: 8px; }
.messages .notice.success { border-left-color: var(--ok); }
.messages .notice.warning { border-left-color: var(--attn); }
.messages .notice.error   { border-left-color: var(--err); }

/* ---------- auth pages (stock Django views, same tokens) ---------- */

.auth-shell {
  min-height: 100vh; display: grid; place-items: center;
  padding: 40px 20px; background: var(--paper);
}
.auth-card {
  width: 100%; max-width: 400px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 2px; padding: 28px 28px 32px;
}
.auth-card .wordmark {
  font: 600 17px/1.1 var(--display); letter-spacing: -.02em; margin-bottom: 4px;
}
.auth-card .wordmark .tick { color: var(--attn); }
.auth-card .lede { color: var(--muted); font-size: 14px; margin: 0 0 20px; }
.auth-card .btn { width: 100%; text-align: center; margin-top: 22px; }
.auth-alt {
  margin: 18px 0 0; text-align: center;
  font: 400 12px/1.6 var(--mono); color: var(--muted);
}
.auth-alt a { color: var(--ink); }

/* ---------- forms ---------- */

/* Input types the mockup tokens do not cover, matched to them exactly. */
input[type="password"], input[type="datetime-local"], input[type="time"],
input[type="search"], input[type="tel"] {
  width: 100%;
  font: 400 14px/1.5 var(--sans);
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 9px 11px;
}
input[type="checkbox"], input[type="radio"] { accent-color: var(--ink); }
select { appearance: auto; }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
.form-grid .wide { grid-column: 1 / -1; }
@media (max-width: 760px) { .form-grid { grid-template-columns: 1fr; } }

fieldset.plain { border: 0; margin: 0; padding: 0; }
fieldset.plain > legend {
  font: 500 11px/1 var(--mono); letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); padding: 0; margin: 22px 0 2px;
}
/* An optional group reads as required unless the legend says otherwise, and a
   campaign's goal is the one field people hit a wall on. */
fieldset.plain > legend .opt {
  font-weight: 400; letter-spacing: .05em; color: var(--faint);
  text-transform: none; font-family: var(--sans); font-size: 11px;
}
/* The goal is two controls answering one question, so they get a boxed group
   rather than sitting loose among the campaign's own fields. */
.goal-pick {
  border: 1px solid var(--line); border-radius: 2px; padding: 14px;
  margin: 22px 0 4px; background: var(--panel-dim);
}
/* A legend renders on the border box and ignores the fieldset's padding-top;
   floating it at full width puts it back in normal flow so the group reads as
   one boxed question rather than a caption pinned to a line. */
.goal-pick > legend { float: left; width: 100%; margin: 0; padding: 0; }
.goal-pick .hint.tight { clear: both; margin: 5px 0 2px; }
.goal-pick .field:first-of-type { margin-top: 10px; }
.goal-pick > .hint:last-child { margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--line-soft); }
.goal-pick .or {
  font: 500 10px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--faint); margin: 14px 0 0; display: flex; align-items: center; gap: 10px;
}
.goal-pick .or::before, .goal-pick .or::after {
  content: ""; height: 1px; background: var(--line); flex: 1;
}
.check {
  display: flex; gap: 9px; align-items: flex-start;
  padding: 9px 0; font-size: 14px;
}
.check input { margin-top: 3px; }
.errorlist {
  list-style: none; margin: 5px 0 0; padding: 0;
  font: 400 12px/1.5 var(--sans); color: var(--err);
}

/* ---------- tabs ---------- */

.tabs {
  display: flex; gap: 0; border-bottom: 1px solid var(--line); margin: 0 0 22px;
  max-width: 100%; overflow-x: auto; overscroll-behavior-inline: contain;
}
.tabs a {
  font: 500 11px/1 var(--mono); letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); text-decoration: none;
  padding: 11px 14px; border-bottom: 2px solid transparent; margin-bottom: -1px;
  flex: 0 0 auto;
}
.tabs a:hover { color: var(--ink); }
.tabs a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }

/* ---------- editor ---------- */

.editor textarea { min-height: 420px; font: 400 15px/1.65 var(--sans); }
.editor textarea.mono { font-family: var(--mono); font-size: 13px; }
.version-strip {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  font: 400 11px/1.6 var(--mono); color: var(--muted);
  padding: 10px 0 0; border-top: 1px solid var(--line-soft); margin-top: 12px;
}
.version-strip a { color: var(--muted); }
.version-strip a[aria-current="true"] { color: var(--ink); font-weight: 600; }

/* ---------- diff-free body preview ---------- */

.prose { max-width: 40em; }
.prose h2 { font: 500 20px/1.3 var(--display); margin: 26px 0 8px; }
.prose h3 { font: 600 15px/1.3 var(--sans); margin: 20px 0 6px; }
.prose p { margin: 0 0 14px; }
.prose ul, .prose ol { margin: 0 0 14px; padding-left: 22px; }

/* ---------- filters bar ---------- */

.filters {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;
  padding: 0 0 16px; border-bottom: 1px solid var(--line-soft); margin-bottom: 4px;
}
.filters label.f { margin: 0 0 5px; }
.filters .fgroup { min-width: 150px; }
.filters select, .filters input { padding: 7px 9px; font-size: 13px; }

/* ---------- variant comparison (A25) ---------- */

.variant-flag { font: 500 10px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase; }
.variant-flag.win { color: var(--ok); }
.variant-flag.lose { color: var(--err); }
.variant-flag.muted { color: var(--faint); }
.creative-thumb {
  width: 100%; max-width: 190px; border: 1px solid var(--line-soft); border-radius: 2px;
  display: block; background: var(--panel-dim);
}

/* ---------- htmx ---------- */

.htmx-indicator { opacity: 0; transition: opacity .15s; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
.htmx-request .swap-target { opacity: .45; }

/* ---------- utilities ---------- */

.stack { display: grid; gap: 18px; }
.row-between { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.mono { font-family: var(--mono); }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.nowrap { white-space: nowrap; }
.mt0 { margin-top: 0; }
.mt18 { margin-top: 18px; }
.mb0 { margin-bottom: 0; }
.right { text-align: right; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- manual publish path (A19) ---------- */

.manual-post > summary {
  font: 600 13px/1 var(--sans);
  cursor: pointer; list-style: none;
  border: 1px solid var(--line); border-radius: 2px;
  padding: 10px 16px; display: inline-block;
}
.manual-post > summary::-webkit-details-marker { display: none; }
.manual-post > summary:hover { border-color: var(--ink); }
.manual-post[open] > summary { border-color: var(--ink); margin-bottom: 14px; }
.manual-post .copybox { width: 100%; font: 400 13px/1.6 var(--mono); }
.mono-note {
  font: 500 10px/1.4 var(--mono); letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); margin: 12px 0 0;
}

/* --------------------------------------------------------------------------
   Evidence strip (D28) — screenshots, creatives and files attached to a piece
   of work. Rendered by templates/content/_evidence.html on content detail, the
   agent task page and publications, so it lives here rather than in one page's
   head block. Every src points at content:asset_file, never MEDIA_URL.
   -------------------------------------------------------------------------- */
.evidence { list-style: none; margin: 12px 0 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
/* A grid item's min-width is min-content by default, and a screenshot carries
   its real pixel width in the img attributes — so without this an 880px
   capture made the whole page scroll sideways. */
.evidence li { min-width: 0; }
.evidence img { display: block; width: 100%; max-width: 100%; height: auto;
  max-height: 220px; border: 1px solid var(--line-soft); border-radius: 3px;
  background: var(--panel-dim);
  /* contain, not cover: cropping evidence hides the part somebody needed. */
  object-fit: contain; }
.evidence .filebox { display: flex; gap: 8px; align-items: center; justify-content: center;
  height: 96px; border: 1px dashed var(--line-soft); border-radius: 3px;
  background: var(--panel-dim); color: inherit; text-decoration: none; }
.evidence .filebox.pending { color: var(--faint); }
.evidence .meta { margin-top: 6px; display: grid; gap: 2px; min-width: 0; }
.evidence .meta b { font-size: 13px; font-weight: 600; line-height: 1.4;
  overflow-wrap: anywhere; }
.evidence .by { font: 400 11px/1.5 var(--mono); color: var(--muted); }
.evidence .mono { font-size: 10px; }
.evidence form { margin: 2px 0 0; }
.linky { background: none; border: 0; padding: 0; font: inherit; font-size: 11px;
  color: var(--muted); text-decoration: underline; cursor: pointer; }
.linky:hover { color: var(--ink); }

/* ── Campaign sub-tabs (T11) ─────────────────────────────────────────────
   Three same-weight buttons at three altitudes became navigation plus one
   primary action per section. */
.subtabs { display: flex; gap: 2px; margin: 20px 0 0; border-bottom: 1px solid var(--line); }
.subtabs a { font: 500 13px/1 var(--sans); text-decoration: none; color: var(--muted);
  padding: 11px 14px; border: 1px solid transparent; border-bottom: none;
  border-radius: 3px 3px 0 0; margin-bottom: -1px; }
.subtabs a:hover { color: var(--ink); background: var(--panel-dim); }
.subtabs a[aria-current="page"] { color: var(--ink); background: var(--panel);
  border-color: var(--line); border-bottom-color: var(--panel); font-weight: 600; }
.subtabs .count { font: 500 11px/1 var(--mono); color: var(--faint); margin-left: 6px; }

/* ── What agents are told: the four prompt layers, in order ───────────── */
.layers > div { padding: 13px 0; border-top: 1px solid var(--line-soft); }
.layers > div:first-child { border-top: none; padding-top: 4px; }
.layers .lk { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.layers .num { font: 500 11px/1 var(--mono); color: var(--faint); width: 16px; flex: none; }
.layers .nm { font-weight: 600; font-size: 14px; }
.layers .src { font-size: 12px; }
/* pre-wrap only for text a person typed — their line breaks are meaningful.
   Static copy uses .body-note, or the template's own indentation renders. */
.layers .body { margin: 7px 0 0 26px; font: 400 13px/1.65 var(--sans); color: var(--muted);
  white-space: pre-wrap; }
.layers .body-note { margin: 7px 0 0 26px; font: 400 13px/1.65 var(--sans);
  color: var(--faint); }
.layers details > summary { margin: 7px 0 0 26px; font: 400 12px/1.5 var(--mono);
  color: var(--muted); cursor: pointer; }
.layers details .body { margin-top: 4px; }

/* ── Which message works (T11b) ──────────────────────────────────────── */
.angles { margin: 0; padding: 0; list-style: none; }
.angles > li { display: grid; grid-template-columns: 1fr 240px; gap: 10px 20px;
  align-items: center; padding: 14px 0; border-top: 1px solid var(--line-soft); }
.angles > li:first-child { border-top: none; padding-top: 4px; }
.angles .nm { font-weight: 600; font-size: 15px; }
.angles .sub { font: 400 12px/1.6 var(--mono); color: var(--muted); margin-top: 3px; }
.angles .bar { height: 8px; background: var(--panel-dim); border: 1px solid var(--line-soft);
  border-radius: 2px; overflow: hidden; margin-top: 8px; max-width: 420px; }
.angles .bar > i { display: block; height: 100%; background: var(--ink); }
.angles .bar > i.weak { background: var(--line); }
.angles .nums { display: flex; gap: 20px; justify-content: flex-end;
  font: 400 12px/1.4 var(--mono); font-variant-numeric: tabular-nums; }
.angles .nums div { min-width: 58px; text-align: right; }
.angles .nums .k { display: block; font-size: 10px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 3px; }
.angles .nums b { font-weight: 500; color: var(--ink); font-size: 14px; display: block; }
.angles > li.none .nm { color: var(--muted); font-weight: 400; font-style: italic; }

/* A rate that wraps onto two lines reads as two numbers, so these columns get
   the width they need and the table scrolls inside its own container. */
.rate { display: block; font: 400 11px/1.5 var(--mono); color: var(--faint);
  margin-top: 2px; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.grid th.num, table.grid td.num { white-space: nowrap; min-width: 86px; }
.nr { color: var(--faint); }
.legend { font: 400 11px/1.7 var(--mono); color: var(--muted); margin: 12px 0 0;
  letter-spacing: .02em; }
.ang { font: 400 11px/1 var(--mono); border: 1px solid var(--line); border-radius: 2px;
  padding: 4px 7px; color: var(--muted); white-space: nowrap; display: inline-block; }
.ang.none { border-style: dashed; color: var(--faint); }
table.grid td a.t { color: var(--ink); font-weight: 600; text-decoration: none; }
table.grid td a.t:hover { text-decoration: underline; text-underline-offset: 3px; }
table.grid td.k { font: 400 12px/1.6 var(--mono); color: var(--muted); white-space: nowrap; }
table.grid td .dest { font: 400 12px/1.55 var(--mono); color: var(--muted); display: block; }
table.grid td .dest .tgt { color: var(--ink); }
table.grid td .made { font: 400 12px/1.55 var(--mono); color: var(--muted); }
tr.unattr td { border-top: 1px solid var(--line); padding-top: 15px; }
tr.unattr td.t { font-style: italic; color: var(--muted); }

@media (max-width: 760px) {
  .angles > li { grid-template-columns: 1fr; }
  .angles .nums { justify-content: flex-start; }
}

/* ── The run timeline (T12) ──────────────────────────────────────────────
   A run reads as a story: one block per action, in order, with the evidence
   for that action directly underneath it. The screenshots were already being
   stored — rendering them as one undifferentiated grid on the task is what
   made "what did it actually do" unanswerable. */
.facts { display: flex; gap: 26px; flex-wrap: wrap; margin: 14px 0 0; padding: 13px 0;
  border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);
  font: 400 12px/1.6 var(--mono); color: var(--muted); font-variant-numeric: tabular-nums; }
.facts b { color: var(--ink); font-weight: 500; }

.tl { margin: 0; padding: 0; list-style: none; }
.tl > li { display: grid; grid-template-columns: 74px 1fr; gap: 0 18px;
  padding: 18px 0; border-top: 1px solid var(--line-soft); }
.tl > li:first-child { border-top: none; padding-top: 4px; }
.tl .gutter { font: 400 12px/1.6 var(--mono); color: var(--faint);
  font-variant-numeric: tabular-nums; }
.tl .gutter .seq { display: block; font-weight: 600; color: var(--muted); }
.tl .hd { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.tl .kind { font: 500 11px/1 var(--mono); letter-spacing: .07em; text-transform: uppercase;
  border: 1px solid var(--line); border-radius: 2px; padding: 4px 6px; color: var(--muted); }
.tl .kind.posted { border-color: var(--ok); color: var(--ok); }
.tl .kind.skipped { border-color: var(--line); color: var(--faint); }
.tl .kind.failed { border-color: var(--err); color: var(--err); }
.tl .kind.ad_change { border-color: var(--attn); color: var(--attn); }
.tl .target { font-weight: 600; font-size: 15px; }
.tl .out { margin-left: auto; }
.tl .copy { margin: 10px 0 0; padding: 12px 14px; background: var(--panel-dim);
  border: 1px solid var(--line-soft); border-radius: 3px; }
.tl .copy .ct { font-weight: 600; font-size: 14px; margin: 0 0 5px; }
.tl .copy .ct a { color: var(--ink); text-decoration: none; }
.tl .copy .ct a:hover { text-decoration: underline; text-underline-offset: 3px; }
.tl .copy .cb { margin: 0; font: 400 13px/1.7 var(--sans); color: var(--muted);
  white-space: pre-wrap; }
.tl .copy .cf { margin: 9px 0 0; font: 400 11px/1.6 var(--mono); color: var(--faint); }
.tl .why { margin: 9px 0 0; font: 400 13px/1.7 var(--sans); color: var(--muted); }

.delta { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin: 10px 0 0;
  font: 400 13px/1.6 var(--mono); }
.delta .was { color: var(--muted); text-decoration: line-through; }
.delta .arrow { color: var(--faint); }
.delta .now { color: var(--ink); font-weight: 600; }
.delta .k { color: var(--faint); font-size: 12px; }

/* Visible, never blocking: a fuzzy score must not be the last word on a
   publish path — the person reading the run is. */
.repeat { margin: 10px 0 0; padding: 9px 12px; border: 1px dashed var(--attn);
  border-radius: 3px; background: var(--attn-bg);
  font: 400 12px/1.6 var(--sans); color: var(--ink); }

.cost { display: flex; gap: 24px; flex-wrap: wrap;
  font: 400 12px/1.6 var(--mono); color: var(--muted); font-variant-numeric: tabular-nums; }
.cost b { color: var(--ink); font-weight: 500; }

@media (max-width: 640px) {
  .tl > li { grid-template-columns: 1fr; gap: 8px; }
  .tl .gutter { display: flex; gap: 10px; }
}

/* Present for a screen reader, absent for everyone else. A table this wide
   needs a caption; sighted readers already have the heading above it. */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* the four numbers that matter, tabular so they line up down the page */
.nums { display: flex; gap: 22px; font: 400 12px/1.4 var(--mono);
  font-variant-numeric: tabular-nums; min-width: 300px; }
.nums div { min-width: 62px; }
.nums .k { display: block; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 3px; }
.nums b { font-weight: 500; color: var(--ink); font-size: 14px; }

/* ── Ad campaign tables ──────────────────────────────────────────────────
   Shared by /campaigns/ads/ and the panel on a campaign, so somebody who knows
   one does not have to learn the other. Both were card rows until each row's
   four figures turned out to start wherever that row's status pill left them —
   "Paused" is wider than "Live" — which made a column impossible to read down.
   Everything numeric inherits `td.num`: right-aligned, tabular figures, with
   the headings said once in the `thead` instead of on every row. */
.ad-table td .title { font-weight: 600; color: var(--ink); text-decoration: none; }
.ad-table td .title:hover { text-decoration: underline; text-underline-offset: 3px; }
.ad-table .sub { font: 400 12px/1.6 var(--mono); color: var(--muted); margin-top: 3px; }
.ad-table .sub .sep { color: var(--faint); padding: 0 4px; }
/* The status pill is the widest thing in its column on a paused row. Right
   against the edge it stays put instead of dragging the numbers around. */
.ad-table th.st, .ad-table td.st { text-align: right; white-space: nowrap; }
/* The controls stay on one line. Wrapped, they doubled every row's height and
   pushed the figures apart vertically — the table already scrolls sideways
   inside `.wrap-x`, so width is the cheaper axis to spend here. */
.ad-table td.st .btn-row { flex-wrap: nowrap; justify-content: flex-end; }
.ad-table tbody tr:last-child td { border-bottom: 0; }

.pill.live { border-color: var(--ok); color: var(--ok); }
.pill.held { border-color: var(--line); color: var(--muted); }

/* Four figures beside a name push the row off screen on a laptop. They stack
   instead: name, then the figures as a grid that still lines up column-wise.
   The ad lists no longer need this — they are tables that scroll inside
   `.wrap-x` — but the campaign header and the angle rollup still use `.nums`. */
@media (max-width: 880px) {
  .nums { min-width: 0; flex: 1 1 100%; display: grid; gap: 10px 18px;
    grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .nums div { min-width: 0; }
}
@media (max-width: 440px) {
  .nums { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ── Wide tables scroll inside themselves ────────────────────────────────
   A table with eight columns will not fit a phone. It scrolls in its own
   container so the *page* never scrolls sideways — a body that slides left
   and right makes every other column on the screen feel broken.

   This was a class name borrowed from the mockups, where the rule was
   page-local, and it existed nowhere in the real stylesheet: every table
   using it overflowed the viewport instead. */
.wrap-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.wrap-x > table.grid { min-width: 640px; }

/* ── Mobile navigation ───────────────────────────────────────────────────
   Below 880px the rail is a horizontal band, and twelve links wrapped into
   three rows before any content began — the entire first screen was
   navigation. They collapse behind a disclosure button.

   Desktop is the default and untouched: the button does not exist there and
   the links are always visible, so nothing depends on JS having run. */
.nav-toggle { display: none; }

@media (max-width: 880px) {
  .nav-toggle {
    display: inline-flex; align-items: center; gap: 9px;
    margin-left: auto; cursor: pointer;
    font: 500 12px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase;
    color: var(--muted); background: var(--panel);
    border: 1px solid var(--line); border-radius: 3px; padding: 10px 13px;
    /* 44px of touch target, which a 12px label does not give on its own. */
    min-height: 44px;
  }
  .nav-toggle:hover { color: var(--ink); border-color: var(--ink); }
  .nav-toggle:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

  /* Three bars that become a cross when open, so the button says which way it
     goes rather than only that it is a menu. */
  .nav-toggle .bars,
  .nav-toggle .bars::before,
  .nav-toggle .bars::after {
    display: block; width: 16px; height: 1.5px; background: currentColor;
    transition: transform .15s ease, opacity .15s ease;
  }
  .nav-toggle .bars { position: relative; }
  .nav-toggle .bars::before, .nav-toggle .bars::after { content: ""; position: absolute; }
  .nav-toggle .bars::before { top: -5px; }
  .nav-toggle .bars::after { top: 5px; }
  .nav-toggle[aria-expanded="true"] .bars { background: transparent; }
  .nav-toggle[aria-expanded="true"] .bars::before { top: 0; transform: rotate(45deg); }
  .nav-toggle[aria-expanded="true"] .bars::after { top: 0; transform: rotate(-45deg); }

  .nav-links { display: none; width: 100%; flex-direction: column; gap: 2px; }
  .nav-links.is-open { display: flex; }

  /* Full-width rows with a real touch target, rather than inline words a
     thumb has to aim at. */
  .rail .nav-links a.nav {
    padding: 13px 4px; min-height: 44px; display: flex; align-items: center;
    border-bottom: 1px solid var(--line-soft);
  }
  .rail .nav-links a.nav:last-child { border-bottom: 0; }
  .rail .nav-links a.nav[aria-current="page"] { font-weight: 600; color: var(--ink); }
}

/* The org switcher and the theme toggle live inside the menu wrapper now, so
   on mobile they are behind the button with everything else instead of three
   controls competing for a header band that reflowed differently on every
   page. On desktop the wrapper is display:contents — it vanishes for layout,
   so both sit in the rail column exactly where a flex child would.

   Scoped to desktop rather than left unqualified: this rule is later in the
   file than the mobile block, so an unscoped version won the cascade and the
   menu never collapsed. */
@media (min-width: 881px) { .nav-links { display: contents; } }

@media (max-width: 880px) {
  /* The header band is now the wordmark and the button, and nothing else. */
  .rail > .wordmark { margin-right: auto; }

  .nav-links .org-switch { width: 100%; margin: 4px 0 2px; }
  .nav-links .org-switch > summary { padding: 13px 4px; min-height: 44px; }
  .nav-links .org-menu { position: static; width: 100%; box-shadow: none; }

  /* A settings row rather than an icon floating beside the logo: on a phone a
     bare icon next to the brand reads as part of the brand. */
  .nav-links .theme-toggle {
    width: 100%; min-height: 44px; justify-content: flex-start; gap: 10px;
    padding: 13px 4px; border: 0; border-top: 1px solid var(--line-soft);
  }
  .nav-links .theme-toggle::after {
    content: "Light / dark";
    font: 500 12px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase;
  }
}

@media (max-width: 880px) {
  .tabs { flex-wrap: wrap; overflow-x: visible; }

  /* .shell is a grid with min-height:100vh. Below 880px it becomes one column
     of two auto rows, and the default align-content:stretch then splits the
     leftover viewport height *between* them — so on a short page the header
     band grew to a few hundred pixels of empty space with the wordmark floating
     in the middle of it, and it changed size with every page's content.

     The rail takes the height it needs and the page gets the remainder. */
  .shell { grid-template-rows: auto 1fr; }
  .rail { align-content: start; }
}
