/* ============================================================================
   cand-record.css — stylesheet for app/cand-record.jsx.

   Every class is prefixed `.e8-cand-rec-`. The pre-existing `.e8-cand-*`,
   `.e8-stagechip-*`, `.e8-needsyou-*`, `.e8-cv-toolbar` and `.e8-reviewbar*`
   rules stay in app/app.css; nothing was moved out of it in this pass.

   What IS here: the inline `style={{…}}` objects that came across with the
   markup. A new .jsx has an inline-style budget of 0
   (scripts/check-inline-style.mjs), so a moved inline style has to become a
   class. Each rule reproduces its inline declarations exactly, and this file is
   linked AFTER app.css so a single-class rule here wins the same way the inline
   style did.

   ONE INLINE STYLE DELIBERATELY STAYS INLINE, because the value is DATA: the
   swipe transform on `.e8-cand-rec-tabbody`, a measured offset that changes
   every frame of a drag.

   `grid-template-columns` on `.e8-cand-rec-expstats` USED to be the second, and
   is now `.is-3` / `.is-1` here. The old note called the inline form
   load-bearing because app.css:3543 targets `.e8-content [style*="repeat(3,
   1fr)"]` and forces two columns below 840px. That was true and it was the
   defect: three tenure tiles in two columns orphan the third and leave an empty
   165x64 cell at 390 and 355x64 at 834. Being reachable by a viewport `@media`
   from app.css is precisely what a block inside the container-queried record
   column must not be. The class form takes it out of that selector's reach —
   the selector matches an inline `style` ATTRIBUTE, and there no longer is one —
   and every other `repeat(3, 1fr)` grid in the app still collapses as before.

   R143 added the next-action card, the fact strip and the Experience / Skills /
   Messages bodies at the bottom of this file. `.e8-cand-rec-explist`,
   `-exprow` and `-expsub` went with that change: the flat role list they styled
   is now the `.e8-cand-rec-tl` timeline, and they had no other call site.

   R143 REVIEW 2 (this pass) — five measured repairs, all argued at their rules:
   the eyebrow's ink (AA in light mode), the next action's 12px label and its
   fourth line at wide widths, the fact strip's two facts that the open rail was
   already showing, the Files tab's two 24px controls, and the Experience tab's
   single 720px strip inside a 948px column. New classes: `.e8-cand-rec-expcols`
   / `-expmain` / `-expside`, and `.is-railsheet` / `.is-railopen` /
   `.is-railaway` on the strip.
   ============================================================================ */

/* was style={{ minWidth: 0 }} beside the swipe transform on the tab body */
.e8-cand-rec-tabbody { min-width: 0; }

/* expanded stage strip rows */
.e8-cand-rec-stagerow { min-width: 0; font-size: var(--ui-text-sm); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* was style={{ display: 'inline-flex' }} on a <Row>; see cand-rail.css for why order suffices */
.e8-cand-rec-inline { display: inline-flex; }

/* ICON RULES CARRY THE CLASS TWICE ON PURPOSE. `.elev8 .material-symbols-outlined`
   (product.css:267) is a (0,2,0) rule that sets EVERY product icon to
   `font-size: var(--ui-icon-md); color: var(--ui-text-secondary)`, and its own comment says
   it is written that way to beat `.elev8 span`. A plain `.e8-cand-…` class is (0,1,0) and
   loses to it no matter how late the file is linked - which is exactly what happened here on
   the first attempt: five icons silently went to 20px grey, and only the computed-style A/B
   caught it because the geometry knock-on was 2-4px. `.material-symbols-outlined.e8-cand-…`
   is (0,2,0), ties, and wins on order. It is also the shape app.css already uses
   (`.material-symbols-outlined.e8-recrow-ic`, `.material-symbols-outlined.e8-cmdk-keep`). */

/* Experience tab — CV toolbar */
/* `flex: none` is the fix for a measured 390 defect that predates this batch: inside
   `.e8-cv-toolbar` the icon shrank from 18px to a 6px sliver of a glyph, because a flex
   item defaults to shrinking and an icon has no intrinsic min-width to stop it. */
.material-symbols-outlined.e8-cand-rec-cvic { font-size: var(--ui-icon-sm); color: var(--ui-icon-quiet); flex: none; }
.e8-cand-rec-cvname { font-size: var(--ui-text-sm); color: var(--ui-text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Experience tab — tenure stats. The columns are on a CLASS now, not inline: see the note at
   the call site in cand-record.jsx for why moving them here is the fix and not the risk. */
.e8-cand-rec-expstats { display: grid; gap: 10px; margin: 16px 0 18px; }
.e8-cand-rec-expstats.is-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.e8-cand-rec-expstats.is-1 { grid-template-columns: minmax(0, 1fr); }
.e8-cand-rec-expstat { border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg); padding: 10px 14px; }

/* queue review bar — "3 of 24" */
.e8-cand-rec-qpos { font-size: var(--ui-text-xs); color: var(--ui-text-secondary); min-width: 48px; text-align: center; }

/* ============================================================================
   R143 — next-action card, fact strip, Experience / Skills / Messages bodies.

   WHY EVERY CONDITIONAL BELOW IS `@container` AND NONE IS `@media`. These blocks
   live inside `.e8-recordbody .e8-content`, which app.css:1415 declares
   `container-type: inline-size`. That box is the CONTENT COLUMN, and the rail
   squeezes it without touching the viewport: measured on this build, the column
   is 339px at a 390px viewport, 524px at 834px and 778px at 1280px — so a
   viewport query would fire at widths where the column is a completely different
   size, which is the bug CLAUDE.md says has shipped twice. The queries are
   UNNAMED on purpose: an unnamed query resolves to the NEAREST container
   ancestor, which is `.e8-content` itself. `@container e8rec` would measure
   `.e8-recordbody` — content PLUS rail — and reintroduce the error in a quieter
   form.

   Every conditional block sits AFTER the rule it overrides. A `@container` adds
   no specificity, so one written above its own base rule never applies at all.
   ============================================================================ */

/* ---- piece 3: the next-action card ---------------------------------------
   Replaces `.e8-needsyou` (still in app.css, still used by nothing on this
   screen). Two defects it exists to fix, both measured at 390: the title and
   the reason were `white-space: nowrap` + ellipsis, so both truncated mid-word
   and the reason — the part that says WHY this is urgent — was unreadable; and
   the action button was a 26px-tall inline control at the end of a flex row.
   Nothing here clamps or ellipsises: this card is the reason the page exists,
   so it is allowed the four lines it needs. */
.e8-cand-rec-na {
  border: 1px solid var(--ui-border-strong);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-surface);
  box-shadow: inset 3px 0 0 var(--ui-accent), var(--ui-shadow-1);
  padding: 9px 12px 10px 15px;
  margin: 0 0 12px;
}
.e8-cand-rec-na-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }
/* `.e8-cand-rec-na .e8-eyebrow { color: var(--ui-text-secondary) }` IS GONE, WITH ITS MARKUP.
   It was a local repair of a token-layer fault: `.e8-eyebrow` (app.css:3097) paints
   `--ui-text-tertiary` (`#9C9CA6`), measured 2.71:1 on this card's white surface at 11.5px
   against a 4.5:1 AA floor. The head now composes `.e8-sectionlabel`, which is
   `--ui-text-secondary` (`#6F6E77`, 5.03:1) by declaration - so the contrast is fixed by the
   class the record already uses for this job rather than by an override that made ONE
   `.e8-eyebrow` on the screen a different ink from the other three. See cand-record.jsx.
   THE UNDERLYING FAULT IS UNCHANGED AND IS NOT OURS: `--ui-text-tertiary` still fails on
   "STILL NEEDED" / "NEEDS RECONFIRMING" (cand-overview), on "AT A GLANCE" and every other
   `.e8-rrail-sec-title` (cand-rail), on every rail timestamp and on `.e8-rrail-tab`. The
   one-line fix for all of them is the token in product.css, which no candidate-record batch
   owns. Reported, not worked around - a second local override would have re-split the ink. */
/* ONE SMALL-PILL BOX FOR THE WHOLE RECORD: 11.5 / 600 / padding 1px 7px / radius-pill,
   which is what `.e8-rfr-pill`, `.e8-ovdis-count` (both app.css) and
   `.e8-cand-overview-actkind` already measure - 18.7px tall. This one was `0 7px` and
   measured 17.3px, so the urgency chip sat 1.4px shorter than every other pill on the
   screen, which reads as a baseline that will not settle rather than as a decision.
   `999px` -> `var(--ui-radius-pill)` throughout this file: the token IS 999px
   (product.css:148), so it was the same value under two spellings. */
.e8-cand-rec-na-urg {
  font-size: var(--ui-text-xs); font-weight: 600; line-height: 1.45;
  padding: 1px 7px; border-radius: var(--ui-radius-pill); white-space: nowrap;
  color: var(--ui-text-secondary); background: var(--ui-fill);
}
.e8-cand-rec-na-urg.is-danger { color: var(--ui-danger); background: var(--ui-danger-tint); }
.e8-cand-rec-na-urg.is-warning { color: var(--ui-warning); background: var(--ui-warning-tint); }
/* `.e8-cand-rec-na-src` — the "same items as Today" caption — was deleted with its markup.
   It named another screen instead of the candidate, and it was 11.5px tertiary ink at 2.72:1. */
.e8-cand-rec-na-item { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 11px; padding: 4px 0 6px; }
.e8-cand-rec-na-item + .e8-cand-rec-na-item { border-top: 1px solid var(--ui-border); }
/* (0,2,0) so it beats `.elev8 .material-symbols-outlined` (product.css:267), which
   sets font-size AND color on every icon and would otherwise win on specificity. */
.material-symbols-outlined.e8-cand-rec-na-ic {
  width: 30px; height: 30px; flex: none; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; font-size: var(--ui-icon-sm);
  color: var(--ui-accent);
  background: color-mix(in srgb, var(--ui-accent) 10%, var(--ui-surface));
}
/* basis 0, not auto. Under `flex-wrap: wrap` (below) a flex item wraps when its
   HYPOTHETICAL main size does not fit, and min-width:0 does not change that -
   with basis auto the body's max-content text width pushed it onto its own line
   and left the 30px icon sitting alone above the title at 390. */
.e8-cand-rec-na-body { flex: 1 1 0; min-width: 0; }
.e8-cand-rec-na-t {
  margin: 0; font-size: var(--ui-text-base); font-weight: 600; line-height: 1.35;
  color: var(--ui-text); text-wrap: pretty; overflow-wrap: break-word;
}
.e8-cand-rec-na-s {
  margin: 2px 0 0; font-size: var(--ui-text-sm); line-height: 1.4;
  color: var(--ui-text-secondary); max-width: 68ch; text-wrap: pretty; overflow-wrap: break-word;
}
/* THE ACTION TAKES ITS OWN LINE AT EVERY WIDTH, indented to the text column (the 30px icon
   plus the 11px flex gap). It used to be `flex: none` at the end of the item row, which put it
   at the card's far right edge: measured at 1440, the title started at x=262 and the button sat
   at x=952, a 690px separation inside an 820px card, so the action and the sentence that
   justifies it never appeared near each other. `flex: 1 0 100%` under the item's `flex-wrap`
   forces the line break; the row gap supplies the space above it. */
/* `1 1 100%`, NOT `1 0 100%`. A flex basis of 100% resolves against the line's available
   space and does NOT subtract the item's own margins, so `basis 100% + margin-left 41px`
   is 41px wider than the line - and `flex-shrink: 0` forbade taking it back. Measured at
   a 834 viewport on #/candidate/c-okafor: the row ran x 77->832 inside a card ending at
   804, and `.e8-content.e8-rbody-content` reported scrollWidth 832 against clientWidth
   824, i.e. an 8px horizontal scrollbar on the whole record, present on ALL FIVE TABS
   because the card sits above the tab strip. At 1440 the wider column padding happens to
   swallow the same 41px, which is why it read clean there - a near miss, not a pass.
   Shrink restored, the line break is unaffected: the wrap decision uses the hypothetical
   main size PLUS margins (755 + 41 > 755), so the action still takes its own line, and
   once alone on it, it shrinks to the 714px that actually fits. */
.e8-cand-rec-na-act { flex: 1 1 100%; min-width: 0; margin-left: 41px; }
/* 24px is 55% of the 44px target and reads as a toolbar control. 32px is the wide-column
   floor; the touch-shell block near the end of this file takes it to 44.
   THE LABEL IS 13.5px, NOT 12px. `e8-btn-sm` carries a hardcoded 12px, which is not on the type
   scale at all (11.5 / 12.5 / 13.5 / 15 / 18 / 24 / 28) — so the one control this whole card
   exists to deliver was set in a size the product does not define, inside a 44px box. Only the
   type moves: the geometry, the variant and the size prop are already right, and changing the
   size prop instead would repad the button and re-break the height.
   THREE CLASSES DEEP, for the same reason the icon rules in this file carry their class twice:
   `.elev8 .e8-btn-sm { font-size: 12px }` (components/ats-button/Button.jsx:24) is (0,2,0) AND
   it is injected into the head at runtime by ds-live.js, i.e. AFTER this linked stylesheet — so
   a (0,2,0) rule here ties and loses on order. Measured: the two-class version read back 12px
   from the live CSSOM. `.e8-cand-rec-na .e8-cand-rec-na-act .e8-btn` is (0,3,0) and wins
   outright. min-height stays on the shorter selector; it already beat `height: 24px` (0,1,0). */
.e8-cand-rec-na-act .e8-btn { min-height: 32px; }
.e8-cand-rec-na .e8-cand-rec-na-act .e8-btn { font-size: var(--ui-text-base); }
.e8-cand-rec-na-more {
  display: flex; align-items: center; gap: 6px; width: 100%; min-height: 34px;
  border: 0; border-top: 1px solid var(--ui-border); background: transparent;
  padding: 8px 0 2px; margin-top: 2px; cursor: pointer; font-family: inherit; text-align: left;
  font-size: var(--ui-text-sm); color: var(--ui-text-secondary);
}
.e8-cand-rec-na-more:hover { color: var(--ui-text); }
.e8-cand-rec-na-more .material-symbols-outlined { font-size: var(--ui-icon-sm); flex: none; }
.e8-cand-rec-na-more-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Narrow column: the action fills the row and becomes a 44px target. The indent that keeps it
   under the text at wide widths is dropped — 41px of a 339px column is a third of the button.
   The card also tightens: at 390 it measured 202px of a 659px scroll viewport (31%), and 529 of
   those 659px are spent before the tab body, so every row of padding here is paid for out of the
   only part of the screen that carries the candidate. What tightens is SPACE, not content — the
   reason line still wraps in full. Clamping it was considered and rejected: this card's whole
   defect history is text that was truncated mid-sentence, and 17px is not worth re-hiding the
   sentence that says why the task is urgent. Reported rather than done. */
@container (max-width: 460px) {
  .e8-cand-rec-na { padding: 7px 12px 9px 13px; }
  .e8-cand-rec-na-head { margin-bottom: 2px; }
  .e8-cand-rec-na-item { gap: 8px 11px; padding: 2px 0 4px; }
  .e8-cand-rec-na-act { margin-left: 0; }
  .e8-cand-rec-na-act .e8-btn { width: 100%; min-height: 44px; justify-content: center; }
}
/* WIDE COLUMN: THE ACTION RIDES THE REASON'S ROW instead of opening a fourth one. Measured at
   1440, the card was 154px tall and 32px of that plus its row gap — 44px, 29% of the card — was
   a line containing one 77px button, while 211px of the same line sat empty to the right of a
   reason that stopped at x=833. `flex: 0 0 auto` puts the action back on the item row and
   `align-self: flex-end` sits it on the BOTTOM of that row, level with the end of the reason
   rather than level with the title.
   That last part is the whole difference from the arrangement this replaced, and the earlier
   measurement against it stands: an action pinned top-right was 690px from the title with the
   sentence justifying it nowhere near either. Bottom-aligned, the action reads as the end of the
   sentence it belongs to. The threshold is the COLUMN, not the device: 834 gets this layout too
   (measured, the content column there is 834px because the rail is a sheet), and it composes with
   the touch-shell block below — 77x44 at x=714, a real touch target on its own row-end. Only 390
   (column 390) keeps the stacked full-width button, which is the right answer for a phone. */
@container (min-width: 620px) {
  .e8-cand-rec-na-act { flex: 0 0 auto; margin-left: 0; align-self: flex-end; }
}

/* ---- piece 4: the fact strip (NEW) ---------------------------------------
   THREE label/value pairs — rate, availability, work auth — in one row in a
   wide column, and one column, label-left / value-right, once it is a phone.
   Which three, and why not six, is argued at CandRecFactStrip in the .jsx.

   THE PAIR IS INLINE AT EVERY WIDTH NOW, not stacked-then-inline. Measured at
   1440, a stacked cell was 272px wide holding at most 81px of value ink and
   53px tall holding ~30px of type, so six facts needed two rows and 109px to
   say what fits in one row of ~35px. Ashby and Greenhouse run these at roughly
   28-32px (own knowledge, not measured here). The breakpoint that remains is
   the one that earns its keep: a phone column cannot hold three pairs abreast,
   so it gets three rows with the values flushed right to a common edge. */
.e8-cand-rec-facts {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px; margin: 0 0 14px; padding: 0;
  border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg);
  background: var(--ui-border); overflow: hidden;
}
.e8-cand-rec-fact {
  background: var(--ui-surface); padding: 7px 12px; min-width: 0;
  display: flex; align-items: baseline; gap: 8px;
}
/* --ui-text-secondary (#6F6E77), NOT --ui-text-tertiary (#9C9CA6). Tertiary measured 2.72:1
   on white at 11.5px against a 4.5:1 AA floor — every label in this strip failed, in the
   DEFAULT theme, on a brand-new surface. Dark mode measured clean. The token itself is the
   real fault and it lives in product.css:18; every 11.5px label in THIS file moved to
   secondary so the module is clean either way. */
.e8-cand-rec-fact-k { flex: none; font-size: var(--ui-text-xs); color: var(--ui-text-secondary); line-height: 1.4; }
.e8-cand-rec-fact-v {
  margin: 0; flex: 1 1 auto; min-width: 0;
  font-size: var(--ui-text-base); font-weight: 500; line-height: 1.4;
  color: var(--ui-text); overflow-wrap: break-word;
}
/* Weight, not colour, carries "we do not know this" — the tertiary tint that used to say it
   failed AA at 13.5px too (2.72:1 against a 4.5:1 floor). */
.e8-cand-rec-fact-v.is-unknown { font-weight: 400; color: var(--ui-text-secondary); }
/* ---- WHICH THREE FACTS DEPENDS ON WHETHER THE RAIL IS OPEN -----------------
   Measured at 1440: of the strip's three cells, TWO were being rendered a second time 300px to
   the right, in the rail's own "At a glance" — `Rate  $92/hr W2` and `Availability  Immediate`,
   verbatim, both visible in the same viewport. The band cost 49px (35px + margin) to deliver one
   fact the reader did not already have. §2.3 defines density as answered QUESTIONS per screen,
   and a question answered twice is one answer at twice the price.
   It cannot be fixed by deleting the strip, because the rail is only a rail on a desktop: at 390
   and 834 it is a dismissed bottom sheet, and then this strip is the ONLY place rate and
   availability appear at all. So the strip renders five facts and shows the three that are not
   already on screen, keyed on `.is-narrow` — the shell's own verdict about whether the rail is
   inline (record-shell.jsx), the same switch the touch-target block at the end of this file
   reads. Rail open: work auth, work model, last contact — none of which the open rail carries
   above its fold. Rail collapsed: rate, availability, work auth, which is what a recruiter needs
   in the first second on a phone. Three cells either way, so the grid never changes shape. */
.e8-recordbody:not(.is-narrow) .e8-cand-rec-fact.is-railsheet { display: none; }
.e8-recordbody.is-narrow .e8-cand-rec-fact.is-railopen { display: none; }
/* The rail has two panes and only Details carries At a glance. With it on Activity — where the
   /activity deep link and every activity toast put it — nothing is repeating rate and
   availability, so the strip takes them back. `is-railaway` is set by the screen from the same
   `railTab` state that drives the pane, so the two cannot disagree. Six classes deep to beat the
   four-class rule above; still three cells, so the grid does not change shape. */
.e8-recordbody:not(.is-narrow) .e8-cand-rec-facts.is-railaway .e8-cand-rec-fact.is-railsheet { display: flex; }
.e8-recordbody:not(.is-narrow) .e8-cand-rec-facts.is-railaway .e8-cand-rec-fact.is-railopen { display: none; }
@container (max-width: 460px) {
  .e8-cand-rec-facts { grid-template-columns: minmax(0, 1fr); }
  .e8-cand-rec-fact { gap: 12px; }
  .e8-cand-rec-fact-k { width: 88px; }
  .e8-cand-rec-fact-v { text-align: right; }
}

/* ---- piece 11: the Experience role timeline ------------------------------- */
.e8-cand-rec-exp { max-width: 720px; }

/* CV toolbar. `.e8-cv-toolbar` is SHARED (app.css:1682) and is deliberately not touched on its
   own here — a bare override would restyle it on every record type that composes it. The
   anchor class does the reaching. Measured at 390: all three controls held one row and the
   filename got 76px of a 255px string, so 70% of "Okafor_Daniel_CV.pdf · updated 2…" was
   hidden — the one string that says WHICH CV this is. */
.e8-cv-toolbar.e8-cand-rec-cvbar { flex-wrap: wrap; }
@container (max-width: 560px) {
  .e8-cv-toolbar.e8-cand-rec-cvbar .e8-cand-rec-cvfile { width: 100%; }
  .e8-cv-toolbar.e8-cand-rec-cvbar .e8-cand-rec-cvacts { width: 100%; flex-wrap: wrap; }
}

/* Tenure stats at a narrow column: three tiles abreast leave ~85px per number and a two-column
   fallback orphans the third. A label/value row list says the same three things in ~95px
   instead of 138, with nothing left over. */
@container (max-width: 460px) {
  .e8-cand-rec-expstats {
    gap: 0; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg);
  }
  .e8-cand-rec-expstats.is-3, .e8-cand-rec-expstats.is-1 { grid-template-columns: minmax(0, 1fr); }
  .e8-cand-rec-expstat {
    border: 0; border-radius: 0; padding: 7px 12px;
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  }
  .e8-cand-rec-expstat + .e8-cand-rec-expstat { border-top: 1px solid var(--ui-border); }
  /* `mt={2}` on the value renders as --e8-ui-mt; in a baseline row it just nudges the number
     off the label's baseline. */
  .e8-cand-rec-expstat > .has-mt { margin-top: 0; }
}
.e8-cand-rec-expnote {
  margin: -6px 0 16px; font-size: var(--ui-text-sm); line-height: 1.45;
  color: var(--ui-warning); max-width: 66ch;
}
.material-symbols-outlined.e8-cand-rec-expnote-ic {
  font-size: var(--ui-icon-xs); color: var(--ui-warning); vertical-align: -3px; margin-right: 4px;
}
.e8-cand-rec-tl { list-style: none; margin: 0; padding: 0; }
.e8-cand-rec-tlrow {
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 14px; padding: 0 0 18px 22px;
}
.e8-cand-rec-tlrow::before {
  content: ''; position: absolute; left: 4px; top: 14px; bottom: 0; width: 1px; background: var(--ui-border);
}
.e8-cand-rec-tldot {
  position: absolute; left: 0; top: 5px; width: 9px; height: 9px; border-radius: 50%;
  background: var(--ui-surface); box-shadow: 0 0 0 1.5px var(--ui-border-strong);
}
.e8-cand-rec-tlrow.is-current .e8-cand-rec-tldot { background: var(--ui-accent); box-shadow: 0 0 0 1.5px var(--ui-accent); }
.e8-cand-rec-tlmain { min-width: 0; }
.e8-cand-rec-tlrole { margin: 0; font-size: var(--ui-text-base); font-weight: 600; line-height: 1.35; color: var(--ui-text); }
.e8-cand-rec-tlco { margin: 1px 0 0; font-size: var(--ui-text-base); color: var(--ui-text-secondary); line-height: 1.35; }
.e8-cand-rec-tlsub {
  margin: 5px 0 0; font-size: var(--ui-text-sm); line-height: 1.5;
  color: var(--ui-text-secondary); max-width: 62ch; text-wrap: pretty;
}
.e8-cand-rec-tlmeta { margin: 0; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; text-align: right; }
.e8-cand-rec-tlspan { font-size: var(--ui-text-sm); color: var(--ui-text-secondary); white-space: nowrap; }
.e8-cand-rec-tldur {
  font-size: var(--ui-text-xs); font-weight: 600; color: var(--ui-text-secondary);
  background: var(--ui-fill); border-radius: var(--ui-radius-pill); padding: 1px 7px; white-space: nowrap;
}
/* A gap is a real finding, so it gets its own row and a dashed connector rather
   than being left for the reader to subtract two years in their head. */
.e8-cand-rec-tlgap {
  position: relative; padding: 0 0 18px 22px;
  font-size: var(--ui-text-sm); line-height: 1.45; color: var(--ui-warning);
}
.e8-cand-rec-tlgap::before {
  content: ''; position: absolute; left: 4px; top: 0; bottom: 0; width: 1px;
  background-image: linear-gradient(var(--ui-warning-br) 55%, transparent 0);
  background-size: 1px 7px; background-repeat: repeat-y;
}
.material-symbols-outlined.e8-cand-rec-tlgapic {
  font-size: var(--ui-icon-xs); color: var(--ui-warning); vertical-align: -3px; margin-right: 2px;
}
.e8-cand-rec-tl > li:last-child { padding-bottom: 0; }
.e8-cand-rec-tl > li:last-child::before { display: none; }
/* Narrow column: dates lead the row instead of competing with the role for it. */
@container (max-width: 460px) {
  .e8-cand-rec-tlrow { grid-template-columns: minmax(0, 1fr); }
  .e8-cand-rec-tlmeta { order: -1; flex-direction: row; align-items: baseline; justify-content: flex-start; gap: 8px; margin-bottom: 2px; text-align: left; }
}

/* ---- Experience: two columns once there is room for two ---------------------
   Measured at 1440: the tab rendered 720x408 at x=224 with the rail's left edge at 1140, so an
   eight-year career and its three tenure numbers ran down one strip and left 196px of window
   doing nothing. Widening the strip is NOT the fix — the role descriptions are capped at 62ch
   (514px measured) on purpose, so a wider single column would have pushed the dates further from
   the roles across a growing hole.
   So the block splits: the timeline keeps a text-measure column, and the tenure stats plus the
   résumé-vs-profile conflict note — which are a SUMMARY of the timeline, not steps in it — move
   into a 264px reference column beside it. That is the reading order the layout already implied
   and the stack could not express. Below the threshold `.e8-cand-rec-expcols` is a plain flex
   column and the DOM order (summary first, then timeline) is exactly what shipped before.
   900px is the CONTENT COLUMN, not the viewport: 948px at a 1440 viewport, 788px at 1280 — so
   1280 keeps the single column, where 1fr + 264 would have left the timeline 372px and started
   wrapping the roles. */
.e8-cand-rec-expcols { display: flex; flex-direction: column; min-width: 0; }
.e8-cand-rec-expmain, .e8-cand-rec-expside { min-width: 0; }
@container (min-width: 900px) {
  .e8-cand-rec-exp { max-width: none; }
  .e8-cand-rec-expcols {
    display: grid; grid-template-columns: minmax(0, 1fr) 264px;
    column-gap: 28px; align-items: start;
  }
  /* Placed explicitly, both in row 1: auto-placement would follow DOM order and put the summary
     in column 1. Order is a narrow-column concern; at this width the two are side by side. */
  .e8-cand-rec-expmain { grid-column: 1; grid-row: 1; }
  .e8-cand-rec-expside { grid-column: 2; grid-row: 1; }
  .e8-cand-rec-expside .e8-cand-rec-expstats.is-3,
  .e8-cand-rec-expside .e8-cand-rec-expstats.is-1 { grid-template-columns: minmax(0, 1fr); margin: 0; }
  .e8-cand-rec-expside .e8-cand-rec-expnote { margin: 12px 0 0; max-width: none; }
}

/* ---- piece 12: Skills, grouped and evidence-backed ------------------------ */
/* 18px -> 20px: the record's one block rhythm. See the note on `.e8-cand-overview`'s row-gap
   in cand-overview.css - three containers were stacking peer blocks at 24 / 20 / 18. */
.e8-cand-rec-skills { display: grid; gap: 20px; max-width: 720px; }
.e8-cand-rec-skhead { display: flex; align-items: baseline; gap: 7px; margin-bottom: 8px; }
/* `.e8-cand-rec-skhead-t` and `.e8-cand-rec-msghead-t` ARE GONE. Both were 12.5/600
   primary - a third section-label look beside `.e8-sectionlabel` (11.5/500 secondary)
   and the prescreen card's 15/600, and the Skills tab ran BOTH of them: its first two
   group headings shouted at 12.5/600 while "On the résumé, not on the profile" and
   "Add a skill", three inches below, whispered at 11.5/500. The markup composes
   `.e8-sectionlabel` now - see the note at h3.e8-cand-overview-ps-title for why that
   one wins. Deleting beats keeping a third variant.
   The count keeps its own class, because a count chip is not a label - but it moves
   onto the record's small-pill box (1px 7px / 600), which is what the tab strip's own
   count badge and `.e8-ovdis-count` beside it already use. It was 0 6px at weight 400,
   i.e. flatter and lighter than the identical idea two elements away. */
.e8-cand-rec-skhead-n {
  font-size: var(--ui-text-xs); font-weight: 600; color: var(--ui-text-secondary);
  background: var(--ui-fill); border-radius: var(--ui-radius-pill); padding: 1px 7px;
}
.e8-cand-rec-sklist { list-style: none; margin: 0; padding: 0; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg); }
.e8-cand-rec-skrow { display: grid; grid-template-columns: 160px minmax(0, 1fr); gap: 12px; padding: 9px 12px; }
.e8-cand-rec-skrow + .e8-cand-rec-skrow { border-top: 1px solid var(--ui-border); }
/* One row can now name several skills — the ones a single quote genuinely backs. They stack so
   the evidence beside them reads as one statement about all of them rather than a repeat. */
.e8-cand-rec-sknames { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.e8-cand-rec-skname { font-size: var(--ui-text-base); font-weight: 500; color: var(--ui-text); overflow-wrap: break-word; }
.e8-cand-rec-skev { min-width: 0; }
.e8-cand-rec-skwhere {
  display: block; font-size: var(--ui-text-xs); color: var(--ui-text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.e8-cand-rec-sksnip { display: block; margin-top: 2px; font-size: var(--ui-text-sm); line-height: 1.45; color: var(--ui-text-secondary); text-wrap: pretty; }
.e8-cand-rec-skempty { margin: 8px 0 0; font-size: var(--ui-text-sm); line-height: 1.45; color: var(--ui-text-secondary); max-width: 62ch; }
@container (max-width: 460px) {
  .e8-cand-rec-skrow { grid-template-columns: minmax(0, 1fr); gap: 3px; }
}

/* ---- piece 13: Messages -------------------------------------------------- */
.e8-cand-rec-msgs { max-width: 720px; }
.e8-cand-rec-msghead { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
/* `--ui-daybreak-text`, not `--ui-accent`: it IS `--ui-accent` in light and a lightened accent
   in dark (app.css:4782), which is the difference between 4.27:1 and AA at 11.5px on the 10%
   accent tint. Measured in dark with an alpha-compositing probe — the raw-rgb version of that
   probe read the tint as opaque and got the answer wrong in both directions. */
.e8-cand-rec-msgunread {
  font-size: var(--ui-text-xs); font-weight: 600; white-space: nowrap;
  color: var(--ui-daybreak-text); background: color-mix(in srgb, var(--ui-accent) 10%, var(--ui-surface));
  border-radius: var(--ui-radius-pill); padding: 1px 7px;
}
.e8-cand-rec-msgchans { min-width: 0; }
.e8-cand-rec-msghead-act { margin-left: auto; flex: none; }
.e8-cand-rec-msgearlier {
  display: flex; align-items: center; gap: 7px; width: 100%; min-height: 38px;
  border: 1px dashed var(--ui-border-strong); border-radius: var(--ui-radius); background: transparent;
  padding: 8px 12px; margin-bottom: 10px; cursor: pointer; font-family: inherit; text-align: left;
  font-size: var(--ui-text-sm); color: var(--ui-text-secondary);
}
.e8-cand-rec-msgearlier:hover { border-color: var(--ui-accent); color: var(--ui-text); }
.e8-cand-rec-msgearlier .material-symbols-outlined { font-size: var(--ui-icon-sm); flex: none; }
.e8-cand-rec-msglist { list-style: none; margin: 0; padding: 0; }
.e8-cand-rec-msgday {
  display: flex; align-items: center; gap: 10px; margin: 14px 0 10px;
  font-size: var(--ui-text-xs); color: var(--ui-text-secondary);
}
.e8-cand-rec-msgday::after { content: ''; flex: 1 1 auto; height: 1px; background: var(--ui-border); }
.e8-cand-rec-msglist > .e8-cand-rec-msgday:first-child { margin-top: 0; }
.e8-cand-rec-msgnew {
  display: flex; align-items: center; gap: 10px; margin: 12px 0 8px;
  font-size: var(--ui-text-xs); font-weight: 600; color: var(--ui-accent);
}
.e8-cand-rec-msgnew::after { content: ''; flex: 1 1 auto; height: 1px; background: color-mix(in srgb, var(--ui-accent) 40%, transparent); }
.e8-cand-rec-msg {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 12px; border-radius: var(--ui-radius-lg); border: 1px solid var(--ui-border);
}
.e8-cand-rec-msg + .e8-cand-rec-msg { margin-top: 6px; }
/* Direction is carried by the fill, not by alignment: a right-aligned bubble
   inside a 339px column wraps to a ragged left edge and reads worse than a tint. */
.e8-cand-rec-msg.is-mine { background: var(--ui-fill); border-color: transparent; }
.e8-cand-rec-msg.is-theirs { background: var(--ui-surface); }
.e8-cand-rec-msg.is-unread { border-color: color-mix(in srgb, var(--ui-accent) 45%, var(--ui-border)); }
.e8-cand-rec-msgav { position: relative; flex: none; display: inline-flex; }
.e8-cand-rec-msgbody { flex: 1 1 auto; min-width: 0; }
.e8-cand-rec-msgmeta { margin: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 7px; }
.e8-cand-rec-msgwho { font-size: var(--ui-text-sm); font-weight: 600; color: var(--ui-text); }
/* "AI-drafted" is the same statement `.e8-cand-overview-actkind` makes with "AGENT" one
   tab away: a machine produced this. There it is a tinted 11.5/600 pill; here it was a
   hairline-bordered 11.5/400 one - the only outlined pill in the module, and the quietest
   ink on a fact that ought to be the loudest thing in a message's meta line. Same box as
   its siblings now; the tint carries the meaning, as it does in the activity feed. */
.e8-cand-rec-msgai {
  font-size: var(--ui-text-xs); font-weight: 600; white-space: nowrap;
  color: var(--ui-daybreak-text); background: var(--ui-daybreak-wash);
  border: 0; border-radius: var(--ui-radius-pill); padding: 1px 7px;
}
.e8-cand-rec-msgwhen { margin-left: auto; font-size: var(--ui-text-xs); color: var(--ui-text-secondary); white-space: nowrap; }
.e8-cand-rec-msgtext {
  margin: 4px 0 0; font-size: var(--ui-text-base); line-height: 1.5;
  color: var(--ui-text); max-width: 66ch; text-wrap: pretty; overflow-wrap: break-word;
}
.e8-cand-rec-msgdraft {
  display: flex; align-items: flex-start; gap: 10px; margin-top: 12px;
  border: 1px dashed var(--ui-border-strong); border-radius: var(--ui-radius-lg); padding: 10px 12px;
}
.material-symbols-outlined.e8-cand-rec-msgdraft-ic { font-size: var(--ui-icon-sm); color: var(--ui-icon-quiet); flex: none; }
.e8-cand-rec-msgdraft-body { flex: 1 1 auto; min-width: 0; }
.e8-cand-rec-msgdraft-k { margin: 0; font-size: var(--ui-text-sm); font-weight: 600; color: var(--ui-text); }
.e8-cand-rec-msgdraft-t {
  margin: 2px 0 0; font-size: var(--ui-text-sm); line-height: 1.45; color: var(--ui-text-secondary);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.e8-cand-rec-msgdraft-act { flex: none; }
@container (max-width: 460px) {
  .e8-cand-rec-msghead-act { margin-left: 0; width: 100%; }
  .e8-cand-rec-msghead-act .e8-btn { width: 100%; min-height: 44px; justify-content: center; }
  .e8-cand-rec-msgdraft { flex-wrap: wrap; }
  .e8-cand-rec-msgdraft-act { width: 100%; }
  .e8-cand-rec-msgdraft-act .e8-btn { width: 100%; min-height: 44px; justify-content: center; }
}

/* ============================================================================
   TOUCH TARGETS — keyed on the SHELL, not on the content column.

   At an 834px viewport the app serves its touch shell: a 58px `.e8-tabbar`, the FAB, no
   desktop sidebar, and `.e8-recordbody.is-narrow` with the rail demoted to a bottom sheet. The
   record inside it was still sized for a mouse — 12 controls under 44px, including the single
   CTA the next-action card exists to deliver, measured at 77x24. §2.8 asks for 44.

   WHY THIS BLOCK IS SPECIFICITY AND NOT A QUERY. The `@container` blocks above measure the
   CONTENT COLUMN, and at 834 that column is 524px — comfortably past every breakpoint in this
   file, so none of them fires, and none of them should: 524px is a wide column and the layout
   is right. What is wrong at 834 is not the column width, it is the INPUT DEVICE, and the app
   already decides that one place: `RecordBody` measures its own row and adds `is-narrow` at
   <= 840px (record-shell.jsx:40-68), which is the same switch that produces the tab bar and
   the sheet. Reading that class is reading the shell's own verdict. A `@media (max-width: …)`
   here would be the viewport bug CLAUDE.md names; `@media (pointer: coarse)` would be honest
   about intent but never fires in a resized desktop browser, which is where every measurement
   on this batch was taken — it would have been a rule that passes review and does nothing.

   The narrow-column `@container` rules above still cover 390 (column 349px), where they also
   stretch the buttons full width. This block only raises heights, so the two compose.
   ============================================================================ */
/* `.e8-cand-rec-files .e8-btn` is the Files tab's own two controls — `CV tools` 87x24 and
   `Add file` 82x24, measured at 390 inside a panel whose file rows are 86-102px tall. They are
   the shared CandidateFilesSection's buttons, so they are reached through this batch's anchor
   class (added around the tab body only) and not by touching that component: the same component
   renders in the files overlay, which is not a record body and is not affected. */
.e8-recordbody.is-narrow .e8-cand-rec-na-act .e8-btn,
.e8-recordbody.is-narrow .e8-cand-rec-cvacts .e8-btn,
.e8-recordbody.is-narrow .e8-cand-rec-skills .e8-btn,
.e8-recordbody.is-narrow .e8-cand-rec-files .e8-btn,
.e8-recordbody.is-narrow .e8-cand-rec-msghead-act .e8-btn,
.e8-recordbody.is-narrow .e8-cand-rec-msgdraft-act .e8-btn { min-height: 44px; }
.e8-recordbody.is-narrow .e8-cand-rec-na-more,
.e8-recordbody.is-narrow .e8-cand-rec-msgearlier { min-height: 44px; }

/* ============================================================================
   FILES TAB — two scoped repairs on the SHARED CandidateFilesSection
   (screens-core.jsx). Both are anchored on `.e8-cand-rec-files`, a class this file's markup
   adds around the tab body only: the same component also renders inside the files overlay and
   on nothing else, and neither is touched here.

   WHAT THIS FILE DEPENDS ON, IN SOMEONE ELSE'S MARKUP. Both repairs reach through
   CandidateFilesSection's own structure, so they are only as stable as it is. The classes and
   shapes they need, all owned by screens-core.jsx:
     `.e8-filerow`                     the row the name and the type chip share
     `.e8-ui-shrink`                   the row's shrinkable name group — given `flex-wrap: wrap`
     its FIRST CHILD `<span>`          the filename, whose white-space / overflow /
                                       text-overflow are written INLINE there (hence the
                                       `!important`s below)
     `.e8-cfl-bar`, `.e8-cfl-types`    the search field and the type chips, hidden by `.is-few`
   Renaming any of them, reordering the name group so the filename is no longer the first child,
   or dropping the inline text styles turns these rules into silent no-ops — the failure is a
   re-ellipsised filename or filter chrome reappearing above four files, neither of which errors
   or fails a test. A markup change there must keep filename wrapping and `.is-few` filter
   hiding working, or update these rules in the same pass.
   ============================================================================ */
/* Measured at 390: 4 of 4 names ellipsised, the type chip taking 98-121px of a 204px parent —
   so the label describing the file outranked the string identifying it. `RTR_JO-10864_signed.pdf`
   showed 49% and lost its JO number. Letting the name wrap gives the whole string back.
   THE `!important` IS NOT DECORATION: screens-core.jsx writes white-space / overflow /
   text-overflow as an INLINE style on that span, and nothing but `!important` reaches an inline
   declaration from a stylesheet. Middle-truncation ("Okafor_Daniel_St…CV.docx", so the extension
   survives) and moving the chip down to the metadata line are markup changes and belong in that
   file — reported, not forked. */
.e8-cand-rec-files .e8-filerow .e8-ui-shrink { flex-wrap: wrap; }
.e8-cand-rec-files .e8-filerow .e8-ui-shrink > span:first-child {
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
  min-width: 0;
  overflow-wrap: anywhere;
}
/* Filter chrome sized for a large library, sitting above four files: search + 5 type chips +
   a date select measured 115px against 239px of content at 1440, a 0.48 chrome-to-content
   ratio. `is-few` is set by the tab when the record holds fewer than 10 files. `Add file`,
   `CV tools` and the row list are never hidden — only the tools for finding a needle. */
.e8-cand-rec-files.is-few .e8-cfl-bar,
.e8-cand-rec-files.is-few .e8-cfl-types { display: none; }
