/* ═══════════════════════════════════════════════════════════════════════
   APPEND-ONLY FILE — read before editing.
   This is the append target (roadmap 3.1 §4.3). Every future dated CSS
   block goes at the EOF of THIS file, in the same house convention already
   used below (a "══ TITLE ══" banner-comment opener + matching
   "══ end TITLE ══" banner-comment closer — see the blocks under this one
   for the exact shape; do not spell the comment delimiters themselves out
   in prose here, that is exactly the bug this file's own tokenizer test
   guards against, test/cssCommentTerminator.test.js). Do not insert new
   sections above the existing ones or split this file further — cascade order across all six
   app.*.css files is load-bearing (ten selectors, incl. .cc-top/.cc-disc/
   .cc-modal*, are redeclared 5-7 times across sections; later sections
   deliberately override earlier ones — verified by
   scripts/css-ruleset-diff.js / test/cssSplitOrder.test.js), and this file
   must always be the LAST app.* <link> in index.html, immediately before
   callsheet-calm.css. Do not reorder.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══ USER VERIFICATION — responsive (appended last per house convention;
   desktop rules live in-place near the Support/guide-list styles and near
   the other admin sections — see .cc-verify-* above) ═══ */
@media (max-width: 900px) {
  /* Admin request detail: profile column + admin metadata rail collapse to
     one column below tablet width — the rail was a fixed 300px side column. */
  .cc-verify-detail-grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  /* Queue filters + action bar: same "let it wrap, never let a control
     shrink" contract as everywhere else — full width on a phone instead of
     a cramped inline row. */
  .cc-verify-filters > * { flex: 1 1 auto; min-width: 140px; }
  .cc-verify-actions .cc-btn { flex: 1 1 auto; justify-content: center; }
}
/* ═══ end USER VERIFICATION ═══ */

/* ═══ CLAIM VOUCHING — responsive (appended last per house convention;
   desktop rules live in-place near .cc-tl-actions and near the other admin
   sections — see .cc-vouch-* / .cc-adm-vf-* above) ═══ */
@media (max-width: 640px) {
  /* A work-history row's actions slot already wraps (.cc-tl-head is a flex
     row) — the vouch slot itself just needs to not force a squeeze against
     a long title on a narrow phone. */
  .cc-tl-head { flex-wrap: wrap; }
  .cc-vouch-slot { width: 100%; justify-content: flex-start; }
  /* Admin vouch-flag void control: the reason input + two buttons no longer
     fit one line under ~640px — stack to full width, same contract as the
     verification action bar above. */
  .cc-adm-vf-void { flex-wrap: wrap; width: 100%; }
  .cc-adm-vf-void .cc-input { max-width: none; flex: 1 1 160px; }
}
/* ═══ end CLAIM VOUCHING ═══ */

/* ═══ AVAILABILITY POSTS — responsive (appended last per house convention;
   desktop rules live in-place near .cc-availcard-* / .cc-availb-* above) ═══ */
@media (max-width: 640px) {
  /* Filter bar: fields go full-width and stack instead of the fixed 230px
     desktop width squeezing three pickers onto one line. */
  .cc-availb-filters .cc-field { width: 100%; }
  .cc-availb-toggles { width: 100%; }
  /* Row: avatar + name/roles/meta + View-profile button no longer fit one
     line on a phone — wrap onto their own, same contract as .cc-row
     elsewhere (max-width:640px block near line 1391). */
  .cc-availrow { flex-wrap: wrap; }
  .cc-availrow .cc-act { width: 100%; text-align: left; }
}
/* ═══ end AVAILABILITY POSTS ═══ */

/* ═══ ACCT ROUND 9 — Est. profit KPI + invoice category/period filters
   (appended last per house convention; desktop rules for the round's other
   pieces reuse .cc-select/.cc-input/.cc-tbl-wrap as-is, no new selectors
   needed there) ═══
   1) .acct-kpi-row5 — the Dashboard's 5-card row (Outstanding/Overdue/
      Collected/Net profit/Est. profit) once CC.ledger.estimatedProfit is
      available; .acct-kpi-row4 is untouched so the 4-card layout still
      renders when the 5th card is omitted. Same auto-fit contract as
      .acct-kpi-row4 — no separate mobile query needed, it already stacks to
      one column once a card can't hold its minmax width. */
.acct-kpi-row5 { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 12px; margin-bottom: 18px; }
/* 2) Invoices list per-row Category <select> (owner "out" tab) — sized to
      fill its table cell like every other .cc-select; no accent, no colour
      coding, text-only hierarchy per the design bible. */
.acct-catcell { padding: 6px 9px; font-size: 12.5px; }
@media (max-width: 640px) {
  /* Keep the Invoices list table from picking up a horizontal scrollbar at
     narrow widths (measured down to 320px) once the Category column is
     added — it's a desktop power-user column; drop it on a phone rather
     than squeeze an 8th column in (same "priority-hide" contract as the
     rest of the app's mobile tables). */
  .acct-th-cat, .acct-td-cat { display: none; }
}
/* ═══ end ACCT ROUND 9 ═══ */

/* ═══ ACCT TILE OVERFLOW FIX (Tomas QA 2026-07-29 — the Dashboard "Needs
   attention"/"Income by category" tiles overflowed their .cc-card border
   by ~60px at 959px width; same class of bug threatens every .acct-shell
   tile. Appended last per house convention.) ═══
   Root cause, two layers: (1) .acct-dash-grid's tracks already carry
   minmax(0, …fr) so the TRACKS can't blow out, but a grid ITEM still
   defaults to min-width:auto — so the .cc-card child kept rendering at
   its content's min-content width (the table's), past the 226px track
   Chrome had actually laid out for it, instead of shrinking to fit. (2)
   .acct-plaintable is a plain <table>, not the .cc-tbl-wrap primitive —
   no overflow-x:auto anywhere rescues it (the app-wide `.cc-card{overflow-x:
   auto}` fallback is gated ≤860px; this bug lives above that, wherever the
   dash grid is 2 columns — active for any viewport over 900px, i.e. most
   of the usable range up to true desktop). Fix: let the grid item
   actually shrink, then hard-cap the table to its own box so it can never
   force ANY ancestor wider, in any layout mode (grid, flex, block —
   .acct-reports-grid's single-column cards hit the same table on the
   Reports page). */
.acct-dash-grid > *, .acct-reports-grid > * { min-width: 0; }
.acct-plaintable { width: 100%; table-layout: fixed; }
/* Numeric/date/id columns (.cc-num — invoice #, due date or "OVERDUE",
   currency) hold bounded, near-constant-length strings; a percentage
   width (never a bare px — table-layout:fixed treats px as literal even
   when it doesn't fit, which would reopen the same escape this block
   fixes) gives each a comfortable, table-relative share that can never
   sum past 100%. They stay nowrap and get NO ellipsis — they must never
   truncate or wrap mid-token. The one free-text column per row (client
   name / category name — the only <td> without .cc-num) is unbounded
   user data; it's the column that yields, via ellipsis, to whatever
   share table-layout:fixed leaves it. This supersedes the R5 mobile
   truncation above, which targeted td:nth-child(2)/(3) by POSITION — that
   assumption breaks on the 2-column income/category tables, where
   nth-child(2) is the .cc-num amount, not the free-text cell; same
   specificity, later in cascade, this block wins for every .acct-plaintable
   td going forward. */
.acct-plaintable td.cc-num {
  width: 34%; white-space: nowrap;
  /* Neutralize the R5 mobile rule above: td:nth-child(2)/(3) there sets
     overflow:hidden + ellipsis by POSITION, which lands on a .cc-num cell
     in the 4-column "Needs attention" row (nth-child(3) = due date) — a
     number silently clipping is exactly what this block exists to stop.
     Equal specificity, later in the file: this wins for every .cc-num
     cell regardless of which position rule above also matches it. */
  overflow: visible;
}
.acct-plaintable td:not(.cc-num) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Drop the least essential number — the invoice # (the row is a click-
   through to the invoice detail; # is redundant next to it) — from the
   "Needs attention" tile UNCONDITIONALLY, not just at narrow widths. Three
   .cc-num columns at any single percentage each would sum past 100% (e.g.
   34% × 3 = 102%) — table-layout:fixed doesn't scale that back down, it
   zeroes the one column with no explicit width (the client name) and lets
   the oversubscribed numeric columns collide instead — and this tile
   never gets enough room (a 1.4fr/2.4 share of a card, itself squeezed
   between the docked accounting rail and app sidebar) to comfortably fit
   3 full numeric columns AND a legible client name at any width this
   ships to. Same "priority-hide" contract as the Invoices list Category
   column above (app.css ~6950). :first-child scopes this to the 4-column
   "Needs attention" row specifically: the 2-column income/category
   tables' first cell is the free-text category name, never .cc-num, so
   this selector never matches there — they keep their one numeric column
   (the amount) at every width, and it needs a wider share than a same-
   sized column could afford to give up in the 4-column row, hence the
   split below by role (.r = the amount, always present; the plain
   .cc-num = the row's one remaining "other numeric" column, due date or
   OVERDUE, once invoice # is gone). */
.acct-plaintable td.cc-num:first-child { display: none; }
/* Two tiers, not one: a single percentage generous enough for the
   narrowest case (a 320px phone) wastes most of the table on numbers at
   a spacious 1280px+ desktop — the client name would get ~1% of the row
   and never show at all even though there's easily 60px+ going spare.
   Below, ≤1080px re-tightens both to their measured worst case (this
   tile never gets more than a ~250px table right as the 2-column grid
   turns on at 1081px). */
.acct-plaintable td.cc-num:not(.r) { width: 47%; }
.acct-plaintable td.r.cc-num { width: 38%; }
/* nth-child(2) only happens in a 2-column row (category/client + amount,
   nothing else — .cc-num:first-child above is display:none, not removed,
   so DOM child-indexing still counts it in the 4-column row, where the
   amount lands at nth-child(4) instead). The income/category tables'
   amount is alone with the free-text column, so it can take a much
   bigger share without starving anything else. */
.acct-plaintable td.r.cc-num:nth-child(2) { width: 58%; }
@media (max-width: 1080px) {
  .acct-plaintable td.cc-num:not(.r) { width: 55%; }
  .acct-plaintable td.r.cc-num { width: 44%; }
}
/* Even with the least essential number gone, the "Needs attention" row's
   remaining 2 numeric columns (due date + amount, ~113px + ~90px at this
   table's 13px type) still don't fit inside the 2-column dash grid's
   narrowest points — right where it activates (901px) the left card's
   own table was ~137px, nowhere near the ~200px+ those two columns need
   even combined at 100%. Extending the single-column range (originally
   900px) further removes that pinch entirely: by 1080px the grid track
   is wide enough that both tiles clear their content comfortably (the
   2-column table above measures ~250px right at 1081px, the new
   narrowest 2-column point — covered by the tighter percentages above),
   and true desktop (1280px+, the standard test width) keeps the 2-up
   layout throughout, roomy enough for the gentler default split. */
@media (max-width: 1080px) { .acct-dash-grid { grid-template-columns: minmax(0, 1fr); } }
/* ═══ end ACCT TILE OVERFLOW FIX ═══ */

/* ═══ DISCOVERY-PILL WRAP FIX (Tomas QA 2026-07-29, measured at 836×1100 —
   same round as the ACCT TILE OVERFLOW FIX above; appended last per house
   convention) ═══
   Two distinct bugs sharing one root: `.cc-disc-when input { width: 7.6em; }`
   (app.css ~876, from BEFORE DateField grew its permanent invisible-overlay
   pattern — src/…/views.js DateField: an absolutely-positioned real
   `<input type=date>` plus a normal-flow `.cc-datefield-disp` text input
   that shows the formatted value) still matches `.cc-datefield-disp` too
   (it's an <input> inside .cc-disc-when) — and at (0,1,1) it OUT-SPECIFIES
   `.cc-datefield-disp { width: 100%; }` (0,1,0), pinning the display input
   to a hard 114px regardless of how much the flex row has actually shrunk
   its wrapper. Below ~900px (crew/events, the plain `.cc-disc-wrap` mount,
   no .cc-ocbar) that alone is enough to push `.cc-disc-when` past its box
   by ~41px and the segment after it by ~17px — silently: nothing clips it,
   so the row just quietly overlaps instead of visibly breaking. */
.cc-disc-when .cc-datefield-disp { width: 100%; }
/* On #/jobs specifically (.cc-ocbar, the hero/docked search bar), the
   existing ≤980px rule already forces the 3 segments into a full-width
   stack (`.cc-ocbar .cc-disc-seg { flex: 1 1 100%; }`, app.css ~5673) —
   that part was already correct. But nothing in that block resets the
   capsule's UNCONDITIONAL 999px pill radius (app.css ~6111) or the go-
   button's circular 50% radius for the now-~200px-TALL stacked box, so
   the pill rendered as a rounded blob and the button stretched into a
   flat ellipse (`.cc-ocbar .cc-disc-go` already goes `width:100%;
   height:auto` there — height:auto collapsed to the icon's own ~20px).
   The base (non-.cc-ocbar) `.cc-disc` component already solved this
   exact problem for ITS OWN ≤760px stack (app.css ~882: rectangular
   radius + a fixed-height, labeled Search button) — mirror that same
   treatment here, just at the wider 980px breakpoint this bar uses. */
@media (max-width: 980px) {
  .cc-ocbar .cc-disc { border-radius: var(--cc-radius-lg); }
  .cc-ocbar .cc-disc-go { height: 46px; border-radius: var(--cc-radius-md); gap: 8px; }
  .cc-ocbar .cc-disc-go::after { content: 'Search'; font: 600 14px/1 var(--cc-font); color: #fff; }
}
/* ═══ end DISCOVERY-PILL WRAP FIX ═══ */

/* ═══ ACCT CELL-CRUSH FIX (Tomas QA follow-up on #305, 2026-07-29 — measured
   live at 959px: INV# cell correctly display:none, but the client-name cell
   collapsed to ~4px (invisible) while due-date sat at 196px and amount at
   157px. Appended last per house convention; overrides the percentage rules
   above by matching/exceeding their selectors' specificity, later in
   cascade order — none of the rules above are edited or removed.) ═══
   Root cause: #305's `.cc-num` columns are sized as a PERCENTAGE OF THE
   WHOLE TABLE WIDTH (34%/47%/55% etc.), tuned by hand per breakpoint to
   "leave enough" for the free-text column. That budget silently assumed
   exactly 3 visible columns sharing the 100%. Once the INV# column goes
   display:none (correct — it's redundant with the row's own click-through)
   its box drops out of the table entirely, but the TWO remaining `.cc-num`
   percentages (55%+44%=99% at ≤1080px, where this tile lives almost the
   whole time — see the single-column breakpoint above) don't get smaller
   to compensate: they still sum to ~99% of the SAME full table width,
   leaving ~1% — a few px — for the client-name cell, which has no width of
   its own (relies on the leftover).
   Fix: stop giving the numeric columns a share of the total and instead
   give them a fixed, content-sized width in `ch` (scales with each cell's
   OWN font-size, so it stays correct through the R5 mobile block's 13px→
   12.5px shrink and through root-font-size zoom alike — a `px` width
   would not). Content is bounded and known: "due Mon D"/"OVERDUE" for the
   date column (acct.js now renders CC.util.dateRange's short "Mon D" form
   instead of the raw 10-char ISO date — see acct.js ~1306; measured ≤8.3ch
   content at any font-size, ch-ratio is font-size-invariant) and a
   currency string for the amount column (measured ≤10.4ch content up to
   $1,234,567.89, 600 weight) — both get a comfortable multiple of that
   with headroom for real invoice totals. Per the CSS table spec
   (17.5.2.1), any column in the first row LEFT AT 'auto' shares the space
   the fixed-width columns don't claim — so the free-text cell (client name
   / category name — the only <td> without a `.cc-num` class, already
   unbounded/no width set) automatically becomes that flexible column and
   gets 100% minus these two fixed widths, whatever that is at the current
   viewport. This is column-count-agnostic: it works unchanged for both the
   4-column "Needs attention" row (INV# hidden + client + due + amount) and
   the 2-column "Income by category"/Reports rows (category + amount) —
   the old nth-child(2) 58% special-case existed only to hand-tune the
   2-column table's split and is no longer needed once the amount column
   sizes itself; superseded below by restating that exact selector. */
.acct-plaintable td.cc-num:not(.r) { width: 11ch; }
.acct-plaintable td.r.cc-num,
.acct-plaintable td.r.cc-num:nth-child(2) { width: 13ch; }
/* R5's mobile block (app.css ~6811, ≤640px) caps td:nth-child(2)/(3) at
   100px/88px by POSITION — on the 2-column income table nth-child(2) IS
   the amount (.cc-num) cell, and 88-100px is tighter than this fix's own
   13ch (~105-113px) at that block's own 12.5px font, which would clip the
   very column this fix guarantees never clips. #305 already neutralized
   that old rule's `overflow` for `.cc-num` cells (comment: "Neutralize the
   R5 mobile rule"); this neutralizes the `max-width` R5 left standing,
   the same way, same reasoning — equal specificity to R5's selectors,
   later in the file. */
.acct-plaintable td.cc-num { max-width: none; }
/* Sub-480px phones: the surrounding chrome (`.cc-main` 12px + `.cc-body`
   26px + `.cc-card` 22px padding, each side, pre-existing/untouched here)
   leaves this table only ~200-220px total at a 320px viewport — even the
   11ch+13ch numeric budget above (already shrunk from the raw-ISO-date
   width by the acct.js date-format change) plus R5's 12.5px-tier padding
   left only single-digit px for the client cell there. Because the
   numeric columns' width is in `ch` (relative to
   each cell's OWN font-size, not the root), tightening padding/font here
   shrinks BOTH the column's reserved width AND its content's rendered
   size together, in lock-step — content and column shrink as one, so
   nothing wraps or clips; it just buys back px for the free column. Floor
   is 11px (DESIGN_BIBLE's "no text <11px" rule). */
@media (max-width: 480px) {
  .acct-plaintable td { padding: 6px 4px; font-size: 11px; }
  /* Even after that shrink, an 11ch/13ch reservation (calibrated with
     headroom for the base 13px/8px-padding tier) still only leaves the
     client cell ~33px of a 320px phone's ~198px table — under the 40px
     floor. Tighten the reservation specifically at this tier: 10ch/12ch
     still clears the measured worst-case content (due "OVERDUE"/"due Mon
     D" ≤8.3ch, amount up to $1,234,567.89 ≤10.4ch) plus this tier's own
     padding with a positive (if thinner) margin — it does NOT touch the
     11ch/13ch base values other breakpoints rely on. */
  .acct-plaintable td.cc-num:not(.r) { width: 10ch; }
  .acct-plaintable td.r.cc-num,
  .acct-plaintable td.r.cc-num:nth-child(2) { width: 12ch; }
}
/* ═══ end ACCT CELL-CRUSH FIX ═══ */

/* ═══ OCBAR STACKED-DIVIDER FIX (coordinator add, same round, 2026-07-29 —
   measured on #/jobs at 836px) ═══
   `.cc-disc-seg + .cc-disc-seg::before` (app.css ~2788) is an absolutely-
   positioned 1px vertical hairline meant to sit BETWEEN horizontally
   adjacent segments. The base `.cc-disc` component un-does it at its own
   ≤760px stack breakpoint (app.css ~4887: `display:none` + a `border-top`
   swap), but `.cc-ocbar` (the #/jobs discovery pill) stacks its segments
   at a wider ≤980px breakpoint (app.css ~5665) — so from 761-980px the
   segments are already full-width stacked ROWS while the divider is still
   THERE, `left:0` now reading as a stray vertical tick on the left edge of
   each row instead of a hairline between columns. Mirror the same
   `display:none`, scoped to BOTH `.cc-ocbar` AND its own ≤980px stacked
   range (unscoped by width, this rule would also kill the divider on the
   desktop HORIZONTAL pill ≥981px, where segments sit side by side and the
   hairline is correct and wanted — confirmed live at 1280px, an easy miss
   since the base ≤760px case doesn't need the same care, it already only
   fires inside its own already-narrow media query); no replacement
   divider in the stacked range — stacked segments read fine on their own
   padding, same as the base component's stacked state relies on a plain
   border instead, and here Tomas's ask was that nothing renders in its
   place. */
@media (max-width: 980px) {
  .cc-ocbar .cc-disc-seg + .cc-disc-seg::before { display: none; }
}
/* ═══ end OCBAR STACKED-DIVIDER FIX ═══ */

/* ═══════════════════════════════════════════════════════════════════════
   === PROBE FOLLOW-UP — /invoices/new + /accounting/settings tile
   overflow (the 3 pre-existing findings #305's data-tile pass surfaced;
   measured on origin/master, all reproduce at BOTH 16px and 20px root
   font — nothing here was actually zoom-only, every offending size is
   px-fixed) ═══

   1) Invoice/estimate editor, desktop: the 2-col grid's hard 620px+420px
   track minimums (1060px + gap) can never fit the REAL content width once
   the docked accounting rail + app sidebar take their share — ~709px at a
   1280px viewport — so the grid escaped its card by ~350px. The 1180px
   viewport breakpoint measured the wrong thing (viewport, not container;
   same class as #305's dashboard bug). flex-wrap is container-driven: the
   preview drops under the form the moment the two bases stop fitting, at
   any viewport/chrome combination, no breakpoint to mistune. Proportions
   above the fit point match the old grid (surplus splits evenly). The
   preview's basis drops 420→360: ScaledDocPreview scales the doc to
   whatever width its column gets, so 360px is a perfectly usable preview
   and buys side-by-side on ~1550px+ viewports instead of ~1630px+. The
   old 1180/900px media rules above still set grid-template-columns —
   inert on a flex container, left in place (append-only zone). */
.acct-editor-wrap { display: flex; flex-wrap: wrap; align-items: flex-start; }
.acct-editor-wrap > .acct-editor-form { flex: 1 1 620px; min-width: 0; }
.acct-editor-wrap > .acct-editor-preview { flex: 1 1 360px; min-width: 0; }

/* Same disease on Settings' 2-col grid (300px+380px+22px = 702px of hard
   minimums): fits the 1280px-viewport's ~709px container by 7px, but
   overflowed at every 901–1279px viewport where the old ≤900px breakpoint
   never fired. Same container-driven conversion. */
.acct-settings-grid { display: flex; flex-wrap: wrap; align-items: flex-start; }
.acct-settings-grid > .acct-settings-col { min-width: 0; }
.acct-settings-grid > .acct-settings-col:first-child { flex: 1 1 300px; }
.acct-settings-grid > .acct-settings-col:last-child { flex: 1 1 380px; }

/* 2) Settings "Defaults" card: .cc-field-row's plain-1fr tracks carry
   AUTO minimums, so a non-shrinking child forces the track past its slot
   — here the seeded category chips (~179px min-content each once the
   160px truncation cap + chip chrome add up) pushed the row to 370px
   inside a 261px slot and the whole column escaped its card (393>307).
   minmax(0,1fr) makes the tracks honest equal shares; inputs are
   width:100% and chips/selects already clip-with-ellipsis inside a
   bounded box. Fixed on the PRIMITIVE (any field-row with a wide child
   overflows the same way, on any form) — restating its full track
   cascade here because an EOF base rule alone would out-cascade the
   earlier ≤860px/≤640px media rules by source order. */
.cc-field-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.cc-field-row-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 860px) { .cc-field-row { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 640px) { .cc-field-row-4 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }

/* 3) Mobile line-item stack (ACCT MOBILE R5 block above): the row's +11px
   escape was NOT the grid — the tracks resolve fine — it's the remove
   button's symmetric tap-target trick (padding:11px; margin:-11px), whose
   border box pokes 11px past the row's right edge (justify-self:end puts
   the MARGIN box at the edge; the negative right margin hangs the border
   box past it, and rightward box escape is exactly what scrollWidth
   counts — measured 264>253 at 390px, both font sizes). Same-size 36px
   hit area, grown leftward/vertically only: the icon stays visually flush
   right (rightmost 14px of the border box), nothing escapes. Trade-off:
   the 11px strip right of the icon (card padding gutter) is no longer
   tappable. */
@media (max-width: 640px) {
  .acct-line > *:nth-child(6) { padding: 11px 0 11px 22px; margin: -11px 0 -11px -22px; }
}
/* ═══ end PROBE FOLLOW-UP ═══ */

/* ═══════════════════════════════════════════════════════════════════════
   POSTGIG "BARE MOUNT" FIX (2026-07-30, fable-kit-audit Lane B)

   Bug: cold Page.navigate straight to #/gigs/new (bookmark/shared-link/
   reload) AND an in-app go('/gigs/new') render the IDENTICAL tree — there
   is only ONE mount path, verified via CDP both ways at 375/836/1280 —
   yet PostGig's own .cc-modal-bg (position:fixed, inset:0, z-index:50)
   covers the sticky .cc-top (position:sticky, z-index:20) whenever the
   wizard's own content is tall enough to approach the dialog's max-height
   (routinely true on page 1). elementFromPoint at the theme toggle /
   search field / bell / account chip all resolved to the modal, not the
   header control — reload the wizard and you lose the header until you
   close it.

   Root cause isn't a stacking-context trap (PostGig's modal-bg is a
   plain SIBLING of .cc-top inside .cc-main, not nested under a sticky
   ancestor the way the #285 Book-offer bug was — z-index:50 vs :20
   already resolves "correctly" there). It's that .cc-modal-bg is styled
   for OVERLAYS laid on top of an already-rendered page. PostGig never is:
   both its real callers (app.js '/gigs/new', and PostComposer's '/post'
   passthrough in views.js) ARE the whole route's content — there's no
   page behind it a dimmed cover would make sense over, so simply raising
   the header's z-index above the modal would only trade one bug for
   another (the header would then paint OVER the wizard's own head/×
   wherever their boxes overlap).

   Fix: give PostGig's wrapper a second class and turn it from a viewport-
   escaping fixed overlay into a normal flex item of .cc-main — which is
   ALREADY `display:flex;flex-direction:column` (line 37) with the mode/
   onboarding banners and .cc-top as its earlier siblings. This is the
   exact technique .cc-main:has(.cc-msgs) / .cc-maxw.cc-msgs already use
   to hand a view the "rest of the viewport" below the header (line 421+)
   — reused here instead of hand-computing a pixel offset, because the
   banners' combined height is NOT constant (0, 1, or — demo + an
   incomplete profile — 2 stacked .cc-mbar rows, any of which can wrap to
   a second line at narrow widths). Flexbox gives the exact remaining
   space for free, on every width, with either banner present or not.
   max-height switches from vh/dvh (relative to the whole viewport) to
   100% (relative to this now-definite-height flex item) so the dialog's
   own internal-scroll cap shrinks along with the space actually left —
   it can never poke back up above its flex box into the header. */
.cc-main:has(.cc-postgig-bg) { height: 100vh; height: 100dvh; overflow: hidden; }
.cc-postgig-bg { position: static; flex: 1; min-height: 0; height: auto; }
.cc-postgig-bg .cc-modal { max-height: 100%; }
/* ═══ end POSTGIG BARE MOUNT FIX ═══ */

/* ═══ VALIDATION-SWEEP FIX ROUND (fable-kit-audit, 2026-07-30) — Lane A,
   fix/sweep-findings-round1. 8 findings from the new total-validation
   harness (npm run validate:seed + scripts/matrix-run.js). Does NOT touch
   .acct-line/.acct-lines/invoice-editor columns — those are owned by the
   parallel fable-cell-crush/fable-invdoc-crush chip sessions. ═══ */

/* 1) Landing kicker invisible in LIGHT look. .cc-herobig always carries a
   hard-coded dark backdrop (background-color: var(--cc-chrome), same
   near-black #1B1915 in every palette incl. the default light look) — its
   sibling h1/p already hardcode white/rgba(255,255,255,.84) instead of an
   ink/soft token for exactly this reason (~app.css:822-823). .cc-lp-kick
   was the one text node in the hero that still used var(--cc-soft) (light
   look's --cc-soft is a dark warm gray, #5F5C55 — nearly invisible on the
   #1B1915 bg it sits on: measured live, kicker text color and hero
   background both computed rgb(27,25,21)). Scoped to `.cc-herobig` only —
   the OTHER place cc-lp-kick renders (the premium landing's light-backdrop
   hero, .cc-lp-hero-copy) is correct as-is and must keep the token. The
   views.js JSX no longer forces the bold half to `var(--cc-ink)` inline
   (same invisibility bug, just harder to override from CSS since inline
   style beats any non-!important rule) — CSS now owns both halves. */
.cc-herobig .cc-lp-kick { color: rgba(255, 255, 255, .72); }
.cc-herobig .cc-lp-kick b { color: #fff; }

/* 2) Guest landing header — "Log in" / "Sign up free" wrap to 2 lines at
   320px (measured 51.19px tall, both buttons) because .cc-btn has no
   white-space floor and .cc-landing-actions is a shrinkable flex row; the
   button box shrinks below the text's natural width and the text wraps
   inside it. Forcing nowrap raises each item's min-content back up to its
   single-line width — but that alone traded a visible bug for an INVISIBLE
   one: at 320px the wordmark (105px) + gap (12px) + both nowrap buttons
   (188px) need ~305px against a 284px content box (18px padding each
   side), 21px over. `html, body { overflow-x: hidden }` (the general
   ≤860px mobile safety net, ~app.css:719) silently clips the excess
   instead of showing a scrollbar or a page-overflow finding — the
   htmlOverflowX(clipped)/scrollWidth(320, looks clean) combination is
   exactly what let this slip past a first pass that only checked
   scrollWidth==clientWidth. Caught by directly comparing each button's
   getBoundingClientRect() against the viewport, not just the document's
   scrollWidth. Fix: let the header itself wrap — the actions row drops
   below the wordmark exactly when (and only when) the two don't fit on
   one line together (verified: still one row at 480px+, two rows with
   both buttons fully on-screen at 320px), same standard flex-wrap
   behavior as the other container-driven fixes in this file. */
.cc-landing-actions .cc-btn { white-space: nowrap; }
.cc-landing-top { flex-wrap: wrap; row-gap: 8px; }

/* 3) /crew: two symptoms, ONE root cause. .cc-clist's grid-template-columns
   is force-reset to a bare `1fr` (no minmax ceiling) by the "single row per
   item" rule (~app.css:5651, Tomas 2026-07-15) instead of the auto-fill
   minmax it started as. A bare `fr` track's default minimum is `auto` —
   the width of its widest item's min-content — so a crew card with enough
   unbreakable content (a long name, a long single-line location) forces
   the ONE grid track wider than .cc-split2-list's actual box. Two
   observable failures from the same overflow: (a) desktop — the card's
   own right edge (and the save-heart pinned to it, position:absolute;
   right:11px) push ~50-80px past the list column into the sticky detail
   panel's territory, so the panel silently eats the heart's clicks
   (elementFromPoint at the heart's rect center returned the panel, not the
   heart); (b) 320px — the same track-growth escapes the whole page by
   281px (scrollWidth 563 vs the 244px .cc-crewb column). `min-width: 0` on
   the grid ITEM (not the grid container, which was already sized
   correctly) is the standard fix for a grid track inflating past its
   container on unbreakable content — verified BOTH symptoms gone at once:
   heart's elementFromPoint hit == the heart button itself at 1320px, and
   .cc-maxw.wide.cc-crewb's scrollWidth==clientWidth at 320px. */
.cc-cwc { min-width: 0; }

/* 4) /u/:id profile header overflow, 320-900px (confirmed the underlying
   .cc-pactions squeeze actually reaches ~1100px on the worst-case seeded
   name — same "breakpoint measured the wrong thing, viewport instead of
   container" disease as the acct-editor-wrap/acct-settings-grid fixes
   above; fixed the same container-driven way, not with a hand-picked
   breakpoint) — three gaps in the same .cc-phead flex row:
   (a) .cc-pactions (Save/Report/Block icons + Message + Invite + "Book
   <name>") is flex-shrink:0 with no wrap-and-drop, so whenever its own
   preferred width (up to ~564px on a long name) plus the fixed avatar
   leaves less than that for the name/meta column, the column gets
   squeezed toward 0 instead of the actions dropping to their own line.
   `flex-wrap: wrap` on `.cc-phead` (unconditional — no breakpoint to
   mistune, matches the acct- fixes' container-driven approach) is half of
   this: flex-wrap only forces an item to a new line once the row's
   MINIMUM combined size exceeds the container, and the info column's
   minimum was `min-width: 0` (an inline style) — meaning the row always
   "fit" by squeezing that column toward zero instead, so wrap never
   triggered. The other half: the info column (now a real class,
   `cc-phead-info`, previously an inline `style={{minWidth:0,flex:1}}`
   with no class to target) gets a real `min-width` floor instead of 0 —
   once the row can't honor BOTH that floor and pactions' natural width,
   flex-wrap correctly drops pactions to its own line instead of
   collapsing the name column toward nothing. Verified across the full
   claimed range plus the wider worst-case-name span this actually
   reaches: 320/836/900/1080/1320px — wraps exactly where the row doesn't
   fit, stays single-row (unchanged) at 1320px where it does.
   (b) ≤640px: .cc-phead switches to flex-direction:column — the info
   column's cross-axis (width) isn't governed by flex:1 in column mode
   (that only sizes the main/vertical axis there), so it needs its own
   width:100% for this axis, same class hook as (a).
   (c) ≤640px: `.cc-pmeta > span` is unconditionally forced `white-space:
   nowrap` (~app.css:1395, so short chips like "5.00" or "15 yrs · 89
   gigs" wrap as one atomic unit, not character-by-character) — correct
   for short chips, but a genuinely long single-line value (a long home-
   market/venue name) had nothing to clip it, so nowrap alone just pushed
   it 479px wide in a 210px column. Capping it to the container and
   finishing the enclosure quartet (already had min-width:0 + nowrap; adds
   max-width/overflow/ellipsis) turns "too long to fit" into a clean
   single-line truncation instead of an escape. */
.cc-phead { flex-wrap: wrap; }
.cc-phead-info { flex: 1; min-width: 200px; }
@media (max-width: 640px) {
  .cc-phead-info { width: 100%; min-width: 0; }
  .cc-pmeta > span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
}
/* Same page, same 320px pass, one more instance of the identical disease
   directly below the header: the "Home market" stat cell's plain-text
   value has no enclosure floor either (unlike the sibling "Works as local
   in" pill list, .cc-mkt, fixed in (6) below) — a worst-case long single-
   line market/venue name escaped its .cc-cell by 12px. Found while
   verifying (4) at 320px, not separately named in the sweep, but same
   root cause + same file + trivial to complete: max-width lets it re-wrap
   inside the real column instead of overhanging. */
.cc-cell .v { max-width: 100%; overflow-wrap: break-word; }

/* 5) Applicants list, 700-900px, worst-case unicode names — .cc-app-main
   already had min-width:0 (it's the flex-shrinkable column), but
   .cc-app-nm/.cc-app-sub themselves carried no enclosure floor at all, so
   a multi-word unbreakable-ish name (Cyrillic, no ASCII hyphenation
   opportunities the layout could use) wrapped word-by-word and still
   escaped a column as narrow as 77-93px at this range (avatar + the
   Book/status actions cluster leave that little once a long name is in
   play). Completes the quartet on the two text rows plus a clipping
   boundary on their container; verified with the harness's own tile-
   overflow predicate (skips anything whose computed overflow-x isn't
   'visible') — zero findings across the applicants list post-fix. */
.cc-app-main { overflow: hidden; }
.cc-appl .cc-app-nm, .cc-appl .cc-app-sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* 6) /me, 320px, two unrelated minor (3-5px) escapes: (a) the feed post-
   byline's name/role-time stack (views.js cc-post-head .nm/.mt) had no
   enclosure floor at all, unlike every OTHER .nm in the app (chip/dock/
   scene-switcher/thread-header/chatdock all already clip+ellipsis) — this
   one was just missed; (b) a "Works as local in" market pill (.cc-mkt)
   auto-sizes to its own longest wrapped line, which can land a hair wider
   than its .cc-cell column (measured 84.875 vs 80px) since nothing caps
   the pill's own box — max-width:100% lets it re-wrap fully inside the
   real column instead of overhanging by a few px (verified: reads as a
   clean 3-line "Los / Angeles, / CA" stack, not a mid-word break). */
.cc-post-head .nm, .cc-post-head .mt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-mkt { max-width: 100%; }

/* 7) Settings → Invite a collaborator, 320px: the read-only link input's
   min-width:220px floor is 10px wider than the row's actual available
   width (210px) at this breakpoint; flex-wrap on the row can't rescue an
   item that's wider than the whole container even alone on its own line.
   It's a read-only display field (not a typing target), so shrinking
   further on phones costs nothing — min-width:0 lets flex:1 take exactly
   what's left. */
@media (max-width: 640px) {
  .cc-setts-invrow .cc-input { min-width: 0; }
}
/* ═══ end VALIDATION-SWEEP FIX ROUND (Lane A) ═══ */

/* ═══ SWEEP ROUND 2 (fable-kit-audit, 2026-07-30, fix/sweep-320-round2) —
   320px cluster from the shard-A/B rerun. Re-verified each against a fresh
   origin/master boot with npm run validate:seed + scripts/matrix-run.js
   before touching anything; 2 of the 4 findings no longer reproduced (see
   below) — not "fixed here", just confirmed already fixed by #310/#311 and
   left untouched. ═══ */

/* 1) /jobs, /gigs, /gigs/c/:id board cards (ARTICLE.cc-ngc), 320px: the
   worst-case rate RANGE ("$99,999–999,999/day") is long enough that
   .cc-ngc-side (flex-shrink:0, holds the "Xh ago" stamp + the rate chip)
   can't fit next to .cc-ngc-id (name/byline) even after id is squeezed to
   its floor (min-width:0) — id disappears to 0px and the row STILL doesn't
   have room, so the rate chip's own text (nowrap by design — .cc-money
   never breaks mid-number, same rule as everywhere else in the app) pokes
   past the card's padding box (measured 262-287 > 242 depending on how
   long the specific worst-case rate string is; the page-level header
   overflow is the same disease one level up — .cc-ngc-top's own
   scrollWidth > clientWidth). This is the same class of bug as the /u/:id
   .cc-phead fix above (an always-flex-shrink:0 sibling with no wrap
   fallback) — same container-driven fix: let the header wrap when (and
   only when) the two halves don't fit together, at any width, no
   breakpoint to mistune. Giving .cc-ngc-id a real min-width (instead of 0)
   is what makes flex-wrap actually trigger at the right threshold rather
   than the id column just collapsing toward nothing first (identical
   reasoning to .cc-phead-info). Verified: short/typical rates ($500-600,
   $900) stay on one line unchanged at every width tested (320-1440); only
   the genuinely-long worst-case ranges drop the rate chip to its own row,
   fully inside the card, nothing escaping. margin-left:auto keeps the chip
   flush right on its own line, matching its flush-right position in the
   single-line case (there it's flush right because id's flex:1 already
   eats the leftover space — margin-left:auto is a no-op there, and only
   does work once the chip is alone on its own flex line). */
.cc-ngc-top { flex-wrap: wrap; row-gap: 6px; }
.cc-ngc-id { min-width: 140px; }
.cc-ngc-side { margin-left: auto; }

/* 2) DIV.cc-row.cc-gigrow title cell, 320px, SHARED GigRow component
   (public/app/views.js — one function, rendered on both /manage's "Your
   applicants" section and the /events/:id open-gigs list via EventPanel;
   fixing the shared class fixes both call sites at once, verified on both
   below). Root cause: .cc-rtag (the small role-name pill, e.g. "Monitor
   Engineer") is white-space:nowrap with overflow:visible and no enclosure
   floor — its automatic flex min-width resolves to its own full
   min-content size (per spec, ONLY overflow:hidden/clip/scroll makes a
   flex item's auto min-width resolve to 0; nowrap+visible keeps it
   content-based), so it refuses to shrink. .cc-ttl (the title) sits right
   next to it in the same .cc-l1 row and DOES already carry the full
   enclosure quartet, so on ordinary gigs (single, even fairly long, role
   names — "Practical Electrician", "Follow Spot Operator") .cc-ttl alone
   absorbs the squeeze and the row already fits, un-clipped, on origin/
   master today. The bug only shows up on the worst-case multi-role string
   ("Lighting Designer / Video Director / FOH", 3 roles concatenated into
   one role_needed field, 484px min-content) — long enough that even a
   fully-collapsed .cc-ttl isn't enough and the pill alone drags the whole
   row (and DIV.cc-row.cc-gigrow with it — .cc-lead/.cc-l1 are proper
   flex:1/min-width:0 already, they were just carrying an unshrinkable
   sibling) 260px past its 242-260px column (502>242 measured on /manage,
   reproduced identically on /events/:id).

   First attempt gave .cc-rtag the same min-width:0/overflow:hidden
   quartet .cc-app-nm etc. got above — WRONG for this element: with the
   automatic min-width now 0, flexbox split the shrink deficit between
   .cc-rtag and .cc-ttl on EVERY row where the two don't both fit at their
   natural size (i.e. most rows at 320px, not just the pathological one),
   so ordinary tags like "Monitor Engineer" got crushed to ~50px instead
   of rendering full-size the way they do today — a real regression traded
   for a rare-string fix. What's actually needed is a CEILING, not
   shrinkability: keep flex-shrink:0 (unchanged — a normal role tag is
   exactly as rigid as before, byte-identical rendering) and add a
   container-relative max-width so only content that would have exceeded
   the row anyway gets capped. `calc(100% - 24px)` reserves 24px (9px gap
   + a legible sliver for .cc-ttl, which can still ellipsis down from
   there) out of .cc-l1's own width — scales with whatever width .cc-l1
   actually has at any viewport (container-driven, not a hand-picked
   breakpoint), and guarantees .cc-rtag alone can never be wide enough to
   push .cc-row past its column, at any width. Verified: every real
   single-role tag in the worst-case seed (up to 157px, "Practical
   Electrician") renders at its full natural width, unclipped, at every
   width tested (320-1440px) — none reaches the cap; only the 484px
   concatenated-role monster actually triggers the ellipsis. */
.cc-rtag { max-width: calc(100% - 24px); flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; }

/* 3) Event page crew-search rows (EventCrewSearch, hiring persona,
   /events/:id), 320px: DIV.cc-row / .cc-lead / .cc-l1 escaping their tile
   (measured .cc-lead 192>172, .cc-row 208>204 on a name+role combo; up to
   264>172 / 280>204 on the worst unicode names). Related to (2) — .cc-rtag
   is one of the culprits here too — but NOT fully closed by (2) alone:
   this row packs up to FOUR items into the same .cc-l1 (.cc-ttl name,
   .cc-rtag role, plus one or two .cc-lz status badges — "Credentialed",
   "Wants work" — that GigRow's row never has). .cc-lz has no enclosure
   floor at all (no white-space/overflow rule of its own), so like .cc-rtag
   pre-fix it's effectively rigid at its natural size; with TWO rigid
   siblings (.cc-rtag capped-but-still-real-width + .cc-lz uncapped) plus
   the name, their combined minimum (both badges alone, ignoring .cc-ttl
   which can shrink to 0) already exceeds the 172px column on a two-word
   role + "Credentialed" — a max-width squeeze on .cc-lz too would start
   truncating short structured labels ("Credentialed" → "Creden…"), worse
   than the multi-role-pill case in (2) because these are fixed vocabulary
   words, not free text, and mid-word ellipsis on a status badge reads as
   broken rather than intentionally-condensed. Wrap instead: flex-wrap on
   .cc-l1 (container-driven, same technique as .cc-ngc-top in (1) and
   .cc-phead elsewhere in this file) lets the role pill and status badge(s)
   drop to their own line under the name whenever they don't all fit
   together, at any width — every label stays fully readable, nothing
   truncated, nothing escapes. Verified across the full worst-case
   attendee list (14 rows incl. Cyrillic/CJK/Vietnamese/Icelandic names +
   both credentialed and wants-work badges) at 320px, both fonts, both
   themes: 0 rows with .cc-row/.cc-lead/.cc-l1 scrollWidth > clientWidth. */
.cc-l1 { flex-wrap: wrap; row-gap: 4px; }

/* NOT reproduced on a fresh origin/master boot — already fixed upstream,
   confirmed via direct CDP measurement (getBoundingClientRect/scrollWidth)
   before writing anything: */
/* - BUTTON.cc-disc-go 66>57 (the /jobs and /gigs board search pill "go"
     button at 320px): the mobile "hero" search bar already renders
     full-width (.cc-disc-go::after { content:'Search' }, width:100%) at
     this width with no icon-only circle at all — 0 overflow, both themes,
     both fonts. Whatever produced 66>57 predates the extensive
     .cc-disc-go mobile rework already in this file (search app.css for
     "OCBAR STACKED-DIVIDER" and the several "MOBILE FIX PASS" blocks
     above touching .cc-disc-go). */
/* - A.cc-post-author 118>105 (/home, feed post byline) at 320px: matches
     the board note this may already be fixed by #311's ".cc-post-head .nm,
     .mt" quartet fix a few sections up in this same file — confirmed via
     direct measurement of every .cc-post-author node on a worst-case /home
     feed (14 posts, unicode + long names/roles): scrollWidth === clientWidth
     on every single one. */
/* ═══ end SWEEP ROUND 2 ═══ */

/* ═══════════════════════════════════════════════════════════════════════
   2026-07-30 — pre-existing 320px/768px overflow cluster (matrix-run
   findings that predate the sweep-320-round2 branch; confirmed on a fresh
   origin/master checkout). Root causes + fixes, all house enclosure
   contract (min-width:0 / overflow:hidden / ellipsis / nowrap on flexible
   text, flex-shrink:0 on icons, container-driven geometry, literals):

   1) /estimates/new, /invoices/new, /invoices/:id/edit @320: DIV.acct-
      editor-toprow + DIV.cc-field tile-h-overflow 240>198. Root cause:
      .acct-clientpicker carried a flat min-width:240px — wider than the
      198px the editor card offers at 320. Fix: min-width:min(240px,100%)
      + max-width:100% — keeps the desktop floor, caps at the field.
   2) /pnl @320/font-20: .acct-cardtotal 214>198. "Income total" +
      "$249,999.50" (unbreakable cc-num token) can't share 198px at font
      20. Fix: flex-wrap:wrap on the row + margin-left:auto on the .cc-num
      so the amount drops to its own line and stays right-aligned.
   3) /me + /settings @320: SPAN.cap 65>63 and (render-timing variant)
      .cc-maxw.cc-prof page-h-overflow 299>244. TWO causes, one page:
      (a) the mobile .cc-pcols/.cc-gd collapse used grid-template-columns:
      1fr — 1fr = minmax(auto,1fr), so one rigid descendant (a .cc-ev-chip
      whose worst-case event name holds the unbreakable token
      "FOH/Monitor/Lighting/Video") set a 299px min-content floor for the
      whole column and pushed the page 55px past the viewport. Fix:
      minmax(0,1fr) (same app-wide pattern as the 2026-07-29 .cc-field-row
      fix) + chip enclosure (max-width:100%, min-width:0, ellipsis quartet
      on the name span, flex-shrink:0 on the icon + .cred badge). The
      .cc-evhop rail chips are exempted (max-width:none) — that rail is a
      horizontal scroller by design, its chips hold bare text nodes, and
      capping them made the nowrap text escape the button instead.
      (b) .cc-tile .cap ("Coachella" in a 63px 3-col gallery tile): the
      caption word's min-content exceeds the tile even though .cc-tile
      clips visually — scrollWidth still counts it. Fix: overflow-wrap:
      anywhere on the cap (shared with the Settings portfolio editor, so
      one fix covers both routes). Long words now break; normal captions
      render unchanged.
   4) /support @320: .cc-support-rows/.cc-support-row 213>198. The
      support@callsheet.gg mailto link is a 142px unbreakable token next
      to a 57px label + 14px gap. Fix: min-width:0 + overflow-wrap:
      anywhere on .cc-support-row a / .cc-support-mail — NOT the ellipsis
      quartet: truncating an email address hides the one thing the row
      exists to show, and the text-box contract flags clipped controls
      (scrollWidth > clientWidth) even when ellipsized. Wrapping keeps the
      full address readable and collapses the min-content floor.
   5) /invoices/:id/edit @768: .acct-line-amt 90>88 (font 16) and
      .acct-lines/.acct-line 652>646 (font 20). The desktop .acct-line
      grid's amount track was a flat 88px — "$4,999.99" needs 90px at
      font 16 and more at font 20, while every other track scaled with
      the font. Fix: minmax(88px,max-content) — the fr name column
      (already minmax(0,…)) absorbs the difference.
   Verified: node scripts/matrix-run.js over every touched route (plus
   /home + /events, which share .cc-ev-chip) × 320/375/768 × font 16/20 ×
   both themes — zero findings.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════
   INVOICE 641-1180 SQUEEZE (2026-07-30, fable-inv1080 — the chip #318's
   gate spawned: /invoices/wc_invoice_1 @1080 matrix residuals)

   Two pre-existing findings, one shared disease: the 901-1180px single-
   column accounting layout hands its content column 420-550px of real
   width, and two invoice surfaces have no floor for that range — only
   the ≤640px ACCT MOBILE R5 rules (viewport-based, per #307's documented
   known gap) or nothing at all.

   1) InvoiceDetail .acct-doc-frame (tile-h-overflow 570>478 @1080/f16,
      + its anonymous doc-root child, same numbers): the base rule's
      width:100% squeezes the fixed-canvas print doc (min-content ≈602px
      on worst-case data) into a 422-548px stage at 1024-1150px, so the
      doc's unbreakable internals escape the frame. R5 already floors the
      frame ≤640 (width:auto; min-width:760px — full natural canvas);
      641-1279px had no floor. min-content (not 760px) keeps every width
      where the doc already fits — 1280 (fits at 678) and up — byte-
      identical, and lets tame invoices never pan at all; when squeezed,
      the frame floors at the doc's own minimum and pans inside
      .acct-doc-stage's existing overflow-x:auto (the R5 mechanism).
      Scoped ≥641 so R5's stronger 760px mobile floor stays the owner
      below (this block appends after R5 and would out-cascade it).

   2) Invoice/estimate editor .acct-line (.cc-combo.cc-rolepick 28>24
      @1080/f20 — and measured down to a 0px role column @1024, plus the
      whole editor chain escaping at 900px: .acct-line 416>298 propagates
      up through acct-editor-wrap/cc-maxw/cc-body on all three editor
      routes): the 6-col grid's fixed+max-content tracks (~418-460px +
      gaps) leave the only shrinkable track — the role NAME,
      minmax(0,1.6fr) — absorbing the whole deficit, and below ~420px of
      container the grid's own minimum overflows the card. The R5 stacked
      grid-areas layout is the canon answer, but its ≤640 viewport
      trigger can't see the 901-1180px single-col form (#307: "stack
      rule is viewport-based"). Fix the TRIGGER, not the layout:
      .acct-lines becomes a size container and the same R5 stack applies
      whenever the rows' actual container is too narrow for six-across
      (560px = just under the 2-col layout's ~576px line floor, so
      ≥1181px never changes; the 6-col minimum with a usable name column
      is ~574px per #307). First @container in this file — viewport
      proxies for this exact range have now failed twice (#307's gap,
      this chip), and the query measures container width directly. The
      RolePicker dropdown anchors to .cc-combo's own position:relative,
      so the new containment context does not re-parent it. nth-child
      areas mirror R5 verbatim; the remove button keeps its plain size
      ≥641 (R5's tap-target padding trick stays mobile-only, cascade
      untouched — this block declares only grid-area + justify-self
      for it). ── */
@media (min-width: 641px) {
  .acct-doc-frame { min-width: min-content; }

  .acct-lines { container-type: inline-size; }
  @container (max-width: 560px) {
    .acct-line {
      grid-template-columns: 1fr 1fr;
      grid-template-areas:
        "name name"
        "cat cat"
        "qty price"
        "amt del";
      row-gap: 8px;
      column-gap: 8px;
      padding-bottom: 12px;
      border-bottom: 1px solid var(--cc-line);
    }
    .acct-lines { gap: 4px; }
    .acct-line > *:nth-child(1) { grid-area: name; }
    .acct-line > *:nth-child(2) { grid-area: cat; }
    .acct-line > *:nth-child(3) { grid-area: qty; }
    .acct-line > *:nth-child(4) { grid-area: price; }
    .acct-line > *:nth-child(5) { grid-area: amt; }
    .acct-line > *:nth-child(6) { grid-area: del; justify-self: end; }
  }
}
/* ═══ end INVOICE 641-1180 SQUEEZE ═══ */

/* ═══════════════════════════════════════════════════════════════════════
   2026-07-30 — SWEEP ROUND 3 (fable-residual-sweep, fix/sweep-residuals-
   round3): the residual findings #311's board row flagged as pre-existing,
   root-caused via full-load CDP measurement + A/B against the unmodified
   tip. (The third residual on that list — /me + /settings SPAN.cap 65>63 —
   was fixed upstream by #313's .cc-tile .cap overflow-wrap:anywhere while
   this round was in diagnosis; not re-touched here.)

   1) /vouch/:id — .cc-phead 235>198 @320. Same profile-header family #311
      fixed on /u/:id, one route over: the vouch card's header still had
      the pre-#311 shape (an inline minWidth:0 div with no class). At
      ≤640px the legacy stack block (~app.css:1379) turns .cc-phead into
      flex-direction:column + align-items:flex-start, and a column child
      that isn't stretched sizes to fit-content — whose floor is its
      MIN-CONTENT. The worst-case claim title holds the unbreakable token
      "FOH/Monitor/Lighting/Video" (slashes are not break opportunities),
      so the info div's min-content is 209px inside a 198px header:
      measured 235>198 with the div at exactly 209px, avatar squeezed.
      Fix, mirroring #311: the div now carries the real .cc-phead-info
      class (views.js) so it gets the same row-mode flex:1 + 200px floor
      and ≤640px width:100% + min-width:0 the /u/:id header got — plus
      overflow-wrap:anywhere on the two text lines (the #313 precedent for
      unbreakable-token wraps: the title IS the content on this page, so
      it wraps rather than truncates; normal titles render unchanged).
      Scoped to the vouch/verification card so profile headers (which have
      their own #311 treatment) keep their exact behavior. */
.cc-verify-hub .cc-phead-info h3, .cc-verify-hub .cc-phead-info .muted { overflow-wrap: anywhere; }

/* 2) /home — .cc-hcard.cc-jobpost h-overflow 218>207 @1150, escape text
      "just now". NOT static geometry: at 1150px the feed column is 514px
      and nothing overflows. The 1080px breakpoint flip (stacked home →
      side-by-side) animates the rail's width (.cc-home-rail
      { transition: width .26s }, ~app.css:5155), and for those 260ms the
      feed column (flex:1 min-width:0) passes through arbitrarily narrow
      widths — matrix-run scans 70ms after resize and caught the card at
      a transient 207px; real users see the same flash when a resize/
      rotate crosses the breakpoint. In any container narrower than the
      head's min-content, .cc-jobpost-head (a nowrap flex row whose
      timestamp+rate cluster is flex-shrink:0 by design — .cc-jobpost-side)
      pushes the cluster past the card edge instead of giving it its own
      line. "just now" is simply the widest timeAgo string (rendered only
      within a minute of a row's creation — why the finding was seed-
      adjacent and looked timestamp-driven). Fix: let the head wrap —
      identical reasoning to #312's .cc-ngc-top{flex-wrap:wrap} on
      BoardGigCard, the row this header deliberately mirrors. At every
      steady-state width the row fits on one line and renders
      byte-identically; only a genuinely too-narrow container (transition
      frames today, any future narrow slot) drops the ago/rate cluster to
      its own line instead of escaping the card.
      The wrap alone is not sufficient for the transition frames, though:
      re-running the sweep kept catching OTHER card internals at the
      transient widths (a role chip at 207px, the head cluster at 145px —
      each frame of a 260ms squeeze exposes whatever atom happens not to
      fit that instant, and no amount of per-atom enclosure can make a
      36px avatar fit a 32px box). The card-level truth: nothing may ever
      paint outside a feed card — steady-state nothing does (ladder-
      verified 320-1280), so clipping the card's x-axis is byte-identical
      at rest and turns the mid-animation escape into a clean truncation
      at the card edge instead of text painting over the rail. clip (not
      hidden): no scroll container, no programmatic-scroll surprises.
      Scoped to .cc-jobpost (FeedGigCard + the availability card that
      reuses its classes) — NOT all .cc-hcard: post cards can grow
      popover-ish children and weren't part of any finding.
      Third atom, found by constraining a live card to the scanned 207px:
      the composed title (.cc-jobpost-ttl) holds the card's min-content at
      230px — the worst-case role string's longest unbreakable run
      measures 198px + 32px card padding (card scrollWidth 214 == 16 +
      198 exactly), and the card is a role=button control, so the
      button-box contract counts clipped content too — the clip alone
      can't clear it. overflow-wrap:anywhere (the #313 precedent for
      unbreakable tokens) collapses the title's min-content; at every
      width the title actually fits (steady-state 320-1560) it renders
      byte-identically, and in a genuinely narrower box it wraps mid-token
      instead of holding the card open. */
.cc-jobpost-head { flex-wrap: wrap; }
.cc-jobpost { overflow-x: clip; }
.cc-jobpost-ttl { overflow-wrap: anywhere; }

/* 3) Skeleton width cap — closing the class behind /me's intermittent
      .cc-maxw.cc-prof page-h-overflow 299>244 @320 (matrix-recorded on
      2e74edb, "only when the scan beats the load"; #313 fixed the
      steady-state .cc-ev-chip driver of the same signature, and with a
      held profile fetch the loading state now measures clean on this
      tip). What structurally remains of the class: Sk placeholders carry
      fixed inline px widths with no container cap — e.g. the 250px
      header bar (views.js ~9309) inside cards that offer 244px at 320px
      — so any skeleton composed wider than its slot escapes exactly the
      way real content can't (real text is enclosure-capped). Some call
      sites already hand-patch this with an inline maxWidth:'100%' (the
      /home head skeleton, views.js ~4624) — the tell that the floor
      belongs on the class. Skeletons in a too-narrow container now
      shrink to fit; steady-state rendering is byte-identical (the cap
      only bites where the fixed width already didn't fit). */
.cc-skel { max-width: 100%; }
/* ═══ end SWEEP ROUND 3 ═══ */

/* ═══════════════════════════════════════════════════════════════════════
   2026-07-30 — SWEEP ROUND 4 (fable-ngc-cluster, fix/board-collapse-
   cluster): chip task_87eae8b7 — the board split-collapse-animation
   cluster (/jobs, /browse, /gigs, /gigs/c/:id @320: ARTICLE.cc-ngc
   h-overflow 236>178 escaping "$99,999–999,999" / "/day"; BUTTON.
   cc-disc-go 66>57) + the /settings work-history rows. All pre-existing,
   git-stash A/B'd on c311544 by the 2026-07-30 full sweep.

   1) Board cards (ARTICLE.cc-ngc — a role=button control; the button-box
      contract counts everything, clipped or not). NOT static geometry:
      at a settled 320px the card is ~244px and holds. Each matrix route
      mounts at the previous route's last width (1150), the width loop
      then sets 320, and the #205 Finder-split collapse animates
      .cc-split2-list's flex-basis 48%→100% over 420ms — of the NEW
      ~288px container — so for those frames the feed passes through
      ~120-190px transient widths; the scan lands 70ms in. Real users
      see the same flash when a resize crosses the 980px breakpoint.
      Measured on a live card width-constrained to the scanned widths
      (the #314 method), the card's min-content pinned at 236 held by
      three atoms, each fixed container-driven (no breakpoint):
      – .cc-ngc-side (row, flex-shrink:0, auto basis) is an unbreakable
        220px unit ("36m ago" + the rate chip): a width cap makes the
        line width its ceiling, flex-wrap lets ago/rate stack only when
        that ceiling bites, and margin-left:auto keeps the money right-
        aligned on its own wrapped line (#313's P&L-total treatment).
        At rest the side is fit-content and always narrower than its
        line, so all three are inert (rect-diffed IDENTICAL at 768/1280;
        at 320 only the pathological $99,999–999,999 seed card changes —
        its chip previously sat 13px deep into the card's right padding).
      – .cc-ngc-rate .cc-money is white-space:nowrap (base .cc-money),
        so "$99,999–999,999" is a 146px unbreakable run — the escape
        text the sweep recorded. Board-card-scoped (NOT global .cc-money
        — invoices/rails/gig-detail keep theirs): normal + overflow-wrap:
        anywhere collapses its min-content; anywhere it fits it renders
        on one line, byte-identical.
      – .cc-ngc-ttl: the airy-pass title is a normal wrapping block with
        overflow:visible, and the worst-case title holds the unbreakable
        214px run "FOH/Monitor/Lighting/Video…" (slashes are not break
        opportunities) — same disease/fix as #314's .cc-jobpost-ttl and
        #313's support emails: the title is the content, wrap not
        truncate; ordinary titles break at spaces, byte-identical.
      – .cc-ngc-id's #312 floor (min-width:140px) is container-blind: at
        transient widths under ~187px the avatar+id line itself escapes.
        min(140px,100%) keeps the exact 140px floor at every real width
        (the floor only yields inside a container smaller than itself).
      – .cc-ngc overflow-x:clip: nothing may ever paint outside a feed
        card. The wrap atoms are what clear the counted overflow (clip
        does NOT zero scrollWidth in Chrome — measured, confirming
        #314's note); the clip covers the frames no per-atom enclosure
        can (a 38px avatar can't fit a 32px box), turning them into
        clean truncation instead of ink over the neighbor column. */
.cc-ngc-id { min-width: min(140px, 100%); }
.cc-ngc-side { flex-wrap: wrap; max-width: 100%; }
.cc-ngc-side .cc-ngc-rate { margin-left: auto; }
.cc-ngc-rate .cc-money { white-space: normal; overflow-wrap: anywhere; }
.cc-ngc-ttl { overflow-wrap: anywhere; }
.cc-ngc { overflow-x: clip; }

/* 2) BUTTON.cc-disc-go 66>57 (68>61 hero variant): the dock↔hero morph
      transition (~6201) rides on state classes whose property deltas
      exist ONLY inside @media (min-width:981px) ("the enlargement only
      makes sense where there's room — desktop", its own comment), but
      the transition list itself is unscoped. So at ≤980px the ONLY
      thing it can ever animate is a breakpoint flip: on a 1150→320
      crossing, width animates 46-50px→100% while the ≤760 ::after
      'Search' label applies instantly (content is not transitionable) —
      66px of label in a ~57px mid-frame box. No wrap can fix a fixed-
      vocabulary button label; the fix is that breakpoint flips SNAP.
      Same reasoning for the #205 split collapse: at ≤980 the detail
      panel is display:none and flex-basis is pinned 100% — the 420ms
      transition has nothing legitimate to animate below the breakpoint,
      and killing it there removes the very squeeze that produced the
      card findings above (the enclosure atoms in (1) remain the durable
      contract for any future narrow slot). Desktop behavior — both
      morphs AND the collapse — is byte-identical: these rules exist
      only below 981px, where the states they'd animate don't. */
@media (max-width: 980px) {
  .cc-jobs .cc-ocbar,
  .cc-jobs .cc-ocdisc .cc-disc,
  .cc-jobs .cc-ocdisc .cc-disc-seg,
  .cc-jobs .cc-ocdisc .cc-disc-seg .lbl,
  .cc-jobs .cc-ocdisc .cc-disc-seg input,
  .cc-jobs .cc-ocdisc .cc-disc-go { transition: none; }
  .cc-boardsplit > .cc-split2-list { transition: none; }
}

/* 3) /settings work-history rows (.cc-tl-item 211>204 / .cc-tl-head
      191>184 @320, 217>210 @font-20) — steady-state, reproduced live
      (the filtered matrix can miss it: Settings loads credits async,
      the #312-documented scan race). The .tt title line holds the same
      unbreakable worst-case claim-title run as (1)'s ttl inside a 184px
      head; .cc-tl-head already flex-wraps (~app.css:6913), the
      title just can't break. Deduped vs #312's chip: #313 (that chip's
      PR) touched no .cc-tl selector. Covers both call sites (Settings
      editor rows + the profile/vouch WorkHistoryRow — .tt is the shared
      class); the .cc-rtag pill inside .tt is nowrap, so inherited
      overflow-wrap is inert on it; ordinary titles break at spaces,
      byte-identical. Wrap, not ellipsis: the title is the content
      (#313's support-email precedent). */
.cc-tl-item .tt { overflow-wrap: anywhere; }
/* ═══ end SWEEP ROUND 4 ═══ */

/* ═══════════════════════════════════════════════════════════════════════
   2026-07-31 — TOUR PNAME OVERFLOW FIX (fix/tour-pname-overflow-320):
   /tour/:id @320px — DIV.cc-pname page-h-overflow 32px past viewport,
   widest offender scrollWidth 295>206 (canonical wc_tour_1 seed name,
   views.js ~10849). Live-measured (getBoundingClientRect, not just the
   scan): .cc-pname itself is a plain block child of .cc-tourd-card (not a
   flex item — its own box already sizes correctly to the card's 206px
   inner column). The escape is its DIRECT flex child, the <h1> — a flex
   item's default min-width:auto floors it at min-content, and for wrapping
   text that floor is the width of the longest run with NO break
   opportunity, not the full-line width. This seed title carries the same
   "FOH/Monitor/Lighting/Video" unbreakable run SWEEP ROUND 4 already
   named for .cc-ngc-ttl / .cc-tl-item .tt above (slashes are not break
   opportunities) — here it's ~295px, wider than the 206px column, so the
   <h1> refuses to shrink below it and the extra 89px bleeds past the
   card (32px of that past the viewport itself; body.scrollWidth 352 vs
   window.innerWidth 320 — document.scrollWidth undercounts this one,
   confirmed live, which is why the check sums max(doc,body) - innerWidth).
   Same disease as that round, same fix, scoped to the tour hero only
   (.cc-tourd, matching the existing desktop .cc-tourd .cc-pname h1 font
   rule in app.redesign.css) — NOT a general .cc-pname change, the other
   six call sites (profile/admin/settings headers) are untouched. min-
   width:0 unlocks the flex-shrink SWEEP ROUND 4's flex-wrap alone can't
   provide; overflow-wrap:anywhere then lets the unbreakable run itself
   break once shrunk narrower than it. Ordinary tour names already fit
   206px and never hit either property — byte-identical there, and inert
   above 640px where the two-column layout gives the hero far more room
   than any real title needs. (Note for anyone re-running the full
   matrix/golden sweep: this route's async CC.data.tour() fetch can lose
   the race against a 47-route sweep's fixed per-route wait budget the
   same way #312 documented for /settings — a route-filtered rerun
   (`node scripts/matrix-run.js --routes=/tour --widths=320`) reproduces
   it reliably where the full sweep can go quiet; not this fix's bug, a
   pre-existing scan-timing gap in the harness itself.) */
@media (max-width: 640px) {
  .cc-tourd .cc-pname { min-width: 0; }
  .cc-tourd .cc-pname h1 { min-width: 0; overflow-wrap: anywhere; }
}
/* ═══ end TOUR PNAME OVERFLOW FIX ═══ */

/* ═══════════════════════════════════════════════════════════════════════
   2026-07-31 — /artist, /org, /u ORG-ARTIST + LOCKED PROFILE HEADER
   OVERFLOW (fix/mobile-overflow-cluster):
   /artist/:id @320px, hiring persona — DIV.cc-phead tile-h-overflow
   494>242 (escapes its .cc-phead-card), live-measured 494 scrollWidth vs
   318 clientWidth at the page level (getBoundingClientRect; the probe's
   242 is the same escape measured relative to the card's own inner
   column). Confirmed deterministic on a single-route rerun
   (`node scripts/matrix-run.js --routes=/artist --widths=320`); only
   shows up when /artist runs ALONE or with a couple of siblings — folded
   into the routes=/artist,/org,/u,/gigs,/events,/crew,/tour combined
   sweep, it goes quiet 2/2 tries. Root-caused live: with only /artist
   filtered the miss vanishes and the 494>242 finding is 12/12 — this
   route's CC.data.profile() fetch loses the fixed-budget scan race the
   same way #312 already documented for /settings and the TOUR PNAME fix
   above documented for /tour; NOT a flake, a pre-existing harness gap
   that widens with sweep size — confirmed by re-running the 7-route
   combined filter twice more (0/0) immediately after the isolated
   route's 12/12. Route-filtered single-route reruns are the only
   reliable read for this route; treat a same-sweep miss as inconclusive,
   not "clean."

   Root cause: CC.views.Profile's non-freelancer branches — LockedProfile
   (guest teaser, ~views.js:2056) and OrgArtistProfile (~views.js:2746) —
   both lay out their name/meta column as a bare `<div style={{minWidth:
   0}}>` direct child of `.cc-phead`, NOT the real `.cc-phead-info` class
   the #311 fix (section 4 above) gave CrewProfile. `.cc-phead-info`'s
   own `{ width: 100%; min-width: 0 }` ≤640px rule (and the `.cc-pmeta >
   span` ellipsis-enclosure rule chained to it) never reaches these two
   siblings, because they carry no class for that selector to hook —
   inline minWidth:0 alone shrinks the flex item but never gives it the
   100%-of-container WIDTH that lets `.cc-pmeta > span`'s max-width:100%
   resolve against something narrow enough to matter. The seeded
   worst-case city (`p.city`, a single long hyphenated/spaced run) sits
   in a `.cc-pmeta > span` forced `white-space:nowrap` (~app.css:1395,
   same mobile chip rule (c) in section 4 documents) — with the
   container never shrunk, that nowrap span pushes the whole `.cc-phead`
   row out to its natural width (494px) instead of truncating.
   `/org/:id` renders the identical OrgArtistProfile component — same
   defect, just not independently confirmed by this sweep because the
   only /org sample (`org_wasserman`, a real seeded persona, not a
   worst-case row) has an ordinary short city and never reaches the
   overflow threshold; fixed here anyway since it's the same component,
   same missing class, zero extra risk. `/u/:id` is unaffected (it's
   CrewProfile, already fixed under #311).

   Fix: give BOTH bare info-column divs the same ≤640px enclosure
   `.cc-phead-info` already has, scoped via the existing `.cc-prof`
   wrapper both profile pages already render inside (matches how
   app.redesign.css:1354/1496-97 already scope `.cc-prof .cc-pname
   h1`/`.cc-prof .cc-phead` for this exact page family) and targeted
   structurally (`:not([class])`) so ONLY the classless info column is
   touched — `.cc-av-lg`/`.cc-avatar`/`.cc-pactions`/`.cc-phead-info`
   all carry a class and are unaffected. This is additive only: no
   existing `.cc-prof` rule changes, `.cc-phead-info`'s own styling is
   untouched, and the SkelGroup loading skeleton's identical bare-div
   shape (~views.js:2013) picks up the same harmless width:100% (its
   fixed-px Sk bars already fit). Verified: `.cc-phead` scrollWidth ==
   clientWidth (318) at 320px/hiring on /artist post-fix; desktop
   untouched (media-gated, and .cc-phead-info's own desktop `flex:1;
   min-width:200px` was never targeted). */
@media (max-width: 640px) {
  .cc-prof .cc-phead > div:not([class]) { width: 100%; min-width: 0; }
}
/* ═══ end ORG-ARTIST + LOCKED PROFILE HEADER OVERFLOW FIX ═══ */
