/* =========================================================================
   121 Brokers CRM — component library
   Built from mockup 6a (.claude/design-system/CRM-Mockups.dc.html:205-393)
   Every value is a token. No literals. Owner: design-system-agent.

   Deviations from the mockup, all deliberate — the mockup is a canvas doc and
   uses inline styles and non-interactive elements for speed:
     · focus-visible on everything    the mockup defines no focus states at all,
                                      but the DS ships --focus-ring
     · toggle/segmented/tabs are real buttons, not <span> — the mockup versions
       are unreachable by keyboard
     · badge/alert palettes lifted to tokens where the mockup hardcoded hex
   ========================================================================= */

/* ------------------------------------------------------- THE [hidden] LAW

   `[hidden] { display: none }` is a USER-AGENT rule. A user-agent rule loses
   to ANY author `display` declaration, at any specificity, in any order. So
   every component below that sets `display` — .btn, .alert, .field__error,
   .badge, .chip, .tabs__tab, .modal, and every one added later — silently
   makes the `hidden` attribute stop working on itself.

   THIS PROJECT HAS RE-LEARNED THAT FIVE TIMES.

     1. a Tailwind display utility on a `<th>`      → solved with .cx-col-hidden
     2. .cx-column-menu__panel                      → solved with .cx-hidden
     3. .cx-manage-columns                          → solved with .cx-hidden
     4. .cx-stats__tile                             → solved with a compound
        selector, alongside .cx-facet__dates, .cx-facet__families, .cx-undo,
        .tpl__menu, .lead-info__status and .record__action-note
     5. .cx-rail__discard (`.btn`)                  → a permanent "Discard"
        button, 73px wide and tab stop 46, on a page with nothing to discard;
        and .field__error (`display:flex`), which rendered an empty red error
        slot under an inline-edit field that had no error

   Each fix was correct and each one taught the rule to exactly one element.
   The pattern was still there for the next component to walk into, because
   nothing in the stylesheet says it once. This says it once.

   `!important` is doing real work rather than papering over specificity: this
   rule has to beat author declarations that are ALREADY more specific and,
   in responsive.css, load later. Normal weight cannot, whatever selector is
   written. It is the same instrument .modal [hidden] already reached for, and
   the intent is identical — only the scope changes.

   `:not([hidden="until-found"])` keeps the HTML `hidden=until-found` value
   working (a browser reveals such content by setting `hidden` to empty on
   find-in-page, and a forced `display:none` would defeat it). Nothing here
   uses it today; the exclusion is what stops this rule becoming a trap of its
   own.

   WHAT THIS DOES NOT COVER: Tailwind's `.hidden` CLASS and this package's
   `.cx-hidden` are different mechanisms and are unaffected. So is anything
   toggled by `style.display` or by Vue's `v-show`, which sets an inline style
   and never touches the attribute.                                          */
[hidden]:not([hidden="until-found"]) { display: none !important; }

/* ---------------------------------------------------------------- BUTTONS */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--space-2);
  border:1px solid transparent; border-radius:var(--radius-pill);
  padding:9px 18px; font:600 13px/1 var(--font-body); cursor:pointer;
  text-decoration:none; white-space:nowrap;
  transition:background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
             box-shadow var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.btn:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.btn:disabled,.btn[aria-disabled="true"]{
  background:var(--ink-50); border-color:var(--border); color:var(--ink-300);
  cursor:not-allowed; box-shadow:none; transform:none;
}
/* DOCUMENT-REQUESTS-RULINGS DR38 K2: the disabled fill above paints
   primitives that stay light in dark mode (a light pill on a dark page, the
   portal's Submit). Semantic tokens here; light is unchanged. */
.dark .btn:disabled,.dark .btn[aria-disabled="true"]{
  background:var(--bg-tint); border-color:var(--border); color:var(--fg-muted);
}

/* --brand-strong, not --brand: this button carries white label text at body
   size, where green-500 measures 3.08:1 and fails AA. See tokens.css. */
.btn--primary{ background:var(--brand-strong); color:var(--fg-on-brand); box-shadow:var(--shadow-brand); }
.btn--primary:hover:not(:disabled){ background:var(--brand-strong-hover); }
.btn--primary:active:not(:disabled){ background:var(--brand-strong-press); transform:translateY(1px); }

.btn--secondary{ background:var(--bg); border-color:var(--border); color:var(--fg); }
.btn--secondary:hover:not(:disabled){ border-color:var(--green-300); }
.btn--secondary:active:not(:disabled){ transform:translateY(1px); }

.btn--tinted{ background:var(--mist); border-color:var(--green-200); color:var(--green-700); }
.btn--tinted:hover:not(:disabled){ background:var(--green-50); }

.btn--ghost{ background:transparent; color:var(--green-700); padding:9px 12px; }
.btn--ghost:hover:not(:disabled){ background:var(--mist); }

.btn--destructive{ background:#fdeeee; border-color:#f3c1c1; color:#c92a2a; }
.btn--destructive:hover:not(:disabled){ background:#fbdede; }

.btn--sm{ padding:6px 13px; font-size:11.5px; }
.btn--lg{ padding:12px 24px; font-size:14px; font-weight:700; box-shadow:var(--shadow-brand); }
/* DR38 K1: a 44px touch target (DR36), a size variant of the kit button. */
.btn--touch{ min-block-size:44px; padding-inline:18px; }

/* icon-only, circular */
.btn-icon{
  display:inline-flex; align-items:center; justify-content:center;
  width:38px; height:38px; border-radius:50%; border:1px solid transparent;
  cursor:pointer; transition:background var(--dur-fast) var(--ease);
}
.btn-icon:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.btn-icon--brand{ background:var(--brand); color:var(--fg-on-brand); }
.btn-icon--brand:hover{ background:var(--brand-hover); }
.btn-icon--plain{ background:var(--bg); border-color:var(--border); color:var(--fg-muted); }
.btn-icon--plain:hover{ border-color:var(--green-300); color:var(--fg); }
.btn-icon--sm{ width:30px; height:30px; }
/* DR38 K1: the same 44px target for an icon button. */
.btn-icon--touch{ inline-size:44px; block-size:44px; }

/* ------------------------------------------------------------------ FORMS */
.field{ display:flex; flex-direction:column; gap:var(--space-1); }
.field__label{ font-size:11.5px; font-weight:600; color:var(--fg-muted); }
.field__hint{ font-size:11px; color:var(--fg-muted); }
.field__error{ display:flex; align-items:center; gap:var(--space-1); font-size:11px; color:#c92a2a; }

/* Provenance marks (S19): the label row for prefilled Application-card fields.
   Kit, not module - the submission record page's Application card renders the
   same "Edited" mark against the stored snapshot. Closed vocabulary of three:
   From lead / From deal / nothing. No new token, no new colour, no new size -
   11px is .field__hint's own size, --fg-muted is .field__hint's own colour,
   --green-700 is .btn--ghost's, --radius-xs is tokens.css:372. */
.field__head  { display:flex; align-items:baseline; gap:var(--space-2); min-width:0; }
.field__mark  { margin-inline-start:auto; font-size:11px; color:var(--fg-muted); white-space:nowrap; }
.field__mark--edited { color:var(--green-700); font-weight:600; } /* D2: the edited mark is findable by scanning; the word still carries the meaning */
.dark .field__mark--edited { color:var(--green-400); } /* --green-700 is 3.11:1 on ink-900; green-400 is 6.9:1 */
.field__reset { border:0; background:none; padding:0; cursor:pointer;
                font:600 11px var(--font-body); color:var(--green-700); text-decoration:underline; }
.field__reset:focus-visible { outline:2px solid var(--focus-outline,#00763d); outline-offset:2px;
                              border-radius:var(--radius-xs); }

.input,.select,.textarea{
  width:100%; border:1px solid var(--border); border-radius:var(--radius-md);
  padding:9px 12px; font:500 13px var(--font-body); color:var(--fg-strong);
  background:var(--bg);
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.textarea{ font-weight:400; color:var(--fg); min-height:56px; resize:vertical; }
.input:hover,.select:hover,.textarea:hover{ border-color:var(--green-200); }
.input:focus,.select:focus,.textarea:focus{
  outline:none; border-color:var(--focus-outline, #00763d); box-shadow:0 0 0 3px var(--focus-ring);
}
.input::placeholder,.textarea::placeholder{ color:var(--fg-subtle); }

.input--error{ border-color:#e8a0a0; background:#fffafa; }
.input--error:focus{ border-color:#d8413a; box-shadow:0 0 0 3px rgba(216,65,58,.16); }
/* PP7.2 (PROFILE-PAGE-RULINGS): a control marked invalid by aria-invalid, the attribute a script sets
   together with aria-describedby, gets the token danger border - the .dialcode--error / datepicker precedent.
   No background tint. Cleared by the owner removing the attribute on the next input. */
.input[aria-invalid="true"],
.select[aria-invalid="true"],
.textarea[aria-invalid="true"]{ border-color:var(--danger); }
.input[aria-invalid="true"]:focus,
.select[aria-invalid="true"]:focus,
.textarea[aria-invalid="true"]:focus{ border-color:var(--danger); box-shadow:0 0 0 3px color-mix(in srgb,var(--danger) 20%,transparent); }

/* input with a leading/trailing adornment */
.input-group{
  display:flex; align-items:center; gap:9px;
  border:1px solid var(--border); border-radius:var(--radius-md);
  padding:9px 12px; background:var(--bg);
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.input-group:focus-within{ border-color:var(--focus-outline, #00763d); box-shadow:0 0 0 3px var(--focus-ring); }
.input-group__icon{ flex:none; width:15px; height:15px; color:var(--fg-subtle); }
/* ---- DARK-MODE-RULINGS.md finding C, ARCHITECT TRIAGE 2026-09-11. THE NOTE
   FOR EVERY `finding C` MARKER IN THIS FILE.

   Finding C's durable rule: a primitive may be a FILL, a primitive may not be
   a FOREGROUND colour - it does not repoint inside the `.dark` block, so it
   goes on being a light-mode colour on a dark surface, silently. `--ink-900`
   as `color:` is the worst case: in dark it IS `--bg` (tokens.css:450), i.e.
   1.00:1, invisible.

   EVERY REPOINT MARKED `finding C` IN THIS FILE IS ZERO-PIXEL IN LIGHT, and
   that is the entry condition for making it here rather than handing it to a
   snapshot: tokens.css:25 defines `--fg-strong` AS `var(--ink-900)` and `--fg`
   AS `var(--ink-700)`, so the light render is byte-identical and only the
   `.dark` block (`--fg-strong` -> white, `--fg` -> `--ink-300`) changes. Same
   shape as symptoms 2-4. Sites whose semantic equivalent is NOT byte-identical
   in light (the `--ink-50` hover fills, `--ink-100`/`--mist` chip fills, the
   `--ink-300` disabled foreground) are deliberately NOT touched here - they
   are listed under finding C with their owner and their token. */
.input-group__input{ flex:1; min-width:0; border:none; outline:none; background:transparent;
  font:500 13px var(--font-body); color:var(--fg-strong); /* finding C */ }
.input-group--success{ border-color:var(--green-300); background:var(--green-50); }

/* `.dialcode__code` shares the chevron rather than carrying its own copy of
   the data URI — it IS a select, it just lives inside a joined control. */
.select,.dialcode__code{ appearance:none; -webkit-appearance:none; padding-right:32px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2300a959' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 11px center; }

.checkbox,.radio{ accent-color:var(--brand); width:15px; height:15px; cursor:pointer; }
.checkbox:focus-visible,.radio:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.choice{ display:inline-flex; align-items:center; gap:7px; font-size:13px; color:var(--fg); cursor:pointer; } /* finding C */

/* switch — a real button[role=switch]; the mockup used a bare <span> */
.switch{
  display:inline-flex; align-items:center; width:38px; height:22px; padding:0;
  border:none; border-radius:var(--radius-pill); background:var(--ink-200);
  position:relative; cursor:pointer; transition:background var(--dur-base) var(--ease);
}
.switch:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.switch[aria-checked="true"]{ background:var(--brand); }
.switch__thumb{
  position:absolute; top:2px; left:2px; width:18px; height:18px; border-radius:50%;
  background:var(--white); box-shadow:var(--shadow-sm);
  transition:transform var(--dur-base) var(--ease);
}
.switch[aria-checked="true"] .switch__thumb{ transform:translateX(16px); }
/* A locked switch (NOTIFICATIONS N10.4): still focusable so its reason is
   discoverable; no opacity change - a locked-on switch must still read as on. */
.switch[aria-disabled="true"]{ cursor:not-allowed; }

/* fieldset reset — a group of controls under a <legend>, with none of the
   browser's inherited border/padding and no min-width floor (the UA's
   `min-inline-size: min-content` is what makes a <fieldset> refuse to shrink
   inside a grid or flex column).

   THE NAME IS HISTORICAL. It arrived in modals.css and reads "modal", but
   nothing about it is modal-specific — the submissions composer wears it on a
   full page. Promoted here by carried finding 5 (SUBMISSIONS-RULINGS.md);
   the name is kept because every caller already says it and a rename buys
   nothing but churn. */
.modal-fieldset{ border:none; margin:0; padding:0; min-width:0; }
.modal-fieldset > legend{ padding:0; }

/* --------------------------------------------------- SEGMENTED  &  CHIPS */
/* DARK-MODE-RULINGS.md finding C: the pill used to sit on the --ink-100
   PRIMITIVE, which never repoints under .dark, while its label used the
   --fg-muted SEMANTIC, which does. The pill stayed light (#eceef1) and the
   text darkened toward it (#8a929e), landing at ~2.7:1. --bg-tint is the
   semantic inset-tint token (D2) — mist in light, ink-800 in dark — so the
   pill now tracks the surface it sits on, same as .dropzone (symptom 4). */
.segmented{ display:inline-flex; gap:2px; background:var(--bg-tint);
  border-radius:var(--radius-pill); padding:3px; }
.segmented__item{
  flex:1; border:none; background:transparent; cursor:pointer;
  padding:7px 16px; font:700 12px var(--font-body); color:var(--fg-muted);
  border-radius:var(--radius-pill); white-space:nowrap;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.segmented__item:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
/* --bg-invert is "the opposite of the page surface" (D2): ink-900 in light,
   white in dark — so the selected chip stays maximally distinct from the
   pill it sits inside in BOTH modes, rather than the fixed --ink-900 fill
   this used to be, which is nearly indistinguishable from --bg-tint's own
   dark value (1.14:1 chip-vs-pill). Text flips with it: --fg-on-dark (white,
   constant) reads on the light-mode dark chip; the .dark override below
   swaps to --ink-900 for the dark-mode light chip. Light mode is
   byte-identical — --bg-invert's light value IS --ink-900. */
/* TASKS-RULINGS TK33.1: the same selected state for a LINK item. The Tasks
   view switcher is a row of <a class="segmented__item" aria-current="page">
   (each option loads a different page, so it is navigation, not a tablist).
   Selector lists only - no new value. `a.segmented__item` drops the link
   underline and centres the label as the button form already does. */
a.segmented__item{ text-decoration:none; text-align:center; }
.segmented__item[aria-selected="true"],
.segmented__item[aria-current="page"]{ background:var(--bg-invert); color:var(--fg-on-dark); }
.dark .segmented__item[aria-selected="true"],
.dark .segmented__item[aria-current="page"]{ color:var(--ink-900); }

/* ---- .segmented--radio — the same control built out of real radios.

   `.segmented`'s items are buttons the page's JS keeps in sync. When the
   choice is a form field that must POST, the item is a <label> wrapping a
   visually-hidden <input type=radio> instead: the browser then owns the
   selection, the keyboard arrow-key behaviour and the value, and no script is
   involved. `:has(input:checked)` paints the selected state, so the styling
   follows the form control rather than an aria attribute a script has to
   remember to set.

   IT LIVES HERE, NOT IN A MODULE STYLESHEET, AND THAT IS THE POINT.
   It shipped in modals.css, where it lost. The admin layout renders
   `@stack('styles')` BEFORE the theme kit — measured link order on
   admin/submissions/create is record, funding-enquiries,
   lead-timeline-comms, modals, submissions, THEN tokens, components — so
   `.segmented--radio { display:flex }` in a stacked file and
   `.segmented { display:inline-flex }` in the kit are equal specificity
   (0,1,0) with the KIT LAST, and the kit won. Measured in Chromium at 1280
   on the shipped Send-bank-statement-link dialog: the group came out 102px
   wide with its three items shrink-wrapped to 27/36/30px instead of `flex:1`
   inside 460px — and because `.segmented--radio .segmented__item` (0,2,0)
   DOES beat `.segmented__item` (0,1,0), those items kept `padding:10px 0`
   and the labels touched.

   Sitting after `.segmented` in this file settles it by position, for every
   caller, permanently. A module stylesheet cannot restyle a kit class at
   equal specificity — see DIALOG-RULINGS.md D-K1. */
.segmented--radio{ display:flex; gap:4px; max-width:460px; }
.segmented--radio .segmented__item{
  flex:1; padding:10px 0; text-align:center;
  font-weight:700; font-size:12.5px;
  border-radius:var(--radius-pill); cursor:pointer;
}
.segmented--radio .segmented__item:has(input:checked){
  background:var(--bg-invert); color:var(--fg-on-dark);
}
.dark .segmented--radio .segmented__item:has(input:checked){ color:var(--ink-900); }
.segmented--radio .segmented__item:has(input:focus-visible){
  outline:2px solid var(--focus-outline, #00763d); outline-offset:2px;
}
/* SR6 (STATEMENT-REQUESTS-RULINGS, finding SR-F2): a disabled option has to
   LOOK disabled. Before this the Send Statement Link dialog's SMS option on a
   lead with no mobile looked selectable and silently refused the click. The
   reason is stated in text beside the control; this is the visual half.
   --fg-muted on --bg-tint stays legible in both modes. */
.segmented--radio .segmented__item:has(input:disabled){ color:var(--fg-muted); cursor:not-allowed; }

.chip{
  display:inline-flex; align-items:center; gap:6px;
  font-size:12px; font-weight:500; padding:6px 13px;
  border:1px solid var(--border); border-radius:var(--radius-pill);
  background:transparent; color:var(--fg-muted); cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.chip:hover{ border-color:var(--green-300); }
.chip:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.chip--active{ background:var(--mist); border-color:transparent; color:var(--green-700); font-weight:600; }
.chip--add{ border-style:dashed; border-color:var(--border-strong); color:var(--fg-subtle); font-weight:600; }

/* ----------------------------------------------------------------- BADGES */
.badge{
  display:inline-flex; align-items:center; gap:5px;
  font-size:11px; font-weight:600; padding:4px 11px;
  border-radius:var(--radius-pill); white-space:nowrap;
}
.badge--sm{ font-size:10.5px; padding:3px 9px; }
.badge--neutral{ background:var(--ink-100); color:var(--ink-600); }
.badge--pink{    background:#ffc6c6; color:#9a2e47; }
.badge--red{     background:#ffebeb; color:#c92a2a; }
/* AMBER AND BLUE CARRY TEXT, SO THEY USE THE TEXT STEP OF THEIR RAMP.
   Measured at this component's real 10.5px/600, the old pairs were
   #b97908 on #fef4e6 = 3.33:1 and #2c7ee0 on #eef4fd = 3.68:1 - both fail
   SC 1.4.3, which needs 4.5:1 (10.5px is nowhere near "large text": that
   starts at 18.66px bold). Amber is the `in_progress` family, 8 of the 17
   lead statuses, so it was the weakest tone on the busiest cell of the
   busiest screen; blue is `new`, the status every lead enters through.

   The BACKGROUNDS are unchanged and the ramps' -700 steps are unchanged:
   the fills ripple into avatar chips, alert icons and the facet rules, and
   those are graphical objects at the 3:1 bar. Only the text step moves.
   --tone-*-fg measure 5.45:1 on their own wash, which lands inside the band
   the passing tones already occupy (red 4.76 → neutral 8.08).
   RATIFIED by design-system-agent, 2026-08-23 —
   .claude/design-system/ACCESSIBILITY-AMENDMENTS.md (A3). */
.badge--blue{    background:var(--tone-blue-bg, #eef4fd); color:var(--tone-blue-fg, #1b62b8); }
.badge--purple{  background:#f3ecfd; color:#7a4fd8; }
.badge--amber{   background:var(--tone-amber-bg, #fef4e6); color:var(--tone-amber-fg, #8a5a00); }
.badge--green{   background:var(--green-100); color:var(--green-800); }
.badge--brand{   background:var(--brand); color:var(--fg-on-brand); font-weight:700; }
.badge--mist{    background:var(--mist); color:var(--green-700); }
.badge--soft-green{ background:var(--green-50); color:var(--green-700); }
.badge--ink{ background:var(--ink-900); color:var(--fg-on-dark); font-size:9.5px; font-weight:700; padding:3px 8px; }

/* A RECIPIENT BADGE IN A DIALOG PANEL HEAD (the statement Send and request-
   details dialogs: "SMS to <phone>", "Email to <address>"). The head is a
   flex row and a long address used to be clipped silently at the panel's
   edge. The badge may now shrink, and the value inside it - the element
   that carries data-overflow-tip - keeps one line and ellipsises, so
   record-shell.js's kv-tooltip shows it whole on hover and focus (memory
   overflow-hover-not-scroll). The badge itself is not overflow:hidden, so
   a focused link's outline is never cut off. */
.modal-panel__head .badge{ min-width:0; max-width:100%; }
.modal-panel__head .badge > [data-overflow-tip]{
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.live-dot{ width:8px; height:8px; border-radius:50%; background:var(--green-400); }
@media (prefers-reduced-motion: no-preference){
  .live-dot{ animation:dsPulse 2s infinite; }
  @keyframes dsPulse{ 0%,100%{box-shadow:0 0 0 0 rgba(0,169,89,.35)} 70%{box-shadow:0 0 0 12px rgba(0,169,89,0)} }
}

/* ---------------------------------------------------------------- AVATARS */
.avatar{
  display:inline-flex; align-items:center; justify-content:center; flex:none;
  border-radius:50%; background:var(--green-100); color:var(--green-800);
  font-family:var(--font-body); font-weight:700; text-transform:uppercase;
}
.avatar--xl{ width:44px; height:44px; font-size:14px; }
.avatar--lg{ width:36px; height:36px; font-size:12px; }
.avatar--md{ width:30px; height:30px; font-size:10px; font-weight:600; }
.avatar--sm{ width:28px; height:28px; font-size:10px; font-weight:600; }
.avatar--xs{ width:22px; height:22px; font-size:8.5px; }
.avatar--ink{ background:var(--ink-900); color:var(--fg-on-dark); }
.avatar--muted{ background:var(--ink-100); color:var(--ink-600); }
.avatar--square{ border-radius:11px; }

.avatar-group{ display:inline-flex; }
.avatar-group .avatar{ border:2px solid var(--bg); }
.avatar-group .avatar + .avatar{ margin-left:-8px; }

/* OWNER — an initials disc and the owner's name beside it.
   ═══════════════════════════════════════════════════════════════════════
   PROMOTED, NOT COPIED (design ruling K2.5 / finding K-F5,
   .claude/design-system/KANBAN-RULINGS.md). These eight rules were declared
   inside components/datagrid/index.blade.php's own `@pushOnce('styles')`
   block, which reaches a page only when the DATAGRID is rendered. The
   Kanban board renders no datagrid, so the second consumer of this recipe
   had none of it — and the alternative on the table was a second copy of
   eight rules built from the same five literals, free to drift.

   THE MOVE CHANGED NOT ONE VALUE. Every declaration below is the
   datagrid block's own; the block deleted its copy in the same commit. The
   five colours keep their literal fallbacks for the same reason they were
   written with them: a saturated primitive that is not tokenised still has
   to paint if tokens.css fails to load.

   `.cx-source-none` shared the `--none` rule and did NOT come with it: it
   is a datagrid cell class with no board consumer, and it stays declared
   beside the grid's other cell renderers.

   The disc is `aria-hidden` at every call site and the NAME is rendered
   beside it — a coloured disc with a `title` is not an accessible name
   (AC-F4). */
.cx-owner { display: inline-flex; align-items: center; gap: 8px; min-width: 0; max-width: 100%; }
.cx-owner__avatar {
  flex: none; width: 24px; height: 24px; border-radius: var(--radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; letter-spacing: .02em; line-height: 1;
  color: #fff; user-select: none;
}
.cx-owner__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* TEXT, so --fg-muted. It renders an em dash and it is NOT aria-hidden - it
   is the cell's whole content and the only thing saying "unassigned", so it
   is rendered copy under SC 1.4.3, not a graphical object. 5.74:1 on the
   row's --bg (dark 5.68:1); the #8a929e it replaces was 3.14:1, and 2.89:1
   on the --bg-tint a hovered or focus-within row wears. */
.cx-owner--none { color: var(--fg-muted); }

.cx-owner__avatar--green  { background: var(--green-500, #00a959); }
.cx-owner__avatar--blue   { background: var(--info,    #2c7ee0); }
.cx-owner__avatar--amber  { background: var(--warning, #f6a624); color: var(--ink-900, #14181c); }
.cx-owner__avatar--purple { background: #7c5cff; }
.cx-owner__avatar--pink   { background: #e0518d; }

/* PRESENCE DOT - PROFILE-MENU-RULINGS.md PM12. The avatar gets
   `presence-host`; the dot is its last child, aria-hidden, with the status
   as text beside the visible name. Offline renders nothing. Available is a
   solid --brand-text disc; Focus is an --amber-700 disc with a bar (the
   "do not disturb" minus), so the two differ in shape, not only hue.
   Dot vs ring: available 5.74 / 8.71, focus 3.62 / 4.93 (PM22).
   Base 12px for 36-44px hosts; --md 10px for 24-30px; --sm 8px for 16-22px.
   Hosts whose call sites cannot add a modifier (the PHP-rendered owner cell,
   the timeline actor) are sized by host here, so the markup stays one shape.
   `.cx-presence` is the same dot under the ARCH 5.1 spelling. */
.presence-host{ position:relative; }
/* The dot hosts are a positioning context UNCONDITIONALLY (a11y P2-2): the
   dot must never depend on :has() support to land on its disc. None of the
   three sets a z-index, so no stacking context is created and no existing
   layout (inline-flex discs, the avatar-group overlap, the board/menu size
   overrides) changes. */
.cx-owner__avatar, .tl-row__avatar, .avatar{ position:relative; }
.presence,
.cx-presence{
  position:absolute; inset-block-end:-1px; inset-inline-end:-1px;
  box-sizing:border-box; inline-size:12px; block-size:12px;
  border-radius:var(--radius-pill); border:2px solid var(--presence-ring, var(--bg));
  pointer-events:auto;
}
.presence--available,
.cx-presence--available{ background:var(--brand-text); }
.presence--focus,
.cx-presence--focus{ background:var(--amber-700); }
.presence--focus::after,
.cx-presence--focus::after{
  content:""; position:absolute; inset:0; margin:auto;
  inline-size:50%; block-size:2px; border-radius:1px;
  background:var(--presence-ring, var(--bg));
}
.presence--md,
.cx-owner__avatar > .presence, .cx-owner__avatar > .cx-presence,
.avatar--md > .presence, .avatar--md > .cx-presence,
.avatar--sm > .presence, .avatar--sm > .cx-presence{ inline-size:10px; block-size:10px; }
.presence--sm,
.tl-row__avatar > .presence, .tl-row__avatar > .cx-presence,
.avatar--xs > .presence, .avatar--xs > .cx-presence{ inline-size:8px; block-size:8px; border-width:1px; }
/* The header trigger and the menu head are 38/40px hosts: the base size.
   Restated so the owner-disc rule above cannot reach them (the disc is a
   sibling there, not the host). */
.pm-trigger > .presence, .pm-head__avatar > .presence{ inline-size:12px; block-size:12px; border-width:2px; }

.identity-pill{
  display:inline-flex; align-items:center; gap:9px;
  border:1px solid var(--divider); border-radius:var(--radius-pill);
  padding:5px 13px 5px 5px; font-size:12.5px; font-weight:600; color:var(--fg-strong); /* finding C */
}

/* ------------------------------------------------------- ALERTS & TOASTS */
.alert{
  display:flex; gap:var(--space-3); padding:11px 14px;
  border-radius:12px; font-size:12.5px; line-height:var(--lh-normal);
}
.alert__icon{ flex:none; width:15px; height:15px; margin-top:1px; }
.alert--success{ background:var(--mist);  color:var(--green-800); }
.alert--success .alert__icon{ color:var(--brand); }
.alert--warning{ background:var(--tone-amber-bg, #fef4e6); color:var(--tone-amber-fg, #8a5a00); }
.alert--warning .alert__icon{ color:var(--amber-700, #b97908); }
.alert--danger{  background:#fdeeee; color:#9a2323; }
.alert--danger  .alert__icon{ color:var(--danger); }
.alert--info{    background:var(--tone-blue-bg, #eef4fd); color:var(--tone-blue-fg, #1b62b8); }
.alert--info    .alert__icon{ color:var(--info); }

/* ---- DARK — DARK-MODE-RULINGS.md finding C: these four were hardcoded hex
   with no .dark repoint at all, so they stayed light-mode islands on a dark
   page. --warning/--info now resolve through the tone-amber and tone-blue
   tokens, which already repoint under .dark (tokens.css D2/D6) — so only their
   icons need a rule here, having fallen under the 3:1 non-text bar once the
   fill darkened. --success/--danger have no global tone tokens yet (D6:
   "literals in components.css's .dark variants until A3's ramp is
   extended") — green-900/green-200 are existing ramp primitives; #5d1512/
   #e8a0a0 are D6's own measured red-900/red-300, not yet promoted to
   tokens, reused verbatim rather than invented here. */
.dark .alert--success{ background:var(--green-900); color:var(--green-200); }
.dark .alert--warning .alert__icon{ color:var(--tone-amber-fg); }
.dark .alert--danger{ background:#5d1512; color:#e8a0a0; }
.dark .alert--danger .alert__icon{ color:#e8a0a0; }

.toast{
  display:flex; align-items:center; gap:var(--space-3); padding:11px 14px;
  border-radius:12px; background:var(--ink-900); color:var(--fg-on-dark);
  font-size:12.5px; box-shadow:var(--shadow-md);
}
.toast__icon{ width:15px; height:15px; color:var(--green-300); }
.toast__action{ margin-left:auto; border:none; background:none; cursor:pointer;
  font:600 11.5px var(--font-body); color:var(--green-300); }
.toast__action:focus-visible{ outline:2px solid var(--green-300); outline-offset:2px; border-radius:4px; }

/* --------------------------------------------------------------- TOASTER
   The product toast: Theme's replacement of Krayin's admin flash-group
   component (views/admin-overrides/components/flash-group/index.blade.php).
   Ruled by .claude/design-system/TOAST-RULINGS.md T1-T17; the approved
   reference is the Sonner-style demo. `.toast` above is the gallery's
   mockup recipe and is deliberately a different selector (T-F1).

   Every colour is a token that tokens.css already flips under .dark, except
   the two carriers below (T14) - the only .dark rule this section carries.
   Stack geometry (T8): --i (0 = newest) and --offset (px, the summed heights
   of newer toasts plus a 14px gap per step, T-F6) are written by the
   component. Enter/leave animate the individual `translate` property, which
   composes with the stack `transform`, so one keyframe pair serves every
   stack position. Reduced motion is the global block in tokens.css. */
.cx-toaster{
  --cx-toast-edge:var(--border); --cx-toast-warn:var(--amber-700);
  position:fixed; inset-block-end:var(--space-6); inset-inline-end:var(--space-6);
  width:356px; max-width:calc(100vw - 2 * var(--space-4));
  z-index:10003; pointer-events:none;
}
.dark .cx-toaster{ --cx-toast-edge:var(--ui-subtle); --cx-toast-warn:var(--tone-amber-fg); }
/* Programmatic-only landing spot (tabindex="-1", never a Tab stop): where a
   keyboard dismissal sends focus once the stack it was in empties out,
   instead of losing it to <body>. Still gets a visible ring when it lands. */
.cx-toaster:focus-visible{ outline:2px solid var(--focus-outline); outline-offset:2px; border-radius:var(--radius-sm); }

.cx-toast{
  position:absolute; inset-block-end:0; inset-inline-end:0; width:100%; box-sizing:border-box;
  display:grid; grid-template-columns:auto 1fr auto; column-gap:var(--space-3); align-items:start;
  padding:14px var(--space-4);
  border:1px solid var(--cx-toast-edge); border-radius:var(--radius-md);
  background:var(--bg); box-shadow:var(--shadow-lg);
  color:var(--fg-strong); font-family:var(--font-body);
  pointer-events:auto; touch-action:none; user-select:none;
  transform:translateY(calc(-1 * var(--i, 0) * 14px)) scale(calc(1 - var(--i, 0) * .05));
  transform-origin:bottom center;
  transition:transform var(--dur-slow) var(--ease), translate var(--dur-slow) var(--ease), opacity var(--dur-slow) var(--ease);
}
.cx-toaster[data-expanded="true"] .cx-toast{
  transform:translateY(calc(-1 * var(--offset, 0px))) scale(1);
}
/* Three visible, expanded or not; the rest are also inert (component). */
.cx-toaster .cx-toast[data-i="3"]{ opacity:0; pointer-events:none; }
.cx-toast.is-entering{ animation:cx-toast-in var(--dur-slow) var(--ease) both; }
.cx-toast.is-leaving{ animation:cx-toast-out var(--dur-slow) var(--ease) forwards; pointer-events:none; }
.cx-toast.is-swiping{ transition:none; }

.cx-toast__icon{ display:flex; width:18px; height:18px; margin-top:1px; }
.cx-toast__icon svg{ display:block; width:18px; height:18px; }
.cx-toast__icon svg *,
.cx-toast__close svg *{ vector-effect:non-scaling-stroke; stroke-width:1.5px; }
.cx-toast[data-type="success"] .cx-toast__icon{ color:var(--brand-text); }
.cx-toast[data-type="error"]   .cx-toast__icon{ color:var(--danger-text); }
.cx-toast[data-type="warning"] .cx-toast__icon{ color:var(--cx-toast-warn); }
.cx-toast[data-type="info"]    .cx-toast__icon{ color:var(--tone-blue-fg); }
.cx-toast[data-type="loading"] .cx-toast__icon{ color:var(--fg-muted); }
.cx-toast__spinner{ animation:cx-toast-spin 1s linear infinite; }

.cx-toast__text{ min-width:0; display:flex; flex-direction:column; gap:2px; }
.cx-toast__title{ margin:0; font-size:var(--t-meta); font-weight:500; line-height:var(--lh-normal); color:var(--fg-strong); }
.cx-toast__description{ margin:0; font-size:var(--t-meta); line-height:var(--lh-normal); color:var(--fg-muted); overflow-wrap:anywhere; }

.cx-toast__actions{ display:flex; align-items:center; gap:var(--space-2); margin-top:var(--space-2); }
.cx-toast__action,
.cx-toast__cancel{
  height:24px; padding:0 10px; border:0; border-radius:var(--radius-sm);
  background:var(--bg-invert); color:var(--bg);
  font:500 11.5px var(--font-body); cursor:pointer;
}
.cx-toast__cancel{ background:var(--tone-neutral-bg); color:var(--tone-neutral-fg); }

.cx-toast__close{
  position:relative; box-sizing:border-box;
  display:inline-flex; align-items:center; justify-content:center;
  width:20px; height:20px; padding:0;
  border:1px solid var(--cx-toast-edge); border-radius:var(--radius-pill);
  background:var(--bg); color:var(--fg-muted); cursor:pointer;
  opacity:0; transition:opacity var(--dur-fast) var(--ease);
}
/* T7 / T-F5: 20px visual, 24px target. */
.cx-toast__close::before{ content:""; position:absolute; inset:-3px; border-radius:var(--radius-pill); }
.cx-toast__close svg{ display:block; width:12px; height:12px; }
.cx-toast:hover .cx-toast__close,
.cx-toast:focus-within .cx-toast__close{ opacity:1; }
.cx-toast__close:hover{ color:var(--fg-strong); }

.cx-toast__action:focus-visible,
.cx-toast__cancel:focus-visible,
.cx-toast__close:focus-visible{ outline:2px solid var(--focus-outline); outline-offset:2px; }

@keyframes cx-toast-in{ from{ opacity:0; translate:0 100%; } }
@keyframes cx-toast-out{ to{ opacity:0; translate:0 100%; } }
@keyframes cx-toast-spin{ to{ transform:rotate(360deg); } }

/* Touch has no hover: the close is always shown (T7). */
@media (pointer: coarse){
  .cx-toast__close{ opacity:1; }
}
/* Phones: full width minus the 16px insets (T2, the shipped 640 rung). */
@media (max-width: 640px){
  .cx-toaster{ inset-inline:var(--space-4); inset-block-end:var(--space-4); width:auto; }
}

/* -------------------------------------------------------------- PROGRESS */
.progress__head{ display:flex; justify-content:space-between; font-size:11.5px;
  color:var(--fg-muted); margin-bottom:5px; }
/* DARK-MODE-RULINGS.md finding C: was an inline style="color:var(--ink-900)"
   in progress.blade.php — a PRIMITIVE used as a foreground, so it never
   repointed under .dark and the readout became invisible on --bg
   (--ink-900 on --ink-900, 1:1). --fg-strong is the semantic role it always
   meant (white in dark, D2). Moved out of the inline style into a class,
   same fix shape as symptom 2/3. */
.progress__value{ color:var(--fg-strong); }
.progress__track{ height:8px; border-radius:var(--radius-pill); background:var(--ink-100); overflow:hidden; }
/* DR38 K3: --ink-100 stays a light bar in dark; the tint token flips. */
.dark .progress__track{ background:var(--bg-tint); }
.progress__fill{ height:100%; border-radius:var(--radius-pill); background:var(--brand);
  transition:width var(--dur-base) var(--ease); }

/* Tone modifiers — SUBMISSIONS-RULINGS.md S3. Semantic tokens only, never
   the primitives, and the bar is never the only signal: the copy changes
   too (aria-valuetext), because colour alone fails SC 1.4.1. */
.progress__track--warning .progress__fill{ background:var(--warning); }
.progress__track--danger  .progress__fill{ background:var(--danger); }

.stage-strip{ display:flex; gap:2px; }
.stage-strip__step{
  flex:1; text-align:center; font-size:10px; font-weight:600;
  padding:5px 2px; background:var(--ink-100); color:var(--ink-500);
}
.stage-strip__step:first-child{ border-radius:7px 0 0 7px; }
.stage-strip__step:last-child{ border-radius:0 7px 7px 0; }
.stage-strip__step--done{ background:var(--green-500); color:var(--fg-on-brand); }
/* NOT a focus indicator - a decorative ring marking the current stage, so it
   keeps --brand rather than following --focus-outline. The two must not be
   confused: an element that permanently wears the focus colour is how a real
   focus ring stops being findable. */
.stage-strip__step--current{ background:var(--green-100); color:var(--green-800); font-weight:700;
  outline:2px solid var(--brand); outline-offset:-2px; }

.meter{ display:flex; gap:4px; align-items:center; }
.meter__tick{ width:22px; height:6px; border-radius:var(--radius-pill); background:var(--ink-200); }
.meter__tick--on{ background:var(--warning); }
.meter__label{ font-size:11px; color:var(--fg-subtle); margin-left:5px; }

/* ------------------------------------------------------------ NAVIGATION */
/* ------------------------------------------------------------- BRANDMARK */
/* The 121 Brokers wordmark as live type, per mockup 5a. Shared by the app
   header, the login panel and anywhere else the mark is needed, so the three
   cannot drift. Sized by the context's font-size. */
.brandmark{
  display:inline-flex; align-items:baseline; gap:1px;
  font:800 18px var(--font-display); letter-spacing:-0.01em;
  color:var(--fg-strong); white-space:nowrap;
}
.brandmark__accent{ color:var(--brand-strong); }
.brandmark__check{
  width:0.72em; height:0.72em; margin-left:2px;
  color:var(--brand-strong); align-self:center;
}
.dark .brandmark{ color:var(--fg-on-dark); }
.dark .brandmark__accent,
.dark .brandmark__check{ color:var(--green-300); }

.tabs{ display:flex; gap:2px; border-bottom:1px solid var(--divider); }
.tabs__tab{
  border:none; background:none; cursor:pointer;
  padding:9px 14px; font:600 13px var(--font-body); color:var(--fg-muted);
  border-bottom:2px solid transparent; margin-bottom:-1px;
}
/* Gradient green hover/active.
   The DS asks for "very subtle green-on-white washes" and no heavier gradient,
   so hover stays a wash and only the selected tab takes the saturated fill.

   The gradient STARTS at green-700, not green-500: white label text needs
   4.5:1, and green-500 gives 3.08:1. green-700 is 5.74:1 and green-900 is
   higher, so every stop along the ramp clears AA — the contrast holds wherever
   the eye lands on the fill, not just at its ends. */
.tabs__tab:hover{
  color:var(--brand-strong);
  background:linear-gradient(180deg, transparent 0%, var(--green-50) 100%);
}
.tabs__tab:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:-2px; border-radius:4px 4px 0 0; }
.tabs__tab[aria-selected="true"]{
  color:var(--fg-on-brand);
  background:linear-gradient(135deg, var(--green-700) 0%, var(--green-900) 100%);
  border-bottom-color:var(--green-900);
  border-radius:var(--radius-sm) var(--radius-sm) 0 0;
}
/* Selected wins over hover — without this, hovering the active tab would swap
   its dark fill for the pale wash and drop the white text onto near-white. */
.tabs__tab[aria-selected="true"]:hover{
  color:var(--fg-on-brand);
  background:linear-gradient(135deg, var(--green-800) 0%, var(--green-900) 100%);
}

.pillnav{ display:flex; gap:4px; }
.pillnav__item{
  padding:7px 14px; border-radius:var(--radius-pill); border:none; background:none;
  font:500 13px var(--font-body); color:var(--fg-muted); cursor:pointer; text-decoration:none;
}
.pillnav__item:hover{ background:var(--ink-50); }
.pillnav__item:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.pillnav__item[aria-current="page"]{ background:var(--mist); color:var(--green-700); font-weight:600; }

.breadcrumb{ font-size:12px; color:var(--fg-subtle); }
.breadcrumb b{ color:var(--fg-strong); } /* finding C */

.pager{ display:flex; align-items:center; gap:var(--space-2); }
.pager__group{ display:flex; border:1px solid var(--border); border-radius:8px; overflow:hidden; }
.pager__btn{ width:28px; height:28px; border:none; background:var(--bg); color:var(--fg); /* finding C */
  cursor:pointer; display:inline-flex; align-items:center; justify-content:center; }
.pager__btn + .pager__btn{ border-left:1px solid var(--border); }
.pager__btn:disabled{ color:var(--ink-300); cursor:not-allowed; }
.pager__btn:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:-2px; }
.pager__count{ font-size:12px; color:var(--fg-subtle); }

/* ------------------------------------------------------- TABLE & KANBAN */
.dtable__head,.dtable__row{
  display:grid; gap:var(--space-3); align-items:center;
  grid-template-columns:26px 1.6fr 1fr 1.1fr;
}
.dtable__head{
  padding:8px 10px; font-size:11px; font-weight:600; letter-spacing:.05em;
  text-transform:uppercase; color:var(--fg-subtle); border-bottom:1px solid var(--divider);
}
.dtable__row{
  padding:var(--row-padding-y) 10px; min-height:var(--row-height);
  font-size:13px; border-bottom:1px solid var(--divider);
  transition:background var(--dur-fast) var(--ease);
  /* T44-4's derivation, this table's own tallest child: `.btn-icon--sm` is
     30px, not the DataGrid's 28px glyph. min-height/padding declared in the
     same rule means the padding wins on any row taller than one text line -
     the same defect T44-4 fixed on .cx-grid-row (index.blade.php:3473-3528).
     `max(0px, ...)` guards a --row-height below 31px, where the calc would
     otherwise go negative and drop the whole declaration. */
  padding-block: max(0px, calc((var(--row-height) - 30px - 1px) / 2));
}
.dtable__row:hover{ background:var(--ink-50); }
.dtable__row--selected{ background:var(--mist); }
.dtable__row a{ font-weight:600; }

/* ---- cx-cell-link — the low-identity cell link (LENDERS-RULINGS.md L1/L2).
   Promoted from lenders.css: L1's own promotion trigger ("the moment a third
   surface … needs this link") has fired — the Submissions index, record page,
   composer and public secure-link page all need it, and a public page cannot
   load lenders.css for one class. ONE declaration, here, for every surface. */
.cx-cell-link {
  color: inherit;
  text-decoration: none;
}

.cx-cell-link--muted {
  color: var(--fg-muted);
}

.cx-cell-link:hover,
.cx-cell-link:focus-visible {
  text-decoration: underline;
}

/* Inset ring: a grid cell is overflow:hidden, and the UA draws an outline
   OUTWARD, so on a link that fills its cell an outward ring is clipped away
   (SC 2.4.7). In addition to the underline above, never instead of it. */
.cx-cell-link:focus-visible {
  outline: 2px solid var(--focus-outline, #00763d);
  outline-offset: -2px;
}

/* ---- file table — the shared file-list treatment (SUBMISSIONS-RULINGS.md
   S5a). Promoted from lead-notes-tasks-files.css: the Bank statements list
   and the public secure-link page reuse it verbatim, so it is no longer one
   screen's own class. Sizing is ruled by DATA-TABLE-RULINGS.md F1: no table
   floor, the File column wraps and carries the table's only minimum, the
   machine-formatted columns opt in to nowrap. (Settles carried finding 6.) */

/* Guard of last resort, never the plan. With the 620px floor gone the table
   fits its container at every measured width >= 1024 (F1's table), so this
   wrapper does nothing; it stays so that a pathological column set overflows
   INSIDE its own box instead of dragging the page sideways. If it is ever
   observed scrolling, the surface has too many columns — drop columns
   (S16 A4), never restore a floor. Below 1024 responsive.css:96 makes the
   table itself the scroller and this wrapper is inert. */
.file-table-scroll {
  overflow-x: auto;
}

/* No min-width. A file list sizes like every other table in this system:
   width:100% + auto layout, which is the table's expression of the mirror's
   pure-`fr` tracks (DATA-TABLE-RULINGS.md, T44-2). */
.file-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  text-align: left;
}

.file-table th {
  padding: 6px 10px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  white-space: nowrap;
}

.file-table td {
  padding: 11px 10px;
  border-top: 1px solid var(--divider);
  color: var(--fg-muted);
  vertical-align: middle;
}

/* The identifying column. It WRAPS rather than truncating (T44-1: never
   silently truncate the identifying field) and carries the only minimum in
   this table: 120px = the type glyph (20) + its gap (9) + ~12 characters of
   13px/700 (91px; a measured 16-char string is 116px, "servicing.xlsx" 86px).
   Without it, a 6-column list in a 498px panel collapses this column to 58px
   and a long file name becomes a 1003px-tall cell — measured. It is a COLUMN
   minimum, not a table floor: it costs the other columns a few pixels and
   never forces a scroller on its own. */
.file-table__name {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 120px;
  font-weight: 700;
  color: var(--fg-strong);
  overflow-wrap: anywhere;
}

/* Opt-in, per cell, for the machine-formatted bounded columns only — size and
   date ("4.2 MB", "11 Sep 2026"). Those read as broken when they wrap, and
   their worst case is knowable. Free text (source, category, a person's name)
   never gets this: at a 498px panel width a nowrapped phrase eats the File
   column. Markup opts in; the kit does not guess which column is which. */
.file-table__meta {
  white-space: nowrap;
}

.file-table__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
}

/* File-type glyphs. Colour is a redundant cue — the file name and its
   extension are right beside it. */
.file-icon--doc {
  color: var(--danger);
}

.file-icon--sheet {
  color: var(--green-600);
}

.file-icon--image {
  color: var(--info);
}

.file-icon--other {
  color: var(--fg-subtle);
}

.kanban-card{
  background:var(--bg); border:1px solid var(--divider); border-radius:12px;
  box-shadow:var(--shadow-xs); padding:11px 13px; cursor:grab;
  transition:box-shadow var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.kanban-card:hover{ box-shadow:var(--shadow-md); transform:translateY(-2px); }
.kanban-card:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.kanban-card__title{ font-size:12.5px; font-weight:700; color:var(--fg-strong); flex:1; } /* finding C */
.kanban-card__amount{ font-size:15px; font-weight:800; color:var(--fg-strong); } /* finding C */
.kanban-card__meta{ font-size:11px; color:var(--fg-subtle); }

/* ----------------------------------------------------- MENU  &  TOOLTIP */
.menu{ border:1px solid var(--divider); border-radius:14px; box-shadow:var(--shadow-lg);
  padding:6px; background:var(--bg); min-width:220px; }
.menu__item{
  display:flex; align-items:center; gap:9px; width:100%; text-align:left;
  border:none; background:transparent; border-radius:9px; padding:8px 11px;
  cursor:pointer; font:600 13px var(--font-body); color:var(--fg-strong); /* finding C */
}
.menu__item:hover{ background:var(--ink-50); }
.menu__item:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:-2px; }
.menu__item[aria-checked="true"]{ background:var(--mist); }
.menu__item--accent{ color:var(--green-700); font-size:12.5px; }
.menu__sep{ border-top:1px solid var(--divider); margin:5px 0; }

/* KEY CAP - PROFILE-MENU-RULINGS.md PM19. `.mc-kbd`'s value set verbatim
   (mail-client.css), promoted on its second consumer (the shortcuts sheet).
   `--sm` is the profile menu row hint. */
.kbd{
  display:inline-block; min-width:22px; padding:1px var(--space-2);
  border:1px solid var(--border-strong); border-bottom-width:2px;
  border-radius:var(--radius-xs); background:var(--bg-alt); color:var(--fg-strong);
  font-family:var(--font-mono); font-size:var(--t-meta); text-align:center;
}
.kbd--sm{ min-width:18px; padding:0 var(--space-1); font-size:11px; line-height:16px; }

.tooltip{ display:inline-flex; flex-direction:column; align-items:center; }
.tooltip__bubble{ background:var(--ink-900); color:var(--fg-on-dark); font-size:11px;
  font-weight:600; padding:6px 11px; border-radius:8px; box-shadow:var(--shadow-md); }
.tooltip__arrow{ width:0; height:0; border-left:5px solid transparent;
  border-right:5px solid transparent; border-top:5px solid var(--ink-900); }

/* ------------------------------------------------- EMPTY STATE & UPLOAD */
.dropzone{
  border:2px dashed var(--green-200); border-radius:14px; background:var(--bg-tint);
  padding:var(--space-6); display:flex; flex-direction:column; align-items:center; gap:7px;
  text-align:center; cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.dropzone:hover,.dropzone--dragover{ border-color:var(--brand); background:var(--green-50); }
.dropzone:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }
.dropzone__title{ font-size:13px; font-weight:600; color:var(--fg-strong); }
.dropzone__hint{ font-size:11.5px; color:var(--fg-muted); }

.empty{ display:flex; flex-direction:column; align-items:center; gap:var(--space-2);
  padding:var(--space-6) 10px 6px; text-align:center; }
.empty__icon{ width:26px; height:26px; color:var(--ink-300); }
.empty__title{ font-size:13px; font-weight:600; color:var(--fg-strong); } /* finding C */
.empty__body{ font-size:11.5px; color:var(--fg-muted); }

/* -------------------------------------------------------- SURFACE / CARD */
.card{ background:var(--bg); border-radius:var(--radius-lg); box-shadow:var(--shadow-sm);
  padding:var(--space-5) 22px;
  transition:box-shadow var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.card--hoverable:hover{ box-shadow:var(--shadow-md); transform:translateY(-2px); }
.card__eyebrow{ font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--fg-subtle); margin-bottom:14px; }

/* .card--surface: the same background/radius/shadow recipe the record
   page's rail cards use (record.css .card--tight: var(--bg), var(--radius-lg),
   var(--shadow-xs)) - WITHOUT that variant's baked-in 16/18 padding.
   Reused rather than reinvented: the three list-page surfaces this class was
   built for (the leads filter rail, the results table, the sticky stats bar
   - components/datagrid/filter-panel.blade.php and index.blade.php) each
   already own tuned, content-specific padding of their own (the rail's
   --space-5 facet rhythm, the stats bar's compact --space-2 tile height), so
   forcing .card--tight's own padding onto all three would fight a value that
   already has a reason to be what it is. One class carrying just background,
   radius and elevation means a future change to card elevation is one edit
   here, not three hand-set copies on three selectors. */
.card--surface{ background:var(--bg); border-radius:var(--radius-lg); box-shadow:var(--shadow-xs); }

/* Lucide icon wrapper — the DS mandates stroke icons at a fixed box.
   Sizes are classes, not inline styles: interpolating Blade into a style
   attribute breaks CSS tooling and trips the design-QA inline-style grep. */
.lu{ display:inline-flex; align-items:center; justify-content:center; flex:none; }
.lu svg{ width:100%; height:100%; stroke-width:1.5; }
.lu--xs{ width:11px; height:11px; }
.lu--sm{ width:13px; height:13px; }
.lu--md{ width:14px; height:14px; }
.lu--lg{ width:15px; height:15px; }
.lu--xl{ width:24px; height:24px; }
.lu--2xl{ width:26px; height:26px; stroke-width:1.75; }

/* screen-reader-only, for accessible names on icon-only and initials UI.

   Off-screen by POSITION and CLIP — never display:none, never
   visibility:hidden. Both of those remove the element from the tab order
   outright, and every element sharing this rule has to stay focusable.

   `[data-dialcode-enhanced="true"]` is the lead form's core Mobile input,
   hidden visually by au-dialcode-widget.js while it goes on being the field
   that is focused, validated and posted. It shares this declaration rather
   than carrying the class because it is Vue-managed: v-phone-component's
   control re-patches that input's `class` attribute every time its error
   state flips, which would silently drop a class added from outside Vue. A
   data-attribute Vue does not bind survives the patch. Same contract, same
   declarations, one place to change them. */
.sr-only,
[data-dialcode-enhanced="true"]{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
}

/* --------------------------------------------------------- THE SKIP LINK
   SC 2.4.1 Bypass Blocks. The first tab stop of a page, hidden until it is
   the thing with focus.

   OFF-SCREEN BY POSITION, NOT BY `display` OR `visibility`. Both of those
   remove an element from the tab order outright, so a skip link built on
   either is a skip link that can never be reached - the same class of mistake
   as `class="peer hidden"` on a checkbox, which this project has already made
   once and measured.

   `position: fixed` rather than `absolute`: absolute would resolve against
   whichever ancestor happens to be positioned, and Krayin's admin layout has
   several. Fixed is viewport-relative, so the link lands in the same place on
   every screen that uses it.

   z-index above the page header's own 1000 - a skip link that appears behind
   the sticky header is a skip link the user cannot read.

   --brand-strong, not --brand: this is white label text at body size, where
   green-500 measures 3.08:1 and fails AA. */
.cx-skip-link{
  position:fixed; left:var(--space-4); top:-100px; z-index:100001;
  display:inline-flex; align-items:center;
  padding:9px 18px; border-radius:var(--radius-pill);
  background:var(--brand-strong); color:var(--fg-on-brand);
  font:600 13px/1 var(--font-body); text-decoration:none;
  box-shadow:var(--shadow-md);
  transition:top var(--dur-fast) var(--ease);
}
.cx-skip-link:focus{ top:var(--space-3); }
.cx-skip-link:focus-visible{ outline:2px solid var(--focus-outline, #00763d); outline-offset:2px; }

@media (prefers-reduced-motion: no-preference){
  .animate-spin{ animation:dsSpin 1s linear infinite; }
  @keyframes dsSpin{ to{ transform:rotate(360deg) } }
}

/* ----------------------------------------------------- PHONE STANDARDISATION
   `.field__warn` / `.input--warn` — the AU-mobile advisory note shown beside
   a Mobile field (create/edit form via au-mobile-warning.js, and the lead
   Info panel's own inline validator). Non-blocking by contract: this is a
   hint, never an error, so it borrows the qualification rail's WARN tone
   rather than --danger.

   `.link-tel` / `.link-tel--brand` — a stored phone number rendered as a
   `tel:` link (lead view Info/Communication panels, the Statement modal, the
   leads grid's Mobile column). `--brand` is reserved for the higher-emphasis
   instances (the Info panel's call action); the plain variant inherits
   surrounding text colour so it reads as text first, link second. */
.field__warn{display:flex;align-items:center;gap:var(--space-1);font-size:11px;color:var(--tone-amber-fg);}
.field__warn__icon{width:12px;height:12px;color:var(--amber-700);}
/* --amber-700, not --warning: WCAG 1.4.11 non-text contrast needs a 3:1 floor
   against the white field background. --warning (#f6a624) measures ~2.02:1
   there and fails; --amber-700 (#b97908) is the token this file already
   reserves for exactly this bar (see the "3:1 bar" comment on its
   definition in tokens.css) and measures ~3.62:1. */
.input--warn{border-color:var(--amber-700);}
.input--warn:focus{border-color:var(--amber-700);box-shadow:0 0 0 3px color-mix(in srgb,var(--warning) 22%,transparent);}
.link-tel,.link-mail{color:inherit;text-decoration:none;}
.link-tel:hover,.link-mail:hover{color:var(--brand-hover);text-decoration:underline;text-underline-offset:3px;}
.link-tel:focus-visible,.link-mail:focus-visible{outline:2px solid var(--focus-outline);outline-offset:2px;border-radius:var(--radius-xs);}
.link-tel--brand{color:var(--brand);}
/* `.link-mail` — the same treatment for a stored email address rendered as a
   `mailto:` link (the record rail's Lead Overview). Text first, link second,
   exactly like its `tel:` sibling above. */

/* ---------------------------------------------------- DIAL-CODE COMPOSITE
   The country dial-code select + spaced national-number input that
   au-dialcode-widget.js inserts beside the lead form's core Mobile input
   (create/edit lead only). The core input remains the posted field; these
   two nodes carry no `name` and exist only to compose its value.

   Built as a variant of `.input-group` above - the design system's existing
   "input with a leading adornment" - because that is the nearest joined
   control the system names. It is not a new primitive: the box model,
   border, radius, focus ring and type below are the `.input` / `.select`
   declarations from the FORMS block, reused through the same tokens.

   FLAT RIGHT EDGE: this sits immediately to the left of core's own
   work/home select, which core renders with `rounded-l-none`. The composite
   therefore rounds on its outer corners only and butts against that select
   exactly the way the input it stands in for did.

   --fg-strong, not --ink-900, for the text. The two are the same colour in
   light mode, but --ink-900 stays near-black under `.dark` while
   --fg-strong flips to white - nothing here should disappear in dark mode. */
.dialcode{
  display:flex; align-items:stretch; flex:1 1 auto; min-width:0;
  border:1px solid var(--border);
  border-radius:var(--radius-md) 0 0 var(--radius-md);
  background:var(--bg);
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.dialcode:hover{ border-color:var(--green-200); }
.dialcode:focus-within{ border-color:var(--focus-outline); box-shadow:0 0 0 3px var(--focus-ring); }

/* Fixed width, not auto: a select sized to its content would size to the
   widest option in a ~240-entry list. The full country name stays available
   as the option's `title`. */
.dialcode__code{
  flex:none; width:138px; max-width:45%; min-width:0;
  border:0; border-right:1px solid var(--border);
  border-radius:var(--radius-md) 0 0 var(--radius-md);
  padding:9px 32px 9px 12px;
  font:500 13px var(--font-body); color:var(--fg-strong);
  background-color:var(--bg-alt);
  cursor:pointer; text-overflow:ellipsis;
}

.dialcode__number{
  flex:1 1 auto; min-width:0;
  border:0; border-radius:0; padding:9px 12px;
  font:500 13px var(--font-body); color:var(--fg-strong);
  background-color:transparent;
}
.dialcode__number::placeholder{ color:var(--fg-subtle); }

/* The focus ring belongs to the wrapper (`:focus-within` above), so the
   inner controls suppress their own default outline. `:focus-visible` still
   draws a real one for keyboard users, inset so the joined edges hold. */
.dialcode__code:focus,
.dialcode__number:focus{ outline:none; }
.dialcode__code:focus-visible,
.dialcode__number:focus-visible{ outline:2px solid var(--focus-outline); outline-offset:-2px; }

.dialcode--disabled{ background:var(--bg-tint); border-color:var(--divider); }
.dialcode--disabled .dialcode__code,
.dialcode--disabled .dialcode__number{
  color:var(--fg-muted); background-color:transparent; cursor:not-allowed;
}

/* Mirrors core's own error state onto the composite, so a failed phone
   validation marks the field and not only the message beneath it. */
.dialcode--error{ border-color:var(--danger); }
.dialcode--error:focus-within{ box-shadow:0 0 0 3px color-mix(in srgb,var(--danger) 20%,transparent); }

/* --------------------------------------------------------- SAVE FLYOUT */
/* .cx-savebar: a form's Save/Cancel pair as a fixed card pinned bottom-right,
   hidden until the form is dirty (the owner toggles .is-dirty). First built
   inline for the lead record page's Info tab (admin/leads/view/panels/
   info.blade.php, "requirement 3"); moved here unchanged when the funding
   enquiry record page's Info form (admin/funding-enquiries/panels/
   info.blade.php) took the same flyout, so both read from one rule set.
   The form itself owns its bottom reserve (.lead-info.is-dirty,
   .fe-form-stack.is-dirty) so the bar never covers the last field.
   z-index 900 sits above page content but below the modal (1000) and all
   popovers (10500). Every value is a token, so the prefers-reduced-motion
   block that zeroes --dur-* also stills this. */
.cx-savebar {
  position: fixed; bottom: var(--space-6); right: var(--space-6);
  z-index: 900;
  padding: var(--space-3) var(--space-4);
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  transform-origin: bottom right;
  opacity: 0; transform: translateY(var(--space-3)) scale(.98);
  visibility: hidden; pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), visibility 0s linear var(--dur-fast);
}
.cx-savebar.is-dirty {
  opacity: 1; transform: translateY(0) scale(1);
  visibility: visible; pointer-events: auto;
  transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), visibility 0s linear 0s;
}
.cx-savebar__inner { display: flex; align-items: center; gap: var(--space-4); }
.cx-savebar__actions { display: flex; align-items: center; gap: var(--space-2); }
.cx-savebar__msg { font-size: .8125rem; font-weight: 600; color: var(--fg-strong); white-space: nowrap; }

/* The pair is the mockup's own density, one step below the DS md button,
   and matches the head action rail record.css already scopes. No
   --shadow-brand on the primary: this is a form-local Save, not the page's
   one lifted-off-the-page CTA, so it stays flush with its partner. */
.cx-savebar__actions .btn { padding: 8px 17px; font-size: 12.5px; }
.cx-savebar__actions .btn--primary { padding: 8px 19px; box-shadow: none; }

/* On a phone the flyout becomes a full-width sticky bottom bar and its two
   buttons split the width evenly. */
@media (max-width: 620px) {
  .cx-savebar {
    left: 0; right: 0; bottom: 0;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-inline: 0; border-bottom: 0;
    transform-origin: bottom center;
    padding-bottom: max(var(--space-3), env(safe-area-inset-bottom));
  }
  .cx-savebar__actions,
  .cx-savebar__actions .btn { flex: 1; justify-content: center; }
}

/* .cx-savebar--inline (PROFILE-PAGE-RULINGS PP4.2): the same bar placed IN FLOW as the last child of a long
   page form and made sticky to the viewport's bottom edge, instead of a fixed flyout. Being in flow it reserves
   its own height whether shown or not, so the form needs no separate bottom reserve and nothing shifts when it
   appears. z-index stays the kit's 900. On a phone it sits flush with the bottom edge. */
.cx-savebar--inline {
  position: sticky; inset-inline: auto; inset-block-end: var(--space-3);
  margin-block-start: var(--space-2);
}
@media (max-width: 620px) {
  .cx-savebar--inline { inset-block-end: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cx-savebar,
  .cx-savebar.is-dirty { transition: none; }
}
