/* ════════════════════════════════════════════════════════════════
   Killquota / Kilto design system — product stylesheet

   Source of truth: docs/UI_REFERENCE.html (viewable at /ui-reference).
   This file is the runtime contract — the reference HTML embeds an
   identical copy of these rules so the catalog renders standalone.
   Update the reference first, then mirror the changes here.

   Do NOT extend kq-*.css (legacy). Use the bare classes documented
   here: .btn, .fld, .pill, .kpi, .card, .tbl, .row-list, .tbar,
   .modal-bg/.modal, .panel-demo, .empty, .chip, .av, .step-nav, …
   ════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════ */
/* DESIGN TOKENS · use these CSS vars everywhere · never hex inline */
/* ════════════════════════════════════════════════════════════════ */
:root{
  /* Surfaces — warm paper palette */
  --bg:#f7f6f3;        /* page background — warm off-white */
  --bg2:#efedea;       /* deeper neutral surface */
  --sf:#ffffff;        /* primary surface (cards, modals) */
  --bd:#e6e3de;        /* default border — warm */
  --bd2:#d5d2cc;       /* stronger border */
  --bl:#f5f4f1;        /* low-emphasis fill (table zebra, hover, info row) */

  /* Text — warm near-black */
  --tx:#161513;        /* primary text — warm ink */
  --t2:#424140;        /* secondary text */
  --t3:#76746f;        /* tertiary text (captions, meta) */
  --t4:#a6a39d;        /* placeholder / disabled */
  --t5:#cac7c1;        /* faintest text (separators in dense UI) */

  /* Brand · default = Kilto monochrome. Per-tenant white-label overrides
     --br/--brl/--brd in resources/views/tenant/layouts/app.blade.php. */
  --br:#161513;
  --brl:#ebe7e1;
  --brd:#0a0908;
  --br-tint:#f1ede7;   /* extra-pale brand wash */

  /* Status */
  --ok:#15803d;  --okd:#14532d;  --okl:#d4ebd9;   /* success / customer */
  --wn:#b45309;  --wnd:#7c3a08;  --wnl:#fce7c5;   /* warning / interested */
  --er:#c03434;  --erd:#8a1f1f;  --erl:#f4d8d8;   /* error / declined */
  --inf:#2563eb; --infd:#1d4ed8; --infl:#dbe5fc;  /* info / visited */
  --vi:#7c3aed;  --vid:#5b21b6;  --vil:#ede9fe;   /* feature / accent violet */
  --co:#e94e2b;  --col:#fde4dd;  --cod:#c2410c;   /* coral accent (rare) */
  --cy:#06b6d4;  --cyl:#ecfeff;                   /* secondary accent */
  --wa:#25d366;  --wad:#1da851;  --wal:rgba(37,211,102,.14); --wa-text:#fff;  /* WhatsApp brand (fixed, not theme-tinted) */
  --wa-chat:#e7ded7; --wa-bub:#d9fdd3; --wa-bub-tx:#111b21; --wa-bub-meta:#667781; --wa-check:#53bdeb; /* WhatsApp chat-preview replica (fixed, mirrors WA UI) */

  /* Type stack */
  --font-display: 'Inter Tight','Outfit',system-ui,-apple-system,sans-serif;
  --font-body:    'Inter','DM Sans',system-ui,-apple-system,sans-serif;
  --font-serif:   'Fraunces',Georgia,serif;
  --font-mono:    'JetBrains Mono',ui-monospace,monospace;

  /* Font sizes */
  --fs-xxs: 10px;
  --fs-xs:  11px;
  --fs-sm:  12.5px;
  --fs-base:14px;
  --fs-md:  15px;
  --fs-lg:  17px;
  --fs-xl:  20px;
  --fs-2xl: 26px;
  --fs-3xl: 36px;
  --fs-4xl: 48px;

  /* Geometry */
  --r-sm: 6px;
  --r:    10px;
  --r-lg: 14px;
  --r-xl: 20px;

  /* Shadows (warm-tuned) */
  --shadow-sm: 0 1px 2px rgba(20,18,15,.04), 0 1px 1px rgba(20,18,15,.03);
  --shadow:    0 1px 2px rgba(20,18,15,.05), 0 4px 12px rgba(20,18,15,.06);
  --shadow-lg: 0 4px 8px rgba(20,18,15,.06), 0 20px 40px rgba(20,18,15,.10);
}

/* ════════════════════════════════════════════════════════════════ */
/* DESIGN SYSTEM CLASSES · referenced everywhere */
/* ════════════════════════════════════════════════════════════════ */

/* ── Buttons ── */
.btn{display:inline-flex;align-items:center;gap:6px;padding:8px 13px;border-radius:8px;background:var(--sf);border:1px solid var(--bd);color:var(--t2);font-family:inherit;font-weight:600;font-size:14px;cursor:pointer;transition:.12s;white-space:nowrap;text-decoration:none}
.btn:hover{border-color:var(--t4);color:var(--tx)}
.btn.primary{background:var(--br);color:var(--br-text);border-color:var(--br);font-weight:700}
.btn.primary:hover{background:var(--brd);border-color:var(--brd);color:var(--br-text)}
.btn.danger{color:var(--er);border-color:rgba(192,52,52,.32);font-weight:700}
.btn.danger:hover{background:var(--erl);border-color:var(--er)}
.btn.ok{color:var(--ok);border-color:rgba(21,128,61,.32);font-weight:700}
.btn.ok:hover{background:var(--okl);border-color:var(--ok);color:var(--okd)}
.btn.ghost{background:transparent;border-color:transparent}
.btn.ghost:hover{background:var(--bl);border-color:var(--bd)}
/* WhatsApp-branded button — instantly recognisable green. Solid for primary
   sends ("Send receipt", "Send on WhatsApp", "Remind"); .soft for icon-only /
   secondary. Works in light + dark (brand green is fixed). */
/* NB: .btn-wa is doubled (.btn.btn-wa.btn-wa = 0,3,0) on purpose — mockup-port pages
   wrap their whole stylesheet in `.kilto-preview{…}`, so their `.btn{background}` is
   really `.kilto-preview .btn` (0,2,0) and tied the single-class rule, leaving the green
   visible only on :hover. The doubled selector beats it so the brand green shows by default. */
.btn.btn-wa.btn-wa{background:var(--wa);color:var(--wa-text);border-color:var(--wa);font-weight:700}
.btn.btn-wa.btn-wa:hover{background:var(--wad);border-color:var(--wad);color:var(--wa-text)}
.btn.btn-wa.btn-wa i{color:var(--wa-text)}
.btn.btn-wa[data-busy]::after,.btn.btn-wa.is-loading::after{border-color:var(--wa-text);border-top-color:transparent}
.btn.btn-wa.btn-wa.soft{background:var(--wal);color:var(--wad);border-color:transparent}
.btn.btn-wa.btn-wa.soft:hover{background:var(--wal);border-color:var(--wa)}
.btn.btn-wa.btn-wa.soft i{color:var(--wad)}
/* WhatsApp checkbox / toggle accent — green when on */
.ckb.wa.on{background:var(--wa);border-color:var(--wa)}
.ckb.wa.on i{color:var(--wa-text)}
.btn.sm{padding:5px 10px;font-size:13px;border-radius:6px}
.btn.lg{padding:11px 17px;font-size:15px;border-radius:9px}
.btn.icon{width:32px;height:32px;padding:0;justify-content:center;border-radius:7px}
.btn.icon.sm{width:26px;height:26px;border-radius:6px}
.btn:disabled{opacity:.5;cursor:not-allowed}
/* Icon size inside a button. PROMOTED (2026-09-06) from the seven page bundles that
   all restated it identically at 12.5px — _contacts / _team / _field-sales / _settings /
   _finances / _products / _notifications, and the web source contacts-directory.css:106.
   7-of-7 unanimous, so this is the design-system value; the copies are now dropped by
   tools/web-css-sync.mjs (CONTROL_NAMES). See CSS_BUCKETS.md, bucket 2. */
.btn i{font-size:12.5px;flex-shrink:0}
/* OVERFLOW GUARD, PROMOTED (2026-09-06) out of `_team-page.css:53-54,67` where it was
   declared BARE at every width — so opening Team once made it app-wide, and navigating
   away did not undo it. Four more bundles declared the same thing inside their own phone
   step (contacts / settings / field-sales / finances); the union of the five is "always",
   which is what team wrote, so it lands here rather than in mobile.css's <=760 step.

   It is INERT unless a button would otherwise overflow its container: `.btn` above already
   says `white-space:nowrap`, and a nowrap label with nothing to catch it paints straight out
   of the button. `min-width:0` is on the SPAN, not on the button — the button keeps its
   default `min-width:auto` at desktop so nothing shrinks that did not shrink before; the
   phone step in `mobile.css` is the only place that relaxes the button itself. */
.btn{max-width:100%}
.btn > span,.btn > i + span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* FIELD SALES ghost buttons carry a visible edge. They are used standalone in map/route
   toolbars rather than grouped in a footer, where the shared borderless ghost reads as
   dead space. A real difference, so it is kept — but as a SCOPED VARIANT of the primitive
   (values from `_field-sales-page.css:1188-1189`), not as the bare `.btn.ghost` that used
   to border every ghost button in the app once Field Sales had been opened once.
   BOTH scopes: `FieldSalesScreen.vue:13667` wears `.fs-app` (23 ghost buttons) and
   `ExploreScreen.vue:644` wears `.fs-ex` (4) — scoping to `.fs-app` alone would strand
   Explore on the shared borderless form. */
.fs-app .btn.ghost,.fs-ex .btn.ghost{background:transparent;border:1px solid var(--bd);color:var(--t2)}
.fs-app .btn.ghost:hover,.fs-ex .btn.ghost:hover{background:var(--bl);color:var(--tx);border-color:var(--t4)}
/* In-flight loading state (driven by request-pipeline.js via [data-busy] or .is-loading).
   The button keeps its original size — content is made transparent and a centered
   spinner is overlaid — so the layout never jumps. Clicks are swallowed while busy. */
.btn[data-busy],.btn.is-loading{color:transparent!important;pointer-events:none;cursor:progress;position:relative}
.btn[data-busy] i,.btn.is-loading i{color:transparent!important}
.btn[data-busy]::after,.btn.is-loading::after{content:"";position:absolute;top:50%;left:50%;width:14px;height:14px;margin:-7px 0 0 -7px;border-radius:50%;border:2px solid var(--t4);border-top-color:transparent;animation:kq-btn-spin .6s linear infinite}
.btn.sm[data-busy]::after,.btn.sm.is-loading::after,.btn.icon.sm[data-busy]::after,.btn.icon.sm.is-loading::after{width:12px;height:12px;margin:-6px 0 0 -6px}
.btn.primary[data-busy]::after,.btn.primary.is-loading::after{border-color:var(--br-text);border-top-color:transparent}
.btn.danger[data-busy]::after,.btn.danger.is-loading::after{border-color:var(--er);border-top-color:transparent}
@keyframes kq-btn-spin{to{transform:rotate(360deg)}}

/* ── Inputs ── */
.fld{display:flex;flex-direction:column;gap:7px}
.fld-l{font-family:var(--font-display);font-weight:800;font-size:12px;color:var(--t3);text-transform:uppercase;letter-spacing:.07em;display:flex;align-items:center;gap:6px}
.fld-l i{font-size:12px;color:var(--t4)}
.fld-l-req::after{content:'';display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--er);margin-left:5px}
.fld-l-hint{margin-left:auto;font-size:12px;color:var(--t4);font-weight:600;text-transform:none;letter-spacing:0;font-family:var(--font-body)}
.fld-in{width:100%;padding:9px 12px;border-radius:8px;border:1px solid var(--bd);background:var(--sf);font-family:inherit;font-size:14.5px;color:var(--tx);outline:none;transition:.12s;font-weight:500}
.fld-in:focus{border-color:var(--br);box-shadow:0 0 0 3px var(--brl)}
.fld-in::placeholder{color:var(--t4);font-weight:400}
.fld-in:disabled{background:var(--bl);color:var(--t4);cursor:not-allowed}
.fld-in.mono{font-family:var(--font-mono);font-weight:500}
/* THE TEXTAREA — the `.fld-in` box plus the three properties only a textarea needs. Promoted
   here because it was the one member of this family the shared layer never owned: `.fld`,
   `.fld-l` and `.fld-in` all live above, while `.fld-ta` was declared BARE by three page
   bundles (_field-sales, _products, _settings) and by nothing shared. Each of those is a
   lazily-loaded route chunk that never unloads, so the textarea a user saw was decided by
   which screen they had visited last — measured on PROD, same `/app/tasks` DOM: direct load
   gave `min-height:0; padding:2px; border-radius:0; monospace 13.3px; resize:both` (a raw
   browser default — 0 matching CSSOM rules), while arriving via Products gave `74px / 9px 12px
   / 8px / Inter 14.5px / vertical`. 16 SPA components render `.fld-ta` and only three screens
   supplied it, so most of them were unstyled until an unrelated screen happened to load.
   Values are the CONSENSUS of the three, not one screen's taste: the box is byte-identical to
   `.fld-in` (which is what the settings bundle's own `.fld-in,.fld-ta,.fld-sel` base already
   said), `resize:vertical` was unanimous, `line-height:1.5` and `font-size` follow the
   majority. `min-height` spread 74/80/90 with no consensus, so 80px is the median rather than
   a pick. The `.mono` modifier mirrors `.fld-in.mono` and is what preserves the settings hub's
   13px monospace textarea — its bundle's bare copy is dropped in web-css-sync's CONTROL_NAMES,
   and the SPA settings screen renders no `.fld-ta` at all, so nothing regresses. */
.fld-ta{width:100%;padding:9px 12px;border-radius:8px;border:1px solid var(--bd);background:var(--sf);font-family:inherit;font-size:14.5px;color:var(--tx);outline:none;transition:.12s;font-weight:500;min-height:80px;resize:vertical;line-height:1.5}
.fld-ta:focus{border-color:var(--br);box-shadow:0 0 0 3px var(--brl)}
.fld-ta::placeholder{color:var(--t4);font-weight:400}
.fld-ta:disabled{background:var(--bl);color:var(--t4);cursor:not-allowed}
.fld-ta.mono{font-family:var(--font-mono);font-size:13px;line-height:1.55}
.fld-row{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.fld-row.three{grid-template-columns:repeat(3,1fr)}
/* Vertical rhythm between stacked fields. Promoted from `_team-page.css`, which was the ONLY
   bundle shipping it BARE (`team/index.blade.php:300 .fld{margin-bottom:14px}`): because a route
   chunk's sheet loads last and never unloads, visiting Team once gave EVERY `.fld` in the app a
   14px margin. Every other bundle scopes the identical 14px to an ancestor (`#adsmod .fld`,
   `.fnb-body .fld`, `.qb-body .fld`, `.rbx-body .fld`, `.sp2-mockup .fld`, `.tm42-mod .fld`,
   `.wbv3 .fld`, `#cbmock .fld`) and the shared layer supplied none — so the app-wide margin was
   unwanted, and two SFCs paid a tax to cancel it (`SpSmmPane.vue:847`, `ExploreScreen.vue:936`).

   Measured before dropping the bare copy: 37 field sites in 16 wrappers across 11 files had no
   other source of spacing (`.analysis/fldwrappers.mjs`). Those wrappers opt in explicitly here.
   The rhythm sits on the FIELDS, not as a `gap` on the wrapper, because several of these wrappers
   also hold non-field siblings that already carry their own margin (`.photo-row` in the staff
   editor is `margin-bottom:14px`) — a wrapper gap would silently double those to 28px.

   Child combinator, and the zero-out is keyed to the FIELD classes, to reproduce the leaked
   semantics exactly and nothing more: a `.fld` nested inside a `.fld-row` is not a direct child
   so it never takes the margin (the leak spent a rule undoing that), and a bare `> :last-child`
   would zero a trailing non-field's OWN margin, which the leak never did. */
.fld-stack > .fld,.fld-stack > .fld-row{margin-bottom:14px}
.fld-stack > .fld:last-child,.fld-stack > .fld-row:last-child{margin-bottom:0}
.fld-help{font-size:13px;color:var(--t3);font-weight:500;line-height:1.4;display:flex;align-items:center;gap:5px}
.fld-help i{font-size:12px;color:var(--t4)}

/* Tooltip — hover-only dark pill */
.tip{position:relative;display:inline-block}
.tip-bubble{position:absolute;left:calc(100% + 9px);top:50%;transform:translateY(-50%);background:var(--tx);color:#fff;padding:5px 10px;border-radius:6px;font-size:13px;font-weight:600;white-space:nowrap;box-shadow:0 4px 14px rgba(20,18,15,.18);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .15s,visibility .15s;z-index:50}
.tip-bubble.below{left:50%;top:calc(100% + 7px);transform:translateX(-50%) translateY(0)}
.tip-bubble.wide{white-space:normal;width:240px;line-height:1.55;font-weight:500}
.tip:hover>.tip-bubble,.tip:focus-within>.tip-bubble{opacity:1;visibility:visible}
.fld-err{color:var(--er);font-size:13px;font-weight:600;display:flex;align-items:center;gap:5px}
textarea.fld-in{resize:vertical;min-height:60px;line-height:1.5}
select.fld-in{cursor:pointer;-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='%23a1a1aa' stroke-width='1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;background-size:12px;padding-right:28px}

/* Toggle switch */
.switch{position:relative;width:38px;height:22px;background:var(--bd);border-radius:99px;cursor:pointer;transition:.18s;flex-shrink:0;border:0;padding:0}
.switch::after{content:'';position:absolute;top:2px;left:2px;width:18px;height:18px;background:#fff;border-radius:50%;box-shadow:0 1px 3px rgba(20,18,15,.18);transition:.18s}
.switch.on{background:var(--br)}
.switch.on::after{transform:translateX(16px)}
.switch.sm{width:30px;height:18px}
.switch.sm::after{width:14px;height:14px}
.switch.sm.on::after{transform:translateX(12px)}

/* Checkbox */
.ckb{width:18px;height:18px;border-radius:5px;border:1.5px solid var(--bd);display:inline-flex;align-items:center;justify-content:center;color:#fff;flex-shrink:0;transition:.12s;cursor:pointer;background:var(--sf)}
.ckb i{font-size:11px;opacity:0;transition:.1s}
.ckb.on{background:var(--br);border-color:var(--br)}
.ckb.on i{opacity:1}

/* Radio chip row */
.chip{display:inline-flex;align-items:center;gap:6px;padding:7px 13px;border-radius:8px;border:1px solid var(--bd);background:var(--sf);font-family:inherit;font-weight:700;font-size:14px;color:var(--t2);cursor:pointer;transition:.12s}
.chip:hover{border-color:var(--t4);color:var(--tx)}
.chip i{font-size:10px}
.chip.sel{background:var(--brl);border-color:var(--br);color:var(--brd)}
.chip.sel.ok{background:var(--okl);border-color:var(--ok);color:var(--ok)}
.chip.sel.wn{background:var(--wnl);border-color:var(--wn);color:var(--wnd)}
.chip.sel.er{background:var(--erl);border-color:var(--er);color:var(--er)}
.chip.sel.inf{background:var(--infl);border-color:var(--inf);color:var(--inf)}

/* Color picker */
.cp-row{display:flex;gap:6px;flex-wrap:wrap}
.cp-chip{width:30px;height:30px;border-radius:8px;cursor:pointer;border:2px solid #fff;box-shadow:0 0 0 1.5px var(--bd);transition:.12s}
.cp-chip:hover{transform:scale(1.08)}
.cp-chip.sel{box-shadow:0 0 0 1.5px var(--tx),0 0 0 4px var(--brl)}

/* Tag input */
.tag-row{display:flex;flex-wrap:wrap;gap:5px;padding:7px 9px;border:1px solid var(--bd);border-radius:8px;background:var(--sf);min-height:40px;align-items:center;transition:.12s}
.tag-row:focus-within{border-color:var(--br);box-shadow:0 0 0 3px var(--brl)}
.tag-chip{display:inline-flex;align-items:center;gap:5px;padding:2px 7px;border-radius:5px;background:var(--bl);color:var(--t2);font-family:var(--font-display);font-weight:700;font-size:11.5px;letter-spacing:.01em}
.tag-chip i{font-size:9px}
.tag-chip.br{background:var(--brl);color:var(--brd)}
.tag-chip-x{background:transparent;border:0;color:var(--brd);cursor:pointer;display:flex;align-items:center;justify-content:center;width:14px;height:14px;border-radius:3px;font-size:11px;opacity:.7}
.tag-chip-x:hover{opacity:1}
.tag-in{flex:1;min-width:80px;border:0;outline:0;background:transparent;font-family:inherit;font-size:14.5px;color:var(--tx);padding:2px 4px;font-weight:500}

/* Tag (inline-row variant — production canonical, color set per-instance via inline style) */
.tag{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:5px;font-family:var(--font-display);font-weight:700;font-size:11px;letter-spacing:.01em;white-space:nowrap}
.tag .dot{width:6px;height:6px;border-radius:50%}
.tag.more{background:var(--bl);color:var(--t3);font-weight:700}

/* Source pill — icon + label, neutral row-inline */
.src{display:inline-flex;align-items:center;gap:5px;font-family:var(--font-display);font-weight:600;font-size:12.5px;color:var(--t2)}
.src i{font-size:11.5px;color:var(--t3);width:14px;text-align:center}

/* Score badge — number + colored dot */
.sc{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-mono);font-weight:700;font-size:13px}
.sc .sc-dot{width:8px;height:8px;border-radius:50%}

/* Channel mini-icons (small icon buttons in row) */
.chans{display:inline-flex;gap:5px;align-items:center}
.chan{width:22px;height:22px;border-radius:6px;display:inline-flex;align-items:center;justify-content:center;font-size:10.5px;border:1px solid var(--bd);background:var(--sf);color:var(--t4)}
.chan.on{background:var(--brl);color:var(--brd);border-color:rgba(9,9,11,.18)}
.chan.on.wa{color:var(--ok);background:var(--okl);border-color:rgba(21,128,61,.22)}

/* Row action icon button (.row-ic) — table row hover-actions */
.row-act{display:inline-flex;gap:4px;justify-content:flex-end}
.row-ic{width:28px;height:28px;border-radius:6px;border:1px solid transparent;background:transparent;color:var(--t3);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:12px;transition:.1s}
.row-ic:hover{background:var(--bl);color:var(--tx);border-color:var(--bd)}

/* Value group (currency + amount + frequency) */
.val-grp{display:grid;grid-template-columns:70px 1fr 130px;gap:6px}
.val-cur{padding:9px 11px;border-radius:8px;border:1px solid var(--bd);background:var(--sf);font-family:var(--font-display);font-weight:800;font-size:15px;color:var(--tx);cursor:pointer;display:flex;align-items:center;justify-content:space-between}
.val-cur:hover{border-color:var(--t4)}
.val-cur i{font-size:11px;color:var(--t4)}
.val-amt{padding:9px 12px;border-radius:8px;border:1px solid var(--bd);background:var(--sf);font-family:var(--font-mono);font-weight:600;font-size:16px;color:var(--tx);outline:none;text-align:right;letter-spacing:-.005em}
.val-amt:focus{border-color:var(--br);box-shadow:0 0 0 3px var(--brl)}
.val-freq{padding:9px 11px;border-radius:8px;border:1px solid var(--bd);background:var(--sf);font-family:inherit;font-weight:600;font-size:14px;color:var(--tx);cursor:pointer;outline:none;-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='%23a1a1aa' stroke-width='1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 9px center;background-size:12px;padding-right:26px}

/* ── Pills · status / role / generic ── */
.pill{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:5px;background:var(--bl);color:var(--t2);font-family:var(--font-display);font-weight:800;font-size:11px;letter-spacing:.05em;text-transform:uppercase;white-space:nowrap}
.pill i{font-size:10px}
.pill.ok{background:var(--okl);color:var(--okd)}
.pill.wn{background:var(--wnl);color:var(--wnd)}
.pill.er{background:var(--erl);color:var(--erd)}
.pill.inf{background:var(--infl);color:var(--infd)}
.pill.vi{background:var(--vil);color:var(--vid)}
.pill.cy{background:var(--cyl);color:var(--cy)}
.pill.br{background:var(--brl);color:var(--brd)}
.pill.lg{padding:3px 10px;font-size:12.5px}
.pill.dot::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block}

/* Notification badge (small) */
.nbadge{display:inline-flex;align-items:center;justify-content:center;background:var(--er);color:#fff;font-family:var(--font-display);font-weight:800;font-size:11.5px;min-width:18px;height:16px;padding:0 5px;border-radius:8px;letter-spacing:.02em;font-feature-settings:'tnum'}
.nbadge.br{background:var(--br)}
.nbadge.t{background:var(--t2)}

/* "Soon" pill */
.soon{background:var(--bg2);color:var(--t4);font-family:var(--font-display);font-weight:800;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;padding:1px 6px;border-radius:4px}

/* "Root" pill (privileged) */
.root-pill{font-family:var(--font-display);font-size:10.5px;font-weight:900;letter-spacing:.07em;color:var(--er);background:var(--erl);padding:2px 6px;border-radius:4px;text-transform:uppercase}

/* Territory / category chip (color-coded) */
.terr-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:5px;background:var(--c,var(--bl))22;color:var(--c,var(--t2));font-family:var(--font-display);font-weight:700;font-size:12px;letter-spacing:.02em}
.terr-chip i{font-size:10.5px}
.terr-chip::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--c,var(--t4))}

/* ── Avatars ── */
.av{border-radius:50%;color:#fff;display:inline-flex;align-items:center;justify-content:center;font-family:var(--font-display);font-weight:800;flex-shrink:0;position:relative;letter-spacing:-.01em}
.av.sq{border-radius:9px}
.av.xs{width:18px;height:18px;font-size:10.5px}
.av.sm{width:28px;height:28px;font-size:12px}
.av.md{width:36px;height:36px;font-size:13px}
.av.lg{width:44px;height:44px;font-size:15.5px;border-radius:11px}
.av.xl{width:54px;height:54px;font-size:19px;border-radius:13px}
.av-status{position:absolute;bottom:-1px;right:-1px;width:9px;height:9px;border-radius:50%;background:var(--t4);border:2px solid var(--sf)}
.av-status.active{background:var(--ok)}
.av-status.idle{background:var(--wn)}
.av-status.offline{background:var(--t4)}
.av-stack{display:flex}
.av-stack .av{border:2px solid var(--sf);margin-left:-7px}
.av-stack .av:first-child{margin-left:0}
.av-more{background:var(--bl);color:var(--t3)}

/* -- Avatar, scoped variant ---------------------------------------------------------------
   ONE screen's avatar genuinely differs from the ladder above: the settings hub paints its
   badges with a flat charcoal gradient instead of the per-entity colour every other screen
   passes inline. It used to say so with a BARE `.av{background:linear-gradient(...)}` in
   `_settings-page.css`, which made that gradient the app-wide avatar background the moment
   Settings was opened once -- so Finances, Commissions and Tasks rendered white initials on a
   dark badge for anyone who had visited Settings and white-on-transparent for anyone who had
   not. Same DOM, same sheets, only navigation order. It is kept, because the difference is
   real, but as a SCOPED VARIANT of the shared primitive, reached only under the class both
   `SettingsScreen.vue:1112` and `MemberSettingsScreen.vue:325` already put on <Page> (and
   which `providePageScope('kilto-settings-scope')` re-applies inside teleported modals).
   Nothing here introduces a new value; every number was read off the bundle it replaces.

   SPECIFICITY, read before touching: the scope is wrapped in `:where()` on purpose. The bundle
   rules these replace were `.av` (0,1,0) and `.av.lg` (0,2,0); writing the scope bare would
   lift the base to (0,2,0), where its `width:32px` would outrank the shared `.av.md`/`.av.xl`
   size ladder and silently resize any sized badge a future settings pane renders. `:where()`
   contributes zero, so each rule keeps the exact weight -- and the exact cascade position --
   the bundle rule had, and wins only because it is declared later than its shared twin.

   `width/height:32px` is the bundle's default size for an UNSIZED `.av`; the shared base
   deliberately carries no size at all. The web still renders one (`shared/settings/index
   .blade.php:3168`, the "Connected as" check badge), so the default is preserved rather than
   dropped with the rest.

   DROPPED WITHOUT PROMOTION, because nothing renders them on either surface: the bundle's
   `.av.sm{26px/10px}` (no `av sm` under this scope in the blade, the screen, the member portal
   or any of the eight panes) and its `.av-stack` trio (`index.blade.php:586-588` styles a stack
   the settings markup never builds). Promoting dead vocabulary would only re-create the drift
   in a new place. */
:where(.kilto-settings-scope) .av{width:32px;height:32px;background:linear-gradient(135deg,#3a3935,#161513);display:flex;font-family:Outfit;font-size:12px}
:where(.kilto-settings-scope) .av.lg{width:44px;height:44px;font-size:15px}
@media (max-width:480px){:where(.kilto-settings-scope) .av.lg{width:38px;height:38px;font-size:13px}}

/* ── KPI card ── */
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:11px;margin:8px 0 18px}
.kpis.cols-3{grid-template-columns:repeat(3,1fr)}
.kpis.cols-2{grid-template-columns:repeat(2,1fr)}
.kpi{background:var(--sf);border:1px solid var(--bd);border-radius:13px;padding:15px 17px;display:flex;align-items:center;gap:13px;transition:.14s}
.kpi:hover{border-color:var(--t4)}
.kpi-ic{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;background:var(--brl);color:var(--br)}
.kpi-ic.co{background:var(--col);color:var(--co)}
.kpi-ic.ok{background:var(--okl);color:var(--ok)}
.kpi-ic.wn{background:var(--wnl);color:var(--wnd)}
.kpi-ic.er{background:var(--erl);color:var(--erd)}
.kpi-ic.inf{background:var(--infl);color:var(--infd)}
.kpi-ic.vi{background:var(--vil);color:var(--vid)}
.kpi-info{flex:1;min-width:0}
.kpi-v{font-family:var(--font-serif);font-weight:600;font-size:30px;color:var(--tx);letter-spacing:-.022em;line-height:1;font-feature-settings:'tnum';display:flex;align-items:baseline;gap:6px;flex-wrap:wrap}
.kpi-v small{font-family:var(--font-display);font-weight:700;font-size:14px;color:var(--t3);letter-spacing:0}
.kpi-l{font-size:12px;color:var(--t3);font-weight:700;text-transform:uppercase;letter-spacing:.05em;margin-top:6px;line-height:1.2}
.kpi-sub{font-size:12px;color:var(--t3);font-weight:500;margin-top:3px}
.kpi-sub strong{font-family:var(--font-display);font-weight:700;color:var(--tx)}
.kpi-delta{font-size:11.5px;font-weight:800;font-family:var(--font-display);display:inline-flex;align-items:center;gap:3px;padding:1px 6px;border-radius:4px;letter-spacing:.01em}
.kpi-delta.up{color:var(--ok);background:var(--okl)}
.kpi-delta.dn{color:var(--er);background:var(--erl)}
.kpi-delta i{font-size:8.5px}

/* ── Stat block (3-up / 4-up) ── */
.stat-grid{display:grid;gap:7px;padding:11px;background:var(--bl);border-radius:9px}
.stat-grid.col-3{grid-template-columns:repeat(3,1fr)}
.stat-grid.col-4{grid-template-columns:repeat(4,1fr)}
.stat-item{text-align:center}
.stat-v{font-family:var(--font-display);font-weight:900;font-size:19px;color:var(--tx);letter-spacing:-.018em;line-height:1}
.stat-l{font-size:11.5px;color:var(--t3);font-weight:700;text-transform:uppercase;letter-spacing:.05em;margin-top:3px}

/* ── Card (generic) ── */
.card{background:var(--sf);border:1px solid var(--bd);border-radius:13px;padding:18px 20px}
.card-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;margin-bottom:14px}
.card-eyebrow{font-family:var(--font-mono);font-weight:600;font-size:10.5px;color:var(--t4);text-transform:uppercase;letter-spacing:.12em;margin-bottom:5px}
.card-t{font-family:var(--font-display);font-weight:800;font-size:17px;color:var(--tx);letter-spacing:-.012em;line-height:1.2}
.card-t em{font-style:italic;font-family:var(--font-serif);font-weight:600;color:var(--co)}
.card-s{font-size:13.5px;color:var(--t3);font-weight:500;margin-top:4px;line-height:1.55}
.card-s strong{font-family:var(--font-display);font-weight:700;color:var(--tx)}
.card-act{display:flex;align-items:center;gap:7px;flex-shrink:0}
.card-link{background:transparent;border:0;color:var(--brd);font-family:var(--font-display);font-weight:700;font-size:13px;cursor:pointer;padding:4px 8px;border-radius:6px;transition:.12s;display:inline-flex;align-items:center;gap:4px}
.card-link:hover{background:var(--brl);color:var(--co)}
.card-link i{font-size:10px}
.card-sub{font-size:14px;color:var(--t3);font-weight:500;margin-top:3px;line-height:1.5}
.card.hover{cursor:pointer;transition:.14s}
.card.hover:hover{border-color:var(--t4);box-shadow:0 4px 14px rgba(20,18,15,.05)}
.card.sel{border-color:var(--br);box-shadow:0 0 0 3px var(--brl)}

/* ── Table ── */
.tbl-wrap{background:var(--sf);border:1px solid var(--bd);border-radius:13px;overflow:hidden;flex-shrink:0}
.tbl{width:100%;border-collapse:collapse;font-size:14px}
.tbl thead th{padding:11px 14px;text-align:left;background:var(--bl);font-family:var(--font-display);font-weight:800;font-size:11.5px;color:var(--t3);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--bd);white-space:nowrap}
.tbl thead th.sortable{cursor:pointer;user-select:none}
.tbl thead th.sortable:hover{color:var(--tx)}
.tbl thead th.sortable i{margin-left:5px;font-size:10px;color:var(--t4);opacity:.7}
.tbl thead th.num{text-align:right}
.tbl thead th.ckb-col{width:36px;padding-right:6px}
.tbl tbody td{padding:11px 14px;border-bottom:1px solid var(--bl);vertical-align:middle;color:var(--tx);font-size:14px}
.tbl tbody td.num{text-align:right;font-family:var(--font-mono);font-weight:600;font-feature-settings:'tnum'}
.tbl tbody td.ckb-col{padding-right:6px}
.tbl tbody td.mono{font-family:var(--font-mono);font-weight:500}
.tbl tbody td.muted{color:var(--t3)}
.tbl tbody tr{cursor:pointer;transition:.1s}
.tbl tbody tr:hover{background:var(--bl)}
.tbl tbody tr.sel{background:var(--brl)}
/* `.sel` and `.selected` are the SAME state under two spellings. Four screens render `.selected`
   (Contacts, Organizations, Tasks, Finances) and the shared layer only knew `.sel`, so those rows
   were highlighted solely by `_finances-page.css`'s bare `.tbl tbody tr.selected` -- i.e. only
   after Finances had been visited. Both spellings owned here so the highlight is not a function
   of navigation order. */
.tbl tbody tr.selected{background:var(--brl)}
.tbl tbody tr.selected:hover{background:var(--brl)}
.tbl tbody tr:last-child td{border-bottom:0}

/* THE STATIC VARIANT -- audit B.4. `.tbl tbody tr` sets `cursor:pointer` unconditionally, so a
   READ-ONLY report table wearing `.tbl` promises a click it does not have: 19 of 82 data rows
   had neither a row `@click` nor a per-row control, and every one of them showed a hand cursor.
   The 17 tables that skipped `.tbl` altogether are near-totally the same tables, so the fix
   cannot be `migrate them all to .tbl` -- that would ADD 17 misleading cursors. `.is-static`
   legitimises the read-only table instead: same grammar, same padding, same header, minus the
   affordance. `<DataTable>` applies it automatically whenever no `rowClick` is passed, which is
   what keeps the promise and the handler from ever disagreeing.
   The hover tint stays: it is orientation across a wide row, not a claim that the row is a button. */
.tbl.is-static tbody tr{cursor:default}

/* <DataTable>'s own switcher row -- the ONLY two rules the shared list surface needs that the
   kit did not already own. The control itself is `.fbar-views`/`.fbar-view-btn` verbatim (see
   :1137); this is just the line it sits on when a page has no <FilterBar> to host it. Lives
   here rather than in a <style> block on the component, because a component that ships CSS is
   how the kit gets forked -- which is the entire defect family B exists to close. */
.kq-dt-bar{display:flex;justify-content:flex-end;margin-bottom:10px}
.kq-dt-bar:empty{display:none}


/* Row identity -- the name/sub pair a table cell renders. Five bundles shipped byte-identical
   copies of this (commissions, courses, field-sales, team, plus scoped telephony/inbox variants);
   two of them (`_field-sales-page.css`, `_team-page.css`) shipped it UNSCOPED, so `.tbl .t-name`
   (0,2,0) beat team's own bare `.t-name` (0,1,0) and stripped `white-space:nowrap` from TeamScreen
   the moment Field Sales had been opened. Owned here, once. A page that needs a different value
   scopes it (`#phonehub .t-name`), never restates the bare form. */
.t-name{font-family:var(--font-display);font-weight:700;font-size:14px;color:var(--tx);letter-spacing:-.005em}
.t-sub{font-size:12px;color:var(--t3);font-weight:500;margin-top:2px}

/* ── Table, scoped variants ──────────────────────────────────────────────────
   Three screens' tables genuinely differ from the grammar above. They used to say so with BARE
   `.tbl` rules in their own page bundles, which made each divergence app-wide the moment that
   screen was opened — the render depended on navigation order. They are kept, because the
   differences are real, but as SCOPED VARIANTS of the shared primitive: the same declarations,
   reached only under the class the screen's `<Page>` already carries. Nothing here introduces a
   new value; every number was read off the bundle it replaces.

   SETTINGS — `.kilto-settings-scope`, worn by BOTH `SettingsScreen.vue:1112` and
   `MemberSettingsScreen.vue:325`, so the variant covers the member portal too. Sole renderer is
   `settings/panes/DataPane.vue:279`. It diverges in VALUES, not just in the 20px edge insets:
   separate borders, wider cell padding, a smaller body size and the secondary text colour. */
.kilto-settings-scope .tbl{border-collapse:separate;border-spacing:0}
.kilto-settings-scope .tbl thead th{padding:11px 16px}
.kilto-settings-scope .tbl thead th:first-child{padding-left:20px}
.kilto-settings-scope .tbl thead th:last-child{padding-right:20px}
.kilto-settings-scope .tbl tbody td{padding:13px 16px;font-size:13.5px;color:var(--t2)}
.kilto-settings-scope .tbl tbody td:first-child{padding-left:20px}
.kilto-settings-scope .tbl tbody td:last-child{padding-right:20px}
.kilto-settings-scope .rs-card > .tbl{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch}

/* FINANCES — `.kilto-preview`, worn by `FinancesScreen.vue`'s `<Page>` root (and by the Blade
   twin, tenant/finances/index.blade.php). A wide ledger: it needs a sticky header row and a much
   larger floor than the shared 680px because of its column count. */
.kilto-preview .tbl{min-width:1100px}
.kilto-preview .tbl thead th{position:sticky;top:0;z-index:2}

/* FIELD SALES — `.fs-app`, worn by `FieldSalesScreen.vue:13667`. */
.fs-app .tbl{min-width:760px}

/* ── List row (visit feed style) ── */
.row-list{background:var(--sf);border:1px solid var(--bd);border-radius:13px;overflow:hidden}
.row-item{display:flex;align-items:flex-start;gap:11px;padding:13px 16px;border-bottom:1px solid var(--bl);cursor:pointer;transition:.1s}
.row-item:hover{background:var(--bl)}
.row-item:last-child{border-bottom:0}

/* ── Progress bar ── */
.pbar{height:5px;border-radius:3px;background:var(--bg2);overflow:hidden}
.pbar-fill{height:100%;background:var(--br);border-radius:3px;transition:.4s}
.pbar.lg{height:8px;border-radius:4px}

/* ── Step nav (wizard) ── */
.step-nav{display:flex;align-items:center;gap:0;padding:14px 0;width:100%}
.step{flex:1 1 0;display:flex;align-items:center;gap:9px;position:relative;min-width:0}
.step:last-child{flex:0 0 auto}
.step:last-child .step-line{display:none}
.step-num{width:26px;height:26px;border-radius:50%;background:var(--sf);border:2px solid var(--bd);display:flex;align-items:center;justify-content:center;font-family:var(--font-display);font-weight:900;font-size:13px;color:var(--t4);flex-shrink:0;transition:.18s}
.step.done .step-num{background:var(--ok);border-color:var(--ok);color:#fff}
.step.active .step-num{background:var(--br);border-color:var(--br);color:#fff;box-shadow:0 0 0 4px var(--brl)}
.step-body{display:flex;flex-direction:column;line-height:1.2;flex-shrink:0}
.step-l{font-family:var(--font-display);font-weight:800;font-size:13px;color:var(--t3);text-transform:uppercase;letter-spacing:.04em;white-space:nowrap}
.step.active .step-l{color:var(--brd)}
.step.done .step-l{color:var(--ok)}
.step-line{flex:1 1 0;height:2px;background:var(--bd);margin:0 14px;border-radius:2px;min-width:14px}
.step.done .step-line{background:var(--ok)}

/* ── Toast ── */
.toast-x{display:inline-flex;align-items:center;gap:8px;background:var(--tx);color:#fff;padding:10px 18px;border-radius:9px;font-size:15px;font-weight:500;box-shadow:0 8px 24px rgba(20,18,15,.22)}
.toast-x i.ok{color:var(--ok)}
.toast-x i.er{color:var(--er)}
.toast-x i.wn{color:var(--wn)}

/* ── Empty state ── */
.empty{padding:36px 24px;text-align:center;color:var(--t3);font-size:14.5px;display:flex;flex-direction:column;align-items:center;gap:11px}
.empty-ic{width:50px;height:50px;border-radius:14px;background:var(--bl);color:var(--t4);display:flex;align-items:center;justify-content:center;font-size:22px}
.empty-t{font-family:var(--font-serif);font-weight:600;font-size:20px;color:var(--tx);letter-spacing:-.018em;line-height:1.15}
.empty-t em{font-style:italic;color:var(--co);font-weight:500}
/* `font-weight:500` PROMOTED (2026-09-06). Every OTHER secondary-text class in this sheet
   already carries it — `.card-s`:342, `.t-sub`:386, `.page-hd-s`:551, `.panel-s`:897,
   `.fld-help`:171 — and `.empty-s` was the one that did not, so eight page bundles set it
   for themselves (settings, notifications, automations, commissions, courses,
   social-planner, trading, plus the `*-empty-s` forks in assistant/deals/setup/inbox).
   Bucket 2: the pages agree and the shared layer was stale. Promoted at the unanimous
   value; the copies are dropped by tools/web-css-sync.mjs. INTENDED DELTA: empty-state
   hint text moves 400 → 500 on the screens that were not already overriding it. */
.empty-s{font-size:var(--fs-sm);color:var(--t3);max-width:420px;line-height:1.5;font-weight:500}
/* THE BARE-ICON EMPTY STATE. Two forms are in use and both are legitimate: the chip
   (`.empty-ic`, a 50px tinted square) and a plain glyph with no box, which is what the ten
   settings panes render. Only the chip had a shared size, so `_settings-page.css` declared
   the bare one for itself — BARE, which made it app-wide the moment Settings was opened.
   MEASURED: 15 sites render an `<i>` directly inside `.empty`, ten of them settings panes.
   Promoted here at settings' own value; the copy is dropped by tools/web-css-sync.mjs.

   `:where(i)` keeps this at (0,1,0) on purpose, so a component that names its own glyph
   still wins on source order rather than needing to out-specify the design system —
   `.cpick-empty-ic` (22px) and `.mp-source-card.empty i` (18px) are the two that do. */
.empty :where(i){font-size:34px;color:var(--t4)}

/* FIELD SALES — `.fs-app`, worn by `FieldSalesScreen.vue:13667`. Its empty states sit
   loose in a scrolling feed rather than inside a card, so the state itself carries the
   card edge. A real per-screen difference, kept as a SCOPED VARIANT of the primitive
   (values read off `_field-sales-page.css:260` before it was dropped) rather than as the
   bare `.empty` redefinition that used to reach all 59 empty states in the app. */
.fs-app .empty{background:var(--sf);border:1px solid var(--bd);border-radius:13px}

/* ── Toolbar (filter bar) — sticky production canonical ── */
.tbar{background:var(--bg);padding:13px 28px;display:flex;align-items:center;gap:7px;flex-wrap:wrap;flex-shrink:0;position:sticky;top:0;z-index:5}
.tbar-tabs{display:flex;gap:1px;background:var(--bl);padding:3px;border-radius:8px;border:1px solid var(--bd)}
.tbar-tab{padding:5px 12px;border-radius:6px;border:0;background:transparent;color:var(--t3);font-family:inherit;font-size:13.5px;font-weight:600;cursor:pointer;transition:.12s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.tbar-tab:hover{color:var(--tx)}
.tbar-tab.active{background:var(--br);color:var(--br-text);box-shadow:0 1px 3px rgba(0,0,0,.16);font-weight:700}
.tbar-tab.active i{color:var(--br-text)}
.tbar-tab i{font-size:12px;color:var(--t4)}
.tbar-sep{width:1px;height:22px;background:var(--bd);margin:0 4px}
.tbar-act-sep{width:1px;height:22px;background:var(--bd);margin:0 6px}
.tbar-sp{flex:1}
.tbar-sr{display:inline-flex;align-items:center;gap:7px;padding:6px 11px;border-radius:7px;background:var(--sf);border:1px solid var(--bd);min-width:220px}
.tbar-sr input{flex:1;background:none;border:0;outline:0;font-family:inherit;font-size:13.5px;color:var(--tx);font-weight:500}
.tbar-sr input::placeholder{color:var(--t4)}
.tbar-sr i{font-size:13px;color:var(--t3)}

/* ── Filter pill (.tb-pill) — toolbar dropdown trigger ── */
.tb-pill{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:7px;background:var(--sf);border:1px solid var(--bd);color:var(--t2);font-family:inherit;font-weight:600;font-size:13.5px;cursor:pointer;transition:.12s;white-space:nowrap}
.tb-pill:hover{border-color:var(--t4);color:var(--tx)}
.tb-pill.active{background:var(--brl);color:var(--brd);border-color:rgba(9,9,11,.22)}
.tb-pill.active > i:first-child{color:var(--co)}
.tb-pill.on{background:var(--br);color:#fff;border-color:var(--br);font-weight:700}
.tb-pill .ct{display:inline-flex;align-items:center;justify-content:center;min-width:17px;height:17px;padding:0 5px;border-radius:9px;background:var(--br);color:#fff;font-family:var(--font-mono);font-size:10.5px;font-weight:700;margin-left:1px}
.tb-pill.active .ct{background:var(--co)}
.tb-pill .chev{font-size:10px;margin-left:1px;color:var(--t4)}
.tb-pill.active .chev{color:var(--brd)}

/* ── Page header / tab header ── */
.page-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:16px;flex-wrap:wrap}
/* Page-shell BAND — the shared DEFAULT for every <x-page> scaffold page.
   Historically each page re-declared this block in its own scope (Tasks .tm2,
   contacts-directory, …) and any page that forgot rendered a BARE header
   (padding 0, no gradient — the Team Feed bug, five review rounds).

   SPECIFICITY, read before touching: the selector is :where(.page-body)>.page-hd
   on purpose. :where() contributes ZERO, so this rule sits at (0,1,0) — the same
   weight as a bare `.page-hd{…}` in a page's own stylesheet. Page CSS loads via
   @stack('styles') (tenant/layouts/app.blade.php:818) AFTER this sheet (:323),
   so a page that re-declares the band ALWAYS wins the tie, whatever selector
   shape it uses — bare `.page-hd` (contact-profile, contacts-directory,
   field-sales/preview, finances, reports, products, team) just as much as a
   scoped `.tm2 .page-hd`. Writing `.page-body>.page-hd` here instead would be
   (0,2,0) and would silently OVERRIDE every bare-selector page — that shipped
   once and flipped contact-profile's deliberately flat header into a gradient
   band on a live route.

   Deliberately NOT set here: margin-bottom. The base `.page-hd` rule above gives
   every page the canonical 16px gap under the band (that is what Tasks and every
   other band page has always rendered); overriding it to 0 from this shared rule
   would shift the content of ~15 pages up 16px for free. A page that genuinely
   wants a flush band declares margin-bottom:0 in its own scope.

   Also deliberately NOT set here: the <=760 border-bottom hairline that the
   Tasks/Feed mobile bands draw. Every other property below is one that band
   pages routinely declare themselves, so their own value wins the tie; but a
   sweep of all 41 files that declare `.page-hd{…}` found only 6 that declare
   border-bottom at all — putting it in the shared rule would paint a hairline
   under the header of ~35 pages that never asked for one and have no
   declaration to win with (contacts-import's transparent header, contact-
   profile, contacts-directory, field-sales/preview, …). A page that wants the
   hairline draws it in its own mobile block, as Tasks and Feed already do.

   And NOT set here: `.page-hd-info{flex:1}`. Only 11 of the 41 band files
   declare it, so a shared version would newly stretch the info column on the
   other 30 — measured effect on Setup, marketing-plan and social-planner: the
   info block shrank to min-content, the title and eyebrow wrapped to two lines
   and the action row was yanked up out of its own row into the header. Pages
   that want a flexing info column declare it, as Tasks (.tm2) does. */
:where(.page-body)>.page-hd{padding:32px 32px 22px;background:linear-gradient(180deg,var(--sf) 0%,var(--bg) 100%);flex-shrink:0;gap:18px}
@media (max-width:1100px){:where(.page-body)>.page-hd{padding:24px 18px 18px}}
/* KEEP THE GRADIENT ON MOBILE. This used to flatten to var(--sf) at <=760, which
   only showed up on pages that rely on this shared default: any page declaring
   its own `.page-hd` (contacts-directory, tasks, field-sales, ...) loads after
   this sheet, wins the (0,1,0) tie and kept its gradient, so Agenda/Contacts
   looked flat next to otherwise identical screens. */
@media (max-width:760px){:where(.page-body)>.page-hd{padding:18px 16px 14px;flex-direction:column;align-items:stretch;gap:10px;background:linear-gradient(180deg,var(--sf) 0%,var(--bg) 100%)}}
.page-hd-t{font-family:'Fraunces',Outfit,serif;font-weight:600;font-size:28px;color:var(--tx);letter-spacing:-.022em;line-height:1.15}
.page-hd-s{font-size:15px;color:var(--t3);font-weight:500;margin-top:5px;line-height:1.55;max-width:580px}
.tab-hd-t{font-family:var(--font-display);font-weight:800;font-size:21px;color:var(--tx);letter-spacing:-.018em;line-height:1.2}

/* ── Modal ──
   The reference catalog renders .modal-bg INLINE inside a .show cell so
   designers can see it next to its docs. The reference HTML embeds that
   inline-positioned copy. In the PRODUCT, every .modal-bg must overlay
   the whole viewport — fixed position, full inset, high z-index, centered
   modal, scroll within the overlay. */
/* iOS safe-area + dvh: viewport-fit=cover (set in app.blade.php) makes env()
   return real values on notched devices. max() keeps the desktop 36/24 padding,
   while bumping it on iOS so the centered .modal isn't covered by the home
   indicator or notch. dvh closes the 1–2px gap that appears when Safari's
   address bar collapses, since 100vh is the LARGEST viewport (chrome retracted),
   not the current one. */
.modal-bg{position:fixed;inset:0;background:rgba(20,18,15,0.52);padding:max(36px,env(safe-area-inset-top)) max(24px,env(safe-area-inset-right)) max(36px,env(safe-area-inset-bottom)) max(24px,env(safe-area-inset-left));display:flex;align-items:center;justify-content:center;z-index:1000;overflow-y:auto;min-height:100vh;min-height:100dvh}
.modal{background:var(--sf);border-radius:14px;width:520px;max-width:100%;box-shadow:0 20px 50px rgba(20,18,15,.28);display:flex;flex-direction:column}
.modal.wide{width:640px}
.modal-hd{padding:16px 20px 12px;display:flex;align-items:center;gap:12px;border-bottom:1px solid var(--bd)}
.modal-ic{width:38px;height:38px;border-radius:10px;background:var(--brl);color:var(--br);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0}
.modal-t{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--tx);letter-spacing:-.01em}
.modal-s{font-size:13.5px;color:var(--t3);font-weight:500;margin-top:2px;line-height:1.5}
.modal-bd{padding:18px 20px;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:14px}
.modal-bd>form{display:flex;flex-direction:column;gap:14px}
.modal-ft{padding:12px 20px;border-top:1px solid var(--bd);background:var(--sf);display:flex;justify-content:flex-end;gap:7px;border-radius:0 0 14px 14px}

/* ── Slide-over panel ── */
.panel-demo{background:var(--sf);border:1px solid var(--bd);border-radius:13px;width:100%;max-width:520px;display:flex;flex-direction:column;box-shadow:-4px 0 12px rgba(20,18,15,.04);overflow:hidden}
.panel-av{width:42px;height:42px;border-radius:10px;color:#fff;display:flex;align-items:center;justify-content:center;font-family:var(--font-display);font-weight:800;font-size:18px;flex-shrink:0}
.panel-info{flex:1;min-width:0}
.panel-meta{display:flex;align-items:center;gap:5px;margin-bottom:5px;flex-wrap:wrap}
/* `.panel-t` is NOT restated here. It had a second, different declaration in this very file
   (Fraunces 800/18px against the canonical 700/16px below) — same single-class specificity, so
   the later one always won and this copy never rendered anywhere; it only misled anyone grepping
   for the class. The ONE definition is the PANEL section's, further down this file. */
.panel-sub{font-size:13.5px;color:var(--t3);font-weight:500;margin-top:4px;display:flex;align-items:center;gap:5px}

/* ── Funnel chart ── */
.funnel{display:flex;flex-direction:column;gap:7px}
.fn-row{display:flex;align-items:center;gap:10px}
.fn-l{width:90px;font-family:var(--font-display);font-weight:700;font-size:13.5px;color:var(--t2);flex-shrink:0}
.fn-bar{height:30px;border-radius:6px;display:flex;align-items:center;justify-content:flex-end;padding-right:10px;min-width:60px}
.fn-v{font-family:var(--font-mono);font-weight:700;font-size:14px;color:#fff}

/* ── Drop zone ── */
.dz{padding:32px 24px;border:2px dashed var(--bd);border-radius:11px;background:var(--bl);display:flex;flex-direction:column;align-items:center;gap:9px;text-align:center;cursor:pointer;transition:.16s}
.dz:hover{border-color:var(--br);background:var(--brl)}
.dz-ic{width:52px;height:52px;border-radius:13px;background:var(--brl);color:var(--br);display:flex;align-items:center;justify-content:center;font-size:22px}
.dz-t{font-family:var(--font-display);font-weight:800;font-size:16px;color:var(--tx)}
.dz-s{font-size:13.5px;color:var(--t3);font-weight:500}

/* ── Phone preview frame ── */
.phone{background:#0a0a0a;padding:10px;border-radius:18px;max-width:280px}
.phone-screen{background:var(--bg);border-radius:11px;padding:13px;min-height:300px}

/* ── Photo box (file attached state) ── */
.attached{padding:11px 13px;background:var(--okl);border:1px solid rgba(16,185,129,.32);border-radius:9px;display:flex;align-items:center;gap:11px}
.attached-ic{color:var(--ok);font-size:17px}
.attached-n{font-family:var(--font-display);font-weight:700;font-size:14px;color:var(--ok)}
.attached-m{font-size:12.5px;color:var(--t3);font-weight:500;margin-top:1px}
/* ── Skeleton loaders ──
   Shimmer placeholders for the first page paint. Use `.skel` as the base
   (shimmering animated background) and size with explicit width/height,
   or use the bar-* / line-* / avatar modifiers. Match the shape of what
   the data will be so the layout doesn't jump when content arrives. */
.skel{background:linear-gradient(90deg,var(--bg2) 25%,var(--bl) 50%,var(--bg2) 75%);background-size:200% 100%;animation:shim 1.4s linear infinite;border-radius:5px;display:block}
.skel.bar-xs{height:9px;border-radius:4px}
.skel.bar-sm{height:11px;border-radius:4px}
.skel.bar-md{height:13px;border-radius:5px}
.skel.bar-lg{height:18px;border-radius:5px}
.skel.bar-xl{height:24px;border-radius:6px}
.skel.av{width:32px;height:32px;border-radius:9px;display:inline-block}
.skel.av.sm{width:24px;height:24px;border-radius:7px}
.skel.av.md{width:32px;height:32px;border-radius:9px}
.skel.av.lg{width:42px;height:42px;border-radius:10px}
.skel.av.round{border-radius:50%}
.skel.line-30{width:30%}.skel.line-40{width:40%}.skel.line-50{width:50%}.skel.line-60{width:60%}.skel.line-65{width:65%}.skel.line-75{width:75%}.skel.line-85{width:85%}.skel.line-100{width:100%}
@keyframes shim{0%{background-position:200% 0}100%{background-position:-200% 0}}

/* ── FAB + speed dial — see docs/UI_REFERENCE.html §fab ──
   The bare `.fab{}` rule was removed because it collided with FontAwesome's
   `.fab` Brands family class — every `<i class="fab fa-whatsapp">` was being
   styled as a 56px circular button. If a real Floating Action Button widget
   is needed, use `.fab-dial` + `.fab-action*` below or introduce a
   non-conflicting class name. */
.fab-dial{display:flex;flex-direction:column;gap:11px;align-items:flex-end}
.fab-dial-items{display:flex;flex-direction:column;gap:9px;align-items:flex-end}
.fab-action{display:flex;align-items:center;gap:9px;background:var(--sf);border:1px solid var(--bd);border-radius:23px;padding:7px 14px 7px 7px;box-shadow:0 4px 14px rgba(0,0,0,.10);cursor:pointer;font-family:inherit}
.fab-action-ic{width:32px;height:32px;border-radius:50%;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0}
.fab-action-l{font-family:var(--font-display);font-weight:700;font-size:var(--fs-sm);color:var(--tx);white-space:nowrap}

/* ── Toast stack — newest at top, max 4 visible (see docs/UI_REFERENCE.html §toaststack)
   Use the .toast-stack container; the existing .toast-x covers single-toast styling.
   Variants apply a border-left of the matching status color. */
.toast-stack{position:fixed;top:14px;right:14px;display:flex;flex-direction:column;gap:7px;width:320px;max-width:calc(100vw - 28px);z-index:200;pointer-events:none}
.toast-stack > *{pointer-events:auto}
.toast-stack .toast-x{background:var(--sf);color:var(--tx);border:1px solid var(--bd);border-left:3px solid var(--inf);box-shadow:0 8px 22px rgba(0,0,0,.10);padding:10px 13px;gap:9px;font-weight:500;font-size:var(--fs-sm);display:flex;align-items:center;width:100%}
.toast-stack .toast-x.ok{border-left-color:var(--ok)}
.toast-stack .toast-x.er{border-left-color:var(--er)}
.toast-stack .toast-x.wn{border-left-color:var(--wn)}
.toast-stack .toast-x.inf{border-left-color:var(--inf)}
.toast-stack .toast-x > i{font-size:var(--fs-base);flex-shrink:0}
.toast-stack .toast-x .toast-x-msg{flex:1}
.toast-stack .toast-x .toast-x-close{background:transparent;border:0;color:var(--t4);cursor:pointer;width:22px;height:22px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center;font-size:11px}
.toast-stack .toast-x .toast-x-close:hover{background:var(--bl);color:var(--tx)}

/* ── Field validation states — extends .fld / .fld-in
   (see docs/UI_REFERENCE.html §valid). Use .fld.error or .fld.ok on the wrapper. */
.fld.error .fld-in{border-color:var(--er);padding-right:36px}
.fld.error .fld-in:focus{box-shadow:0 0 0 3px var(--erl)}
.fld.ok .fld-in{border-color:var(--ok);padding-right:36px}
.fld.ok .fld-in:focus{box-shadow:0 0 0 3px var(--okl)}
.fld-state-ic{position:absolute;right:11px;top:50%;transform:translateY(-50%);font-size:14px;pointer-events:none}
.fld.error .fld-state-ic{color:var(--er)}
.fld.ok .fld-state-ic{color:var(--ok)}
.fld-input-wrap{position:relative}

/* ── Tree view — collapsible nested node list (see §tree) ── */
.tree{display:flex;flex-direction:column;font-family:inherit}
.tree-node{display:flex;flex-direction:column}
.tree-node-row{display:flex;align-items:center;gap:7px;padding:6px 9px;border-radius:7px;cursor:pointer;color:var(--tx);font-size:var(--fs-sm);transition:.1s;font-family:inherit;background:transparent;border:0;text-align:left;width:100%}
.tree-node-row:hover{background:var(--bl)}
.tree-node-row.active{background:var(--brl);color:var(--brd);font-weight:700}
.tree-node-chev{width:14px;font-size:9px;color:var(--t4);flex-shrink:0;text-align:center;transition:transform .14s}
.tree-node.open > .tree-node-row > .tree-node-chev{transform:rotate(90deg);color:var(--br)}
.tree-node-leaf .tree-node-chev{visibility:hidden}
.tree-node-ic{width:16px;font-size:var(--fs-sm);color:var(--t3);flex-shrink:0;text-align:center}
.tree-node-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tree-node-meta{font-family:'JetBrains Mono';font-size:var(--fs-xs);color:var(--t3);font-weight:600;flex-shrink:0}
.tree-children{display:none;padding-left:22px;border-left:1px solid var(--bd);margin-left:13px}
.tree-node.open > .tree-children{display:flex;flex-direction:column}

/* ── Usage / quota meter — extends .pbar with status variants (see §plan) ── */
.usage-bar{height:8px;border-radius:4px;background:var(--bg2);overflow:hidden;display:block;width:100%}
.usage-bar-fill{height:100%;background:var(--ok);border-radius:4px;transition:width .4s}
.usage-bar.warn .usage-bar-fill{background:var(--wn)}
.usage-bar.danger .usage-bar-fill{background:var(--er)}
.usage-bar-head{display:flex;align-items:baseline;justify-content:space-between;gap:9px;margin-bottom:6px;font-size:var(--fs-sm)}
.usage-bar-l{font-family:var(--font-display);font-weight:700;color:var(--tx);display:flex;align-items:center;gap:6px}
.usage-bar-l i{color:var(--t3);font-size:var(--fs-xs)}
.usage-bar-v{font-family:'JetBrains Mono';font-weight:700;color:var(--t2);font-size:var(--fs-xs)}
.usage-bar-v strong{color:var(--tx)}

/* ── Progress ring (SVG) — base sizing/stroke; consumer sets stroke-dasharray
   and stroke-dashoffset per value. See §gauge for usage. */
.ring{display:inline-block;width:120px;height:120px;position:relative}
.ring-svg{width:100%;height:100%;transform:rotate(-90deg)}
.ring-track{fill:none;stroke:var(--bg2);stroke-width:10}
.ring-fill{fill:none;stroke:var(--br);stroke-width:10;stroke-linecap:round;transition:stroke-dashoffset .5s ease}
.ring-fill.ok{stroke:var(--ok)}
.ring-fill.wn{stroke:var(--wn)}
.ring-fill.er{stroke:var(--er)}
.ring-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}
.ring-v{font-family:var(--font-display);font-weight:800;font-size:28px;color:var(--tx);letter-spacing:-.025em;line-height:1}
.ring-l{font-family:var(--font-display);font-weight:700;font-size:var(--fs-xs);color:var(--t3);text-transform:uppercase;letter-spacing:.05em;margin-top:3px}

/* ── Tag input (live add) — extends the existing .tag-row / .tag-chip ──
   Already covered by .tag-row + .tag-chip + .tag-chip-x + .tag-in. The
   reference §taginput uses the same primitives — no additions needed. */

/* ── Empty state extensions — .empty already covers the basic case; these
   add an illustration container and a primary CTA button slot. (see §empty) */
.empty-ill{width:88px;height:88px;border-radius:50%;background:var(--bl);color:var(--t4);display:flex;align-items:center;justify-content:center;font-size:34px}
.empty-cta{margin-top:6px}

/* ── Plan / usage card — extends .card with a top-row brand block, used for
   pricing / current-plan / quota panels (see §plan) ── */
.plan-card{background:var(--sf);border:1px solid var(--bd);border-radius:14px;padding:0;overflow:hidden;display:flex;flex-direction:column}
.plan-card-hd{padding:18px 20px;background:linear-gradient(135deg,var(--brl),var(--sf));border-bottom:1px solid var(--bd);display:flex;align-items:center;gap:13px}
.plan-card-ic{width:42px;height:42px;border-radius:10px;background:var(--br);color:#fff;display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}
.plan-card-name{font-family:var(--font-display);font-weight:800;font-size:var(--fs-lg);color:var(--tx);letter-spacing:-.012em}
.plan-card-price{margin-left:auto;font-family:var(--font-display);font-weight:800;font-size:var(--fs-xl);color:var(--tx)}
.plan-card-price small{font-family:var(--font-body);font-weight:500;font-size:var(--fs-xs);color:var(--t3)}
.plan-card-bd{padding:18px 20px;display:flex;flex-direction:column;gap:11px}
.plan-card-ft{padding:14px 20px;border-top:1px solid var(--bd);background:var(--bl);display:flex;justify-content:flex-end;gap:7px}

/* ── Vertical-nav layout — two-column page primitive: 280px sticky nav on the
   left, scrollable content on the right. Use for settings / configuration /
   onboarding / knowledge-base pages with 8+ subsections.
   See docs/UI_REFERENCE.html §vertnav.

   Font sizes use --fs-* tokens (fs-scale.css):
     --fs-xs (14px), --fs-sm (16px, default body),
     --fs-base (18px), --fs-lg (20px), --fs-xl (22px).
   Tiny labels (9-11px) below the scale are an explicit exception for
   uppercase eyebrows / nav sub-labels where 14px would be too loud.
   The content pane is full-width by default — no max-width cap. ── */
.vn-hero{background:var(--sf);border-bottom:1px solid var(--bd);padding:22px 28px}
.vn-hero-t{font-family:var(--font-display);font-weight:800;font-size:var(--fs-xl);color:var(--tx);margin:0;letter-spacing:-.01em}
.vn-hero-s{font-size:var(--fs-xs);color:var(--t3);margin-top:3px;font-weight:600}
.vn-layout{display:grid;grid-template-columns:280px 1fr;gap:0;height:100%;min-height:0;overflow:hidden;background:var(--sf)}
.vn-nav{padding:14px 14px 24px;background:var(--sf);border-right:1px solid var(--bd);overflow-y:auto}
.vn-nav-group{margin-bottom:20px}
.vn-nav-group:last-child{margin-bottom:0}
.vn-nav-group-hd{font-family:var(--font-display);font-size:10px;font-weight:800;color:var(--t3);text-transform:uppercase;letter-spacing:.08em;padding:0 12px;margin-bottom:6px}
.vn-nav-item{width:100%;display:flex;align-items:flex-start;gap:11px;padding:9px 12px;background:transparent;border:0;border-radius:8px;text-align:left;cursor:pointer;font-family:inherit;color:var(--t2);transition:.12s;margin-bottom:2px}
.vn-nav-item:hover{background:var(--bl);color:var(--tx)}
.vn-nav-item.active{background:var(--brl);color:var(--brd)}
.vn-nav-item.active .vn-nav-name{color:var(--brd)}
.vn-nav-item.active .vn-nav-sub{color:var(--brd);opacity:.7}
.vn-nav-item i{font-size:var(--fs-xs);margin-top:3px;width:16px;text-align:center;flex-shrink:0;color:var(--t3)}
.vn-nav-item:hover i{color:var(--t2)}
.vn-nav-item.active i{color:var(--brd)}
.vn-nav-name{font-family:var(--font-display);font-size:var(--fs-xs);font-weight:700;color:var(--tx);line-height:1.3}
.vn-nav-sub{font-size:11px;color:var(--t3);margin-top:2px;font-weight:500;line-height:1.35}
.vn-content{padding:24px 32px 60px;overflow-y:auto;background:var(--bl);min-width:0}
/* Full-width content — no inner max-width. Each page can opt in to a
   narrower reading width by overriding .vn-content-inner per page if it
   really needs centered forms. */
.vn-content-inner{width:100%;max-width:none}
.vn-page-hd{margin-bottom:18px;display:flex;align-items:flex-end;justify-content:space-between;gap:14px;flex-wrap:wrap}
.vn-page-hd-info{flex:1;min-width:0}
.vn-page-hd-action{flex-shrink:0;display:flex;gap:8px}
.vn-page-t{font-family:var(--font-display);font-weight:900;font-size:var(--fs-xl);color:var(--tx);letter-spacing:-.01em;display:flex;align-items:center;gap:9px;line-height:1.2}
.vn-page-t > i{color:var(--br)}
.vn-page-s{font-size:var(--fs-sm);color:var(--t3);font-weight:500;margin-top:6px;max-width:680px;line-height:1.5}
.vn-card{background:var(--sf);border:1px solid var(--bd);border-radius:12px;padding:18px;margin-bottom:14px}
.vn-card:last-child{margin-bottom:0}
.vn-card-hd{margin-bottom:14px;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.vn-card-hd-info{flex:1;min-width:0}
.vn-card-t{font-family:var(--font-display);font-weight:800;font-size:var(--fs-base);color:var(--tx)}
.vn-card-s{font-size:var(--fs-sm);color:var(--t3);font-weight:500;margin-top:3px;line-height:1.5}
@media (max-width:900px){
    .vn-layout{grid-template-columns:1fr;height:auto}
    .vn-layout .vn-nav{max-height:none;border-right:0;border-bottom:1px solid var(--bd)}
    .vn-content{padding:18px 18px 60px}
}

/* ═══════════════════════════════════════════════════════════════════════════
   TAB NAVIGATOR — <x-tab-nav> (canonical coral-underline section nav)
   Reusable, theme-uniform (tokens only), mobile-safe (horizontal-only swipe).
   Replaces the duplicated .djb-sn / .sn-row / .cp-tabs / .mod-tabs / .suv2-sn /
   .panel-tabs / .page-tabs / … strips.
   ═══════════════════════════════════════════════════════════════════════════ */
.tabnav{
    display:flex;gap:0;align-items:stretch;
    /* overflow-y:hidden stops overflow-x:auto from auto-promoting overflow-y to auto.
       Without it the nav is a scroll container whose flex min-height:auto resolves to 0,
       so inside a flex-column page (e.g. .scroll) it collapses to 0 height and vanishes.
       flex-shrink:0 belts-and-braces: a nav must never be shrunk away. */
    overflow-x:auto;overflow-y:hidden;scrollbar-width:none;flex-shrink:0;
    border-bottom:1px solid var(--bd);background:var(--sf);
    /* mobile: swipe the strip sideways only — never vertically / never the page */
    touch-action:pan-x;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
}
.tabnav::-webkit-scrollbar{display:none}
.tabnav-tab{
    padding:14px 17px;background:transparent;border:0;color:var(--t3);
    font-family:var(--font-display);font-weight:700;font-size:var(--fs-base);
    cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;
    transition:.14s;display:inline-flex;align-items:center;gap:8px;
    white-space:nowrap;letter-spacing:-.01em;flex-shrink:0;
}
.tabnav-tab i{font-size:var(--fs-sm);color:var(--t4);transition:.14s}
.tabnav-tab:hover{color:var(--tx)}
.tabnav-tab:hover i{color:var(--t2)}
.tabnav-tab.is-active{color:var(--tx);border-bottom-color:var(--co)}
.tabnav-tab.is-active i{color:var(--co)}
.tabnav-tab.is-soon{opacity:.55;cursor:not-allowed}
.tabnav-ct{
    font-family:var(--font-mono);font-weight:700;font-size:var(--fs-xxs);
    color:var(--t4);background:var(--bl);padding:1px 5px;border-radius:3px;
    letter-spacing:0;min-width:22px;display:inline-flex;justify-content:center;
}
/* THE ACTIVE COUNT IS INVISIBLE IN DARK MODE unless both halves flip together.
   `--brl` is a brand TINT that is the same light value in both themes (#ebe7e1), while
   `--tx` flips to near-white (#f1f5f9) — so a dark-mode active tab painted #f1f5f9 text on
   a #ebe7e1 pill and the digit simply vanished. Measured on the notifications bell strip,
   but the rule is shared, so every tab count in the app carried it.
   `color-mix` derives the ink FROM the pill itself: on the always-light `--brl` it always
   lands dark enough to read, in either theme, with no second token to keep in sync.
   The literal is deliberate, and is the one honest option here — EVERY text token
   (`--tx`, `--ink`, `--t2`, `--t3`) flips with the theme, so none can pair with a background
   that does not. It is the light theme's own `--tx`, i.e. the ink this pill already carried
   before dark mode existed. Measured contrast: 1.12 → 9.09 (WCAG AA wants 4.5). */
.tabnav-tab.is-active .tabnav-ct{color:color-mix(in srgb,var(--brl) 18%,#161513);background:var(--brl)}
.tabnav-ct.is-hot{background:var(--col,var(--okl));color:var(--co,var(--okd))}
.tabnav-soon{
    font-family:var(--font-display);font-weight:800;font-size:var(--fs-xxs);
    color:var(--t4);background:var(--bl);padding:1px 5px;border-radius:3px;
    text-transform:uppercase;letter-spacing:.05em;
}
/* size: compact / panel variant (smaller, uppercase) — matches old .djb-pn-tab */
.tabnav-sm .tabnav-tab{padding:11px 13px;font-size:var(--fs-sm);text-transform:uppercase;letter-spacing:.05em;gap:7px}
.tabnav-sm .tabnav-tab i{font-size:var(--fs-xs)}
/* reactive pill states (e.g. Setup "Required": coral when pending, green when clear) */
.tabnav-ct.alert{background:var(--col,var(--erl));color:var(--co,var(--er))}
.tabnav-ct.ok{background:var(--okl);color:var(--okd)}
.tabnav-ct.warn{background:var(--wnl);color:var(--wnd)}
/* ── Page sub-nav bar variant ──────────────────────────────────────────────
   The canonical sticky page sub-nav (Deals · Payments · Field Sales · Team).
   It uses the same surface token as wrapped tab bars, so every tab header is
   one consistent white surface in light mode and the matching elevated surface
   in dark mode. */
.tabnav--bar{
    position:sticky;top:0;z-index:25;padding:0 28px;
    background:var(--sf);
    border-bottom:1px solid var(--bd);
}
@media(max-width:1024px){ .tabnav--bar{padding-left:18px;padding-right:18px} }
/* When the nav sits INSIDE an already-styled sticky bar (e.g. a .stickbar that
   also holds right-aligned actions), drop the component's own white bg + border
   so the surrounding bar shows through — same blended look as .tabnav--bar. */
.tabnav.is-bare{background:transparent;border-bottom:0}
/* The tabs carry margin-bottom:-1px so their active underline overlaps the nav's
   own 1px bottom border. `is-bare` removes that border, so the -1px would push the
   active tab's 2px coral underline 1px BELOW the nav and the nav's overflow-y:hidden
   clips it to a sliver. Drop the overlap on bare navs so the full coral underline
   sits inside the clip box and renders identically to a bordered nav (Field Sales). */
.tabnav.is-bare .tabnav-tab{margin-bottom:0}

/* Canonical sticky tab-bar wrapper (around <x-tab-nav>). z-30 keeps it below
   the topbar (z-40) and modals (z-50). Optional .tabnav-wrap-acts holds actions. */
.tabnav-wrap{position:sticky;top:0;z-index:30;display:flex;align-items:center;gap:14px;background:var(--sf);border-bottom:1px solid var(--bd);padding:0 28px}
.tabnav-wrap .tabnav{flex:1 1 auto;border-bottom:none;margin-bottom:-1px}
.tabnav-wrap-acts{display:flex;align-items:center;gap:8px;flex-shrink:0}
@media (max-width:760px){.tabnav-wrap{padding:0 16px}}

/* ═══════════════════════════════════════════════════════════════════════════
   MODAL — <x-modal> extras (the .modal-bg/.modal/.modal-hd/-bd/-ft base is
   defined above). Adds the close button, size + icon-colour variants, and a
   header text wrapper. Mobile bottom-sheet behaviour comes from
   responsive-overlays.css (which already targets .modal/.modal-bg).
   ═══════════════════════════════════════════════════════════════════════════ */
.modal.sm{width:440px}
.modal.lg{width:600px}
.modal-hd-tx{flex:1;min-width:0}
.modal-x{
    width:30px;height:30px;border-radius:7px;border:1px solid var(--bd);
    background:var(--sf);color:var(--t2);cursor:pointer;flex-shrink:0;
    display:flex;align-items:center;justify-content:center;font-size:13px;transition:.12s;
}
.modal-x:hover{border-color:var(--t4);color:var(--tx)}
.modal-ic.danger{background:var(--erl);color:var(--er)}
.modal-ic.warning{background:var(--wnl);color:var(--wnd)}
.modal-ic.info{background:var(--infl);color:var(--inf)}
.modal-ic.success{background:var(--okl);color:var(--okd)}
.modal-ic.vi{background:var(--vil);color:var(--vid)}

/* ═══════════════════════════════════════════════════════════════════════════
   PANEL — <x-panel> (canonical slide-over). Desktop: fixed right-side panel.
   Mobile: bottom sheet (responsive-overlays.css targets .panel). Modeled on the
   deal-journey .djb-panel. Pairs with a .panel-scrim backdrop.
   ═══════════════════════════════════════════════════════════════════════════ */
.panel-scrim{position:fixed;inset:0;background:rgba(9,9,11,.36);backdrop-filter:blur(2px);z-index:90;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .28s ease,visibility 0s linear .3s}
.panel-scrim.open{opacity:1;visibility:visible;pointer-events:auto;transition:opacity .28s ease,visibility 0s linear 0s}
.panel{
    position:fixed;top:0;right:0;bottom:0;width:640px;max-width:96vw;
    background:var(--sf);border-left:1px solid var(--bd);z-index:95;
    transform:translateX(100%);visibility:hidden;
    transition:transform .28s cubic-bezier(.16,1,.3,1),visibility 0s linear .28s;
    display:flex;flex-direction:column;box-shadow:var(--shadow-lg);
}
.panel.open{transform:translateX(0);visibility:visible;transition:transform .28s cubic-bezier(.16,1,.3,1)}
.panel.sm{width:480px}
.panel.lg{width:760px}
/* `.panel-hd` is NOT declared here — its ONE definition is public/css/modal-kit.css:147, which is
   <link>ed AFTER this file (tenant/layouts/app.blade.php:354 then :357) and so always won anyway.
   The rival copy that used to sit on this line differed only in `gap:12px` and the missing
   gradient, i.e. it was pure dead weight that made the class look ambiguous. Every one of the 19
   blades that render `.panel-hd` also receives modal-kit.css (own <link> or via the tenant
   layout); the 5 public pages that load this sheet WITHOUT modal-kit.css (blog/unsubscribed,
   privacy, product, support, terms) do not use the class. */
.panel-ic{width:42px;height:42px;border-radius:11px;background:var(--bl);color:var(--t2);display:flex;align-items:center;justify-content:center;font-size:17px;flex-shrink:0}
.panel-hd-tx{flex:1;min-width:0}
.panel-t{font-family:var(--font-display);font-weight:700;font-size:16px;color:var(--tx);letter-spacing:-.01em;line-height:1.25}
.panel-s{font-size:13px;color:var(--t3);font-weight:500;margin-top:3px;line-height:1.5}
.panel-x{width:32px;height:32px;border-radius:8px;border:1px solid var(--bd);background:var(--sf);color:var(--t2);cursor:pointer;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:13px;transition:.12s}
.panel-x:hover{border-color:var(--t4);color:var(--tx)}
.panel-bd{flex:1;overflow-y:auto;padding:18px 22px 22px}
.panel-ft{padding:12px 22px;border-top:1px solid var(--bd);background:var(--sf);display:flex;justify-content:flex-end;gap:8px;flex-shrink:0}

/* ── Panel footer action buttons — solid-filled CTA look.
   NOTE: .modal-ft buttons are now owned by modal-kit.css (.modal-bg .btn*),
   so they were removed here to avoid a duplicate/conflicting rule set.
   Panels are not yet migrated, so they keep this footer-button styling. */
.panel-ft .btn{font-size:13px}
.panel-ft .btn.primary{background:var(--br);border-color:var(--br);color:var(--br-text);font-weight:700}
.panel-ft .btn.primary:hover{background:var(--brd);border-color:var(--brd);color:var(--br-text)}
.panel-ft .btn.danger{background:var(--er);border-color:var(--er);color:#fff;font-weight:700}
.panel-ft .btn.danger:hover{background:var(--erd,#b3392f);border-color:var(--erd,#b3392f);color:#fff}
.panel-ft .btn.warn{background:var(--wn);border-color:var(--wn);color:#fff;font-weight:700}
.panel-ft .btn.warn:hover{background:var(--wnd);border-color:var(--wnd);color:#fff}

/* ════════════════════════════════════════════════════════════════════════
   FILTER BAR (<x-filter-bar>) — universal list-filter toolbar, reused by
   every model index. Canonical replacement for the legacy per-page
   .djb-tbar / .djb-dd / .djb-search clusters.
   ════════════════════════════════════════════════════════════════════════ */
.fbar{
    /* THE RULE (UI-consistency audit family E, option E1, 2026-09-09): a filter bar ALIGNS
       WITH THE CONTENT EDGE of its own screen. A side inset is the EXPLICIT EXCEPTION, never
       the default — so `--fbar-x` falls back to 0 and a bar inherits whatever gutter its
       container already has.

       WHY THE DEFAULT FLIPPED. It used to be 28px, on the theory that most bars sit in a
       full-bleed layout and should self-inset. Measured on 15 screens it was not: 9 bars sat
       at offset 0 against their content edge and 4 sat at +28 — a full gutter INSIDE an
       already-padded wrapper (automations, email-marketing, feed, community). Those four were
       not choosing an inset; they were the ones that had not opted OUT of a default nobody had
       re-derived since the class was written. Making 0 the default turns "aligned" into the
       thing you get for free and "inset" into the thing you must ask for and can therefore be
       reviewed. Pinned by __tests__/fbar-offset-consistency.test.ts.

       A page that IS full-bleed (its own body has no horizontal padding) states its gutter
       explicitly in the opt-in block below — e.g. `.dshv2 .fbar{--fbar-x:32px}`. */
    padding:14px var(--fbar-x, 0px) 10px;display:flex;align-items:center;gap:6px;
    flex-wrap:wrap;background:var(--bg);
}
.fbar-sep{width:1px;height:22px;background:var(--bd);margin:0 4px;flex-shrink:0}
.fbar-sp{flex:1}
.fbar-filters{display:contents}

/* ── Per-consumer filter-bar side inset. The .fbar default is now 0 (see the rule above):
   a bar inherits whatever gutter its own container already carries. This block is the
   COMPLETE list of screens that ask for something else, and every value below was MEASURED
   with resources/js/spa/tools/cdp-fbar-offset-probe.mjs at 1600x1000 — the number is the
   horizontal padding of the content column the bar sits above, not an estimate.
   Centralized here — next to .fbar and in a file that always parses cleanly — so a page's
   own (often huge) inline <style> block can't drop it, and so the whole family can be read
   in one place. NOTE this file is shared by BOTH surfaces: the SPA mirrors it into
   styles/web/design-system.css and the Blade web links it globally, so a selector with no
   SPA wearer may still have a Blade one (see the .inv-/.ch-/.lg-/.ml-/.rpn- note below).

   ONLY ONE KIND OF ENTRY EXISTS NOW: an OPT-IN, stating the gutter a full-bleed page's own
   content column carries. The old second kind — an OPT-OUT zeroing the 28px default for a
   bar nested in an already-padded wrapper — is gone, because 0 is what you now get for free.

   THE DEAD-SELECTOR HAZARD this block just paid for: .sl-fbar sat in the old opt-out group
   with a confident comment about Short Links' padded wrapper. Short Links never wore that
   class on either surface, so the rule matched nothing and the screen silently rode the 28px
   default into a -28 misalignment against its own #slmock .sl-scroll column — invisible for
   as long as the default happened to be the value most pages wanted.
   __tests__/fbar-offset-consistency.test.ts now asserts that every selector below has a live
   wearer in resources/js/spa or resources/views, so a rule can never again describe a screen
   it does not reach. ── */

/* Full-bleed page bodies restating the gutter their own content column carries.
   `.kilto-preview` is a SPLIT case since 2026-09-20: the Blade twin
   (tenant/finances/index.blade.php) is still full-bleed and needs this row, but the SPA screen
   gave its tab panes a real container gutter (`.fz-body` in FinancesScreen.vue) and opts back
   OUT locally with `--fbar-x:0`. Keep this row — deleting it would re-break the Blade page,
   which the live-wearer gate would not catch because both surfaces wear the same class. */
.kilto-preview .fbar, .kt-cat .fbar, .wbv3 .fbar, .cal-pv-root .fbar, #crsmock .fbar,
.djb-fbar, .tm-fbar, .inv-fbar, .cd-fbar { --fbar-x:28px }
.dshv2 .fbar { --fbar-x:32px }
.ch-fbar, .lg-fbar { --fbar-x:22px }
.ml-fbar { --fbar-x:16px }
/* .inv-fbar/.ch-fbar/.lg-fbar/.ml-fbar/.rpn-tbar have NO SPA wearer — their wearers are the
   Blade pages invoices/, customer-success/, logs/, media/ and reports/index.blade.php, which
   link this same stylesheet. They are live, not dead; do not sweep them as unused. */

/* THE THREE SCREENS THE FLIP EXPOSED (each measured at -28 before this rule landed —
   worktree-logs/p3/fbar-after-flip-1600.json). Each hosts its bar OUTSIDE the padded column
   it filters, so it was riding the old 28px default without ever declaring it. The selector
   names the bar's real container and the value is copied from that column's own padding rule,
   so the two can only ever drift together:
     .tm2 .sticky-bar       → Tasks, column .tm2 .scroll{padding:14px 28px 90px}
     .sp2-mockup .sticky-bar → Social planner, column .sp2-mockup .kpis{padding:4px 28px 16px}
     #slmock                → Short links, column #slmock .sl-scroll{padding:18px 28px 60px}
   The social-planner selector is deliberately scoped to .sticky-bar: the Signal tab ships a
   SECOND FilterBar inside .sp2-mockup .sig-wrap{padding:18px 28px 40px}, which is already
   padded and must keep the 0 default. An unqualified .sp2-mockup .fbar would double-pad it. */
.tm2 .sticky-bar .fbar, .sp2-mockup .sticky-bar .fbar, #slmock .fbar { --fbar-x:28px }

/* WhatsApp campaigns — the bar is a direct sibling of the padded column on BOTH surfaces
   (`<x-filter-bar>` then `.wc-scroll` inside `<x-page id="wacamp">`; the SPA mirrors that
   structure in features/inbox/campaigns/CampaignsView.vue), so it is full-bleed and restates
   the column's own gutter: #wacamp .wc-scroll{padding:18px 28px 60px}. The SPA used to nest
   the pair in Autopilot's `.ap-wrap`, whose 28px stacked ON TOP of this one — measured at
   390x844 as a bar at l=16 over a content column at 32. That wrapper is gone; the inset lives
   here, where it is the same number on both surfaces. */
#wacamp .fbar { --fbar-x:28px }

@media (max-width:1100px){
    .cal-pv-root .fbar{--fbar-x:18px}
    .tm2 .sticky-bar .fbar{--fbar-x:18px}          /* .tm2 .scroll{padding:14px 18px 90px} */
}
@media (max-width:1024px){
    .kilto-preview .fbar, .kt-cat .fbar, #crsmock .fbar{--fbar-x:18px}
    .cd-fbar{--fbar-x:20px}
    .dshv2 .fbar{--fbar-x:22px}
}
@media (max-width:860px){
    .sp2-mockup .sticky-bar .fbar{--fbar-x:16px}   /* .sp2-mockup .kpis{padding:4px 16px 14px} */
}
@media (max-width:760px){
    .kilto-preview .fbar, .kt-cat .fbar, .cal-pv-root .fbar, .tm-fbar, .cd-fbar, .dshv2 .fbar{--fbar-x:16px}
    #crsmock .fbar, .wbv3 .fbar{--fbar-x:14px}
    .tm2 .sticky-bar .fbar{--fbar-x:14px}          /* .tm2 .scroll{padding:12px 14px 90px} */
    #slmock .fbar{--fbar-x:16px}                   /* #slmock .sl-scroll{padding:14px 16px 60px} */
    #wacamp .fbar{--fbar-x:16px}                   /* #wacamp .wc-scroll{padding:14px 16px 60px} */
}

/* view switcher */
.fbar-views{display:inline-flex;align-items:center;padding:3px;gap:1px;background:var(--sf);border:1px solid var(--bd);border-radius:8px;flex-shrink:0}
.fbar-view-btn{width:30px;height:26px;border:0;background:transparent;border-radius:5px;cursor:pointer;color:var(--t3);display:inline-flex;align-items:center;justify-content:center;font-size:var(--fs-sm);transition:.12s}
.fbar-view-btn:hover{color:var(--tx)}
.fbar-view-btn.is-active{background:var(--br);color:#fff}

/* trigger pill */
.fbar-dd-wrap{position:relative;flex-shrink:0}
.fbar-dd{
    display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:7px;
    background:var(--sf);border:1px solid var(--bd);color:var(--t2);
    font-family:var(--font-body);font-weight:600;font-size:var(--fs-sm);
    cursor:pointer;transition:.12s;white-space:nowrap;
}
.fbar-dd:hover{border-color:var(--t4);color:var(--tx)}
.fbar-dd:disabled{opacity:.55;cursor:not-allowed}
.fbar-dd.is-open{border-color:var(--bd2);color:var(--brd);background:var(--brl)}
.fbar-dd i{font-size:var(--fs-sm);color:var(--t3)}
.fbar-dd.is-open i:not(.fbar-dd-chev){color:var(--brd)}
.fbar-dd-chev{font-size:var(--fs-xs);margin-left:1px;color:var(--t4)}
.fbar-dd-ct{
    font-family:var(--font-mono);font-weight:700;font-size:var(--fs-xxs);color:#fff;background:var(--co);
    min-width:16px;height:16px;padding:0 4px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;
}

/* dropdown panel */
/* desktop: the wrapper is the anchored popover; mobile: it becomes the backdrop/scrim.
   x-show lives on the wrapper (not the sheet) so the sheet can keep display:flex when it
   joins the shared .modal sheet rule on mobile. */
/* position:fixed (coords set by window.fbarPlacePop on open) so the popover
   overlays the page content and escapes any ancestor overflow clipping — the old
   position:absolute version got cut off on short pages. JS also flips it left/up
   to stay inside the viewport. */
.fbar-dd-pop{position:fixed;top:0;left:0;z-index:60}
/* the mobile filter sheet is a real <x-modal> (.fbar-modal). On desktop the popover above
   handles it, so the modal is hidden there. Its option list is a simple flex column. */
.fbar-modal-list{display:flex;flex-direction:column;gap:1px}
@media (min-width:761px){ .modal-bg:has(> .modal.fbar-modal){display:none !important} }
/* custom-panel filters (e.g. date picker): desktop wrapper is layout-transparent so the
   bespoke panel keeps its own anchoring; on mobile it's hidden and the panel renders inside
   the modal instead, flowing in the body rather than floating as an absolute popover. */
.fbar-dd-custom-desktop{display:contents}
.fbar-modal--cal .modal-bd > *{position:static !important;top:auto !important;left:auto !important;width:100% !important;max-width:100% !important;box-shadow:none !important;border:0 !important}
/* compact date-range picker inside the mobile filter modal (desktop popover untouched) */
.fbar-modal--cal .modal-bd{padding:0 !important}
.fbar-modal--cal .djb-dr{flex-direction:column;gap:0;border:0;border-radius:0;width:100%;overflow:visible}
/* presets → one horizontally-scrollable pill row */
.fbar-modal--cal .djb-dr-presets{flex-direction:row;flex-wrap:nowrap;overflow-x:auto;gap:7px;padding:12px 16px;min-width:0;background:var(--sf);border-right:0;border-bottom:1px solid var(--bd);scrollbar-width:none}
.fbar-modal--cal .djb-dr-presets::-webkit-scrollbar{display:none}
.fbar-modal--cal .djb-dr-presets-lab,.fbar-modal--cal .djb-dr-presets-sep{display:none}
.fbar-modal--cal .djb-dr-preset{flex:0 0 auto;width:auto;white-space:nowrap;padding:8px 14px;border-radius:999px;background:var(--bl);text-align:center}
.fbar-modal--cal .djb-dr-preset.is-on{background:var(--brl);color:var(--brd)}
/* body + full-width stacked calendars */
.fbar-modal--cal .djb-dr-body{padding:16px;gap:16px}
.fbar-modal--cal .djb-dr-inputs{justify-content:center}
.fbar-modal--cal .djb-dr-cals{flex-direction:column;gap:22px}
.fbar-modal--cal .djb-dr-cal{min-width:0;width:100%}
.fbar-modal--cal .djb-dr-cal-grid{grid-template-columns:repeat(7,1fr);gap:3px;width:100%}
.fbar-modal--cal .djb-dr-day{padding:9px 0;font-size:var(--fs-base)}
.fbar-modal--cal .djb-dr-cal-d{padding:5px 0}
/* same compact treatment for the Finances hub date picker (.dr*) — overrides the page's
   legacy mobile bottom-sheet rules (higher specificity) so the panel flows inside the modal. */
.fbar-modal--cal .dr{flex-direction:column;gap:0;border:0;border-radius:0;width:100%;overflow:visible;position:static;transform:none;box-shadow:none;max-height:none;z-index:auto}
.fbar-modal--cal .dr-presets{flex-direction:row;flex-wrap:nowrap;overflow-x:auto;gap:7px;padding:12px 16px;min-width:0;background:var(--sf);border-right:0;border-bottom:1px solid var(--bd);scrollbar-width:none;max-height:none}
.fbar-modal--cal .dr-presets::-webkit-scrollbar{display:none}
.fbar-modal--cal .dr-presets-l,.fbar-modal--cal .dr-sep{display:none}
.fbar-modal--cal .dr-preset{flex:0 0 auto;width:auto;white-space:nowrap;padding:8px 14px;border-radius:999px;background:var(--bl);text-align:center}
.fbar-modal--cal .dr-preset.on{background:var(--brl);color:var(--brd)}
.fbar-modal--cal .dr-main{padding:16px;gap:16px}
.fbar-modal--cal .dr-inputs{justify-content:center}
.fbar-modal--cal .dr-cals{flex-direction:column;gap:22px}
.fbar-modal--cal .dr-cal{min-width:0;width:100%}
.fbar-modal--cal .dr-grid{grid-template-columns:repeat(7,1fr);gap:3px;width:100%}
.fbar-modal--cal .dr-day{height:auto;padding:9px 0;font-size:var(--fs-base)}
.fbar-modal--cal .dr-dow{padding:5px 0}
.fbar-dd-pan{
    min-width:200px;max-height:340px;overflow-y:auto;
    background:var(--sf);border:1px solid var(--bd);border-radius:11px;box-shadow:var(--shadow-lg,0 12px 32px rgba(20,18,15,.16));
    padding:5px;display:flex;flex-direction:column;gap:1px;
}
.fbar-dd-pop .fbar-dd-pan.is-wide,.fbar-dd-pan.is-wide{min-width:260px}
.fbar-dd-it{
    display:flex;align-items:center;gap:9px;width:100%;padding:8px 10px;border:0;border-radius:7px;
    background:transparent;cursor:pointer;text-align:left;color:var(--t2);
    font-family:var(--font-body);font-weight:600;font-size:var(--fs-sm);transition:.1s;
}
.fbar-dd-it:hover{background:var(--bl);color:var(--tx)}
.fbar-dd-it.is-sel{background:var(--brl);color:var(--brd)}
.fbar-dd-it-n{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* trailing per-option count badge (e.g. status pills moved into the dropdown) */
.fbar-dd-it-ct{flex-shrink:0;font-family:var(--font-mono);font-weight:600;font-size:var(--fs-xxs);color:var(--t3)}
.fbar-dd-it.is-sel .fbar-dd-it-ct{color:var(--brd)}
.fbar-dd-it-lead{color:var(--co);font-size:var(--fs-sm)}
.fbar-dd-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0}
.fbar-dd-sep{height:1px;background:var(--bd);margin:4px 2px}
.fbar-dd-empty{padding:10px;text-align:center;color:var(--t4);font-size:var(--fs-xs);font-weight:500}
.fbar-dd-ft{border-top:1px solid var(--bd);margin-top:4px;padding-top:5px}
.fbar-dd-ft button{width:100%;padding:7px;border:0;border-radius:7px;background:transparent;color:var(--er);font-family:var(--font-body);font-weight:600;font-size:var(--fs-xs);cursor:pointer}
.fbar-dd-ft button:hover{background:var(--erl)}
/* multi-select checkbox */
.fbar-ckb{
    width:18px;height:18px;border-radius:5px;border:1.5px solid var(--bd);background:var(--sf);
    display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;transition:.12s;color:transparent;font-size:var(--fs-xxs);
}
.fbar-ckb.is-on{background:var(--br);border-color:var(--br);color:#fff}

/* search */
.fbar-search{display:inline-flex;align-items:center;gap:8px;padding:6px 11px;border-radius:7px;background:var(--sf);border:1px solid var(--bd);min-width:240px;transition:.12s}
.fbar-search i{color:var(--t4);font-size:var(--fs-sm)}
.fbar-search input{flex:1;border:0;background:transparent;outline:none;font-family:var(--font-body);font-size:var(--fs-sm);color:var(--tx);font-weight:500;min-width:0}
.fbar-search input::placeholder{color:var(--t4);font-weight:400}
.fbar-search.is-disabled{opacity:.6;pointer-events:none}
.fbar-search-x{border:0;background:transparent;color:var(--t4);cursor:pointer;font-size:var(--fs-sm);padding:0;display:inline-flex}
.fbar-search-x:hover{color:var(--er)}

/* KPI strips placed above a <x-filter-bar> need the same page gutter as the bar's
   pills (the .fbar carries its own 28px; a bare .kpis grid has none). Add this class
   to a KPI row that sits directly above the filter bar so they line up. */
.kpis-pad{padding-left:28px;padding-right:28px}
@media (max-width:760px){ .kpis-pad{padding-left:16px;padding-right:16px} }

/* ── mobile: row 1 = views + search, row 2 = one scrollable pill row ── */
@media (max-width:760px){
    /* keep the horizontal inset page-driven on mobile too (var(--fbar-x)); the
       .fbar-filters bleed below re-aligns the scrolling pill row to it. */
    .fbar{flex-direction:row;flex-wrap:wrap;gap:9px;padding:12px var(--fbar-x, 0px) 8px}
    .fbar-sep{display:none}
    .fbar-views{order:1}
    .fbar-search{order:2;margin-left:auto;min-width:0;flex:1}
    .fbar-sp{display:none}
    .fbar-filters{
        display:flex;order:3;flex-basis:100%;width:100%;gap:8px;
        overflow-x:auto;flex-wrap:nowrap;scrollbar-width:none;
        touch-action:pan-x;overscroll-behavior-x:contain;
        margin:0 -16px;padding:2px 16px;
    }
    .fbar-filters::-webkit-scrollbar{display:none}
    .fbar-dd{border-radius:999px;padding:7px 14px}
    /* on mobile the desktop popover is hidden — the open dropdown is the real <x-modal>
       sheet (.fbar-modal), which brings the backdrop, header, X and slide in/out for free. */
    .fbar-dd-pop{display:none !important}
    .fbar-dd-custom-desktop{display:none !important}
    .fbar-dd-it{padding:12px 12px}
}

/* ═══ Client picker (x-client-picker) — reusable client/contact selector ═══
   Self-contained so it works on any page (no dependency on the booking-kit's
   page-local .bm-* styles). Reuses the global .sel-card / .pick-search / .lrow
   from modal-kit.css for the card, search box and result rows. */
.cpick{display:block}
.cpick-trigger{display:flex;align-items:center;gap:10px;width:100%;padding:11px 13px;border:1.5px solid var(--bd);border-radius:10px;background:var(--sf);cursor:pointer;transition:.14s;text-align:left}
.cpick-trigger:hover{border-color:var(--t4);background:var(--bl)}
.cpick-trigger-ic{color:var(--t4);font-size:var(--fs-sm)}
.cpick-trigger-ph{flex:1;min-width:0;color:var(--t3);font-size:var(--fs-sm);font-family:var(--font-body)}
.cpick-trigger-chev{color:var(--t4);font-size:var(--fs-xs)}
.cpick-list{display:flex;flex-direction:column;gap:4px;margin-top:4px}
.cpick-meta{flex:1;min-width:0}
.cpick-meta .n{font-size:var(--fs-sm);font-weight:600;color:var(--tx);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cpick-meta .sub{font-size:var(--fs-xs);color:var(--t3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cpick-empty{padding:24px 16px;text-align:center}
.cpick-empty-ic{font-size:22px;color:var(--t3);opacity:.6;display:block;margin-bottom:8px}
.cpick-empty-t{font-family:var(--font-display);font-weight:700;color:var(--tx);margin-bottom:4px}
.cpick-empty-s{font-size:var(--fs-xs);color:var(--t3);margin-bottom:10px}
.cpick-create{display:flex;align-items:center;justify-content:center;gap:7px;width:100%;margin-top:6px;padding:9px 12px;border:1px dashed var(--bd);border-radius:9px;background:transparent;color:var(--t2);font-family:var(--font-display);font-weight:600;font-size:var(--fs-xs);cursor:pointer;transition:.14s}
.cpick-create:hover{border-color:var(--br,var(--co));color:var(--brd,var(--co));background:var(--bl)}
.cpick-spin{width:14px;height:14px;border:2px solid var(--bd);border-top-color:var(--br,var(--co));border-radius:50%;display:inline-block;animation:cpick-spin .6s linear infinite}
@keyframes cpick-spin{to{transform:rotate(360deg)}}

/* ═══ Appointment practitioner chips + picker modal (x-schedule-appointment) ═══
   Agenda-style chips; "+ Add" opens a teleported slide-over with multi-select toggle. */
.appt-pract-wrap{display:flex;flex-wrap:wrap;gap:7px;align-items:center}
.appt-pract-chip{display:inline-flex;align-items:center;gap:7px;padding:5px 7px 5px 6px;border-radius:8px;background:var(--sf);border:1px solid var(--bd);font-family:var(--font-display);font-weight:700;font-size:var(--fs-xs);color:var(--t2)}
.appt-pract-chip .av{width:22px;height:22px;border-radius:6px;font-size:10px}
.appt-pract-chip .x{width:18px;height:18px;border-radius:5px;border:0;background:transparent;color:var(--t3);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:10px;transition:.12s}
.appt-pract-chip .x:hover{background:var(--erl);color:var(--er)}
.appt-pract-add{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:8px;border:1.5px dashed var(--bd2,var(--bd));background:transparent;color:var(--t2);cursor:pointer;font-family:var(--font-display);font-weight:700;font-size:var(--fs-xs);transition:.14s}
.appt-pract-add:hover{border-color:var(--br,var(--co));color:var(--tx)}
.appt-pract-pick-list{display:flex;flex-direction:column;gap:3px}
.appt-pract-pick-it{display:flex;align-items:center;gap:10px;width:100%;padding:9px 10px;border-radius:9px;border:1px solid transparent;background:transparent;cursor:pointer;text-align:left;transition:.12s}
.appt-pract-pick-it:hover{background:var(--bl)}
.appt-pract-pick-it.on{background:var(--brl,var(--bl));border-color:var(--br,var(--bd))}
.appt-pract-pick-it .av{width:28px;height:28px;border-radius:7px;font-size:11px;flex-shrink:0}
.appt-pract-pick-nm{flex:1;min-width:0;display:flex;flex-direction:column}
.appt-pract-pick-nm .n{font-family:var(--font-display);font-weight:600;font-size:var(--fs-sm);color:var(--tx);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.appt-pract-pick-nm .sub{font-size:var(--fs-xs);color:var(--t3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.appt-pract-pick-ck{width:22px;height:22px;border-radius:50%;border:1.5px solid var(--bd);display:inline-flex;align-items:center;justify-content:center;color:transparent;font-size:10px;flex-shrink:0;transition:.12s}
.appt-pract-pick-it.on .appt-pract-pick-ck{background:var(--br,var(--co));border-color:var(--br,var(--co));color:#fff}

/* ── Phone input (<x-phone-input>) ────────────────────────────────────────
   Design-system component. Lives here (global, <link>-loaded in <head>) so it
   is reliably styled in EVERY context — including modals whose markup is
   teleported/x-if'd (the create/edit-sucursal modal), where the component's
   own runtime style-injector <script> never executes. The component keeps that
   JS injector only as a fallback for layouts that don't load this file. */
.phx-wrap{position:relative;display:flex;align-items:stretch;width:100%;font-family:var(--font-body);box-sizing:border-box}
.phx-wrap *,.phx-wrap *::before,.phx-wrap *::after{box-sizing:border-box}
.phx-trigger{display:flex;align-items:center;gap:7px;padding:0 10px;border:1px solid var(--bd);border-right:none;border-radius:9px 0 0 9px;background:var(--bg2);cursor:pointer;font-size:var(--fs-sm);font-family:var(--font-body);white-space:nowrap;user-select:none;color:var(--tx);transition:background .12s,border-color .12s;min-height:38px;flex:0 0 auto}
.phx-trigger:hover{background:var(--bd)}
.phx-trigger.is-open{border-color:var(--br);background:var(--sf);z-index:2;position:relative}
.phx-trigger[disabled],.phx-trigger.is-disabled{cursor:not-allowed;opacity:.55}
.phx-flag{display:inline-block;width:22px;height:16px;border-radius:3px;flex-shrink:0;box-shadow:inset 0 0 0 1px rgba(20,18,15,.10)}
.phx-code{font-weight:600;letter-spacing:.2px;font-family:var(--font-mono);font-size:var(--fs-xs)}
.phx-chev{font-size:var(--fs-xs);color:var(--t3);transition:transform .15s;margin-left:1px}
.phx-trigger.is-open .phx-chev{transform:rotate(180deg)}
.phx-input{flex:1 1 auto;min-width:0;padding:0 12px;border:1px solid var(--bd);border-radius:0 9px 9px 0;font-family:var(--font-body);font-size:var(--fs-sm);background:var(--sf);color:var(--tx);outline:none;min-height:38px;transition:border-color .12s,box-shadow .12s}
.phx-input:focus{border-color:var(--br);box-shadow:0 0 0 3px var(--brl)}
.phx-input[disabled]{background:var(--bg2);color:var(--t3);cursor:not-allowed}
.phx-wrap.phx-sm .phx-trigger,.phx-wrap.phx-sm .phx-input{min-height:32px;font-size:var(--fs-xs)}
.phx-wrap.phx-lg .phx-trigger,.phx-wrap.phx-lg .phx-input{min-height:44px;font-size:var(--fs-base)}
.phx-dd{position:fixed;top:0;left:0;background:var(--sf);border:1px solid var(--bd);border-radius:11px;box-shadow:0 14px 34px rgba(20,18,15,.18);z-index:2147483000;width:264px;max-height:248px;overflow-y:auto;padding:5px;display:none}
.phx-dd.is-open{display:block}
.phx-opt{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;cursor:pointer;font-size:var(--fs-xs);color:var(--tx);transition:background .08s}
.phx-opt:hover{background:var(--bg2)}
.phx-opt.is-selected{background:var(--brl);color:var(--br);font-weight:600}
.phx-opt-flag{display:inline-block;width:22px;height:16px;border-radius:2px;flex-shrink:0;box-shadow:inset 0 0 0 1px rgba(20,18,15,.10)}
.phx-opt-name{flex:1;font-weight:500}
.phx-opt-code{color:var(--t3);font-size:var(--fs-xs);font-weight:600;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.phx-opt.is-selected .phx-opt-code{color:var(--br)}
.phx-opt-check{font-size:var(--fs-xs);color:var(--br);opacity:0;flex-shrink:0}
.phx-opt.is-selected .phx-opt-check{opacity:1}
.phx-search{padding:6px 7px;border-bottom:1px solid var(--bd);position:sticky;top:-5px;background:var(--sf);margin:-5px -5px 5px -5px}
.phx-search input{width:100%;border:1px solid var(--bd);border-radius:7px;padding:7px 9px;font-size:var(--fs-xs);font-family:var(--font-body);background:var(--bg2);color:var(--tx);outline:none}
.phx-search input:focus{border-color:var(--br)}

/* ════════════════════════════════════════════════════════════════════════
   RICH PAGE PATTERNS — ported from the Kilto Design System project
   (claude.ai/design "Kilto Design System" → tokens/components.css), the
   patterns the manually-iterated mockups use. Shared bare classes — pages
   compose these, never redefine them. Documented in docs/UI_REFERENCE.html
   (§sect-hd, §banner, §alerts, §rcard, §agenda, §weektiles, §actfeed,
   §perf, §entitycards, §kanban, §panelrich).
   Naming maps (bundle ⇄ product): .dd-* ⇄ .fbar-dd-* · .cmdk-* ⇄ .cmd-*
   (live palette in layouts/partials/command-palette.blade.php) · .pg ⇄ .pag
   · .tb-search ⇄ .fbar-search. Do NOT add the bundle-side names here.
   ════════════════════════════════════════════════════════════════════════ */

/* ── Section header (in-page, editorial serif — §sect-hd) ── */
.sect-hd{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;margin:24px 0 12px}
.sect-hd:first-child{margin-top:0}
.sect-t{font-family:var(--font-serif);font-weight:600;font-size:22px;color:var(--tx);letter-spacing:-.018em;line-height:1.15;margin:0}
.sect-t em{font-style:italic;color:var(--co);font-weight:500}
.sect-s{font-size:13px;color:var(--t3);font-weight:500;margin-top:2px}
.sect-link{font-size:13.5px;color:var(--brd);font-weight:700;font-family:var(--font-display);cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;gap:5px}
.sect-link:hover{color:var(--co)}
.sect-link i{font-size:10px}

/* ── Urgent banner (violet→coral wash — §banner) ── */
.banner{display:flex;align-items:center;gap:13px;padding:13px 17px;background:linear-gradient(105deg,var(--vil) 0%,var(--col) 100%);border:1px solid var(--bd);border-radius:13px;margin-bottom:18px;position:relative;overflow:hidden}
.banner::before{content:'';position:absolute;right:-40px;top:-40px;width:200px;height:200px;border-radius:50%;background:radial-gradient(circle,rgba(124,58,237,.10),transparent 70%);pointer-events:none}
.banner-ic{width:38px;height:38px;border-radius:10px;background:linear-gradient(135deg,var(--er),var(--co));color:#fff;display:flex;align-items:center;justify-content:center;font-size:15px;flex-shrink:0;box-shadow:0 4px 12px rgba(192,52,52,.22);position:relative;z-index:1}
.banner-info{flex:1;min-width:0;position:relative;z-index:1}
.banner-t{font-family:var(--font-display);font-weight:800;font-size:14.5px;color:var(--tx)}
.banner-t em{font-family:var(--font-serif);font-style:italic;font-weight:600;color:var(--er)}
.banner-s{margin-top:3px;font-size:13px;color:var(--t2);font-weight:500;line-height:1.5}
.banner-s strong{font-family:var(--font-display);font-weight:700;color:var(--tx)}

/* ── Alert cards (attention grid — §alerts) ── */
.alerts{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
.alert-card{display:flex;flex-direction:column;gap:8px;padding:14px 16px;background:var(--sf);border:1px solid var(--bd);border-radius:12px;cursor:pointer;transition:.14s;position:relative;overflow:hidden}
.alert-card:hover{border-color:var(--t4);transform:translateY(-1px);box-shadow:0 4px 12px rgba(20,18,15,.06)}
.alert-card.er{border-color:rgba(192,52,52,.28)}
.alert-card.er:hover{border-color:var(--er)}
.alert-card.wn{border-color:rgba(180,83,9,.24)}
.alert-card.wn:hover{border-color:var(--wn)}
.alert-hd{display:flex;align-items:center;gap:10px}
.alert-ic{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:13.5px;flex-shrink:0;background:var(--bl);color:var(--t2)}
.alert-card.er .alert-ic{background:var(--erl);color:var(--erd)}
.alert-card.wn .alert-ic{background:var(--wnl);color:var(--wnd)}
.alert-card.inf .alert-ic{background:var(--infl);color:var(--infd)}
.alert-t{font-family:var(--font-display);font-weight:800;font-size:13.5px;color:var(--tx);letter-spacing:-.008em}
.alert-count{margin-left:auto;font-family:var(--font-display);font-weight:900;font-size:24px;line-height:1;color:var(--tx);letter-spacing:-.025em}
.alert-card.er .alert-count{color:var(--erd)}
.alert-card.wn .alert-count{color:var(--wnd)}
.alert-s{font-size:12.5px;color:var(--t2);line-height:1.5}
.alert-s strong{font-family:var(--font-display);font-weight:700;color:var(--tx)}
.alert-cta{display:flex;align-items:center;gap:5px;margin-top:auto;padding-top:4px;font-family:var(--font-display);font-weight:700;font-size:12px;color:var(--brd);letter-spacing:-.005em}
.alert-cta i{font-size:9px}
.alert-card.er .alert-cta{color:var(--erd)}
.alert-card.wn .alert-cta{color:var(--wnd)}
.all-clear{grid-column:1/-1;display:flex;align-items:center;gap:12px;padding:18px 20px;background:linear-gradient(105deg,var(--okl) 0%,var(--sf) 70%);border:1px solid rgba(21,128,61,.18);border-radius:12px}
.all-clear-ic{width:42px;height:42px;border-radius:11px;background:var(--ok);color:#fff;display:flex;align-items:center;justify-content:center;font-size:17px;flex-shrink:0}
.all-clear-t{font-family:var(--font-display);font-weight:800;font-size:14.5px;color:var(--tx)}
.all-clear-s{font-size:13px;color:var(--t2);margin-top:2px}

/* ── Rich card (header + count sub-row — §rcard) ── */
.rcard{background:var(--sf);border:1px solid var(--bd);border-radius:14px;overflow:hidden}
.rcard-hd{padding:14px 18px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--bd);background:var(--sf)}
.rcard-t{font-family:var(--font-display);font-weight:800;font-size:14.5px;color:var(--tx);letter-spacing:-.012em}
.rcard-sub{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 18px;border-bottom:1px solid var(--bd);background:var(--bl)}
.rcard-cnt{font-size:12.5px;color:var(--t3);font-family:var(--font-mono);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1}
.rcard-actions{display:flex;gap:6px;flex-shrink:0}

/* ── Agenda rows (timeline — §agenda) ── */
.ag{padding:12px 14px 14px}
.ag-rows{display:flex;flex-direction:column;gap:6px}
.ag-row{display:flex;align-items:center;gap:13px;padding:10px 12px;border:1px solid var(--bd);border-radius:10px;cursor:pointer;transition:.14s;background:var(--sf);position:relative}
.ag-row:hover{border-color:var(--t4);background:var(--bl);transform:translateX(2px)}
.ag-row.done{opacity:.6}
.ag-row.done .ag-name{text-decoration:line-through}
.ag-row.now{border-color:var(--co);background:var(--col);box-shadow:0 0 0 3px rgba(233,78,43,.10)}
.ag-row.now::after{content:'NOW';position:absolute;right:14px;top:50%;transform:translateY(-50%);font-family:var(--font-mono);font-weight:700;font-size:10px;color:var(--co);letter-spacing:.08em;background:var(--sf);padding:2px 6px;border-radius:4px;border:1px solid var(--co)}
.ag-row.now .ag-status{visibility:hidden}
.ag-time{display:flex;flex-direction:column;align-items:center;width:60px;flex-shrink:0;border-right:1px solid var(--bd);padding-right:13px}
.ag-hour{font-family:var(--font-display);font-size:15.5px;font-weight:800;color:var(--tx);line-height:1;letter-spacing:-.01em}
.ag-dur{font-size:10.5px;color:var(--t3);margin-top:4px;font-family:var(--font-mono);font-weight:600}
.ag-avatar{width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;color:#fff;font-family:var(--font-display);font-weight:800;font-size:11.5px;flex-shrink:0;letter-spacing:-.01em}
.ag-main{flex:1;min-width:0}
.ag-name{font-size:14px;font-weight:700;color:var(--tx);line-height:1.3;font-family:var(--font-display);letter-spacing:-.008em}
.ag-svc{font-size:12.5px;color:var(--t3);margin-top:2px;display:flex;align-items:center;gap:8px}
.ag-svc i{font-size:10px;color:var(--t4)}
.ag-svc .plan{color:var(--brd);font-weight:600}
.ag-status{display:flex;align-items:center}
.ag-staff{display:flex;align-items:center;gap:6px;color:var(--t3);font-size:12px;font-weight:600;padding-left:10px;border-left:1px solid var(--bd);margin-left:2px}
.ag-staff-av{width:22px;height:22px;border-radius:50%;background:var(--brl);color:var(--brd);display:flex;align-items:center;justify-content:center;font-family:var(--font-display);font-weight:800;font-size:10px}

/* ── Week tiles (7-day load strip — §weektiles) ── */
.wk-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:8px}
.wk-day{padding:14px 12px;border:1px solid var(--bd);border-radius:11px;background:var(--sf);cursor:pointer;transition:.14s;text-align:left;font-family:var(--font-body)}
.wk-day:hover{border-color:var(--t4);transform:translateY(-1px);box-shadow:0 4px 12px rgba(20,18,15,.06)}
.wk-day.today{border-color:var(--co);background:linear-gradient(180deg,var(--col) 0%,var(--sf) 60%)}
.wk-day-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:9px}
.wk-day-name{font-family:var(--font-display);font-weight:800;font-size:11.5px;color:var(--t4);text-transform:uppercase;letter-spacing:.08em}
.wk-day.today .wk-day-name{color:var(--co)}
.wk-day-num{font-family:var(--font-display);font-weight:800;font-size:22px;color:var(--tx);letter-spacing:-.024em;line-height:1}
.wk-day-meta{font-size:12px;color:var(--t3);font-weight:500;margin-bottom:8px}
.wk-day-bar{height:6px;border-radius:99px;background:var(--bl);overflow:hidden}
.wk-day-bar i{display:block;height:100%;background:linear-gradient(90deg,var(--br),var(--co));border-radius:99px;transition:.3s}

/* ── Activity feed (compact event stream — §actfeed) ── */
.act-list{display:flex;flex-direction:column;max-height:380px;overflow-y:auto}
.act-row{display:flex;align-items:flex-start;gap:11px;padding:11px 18px;border-bottom:1px solid var(--bl)}
.act-row:last-child{border-bottom:0}
.act-row:hover{background:var(--bl)}
.act-dot{width:30px;height:30px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:12px}
.act-main{flex:1;min-width:0}
.act-text{font-size:13px;color:var(--tx);line-height:1.45}
.act-text strong{font-weight:700;color:var(--tx)}
.act-text em{font-style:normal;color:var(--brd);font-weight:600}
.act-time{font-size:11px;color:var(--t4);margin-top:3px;font-family:var(--font-mono);font-weight:500;letter-spacing:.02em}

/* ── Performance recap card (period KPIs + sparklines — §perf) ── */
.perf{background:var(--sf);border:1px solid var(--bd);border-radius:14px;overflow:hidden;margin-top:18px}
.perf-hd{padding:16px 20px 8px;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.perf-eyebrow{font-family:var(--font-mono);font-weight:600;font-size:11px;color:var(--t3);text-transform:uppercase;letter-spacing:.12em}
.perf-t{font-family:var(--font-serif);font-weight:600;font-size:24px;color:var(--tx);letter-spacing:-.02em;line-height:1.1;margin-top:5px}
.perf-t em{font-style:italic;color:var(--co);font-weight:500}
.perf-s{font-size:13px;color:var(--t2);margin-top:5px}
.perf-s strong{font-family:var(--font-display);font-weight:700;color:var(--tx)}
.perf-progress{display:flex;flex-direction:column;gap:5px;align-items:flex-end;min-width:160px;padding-top:4px}
.perf-progress-l{font-family:var(--font-mono);font-size:11px;color:var(--t3);font-weight:600;text-transform:uppercase;letter-spacing:.08em}
.perf-progress-bar{width:160px;height:5px;background:var(--bl);border-radius:99px;overflow:hidden}
.perf-progress-bar i{display:block;height:100%;background:linear-gradient(90deg,var(--br),var(--co));border-radius:99px}
.perf-progress-sub{font-size:11px;color:var(--t4);font-family:var(--font-mono);font-weight:500}
.perf-grid{display:grid;grid-template-columns:repeat(4,1fr);padding:18px 20px 20px;gap:0}
.perf-kpi{padding:0 20px;border-right:1px solid var(--bd);display:flex;flex-direction:column;gap:6px}
.perf-kpi:first-child{padding-left:0}
.perf-kpi:last-child{border-right:0;padding-right:0}
.perf-kpi-l{font-family:var(--font-mono);font-size:11px;color:var(--t3);font-weight:600;text-transform:uppercase;letter-spacing:.08em}
.perf-kpi-v{font-family:var(--font-display);font-weight:800;font-size:30px;color:var(--tx);letter-spacing:-.026em;line-height:1;font-feature-settings:'tnum';display:flex;align-items:baseline;gap:5px}
.perf-kpi-v .unit{font-size:14px;font-weight:600;color:var(--t3);font-family:var(--font-display);letter-spacing:0}
.perf-kpi-delta{font-family:var(--font-display);font-size:12px;font-weight:700;display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:5px;letter-spacing:.005em;width:fit-content}
.perf-kpi-delta.up{color:var(--ok);background:var(--okl)}
.perf-kpi-delta.dn{color:var(--er);background:var(--erl)}
.perf-kpi-delta.flat{color:var(--t3);background:var(--bl)}
.perf-kpi-delta i{font-size:9px}
.spark{display:flex;align-items:flex-end;gap:2px;height:24px;margin-top:5px}
.spark b{display:block;flex:1;background:var(--br);opacity:.4;border-radius:1px 1px 0 0;min-height:2px;transition:.18s}
.spark b.cur{opacity:1;background:var(--co)}

/* ── Table identity cell (avatar + name + sub — §ct-name) ── */
.ct-name{display:flex;align-items:center;gap:10px;min-width:0}
.ct-name-info{min-width:0}
.ct-name-n{font-family:var(--font-display);font-weight:700;font-size:14px;color:var(--tx);letter-spacing:-.005em;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}
.ct-name-sub{font-size:12px;color:var(--t3);font-weight:500;margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}

/* ── Entity cards view (grid alternative to the table — §entitycards) ── */
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
.cd{background:var(--sf);border:1px solid var(--bd);border-radius:13px;padding:16px 18px;cursor:pointer;transition:.14s;position:relative;overflow:hidden;display:flex;flex-direction:column;gap:12px}
.cd::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--co);transform:scaleY(0);transform-origin:center;transition:.16s}
.cd:hover{border-color:var(--bd2);box-shadow:0 4px 14px rgba(20,18,15,.04)}
.cd:hover::before{transform:scaleY(1)}
.cd.sel{background:var(--brl);border-color:rgba(9,9,11,.22)}
.cd.sel::before{transform:scaleY(1)}
.cd-hd{display:flex;align-items:flex-start;gap:11px}
.cd-info{flex:1;min-width:0}
.cd-name{font-family:var(--font-serif);font-weight:600;font-size:17px;color:var(--tx);letter-spacing:-.012em;line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cd-co{font-style:italic;font-family:var(--font-serif);font-size:13.5px;color:var(--t3);font-weight:500;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cd-tags{display:flex;flex-wrap:wrap;gap:5px}
.cd-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;padding:11px;background:var(--bl);border-radius:9px}
.cd-stat{text-align:center}
.cd-stat-l{font-size:10.5px;color:var(--t3);font-weight:700;text-transform:uppercase;letter-spacing:.05em;margin-bottom:3px}
.cd-stat-v{font-family:var(--font-display);font-weight:800;font-size:15px;color:var(--tx);letter-spacing:-.012em;line-height:1;font-feature-settings:'tnum'}
.cd-ft{display:flex;align-items:center;gap:11px;font-size:12px;color:var(--t3);font-weight:600;flex-wrap:wrap;border-top:1px solid var(--bl);padding-top:10px}
.cd-ft i{font-size:11px;margin-right:3px}
.cd-ft strong{font-family:var(--font-mono);font-weight:700;color:var(--tx)}

/* ── Kanban board (pipeline journey — §kanban) ──
   Column stage color rides the `--stg-c` custom property set inline per column. */
.kb-board{display:flex;gap:11px;overflow-x:auto;overflow-y:visible;padding:0 28px 24px;scroll-behavior:smooth;align-items:flex-start}
.kb-col{width:284px;min-width:284px;flex-shrink:0;background:var(--bg2);border:1px solid var(--bd);border-radius:13px;display:flex;flex-direction:column;max-height:calc(100vh - 100px);transition:.15s}
.kb-col-hd{padding:12px 14px 9px;display:flex;align-items:center;gap:7px;flex-shrink:0}
.kb-col-dot{width:9px;height:9px;border-radius:50%;background:var(--stg-c,#a6a39d);box-shadow:0 0 0 2px var(--bg2),0 0 0 3px var(--stg-c,#a6a39d);flex-shrink:0}
.kb-col-n{font-family:var(--font-display);font-weight:800;font-size:11.5px;color:var(--tx);text-transform:uppercase;letter-spacing:.07em}
.kb-col-ct{font-family:var(--font-mono);font-weight:700;font-size:10.5px;color:var(--t3);background:var(--sf);padding:1px 6px;border-radius:3px;border:1px solid var(--bd)}
.kb-col-v{margin-left:auto;font-family:var(--font-serif);font-weight:700;font-size:13px;color:var(--tx);font-feature-settings:'tnum';letter-spacing:-.015em}
.kb-col-pbar{height:3px;margin:0 14px 7px;background:var(--bl);border-radius:2px;overflow:hidden;flex-shrink:0}
.kb-col-pbar i{display:block;height:100%;background:linear-gradient(90deg,var(--br),var(--co));border-radius:2px}
.kb-col-bd{flex:1;overflow-y:auto;padding:4px 10px 8px;display:flex;flex-direction:column;gap:7px;min-height:60px}
.kb-col-ft{padding:7px 10px 10px;flex-shrink:0}
.kb-col-add{width:100%;padding:7px 10px;border:1px dashed var(--bd2);background:transparent;border-radius:7px;color:var(--t3);font-family:var(--font-display);font-weight:700;font-size:12.5px;cursor:pointer;transition:.12s;display:inline-flex;align-items:center;justify-content:center;gap:6px}
.kb-col-add:hover{border-color:var(--t4);color:var(--tx);background:var(--bl)}
.kb-col-empty{padding:20px 12px;text-align:center;color:var(--t4);font-size:12px;font-style:italic;border:1px dashed var(--bd);border-radius:9px;background:var(--bl)}
.kb-card{background:var(--sf);border:1px solid var(--bd);border-radius:10px;padding:11px 12px 10px;cursor:pointer;position:relative;user-select:none;box-shadow:0 1px 2px rgba(20,18,15,.03);transition:.12s}
.kb-card:hover{border-color:var(--t4);box-shadow:0 4px 12px rgba(20,18,15,.07)}
.kb-card.sel{border-color:var(--br);box-shadow:0 0 0 2px var(--brl)}
.kb-card-cb{position:absolute;top:9px;right:9px;width:18px;height:18px;border:1.5px solid var(--bd2);border-radius:5px;background:var(--sf);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:.14s;z-index:3;box-shadow:0 1px 3px rgba(20,18,15,.08);color:#fff;font-size:10px}
.kb-card:hover .kb-card-cb,.kb-card.sel .kb-card-cb{opacity:1}
.kb-card-cb.on{background:var(--br);border-color:var(--br)}
.kb-card-hd{display:flex;align-items:center;gap:6px;margin-bottom:7px}
.kb-card-ttl{font-family:var(--font-display);font-weight:700;font-size:13.5px;color:var(--tx);line-height:1.3;margin-bottom:8px;letter-spacing:-.005em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.kb-card-c{display:flex;align-items:center;gap:7px;margin-bottom:8px;font-size:12.5px;color:var(--t3);font-weight:500}
.kb-card-m{display:flex;align-items:center;gap:8px}
.kb-card-v{font-family:var(--font-mono);font-weight:700;font-size:13px;color:var(--tx);font-feature-settings:'tnum'}
.kb-card-d{margin-left:auto;display:inline-flex;align-items:center;gap:3px;font-family:var(--font-mono);font-weight:600;font-size:10.5px;color:var(--t4)}
.kb-card-d.warn{color:var(--wn)}
.kb-card-d.danger{color:var(--er)}
.kb-card-tags{display:flex;gap:4px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px dashed var(--bd)}

/* ── Panel rich content · value hero, AI score, timeline (§panelrich) ──
   Extend the slide-over panel body (.panel-bd). Tabs/footer use the existing
   .panel-tabs / .panel-ft — do not port the bundle's .pn-tabs/.pn-ft twins. */
.pn-hero{border:1px solid var(--bd);border-radius:11px;background:linear-gradient(135deg,var(--vil) 0%,var(--col) 100%);padding:16px 18px;position:relative;overflow:hidden}
.pn-hero-l{font-family:var(--font-mono);font-weight:600;font-size:10.5px;color:var(--t3);text-transform:uppercase;letter-spacing:.1em;margin-bottom:6px}
.pn-hero-v{font-family:var(--font-serif);font-weight:700;font-size:32px;color:var(--tx);letter-spacing:-.025em;line-height:1.05;font-feature-settings:'tnum'}
.pn-hero-v em{font-style:italic;font-size:17px;color:var(--t3);font-weight:500}
.pn-hero-s{margin-top:6px;font-size:13px;color:var(--t2);font-weight:500;line-height:1.5}
.pn-hero-s strong{font-family:var(--font-display);font-weight:700;color:var(--tx)}
.pn-ai{display:flex;align-items:center;gap:14px;padding:14px;border:1px solid var(--bd);border-radius:11px;background:var(--sf)}
.pn-ai-ring{position:relative;width:68px;height:68px;flex-shrink:0}
.pn-ai-ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.pn-ai-ring .v{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-family:var(--font-display);font-weight:900;font-size:19px;color:var(--tx);letter-spacing:-.02em}
.pn-ai-info{flex:1;min-width:0}
.pn-ai-l{font-family:var(--font-display);font-weight:800;font-size:13.5px;color:var(--tx)}
.pn-ai-l em{font-style:italic;font-family:var(--font-serif);color:var(--co);font-weight:600}
.pn-ai-s{font-size:12.5px;color:var(--t3);margin-top:3px;line-height:1.5;font-weight:500}
.pn-ai-axes{display:flex;gap:14px;margin-top:9px;flex-wrap:wrap;font-family:var(--font-mono);font-size:10.5px;color:var(--t3);font-weight:600;text-transform:uppercase;letter-spacing:.05em}
.pn-ai-axes b{color:var(--tx);font-weight:700}
.pn-tl{display:flex;flex-direction:column;border-left:2px solid var(--bd);margin-left:8px;padding-left:18px}
.pn-tl-it{margin-bottom:16px;position:relative}
.pn-tl-dot{position:absolute;left:-27px;top:2px;width:14px;height:14px;border-radius:50%;background:var(--bl);border:2px solid var(--sf);box-shadow:0 0 0 2px var(--t4);display:flex;align-items:center;justify-content:center;font-size:6px;color:var(--t3)}
.pn-tl-t{font-family:var(--font-display);font-weight:700;font-size:13.5px;color:var(--tx);letter-spacing:-.005em}
.pn-tl-t strong{font-weight:800}
.pn-tl-s{font-size:12.5px;color:var(--t3);margin-top:3px;font-weight:500;line-height:1.5}
.pn-tl-when{font-family:var(--font-mono);font-weight:500;font-size:10.5px;color:var(--t4);margin-top:4px}

/* ── Responsive steps for the rich patterns ── */
@media(max-width:1100px){
  .perf-grid{grid-template-columns:repeat(2,1fr);row-gap:16px}
  .perf-kpi{padding:0 16px}
  .perf-kpi:nth-child(2n){border-right:0}
  .wk-grid{grid-template-columns:repeat(4,1fr)}
}
@media(max-width:820px){
  .kb-board{padding:0 16px 16px;gap:9px}
  .kb-col{width:240px;min-width:240px}
  .alerts{grid-template-columns:1fr}
  .wk-grid{grid-template-columns:repeat(2,1fr)}
  .ag-staff{display:none}
}

/* -- Pagination (.pgn) -- */
/* PROMOTED 2026-09-09 out of `app/Modules/Sales/Views/field-sales/preview.blade.php` (i.e.
 * out of the generated OPT-IN chunk `styles/web/_field-sales-page.css`). This is the app's
 * most-used pager grammar and it was declared in ONE page's route chunk, bare. That is the
 * REVERSE of the leak this pass kills: a bare rule in an opt-in sheet does not just outrank
 * the shared layer once it is injected - the class it defines does not exist AT ALL until
 * someone visits the owning screen. Measured: `getComputedStyle(.pgn).display` read `block`
 * on a cold load and `flex` only after Field Sales had been opened.
 *
 * The values are the field-sales cascade's EFFECTIVE ones, not a redesign: `.pgn-info` merges
 * the first declaration's `margin-left:11px` with the later override that wins on padding,
 * family, size and weight. The field-sales copy is DROPPED by `tools/web-css-sync.mjs`
 * (`PGN_NAMES`) rather than scoped, so this is the family's single definition and the screen
 * it came from renders from it too - a confined `.fs-app .pgn` at (0,2,0) would have
 * outranked this block forever and left two copies to keep in step. Telephony (`#phonehub`)
 * and Trading (`#tm42`/`.tm42-so-panel`) ship their own, deliberately different pagers at id
 * specificity and outrank this block wherever they apply. */
.pgn{display:flex;align-items:center;justify-content:center;gap:6px;padding:22px 0 0}
.pgn-btn{padding:6px 11px;border-radius:7px;border:1px solid var(--bd);background:var(--sf);color:var(--t2);font-family:var(--font-display);font-weight:600;font-size:var(--fs-sm);cursor:pointer;min-width:32px;text-align:center;transition:.12s}
.pgn-btn:hover:not(:disabled){color:var(--tx);border-color:var(--t4)}
.pgn-btn:disabled{opacity:.4;cursor:not-allowed}
.pgn-btn.active{background:var(--br);color:var(--br-text);border-color:var(--br)}
.pgn-info{margin-left:11px;padding:0 11px;font-family:var(--font-display);font-weight:500;font-size:12.5px;color:var(--t3)}
.pgn-info strong{font-weight:700;color:var(--tx)}
@media(max-width:760px){
  .pgn{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;justify-content:flex-start;padding:18px 16px 0;scrollbar-width:none}
  .pgn::-webkit-scrollbar{display:none}
  .pgn-info{margin-left:8px;flex-shrink:0;font-size:11px}
}
