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

   TWO PREFIXES LIVE HERE, ON PURPOSE.
   `.e8-cand-ov-*` is the module's historical namespace and still owns the rules
   that were literally moved out of the JSX as inline styles (the "Also in play"
   list, the activity link). Everything AUTHORED in this pass — About, the
   prescreen strip, the activity feed — is `.e8-cand-overview-*`, which is the
   namespace this batch was told to write under. Neither collides with the other,
   nor with `.e8-cand-overview` / `.e8-cand-ov-main` / `.e8-cand-ov-why` in
   app.css (a class selector matches a whole token, so `.e8-cand-overview` and
   `.e8-cand-overview-ps` are unrelated). Grep the prefix before adding a name.

   THREE RULES THIS FILE IS BOUND BY, each of which has shipped as a bug here:
   1. `@container e8rec`, never `@media`. `.e8-recordbody` sets
      `container-type: inline-size; container-name: e8rec`, and the resizable rail
      squeezes the content column WITHOUT changing the viewport — so a viewport
      query in a record measures the wrong box.
   2. Every conditional at-rule sits AFTER the unconditional rule it overrides.
      `@container` adds no specificity; written above, it is dead code that never
      applies in any state.
   3. Icon rules carry the class TWICE. `.elev8 .material-symbols-outlined`
      (product.css:267) is (0,2,0) and sets font-size AND color on every product
      icon. A plain `.e8-cand-…` class is (0,1,0) and loses no matter how late
      this file is linked. `.material-symbols-outlined.e8-cand-…` ties at (0,2,0)
      and wins on order.

   Colour is tokens or color-mix() on tokens — no hex — so dark mode inverts for
   free. Type comes only from the --ui-text-* scale (11.5 / 12.5 / 13.5 / 15 /
   18 / 24 / 28); there is no 14px.
   ============================================================================ */

/* ─────────────────────────── moved inline styles ─────────────────────────── */

/* was style={{ fontSize: 'var(--ui-text-base)' }} on the "View full activity" link */
.e8-cand-ov-actlink { font-size: var(--ui-text-base); }

/* "Also in play" — the candidate's other ranked jobs */
.e8-cand-ov-alsolist { display: grid; gap: 8px; }
.e8-cand-ov-jmmain { min-width: 0; flex: 1; text-align: left; }
/* `var(--ui-radius)` IS 6px and `4px` was a raw literal - the only hand-written radius in
   the five candidate stylesheets. Same idea, one spelling. */
.e8-cand-ov-simchip { font-size: var(--ui-text-xs); color: var(--ui-text-tertiary); border: 1px solid var(--ui-border); border-radius: var(--ui-radius); padding: 0 4px; }
.e8-cand-ov-jmwhys { display: flex; flex-wrap: wrap; gap: 2px 12px; margin-top: 5px; }
.material-symbols-outlined.e8-cand-ov-whyic { font-size: var(--ui-icon-xs); color: var(--ui-success-text); }
.material-symbols-outlined.e8-cand-ov-jmchev { font-size: var(--ui-icon-md); color: var(--ui-icon-quiet); align-self: center; }


/* THE STACKED COLUMN FILLS THE ROW IT IS ALONE IN.
   `.e8-cand-overview` (app.css:1408) is `display:flex; align-items:flex-start`, and
   at ≤1080 app.css:1422 flips it to `flex-direction: column`. In column direction
   `align-items: flex-start` is a CROSS-axis rule, so the left column stops being
   full-width and shrinks to fit its content: measured 644px inside a 784px row at
   834, with `.e8-cand-ov-why` sitting at the full 784 directly beneath it — 140px
   of ragged dead band down the right of About, prescreen and activity.
   `align-self: stretch` fixes the width there and is a no-op at desktop, where the
   cross axis is height and this column is already the taller of the two.
   `.e8-cand-ov-main` is declared in app.css but RENDERED ONLY BY THIS FILE
   (`grep -rn e8-cand-ov-main app/*.jsx` → cand-overview.jsx only), and the selector
   is anchored on this module's own root, so its reach is exactly this block. */
.e8-cand-overview > .e8-cand-ov-main { align-self: stretch; }

/* WAVE-3 SEAM FIX — ONE VERTICAL RHYTHM FOR THE RECORD'S BLOCK STACKS.
   Measured at 1440 on #/candidate/c-okafor, the gap between two peer blocks depended on which
   module had drawn the container:
     About -> Prescreen                24px   (`.e8-cand-overview` gap, app.css:1408)
     Prescreen -> Latest activity      20px   (`.e8-cand-ov-main` gap, app.css)
     the four sections of the Skills tab 18px (`.e8-cand-rec-skills`, cand-record.css)
   Three numbers for the same relationship, two of them inside ONE scroll of one tab - the
   reader gets a rhythm that resets under About and again at the tab switch. 20px wins because
   it is the gap that governs the most block boundaries on the record (every block inside
   `.e8-cand-ov-main`, which is where most of the Overview lives) and it needs no new value.
   ROW-GAP ONLY. `.e8-cand-overview` is a wrapping flex row, and its 24px is ALSO the gutter
   between the "who they are" and "why we matched" columns at desktop, where 24 is right -
   that is a different relationship from two stacked blocks and it keeps its own number.
   Below 1080 app.css:1422 flips this to `flex-direction: column`, at which point the 24px
   column gutter is a block gap too, and row-gap is the axis that carries it: the fix reaches
   exactly the boundaries it is about at every width.
   Reach: `.e8-cand-overview` has one call site in the whole app (cand-overview.jsx:497). */
.e8-cand-overview { row-gap: 20px; }


/* ════════════════════════════ 6. ABOUT ════════════════════════════ */

/* ABOUT SPANS THE ROW. It is a direct child of `.e8-cand-overview` (flex, wrap),
   so `width: 100%` with `flex: none` gives it a line of its own and pushes the two
   columns below it — without `flex-basis: 100%`, which app.css turns into a HEIGHT
   the moment `.e8-cand-overview` flips to `flex-direction: column` at ≤1080.
   Measured at 1440: the left column is 403px, which ran the paragraph at 45ch. */
.e8-cand-overview-ab { display: grid; gap: 8px; justify-items: start; flex: none; width: 100%; }
.e8-cand-overview-abhead { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.e8-cand-overview-absrc { min-width: 0; }

/* THE MEASURE. Capped in `ch`, not px: the column this sits in is resized by the
   rail, so a px cap is a cap at one rail width only. 66ch holds the line length in
   the middle of the 55–75 character band at every column width and every text
   size. Measured before: 79ch at 1280 (714px of running text) when this block ran
   the full page width, then 45ch once it was inside the left column. */
.e8-cand-overview-abtext {
  margin: 0;
  max-width: 66ch;
  font-size: var(--ui-text-base);
  line-height: 1.55;
  color: var(--ui-text-secondary);
  text-wrap: pretty;
}
/* Collapsed state. The disclosure only renders when this actually clips (the JSX
   measures scrollHeight against clientHeight), so the control never lies. */
.e8-cand-overview-abtext.is-clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}
.e8-cand-overview-abmore {
  display: inline-flex; align-items: center; gap: 2px;
  border: 0; background: transparent; padding: 2px 0;
  font-family: inherit; font-size: var(--ui-text-sm); font-weight: 500;
  color: var(--ui-accent); cursor: pointer; border-radius: var(--ui-radius);
}
.e8-cand-overview-abmore:hover { text-decoration: underline; }
/* WAVE-3 SEAM FIX. This chevron used to turn over on expand while every other disclosure on
   the record swapped its ligature - including `.e8-ovdis-car`, which is co-visible with this
   one on the Overview tab. The transform, its transition and the reduced-motion guard that
   existed only for the two of them are all deleted; the JSX renders the right glyph. */
.material-symbols-outlined.e8-cand-overview-abchev {
  font-size: var(--ui-icon-xs); color: var(--ui-accent);
}


/* ═════════════════════ 7. PRESCREEN COMPLETENESS ═════════════════════ */

.e8-cand-overview-ps {
  border: 1px solid var(--ui-border);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-surface);
  padding: 12px 14px;
  display: grid;
  gap: 8px;
}
.e8-cand-overview-pshead { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; }
/* ONE SECTION-LABEL GRAMMAR ACROSS THE FIVE TAB BODIES (wave-2 seam fix).
   Measured at 1440 on #/candidate/c-okafor, in DOM order down the Overview column:
     About            .e8-sectionlabel            11.5 / 500 / secondary
     Prescreen        h3.e8-cand-overview-ps-title 15   / 600 / primary
     Latest activity  .e8-sectionlabel            11.5 / 500 / secondary
     Why we matched   .e8-sectionlabel            11.5 / 500 / secondary
   - and in the sibling tabs, Skills and Messages ran a THIRD look at 12.5/600.
   Four peer blocks, three treatments, so the type ramp said "Prescreen is the most
   important thing on this record" when nothing had decided that. `.e8-sectionlabel`
   wins because it is already 3 of the 4 labels in this very column (and 149 call
   sites app-wide); it is the house sentence-case section label. The card keeps its
   emphasis from its border, its progress bar and its count - not from 3.5px and 100
   weight of type.
   `h3.` and not `.` alone: this stays an <h3> (its id is the section's
   aria-labelledby), and `.elev8 h3` (product.css:249) is (0,1,1) - it sets
   font-size, letter-spacing AND, via product.css:234, font-weight and colour. A bare
   class at (0,1,0) loses all four. `letter-spacing: inherit` reproduces the value the
   `.e8-sectionlabel` spans beside it compute (-0.0675px at 11.5px, i.e. the body's). */
h3.e8-cand-overview-ps-title {
  margin: 0;
  font-size: var(--ui-text-xs);
  font-weight: 500;
  letter-spacing: inherit;
  color: var(--ui-text-secondary);
}
/* One notation for one fact: the "70%" that used to sit at the end of this line
   said exactly what "7 of 10 answers captured" and the bar below it already say.
   The rule for it is gone with the element rather than left behind as dead CSS. */
.e8-cand-overview-ps-count { margin-right: auto; font-size: var(--ui-text-sm); color: var(--ui-text-secondary); }
.e8-cand-overview-ps-count b { font-weight: 650; color: var(--ui-text); }

/* The bar reads as progress toward a finish line, so the FILL is the app accent,
   not a warning colour — the shortfall is what warns, in the chips below. The
   fraction counts FRESH answers (total − missing − stale): the strip it replaces
   used done/total, which reaches 100% while volatile answers have expired. */
.e8-cand-overview-ps-track {
  height: 6px; border-radius: 3px; background: var(--ui-fill); overflow: hidden;
}
.e8-cand-overview-ps-track > i {
  display: block; height: 100%; border-radius: 3px;
  width: var(--e8-cov-pct, 0%);
  background: var(--ui-accent);
  transition: width .3s ease;
}
.e8-cand-overview-ps-why { margin: 0; font-size: var(--ui-text-sm); color: var(--ui-text-secondary); }

/* WHAT IS MISSING, AS CHIPS THAT WRAP. The rule this replaces was
   `white-space: nowrap; overflow: hidden; text-overflow: ellipsis` on one running
   line, which at 390 cut "Other opportunities / offers" to "…offer…" — 326px of
   text in a 273px box. A chip can be long. It can never be cut in half. */
.e8-cand-overview-psneed { display: grid; gap: 5px; }
/* `.e8-cand-overview-psneed-k` IS GONE, and the markup composes `.e8-eyebrow` instead.
   It was a fourth copy of the uppercase label - 11.5 / 650 / .05em / tertiary - beside
   `.e8-eyebrow` (600), `.e8-rrail-sec-title` (600) and `.e8-cand-overview-actkind`
   (.04em). Everything it declared, `.e8-eyebrow` already declares; the only difference
   was a 650 nobody chose. Deleting the rule is how the set stops growing. */
/* `align-items: flex-start`, because a flex row STRETCHES by default and one member of this
   row is a 44px touch target. MEASURED at 834 on #/candidate/c-vasquez (seven missing answers,
   so the `+4 more` button is present): every "Still needed" chip reported height 44 with
   `min-height: auto` and `padding: 1px 7px` - they were not 44px tall, they were being stretched
   to the button beside them, while the `DSc.ConfidenceChip`s 40px below stayed at 21. So the two
   chips agreed at 1440 and disagreed by 23px at exactly the widths where the touch rule fires.
   Pre-existing (the same stretch made them 44 when they were 24), and it is what would have made
   the size fix above look like it had not worked. The button keeps its 44px; nothing else does. */
.e8-cand-overview-psneed-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 5px;
}
/* WAVE-3 SEAM FIX — THE TWO AMBER CHIPS IN THIS CARD ARE NOW ONE CHIP.
   Measured at 1440 on #/candidate/c-okafor, inside `.e8-cand-overview-ps`, ~90px apart and
   always co-visible when both lists have rows:
     "Still needed" chips  `.e8-cand-overview-psneed-chip`  12.5 / 400 / pad 2px 8px / h 24
     "Heard on the call"   `.e8-confchip-suggested` (DS)    11.5 / 500 / pad 0px 7px / h 21
   Identical background (rgb(253,243,220)), identical border (rgb(242,223,171)), identical
   6px radius - and three pixels of height, a size step and a weight step apart. Same tint,
   same meaning ("not nailed down yet"), two boxes. The DS chip wins: `DSc.ConfidenceChip`
   is a shared component with call sites across the app, this class has exactly one
   (cand-overview.jsx:145), and the rule is that the more-used variant survives. So the
   local chip adopts the DS chip's type and box rather than a third set of numbers being
   invented for the pair. The colours and the `is-stale` dashed treatment are untouched. */
.e8-cand-overview-psneed-chip {
  font-size: var(--ui-text-xs); font-weight: 500; line-height: 1.45;
  color: var(--ui-warning-text);
  background: var(--ui-warning-tint);
  border: 1px solid var(--ui-warning-br);
  border-radius: var(--ui-radius);
  padding: 1px 7px;
  max-width: 100%;
  overflow-wrap: anywhere;
}
.e8-cand-overview-psneed-chip.is-stale {
  color: var(--ui-text-secondary);
  background: var(--ui-fill);
  border-color: var(--ui-border-strong);
  border-style: dashed;
}
/* Sits IN the chip list, so it wears the chip's box - it was 12.5/400 among 11.5/500 chips. */
.e8-cand-overview-psneed-more {
  font-family: inherit; font-size: var(--ui-text-xs); font-weight: 500; line-height: 1.45;
  color: var(--ui-text-secondary); background: transparent;
  border: 1px dashed var(--ui-border-strong); border-radius: var(--ui-radius);
  padding: 1px 7px; cursor: pointer;
}
.e8-cand-overview-psneed-more:hover { color: var(--ui-text); border-color: var(--ui-text-tertiary); }

/* ONE action. The portal request is the same job by another route, so it stays a
   subordinate link rather than a second button competing for the same decision —
   and it now READS subordinate: one step down the type scale, against a CTA that
   went from 24px to 34px. Two controls of near-equal weight is how this block was
   read as having two CTAs.
   THE DEMOTION IS SIZE ONLY — the ink stays `--ui-text-secondary`. Dropping it to
   `--ui-text-tertiary` was tried and measured 2.7:1 against `--ui-surface` in light
   (rgb(156,156,166) on white), i.e. an interactive control under the 4.5:1 floor;
   secondary is 5.0:1 in light and 5.0:1 in dark. A control may be quiet. It may
   not be unreadable. */
.e8-cand-overview-psact { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; margin-top: 2px; }
.e8-cand-overview-psalt {
  font-family: inherit; font-size: var(--ui-text-xs);
  color: var(--ui-text-secondary); background: transparent; border: 0; padding: 2px 0;
  cursor: pointer; border-radius: var(--ui-radius); text-align: left;
}
.e8-cand-overview-psalt:hover { color: var(--ui-accent); text-decoration: underline; }

.e8-cand-overview-pssugg {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin-top: 2px; padding-top: 8px; border-top: 1px solid var(--ui-border);
}
.e8-cand-overview-pssugg-k { font-size: var(--ui-text-xs); color: var(--ui-text-tertiary); }

/* Reconfirm: everything was gathered, but the volatile answers expired. An old
   prescreen must never impersonate a fresh one, so the bar goes warning-toned. */
.e8-cand-overview-ps.is-reconfirm .e8-cand-overview-ps-track > i { background: var(--ui-warning); }

/* Complete. */
.e8-cand-overview-ps.is-ready {
  display: flex; align-items: flex-start; gap: 8px;
  background: var(--ui-success-tint); border-color: transparent;
  color: var(--ui-success-text);
  padding: 9px 12px;
}
.material-symbols-outlined.e8-cand-overview-ps-ic { font-size: var(--ui-icon-sm); color: var(--ui-success-text); flex: none; }
.e8-cand-overview-ps-readytxt { margin: 0; font-size: var(--ui-text-sm); line-height: 1.5; }
.e8-cand-overview-ps-readytxt b { font-weight: 650; }
.e8-cand-overview-ps-prov { color: color-mix(in srgb, var(--ui-success-text) 82%, transparent); }

/* Parked record: the gap is real but it is not today's work. */
.e8-cand-overview-psmini {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border: 1px dashed var(--ui-border-strong); border-radius: var(--ui-radius-pill);
  background: transparent; padding: 4px 12px; cursor: pointer;
  font-family: inherit; font-size: var(--ui-text-sm); color: var(--ui-text-tertiary);
  text-align: left;
}
.e8-cand-overview-psmini > i { width: 6px; height: 6px; border-radius: 3px; background: var(--ui-warning); flex: none; }
.e8-cand-overview-psmini-t { color: var(--ui-text-secondary); }
.e8-cand-overview-psmini-t b { font-weight: 650; color: var(--ui-text); }
.e8-cand-overview-psmini-sub { font-size: var(--ui-text-xs); }
.e8-cand-overview-psmini:hover { border-color: var(--ui-warning); }


/* ════════════════════════ 8. ACTIVITY FEED ════════════════════════ */

.e8-cand-overview-act { display: grid; gap: 6px; justify-items: start; }
.e8-cand-overview-acthead { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; width: 100%; }
.e8-cand-overview-actcount { margin-left: auto; }
.e8-cand-overview-actgroup { width: 100%; }

/* THE DAY DIVIDER, DRAWN THE WAY THE OTHER DAY DIVIDER ON THIS RECORD IS DRAWN.
   Messages groups its thread by day too (`.e8-cand-rec-msgday`, cand-record.css):
   11.5px, secondary, sentence case, with a hairline running out to the right. This
   one arrived uppercase, tracked, on its own border and STICKY - one idea, two looks,
   two modules.

   Worse, the look it arrived with was not the one it asked for. Measured at 1440 and
   834: it computed 13.5px / 600 / letter-spacing -0.135px / --ui-text, because
   `.elev8 h4` (product.css:250 + :234) is (0,1,1) and the class was (0,1,0) - so
   font-size, letter-spacing, weight and colour ALL came from the type selector and
   the declared 11.5 / 650 / .05em / tertiary never applied. The result was a day
   stamp LARGER and blacker than the "Latest activity" label that owns it and equal
   in size to the entry titles under it: the type ramp inverted twice in 40px.

   Sentence case also ends the label-case drift between the two feeds - "JUL 30" over
   here, "Thu, Aug 7" over there, from the same kind of list.

   `h4.` keeps the heading semantics and beats the type selector.

   STICKY IS BACK, AND THE ARGUMENT FOR DROPPING IT WAS HALF RIGHT. It was dropped
   because the digest caps at three entries (`all.slice(0, 3)`), and that is true of
   the RESTING state: measured at 390x844, the "Today" group is 285.9px inside a
   659px scroll port, so the header cannot leave while its own entries are on
   screen. What the argument missed is that every entry in this feed OPENS - the
   body clamps to two lines and expands on demand (`.e8-cand-overview-acttext`) -
   and three opened entries clear the port easily. §2.6 of the reference asks for
   sticky day headers outright, and a header that is only load-bearing in the
   expanded state is still load-bearing.

   Three things it needs to be correct rather than merely present:
   - `background`, because a transparent stuck header lets the entries scroll
     THROUGH its glyphs. `--ui-bg-app` is not a guess: it is the token
     `.e8-recordbody .e8-rbody-content` (app.css:2326) paints the scroll port with,
     read back from the live element (rgb(249,249,250) in light), and this column
     sits directly on it — the section, the group and the header all compute
     `background-color: rgba(0,0,0,0)`. Same token, so dark mode cannot drift.
   - `z-index: 1`, because `.e8-cand-overview-actflagwrap` is `position: relative`
     at z-index auto and sits LATER in the DOM: two auto-z positioned boxes paint
     in tree order, so a following group's Unreviewed pill would slide over the
     stuck header. 1 beats auto and still loses to the flag menu's 30, which is
     what must stay on top.
   - the 8px gap to the list is now 4 + 4 rather than 0 + 8, so the header's opaque
     box keeps 4px of air under it when an entry passes beneath. The resting gap is
     unchanged — this is the same 8px, spent on both sides of the seam.

   AND ONE THING THIS FILE CANNOT FINISH ALONE — SAID PLAINLY RATHER THAN FAKED.
   `.e8-cand-tabs-row` (cand-tabs.css) is ALSO sticky in this same scroller at
   `top: 0; z-index: 2` with an opaque `--ui-bg-app`, at container widths ≤840.
   Measured at 390x844: the port's top edge is y=163, the tab row occupies
   163→252, and this header sticks at exactly y=163 — under an opaque bar that is
   both taller and higher in the stack, so on the phone and tablet layouts the
   stuck header is INVISIBLE. Nothing paints wrongly (verified: no ghost, no gap,
   no overlap — the header simply disappears under the bar exactly as it used to
   disappear off the top), but the sticky only earns its keep where the tab row is
   static, i.e. the desktop layout.
   The missing piece is a contract, not a value: whatever is sticky at the top of
   the record's content column must publish its height so anything else sticky in
   that column can sit below it. `top` therefore reads
   `--e8-cand-rec-sticky-top`, which nothing declares today (so it resolves to the
   0px fallback and this is exactly as measured above) and which the record shell
   or the tab row can start publishing without a change here. Hard-coding another
   module's 89px into this file is the workaround that rule exists to prevent —
   the row is 89px at 390 only because five tabs wrap to two lines. */
h4.e8-cand-overview-actday {
  display: flex; align-items: center; gap: 10px;
  margin: 0; padding: 4px 0;
  position: sticky; top: var(--e8-cand-rec-sticky-top, 0px); z-index: 1;
  background: var(--ui-bg-app);
  font-size: var(--ui-text-xs); font-weight: 400;
  letter-spacing: inherit; text-transform: none;
  color: var(--ui-text-secondary);
}
h4.e8-cand-overview-actday::after {
  content: ''; flex: 1 1 auto; height: 1px; background: var(--ui-border);
}
.e8-cand-overview-actlist { list-style: none; margin: 0; padding: 4px 0 0; }

.e8-cand-overview-actitem { display: flex; gap: 12px; }
.e8-cand-overview-actrail { display: flex; flex-direction: column; align-items: center; width: 24px; flex: none; }
/* THE ACTOR MARK'S MEASUREMENTS, because the DS component's are off the type scale
   and unreachable. `DSc.Avatar` writes width/height/font-size as INLINE styles and
   derives the size as `px * 0.4` — `size="sm"` is 24px, so its initials render at
   9.5px: the smallest type on this record, and not one of 11.5 / 12.5 / 13.5 / 15 /
   18 / 24 / 28. None of its five sizes is on the scale (8 / 9.5 / 10.5 / 14.5 /
   22.5), so no prop fixes it and no class rule outranks an inline style.
   `cand-header.jsx` hit this first and answered it the same way (cand-header.css:63):
   render `.e8-avatar`'s classes on a plain span — shape, tint, ink and the agent
   mark's `::after` all still come from the DS sheet — and state the two numbers here.
   The box is unchanged at 24px, which is the rail's width; only the glyph moves. */
.e8-cand-overview-actav { width: 24px; height: 24px; font-size: var(--ui-text-xs); line-height: 1; }
.e8-cand-overview-actline { flex: 1; width: 1px; background: var(--ui-border); margin: 4px 0; }
.e8-cand-overview-actitem.is-last .e8-cand-overview-actline { background: transparent; }
.e8-cand-overview-actbody { flex: 1; min-width: 0; padding-bottom: 16px; }

/* ACTOR DISTINCTION, on two independent signals rather than colour alone: the
   gutter mark (round initials for a person, the square agent mark for an agent)
   and the "Person"/"Agent" tag beside the name, plus a bot glyph on the agent. */
.e8-cand-overview-actmeta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-width: 0; }
.e8-cand-overview-actwho {
  display: inline-flex; align-items: center; gap: 4px; min-width: 0;
  font-size: var(--ui-text-sm); font-weight: 600; color: var(--ui-text);
}
.material-symbols-outlined.e8-cand-overview-actwho-ic { font-size: var(--ui-icon-xs); color: var(--ui-daybreak-text); }
/* .05em, not .04em: the record's uppercase labels are `.e8-eyebrow`,
   `.e8-rrail-sec-title` and this tag, and two of the three were already .05em. */
.e8-cand-overview-actkind {
  font-size: var(--ui-text-xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ui-text-tertiary); background: var(--ui-fill);
  border-radius: var(--ui-radius-pill); padding: 1px 7px;
}
.e8-cand-overview-actitem.is-agent .e8-cand-overview-actkind {
  color: var(--ui-daybreak-text); background: var(--ui-daybreak-wash);
}
.e8-cand-overview-actwhen {
  margin-left: auto; font-size: var(--ui-text-xs); color: var(--ui-text-tertiary); white-space: nowrap;
}

/* EXPANDABLE, NOT TRUNCATED. The title is the one thing that never clips — it is
   the whole point of the row. The body clamps to two lines and opens on demand,
   and the deep link arrives with the detail rather than sitting under a summary
   nobody has read yet. */
.e8-cand-overview-actsum {
  display: flex; align-items: flex-start; gap: 6px; width: 100%;
  margin-top: 5px; padding: 0; border: 0; background: transparent;
  font-family: inherit; text-align: left; cursor: pointer; border-radius: var(--ui-radius);
}
.e8-cand-overview-actsum.is-static { cursor: default; }
.e8-cand-overview-acttitle {
  flex: 1; min-width: 0;
  font-size: var(--ui-text-base); font-weight: 500; line-height: 1.45; color: var(--ui-text);
  overflow-wrap: anywhere;
}
.e8-cand-overview-actsum:hover .e8-cand-overview-acttitle { color: var(--ui-accent); }
.e8-cand-overview-actsum.is-static:hover .e8-cand-overview-acttitle { color: var(--ui-text); }
/* The rotation and its transition are GONE - the JSX swaps `expand_more`/`expand_less`, which
   is what the header's score chip, the stage chip and the shared `OvDisclose` all do. See the
   note at the About chevron above; `rotate(180deg)` appears nowhere in app.css. */
.material-symbols-outlined.e8-cand-overview-actchev {
  font-size: var(--ui-icon-sm); color: var(--ui-icon-quiet); flex: none;
}
.e8-cand-overview-acttext {
  margin: 3px 0 0; max-width: 72ch;
  font-size: var(--ui-text-sm); line-height: 1.5; color: var(--ui-text-secondary);
  text-wrap: pretty;
}
.e8-cand-overview-acttext.is-clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.e8-cand-overview-actgo { display: inline-block; margin-top: 5px; font-size: var(--ui-text-sm); white-space: nowrap; }
/* ONE INK FOR EVERY EMPTY STATE ON THE RECORD. Three modules wrote this sentence and
   two of them wrote it in tertiary: `.e8-cand-rec-skempty` (cand-record.css) was
   secondary, this and `.e8-cand-rail-empty` were tertiary, so the same "nothing here
   yet, and here is what goes here" voice was two different greys depending on which
   block you were looking at. Secondary wins on both counts: it is the ink the longest
   of the three already used, and --ui-text-tertiary is rgb(156,156,166), which measures
   2.72:1 on --ui-surface against a 4.5:1 AA floor - an empty state is prose a person is
   meant to read, not a stamp. */
.e8-cand-overview-actempty {
  margin: 0; max-width: 60ch;
  font-size: var(--ui-text-sm); line-height: 1.5; color: var(--ui-text-secondary);
}

/* Unreviewed AI activity — actionable, not decorative.

   `scrollWidth 92 / clientWidth 84` ON THIS PILL IS NOT CLIPPED TEXT. It was read
   as the last ~8px of "Unreviewed" painting outside its own fill; it is the 44px
   hit-area `::after` at the bottom of this file, which is `inset: -8px` and so
   overflows its host by exactly 8px on each side — scrollWidth counts the right-
   hand 8 and reports 92. Measured on the live pill at 834 with a Range over its
   text: the glyphs run 208.9→272.9 inside a border box of 197.9→283.9. Nothing
   paints outside. Anything reasoning from scrollWidth on an element with an
   outset pseudo-element is measuring the pseudo-element.
   RE-MEASURED AT 390x844 after two more reports of the same 92/84, and the same
   answer holds with a second, independent tell: scrollHEIGHT is 34 against a
   clientHeight of 26 — the identical +8, on an axis where no theory of clipped
   `nowrap` text predicts anything at all. A Range over the label reads 209.45 →
   273.47 (64.02px of glyphs) inside a border box of 198.45 → 284.47, i.e. 11px of
   clear padding at each end. The 28.09px HEIGHT reported against the 44px touch
   floor is the layout box, not the target: with the pill scrolled into view,
   `elementFromPoint` returns this button at 6px beyond all four of its edges, so
   the touchable area is 102 x 44.09.
   `flex: none` below is a floor, not a fix for that: app.css:4646 sets
   `min-width: 0` on `.e8-cand-overview *` under `@media (max-width: 840px)`, which
   removes the automatic minimum size that normally stops a flex item shrinking
   under its own `nowrap` label. Nothing is shrinking at 390/834/1440 today — a
   longer label or a narrower meta line is all it would take, and the meta line
   wraps instead, which is what a wrapping flex container is for. */
.e8-cand-overview-actflagwrap { position: relative; display: inline-flex; flex: none; max-width: 100%; }
.e8-cand-overview-actflag {
  flex: none;
  font-family: inherit; font-size: var(--ui-text-xs); font-weight: 600; line-height: 1.4;
  color: var(--ui-warning-text); background: var(--ui-warning-tint);
  border: 1px solid var(--ui-warning-br); border-radius: var(--ui-radius-pill);
  padding: 1px 8px; cursor: pointer; white-space: nowrap;
}
.e8-cand-overview-actflagmenu {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 30; min-width: 190px;
  display: grid; padding: 4px;
  background: var(--ui-surface); border: 1px solid var(--ui-border-strong);
  border-radius: var(--ui-radius-card); box-shadow: var(--ui-shadow-overlay);
}
.e8-cand-overview-actflagmenu button {
  border: 0; background: transparent; text-align: left; cursor: pointer;
  font-family: inherit; font-size: var(--ui-text-sm); font-weight: 500; line-height: 1.4;
  color: var(--ui-text); padding: 7px 10px; border-radius: var(--ui-radius);
}
.e8-cand-overview-actflagmenu button:hover { background: var(--ui-fill); }
/* THE ONLY LOCAL FOCUS RING LEFT IN THIS FILE, AND THE ONLY ONE THAT EVER PAINTED.
   Six others (`abmore`, `psneed-more`, `psalt`, `psmini`, `actsum`, `actflag`) were
   deleted: `.e8-cand-overview-x:focus-visible` is (0,2,0) and `.elev8 button:focus-visible`
   (app.css) is (0,2,1), so `outline: none` won and what actually painted was the house
   box-shadow ring. Verified in the browser, not derived: with the button focused,
   `matches(':focus-visible')` true, `outlineStyle` "none", `boxShadow`
   "rgb(255,255,255) 0 0 0 2px, rgb(82,21,252) 0 0 0 4px". cand-header.css and
   cand-tabs.css had each measured this separately; this file had not.

   This one survives because it is (0,2,1) - the `button` type selector - and so wins on
   order, and because it needs to: the house ring is a 4px OUTWARD shadow and this button
   sits in a 4px-padded popover, where an outward ring is clipped and overlaps its
   neighbours. An inset ring is the right answer here for the same reason it is right in
   the tab scroller. What changes is that it now uses the SAME inset recipe as
   `.e8-cand-tabs-sc .e8-cand-tabs-btn:focus-visible` - solid `--ui-accent`, not the 30%
   `--ui-ring` - and adds the `box-shadow: none` that file's header documents: winning the
   outline war does not turn the shadow off, so both rings were being asked for at once. */
.e8-cand-overview-actflagmenu button:focus-visible {
  outline: 2px solid var(--ui-accent);
  outline-offset: -2px;
  box-shadow: none;
}


/* ═══════════════ TOUCH SHELL — @container, AFTER the base ═══════════════
   `@container e8rec`, not `@media`: the rail squeezes this column without moving
   the viewport, so a viewport query fires at the wrong moment (and has shipped as
   a bug twice). Every rule below overrides one written ABOVE it — a conditional
   at-rule adds no specificity, so the order is the mechanism, not a preference.

   THE THRESHOLD IS 840, NOT 640, AND THAT WAS THE TABLET BUG. `e8rec` is named on
   `.e8-recordbody` (app.css:2322), which at 834 measures 834 — so a 640 query left
   the whole tablet at desktop control sizes while the app around it was serving
   its touch shell (58px bottom tab bar, FAB, `.is-narrow`, bottom-sheet rail).
   Measured at 834 before this: the prescreen CTA 24px, the activity summary 19.6px,
   "View full activity" 19.6px, the unreviewed pill 20.1px. 840 is the app's own
   touch breakpoint and the recordbody is 1088 at 1280 and 1248 at 1440, so desktop
   is untouched. */
@container e8rec (max-width: 840px) {
  /* ≥44px touch targets on the controls this file adds. */
  .e8-cand-overview-abmore { min-height: 44px; padding: 0 2px; }
  /* The block's ONE CTA. `.e8-btn-lg` is 34px from the component's own sheet at
     (0,1,0); this is (0,2,0) and `min-height` outranks `height` regardless. */
  .e8-cand-overview-psact .e8-btn { height: auto; min-height: 44px; }
  /* The chips are labels; only the "+N more" is a control, so only it takes the
     44px target. It reads slightly taller than its neighbours, which is honest —
     it is the one thing in that row you can press. */
  .e8-cand-overview-psneed-more { padding: 6px 12px; min-height: 44px; }
  .e8-cand-overview-psalt { min-height: 44px; display: inline-flex; align-items: center; }
  .e8-cand-overview-psmini { min-height: 44px; }
  .e8-cand-overview-actsum { min-height: 44px; align-items: center; }
  /* The door out of the digest is a target like any other. */
  .e8-cand-ov-actlink { min-height: 44px; display: inline-flex; align-items: center; }
  /* The unreviewed pill sits INSIDE a meta line beside the actor and the time, so
     growing it to 44px would push that line to 44px too and wreck the rhythm of
     every row. The hit area grows instead of the pill: a transparent ::after
     inset by -8px takes the 28px pill to 44px of touchable area while the layout
     box stays 28px. Measured, not assumed — see the report. */
  .e8-cand-overview-actflag { padding: 5px 10px; position: relative; }
  .e8-cand-overview-actflag::after { content: ''; position: absolute; inset: -8px; }
  .e8-cand-overview-actflagmenu button { padding: 11px 10px; min-height: 44px; }
}

/* ═══════════════ NARROW COLUMN — layout only, AFTER the 840 block ═══════════════
   What changes at a phone's width rather than at a finger's size. */
@container e8rec (max-width: 640px) {
  /* `.e8-cand-overview-psneed-chip { padding: 6px 10px }` IS GONE. It grew these chips to
     ~32px on a phone while the `DSc.ConfidenceChip`s in the same card stayed at 21px, so the
     narrow width was where the two boxes disagreed MOST. It was not a touch-target rule
     either - these are `<li>` elements, not controls, so there is nothing to hit. The one
     control in the list (`+N more`) keeps the 44px minimum it gets from the touch block. */
  /* The count is a second line's worth of meta on a phone; the label leads. */
  .e8-cand-overview-actcount { margin-left: 0; }
  /* The source line gets its own row rather than fighting the badge for width. */
  .e8-cand-overview-absrc { flex: 1 0 100%; }
}

/* Motion is decoration here; the state change is carried by aria-expanded and by
   the text itself, so removing it costs nothing. Written last, as it must be. */
@media (prefers-reduced-motion: reduce) {
  /* The two chevrons left this list with their `transition: transform` - they swap glyphs now
     and there is no motion to reduce. The progress fill is the only animation this file has. */
  .e8-cand-overview-ps-track > i { transition: none; }
}
