/* ── Typefaces, bundled ────────────────────────────────────────────────────────
   Declared ABOVE the token block on purpose: tests/test_stylesheet_scales.py scans
   everything after `:root` for literal weights and inline face names, and these are
   descriptors, not the type scale. Same-origin files under static/fonts/, with their
   OFL notices and pinned provenance in static/fonts/FONTS.md — no Google Fonts request,
   because a job-search tool should not report each page view to a third party.
   Plex Mono is static and stops at 700; the tokens reach 650 and 780. The weight RANGES
   below map both onto the real Bold file, so nothing is synthesised. Newsreader is
   variable and covers the scale natively. `swap`: text renders in the fallback until
   the file arrives rather than staying invisible. */
@font-face {
  font-family: "Newsreader"; font-style: normal; font-weight: 200 800; font-display: optional;
  src: url("fonts/Newsreader[opsz,wght].ttf") format("truetype");
}
@font-face {
  font-family: "IBM Plex Mono"; font-style: normal; font-weight: 100 549; font-display: optional;
  src: url("fonts/IBMPlexMono-Regular.ttf") format("truetype");
}
@font-face {
  font-family: "IBM Plex Mono"; font-style: normal; font-weight: 550 649; font-display: optional;
  src: url("fonts/IBMPlexMono-SemiBold.ttf") format("truetype");
}
@font-face {
  font-family: "IBM Plex Mono"; font-style: normal; font-weight: 650 900; font-display: optional;
  src: url("fonts/IBMPlexMono-Bold.ttf") format("truetype");
}

:root {
  /* Direction "E · Field notebook", chosen from six by the owner (planner 1486). The
     previous scheme's lime and green-black were rejected in his words as "the neon green
     in general, just a bad color choice" and "corporate and AI". Warm umber-black with a
     honey/brass attention colour; --red and --blue keep their jobs from 1441. */
  --ink: #ece2d0;
  --muted: #a2957f;
  /* Lifted from the direction's #8b7f6a by eight per channel — visually the same
     colour, and the smallest step that clears AA on EVERY ground it sits on rather than
     only on --bg. At the given value it measured 4.44:1 on --surface and 4.10:1 on
     --surface-2, both under 4.5 for body text, while passing 4.70:1 against --bg. That is
     exactly the trap 1486 names: an audit against the base background calls it fine. */
  --dim: #938772;
  --decorative: #6f6455;
  /* Body prose sits a step below --ink. It existed already as four near-identical greys
     written by hand (#cbc8c0, #d2cfc7, #c9c7c0, #b9b7b0); nobody perceives those as
     different levels, so they are one token. */
  --prose: #c4b8a4;
  --on-accent: #17130f;
  --surface-quiet: #3b3226;
  --bg: #17130f;
  --surface: #1e1912;
  --surface-2: #262019;
  --line: #3a2f22;
  /* Split, because at 57 uses across 47 selectors an attention colour is the default and
     nothing can stand out (planner 1409). --ok is the resting state a label already names;
     --accent is reserved for the few places that genuinely mean "look here". */
  --ok: #9aa06b;
  --accent: #dba54a;
  --amber: #d9a05e;
  --ink-lit: #f6efe0;     /* a row's title on hover/focus (planner 1486 §4) */
  /* The terrain is masked out from under the masthead by a band this tall, feathered
     below it. Sized from the real header rather than the drawing's own zones, because
     those scale with the picture and the header does not; measured live at 1440 and 390. */
  --masthead-mask: 140px;
  /* How far the highest hypsometric band leans toward --amber. The mockup's own high band
     sits near 50%; 45% is the brightest value at which every text token still clears AA on
     the ground it lights (at the direction's 21% band opacity, --dim measures 4.53:1 there
     and 3.55:1 with the band at full --amber). test_palette_contrast reads this. */
  --terrain-high: 45%;
  /* Every tint and glow below is mixed FROM one of these tokens rather than written as an
     rgba() literal. The palette changed once and five literals of the old scheme stayed
     behind — the body's own radial glow was still the rejected lime, and a detail bar was
     still green-black — because a raw-hex guard cannot see an rgb(). A tint written as
     color-mix(token, N%, transparent) keeps its alpha and moves with the palette
     (codex 1737). Three of those five sites were not palette residue but accent-budget
     evasion: the body haze, the local-badge dot and the batch-review region had all been
     lime as literals, invisible to the five-selector guard from 1409. None of them means
     "look here", so they do not take --accent now either — the haze is a cream lift, the
     dot is --ok as the resting state its label names, the region a neutral border. */
  --red: #ff8275;
  --blue: #8dd7ff;
  --radius: 2px;

  /* Rank, as tokens. Colour and radius were tokenised from the start; size, space,
     weight and leading never were, and those are what the eye uses to tell a heading
     from an aside. 19 font sizes with half-pixel steps, nine weights within fifty units
     of each other and eleven leadings meant everything competed at equal weight, which
     reads as noise however restrained the palette is (planner 1403/1407).

     THE RULE THAT KEEPS IT: a new size, space, weight or leading needs a new token here.
     Not a convention to remember — a thing visible in the diff. That is the only reason
     colour stayed healthy while these drifted. */
  --t-display: clamp(28px, 4vw, 48px);
  --t-title: 20px;
  --t-lead: 15px;
  --t-body: 13px;
  --t-small: 12px;
  --t-micro: 11px;
  --t-nano: 10px;

  --w-plain: 400;
  --w-medium: 600;
  --w-strong: 650;
  --w-heavy: 780;

  --lh-tight: 1.1;
  --lh-heading: 1.25;
  --lh-body: 1.55;

  --s0: 2px;
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  /* Page-level steps (planner 1807). Every step above is component-internal; with the
     panels gone, the distance between one section and the next is the only grouping
     there is, and it cannot be the same 24px that separates a heading from its subtitle.
     The mockups use ~46px between sections against 6–24px within them. */
  --s6: 40px;
  --s7: 64px;

  /* One measure for prose. Line length was 78ch, 88ch and 92ch depending on the page, and
     92ch is well past where the eye reliably finds the start of the next line. A wide
     variant exists for data, and is a named second value rather than a third ad-hoc one
     (planner 1419). */
  --measure: 72ch;
  --measure-wide: 96ch;

  /* Owner's rule, decided at planner 1409: mono for labels and data, Inter for prose.
     Labels, state chips, identifiers, counts, scores, timestamps, money, anything
     tabular is mono; sentences a person reads are Inter. */
  /* A serif reading face is where the warmth comes from: it makes the fit reasoning read
     as a note from someone rather than a field in a record. Inter was most of what the
     owner called "corporate and AI" (planner 1486). No sans anywhere. */
  --face-prose: "Newsreader", Georgia, "Times New Roman", serif;
  --face-data: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

* { box-sizing: border-box; }
body {
  margin: 0;
  color: var(--ink);
  background:
    radial-gradient(circle at 85% -15%, color-mix(in srgb, var(--ink) 9%, transparent), transparent 30rem),
    var(--bg);
  font-family: var(--face-prose);
  line-height: var(--lh-body);
}
/* A link needs an affordance of its own. It took the surrounding text colour and a dozen
   components stripped the underline, so across much of the product a link was
   indistinguishable from the text beside it and the only cue was the cursor (planner 1419).
   Components that deliberately look like chips or buttons still opt out below. */
a { color: inherit; text-decoration: underline; text-decoration-color: var(--decorative);
    text-underline-offset: 2px; }
a:hover { text-decoration-color: currentColor; }
button, select { font: inherit; }
.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; }

.masthead {
  min-height: 72px;
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--line);
}
/* The bar is full-bleed; its contents take main's measure, so the wordmark and the
   page's first heading share a left edge at every width (planner 1858). */
.masthead-inner {
  width: min(1180px, calc(100% - 40px));
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3) var(--s5);
  align-items: center;
  justify-content: space-between;
}
/* Seven places in one row, wrapping to a second on a phone rather than folding into a
   menu: what is visible is what a person can reach. The open place is the lit one. */
.places { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); }
.navlink[aria-current="page"] { color: var(--ink); border-bottom: 1px solid var(--ink); padding-bottom: var(--s0); }
.find-jobs { margin: 0; }
.brand-lockup { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s1) var(--s2); min-width: 0; }
.brand { text-decoration: none; text-transform: uppercase; letter-spacing: .14em; font-weight: var(--w-heavy); font-size: var(--t-body); white-space: nowrap; }
.brand-mark { color: var(--accent); margin-left: var(--s0); }
/* One attention identity. The waypoint mark on the map's plotted course is the same mark
   that appears at the left of a row on hover and focus — "the thing you click is the thing
   the map has been drawing" (planner 1486 §4). It is the only brass here: the ridges are
   relief and keyboard focus is a neutral ring, because the accent budget (planner 1409)
   counts what reaches for the colour, and a credit link's focus is not the mark. */
.waypoint-mark { color: var(--accent); }
.brand-credit a:focus-visible { outline: 2px solid var(--muted); outline-offset: 4px; }
.pform-section > summary:focus-visible { outline: 2px solid var(--muted); outline-offset: 2px; }
.brand-credit { color: var(--muted); font-size: var(--t-micro); letter-spacing: .01em; white-space: nowrap; }
.brand-credit a { text-decoration: none; }
.brand-credit a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.masthead-meta { display: flex; align-items: center; gap: var(--s4); }
.local-badge { color: var(--muted); font: var(--t-small) var(--face-data); }
.local-badge span { display: inline-block; width: 7px; height: 7px; margin-right: var(--s2); border-radius: 50%; background: var(--ok); box-shadow: 0 0 14px color-mix(in srgb, var(--ok) 60%, transparent); }
.workspace-switcher select { color: var(--ink); padding: var(--s2) var(--s5) var(--s2) var(--s3); border-radius: var(--radius); }

main { width: min(1180px, calc(100% - 40px)); margin: 0 auto; padding: var(--s7) 0 var(--s7); }
.eyebrow { margin: 0 0 var(--s3); color: var(--muted); font: var(--w-heavy) var(--t-micro)/var(--lh-tight) var(--face-data); letter-spacing: .14em; text-transform: uppercase; }
h1, h2, h3, p { margin-top: 0; }
h1 { max-width: 900px; margin-bottom: 0; font-size: var(--t-display); font-weight: var(--w-strong); line-height: var(--lh-tight); letter-spacing: -.045em; }
/* One rank per heading level, from the tokens. There was no bare h2 rule at all, so the
   same semantic element rendered anywhere from 10px to display size depending on which
   container it landed in — rank determined by nesting rather than by meaning, across the
   77 h2 and 31 h3 in the templates (planner 1418). */
h2 { font-size: var(--t-title); font-weight: var(--w-strong); line-height: var(--lh-heading);
     letter-spacing: -.02em; }
h3 { font-size: var(--t-lead); font-weight: var(--w-medium); line-height: var(--lh-heading); }

/* A display-sized heading is one role, written once, rather than the same override
   repeated in three unrelated containers. */
.empty-state h2, .honesty-heading h2, .evaluation-heading h2 { font-size: var(--t-display); }

/* Two of the old h2 overrides were labels wearing a heading tag — eyebrows, not section
   titles. They keep the label treatment and stop competing on the heading scale. */
.signal-grid h2, .track-head h2, .flight h2,
.ats-suggestions h3, .eval-main h3, .eval-rail h3 {
     font-size: var(--t-nano); font-weight: var(--w-heavy); line-height: var(--lh-tight);
     letter-spacing: .12em; text-transform: uppercase; font-family: var(--face-data); }
.review-heading { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: var(--s5); align-items: end; margin-bottom: var(--s5); }
.review-note { margin: 0; color: var(--muted); font-size: var(--t-body); }

.opportunity-list { display: grid; gap: var(--s4); }
.opportunity-card { padding: clamp(24px, 4vw, 44px); }
.card-topline { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s5); }
.recommendation, .strategy { font: var(--w-heavy) var(--t-micro) var(--face-data); letter-spacing: .1em; text-transform: uppercase; }
.recommendation { color: var(--bg); background: var(--ok); padding: var(--s2) var(--s2); }
.recommendation-high-value-stretch { background: var(--amber); }
.recommendation-interesting { color: var(--ink); }
.strategy { color: var(--muted); }
.opportunity-title { display: inline-flex; flex-direction: column; text-decoration: none; margin-bottom: var(--s4); }
.opportunity-title span { font-size: var(--t-display); font-weight: var(--w-strong); line-height: var(--lh-tight); letter-spacing: -.035em; }
.opportunity-title small, .company-name { margin-top: var(--s2); color: var(--ink); font-size: var(--t-lead); }
.facts { display: flex; flex-wrap: wrap; gap: var(--s2) 0; color: var(--muted); font: var(--t-small) var(--face-data); text-transform: uppercase; }
.facts span:not(:last-child)::after { content: "/"; margin: 0 var(--s3); color: var(--decorative); }
.explanation { max-width: 880px; margin: var(--s5) 0; color: var(--prose); white-space: pre-line; }
.explanation.long { font-size: var(--t-lead); line-height: var(--lh-body); }
.signal-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); padding: var(--s5) 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.signal-grid h2 { color: var(--muted); }
.signal-grid p { margin: var(--s2) 0 0; font-size: var(--t-body); }
.signal-grid b { color: var(--muted); margin-right: var(--s2); font: var(--t-nano) var(--face-data); }
.muted { color: var(--dim); }

.card-actions { display: flex; gap: var(--s4); align-items: center; justify-content: space-between; margin-top: var(--s5); }
.card-actions form, .detail-actions form { display: flex; gap: var(--s2); align-items: center; }
/* keeps its fill and edge: a button is a target, and a target needs a shape the eye finds
   before the hand does; spacing cannot say "press here". Every button-shaped control
   shares this one rule. */
button, .button-primary, .act-open, .skip-menu summary {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 40px; padding: 0 var(--s4); border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--ink); background: var(--surface-2); text-decoration: none; cursor: pointer; font-weight: var(--w-strong);
}
button:hover, button:focus-visible { border-color: var(--muted); }
.button-primary { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }
.detail-link { color: var(--muted); font-size: var(--t-body); text-decoration-color: var(--dim); text-underline-offset: 4px; }
.skip-menu { position: relative; }
.skip-menu summary { list-style: none; cursor: pointer; padding: var(--s2) var(--s3); font-weight: var(--w-strong); }
.skip-menu summary::-webkit-details-marker { display: none; }
.skip-menu > div { /* keeps its fill and edge: a popover floats over content and must be opaque, or the
     menu and the text beneath it collide. */ position: absolute; z-index: 2; left: 0; top: calc(100% + 8px); width: 250px; padding: var(--s3); background: var(--surface-2); border: 1px solid var(--line); box-shadow: 0 20px 45px color-mix(in srgb, var(--bg) 45%, transparent); }
.skip-menu label { display: grid; gap: var(--s2); color: var(--muted); font-size: var(--t-small); }
.skip-menu select { width: 100%; padding: var(--s2); color: var(--ink); background: var(--bg); }
.skip-menu button { width: 100%; margin-top: var(--s3); }

.empty-state { margin-top: var(--s5); min-height: 320px; padding: var(--s5); display: flex; flex-direction: column; justify-content: center; border: 1px dashed var(--line); background: color-mix(in srgb, var(--ink) 1.5%, transparent); }
.empty-state h2 { margin-bottom: var(--s2); }
.empty-state p { max-width: 620px; color: var(--muted); }
.empty-mark { color: var(--ink); font-size: var(--t-display); line-height: var(--lh-tight); font-weight: var(--w-heavy); }
.choose-workspace { max-width: 760px; }
.workspace-list { display: grid; gap: var(--s3); margin-top: var(--s5); }
.workspace-list a { display: flex; gap: var(--s4); align-items: center; padding: var(--s4); text-decoration: none; border-bottom: 1px solid var(--line);
}
.workspace-list a span { display: grid; place-items: center; width: 34px; height: 34px; color: var(--bg); background: var(--ok); font-weight: var(--w-heavy); }

.back-link { display: inline-block; margin-bottom: var(--s5); color: var(--muted); text-underline-offset: 4px; }
.detail-hero { display: flex; justify-content: space-between; align-items: end; gap: var(--s5); padding-bottom: var(--s5); border-bottom: 1px solid var(--line); }

.apply-link { flex: 0 0 auto; }
.detail-actions { padding: var(--s4) 0; border-bottom: 1px solid var(--line); }
.honesty-panel { margin-top: var(--s6); padding: clamp(24px, 4vw, 40px); }
.honesty-panel.honesty-blocked { border-top-color: var(--red); }
.honesty-heading { display: flex; justify-content: space-between; gap: var(--s5); align-items: start; margin-bottom: var(--s5); }
.honesty-heading h2 { margin-bottom: 0; }
.honesty-status { text-align: right; }
.honesty-status strong { display: block; color: var(--ok); text-transform: uppercase; font: var(--w-heavy) var(--t-body) var(--face-data); }
.honesty-blocked .honesty-status strong { color: var(--red); }
.honesty-status span { color: var(--muted); font-size: var(--t-small); }
.honesty-violation { display: grid; grid-template-columns: 70px 1fr; gap: var(--s4); margin-top: var(--s3); padding: var(--s4); border-left: 3px solid var(--amber); }
.honesty-violation.severity-block { border-left-color: var(--red); }
.honesty-violation > span { color: var(--amber); font: var(--w-heavy) var(--t-nano) var(--face-data); text-transform: uppercase; }
.honesty-violation.severity-block > span { color: var(--red); }
.honesty-violation b { font-size: var(--t-body); }
.honesty-violation p { margin: var(--s2) 0 0; color: var(--muted); font-size: var(--t-body); }
.honesty-violation blockquote { margin: var(--s3) 0 0; padding-left: var(--s3); border-left: 2px solid var(--muted); color: var(--ink); font-size: var(--t-body); }
.honesty-clear { color: var(--ok); }
.ats-suggestions { margin-top: var(--s5); }
.ats-suggestions h3 { color: var(--muted); }
.ats-suggestions p { display: flex; gap: var(--s3); align-items: start; margin: var(--s2) 0; font-size: var(--t-body); }
.ats-suggestions span { color: var(--bg); background: var(--blue); padding: var(--s0) var(--s1); font: var(--w-heavy) var(--t-nano) var(--face-data); }
.material-links { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--line); }
.material-links a { padding: var(--s2) var(--s3); color: var(--muted); text-decoration: none; font: var(--t-micro) var(--face-data); }
.material-links a:hover { color: var(--ink); border-color: var(--muted); }
.evaluation-block { padding: var(--s5) 0; border-bottom: 1px solid var(--line); }
.evaluation-heading { display: flex; justify-content: space-between; gap: var(--s4); align-items: start; }

.score { color: var(--ink); font: var(--t-display)/var(--lh-tight) var(--face-data); }
.dimension-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s0); margin-bottom: var(--s5); }
.dimension-grid > div { padding: var(--s4); }
.dimension-grid span { color: var(--muted); text-transform: capitalize; font-size: var(--t-small); }
.dimension-grid b { float: right; color: var(--muted); font: var(--t-title) var(--face-data); }
.dimension-grid p { clear: both; margin: var(--s4) 0 0; color: var(--prose); font-size: var(--t-body); }
.evidence-table-wrap { overflow-x: auto; }
.evidence-table { width: 100%; border-collapse: collapse; font-size: var(--t-body); }
.evidence-table th { color: var(--muted); text-align: left; font: var(--w-heavy) var(--t-nano) var(--face-data); letter-spacing: .12em; text-transform: uppercase; }
.evidence-table th, .evidence-table td { padding: var(--s4) var(--s3); border-bottom: 1px solid var(--line); vertical-align: top; }
.evidence-class { display: block; color: var(--muted); font: var(--w-heavy) var(--t-nano) var(--face-data); }
.class-gap { color: var(--red); }
.class-adjacent { color: var(--amber); }
.evidence-table small { display: block; color: var(--muted); margin-top: var(--s1); }
.provenance { margin-top: var(--s4); color: var(--dim); font: var(--t-micro) var(--face-data); }
.evaluation-signals { margin: var(--s5) 0 var(--s5); }
.raw-evaluation { margin-top: var(--s4); border-top: 1px solid var(--line); }
.raw-evaluation summary { padding: var(--s4) 0; cursor: pointer; color: var(--muted); font-size: var(--t-small); }
.material-extras summary { padding: var(--s3) 0; cursor: pointer; color: var(--muted); font-size: var(--t-small); }
.raw-evaluation pre { max-height: 420px; overflow: auto; white-space: pre-wrap; color: var(--prose); font: var(--t-micro)/var(--lh-body) var(--face-data); }
.posting-copy { margin-top: var(--s5); }
.posting-copy summary { padding: var(--s4); cursor: pointer; color: var(--muted); }
.posting-copy pre { padding: var(--s5); max-height: 520px; overflow: auto; white-space: pre-wrap; color: var(--prose); font: var(--t-small)/var(--lh-body) var(--face-data); }
.action-result { min-height: 250px; display: flex; flex-direction: column; justify-content: center; }
.action-result h2 { margin-bottom: var(--s0); }
.action-result .detail-link { margin-top: var(--s4); }

@media (max-width: 760px) {
  .masthead { height: auto; min-height: 72px; padding: var(--s3) 0; }
  .masthead-inner { gap: var(--s3); }
  .masthead-meta { max-width: 100%; flex-wrap: wrap; gap: var(--s3); }
  .workspace-switcher { min-width: 0; max-width: 100%; }
  .workspace-switcher select { max-width: 100%; }
  .local-badge { display: none; }
  main { padding-top: var(--s5); }
  /* The fixed action floats over the page's foot, so the pages that carry it keep a
     clear band at the bottom: at 375 it sat on the Add-a-job inputs (codex 1875). */
  .find-jobs { position: fixed; right: var(--s4); bottom: var(--s4); z-index: 2; }
  .has-find main { padding-bottom: calc(var(--s7) + var(--s7)); }
  .review-heading, .signal-grid { grid-template-columns: 1fr; gap: var(--s4); }
  .review-note { max-width: 500px; }
  .opportunity-card { padding: var(--s5) var(--s4); }
  .card-actions, .detail-hero { align-items: stretch; flex-direction: column; }
  .honesty-heading { flex-direction: column; }
  .honesty-status { text-align: left; }
  .honesty-violation { grid-template-columns: 1fr; }
  .card-actions form { flex-wrap: wrap; }
  /* Each choice wraps as a whole. Inline text wrapping broke "set it up by hand"
     across two lines mid-phrase on a 375px screen, which reads as one dead link and
     one stray word rather than as the alternative to importing. */
  .pathline a { display: inline-block; white-space: nowrap; }
  .detail-link { padding: var(--s2) 0; }
  .dimension-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: no-preference) {
  .opportunity-card { animation: rise .36s ease both; }
  @keyframes rise { from { opacity: 0; transform: translateY(8px); } }
}

/* ── Triage console (dashboard) ───────────────────────────────────────────
   Dense, keyboard-first decision surface. One row expanded at a time; the
   collapsed rows stay one line so the whole queue fits on one screen. */
/* The gap between sections: a page-level step, so a group's end reads without a box. */
.console { display: flex; flex-direction: column; gap: var(--s6); }

.statusbar {
  display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  padding: var(--s3) var(--s4);
  font: var(--t-small) var(--face-data); text-transform: uppercase;
  letter-spacing: .08em; color: var(--muted);
}
.statusbar b { color: var(--ink); font-size: var(--t-lead); margin-right: var(--s1); }
.stat-primary b { color: var(--ink); }
.statusbar .muted b { color: var(--dim); }
.elicitation-action { margin-left: auto; color: var(--ok); text-transform: none;
  letter-spacing: 0; font: var(--w-medium) var(--t-small)/var(--lh-heading) var(--face-prose); }
.elicitation-flow { display: flex; align-items: baseline; gap: var(--s2); min-height: 26px;
  padding: 0 var(--s0); color: var(--dim); font-size: var(--t-body); }
.elicitation-flow b { color: var(--ok); }
.elicitation-form { display: grid; gap: var(--s2); max-width: 58rem; padding: var(--s0) 0 var(--s4);
  border-bottom: 1px solid var(--line); }
.elicitation-form label { color: var(--ink); font-weight: var(--w-strong); }
.elicitation-form textarea { width: 100%; resize: vertical; }
.elicitation-context { margin: 0; padding-left: var(--s3); border-left: 2px solid var(--line);
  color: var(--muted); }
.elicitation-controls { display: flex; align-items: center; gap: var(--s3); }
.keyhint { margin-left: auto; color: var(--dim); text-transform: none; letter-spacing: 0; }
.keyhint kbd { /* keeps its edge: a key cap drawn as a key, so the glyph reads as a key. */
  display: inline-block; padding: var(--s0) var(--s1); margin: 0 var(--s0);
  border-radius: 3px; color: var(--muted); font-size: var(--t-micro); border: 1px solid var(--line);
}

.queue { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.row { border-bottom: 1px solid var(--line); outline: none; }

.row-head {
  display: grid; align-items: start; gap: var(--s3); padding: var(--s3) var(--s3); cursor: pointer;
  /* Two columns: the job, and its facts. Both bounded (minmax(0, …)), never `auto`: as
     `auto` a facts column once took its content width and a sentence-long location left
     the title measuring zero (planner 1119). The main column wraps — a title and a why
     are read, not scanned — and the facts column truncates, because a fact that does
     not fit is still recoverable from the body. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 200px); position: relative; padding-right: var(--s6);
}
.row-head > * { min-width: 0; }
.row-main { display: grid; gap: var(--s0); }
.row-line { color: var(--muted); font: var(--t-small) var(--face-data); overflow-wrap: anywhere; }
.row-head .why { margin: 0; font-size: var(--t-small); }
.row-facts { display: grid; gap: var(--s0); justify-items: end; text-align: right; }
.row-facts > * { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-age { color: var(--dim); font: var(--t-nano) var(--face-data); letter-spacing: .08em; text-transform: uppercase; }
.queue-eyebrow { margin: var(--s6) 0 var(--s2); }
/* The Jobs page's one quiet line: what is being looked for, and the numbers that are a
   decision here. Muted, one row, the key hints at its far end. */
.jobs-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2) var(--s4); margin: 0 0 var(--s4);
  color: var(--muted); font-size: var(--t-small); }
.jobs-line b { color: var(--ink); font-weight: var(--w-medium); }
.jobs-flight { margin: var(--s6) 0 0; font-size: var(--t-body); }
.queue-stretch .row-title { color: var(--muted); }

/* ── One job row, two callers ─────────────────────────────────────────────────
   A job in a list was built twice: `.row-*` for the ranked queue and `.found-*`
   for the found list. The two copies had already diverged on every shared
   element — the title's weight and tracking, the employer's colour, face and
   size, and whether the facts read as uppercase labels or as a sentence
   (planner 1710, measured three hours after the second family was written).
   The tell was in this file. `.found-title` carried "same reasoning as
   .row-title" and then restated the rule, because there was nowhere to put the
   shared part — which is how 1445's sixteen implementations of three components
   happened, one reasonable copy at a time.
   Settled here while there are only two callers. "In flight" arrives as a third
   under 1700 and inherits these rather than starting a fourth family.
   THE THREE SETTLED VALUES, and why each went the way it did:
   - the title takes the queue's typography (medium, -.01em); it was the more
     considered of the two and the found list had simply not set them.
   - the employer and the facts take the found list's mono treatment, because
     1700 specifies "employer · location · pay in mono beneath" for BOTH lists —
     the bright Inter employer column predates the mockups, and item 5 moves the
     queue there anyway. Employer stays one step brighter than the rest of the
     facts so it keeps its rank as the second string a person reads.
   - the facts read as a sentence, not uppercase labels: a location is a phrase,
     and shouting "PAWTUCKET, RHODE ISLAND" changes how it reads without adding
     anything.
   What genuinely differs stays with its own family below: the queue has a score
   and an expandable body, the found list has a source link. */
.row-title, .found-title {
  font-weight: var(--w-medium); font-size: var(--t-lead); letter-spacing: -.01em;
  color: var(--ink);
  /* A job title carries its distinguishing qualifier at the end, so it wraps
     rather than truncating, and an unbroken token breaks rather than hanging
     outside its column (planner 1692, codex 1696). */
  white-space: normal; overflow: visible; text-overflow: clip; overflow-wrap: anywhere;
}
.row-company, .found-employer {
  color: var(--muted); font: var(--t-small) var(--face-data);
  /* Wraps for the same reason the title and the facts line do. Mono is wider per
     character than the Inter this used to be set in, so moving the employer to the
     facts face made a 32-character name measure 231px against a 202px column and
     truncate in all eight rows, where none had truncated before — the consolidation
     reintroducing exactly the defect 1119 and 1692 are about. An employer clipped to
     "Pawtucket Electrical Contr…" has lost the part that identifies it. */
  white-space: normal; overflow: visible; overflow-wrap: anywhere;
}
.row-comp, .row-meta, .found-meta { color: var(--dim); font: var(--t-small) var(--face-data); }
.badge {
  font: var(--w-heavy) var(--t-nano) var(--face-data); letter-spacing: .1em;
  text-align: center; padding: var(--s1) var(--s2); color: var(--bg); background: var(--dim);
}
.badge-must, .badge-strong { background: var(--ok); }
.badge-stretch { background: var(--amber); }
.badge-maybe { color: var(--ink); }
.badge-low, .badge-no { color: var(--dim); }
.row-score { color: var(--muted); font: var(--t-body) var(--face-data); }

.row-body { display: none; padding: 0 var(--s3) var(--s3) var(--s3); }
.row.is-open .row-body { display: block; }
.why { margin: 0 0 var(--s2); color: var(--prose); font-size: var(--t-body); line-height: var(--lh-body); max-width: var(--measure); }
.comp-note { margin: 0 0 var(--s3); color: var(--amber); font-size: var(--t-body); max-width: var(--measure); }
.signals { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2) var(--s5); margin-bottom: var(--s3); }
.sig { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s1); }
.sig li { font-size: var(--t-small); color: var(--prose); padding-left: var(--s4); position: relative; }
.sig li::before { position: absolute; left: 0; font-weight: var(--w-heavy); }
.sig-plus li::before { content: "+"; color: var(--ok); }
.sig-minus li::before { content: "−"; color: var(--amber); }

.actions { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.act { min-height: 32px; padding: 0 var(--s3); font-size: var(--t-body); font-weight: var(--w-strong); }
.act-yes { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }
.act-no:hover { border-color: var(--red); }
.reason {
  min-height: 32px; padding: 0 var(--s2); color: var(--muted); background: var(--bg); border-radius: var(--radius); font-size: var(--t-small);
}
.actions .detail { margin-left: auto; color: var(--muted); font-size: var(--t-small); }

.clear-queue {
  padding: var(--s5); border: 1px dashed var(--line); background: color-mix(in srgb, var(--ink) 1.5%, transparent);
  color: var(--muted);
}
.clear-queue b { color: var(--ink); display: block; margin-bottom: var(--s1); font-size: var(--t-title); }
/* Said about results that are visible immediately below it, so it is a caption on them
   rather than the empty state .clear-queue draws — one readable line, no dashed box,
   nothing on the page larger than the jobs it qualifies. */
.queue-qualifier { margin: 0 0 var(--s0); color: var(--muted); font-size: var(--t-body); max-width: var(--measure); }
/* Found rows can arrive out of band DURING a run, and the panel above them cannot be
   replaced when they do: it sits inside #search-results, which carries editable work and
   is never swapped by a running poll. The server condition handles a full page; this
   follows the rows' actual arrival in the DOM, so an empty-outcome panel stops dominating
   records that are now on the screen (codex 1500). A failure keeps its full weight. */
body:has(#found-jobs li) .clear-queue {
  padding: 0; border: 0; background: none; margin: 0 0 var(--s0);
}
body:has(#found-jobs li) .clear-queue b {
  display: inline; margin: 0; color: var(--muted); font-size: var(--t-body);
}

.flight { border-top: 1px solid var(--line); padding-top: var(--s6); }
.flight h2 {
  margin: 0 0 var(--s3); color: var(--muted);
 
}
.flight ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s0); }
.flight li {
  display: grid; align-items: baseline; gap: var(--s3); padding: var(--s2) var(--s3);
  grid-template-columns: 88px minmax(0, 1.4fr) minmax(0, .7fr) 1fr auto; font-size: var(--t-body); border-bottom: 1px solid var(--line);
}
.flight li > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pstate {
  font: var(--w-heavy) var(--t-nano) var(--face-data); letter-spacing: .08em;
  text-transform: uppercase; color: var(--blue);
}
.pstate-prepared, .pstate-offer { color: var(--ok); }
.pstate-applied, .pstate-responded, .pstate-interviewing { color: var(--amber); }
.pcompany { color: var(--muted); }
.pnext { color: var(--dim); font-size: var(--t-small); }
.pblocked { color: var(--red); }
.pdays { color: var(--dim); font: var(--t-micro) var(--face-data); }
.flight-page { border-top: 0; padding-top: 0; }
.flight-lede { max-width: var(--measure); color: var(--prose); margin: 0 0 var(--s5); }
.flight-strip { display: flex; flex-wrap: wrap; gap: var(--s4); margin: var(--s5) 0 0; color: var(--dim);
  font: var(--t-nano) var(--face-data); letter-spacing: .11em; text-transform: uppercase; }

@media (max-width: 860px) {
  /* One column: beside a 200px facts column the job's own column was 150px wide and a
     row head stood 567px tall at 375 (measured), and the six-column rule this replaces
     put the title in a 68px track. The facts go under the job, left-aligned, one line each. */
  .row-head { grid-template-columns: minmax(0, 1fr); }
  .row-facts { justify-items: start; text-align: left; }
  /* Wrapping is set for every width above; here the line simply has its own row. */
  .signals { grid-template-columns: 1fr; }
  .keyhint { display: none; }
  .flight li { grid-template-columns: 1fr; row-gap: var(--s0); border-bottom: 1px solid var(--line);
}
}

/* A decided row: collapsed, dimmed, stays in place so the queue doesn't reflow. */
.row-done { opacity: .55; }
.row-done .row-head { cursor: default; }
.badge-done { background: var(--dim); color: var(--bg); }

/* Tier disclosure: full inventory available, none of it demanding attention. */
.tier > summary {
  padding: var(--s3) var(--s3); cursor: pointer; color: var(--muted);
  font: var(--t-small) var(--face-data); letter-spacing: .06em;
  text-transform: uppercase; list-style: none;
}
.tier > summary::-webkit-details-marker { display: none; }
.tier > summary::before { content: "▸ "; color: var(--dim); }
.tier[open] > summary::before { content: "▾ "; }
.tier > summary b { color: var(--ink); font-weight: var(--w-strong); }
.tier > summary span { color: var(--muted); margin: 0 var(--s1); }
.tier-quiet > summary b { color: var(--muted); }
.queue-sub { padding: 0 var(--s2) var(--s2); gap: var(--s0); }
.wild-note { margin: 0 0 var(--s3); color: var(--blue); font-size: var(--t-body); max-width: var(--measure); }
.funnel {
  list-style: none; margin: 0; padding: var(--s1) var(--s3) var(--s3); display: flex; flex-wrap: wrap;
  gap: var(--s2) var(--s4); color: var(--dim); font-size: var(--t-small);
}
.funnel b { color: var(--muted); font: var(--t-body) var(--face-data); }
/* The counts above are chips and wrap into a row. This is a sentence, so it takes the
   whole width rather than sitting beside a chip and reading as one more of them. */
.funnel-note { flex-basis: 100%; max-width: var(--measure); }
.funnel-sub { list-style: none; margin: var(--s1) 0 0; padding: 0 0 0 var(--s3); }
.funnel-sub li { padding: var(--s0) 0; border-left: 2px solid var(--line); padding-left: var(--s3); }

/* ── Found jobs: the first screen, and until evaluation runs the only one ──────
   This list was `.funnel`, which is a chip strip for short stat counts: flex, wrap,
   gap, --t-small, --dim. Twenty postings flowed through it as a ragged two-column
   wall with "original posting →" repeated under every entry (planner 1700, from the
   live site). It takes the ranked queue's row shape instead — title on its own line
   at reading size, the facts in mono beneath, one row per posting, vertical.
   No card and no panel: rows are separated by a hairline, which is what the rest of
   the product already does and what the direction requires. */
.found-jobs { list-style: none; margin: 0; padding: 0; }
.found-jobs > li {
  position: relative; padding: var(--s3) var(--s5) var(--s3) var(--s3);
  border-top: 1px solid var(--line);
}
.found-jobs > li:first-child { border-top: 0; }
.found-title { display: block; }
.found-meta { margin: var(--s1) 0 0; white-space: normal; overflow-wrap: anywhere; }
.found-state { color: var(--muted); }
.found-state::before { content: " · "; color: var(--dim); }
/* The row's own affordance at its right edge, not a line of text under every entry.
   It stays in the DOM and focusable so the keyboard reaches it, and reveals itself on
   hover or when focused — a control that is only reachable when it is already visible
   is not reachable at all. */
.found-source {
  position: absolute; top: var(--s3); right: var(--s2);
  /* Quiet for now, deliberately. The direction gives this arrow the brass of the
     waypoint mark (planner 1486 §4), but --accent is budgeted to five selectors by
     planner 1409 and is already at five. That budget and the brass row identity are
     two planner rules pointing opposite ways; item 3 of the build order is where the
     row interaction lands, so the conflict gets settled once, there, rather than by
     widening someone else's guard to fit a single arrow. */
  color: var(--muted); text-decoration: none; font: var(--t-body) var(--face-data);
  opacity: 0;
}
.found-jobs > li:hover .found-source,
.found-jobs > li:focus-within .found-source,
.found-source:focus-visible { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .found-source { transition: opacity .12s ease; }
}

/* ── Detail page: second look, same discipline ───────────────────────────── */
.detail { display: flex; flex-direction: column; gap: var(--s4); }
.detail-bar {
  position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s3); background: color-mix(in srgb, var(--bg) 94%, transparent); backdrop-filter: blur(6px); flex-wrap: wrap; border-bottom: 1px solid var(--line);
}
.detail-bar .back { color: var(--muted); font-size: var(--t-title); text-decoration: none; }
.detail-id { display: flex; flex-direction: column; min-width: 0; flex: 1 1 260px; }
.detail-id b { font-size: var(--t-lead); font-weight: var(--w-strong); letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.detail-id span { color: var(--muted); font: var(--t-micro) var(--face-data);
  text-transform: uppercase; overflow-wrap: anywhere; white-space: normal; line-height: var(--lh-body); }
/* A select is as wide as its longest option, and a flex item does not shrink below its
   content — the T-62 defect, in a place T-62's rule cannot reach because that one is
   scoped to `.pform` and this control is not in one. Authored search names arrive here
   now (T-252), so "Community outreach and library programme coordination" made this
   select 438px inside a 390px screen, pushed Pursue, Save and Skip off the right edge and
   scrolled the page to 672px. Wrapping alone would not have done it: without the shrink
   the row is one over-wide item. */
.detail-acts { display: flex; gap: var(--s2); flex-wrap: wrap; min-width: 0; }
.strategy-choice { min-width: 0; }
.strategy-choice select { max-width: 100%; }
.act-open { display: inline-flex; align-items: center; min-height: 32px; padding: 0 var(--s3); border-radius: var(--radius); color: var(--ink); text-decoration: none; font-size: var(--t-body); font-weight: var(--w-strong); }
.detail-state { color: var(--dim); font: var(--t-nano) var(--face-data);
  text-transform: uppercase; letter-spacing: .1em; }

.eval-alt { opacity: .92; }
.eval-head { display: flex; align-items: center; gap: var(--s3); padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.eval-head .badge { padding: var(--s1) var(--s2); }
.eval-score { color: var(--ink); font: var(--t-title) var(--face-data); }
.eval-strategy { color: var(--muted); font: var(--t-micro) var(--face-data);
  text-transform: uppercase; letter-spacing: .1em; }
.eval-prov { margin-left: auto; color: var(--dim);
  font: var(--t-nano) var(--face-data); }

.eval-cols { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(240px, .75fr); }
.eval-main { padding: var(--s4) var(--s4); min-width: 0; }
.eval-rail { padding: var(--s4) var(--s4); border-left: 1px solid var(--line); background: color-mix(in srgb, var(--bg) 16%, transparent); }
.eval-main h3, .eval-rail h3 {
  margin: var(--s4) 0 var(--s2); color: var(--muted);
 
}
.eval-rail h3:first-child, .eval-main h3:first-child { margin-top: 0; }
.reasoning { color: var(--prose); font-size: var(--t-lead); line-height: var(--lh-body); max-width: var(--measure); }
.reasoning h4 { margin: var(--s4) 0 var(--s2); color: var(--muted);
  font: var(--w-heavy) var(--t-nano) var(--face-data);
  letter-spacing: .13em; text-transform: uppercase; }
.reasoning h4:first-child { margin-top: 0; }
.reasoning p { margin: 0 0 var(--s2); }
.reasoning ul { margin: 0 0 var(--s3); padding-left: var(--s4); }
.reasoning li { margin-bottom: var(--s1); }
.reasoning strong { color: var(--ink); font-weight: var(--w-strong); }

.dims { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s1); }
.dims li { display: grid; grid-template-columns: 1fr 62px 26px; align-items: center; gap: var(--s2);
  font-size: var(--t-micro); color: var(--muted); cursor: help; }
.dim-name { text-transform: capitalize; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.dim-bar { height: 5px; border-radius: 3px; overflow: hidden; background: var(--line);
}
.dim-bar i { display: block; height: 100%; background: var(--ok); }
.dim-score { color: var(--ink); font: var(--t-micro) var(--face-data);
  text-align: right; }
.rail-note { margin: 0 0 var(--s3); color: var(--prose); font-size: var(--t-small); }
.pkg { color: var(--muted); font: var(--t-micro) var(--face-data);
  text-transform: uppercase; }
.pkg-blocked { color: var(--red); }
.viol { margin-bottom: var(--s1); border-left: 2px solid var(--amber); }
.viol summary { padding: var(--s2) var(--s2); cursor: pointer; color: var(--amber); font-size: var(--t-micro); }
.viol.severity-block { border-left-color: var(--red); }
.viol.severity-block summary { color: var(--red); }
.viol.severity-ats { border-left-color: var(--blue); }
.viol.severity-ats summary { color: var(--blue); }
.viol p { margin: 0 var(--s2) var(--s2); color: var(--prose); font-size: var(--t-small); }
.viol blockquote { margin: 0 var(--s2) var(--s2); padding-left: var(--s2); border-left: 2px solid var(--line);
  color: var(--ink); font-size: var(--t-small); }
.viol .guide { color: var(--dim); }
.material-links { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s3); }
.material-links a { padding: var(--s1) var(--s2);
  color: var(--muted); font: var(--t-micro) var(--face-data);
  text-decoration: none; }
/* The blocked attempt's review sits directly above these links. Without a visible
   boundary the two read as one package, and the person would take the blocks to be
   about the files underneath them. The rule and the inset are the boundary. */
/* Sits between the counts and the queue: the thing you just did, with the way back.
   Quiet enough not to compete with the next decision, present enough to be found. */
/* Inside the row it belongs to, because that is the job the refusal is about. Red
   enough to stop someone reaching for the same button again. */
/* Present, not alarming. The listing's own statement about itself, which the person
   weighs — not a verdict this system reached about whether the job is still there. */
.source-expiry { color: var(--dim); }
.expiry-passed { color: var(--red); }
.action-refused { margin: var(--s3) 0 0; padding: var(--s2) var(--s3); border-left: 2px solid var(--red); }
.action-refused p { margin: 0 0 var(--s2); color: var(--prose); font-size: var(--t-small); }
.action-refused:focus { outline: 1px solid var(--red); outline-offset: 2px; }
/* Sits with the other "where everything went" disclosures, not above the queue: it is
   something to read when you want it, not an interruption. */
.floor-unknown { margin: 0 0 var(--s3); }
.floor-unknown > summary { padding: var(--s2) var(--s3); cursor: pointer; color: var(--dim);
  font: var(--t-micro) var(--face-data); text-transform: uppercase; }
.floor-unknown > p, .floor-unknown > ul { margin: 0 var(--s3) var(--s3); }
.just-skipped { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3);
  margin: 0 0 var(--s3); padding: var(--s2) var(--s3); }
.just-skipped .js-label { color: var(--dim);
  font: var(--t-micro) var(--face-data); text-transform: uppercase; }
.just-skipped .js-item { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
.just-skipped .js-title { color: var(--muted); font-size: var(--t-small);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.just-skipped .js-all { margin-left: auto; color: var(--dim); font-size: var(--t-micro); }
.earlier-approved { margin-top: var(--s4); padding: var(--s3) 0 0; border-top: 1px solid var(--line); }
.earlier-approved h3 { margin: 0 0 var(--s2); color: var(--muted); }
.earlier-approved .material-links a { border-color: var(--muted); color: var(--muted); }
.ev-ids { font: var(--t-micro) var(--face-data); color: var(--muted); }
.raw-evaluation summary, .posting-copy summary { padding: var(--s3) var(--s4); cursor: pointer;
  color: var(--dim); font-size: var(--t-small); }
.raw-evaluation { border-top: 1px solid var(--line); }
.raw-evaluation pre { margin: 0; padding: var(--s3) var(--s4); max-height: 400px; overflow: auto;
  white-space: pre-wrap; color: var(--prose); font: var(--t-micro)/var(--lh-body) var(--face-data); }

@media (max-width: 900px) {
  .eval-cols { grid-template-columns: 1fr; }
  .eval-rail { border-left: none; border-top: 1px solid var(--line); }
  .detail-bar { position: static; border-bottom: 1px solid var(--line);
}
}

/* Reviewing is a quick action: the decision leads, the rest waits to be asked for. */
.more-reasoning { margin: var(--s1) 0 var(--s3); }
.more-reasoning summary { cursor: pointer; color: var(--dim);
  font: var(--t-micro) var(--face-data); letter-spacing: .08em;
  text-transform: uppercase; }
.more-reasoning[open] summary { margin-bottom: var(--s2); }

/* Only TRANSFERABLE rows carry a note — the transferability argument is the product
   thesis. Everything else is class + evidence ids, which say it without prose. */
.why-transfers { display: block; margin-top: var(--s0); color: var(--muted); font-size: var(--t-micro);
  line-height: var(--lh-heading); }
.evidence-table td:first-child { max-width: 34ch; }

/* Held-back count: visible on purpose. Nothing is hidden, it is queued. */
.stat-waiting b { color: var(--amber); }

/* Posting age: an evergreen req looks identical to a fresh one until you show this. */
.age-stale { color: var(--amber); }

/* Backlog tiers: scanning is a spend decision, so show the size of each choice. */
.tiers { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; padding: var(--s2) var(--s3); }
.tiers-label { color: var(--dim); font: var(--t-nano) var(--face-data);
  letter-spacing: .12em; text-transform: uppercase; margin-right: var(--s1); }
.pill { display: inline-flex; align-items: baseline; gap: var(--s1); padding: var(--s0) var(--s2); border-radius: 999px;
  color: var(--muted); font: var(--t-micro) var(--face-data); }
.pill b { color: var(--ok); font-size: var(--t-small); }
.pill i { color: var(--dim); font-style: normal; }
.pill-old { opacity: .6; }
.pill-old b { color: var(--dim); }

/* A posting that vanished mid-preparation: the loudest thing in the strip, because
   the user is about to spend effort on a role that may no longer exist. */
.listing-gone { color: var(--red); font-weight: var(--w-strong); }

/* ── Profile editor: the surface a friend meets first ─────────────────────── */
.notice { padding: var(--s3) var(--s3); font-size: var(--t-body); }
.notice-ok { border-left: 3px solid var(--ok); color: var(--ink); }
.notice-bad { border-left: 3px solid var(--red); color: var(--red); }

/* The one destructive control on Settings, red so it reads as such, and the dialog that
   confirms it. The dialog keeps a painted surface because a modal must show its own
   extent over the page it interrupts. */
.act-danger { color: var(--red); border-color: var(--red); }
.act-danger:disabled { opacity: .5; }
.clear-jobs { display: flex; align-items: center; gap: var(--s3); margin-top: var(--s6); }
/* keeps its surface: a modal has to show its own extent over the page it interrupts. */
.confirm { background: var(--surface); color: var(--ink); border: 1px solid var(--red);
  border-radius: var(--radius); padding: var(--s4); max-width: min(92vw, 30rem); }
.confirm h2 { margin: 0 0 var(--s3); }
.confirm-actions { display: flex; gap: var(--s3); justify-content: flex-end; margin: var(--s4) 0 0; }
.blockers { padding: var(--s3); }
.blockers b { color: var(--amber); font-size: var(--t-body); }
.blockers ul { margin: var(--s2) 0 0; padding-left: var(--s4); color: var(--muted); font-size: var(--t-body); }
.blockers li { margin-bottom: var(--s0); }

.pform { padding: var(--s4) 0; }
.pform h2 { margin: 0 0 var(--s1); }
.pform h2 small { color: var(--dim); font-size: var(--t-small); font-weight: var(--w-plain); letter-spacing: 0; }
.pform-note { margin: 0 0 var(--s4); color: var(--muted); font-size: var(--t-body); max-width: var(--measure);
  line-height: var(--lh-body); }
.pform-note b { color: var(--ok); }
.fieldrow { display: flex; flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s3); }
/* The owner's rejection in 0962 named "loud uppercase labels" and asked for calm readable
   ones; codex 1045 found them still uppercase, tracked and monospace on the actual screen.
   Body font, sentence case, no tracking. The colour still carries the hierarchy, so the
   label is quieter than its value rather than shouting above it. Every .pform page gets
   this — it was one rule making them all loud and it is one rule making them all calm. */
.pform label { display: flex; flex-direction: column; gap: var(--s1); flex: 1 1 190px;
  color: var(--muted); font-size: var(--t-small); line-height: var(--lh-heading);
  /* A flex item will not shrink below the intrinsic width of its content, and a select
     is as wide as its longest option. On Setup that made three of them — "Where to look",
     the assistance level and the model provider — 371px to 441px inside a 375px screen,
     and the whole page scrolled sideways to 474px. `min-width: 0` lets the item shrink;
     the cap below keeps the control inside it. Same defect codex fixed inline for the
     practice question selector in T-196, as a rule here so the next long option is
     covered too. */
  min-width: 0; }
.pform label.wide { flex-basis: 100%; }
/* A fieldset is only a grouping here; it must not draw a box of its own around a row. */
.ev-fields { border: 0; margin: 0; padding: 0; min-width: 0; }
/* An approved proposal reads as its values rather than as a row of controls. */
.ev-preview { margin: var(--s1) 0; color: var(--ink); overflow-wrap: anywhere; }
.ev-preview.muted { color: var(--muted); font-size: var(--t-body); }
.done-continue { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.done-continue .act { margin-left: auto; text-decoration: none; }
/* The Profile page was 6231px — 8.7 screens and 76 controls, every blank field expanded
   at once, which is what the owner rejected (planner 0962). Each section is a disclosure
   now: its heading, and a short line saying what it holds. A section with something saved
   opens, so nothing already entered has to be hunted for; an empty one stays shut. The
   marker is hidden because the row reads as a heading, and the whole row is the target. */
.pform-section > summary { cursor: pointer; list-style: none; display: flex;
  align-items: baseline; gap: var(--s3); }
.pform-section > summary::-webkit-details-marker { display: none; }
.pform-section > summary > h2 { margin: 0; }
/* `nowrap` overflowed at 390 for a 75-character saved name — measured scrollWidth 653
   against a summary ending at 357 (codex 1009). It wraps and shrinks now, and never
   truncates: the point of the line is showing the authored value. */
.section-state { margin-left: auto; color: var(--muted); text-align: right;
  min-width: 0; overflow-wrap: anywhere;
  font: var(--t-micro) var(--face-data); letter-spacing: .06em; }
.pform-section > summary { flex-wrap: wrap; }
/* A row of labels stretches to its tallest, but each label is its own column and its
   control follows immediately after the text — so a two-line label put its input 26px
   below its neighbour's, measured on Profile's standing answers (planner 0962). Pushing
   the control to the bottom of the stretched cell lines the row up whatever the labels
   do. The checkbox is excluded: it is the first child of its label, and bottoming it
   would drop it under its own caption. */
.pform label > input:not([type="checkbox"]),
.pform label > select,
.pform label > textarea { margin-top: auto; }
/* Bottom-aligning only helps if the controls are the same height, and they were not: an
   input computed 39px against a select's 37px, because a select ignores the line-height
   in the shorthand above. Same padding and border, so the gap is the content box alone —
   this states it once, in em, rather than freezing a pixel height that stops matching
   the moment the font size changes. */
.pform input:not([type="checkbox"]),
.pform select { min-height: calc(1.5em + 18px); box-sizing: border-box; }
/* A checkbox is not a captioned field. `.pform label` is a flex column, so the box landed
   on one line and its caption on the next — "That answer is the notice you owe" rendered
   68px tall with the square floating above the words, and the same defect is visible in
   the builder's own 1280 and 390 screenshots for "Evaluate it now" (planner 0988). The
   `.pillform { display: inline }` further down never had a chance: `.pform label` is the
   more specific rule.

   `:has()` rather than a class, because the planner asked for every `.pform` checkbox and
   not just the two that were noticed; coaching.html:48 had already worked the same defect
   around with an inline style, which is what one template solving a shared problem looks
   like. `nowrap` matters: allowing the row to wrap puts a long caption back on its own
   line, which is the original defect wearing a different rule. The caption reads as a
   sentence rather than a tracked uppercase label, and the whole label stays clickable. */
.pform label:has(> input[type="checkbox"]),
.pform label:has(> input[type="radio"]) {
  flex-direction: row; align-items: flex-start; gap: var(--s2); flex-wrap: nowrap;
  min-height: 32px; text-transform: none; letter-spacing: normal;
  font: var(--t-body)/var(--lh-body) var(--face-prose); }
.pform label > input[type="checkbox"],
.pform label > input[type="radio"] {
  flex: none; width: auto; min-height: 0; margin: var(--s0) 0 0; }
/* keeps its edge: a field is where typing goes, and an edge is what says so. The one
   field rule for every input-shaped control. */
.pform input, .pform textarea, .pform select, .reason, .fillvalue,
.workspace-switcher select, .skip-menu select {
  padding: var(--s2) var(--s3); color: var(--ink); background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius); font: var(--t-body)/var(--lh-body) var(--face-prose);
  text-transform: none; letter-spacing: 0;
  max-width: 100%;
}
.pform input:focus, .pform textarea:focus { outline: none; border-color: var(--ink); }
.pform textarea { resize: vertical; width: 100%; }

.evlist { list-style: none; margin: 0 0 var(--s4); padding: 0; display: grid; gap: var(--s2); }
.ev { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s3); align-items: end;
  padding: var(--s3); border-left: 3px solid var(--dim); }
.ev-approved { border-left-color: var(--ok); }
.ev-draft { border-left-color: var(--amber); }
.ev-empty { display: block; color: var(--muted); font-size: var(--t-body); border-left-color: var(--line); }
.ev-head { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: baseline;
  margin-bottom: var(--s2); }
.ev-id { color: var(--muted); font: var(--t-micro) var(--face-data); }
.ev-state { font: var(--t-nano) var(--face-data); letter-spacing: .1em;
  text-transform: uppercase; color: var(--dim); }
.ev-approved .ev-state { color: var(--ok); }
.ev-draft .ev-state { color: var(--amber); }
.ev-claim { width: 100%; margin-bottom: var(--s2); font-weight: var(--w-medium); }
.ev-detail { margin-bottom: var(--s2); }
.ev-add { display: grid; gap: var(--s3); padding: var(--s3); border: 1px dashed var(--line); }
.ev-add input, .ev-add textarea { width: 100%; }
.rolelist { list-style: none; margin: 0 0 var(--s3); padding: 0; display: grid; gap: var(--s1);
  font-size: var(--t-body); }
.rolelist .muted { font-size: var(--t-small); }
.navlink { color: var(--muted); font: var(--t-small) var(--face-data);
  letter-spacing: .08em; text-transform: uppercase; text-decoration: none; }
.navlink:hover { color: var(--muted); }
/* The number beside Applications is the one on the page it leads to; it is attention in the
   planner's sense (applications out are progress), so it takes the accent — the fifth and
   last selector the budget allows. */
.navcount { color: var(--accent); margin-left: var(--s1); font-weight: var(--w-medium); }
.nav-session { margin: 0; }
button.navlink { min-height: 0; padding: 0; border: 0; background: none; font-weight: inherit; }
.dim-note { color: var(--dim); font-size: var(--t-micro); margin-top: var(--s2); }
.ev-todo { color: var(--amber); font: var(--t-nano) var(--face-data);
  letter-spacing: .08em; text-transform: uppercase; }
.pathline { color: var(--blue); font: var(--t-micro) var(--face-data);
  text-transform: uppercase; letter-spacing: .06em; }

/* Learning panel: proposals live where decisions are made, never applied silently. */
.learning { padding: var(--s1) var(--s3) var(--s3); }
.proposal { margin-top: var(--s3); padding: var(--s3);
  border-left: 3px solid var(--amber); }
.proposal-head { font-size: var(--t-body); margin-bottom: var(--s2); }
.proposal-delta { color: var(--muted); font: var(--t-small) var(--face-data);
  margin-left: var(--s2); }
.proposal p { margin: 0 0 var(--s2); color: var(--prose); font-size: var(--t-body); }
.proposal-caveat { color: var(--amber) !important; font-size: var(--t-small); }
.proposal code { display: inline-block; padding: var(--s1) var(--s2); background: var(--bg); color: var(--muted);
  font: var(--t-micro) var(--face-data); }
.rolelist li { display: flex; justify-content: space-between; align-items: center; gap: var(--s3); }
.rolelist li > details { flex: 1 1 auto; min-width: 0; }
.rolelist details > summary { cursor: pointer; padding: var(--s2) 0; }
.rolelist details form { margin-top: var(--s3); }
.evidence-picker { /* keeps its edge: a scrolling box must show where it ends, or the list looks cut off. */ display: grid; gap: var(--s1); max-height: 210px; overflow: auto;
  margin: var(--s3) 0 var(--s3); padding: var(--s3); background: var(--bg); border: 1px solid var(--line);
}
.evidence-picker label { display: grid; grid-template-columns: auto 1fr; align-items: start;
  gap: var(--s2); font-size: var(--t-small); color: var(--text); }
.evidence-picker input { width: auto; margin-top: var(--s0); }
.inline-del button { min-height: 26px; padding: 0 var(--s2); font-size: var(--t-small); }
.newuser { margin-top: var(--s5); max-width: 620px; }
.srclist { flex-direction: column; align-items: flex-start; }
/* A source name and locator is arbitrary text on one unbroken line, and at 390 it
   pushed the page 17px wider than the viewport (codex 1023). Let the row wrap, and
   let the name itself break when one filename is longer than the row. */
.src-from { color: var(--dim); font: var(--t-nano) var(--face-data);
  min-width: 0; overflow-wrap: anywhere; }
.proposal-actions { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: center; }
.mergefield { padding: var(--s1) var(--s2); font-size: var(--t-small); background: var(--bg); color: var(--ink); }
.batch-review { display: flex; justify-content: space-between; align-items: center; gap: var(--s4);
  margin: var(--s3) 0; padding: var(--s3) var(--s4); border: 1px solid color-mix(in srgb, var(--muted) 30%, transparent);
  background: color-mix(in srgb, var(--ink) 4.5%, transparent); }
.batch-review div { display: grid; gap: var(--s0); }
.batch-review b { color: var(--ink); font-size: var(--t-lead); }
.batch-review span { color: var(--muted); font-size: var(--t-small); line-height: var(--lh-heading); }
.pform .batch-choice { display: flex; flex: 0 0 auto; flex-direction: row; align-items: center;
  gap: var(--s2); width: fit-content; margin: 0 0 var(--s2); color: var(--ink);
  font: var(--w-medium) var(--t-nano) var(--face-data);
  letter-spacing: .08em; text-transform: uppercase; cursor: pointer; }
.pform .batch-choice input { width: auto; margin: 0; padding: 0; accent-color: var(--muted); }
.pform .batch-choice-held { color: var(--amber); cursor: default; }

@media (max-width: 600px) {
  .batch-review { align-items: stretch; flex-direction: column; gap: var(--s3); }
  .batch-review .act { width: 100%; }
}

/* Background jobs: long actions must be visible, not a frozen tab. */
.jobbar { display: flex; align-items: center; gap: var(--s3); padding: var(--s3) var(--s3); border-left: 3px solid var(--blue); }
.job-running { border-left-color: var(--blue); }
.job-done { border-left-color: var(--ok); }
.job-failed { border-left-color: var(--red); }
/* Finished, but it produced something that must not be used. Not a failure of
   the job, so not red — but never the colour that means ready. */
.job-attention { border-left-color: var(--amber); }
.job-state { font: var(--w-heavy) var(--t-nano) var(--face-data);
  letter-spacing: .12em; text-transform: uppercase; color: var(--blue); }
.job-done .job-state { color: var(--ok); }
.job-failed .job-state { color: var(--red); }
.job-attention .job-state { color: var(--amber); }
.job-label { font-size: var(--t-body); font-weight: var(--w-medium); }
.job-secs { color: var(--dim); font: var(--t-micro) var(--face-data); }
.job-msg { color: var(--muted); font-size: var(--t-body); margin-left: auto; }
@media (max-width: 600px) {
  .jobbar { flex-wrap: wrap; }
  .job-msg { flex: 1 1 100%; margin-left: 0; overflow-wrap: anywhere; }
  .jobbar .inline-del { margin-left: auto; }
}
.pillform { display: inline; }
.pill-action { cursor: pointer; border-radius: 999px; min-height: 0; }
.pill-action:hover { border-color: var(--muted); }
.tiers-note { color: var(--dim); font-size: var(--t-micro); margin-left: var(--s1); }
/* A sentence with a button in it, beside the backlog the button fills. */
.recoverable {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2);
  margin: 0 var(--s3) var(--s3); font-size: var(--t-small); max-width: var(--measure);
}
.recoverable b { color: var(--muted); font: var(--t-body) var(--face-data); }

/* --- separate searches, separate rankings (T-22) ------------------------------
   Two strategies are two searches, not two views of one list. The heading exists so
   a decision is always made in the context of the objective that produced the row —
   without it, top picks from searches with different objectives look like one ranking
   the user is expected to reconcile. */
.track + .track { margin-top: var(--s7); }
.track-head { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap;
  padding: var(--s2) var(--s3) var(--s2); border-left: 2px solid var(--ink); }
.track-head h2 { margin: 0; }
.track-objective { margin: 0; color: var(--muted); font-size: var(--t-small); flex: 1 1 320px; }
.track-counts { color: var(--dim); font: var(--t-micro) var(--face-data); }

/* Outcome reporting sits on the in-flight row itself: recording what happened has to
   be as cheap as the decision that started it, or the feedback loop stays theoretical. */
/* The row is a five-column grid and this form is its SIXTH child, so it wrapped onto a new
   row and took the first track -- 88px, less margin, 80px of usable width with the row's
   own overflow: hidden over it. Measured at 1280x900: the form sits x71..151 while the li
   it belongs to is 1178px wide, and the date input runs x71..282.3, clipped 131.3px short.
   Only 'mm/dd/yyyy' survived, with no visible time control and every outcome button stacked
   in a tall narrow column (codex 1642).
   Nothing was overflowing the viewport, which is why a viewport-based check passed: the
   boundary that mattered was this 80px form, an ancestor well inside a 1280px page.
   Spanning the full row gives the existing flex-wrap the width it always assumed it had. */
.outcome-actions {
  display: inline-flex; gap: var(--s1); flex-wrap: wrap; margin-left: var(--s2);
  grid-column: 1 / -1;
}
.outcome-actions .act { padding: var(--s0) var(--s2); font-size: var(--t-micro); }
/* The pipeline row sets `nowrap` with an ellipsis so one long job title cannot push the
   whole row sideways. That inherits into the outcome disclosure, where there is nothing
   to ellipsise and no row to protect -- so when it is opened its contents lay themselves
   out on a single line and simply leave the screen. Measured at 390x844: the details is
   612.8px wide inside a 390px viewport, and the sentence explaining the field starts at
   x364 and ends 258px past the right edge (codex 1638).
   `document.scrollWidth` still reads 390 throughout, because the row clips its overflow
   -- so a page-width assertion sees a page that fits and the text is gone anyway. The
   element's own bounds are the only thing that shows it.
   Scoped to the disclosure alone: the summary keeps `nowrap` so the closed one-click row
   is exactly as compact as before, and `min-width: 0` is what actually lets the flex item
   shrink below its content. */
.outcome-when { white-space: normal; max-width: 100%; min-width: 0; }
.outcome-when > summary { white-space: nowrap; }

/* --- fill-for-review: every value one keystroke from its box --------------------- */
.filllist { list-style: none; margin: var(--s3) 0 0; padding: 0; }
.fillrow { display: grid; grid-template-columns: 1fr auto; gap: var(--s2) var(--s3);
  align-items: start; padding: var(--s3) 0; border-top: 1px solid var(--line); }
.fillhead { grid-column: 1 / -1; display: flex; align-items: baseline; gap: var(--s2);
  flex-wrap: wrap; }
.fillname { color: var(--dim); font-size: var(--t-nano); }
.fillwhy { color: var(--dim); font-size: var(--t-micro); margin: var(--s0) 0 var(--s1); }
.fillvalue { width: 100%; color: var(--ink); border-radius: var(--radius); padding: var(--s2) var(--s2);
  font: var(--t-small)/var(--lh-body) var(--face-data); resize: vertical; }
.fillcopy { align-self: start; min-width: 84px; }
/* Copied rows recede so the eye lands on what is still to do, without hiding
   anything — a value you copied wrongly must remain findable. */
.fillrow.is-copied { opacity: .5; }
.fillrow.is-copied .fillvalue { border-style: dashed; }

/* Where a claim came from, kept beside the claim rather than in a tooltip. */
.provenance { margin: var(--s1) 0 0; color: var(--dim); font-size: var(--t-micro); }
.provenance code { color: var(--decorative); }

/* --- guided first run ---------------------------------------------------------- */
.wizsteps { display: flex; flex-wrap: wrap; gap: var(--s2); list-style: none; margin: 0 0 var(--s3);
  padding: 0; font: var(--t-micro) var(--face-data); }
.wizsteps li { padding: var(--s1) var(--s3); border-radius: 999px; }
.wizsteps li a { color: var(--dim); text-decoration: none; }
.wizsteps li.is-done a { color: var(--muted); }
.wizsteps li.is-current { color: var(--ok); }
.wizsteps li.is-current a { color: var(--ok); }
.ev-detail-label { display: block; margin: var(--s3) 0 var(--s0); }
/* Labels for the fields that used to be labelled by their placeholder (planner 1853). */
.ev-field, .capture-label { display: block; font-size: var(--t-small); color: var(--muted); }
.ev-field > input, .capture-label > input { display: block; width: 100%; margin-top: var(--s1); }
.mergelabel { display: inline-flex; align-items: center; gap: var(--s2); font-size: var(--t-small); color: var(--muted); }
.ev-detail-label textarea { width: 100%; margin-top: var(--s1); }

/* Onboarding readiness. Four states that become true at different moments, so each
   carries its own word rather than a shared bar: "not yet" is a next step, not a
   failure, and it is never louder than the line explaining what is missing. */
.rstate {
  font: var(--w-heavy) var(--t-nano) var(--face-data); letter-spacing: .1em;
  text-transform: uppercase; margin-right: var(--s2);
}
.rstate-yes { color: var(--ok); }
.rstate-no { color: var(--amber); }
.rstate-opt { color: var(--dim); }
.pform-sub {
  margin: var(--s4) 0 var(--s2); color: var(--muted);
  font: var(--w-medium) var(--t-small) var(--face-data); letter-spacing: .06em;
}
.pform-sub small { color: var(--dim); font-weight: var(--w-plain); margin-left: var(--s2); }
/* One line per statement. `.funnel` wraps short chips into a row, which runs two
   different sentences together as soon as the text is a sentence rather than a count. */
.rlist { list-style: none; margin: 0; padding: var(--s1) 0 var(--s3); color: var(--dim); font-size: var(--t-body); }
.rlist li { padding: var(--s0) 0; max-width: var(--measure); }
.rlist b { color: var(--muted); font-weight: var(--w-medium); }

/* A search nothing can feed. Loud enough to notice, because an empty queue every day
   otherwise reads as "the market has nothing for you" — a conclusion the data does not
   support and the user has no way to check. */
.starved {
  margin: var(--s3) var(--s3) var(--s4); padding: var(--s3) var(--s3); border-left: 3px solid var(--amber); font-size: var(--t-body); color: var(--muted);
}
.starved b { color: var(--ink); }
.starved p { margin: var(--s2) 0 0; max-width: var(--measure); }
.starved-firms span {
  display: inline-block; margin: var(--s1) var(--s2) 0 0; padding: var(--s0) var(--s2); border-radius: 999px;
  font: var(--t-micro) var(--face-data); color: var(--dim);
}
.starved-why { margin: var(--s3) 0 0; padding-left: var(--s4); color: var(--dim); }
.starved-why li { padding: var(--s0) 0; max-width: var(--measure); }
.starved-why b { color: var(--muted); font-weight: var(--w-medium); }

/* Getting a stale queue back. The price sits on the button because this is a spend
   decision, and the sentence explaining the price gets its own line rather than
   trailing off the end of one. */
.refresh-all { margin: var(--s3) 0 var(--s1); }
.refresh-all .act i { font-style: normal; font-weight: var(--w-plain); opacity: .75; }
.refresh-note {
  display: block; margin: var(--s2) 0 0; max-width: var(--measure);
  color: var(--dim); font-size: var(--t-small);
}

/* Sign-in and invitation. One column, because a page with two fields on it should not
   look like a dashboard with the dashboard missing. */
.console-narrow { max-width: 46rem; }

/* A secret shown once. Big, monospaced and selectable, because the alternative is
   someone transcribing it by eye and blaming the extension. */
.credential-once { display: block; }
/* keeps its edge: a value meant to be selected and copied whole needs its extent drawn.
   The one rule for every copy target. */
.credential, .mergefield, .proposal code {
  display: block; margin: var(--s2) 0; padding: var(--s2) var(--s3); user-select: all; background: var(--bg); color: var(--ink);
  font: var(--t-body) var(--face-data); word-break: break-all; border: 1px solid var(--line);
}
.inline-form { display: inline; margin-left: var(--s2); }
.act-quiet { padding: var(--s0) var(--s2); font-size: var(--t-micro); }

/* The apply page has two shapes and BOTH conditions have to hold to take the copy path
   away: the extension marked the document (pair.js, before first paint), and the workspace
   is at an assistance level where the keystroke is actually allowed.

   The mark alone was enough in T-253, and that stranded the default install: filling is
   level 3, a clean workspace ships level 1, so the list vanished and the keystroke
   returned 403 — neither path (planner 0887). This copy page is deliberately level 2
   because it touches nothing but Ratherable's own screen, so below level 3 the mark changes
   nothing.

   Default is still the copy path, so no extension, no JS, or a failed content script all
   leave the page working. Every rule here only ever removes. */
.fill-has-ext { display: none; }
html[data-waypoint-fill][data-fill-ready] .fill-has-ext { display: block; }
html[data-waypoint-fill][data-fill-ready] .fill-no-ext { display: none; }
html[data-waypoint-fill][data-fill-ready] #filllist { display: none; }

/* ── Terrain ────────────────────────────────────────────────────────────────────
   Drawn, not an image; masked, not faded (see _terrain.html). Fixed behind everything,
   so the mask zones stay where the drawing puts them while the page scrolls above.
   Bands step from low moss (--ok) to high ochre (--amber) at the direction's 21%. */
.terrain {
  position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none;
  mask-image: linear-gradient(to bottom, transparent 0, transparent var(--masthead-mask),
                              black calc(var(--masthead-mask) + var(--s5) * 2));
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, transparent var(--masthead-mask),
                                      black calc(var(--masthead-mask) + var(--s5) * 2));
}
.masthead, main { position: relative; z-index: 1; }
/* Opacity on the GROUP. The bands are nested fills — the high band sits on the three
   beneath it — so opacity on each path stacks four times, and the top zone measured a
   ground where --dim is 3.38:1 (codex 1748). Inside a group they cover each other
   opaquely and the whole composites once, so the lit ground is one band at 21%. */
.terrain-bands { opacity: .21; }
.terrain-band-1 { fill: color-mix(in srgb, var(--ok) 30%, var(--bg)); }
.terrain-band-2 { fill: color-mix(in srgb, var(--ok) 45%, var(--bg)); }
.terrain-band-3 { fill: color-mix(in srgb, var(--amber) 35%, var(--bg)); }
.terrain-band-4 { fill: color-mix(in srgb, var(--amber) var(--terrain-high), var(--bg)); }
.terrain-contour { fill: none; stroke-width: 1; stroke: var(--muted); }
.terrain-contour-faint { opacity: .30; }
.terrain-contour-mid { opacity: .41; }
.terrain-contour-strong { opacity: .52; }
.terrain-ridge { fill: none; stroke: var(--muted); stroke-width: 1; opacity: .28; }
.terrain-course { fill: none; stroke: color-mix(in srgb, var(--amber) 70%, var(--bg)); stroke-width: 1.2; stroke-dasharray: 1 6; stroke-linecap: round; }
.terrain-spot { font: var(--t-nano) var(--face-data); fill: color-mix(in srgb, var(--amber) 75%, var(--muted)); opacity: .5; }

/* ── Row identity: hover and keyboard focus, identically ──────────────────────
   Brass mark at the left, title brightens, ground lifts one step, a hairline inset; the
   found list keeps its right-edge arrow because that row has an outbound link. A ranked row
   already links to its own detail from its body, and a second link to the same job inside
   one row reads as a job delivered twice — test_search refuses exactly that, rightly. Nothing
   moves or reflows: the mark lives in the row's padding, absolutely placed, and only its
   opacity changes (planner 1486 §4). */
.row, .found-jobs > li { position: relative; }
.row-mark {
  position: absolute; left: var(--s0); top: 50%; width: 8px; height: 8px; transform: translateY(-50%);
  opacity: 0; pointer-events: none;
}
/* keeps its fill: the one state lift. A row under the pointer, under keyboard focus, or
   open: the ground rises one step and a hairline inset marks it. This is the row identity
   planner 1486 §4 asked for, not a container. */
.row:hover, .row:focus-visible, .row:focus-within, .row.is-open,
.found-jobs > li:hover, .found-jobs > li:focus-within {
  background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line);
}
/* The right-edge arrow (planner 1700 item 3) is drawn by the row's HEAD, not by a second
   link: a first cut added an anchor and test_search read it as the job delivered twice.
   On the head, not the row: centred on the row it sat beside the body's text once the row
   was open at 390 (codex 1758). The facts column leaves it room at the right. */
.row-head::after { content: "\2192"; position: absolute; right: var(--s3); top: 50%; transform: translateY(-50%);
  color: var(--muted); font: var(--t-small) var(--face-data); opacity: 0; pointer-events: none; }
.row:hover .row-head::after, .row:focus-visible .row-head::after, .row:focus-within .row-head::after { opacity: 1; }
.row:hover .row-mark, .row:focus-visible .row-mark, .row:focus-within .row-mark,
.found-jobs > li:hover .row-mark, .found-jobs > li:focus-within .row-mark { opacity: 1; }
.row:hover .row-title, .row:focus-visible .row-title, .row:focus-within .row-title,
.found-jobs > li:hover .found-title, .found-jobs > li:focus-within .found-title { color: var(--ink-lit); }
@media (prefers-reduced-motion: no-preference) {
  .row-mark, .row-title, .found-title { transition: opacity .12s ease, color .12s ease; }
}
