/* ═══════════════════════════════════════════════════════════
   AlexanianOS — Design System v1.0
   Red #A90432 · Blue #15486B · Near-Black #1F2124
   Font: Hanken Grotesk
   ═══════════════════════════════════════════════════════════ */

/* ── Custom Properties ──────────────────────────────────── */
:root {
    --color-orderwriter:              #A90432;
    --color-orderwriter-dark:         #8a0228;
    --color-paykeeper:             #15486B;
    --color-paykeeper-dark:        #103850;
    --color-near-black:       #1F2124;
    --color-near-black-dark:  #101214;
    --color-inventorycounter:            #1d6b4f;
    --color-inventorycounter-dark:       #16543e;
    /* Deep/burnt orange app identity. Deliberately darker than the two brighter SEMANTIC oranges
       (--color-warning #D97706, --color-orange #EA580C) so a solid accent action reads distinct from a
       tinted warning/orange state (the treatment rule) — ShiftKeeper's ambers (timeclock pending/blocked
       badges, IP enforcement-off card) are all tinted states, so they stay separate. App-named, NOT
       "--color-orange" — that token already exists as a semantic. */
    --color-shiftkeeper:           #C2410C;
    --color-shiftkeeper-dark:      #9A3412;
    --color-admin:            #64748b;
    --color-admin-dark:       #475569;
    /* Sky blue app identity — cooler and brighter than PayKeeper's navy, and distinct from the semantic
       info blue (#2563eb). PriceLister opens over OrderWriter's crimson, so it needs a clear cool
       contrast; the burnt orange it used to carry moved to ShiftKeeper to rebalance the suite (which had
       skewed cool once PriceLister went blue). */
    --color-pricelister:      #0369A1;
    --color-pricelister-dark: #075985;
    --color-reporter:         #7C3AED;
    --color-reporter-dark:    #6D28D9;
    /* Back-office charcoal: ONE shared colour for single-user, office-only apps (BankSitter; PurchaseMatcher
       next) so they don't use up the distinct colours the store-facing apps need (user, 2026-09-30).
       Darker than Admin's slate; the tiles are told apart by their initials. */
    --color-backoffice:       #374151;
    --color-backoffice-dark:  #1F2937;
    --color-banksitter:       var(--color-backoffice);
    --color-banksitter-dark:  var(--color-backoffice-dark);
    /* Indigo for A-Team Rewards (user, 2026-09-24; tried gold, then violet). Gold stacked badly against
       OrderWriter's crimson for everyday users (OrderWriter, PayKeeper, PriceLister, ShiftKeeper, A-Team);
       indigo is brighter than PayKeeper's navy and bluer than Reporter's violet #7C3AED. */
    --color-ateamrewards:      #4338CA;
    --color-ateamrewards-dark: #3730A3;
    /* Bronze for GoalTender (executive targets): the exact swatch the user supplied 2026-10-08. */
    --color-goaltender:       #A56C41;
    --color-goaltender-dark:  #7F5332;
    --color-appointments:     #0F766E;
    --color-appointments-dark: #115E59;

    /* ── App accent ──────────────────────────────────────────
       ⚠️ POLICY: each app is themed by REBINDING THIS ONE VARIABLE (see .app-orderwriter etc.
       below), never by overriding individual selectors per app. PayKeeper originally re-themed
       itself selector-by-selector and the job came out half-done — its tabs and pills went green
       while every btn-primary stayed red — because each new component had to remember to opt in.
       Bind the variable and control chrome follows automatically.

       --app-accent is for CONTROL CHROME ONLY: buttons, active tabs, active nav, toggles, focus
       rings. It must NEVER carry meaning. State always comes from the semantic tokens below, which
       are identical in all four apps.

       ⚠️ Every accent sits near a semantic colour (red≈danger, green≈success, blue≈info), so hue
       alone cannot separate them. The TREATMENT does: a SOLID FILL is an action, a TINTED PILL or
       inline coloured text is a state. Keep new components on the right side of that line.

       Default is red, which is what the login page and the pre-app boot UI use — they render
       outside any app, so there is no accent to inherit. */
    --app-accent:             #A90432;
    --app-accent-dark:        #8a0228;
    --app-accent-ring:        rgba(169,4,50,0.1);
    /* Tinted variations of the accent, derived so they re-tint automatically per app from the single
       --app-accent rebind. These carry the app's SELECTION / EDITING / HOVER / GROUPING states (a
       tint = a state, per the treatment rule); the solid --app-accent stays for actions.
       --app-accent-bg = a light selected/hover row background; --app-accent-border = a mid selection
       bar / band. */
    --app-accent-bg:          color-mix(in srgb, var(--app-accent) 8%, white);
    --app-accent-border:      color-mix(in srgb, var(--app-accent) 35%, white);

    --color-bg:               #f4f5f7;
    --color-surface:          #ffffff;
    --color-border:           #e2e4e7;
    --color-text:             #1F2124;
    --color-text-muted:       #6b7280;
    --color-text-subtle:      #9ca3af;

    --color-success:          #15803d;
    --color-success-bg:       #f0fdf4;
    --color-success-border:   #bbf7d0;
    --color-warning:          #D97706;
    --color-warning-bg:       #fffbeb;
    --color-warning-border:   #fde68a;
    /* A standalone SEMANTIC "info" blue for states/legends (e.g. reconciliation accept/reviewing).
       Deliberately NOT --color-paykeeper: that token is PayKeeper's accent, and a status colour must not move
       because another app changed its identity. A cleaner, more standard blue than the navy accent. */
    --color-info:             #2563eb;
    --color-info-bg:          #eff6ff;
    --color-info-border:      #bfdbfe;
    --color-orange:           #EA580C;
    --color-orange-bg:        #fff2e8;
    --color-orange-border:    #fed7aa;
    --color-danger:           #DC2626;
    --color-danger-bg:        #fef2f2;
    --color-danger-border:    #fecaca;
    /* The deeper red destructive BUTTONS use — was hardcoded as #7f0220 in two places. Kept distinct
       from --color-danger, which is for inline alert text and tinted state pills. */
    --color-danger-strong:    #7f0220;
    --color-danger-strong-dark: #5c0117;

    --font:                   'Hanken Grotesk', system-ui, -apple-system, sans-serif;

    --space-1:  4px;
    --space-2:  8px;
    --space-3:  12px;
    --space-4:  16px;
    --space-5:  20px;
    --space-6:  24px;
    --space-8:  32px;
    --space-10: 40px;
    --space-12: 48px;

    --radius-sm: 4px;
    --radius:    8px;
    --radius-lg: 12px;

    --shadow-sm: 0 1px 3px rgba(0,0,0,0.07), 0 1px 2px rgba(0,0,0,0.05);
    --shadow:    0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.05);
    --shadow-lg: 0 10px 25px rgba(0,0,0,0.12), 0 4px 10px rgba(0,0,0,0.08);

    --nav-height: 56px;
}

/* ── Reset & Base ───────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { font-size: 16px; -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }

body {
    font-family: var(--font);
    font-size: 1rem;
    color: var(--color-text);
    background: var(--color-bg);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

h1 { font-size: 1.875rem; font-weight: 700; line-height: 1.2; }
/* Blazor's FocusOnNavigate (App.razor) programmatically focuses the page h1 on every navigation
   for screen-reader announcement — harmless for accessibility, but browsers draw a default focus
   ring around it, which reads as an unwanted selection box on a heading that isn't interactive. */
h1:focus { outline: none; }
h2 { font-size: 1.5rem;   font-weight: 700; line-height: 1.25; }
h3 { font-size: 1.125rem; font-weight: 600; line-height: 1.3; margin-bottom: var(--space-4); }
h4 { font-size: 1rem;     font-weight: 600; }
p  { line-height: 1.6; }
strong { font-weight: 700; }

/* ── App Shell ──────────────────────────────────────────── */
/* padding-top reserves the space .top-nav no longer occupies now that it's fixed (out of flow). */
.app-shell { min-height: 100vh; display: flex; flex-direction: column; padding-top: var(--nav-height); }

/* Per-app accent. MainLayout stamps app-<AppKeys key> on .app-shell from AppRegistry.ForPath, so
   these match the identity colours the homepage tiles already use. The home page itself carries no
   app class and keeps the default red. Adding an app = one entry here, nothing else. */
.app-shell.app-orderwriter      { --app-accent: var(--color-orderwriter);        --app-accent-dark: var(--color-orderwriter-dark);        --app-accent-ring: rgba(169,4,50,0.1); }
.app-shell.app-inventorycounter { --app-accent: var(--color-inventorycounter);      --app-accent-dark: var(--color-inventorycounter-dark);      --app-accent-ring: rgba(29,107,79,0.12); }
.app-shell.app-paykeeper        { --app-accent: var(--color-paykeeper);       --app-accent-dark: var(--color-paykeeper-dark);       --app-accent-ring: rgba(21,72,107,0.12); }
.app-shell.app-shiftkeeper      { --app-accent: var(--color-shiftkeeper);     --app-accent-dark: var(--color-shiftkeeper-dark);     --app-accent-ring: rgba(194,65,12,0.12); }
.app-shell.app-admin            { --app-accent: var(--color-admin);      --app-accent-dark: var(--color-admin-dark);      --app-accent-ring: rgba(100,116,139,0.12); }
.app-shell.app-pricelister      { --app-accent: var(--color-pricelister);     --app-accent-dark: var(--color-pricelister-dark);     --app-accent-ring: rgba(3,105,161,0.12); }
.app-shell.app-reporter         { --app-accent: var(--color-reporter);        --app-accent-dark: var(--color-reporter-dark);        --app-accent-ring: rgba(124,58,237,0.12); }
.app-shell.app-banksitter       { --app-accent: var(--color-banksitter);      --app-accent-dark: var(--color-banksitter-dark);      --app-accent-ring: rgba(55,65,81,0.12); }
.app-shell.app-ateamrewards     { --app-accent: var(--color-ateamrewards);    --app-accent-dark: var(--color-ateamrewards-dark);    --app-accent-ring: rgba(67,56,202,0.14); }
.app-shell.app-goaltender       { --app-accent: var(--color-goaltender);      --app-accent-dark: var(--color-goaltender-dark);      --app-accent-ring: rgba(165,108,65,0.12); }
.app-shell.app-appointments     { --app-accent: var(--color-appointments);    --app-accent-dark: var(--color-appointments-dark);    --app-accent-ring: rgba(15,118,110,0.12); }

/* Re-derive the accent TINTS on .app-shell so they recompute from each app's OWN --app-accent.
   The :root copies (see the --app-accent-bg/-border definitions above) are computed once, at :root,
   where --app-accent is still the default red — a custom property's var() resolves against the value
   at the element where the property is DECLARED, and :root sits above every app-* rebind. So without
   this rule every app's selected-row / hover / band tint stayed RED (admin/paykeeper/etc. selected
   rows all showed OrderWriter red). Declaring the tints here, on .app-shell — where the cascaded
   --app-accent is already the app's colour — makes them re-tint per app, which is what the accent
   policy always intended. :root keeps its copies for chrome outside any app-shell (login/boot). */
.app-shell {
    --app-accent-bg:     color-mix(in srgb, var(--app-accent) 8%, white);
    --app-accent-border: color-mix(in srgb, var(--app-accent) 35%, white);
}

/* ── Top Nav ────────────────────────────────────────────── */
/* position:fixed (not sticky) — sticky only resists the *vertical* scroll of its own containing
   block; pages with horizontally-overflowing content (e.g. Pricelist) still drag a sticky header
   sideways with the rest of the page. Fixed pins it to the viewport on both axes. */
.top-nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
    height: var(--nav-height);
    background: var(--color-near-black);
    display: flex;
    align-items: center;
    padding: 0 var(--space-4);
    gap: var(--space-3);
    /* An accent line along the bottom of the black header, in the active app's colour (--app-accent is
       rebound per app on the .app-shell) — a persistent, always-visible cue for which app you're in.
       Sits inside the fixed nav height (border-box), so it adds no layout shift. */
    box-shadow: var(--shadow);
    border-bottom: 4px solid var(--app-accent);
}
/* The launcher / home page (.app-none) is in no app, so it shows NO line — the border matches the header
   colour, keeping the header's shape without implying an app. A visible line means "you're in an app".
   (Admin needs no special case any more: its accent is now a real slate grey, so the line just follows
   --app-accent like every other app.) */
.app-shell.app-none .top-nav { border-bottom-color: var(--color-near-black); }

.store-selector {
    width: auto;
    min-width: 110px;
    flex: 0 0 auto;
}

.hamburger-btn {
    background: none;
    border: none;
    color: #fff;
    font-size: 1.375rem;
    line-height: 1;
    padding: var(--space-2);
    cursor: pointer;
    flex-shrink: 0;
}

.app-title {
    font-size: 1.0625rem;
    font-weight: 700;
    color: #fff;
    letter-spacing: 0.02em;
    flex: 1;
    text-decoration: none;
    cursor: pointer;
}

/* White wordmark lockup for the dark top-nav. Height-capped to sit comfortably in the 56px bar;
   width auto-scales to preserve the lockup's aspect ratio. */
.app-logo { height: 26px; width: auto; display: block; }

/* Phones get the mark (the A over "OS") instead — ~60px wide against the lockup's ~157px. That width is
   what the store selector, help and Sign Out were being squeezed out of. Both images are always in the
   markup; only one is ever displayed. */
.app-logo-mark { display: none; }
@media (max-width: 600px) {
    .app-logo-lockup { display: none; }
    .app-logo-mark { display: block; }
    /* Sign Out moves to the drawer's Account section at this width. Even with the mark in place the bar
       wanted 403px of a 375px phone, and this is the 98px that closes it — a button the user presses
       once a day, against a store selector and help they use all shift. */
    .logout-btn { display: none; }
}

.logout-btn {
    margin-left: auto;
    background: transparent;
    border: 1px solid rgba(255,255,255,0.25);
    color: rgba(255,255,255,0.75);
    font-family: var(--font);
    font-size: 0.8125rem;
    font-weight: 600;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
}
.logout-btn:hover { border-color: rgba(255,255,255,0.6); color: #fff; }

.nav-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 150;
}

.nav-drawer {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: 260px;
    background: var(--color-near-black);
    z-index: 200;
    display: flex;
    flex-direction: column;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    box-shadow: var(--shadow-lg);
}

.nav-drawer.open { transform: translateX(0); }

.nav-drawer-title {
    font-size: 1.0625rem;
    font-weight: 700;
    color: #fff;
    letter-spacing: 0.02em;
    padding: var(--space-5) var(--space-6);
    border-bottom: 1px solid rgba(255,255,255,0.1);
    margin-bottom: var(--space-2);
}

/* A second heading further down the drawer (e.g. "Account" under the app list). Separates from the
   group above with a rule on top rather than below, and sits quieter than the drawer's first title. */
.nav-drawer-title-secondary {
    font-size: 0.9375rem;
    color: rgba(255,255,255,0.55);
    border-bottom: none;
    border-top: 1px solid rgba(255,255,255,0.1);
    margin-top: var(--space-4);
    padding-bottom: var(--space-2);
}

.nav-drawer a {
    display: block;
    color: rgba(255,255,255,0.65);
    text-decoration: none;
    font-size: 1rem;
    font-weight: 600;
    padding: var(--space-4) var(--space-6);
    transition: color 0.15s, background 0.15s;
}

.nav-drawer a:hover  { color: #fff; background: rgba(255,255,255,0.06); }
.nav-drawer a.active { color: #fff; background: var(--app-accent); }

/* An action rather than a destination (Sign Out), so it's a button — styled as a drawer row so the
   Account section reads as one list instead of a link with a stray control under it. */
.nav-drawer-action {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    font-family: var(--font);
    color: rgba(255,255,255,0.65);
    font-size: 1rem;
    font-weight: 600;
    padding: var(--space-4) var(--space-6);
    /* Matches the anchors' 56px row height. The global `button` rule pins every button to height: 40px,
       which capped this row 16px short of the links above it — so the height is released and the row is
       sized by its own padding and line-height, like the anchors are. */
    height: auto;
    line-height: 1.5;
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
}
.nav-drawer-action:hover { color: #fff; background: rgba(255,255,255,0.06); }

/* ── Main Content ───────────────────────────────────────── */
.main-content {
    flex: 1;
    max-width: 1024px;
    width: 100%;
    margin: 0 auto;
    padding: var(--space-8) var(--space-6);
}

/* ── Page Header ────────────────────────────────────────── */
.page-header, .count-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-8);
}

.page-header h2, .count-header h2 { margin-bottom: var(--space-1); }

/* For pages with many header actions: the title keeps the full first line and the buttons wrap on the
   line below, instead of the buttons squeezing the title into a narrow column. */
.page-header.page-header-stacked { flex-direction: column; align-items: stretch; gap: var(--space-3); }
.page-header-stacked .header-actions { flex-wrap: wrap; flex-shrink: 1; }

.header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
}

.session-meta {
    font-size: 0.875rem;
    color: var(--color-text-muted);
    display: block;
    margin-top: var(--space-1);
}

/* ── Buttons ────────────────────────────────────────────── */
button {
    font-family: var(--font);
    font-size: 0.875rem;
    font-weight: 600;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    padding: 0 var(--space-5);
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    transition: background 0.15s, opacity 0.15s, border-color 0.15s, color 0.15s;
    text-decoration: none;
    letter-spacing: 0.02em;
}

button:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-primary {
    background: var(--app-accent);
    color: #fff;
    border: 1px solid transparent;
}
.btn-primary:hover:not(:disabled) { background: var(--app-accent-dark); }

.btn-secondary {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
}
.btn-secondary:hover:not(:disabled) { background: var(--color-bg); border-color: #c0c4cc; }

/* ⚠️ SOLID DANGER IS FOR THE POINT OF CONFIRMATION, NOT THE POINT OF OFFER.
   A destructive action sitting in a list ("Abandon" beside "Resume") is only an invitation — the
   commitment happens in the modal that follows, and that is where the loud treatment belongs. Two
   solid buttons side by side also make the row compete with itself, which is what the red Abandon
   was doing to InventoryCounter once its accent went blue. Offer with .btn-danger-outline, confirm
   with .btn-danger. */
.btn-danger {
    background: var(--color-danger-strong);
    color: #fff;
    border: 1px solid transparent;
}
.btn-danger:hover:not(:disabled) { background: var(--color-danger-strong-dark); }

/* The quiet half of the pair: unmistakably destructive, but it does not shout across the page. */
.btn-danger-outline {
    background: var(--color-surface);
    color: var(--color-danger-strong);
    border: 1px solid var(--color-danger-border);
}
.btn-danger-outline:hover:not(:disabled) {
    background: var(--color-danger-bg);
    border-color: var(--color-danger-strong);
}

.btn-sm { height: 32px; padding: 0 var(--space-3); font-size: 0.75rem; }

a.btn-secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 32px;
    padding: 0 var(--space-3);
    font-size: 0.75rem;
    font-family: var(--font);
    font-weight: 600;
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    text-decoration: none;
    transition: background 0.15s, border-color 0.15s;
}
a.btn-secondary:hover { background: var(--color-bg); border-color: #c0c4cc; }

/* ── Forms ──────────────────────────────────────────────── */
.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.field label {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

input[type="text"],
input[type="number"],
input[type="password"],
input[type="email"],
input[type="tel"],
input[type="date"],
input:not([type]),
select,
textarea {
    font-family: var(--font);
    font-size: 1rem;
    color: var(--color-text);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-3);
    height: 40px;
    width: 100%;
    transition: border-color 0.15s, box-shadow 0.15s;
    outline: none;
    appearance: none;
}

textarea {
    height: auto;
    padding: var(--space-3);
    resize: vertical;
    line-height: 1.5;
}

select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236b7280' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-3) center;
    padding-right: var(--space-8);
}

input:focus, select:focus, textarea:focus {
    border-color: var(--app-accent);
    box-shadow: 0 0 0 3px var(--app-accent-ring);
}

input::placeholder, textarea::placeholder { color: var(--color-text-subtle); }

.form-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
}

.form-row label {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.form-row input, .form-row select { width: auto; flex: 1; min-width: 120px; }

/* ── Toggle switch (binary settings — Same as Sold-To, Show Costs, etc.) ─────
   Larger touch target and clearer at-a-glance state than a checkbox, especially
   on mobile. Reserved for on/off preferences; list-selection checkboxes (sample
   log, line selection) stay plain checkboxes since "select this item" is a
   different meaning than "toggle this setting". */
.toggle-switch {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    font-size: 0.875rem;
    color: var(--color-text);
    user-select: none;
}

.toggle-switch input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.toggle-track {
    position: relative;
    width: 38px;
    height: 21px;
    flex-shrink: 0;
    background: var(--color-border);
    border-radius: 999px;
    transition: background 0.15s;
}

.toggle-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
    transition: transform 0.15s;
}

.toggle-switch input:checked + .toggle-track { background: var(--app-accent); }
.toggle-switch input:checked + .toggle-track .toggle-thumb { transform: translateX(17px); }
.toggle-switch input:focus-visible + .toggle-track { box-shadow: 0 0 0 3px var(--app-accent-ring); }
.toggle-switch input:disabled + .toggle-track { opacity: 0.5; }
.toggle-switch:has(input:disabled) { cursor: not-allowed; }

/* ── Tabs ───────────────────────────────────────────────── */
.tab-bar {
    display: flex;
    gap: 0;
    border-bottom: 2px solid var(--color-border);
    margin-bottom: var(--space-6);
    overflow-x: auto;
    /* Leaving overflow-y unset here computes to auto (per spec, once either axis is non-visible the
       other stops being visible too), so a couple px of sub-pixel vertical overflow from the tab
       buttons' -2px margin/border math was silently triggering an unwanted vertical scrollbar that
       clipped the tabs short — pin it to hidden so only the intended horizontal scroll applies. */
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    /* Its own overflow-x:auto otherwise gives it an automatic min-height of 0 as a flex item, letting a
       height-capped flex-column ancestor (e.g. .manager-dash-body) squeeze it away entirely instead of
       shrinking the scrollable content area — pin it to its natural size instead. */
    flex-shrink: 0;
}

.tab, .tab-active {
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    height: 40px;
    padding: 0 var(--space-5);
    margin-bottom: -2px;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
    letter-spacing: 0.02em;
    white-space: nowrap;
    flex-shrink: 0;
}
.tab:hover { color: var(--color-text); }
.tab-active { color: var(--app-accent); border-bottom-color: var(--app-accent); }
.tab-bar a { text-decoration: none; display: inline-flex; align-items: center; }

/* The lead-type tabs above the CRM leads list. Same .tab-bar/.tab as the lead detail (so it reads as
   the same control and keeps the horizontal scroll on a phone), just tighter: the list pane is narrow,
   and at the default spacing three or four tabs would already be scrolling on a desktop. */
.lead-type-tab-bar { margin-bottom: var(--space-3); }
.lead-type-tab-bar .tab,
.lead-type-tab-bar .tab-active { height: 34px; padding: 0 var(--space-3); font-size: 0.8125rem; }

/* Count beside each tab name — quiet, so the name stays the thing you read. */
.lead-type-tab-count {
    margin-left: 4px;
    font-weight: 500;
    color: var(--color-text-subtle);
}
.tab-active .lead-type-tab-count { color: inherit; opacity: 0.75; }

/* ── Modal ──────────────────────────────────────────────── */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(31,33,36,0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 200;
    padding: var(--space-4);
}

.modal {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-8);
    width: 100%;
    max-width: 480px;
    /* Bounds every modal to the viewport (minus .modal-overlay's own padding) with its own internal
       scroll, so content taller than the screen — e.g. Customer Info's stacked Sold-To/Ship-To panels —
       stays reachable instead of overflowing off-screen with no way to scroll to it. */
    max-height: calc(100vh - 2 * var(--space-4));
    overflow-y: auto;
}

.modal h3 { margin-bottom: var(--space-4); }
.modal > p { color: var(--color-text-muted); margin-bottom: var(--space-3); line-height: 1.6; }
.modal-warning { color: var(--color-warning) !important; background: var(--color-warning-bg); border: 1px solid var(--color-warning-border); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); }

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-6);
}

/* Suite convention: a modal's buttons are docked at its bottom, so nobody scrolls to reach Save.
   Measured 2026-09-18, the long forms (Hire employee, Add User, Add Store, Customer Info…) had their
   buttons up to ~580px below the fold on a desktop and ~1,400px on a phone.
   Sticky, not fixed, so the bar stays inside the modal's own scrolling box. The negative margins pull it
   out to .modal's padding edges and the padding puts the buttons back where they were, so it reads as a
   footer bar with content scrolling under it; bottom: -32px matches .modal's bottom padding, so the bar is
   already parked at the end of the scroll rather than jumping the last 32px. Every modal gets the top
   border, including short ones that never scroll — accepted, for one consistent footer.
   Only the modal's LAST direct child: some modals carry an action row mid-form, and a sticky one of
   those would float over the fields. A modal whose buttons aren't its final child keeps the old layout. */
.modal > .modal-actions:last-child {
    position: sticky;
    bottom: calc(-1 * var(--space-8));
    z-index: 1;
    margin: var(--space-6) calc(-1 * var(--space-8)) calc(-1 * var(--space-8));
    padding: var(--space-4) var(--space-8);
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* ── Inline error ───────────────────────────────────────── */
.error {
    font-size: 0.875rem;
    color: var(--color-danger);
    background: var(--color-danger-bg);
    border: 1px solid var(--color-danger-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
}

/* ── Session Cards (Home) ───────────────────────────────── */
.session-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-bottom: var(--space-8);
}

.session-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4) var(--space-5);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    box-shadow: var(--shadow-sm);
}

.session-store {
    display: block;
    font-size: 1.125rem;
    font-weight: 700;
    margin-bottom: var(--space-1);
}

.session-actions { display: flex; gap: var(--space-2); flex-shrink: 0; }

.empty-state {
    color: var(--color-text-muted);
    padding: var(--space-12) 0;
    text-align: center;
}

/* ── App Tiles (Homepage) ───────────────────────────────── */
/* Centre the launcher tiles in the content area instead of letting the fixed-width grid sit left-aligned
   in the (centred, 1024px) .main-content column. */
.home-launcher {
    min-height: 65vh;
    display: flex;
    align-items: center;
    justify-content: center;
}

.app-tile-grid {
    display: grid;
    /* auto-fill (not auto-fit) so empty column tracks are retained — a user with a single app gets a
       normal-sized tile in the first track instead of one stretched to fill the whole row. Fill the
       content frame (capped at 1024px by .main-content) so the tiles spread across ~4 columns on desktop
       and fewer as the frame narrows, rather than being pinned to two. */
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: var(--space-6);
    width: 100%;
}

.app-tile {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-8) var(--space-4);
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    cursor: pointer;
    font-family: var(--font);
    transition: box-shadow 0.15s, transform 0.15s;
}
.app-tile:hover { box-shadow: var(--shadow); transform: translateY(-2px); }

.app-tile-icon {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    font-weight: 700;
    color: #fff;
    letter-spacing: 0.02em;
}
.app-tile-icon-orderwriter  { background: var(--color-orderwriter); }
.app-tile-icon-paykeeper { background: var(--color-paykeeper); }
.app-tile-icon-admin { background: var(--color-admin); }
.app-tile-icon-inventorycounter { background: var(--color-inventorycounter); }
.app-tile-icon-shiftkeeper { background: var(--color-shiftkeeper); }
.app-tile-icon-pricelister { background: var(--color-pricelister); }
.app-tile-icon-reporter { background: var(--color-reporter); }
.app-tile-icon-banksitter { background: var(--color-banksitter); }
.app-tile-icon-ateamrewards { background: var(--color-ateamrewards); }
.app-tile-icon-goaltender { background: var(--color-goaltender); }
.app-tile-icon-appointments { background: var(--color-appointments); }

.app-tile-name {
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-text);
}

/* On phones the 180px minmax floor collapses the grid to a SINGLE column, so a 6-app user gets a
   tall 6-row stack — and the 65vh vertical-centering then starts that stack low and runs it past the
   fold, leaving only the first ~3 tiles visible without scrolling. Pin to a compact 2-column grid and
   drop the centering so all tiles sit at the top and fit the screen the way they do on desktop. */
@media (max-width: 640px) {
    .home-launcher {
        min-height: 0;
        align-items: flex-start;
        padding-top: var(--space-6);
    }
    .app-tile-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-4);
    }
    .app-tile { padding: var(--space-6) var(--space-3); }
    .app-tile-icon { width: 52px; height: 52px; }
}

/* ── Count Page ─────────────────────────────────────────── */
.pending-scan-overlay {
    position: fixed;
    inset: var(--nav-height) 0 0 0;
    background: rgba(31,33,36,0.6);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    z-index: 150;
    padding: var(--space-8) var(--space-4);
    overflow-y: auto;
}

.pending-scan-card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-6);
    width: 100%;
    max-width: 560px;
}

/* On a phone the counter is holding a roll in one hand. Give the card the full height it can have,
   drop the desktop breathing room, and let the long middle section scroll inside the card so Cancel /
   Submit stay put at the bottom instead of being pushed off the screen. */
@media (max-width: 640px) {
    /* flex-start, not stretch: the card hugs its content at the top of the screen instead of growing to
       fill the height, which is what pushed the actions down behind the keyboard. */
    .pending-scan-overlay { padding: var(--space-3); align-items: flex-start; }

    .pending-scan-card {
        padding: var(--space-4);
        display: flex;
        flex-direction: column;
        max-height: 100%;
    }

    .lookup-results { max-height: none; }

    .pending-scan-card .allocation-banner,
    .pending-scan-card .candidate-list {
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        min-height: 0;
    }

    /* The on-screen keyboard covers roughly the bottom half of the screen, so Submit must sit directly
       under the quantity fields rather than at the foot of the card. Reordering keeps the DOM (and
       therefore tab order and screen readers) in its natural sequence while pulling the input/button
       pair to the top; the allocation list drops below them and scrolls. */
    .pending-scan-card .pending-item-header { order: 0; }
    .pending-scan-card .pending-description { order: 1; }
    .pending-scan-card .qty-entry           { order: 2; }
    .pending-scan-card .pending-actions     { order: 3; padding-top: var(--space-3); }
    .pending-scan-card .allocation-banner   { order: 4; margin-top: var(--space-4); }
}

.pending-item-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.pending-type {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    background: var(--color-near-black);
    color: #fff;
    padding: 3px var(--space-2);
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}

.pending-id {
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: 0.01em;
}

.pending-description {
    font-size: 1rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-4);
}

.rug-size {
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--app-accent);
    margin: var(--space-2) 0 var(--space-4);
}

.allocation-banner {
    background: var(--color-info-bg);
    border-left: 3px solid var(--color-info);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
    font-size: 0.875rem;
}

.allocation-banner strong { color: var(--color-info); display: block; margin-bottom: var(--space-2); }

.allocation-row {
    display: flex;
    gap: var(--space-4);
    padding: 3px 0;
    flex-wrap: wrap;
    color: var(--color-text-muted);
    font-size: 0.875rem;
}

.qty-entry { margin-bottom: var(--space-4); }

.qty-entry label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin-bottom: var(--space-2);
}

.qty-entry input { max-width: 180px; }

.lf-entry { display: flex; align-items: center; gap: var(--space-2); }
.lf-entry input { max-width: 90px; }
.lf-entry span { font-weight: 600; color: var(--color-text-muted); }

.running-count {
    font-size: 0.875rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
}

.pending-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
}

/* Orphan / notification banners */
.orphan-banner {
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
    font-size: 0.875rem;
    font-weight: 600;
    border-left: 4px solid;
}

.orphan-warning {
    background: var(--color-warning-bg);
    border-left-color: var(--color-warning);
    color: var(--color-warning);
}

.orphan-error {
    background: var(--color-danger-bg);
    border-left-color: var(--color-danger);
    color: var(--color-danger);
}

.scan-notification {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--color-success);
    background: var(--color-success-bg);
    border-left: 4px solid var(--color-success);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-3);
}

/* Scan input area */
.scan-input-area {
    position: sticky;
    bottom: 0;
    background: var(--color-bg);
    border-top: 1px solid var(--color-border);
    padding: var(--space-4) 0;
    margin-top: var(--space-6);
}

.scan-field input {
    width: 100%;
    font-size: 1.25rem;
    height: 54px;
    font-weight: 600;
    border: 2px solid var(--color-border);
    border-radius: var(--radius);
    letter-spacing: 0.02em;
}

.scan-field input:focus {
    border-color: var(--app-accent);
    box-shadow: 0 0 0 3px var(--app-accent-ring);
}

.undo-btn { margin-top: var(--space-2); }

/* Scan history */
.scan-history { margin-top: var(--space-8); }
.scan-history h3 { margin-bottom: var(--space-3); }

.entry-list { display: flex; flex-direction: column; gap: 2px; }

.entry-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    background: var(--color-surface);
    border-radius: var(--radius-sm);
    font-size: 0.875rem;
    border-left: 3px solid transparent;
}

.entry-confirmed { border-left-color: var(--color-success); }
.entry-variance  { border-left-color: var(--color-warning); }
.entry-exception { border-left-color: var(--color-danger); }

.entry-seq    { color: var(--color-text-subtle); font-size: 0.75rem; flex-shrink: 0; width: 32px; }
.entry-bin    { font-size: 0.75rem; font-weight: 700; color: var(--color-text); flex-shrink: 0; }
.entry-time   { font-size: 0.75rem; color: var(--color-text-subtle); margin-left: auto; flex-shrink: 0; }
.entry-type   { font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); flex-shrink: 0; width: 90px; }
.entry-id     { font-weight: 700; flex-shrink: 0; }
.entry-desc   { color: var(--color-text-muted); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.entry-qty    { color: var(--color-text-muted); flex-shrink: 0; }
.entry-status { flex-shrink: 0; font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-subtle); }

/* ── Summary Page ───────────────────────────────────────── */
.summary-stats {
    display: flex;
    gap: var(--space-3);
    margin-bottom: var(--space-8);
    flex-wrap: wrap;
}

.stat-card {
    flex: 1;
    min-width: 90px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4) var(--space-5);
    display: flex;
    flex-direction: column;
    align-items: center;
    box-shadow: var(--shadow-sm);
}

.stat-number {
    font-size: 2rem;
    font-weight: 700;
    line-height: 1;
    margin-bottom: var(--space-2);
    color: var(--color-text);
}

.stat-label {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--color-text-muted);
    text-align: center;
}

.stat-good .stat-number { color: var(--color-success); }
.stat-warn .stat-number { color: var(--color-warning); }
.stat-bad  .stat-number { color: var(--color-danger); }

.summary-section { margin-bottom: var(--space-8); }
.summary-section h3 { margin-bottom: var(--space-4); }

/* ── Tables ─────────────────────────────────────────────── */
.summary-table, .report-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.875rem;
    background: var(--color-surface);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
}

.summary-table th, .report-table th {
    background: var(--color-near-black);
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    padding: var(--space-3) var(--space-4);
    text-align: left;
}

.summary-table td, .report-table td {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
}

.summary-table tr:last-child td,
.report-table  tr:last-child td { border-bottom: none; }

.summary-table tbody tr:hover td,
.report-table  tbody tr:hover td { background: var(--color-bg); }

.row-negative td:last-child { color: var(--color-danger); font-weight: 700; }
.row-positive td:last-child { color: var(--color-success); font-weight: 700; }
.negative { color: var(--color-danger) !important; font-weight: 700; }
.positive { color: var(--color-success) !important; font-weight: 700; }

.auto-accepted td { color: var(--color-text-muted); }
.auto-accept-badge { color: var(--color-warning); font-weight: 700; margin-left: 2px; }

.clerk-note        { color: var(--color-text-muted); font-size: 0.8125rem; margin-top: 2px; }
.investigation-note { color: var(--color-info); font-size: 0.8125rem; margin-top: 2px; }

/* ── Reconciliation ─────────────────────────────────────── */
/* A neutral guidance banner. NOT the app accent (green would blur into this page's heavy "confirmed /
   finalized" success-green) and NOT --color-paykeeper (that was a leftover from when InventoryCounter's accent
   was blue; blue here also belongs to the disposition/status legend, so a banner in it read as a state). */
.recon-instructions {
    background: var(--color-surface);
    border-left: 4px solid var(--color-text-subtle);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-6);
    font-size: 0.875rem;
    color: var(--color-text-muted);
}
/* The finalized message IS a success announcement, so it takes the semantic success treatment (green),
   matching the .recon-finalized status — unlike the plain-guidance variants, where green would falsely
   read as "done". */
.recon-instructions-finalized {
    background: var(--color-success-bg);
    border-left-color: var(--color-success);
    color: var(--color-success);
}

.recon-status {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
}

.recon-pending   { background: var(--color-warning-bg); color: var(--color-warning); }
.recon-reviewing { background: var(--color-info-bg); color: var(--color-info); }
.recon-finalized { background: var(--color-success-bg); color: var(--color-success); }

.adjustment-forms-list {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-6);
}

.adjustment-forms-list h4 {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
}

.adjustment-form-row {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-2) 0;
    font-size: 0.875rem;
    color: var(--color-text-muted);
    border-top: 1px solid var(--color-border);
    flex-wrap: wrap;
}

.form-badge {
    font-size: 0.6875rem;
    font-weight: 700;
    background: var(--color-near-black);
    color: #fff;
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Recon lines */
.recon-line {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
    margin-bottom: var(--space-3);
    box-shadow: var(--shadow-sm);
}

.recon-disp-confirmed   { border-left-color: var(--color-success); }
.recon-disp-accept      { border-left-color: var(--color-info); }
.recon-disp-investigate { border-left-color: var(--color-warning); }
.recon-disp-updatecount { border-left-color: #7c3aed; }
.recon-disp-unset       { border-left-color: var(--color-border); }

.recon-line-header {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin-bottom: var(--space-3);
}

.recon-type {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    background: var(--color-near-black);
    color: #fff;
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}

.recon-exception-type {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    flex-shrink: 0;
}

.recon-id   { font-weight: 700; }
.recon-desc { color: var(--color-text-muted); }

/* Who recorded a scan, on the history list when more than one person counted the session. */
.entry-counter {
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--app-accent);
    white-space: nowrap;
}

/* Why the quantity modal is showing an exception rather than an ordinary count. */
.exception-banner {
    background: var(--color-warning-bg, rgba(217, 119, 6, 0.10));
    border-left: 3px solid var(--color-warning);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    margin-bottom: var(--space-3);
    font-size: 0.875rem;
}

.exception-hint {
    display: block;
    margin-top: var(--space-1);
    color: var(--color-text-muted);
}

/* ── Scan: ambiguous barcode picker ────────────────────────── */
.pending-type-warning { background: var(--color-warning); color: var(--color-near-black); }

.candidate-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: var(--space-3) 0;
}

/* Overrides the global button rule, which pins height to 40px and forbids wrapping — a candidate needs
   to wrap onto a second line on a phone. */
.candidate-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2) var(--space-3);
    width: 100%;
    height: auto;
    white-space: normal;
    text-align: left;
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}
.candidate-row:hover { border-color: var(--app-accent); background: var(--color-bg); }

.candidate-type {
    font-size: 0.625rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    background: var(--color-near-black);
    color: #fff;
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
}
.candidate-code { font-weight: 700; }
.candidate-roll {
    font-weight: 700;
    color: var(--app-accent);
    white-space: nowrap;
}
.candidate-counted { opacity: 0.6; }
.candidate-counted-flag {
    font-size: 0.625rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-success);
    white-space: nowrap;
}

/* Dismiss control for the scan modals. Overrides the global button rule's fixed height and side
   padding, and margin-left:auto pins it to the right of the flex header. */
.modal-close-x {
    margin-left: auto;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--color-text-muted);
    font-size: 1rem;
    line-height: 1;
}
.modal-close-x:hover { background: var(--color-bg); color: var(--color-text); }

/* ── Scan: item lookup ─────────────────────────────────────── */
.lookup-btn { font-size: 1.125rem; }

.lookup-filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.lookup-categories { flex-wrap: wrap; }

/* Uses the shared .toggle-switch — this is an on/off preference, which is exactly what that component
   is for. Only the wrapping behaviour is local. */
.lookup-unscanned-toggle { white-space: nowrap; font-size: 0.8125rem; font-weight: 600; }

.lookup-search {
    width: 100%;
    margin-bottom: var(--space-3);
}

.lookup-results { max-height: 55vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }

.lookup-hint {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    margin: var(--space-2) 0 0 0;
}
.candidate-desc { color: var(--color-text-muted); flex: 1 1 auto; }
.candidate-qty  { font-weight: 700; white-space: nowrap; }

/* ── Reconciliation category filter ────────────────────────── */
.recon-filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

/* ── Reconciliation toolbar ─────────────────────────────────
   One panel: search + toggle, then the tab filters on a shared label column, then bulk apply as the
   footer, since it acts on exactly what the rows above leave on screen. */
.recon-toolbar {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    margin-bottom: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.recon-toolbar-search {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
}
.recon-toolbar-search input[type="text"] { flex: 1 1 260px; min-width: 0; }
.recon-toolbar-search .btn-sm { flex: none; white-space: nowrap; }
/* Filters are in force while hidden — the button says so. */
.recon-filters-active { border-color: var(--app-accent); color: var(--app-accent); }

/* Labels in one column so both sets of tabs start at the same edge. */
.recon-toolbar-filters {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: center;
    gap: var(--space-2) var(--space-4);
}
.recon-toolbar-filters .segmented-control { justify-self: start; max-width: 100%; overflow-x: auto; }
.recon-toolbar-filters .segment,
.recon-toolbar-filters .segment-active { white-space: nowrap; flex: none; }

.recon-toolbar-bulk {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
}
.recon-toolbar-bulk select { width: auto; min-width: 220px; }
.recon-toolbar-bulk input[type="text"] { flex: 1 1 200px; min-width: 0; }
.recon-toolbar-bulk-action { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.recon-bulk-confirm { font-size: 0.875rem; font-weight: 600; }

/* ── Post to Compufloor ─────────────────────────────────── */
.post-summary {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-6);
    padding: var(--space-4);
    margin-bottom: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: 0.875rem;
    color: var(--color-text-muted);
}
.post-summary-figure { display: block; font-size: 1.25rem; font-weight: 700; color: var(--color-text); }
.post-summary-figure.positive, .summary-table td.positive { color: var(--color-success); }
.post-summary-figure.negative, .summary-table td.negative { color: var(--color-danger); }
.summary-table td.num, .summary-table th.num { text-align: right; white-space: nowrap; }
.post-sub { font-size: 0.75rem; color: var(--color-text-muted); }
.post-warning { font-size: 0.75rem; color: var(--color-warning); }
.post-row-failed td { color: var(--color-danger); }
.post-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-top: var(--space-3); }
.lock-badge.lock-badge-posted { color: var(--color-success); }

/* A reconciliation line whose stock is mid-transfer in Compufloor. */
.recon-transit {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--color-warning);
    background: var(--color-warning-bg);
    border: 1px solid var(--color-warning-border);
    border-radius: var(--radius-sm);
    padding: 1px var(--space-2);
    white-space: nowrap;
}

/* Adjustment summary */
.report-table td.num, .report-table th.num { text-align: right; white-space: nowrap; }
.summary-totals { margin-bottom: var(--space-6); }
.summary-test-note { color: var(--color-warning); }

/* The reviewer's editable note inside the Investigate banner. */
.recon-investigate-banner input[type="text"] { flex: 1 1 240px; width: auto; height: 32px; font-size: 0.875rem; }

@media (max-width: 600px) {
    .recon-toolbar { padding: var(--space-3); }
    .recon-toolbar-bulk select { flex: 1 1 100%; }
    .recon-toolbar-bulk-action { margin-left: 0; }
}

.recon-filter-label {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
}

.recon-qty {
    font-size: 0.875rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.recon-allocated { color: var(--color-info); font-weight: 600; }

.recon-variance { font-weight: 700; font-size: 0.875rem; white-space: nowrap; }
.recon-variance.negative { color: var(--color-danger); }
.recon-variance.positive { color: var(--color-success); }

.recon-value { font-size: 0.875rem; color: var(--color-text-muted); }

.recon-variance-value { font-size: 0.875rem; font-weight: 700; }
.recon-variance-value.negative { color: var(--color-danger); }
.recon-variance-value.positive { color: var(--color-success); }

.recon-line-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-top: var(--space-3);
}

.recon-line-actions select           { width: auto; flex: 1; min-width: 200px; }
.recon-line-actions input[type="text"]   { flex: 1; min-width: 160px; }
.recon-line-actions input[type="number"] { width: 130px; flex: none; }
.recon-line-actions textarea { width: 100%; flex-basis: 100%; }

.recon-locked {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-2) var(--space-3);
    background: var(--color-bg);
    border-radius: var(--radius-sm);
    margin-top: var(--space-2);
}

.lock-badge {
    font-size: 0.6875rem;
    font-weight: 700;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.recon-disposition { font-weight: 600; font-size: 0.875rem; }

.recon-disp-badge-confirmed   { color: var(--color-success); }
.recon-disp-badge-accept      { color: var(--color-info); }
.recon-disp-badge-investigate { color: var(--color-warning); }
.recon-disp-badge-updatecount { color: #7c3aed; }

.recon-clerk-action { font-size: 0.875rem; font-weight: 600; }
.recon-clerk-note   { font-size: 0.875rem; color: var(--color-text-muted); font-style: italic; }

.recon-investigate-banner {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    background: var(--color-warning-bg);
    border-left: 3px solid var(--color-warning);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-3);
    font-size: 0.875rem;
    color: var(--color-warning);
    font-weight: 600;
}

.recon-note { font-style: italic; color: var(--color-text-muted); font-weight: 400; }

.recon-review-result {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-top: var(--space-2);
    font-size: 0.875rem;
}

.recon-investigation { color: var(--color-info); }
.recon-meta { color: var(--color-text-subtle); font-size: 0.75rem; }

/* ── Adjustment Form / Report ───────────────────────────── */
.report-toolbar {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    margin-bottom: var(--space-6);
}

.report-page {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-8);
    box-shadow: var(--shadow-sm);
}

.report-header { margin-bottom: var(--space-8); }
.report-header h1 { font-size: 1.5rem; margin-bottom: var(--space-4); }

.report-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-2) var(--space-6);
    font-size: 0.875rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-4);
}

.report-instructions {
    font-size: 0.875rem;
    color: var(--color-text-muted);
    font-weight: 600;
}

.report-section { margin-bottom: var(--space-8); }
.report-section h2 { font-size: 1.125rem; margin-bottom: var(--space-3); }

.report-footer {
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
    font-size: 0.875rem;
    color: var(--color-text-muted);
}

/* ── Camera Scanner ─────────────────────────────────────── */
.camera-overlay {
    position: fixed;
    inset: 0;
    z-index: 300;
    background: #000;
}

.camera-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

.camera-video video {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover !important;
}

.camera-ui {
    position: relative;
    z-index: 10;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
}

.camera-toolbar {
    padding: var(--space-4) var(--space-5);
    display: flex;
    justify-content: flex-end;
    background: linear-gradient(to bottom, rgba(0,0,0,0.65), transparent);
}

.camera-close {
    background: rgba(255,255,255,0.15);
    border: 1px solid rgba(255,255,255,0.35);
    color: #fff;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    font-size: 1.25rem;
    padding: 0;
}

.camera-close:hover { background: rgba(255,255,255,0.28); }

.camera-viewfinder {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.camera-reticle {
    width: 72vw;
    max-width: 320px;
    height: 36vw;
    max-height: 160px;
    border: 2px solid rgba(255,255,255,0.85);
    border-radius: var(--radius);
    box-shadow: 0 0 0 9999px rgba(0,0,0,0.45);
}

.camera-status {
    padding: var(--space-4) var(--space-5) var(--space-10);
    background: linear-gradient(to top, rgba(0,0,0,0.72), transparent);
    min-height: 90px;
    display: flex;
    align-items: flex-end;
}

.camera-hint {
    color: rgba(255,255,255,0.55);
    font-size: 0.875rem;
    text-align: center;
    width: 100%;
}

.camera-message {
    width: 100%;
    padding: var(--space-3) var(--space-5);
    border-radius: var(--radius);
    font-weight: 600;
    font-size: 0.9375rem;
    text-align: center;
    color: #fff;
}

.camera-msg-success { background: rgba(21,128,61,0.92); }
.camera-msg-warning { background: rgba(180,83,9,0.92); }
.camera-msg-error   { background: rgba(220,38,38,0.92); }

.bin-field { margin-bottom: var(--space-2); }

.bin-field input {
    width: 100%;
    font-size: 0.9375rem;
    height: 40px;
    font-weight: 500;
    border-radius: var(--radius);
    letter-spacing: 0.02em;
    color: var(--color-text);
}

.bin-field input:focus {
    border-color: var(--app-accent);
    box-shadow: 0 0 0 3px var(--app-accent-ring);
}

.scan-field {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}

.scan-field input { flex: 1; }

.camera-btn {
    flex-shrink: 0;
    height: 54px;
    padding: 0 var(--space-4);
    font-size: 1.375rem;
    background: var(--color-surface);
    border: 2px solid var(--color-border);
    border-radius: var(--radius);
}

.camera-btn:hover:not(:disabled) { background: var(--color-bg); border-color: #c0c4cc; }

/* ── Tag Printing ───────────────────────────────────────── */
.no-print { }

.tag-preview-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin: var(--space-4) 0;
}

.range-results  { margin-top: var(--space-6); }
.range-section  { margin-bottom: var(--space-6); }

.range-section-header {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-bottom: var(--space-3);
}

/* ── Utility text ───────────────────────────────────────── */
.success-text { color: var(--color-success); font-weight: 600; }
.warning-text { color: var(--color-warning); font-weight: 600; }
.muted        { color: var(--color-text-muted); font-size: 0.875rem; margin-top: var(--space-2); }

/* ── Login ──────────────────────────────────────────────── */
.login-container {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg);
    padding: var(--space-4);
}

.login-notice {
    font-size: 0.875rem;
    color: var(--color-info);
    background: var(--color-info-bg);
    border: 1px solid var(--color-info-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-5);
    text-align: center;
}

.login-box {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-10) var(--space-8);
    width: 100%;
    max-width: 380px;
}

.login-box h1 {
    font-size: 1.75rem;
    margin-bottom: var(--space-8);
    color: var(--app-accent);
    text-align: center;
    letter-spacing: -0.01em;
}

/* Red wordmark lockup on the white login card — centered, scales down on narrow screens. */
.login-logo {
    display: block;
    width: 100%;
    max-width: 260px;
    height: auto;
    margin: 0 auto var(--space-8);
}

.login-box button[type="submit"] {
    width: 100%;
    height: 44px;
    background: var(--app-accent);
    color: #fff;
    font-family: var(--font);
    font-size: 0.875rem;
    font-weight: 700;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-top: var(--space-2);
    transition: background 0.15s;
}

.login-box button[type="submit"]:hover:not(:disabled) { background: var(--app-accent-dark); }
.login-box button[type="submit"]:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Print (adjustment form) ────────────────────────────── */
@media print {
    .no-print { display: none !important; }

    .report-page  { border: none; box-shadow: none; padding: 0; }
    .main-content { padding: 0; }

    .summary-table th, .report-table th {
        background: #222 !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}

/* ── Blazor loading / error UI ──────────────────────────── */
#blazor-error-ui {
    color-scheme: light only;
    background: var(--color-danger-bg);
    color: var(--color-danger);
    border-top: 2px solid var(--color-danger);
    bottom: 0;
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: var(--space-3) var(--space-6);
    position: fixed;
    width: 100%;
    z-index: 1000;
    font-size: 0.875rem;
    font-weight: 600;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: var(--space-4);
    top: 50%;
    transform: translateY(-50%);
}

.blazor-error-boundary {
    background: var(--color-danger-bg);
    border-left: 4px solid var(--color-danger);
    padding: var(--space-4) var(--space-6);
    color: var(--color-danger);
    border-radius: var(--radius-sm);
}

.blazor-error-boundary::after { content: "An error has occurred."; }

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 20vh 0 auto 0;
    margin: 0 auto;
}

.loading-progress circle {
    fill: none;
    stroke: var(--color-border);
    stroke-width: 0.6rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: var(--app-accent);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: 600;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
    font-size: 0.875rem;
    color: var(--color-text-muted);
}

.loading-progress-text:after { content: var(--blazor-load-percentage-text, "Loading"); }

/* ── Blazor form validation ─────────────────────────────── */
.valid.modified:not([type=checkbox]) { border-color: var(--color-success); }
.invalid { border-color: var(--color-danger) !important; }
.validation-message { color: var(--color-danger); font-size: 0.875rem; margin-top: var(--space-1); }

/* ═══════════════════════════════════════════════════════════
   OrderWriter — CRM Dashboard
   ═══════════════════════════════════════════════════════════ */

/* Full-bleed breakout of .main-content's centered 1024px cap —
   the CRM shell is a data-dense app view, not a narrow form page. */
.crm-shell {
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    width: 100vw;
    padding: 0 var(--space-6) var(--space-6);
}

/* ── Global header (Compufloor stats + Tools) ──────────────── */
.crm-header { margin-bottom: var(--space-4); }

.crm-header-toggle {
    display: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-4);
    height: 40px;
    align-items: center;
    gap: var(--space-2);
    position: relative;
}

.crm-header-content {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    box-shadow: var(--shadow-sm);
}

.cuf-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-4);
    flex: 1;
}

.cuf-header-field { display: flex; flex-direction: column; gap: var(--space-1); }
.cuf-header-field label { font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); }
.cuf-header-field input { height: 32px; width: 140px; }

.cuf-header-stat { display: flex; flex-direction: column; gap: 2px; }
.cuf-stat-label { font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); }
.cuf-stat-value { font-size: 1.0625rem; font-weight: 700; }

.cuf-hide-toggle {
    background: transparent;
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    height: 32px;
    padding: 0 var(--space-3);
    font-size: 0.75rem;
    border-radius: var(--radius-sm);
}

/* ── Tools dropdown ─────────────────────────────────────────── */
.tools-menu-mobile { display: none; }

.tools-menu { position: relative; }

.tools-menu-trigger {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    border-radius: var(--radius-sm);
    height: 40px;
    padding: 0 var(--space-4);
    position: relative;
}

.tools-menu-badge {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-success);
    border: 1.5px solid var(--color-surface);
}

.tools-menu-overlay { position: fixed; inset: 0; z-index: 190; background: transparent; }

.tools-menu-dropdown {
    position: absolute;
    top: calc(100% + var(--space-2));
    right: 0;
    z-index: 200;
    min-width: 200px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: var(--space-2);
    display: flex;
    flex-direction: column;
}

.tools-menu-item {
    background: transparent;
    border: none;
    color: var(--color-text);
    text-align: left;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: var(--space-2);
    height: 36px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    font-weight: 500;
    /* Same root cause as the text-decoration fix below: the global button{} reset sets font-size:
       0.875rem, but <a>-rendered items (Office Dashboard, View Pricelists, etc.) never got that reset
       and rendered at the browser-default 16px instead of the button items' 14px. */
    font-size: 0.875rem;
    /* <a>-rendered items (Office Dashboard, View Pricelists, etc.) otherwise pick up the browser's
       default underline that <button>-rendered items (Stock Check) never had — the global button{}
       reset already sets text-decoration: none, this makes the two link types match it exactly. */
    text-decoration: none;
}
.tools-menu-item:hover { background: var(--color-bg); }
.tools-menu-item:disabled { color: var(--color-text-subtle); cursor: default; }
.tools-menu-item:disabled:hover { background: transparent; }

/* Groups items by WHAT THEY DO inside one menu. Used by the employee record's Actions menu to separate
   the workflows that write immediately from the ones that only post a request into an approval queue —
   a distinction a practitioner (who sees both) has to make BEFORE choosing, not after posting. Not a
   role divider: role decides what is in the menu, this says what will happen. */
.tools-menu-heading {
    padding: var(--space-2) var(--space-3) 0.15rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-subtle);
}
.tools-menu-heading + .tools-menu-item { margin-top: 0; }
/* A second heading needs air above it; the first sits flush with the top of the panel. */
.tools-menu-item + .tools-menu-heading {
    margin-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    padding-top: var(--space-2);
}

/* Same shaded-background treatment as .lead-card-reminder / .office-dash-row-ready — flags the Office
   Dashboard item when it has a Ready order waiting, same signal that drives .tools-menu-badge on the
   outer "Tools" trigger. */
.tools-menu-item-notify { background: var(--color-success-bg); }
.tools-menu-item-notify:hover { background: var(--color-success-bg); filter: brightness(0.97); }

.tools-menu-item-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-success);
    flex-shrink: 0;
}

/* ── Master-detail body ─────────────────────────────────────── */
.crm-body { display: flex; gap: var(--space-4); align-items: flex-start; }

/* Capped relative to viewport (nav bar + the page's own header/toolbar above it, roughly measured,
   plus a bottom buffer) so a long lead list can't push the pane taller than the screen — the list
   itself then flex-fills whatever room is left under its own header (search/filters/New Lead), rather
   than both being sized independently against a flat 70vh that didn't account for what's above them. */
.crm-list-pane {
    width: 340px;
    flex-shrink: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 220px);
}

.crm-detail-pane {
    flex: 1;
    min-width: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: var(--space-5) var(--space-6);
}

/* Shown for the duration of a lead's data fetch — covers both a first-ever selection (which otherwise
   shows the generic "Select a lead" placeholder) and switching between two already-selected leads
   (which otherwise leaves the previous lead's stale data on screen until the new one arrives). */
.crm-detail-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-8) 0;
    color: var(--color-text-muted);
}

/* The lead itself failed to load: same place and shape as the spinner it replaces, with a retry. */
.crm-detail-load-error {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-8) 0;
}

/* Part of a lead (the Compufloor figures / Invoice History) couldn't be fetched. A tinted state, not an
   error box: the rest of the lead is fine and usable, this one section is just missing. */
.crm-summary-unavailable {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin: var(--space-3) 0;
    padding: var(--space-2) var(--space-3);
    background: var(--color-warning-bg);
    border: 1px solid var(--color-warning-border);
    border-radius: var(--radius-sm);
    font-size: 0.875rem;
}
.spinner {
    width: 28px;
    height: 28px;
    border: 3px solid var(--color-border);
    border-top-color: var(--app-accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}
@keyframes spin {
    to { transform: rotate(360deg); }
}

.crm-list-header h3 { margin-bottom: var(--space-3); }
/* Heading and its Expand / Collapse button on one line. */
.crm-list-title-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-3); }
.crm-list-title-row h3 { margin-bottom: 0; }
/* Expand / Collapse: a square icon button, the same height as the other small buttons. */
.crm-list-expand-btn { width: 32px; padding: 0; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.crm-list-expand-btn .lead-card-icon { width: 16px; height: 16px; }

/* ── Expanded leads table (LeadTable.razor) ─────────────────────────────────────────────────────
   Expand widens the list pane over the whole body and hides the detail pane; opening a lead collapses
   it again (CrmDashboard's listExpanded). The pane keeps its viewport cap, so the table scrolls inside
   it under a sticky heading row instead of growing the page. */
.crm-body.list-expanded .crm-list-pane { width: auto; flex: 1; min-width: 0; }
/* The frame always runs down to the page's bottom margin, however few leads are showing, and the page
   itself never scrolls. Sized by the layout rather than a measured offset, so it stays right whether
   the Written Sales bar is shown, hidden, or wrapped: the page is held to the window's height, and each
   box down to the frame takes whatever height is left (min-height:0 lets them shrink below their
   content, so the table scrolls inside the frame instead). Desktop only; phones scroll the page. */
@media (min-width: 901px) {
    .app-shell:has(.crm-body.list-expanded) { height: 100vh; }
    .app-shell:has(.crm-body.list-expanded) .main-content { display: flex; flex-direction: column; min-height: 0; }
    .crm-shell:has(.crm-body.list-expanded) { flex: 1; min-height: 0; display: flex; flex-direction: column; }
    .crm-body.list-expanded { flex: 1; min-height: 0; align-items: stretch; }
    .crm-body.list-expanded .crm-list-pane { max-height: none; }
}
.crm-body.list-expanded .crm-detail-pane { display: none; }
/* Every pixel of header is a row of leads not shown, so expanded the whole header is one line: the
   title on the left, and on the right, in the cards' order, search and Clear, the two toggles, New
   Lead, then Collapse (display:contents lifts the title and its button out of their row so they can
   sit either end). It wraps only when it must. */
.crm-body.list-expanded .crm-list-header { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); margin-bottom: var(--space-2); }
.crm-body.list-expanded .crm-list-header > * { margin-bottom: 0; }
.crm-body.list-expanded .crm-list-title-row { display: contents; }
.crm-body.list-expanded .crm-list-title-row h3 { white-space: nowrap; }
.crm-body.list-expanded .crm-list-title-row > button { order: 1; }
/* A search box sized for a customer's name, not the leftover width (that goes between the title and
   the search, pushing the controls right). min-width:0 lets it give way before anything wraps on a
   narrow screen. */
.crm-body.list-expanded .crm-list-header .form-row { flex: 0 1 300px; margin-left: auto; min-width: 0; flex-wrap: nowrap; gap: var(--space-2); }
.crm-body.list-expanded .crm-list-header .form-row input { min-width: 0; height: 32px; font-size: 0.875rem; }
.crm-body.list-expanded .crm-list-filters { flex-wrap: nowrap; white-space: nowrap; }

/* The lead-type tabs, and when expanded the table's filters beside them on the same line. */
.crm-list-toolbar { flex-shrink: 0; }
.crm-body.list-expanded .crm-list-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); margin-bottom: var(--space-2); }
.crm-body.list-expanded .crm-list-toolbar .help-chip { flex-basis: 100%; }
.crm-body.list-expanded .lead-type-tab-bar { margin-bottom: 0; min-width: 0; }

/* Compact dropdowns, no labels (each "all" choice names its filter), pushed to the right of the tabs. */
.lead-table-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-left: auto; }
.lead-table-filters select {
    width: auto;
    height: 32px;
    font-size: 0.8125rem;
    padding-left: var(--space-2);
    padding-right: var(--space-6);
    background-position: right var(--space-2) center;
}
.lead-table-filters .toggle-switch { margin-bottom: 0; font-size: 0.8125rem; white-space: nowrap; }

.lead-table-scroll { flex: 1 1 auto; min-height: 120px; overflow: auto; border-radius: var(--radius); box-shadow: var(--shadow-sm); }
.lead-table-scroll .lead-table { overflow: visible; border-radius: 0; box-shadow: none; }
.lead-table-scroll .lead-table thead th { position: sticky; top: 0; z-index: 1; }
/* One line per lead — dense, like the price list, so a screen holds far more leads than the cards. */
.lead-table th, .lead-table td { padding: var(--space-1) var(--space-2); white-space: nowrap; }
/* Headings may wrap ("Last / activity"), so a column is only as wide as its dates, not its heading —
   that's what lets all ten columns fit on a 1024px-wide screen. */
.lead-table th { white-space: normal; vertical-align: bottom; }
.lead-table td { font-size: 0.8125rem; vertical-align: middle; }
.lead-table tbody tr { cursor: pointer; }
.lead-table tbody tr.lead-table-row-selected td { background: var(--app-accent-bg); }
/* A long name (or ship-to tag) is cut off with an ellipsis instead of pushing the dates off-screen;
   the full text is in the row's title. */
.lead-table-customer { font-weight: 600; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }
.lead-table-shipto { margin-left: var(--space-2); font-weight: 400; font-size: 0.75rem; color: var(--color-text-muted); }
/* flex, not inline-flex: an inline box starting with the (often empty) dot slot has no text baseline
   and drops below the row's other cells. */
.lead-table-expiry, .lead-table-reminder { display: flex; align-items: center; gap: var(--space-1); }
.lead-table-none { color: var(--color-text-subtle); }
.crm-list-header .form-row { margin-bottom: var(--space-2); }

.crm-list-filters {
    display: flex;
    gap: var(--space-4);
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
    flex-wrap: wrap;
}
.crm-list-filters label { display: flex; align-items: center; gap: var(--space-1); }

.crm-sort-filter-panel {
    display: flex;
    align-items: flex-end;
    gap: var(--space-4);
    flex-wrap: wrap;
    padding: var(--space-3);
    margin-bottom: var(--space-3);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}
.crm-sort-filter-panel .field { margin-bottom: 0; }
.crm-sort-filter-panel .toggle-switch { margin-bottom: var(--space-2); }

/* New Lead sits alongside the (optional) expanded Sort & Filter panel, rather than the panel
   rendering in a separate row below it. */
.crm-new-lead-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
}
.crm-new-lead-row .crm-sort-filter-panel { flex: 1; min-width: 220px; margin-bottom: 0; }

.crm-back-btn { display: none; margin-bottom: var(--space-3); }

/* The page-level "return to the app" button — "‹ PayKeeper", "‹ Home", "‹ Back to <lead>". These had
   NO bottom margin anywhere, so the button sat flush against the page header on every screen that
   used one. One class, applied app-wide, so the spacing can't drift page by page again.
   Distinct from .crm-back-btn, which is the master-detail back INSIDE a pane and sits tighter. */
.app-back-btn { margin-bottom: var(--space-4); }

.crm-detail-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}
.crm-detail-header h2 { margin-bottom: var(--space-1); }
.crm-detail-meta { font-size: 0.8125rem; color: var(--color-text-muted); }

/* Lead type selector in the detail header. Sits under the meta line as a labelled control rather
   than inline with it — it's editable, and reading as static text would hide that. */
/* "Assigned to · Status" and the Type dropdown on ONE line, to save a row of header height. Wraps on
   a narrow screen — the dropdown drops under the text rather than being pushed off-screen. */
.crm-detail-meta-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--space-4);
    row-gap: var(--space-1);
}

.lead-type-field {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.8125rem;
}

.lead-type-field label {
    color: var(--color-text-muted);
    font-weight: 600;
}

.lead-type-field select {
    width: auto;
    min-width: 9rem;
    /* 32px, not the app-wide 40px select height: it shares a line with 13px meta text now, and the
       tallest thing on that line sets the header's height. Same height as the order settings bar. */
    height: 32px;
    padding: 2px var(--space-2);
    font-size: 0.8125rem;
}

.lead-type-error { font-size: 0.75rem; }

/* Back and the order number as bookends on one line. Centred rather than .crm-detail-header's default
   top-alignment so the 32px button shares a midline with the two-line title block, and the button's own
   bottom margin is dropped — in a centred row that margin is part of what gets centred, which left the
   button sitting 8px high. */
.order-entry-header-bar { align-items: center; margin-bottom: var(--space-4); }
.order-entry-header-bar .app-back-btn { margin-bottom: 0; }
.order-entry-header-title { text-align: right; }

/* The settings strip: the Add strip's container (.line-entry-toolbar) with the order's own controls in
   it, left-aligned like the buttons below. Every control stands 32px — the height of the .btn-sm the Add
   strip is made of — so the two strips are the same height and read as one stack. A smaller bottom margin
   than .line-entry's own pairs them, instead of spacing them like separate sections. */
.line-entry.order-entry-settings { margin-bottom: var(--space-3); }
.order-entry-settings .segmented-control { padding: 2px; }
.order-entry-settings .segment,
.order-entry-settings .segment-active { height: 26px; }
.order-entry-settings .order-classification-field select,
.order-entry-settings .order-classification-field input { height: 32px; }
.order-entry-settings .order-classification-check { height: 32px; }
/* Label beside the control, not above it: a stacked label would make this strip twice the Add strip's
   height, which is the whole point of matching them. */
.order-entry-settings .order-classification-field {
    display: flex;
    /* .field stacks its label; this strip doesn't. Wraps so a hint after the input drops below it. */
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}
.order-entry-settings .order-classification-field label { margin: 0; white-space: nowrap; }
.order-entry-settings .order-classification-field select,
.order-entry-settings .order-classification-field input { width: auto; min-width: 7.5rem; }
/* A native select is as wide as its longest option, and reason names are sentences; capped so a long
   one can't push the bar past a phone's width. */
.order-entry-settings .order-tax-field { max-width: 100%; }
.order-entry-settings .order-tax-field select { max-width: 100%; }

/* The order's division, read-only (it's the lead's type). Same 32px height and footprint as the
   dropdown it replaced, so the bar keeps its rhythm, but visibly NOT a control: no border, no chevron,
   a muted fill — a bordered box here would invite a click that does nothing. */
.order-entry-settings .order-division-readonly {
    display: inline-flex;
    align-items: center;
    height: 32px;
    min-width: 7.5rem;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--color-surface-muted, rgba(0,0,0,0.04));
    color: var(--color-text-muted);
    font-size: 0.875rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: default;
}

.order-entry-header-title h2 { margin-bottom: 0; font-size: 1.25rem; }

.lead-expiry-warning {
    display: inline-block;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
    margin-left: var(--space-2);
    vertical-align: middle;
}
.lead-expiry-warning-orange { color: var(--color-orange); background: var(--color-orange-bg); }
.lead-expiry-warning-red    { color: var(--color-danger); background: var(--color-danger-bg); }

/* ── Lead cards ─────────────────────────────────────────────── */
.lead-card-list { display: flex; flex-direction: column; gap: var(--space-1); flex: 1 1 auto; min-height: 120px; overflow-y: auto; }

/* Deliberately compact: many salespeople carry a few dozen open leads, so the denser these are the
   more fit above the fold. Trimmed padding (12/16 -> 8/12), tightened line-height, meta pulled closer
   to the name (see .lead-card-meta), and a halved inter-card gap (--space-1) together cut the common
   card from ~75px to ~57px — ~50% more leads visible before scrolling — with no text or field removed. */
.lead-card {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-2) var(--space-3);
    line-height: 1.35;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.lead-card:hover { border-color: #c0c4cc; }
.lead-card-selected { background: var(--app-accent-bg); border-color: var(--app-accent-border); }

/* Same shaded-background + left-edge-band treatment as .note-card-reminder in the Notes tab, plus a
   small dot badge (kept from the old expiry indicator) so Reminder (yellow/amber) and Orange expiry
   stay visually distinct even though both are warm colors. Priority Red > Orange > Reminder — a lead
   that's both expiring and has a reminder due shows the expiry color; the reminder still shows via
   its gold bell in the card's bottom-right column (.lead-card-slot-bell). */
.lead-card-reminder      { border-left: 3px solid var(--color-warning); background: var(--color-warning-bg); }
.lead-card-expiry-orange { border-left: 3px solid var(--color-orange); background: var(--color-orange-bg); }
/* --color-danger, not --color-orderwriter — matches the Red used by OrderTile/LeadStatusPanel's status
   dots (.status-dot.red), not the brand red used for buttons/selected state. */
.lead-card-expiry-red    { border-left: 3px solid var(--color-danger); background: var(--color-danger-bg); }

.lead-card-top { display: flex; align-items: center; gap: var(--space-2); }
/* Truncates instead of wrapping, so a long name can never make the card a line taller. */
.lead-card-name { flex: 1; min-width: 0; font-weight: 700; font-size: 0.9375rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The card's right-edge column, on both lines: the expiry dot (top) and the reminder bell (bottom)
   sit centred in it, one above the other. It keeps its width when empty so everything to its left
   lines up from card to card. */
.lead-card-slot { width: 16px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }

.lead-badge { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.lead-badge-red    { background: var(--color-danger); }
.lead-badge-orange { background: var(--color-orange); }

.lead-card-icon { width: 13px; height: 13px; flex-shrink: 0; display: block; }
/* Yellow-gold, deliberately NOT --color-warning: that amber sits too close to --color-orange's expiry dot. */
.lead-card-bell { display: flex; color: #CA8A04; }
.lead-card-bell .lead-card-icon { width: 14px; height: 14px; }

/* Appointment chip (Lead_Appointment). Colour = type: teal in-home, navy in-store — neither means
   anything else in OrderWriter (crimson = accent/selection, red/orange = expiry, gold = reminder,
   indigo = A-Team points). Filled (--soon) = today or tomorrow; outlined = any other day. Same
   height as the lead-type chip, so it adds nothing to the line. */
.lead-card-appt {
    --appt: #0F6E56; --appt-text: #085041; --appt-fill: #E1F5EE;
    display: inline-flex; align-items: center; gap: 3px; flex-shrink: 0;
    line-height: 1; padding: 1px 5px;
    border: 1px solid var(--appt); border-radius: var(--radius-sm);
    font-size: 0.6875rem; font-weight: 500; white-space: nowrap;
    color: var(--appt-text); background: var(--color-surface);
}
.lead-card-appt .lead-card-icon { width: 12px; height: 12px; }
.lead-card-appt-instore { --appt: #15486B; --appt-text: #15486B; --appt-fill: #E7EEF4; }
.lead-card-appt-soon { background: var(--appt-fill); font-weight: 700; }

.lead-card-shipto { font-size: 0.75rem; color: var(--color-text-muted); margin-top: 2px; }

/* Non-default lead type chip. Deliberately quiet — it marks a minority of cards, and the card's
   loud states (expiry red/orange, reminder yellow) must stay the things that catch the eye. */
/* Sits inside .lead-card-meta, beside "Last activity", so it adds no height to the card: no top
   margin, line-height pinned to 1 so the bordered chip is no taller than the text line beside it. */
.lead-card-type {
    display: inline-block;
    line-height: 1;
    padding: 1px var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--color-text-muted);
    background: var(--color-surface);
}

.lead-card-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.75rem;
    color: var(--color-text-subtle);
    margin-top: 3px;
    white-space: nowrap;
}
/* Right-aligned against the bell's column (.lead-card-slot-bell), which holds its place when empty.
   On a narrow card it's "Last activity" that gives way (ellipsis), never the chip or the bell column. */
.lead-card-meta .lead-card-type { margin-left: auto; flex-shrink: 0; }
.lead-card-activity { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.lead-card-meta .lead-card-type + .lead-card-slot-bell { margin-left: 0; }
.lead-card-slot-bell { margin-left: auto; }

/* ── Contact info card ──────────────────────────────────────── */
.contact-info-card {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-4);
}
.contact-info-card h4 { margin-bottom: var(--space-3); text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.06em; color: var(--color-text-muted); }

.contact-info-groups {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2) var(--space-6);
}

.info-row { display: flex; gap: var(--space-2); font-size: 0.875rem; padding: 2px 0; }
.info-label { color: var(--color-text-muted); min-width: 90px; flex-shrink: 0; }
.info-value { color: var(--color-text); font-weight: 500; }

/* ── Customer Info modal (New Lead / Edit Customer Info — CustomerNewForm.vb) ──── */
.modal-customer-info { max-width: 840px; width: 95vw; }
/* Admin-only shared-account toggle. Sits between the customer panels and the docked action row,
   separated by a rule so it reads as a setting about the customer rather than another field of it. */
.customer-shared-account { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--color-border); }
.customer-shared-account p.muted { margin: var(--space-2) 0 0; }

.customer-info-panels { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-2); }
.customer-info-panel { min-width: 0; margin-bottom: 0; }
/* The fields under a phone, shut until that phone has been looked up (CustomerInfoModal). */
.customer-info-fields { border: 0; padding: 0; margin: 0; min-width: 0; }
.customer-info-fields:disabled { opacity: 0.5; }
.customer-info-lookup-notes p { margin: 0 0 var(--space-1); }
.customer-info-release { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.customer-info-release p { flex-basis: 100%; margin: 0; }

/* Label-above-input instead of the shared .form-row's label-beside-input — with labels of very
   different lengths ("Customer Phone (required)" vs "City"), a beside layout makes every input start
   at a different x position row to row. Scoped to this modal only; .form-row is shared app-wide. */
.customer-info-panel .form-row { flex-direction: column; align-items: stretch; gap: var(--space-1); }
.customer-info-panel .form-row input,
.customer-info-panel .form-row select { width: 100%; min-width: 0; flex: none; }
.customer-info-panel .form-row.customer-info-validation-row { flex-direction: row; align-items: center; }

/* City/Prov stays a side-by-side pair (standard address-form convention) — each half keeps its own
   stacked label-above-field internally, so it isn't subject to the same cross-row misalignment. */
.customer-info-panel .customer-info-cityprov-row { flex-direction: row; align-items: flex-end; gap: var(--space-3); }
.customer-info-field { display: flex; flex-direction: column; gap: var(--space-1); flex: 1; min-width: 0; }
.customer-info-field-narrow { flex: 0 0 90px; }

.customer-info-sameassoldto { align-self: flex-start; }

.customer-search-panel { display: flex; flex-direction: column; gap: var(--space-2); }
.customer-search-panel .product-picker-search-fields { margin-bottom: 0; }

.customer-info-validation-row { border-top: 1px solid var(--color-border); padding-top: var(--space-3); margin-top: var(--space-2); }
.address-validation-label { font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--color-text-muted); white-space: nowrap; }

/* Address 1 with Google's suggestions (AddressAutocompleteInput). The list hangs under the input inside
   whatever panel holds it, so it scrolls with a modal instead of needing to sit above the overlay. */
.address-autocomplete { position: relative; width: 100%; }
.address-autocomplete > input { width: 100%; min-width: 0; }
.address-autocomplete-list {
    font-weight: 400;
    position: absolute;
    top: calc(100% + 2px);
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}
.address-autocomplete-list .product-picker-item { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; height: auto; text-align: left; }
.address-autocomplete-main { font-weight: 600; }
.address-autocomplete-secondary { color: var(--color-text-muted); font-size: 0.75rem; }
.address-autocomplete-list .product-picker-item-selected .address-autocomplete-secondary { color: inherit; font-weight: 400; }
.address-autocomplete-attribution { padding: var(--space-1) var(--space-3); font-size: 0.6875rem; color: var(--color-text-muted); text-align: right; border-top: 1px solid var(--color-border); }

/* ── KPI tiles ──────────────────────────────────────────────── */
.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-5);
}

.kpi-tile {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.kpi-value { font-size: 1.25rem; font-weight: 700; }
.kpi-label { font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); }

/* ── Quick actions ──────────────────────────────────────────── */
.quick-actions { margin-bottom: var(--space-5); }
.quick-actions h4 { text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.06em; color: var(--color-text-muted); margin-bottom: var(--space-3); }
.quick-actions-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* ── Summary tab layout ─────────────────────────────────────── */
.crm-summary-grid { display: grid; grid-template-columns: 1fr 280px; gap: var(--space-6); align-items: start; }
.crm-summary-side { display: flex; flex-direction: column; gap: var(--space-4); }

/* Summary ▸ Appointments (LeadAppointmentsPanel) — a second .lead-status-panel under Lead Status. */
.lead-appt-panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-3); }
.lead-appt-panel-head h4 { margin-bottom: 0; }
.lead-appt-form { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-3); }
.lead-appt-when { display: flex; gap: var(--space-2); }
.lead-appt-when input { flex: 1; min-width: 0; }
.lead-appt-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.lead-appt-item { font-size: 0.8125rem; }
.lead-appt-item + .lead-appt-item { border-top: 1px solid var(--color-border); padding-top: var(--space-3); }
.lead-appt-item-head { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); }
.lead-appt-when-text { font-weight: 600; }
.lead-appt-source { color: var(--color-text-muted); font-size: 0.75rem; margin-top: 2px; }
.lead-appt-detail { margin-top: var(--space-1); }
.lead-appt-label { display: block; color: var(--color-text-muted); font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.04em; }
.lead-appt-actions { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-1); }
.lead-appt-confirm { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-1) var(--space-2); margin-top: var(--space-1); font-size: 0.75rem; color: var(--color-text-muted); }
.lead-appt-confirm-pending { font-weight: 600; color: var(--color-warning); }
.lead-appt-confirm-form { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-2); }
.lead-appt-confirm-form textarea { font-size: 0.8125rem; }

/* Lead header: the appointment chip, as a button that opens the Summary tab's Appointments panel. */
.lead-header-appt { background: none; border: none; padding: 0; cursor: pointer; display: inline-flex; }

/* ── Status row / Lead status panel (shared by LeadStatusPanel & OrderTile) ── */
.lead-status-panel {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
}
.lead-status-panel h4 { text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.06em; color: var(--color-text-muted); margin-bottom: var(--space-3); }

.status-row-list { display: flex; flex-direction: column; gap: var(--space-2); }

.status-row { display: flex; align-items: baseline; gap: var(--space-2); font-size: 0.8125rem; }
.status-category { color: var(--color-text-muted); min-width: 80px; flex-shrink: 0; }
.status-desc { font-weight: 600; }

.status-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; align-self: center; }
.status-dot.grey,  .status-desc.grey  { color: var(--color-text-subtle); }
.status-dot.red,   .status-desc.red   { color: var(--color-danger); }
.status-dot.amber, .status-desc.amber { color: var(--color-warning); }
.status-dot.green, .status-desc.green { color: var(--color-success); }
.status-dot.grey  { background: var(--color-text-subtle); }
.status-dot.red   { background: var(--color-danger); }
.status-dot.amber { background: var(--color-warning); }
.status-dot.green { background: var(--color-success); }

/* ── Orders & Quotes tab ────────────────────────────────────── */
.orders-tab-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.orders-tab-header h4 { margin-bottom: 0; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.06em; color: var(--color-text-muted); }
.orders-tab-subheader { text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.06em; color: var(--color-text-muted); margin: var(--space-6) 0 var(--space-3); }

.order-tile-grid { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-4); }

.order-tile {
    width: 280px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    transition: border-color 0.15s;
}
.order-tile:hover { border-color: #c0c4cc; }
.order-tile-selected { border-color: var(--app-accent); border-width: 2px; }

.order-tile-top { display: flex; justify-content: space-between; gap: var(--space-3); }

.order-tile-no { font-weight: 700; font-size: 0.9375rem; }
.order-tile-cuf { font-size: 0.75rem; color: var(--color-text-muted); }
.order-tile-type { font-size: 0.75rem; margin-top: var(--space-1); }
.order-tile-date { font-size: 0.75rem; color: var(--color-text-muted); }

.order-tile-financials { text-align: right; flex-shrink: 0; }
.order-tile-fin-row { display: flex; justify-content: space-between; gap: var(--space-2); font-size: 0.75rem; min-width: 130px; }
.order-tile-fin-row span:first-child { color: var(--color-text-muted); }

.order-tile-divider { height: 1px; background: var(--color-border); margin: var(--space-3) 0; }

.order-tile-conditions { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-3); }

.order-tile-ready {
    width: 100%;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    font-size: 0.8125rem;
    height: 34px;
}
.order-tile-ready.ready { background: var(--color-success); border-color: var(--color-success); color: #fff; }

.order-tile-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-top: var(--space-2); }
.order-tile-action { width: 100%; height: 34px; }

/* ── E-Sign modal ───────────────────────────────────────────── */
.modal-esign { max-width: 520px; width: 95vw; }
.esign-status-block { border: 1px solid var(--color-border); border-radius: 6px; padding: var(--space-3); margin-bottom: var(--space-3); }
.esign-resend-note { color: var(--color-text-muted); font-size: 0.8125rem; margin-top: var(--space-2); }
.esign-send-options { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }

/* 2x2 grid for the app's 4 recurring order-format options (Detail/Summary x Itemized/Grouped) —
   used wherever those 4 buttons appear (Signature Menu's "Send for Signature", PrintOrderOptions.razor's
   Save/Print). Equal-width cells so 4 differently-sized buttons don't read as a sloppy, unaligned row. */
.order-format-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); margin-bottom: var(--space-3); }
.order-format-grid button { width: 100%; }

/* Open/Save mode switch above the 4 format buttons (PrintOrderOptions) — Open opens the PDF in a new
   tab, Save downloads it already named. Reuses the shared .segmented-control. */
.order-format-mode { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-4); }
.order-format-mode-label { font-size: 0.8125rem; font-weight: 600; color: var(--color-text); }
.order-format-mode-toggle { flex: 0 0 auto; }
.order-format-mode-hint { font-size: 0.8125rem; color: var(--color-text-muted); }

/* Same fix as .order-lines-table above: .summary-table's overflow:hidden (for rounded corners) also
   clips this table's per-row kebab dropdown, since it extends below the table's own bounds. */
.invoice-table { overflow: visible; }
.invoice-table thead tr th:first-child { border-top-left-radius: var(--radius); }
.invoice-table thead tr th:last-child { border-top-right-radius: var(--radius); }
.invoice-table tr { cursor: pointer; }
/* !important so selection reliably wins over higher-specificity backgrounds sharing this class
   elsewhere (e.g. Order Lookup's zebra striping, .order-lookup-table tbody tr:nth-child(even) td,
   which otherwise outranks this rule's specificity on even rows) — same precedent as
   .product-picker-row-selected. */
.invoice-row-selected td { background: var(--app-accent-bg) !important; }

/* ── Sample Log tab ─────────────────────────────────────────── */
.sample-checklist { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-4); }

.sample-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
}

.sample-row input[type="checkbox"] { margin-top: 3px; flex-shrink: 0; width: auto; height: auto; }

.sample-row-body { display: flex; flex-direction: column; gap: 2px; }
.sample-desc { font-weight: 600; font-size: 0.875rem; }
.sample-meta { font-size: 0.75rem; color: var(--color-text-muted); }

.sample-check-done {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-success);
    font-size: 0.75rem;
    font-weight: 700;
    margin-top: 3px;
}

.sample-checklist-returned .sample-row { cursor: default; background: var(--color-bg); }
.sample-checklist-returned .sample-desc { color: var(--color-text-muted); font-weight: 500; }

/* ── Notes tab ──────────────────────────────────────────────── */
.note-feed { display: flex; flex-direction: column; gap: var(--space-3); }

.note-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
}
.note-card-reminder { border-left: 3px solid var(--color-warning); background: var(--color-warning-bg); }

.note-reminder-badge {
    display: inline-block;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-warning);
    margin-bottom: var(--space-2);
}

.note-text { font-size: 0.875rem; margin-bottom: var(--space-3); white-space: pre-wrap; }

.note-reminder-locked-hint {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    margin-top: var(--space-1);
}

.note-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.note-byline { font-size: 0.75rem; color: var(--color-text-subtle); }
.note-reminder-pending { color: var(--color-text-muted); }
.note-actions { display: flex; gap: var(--space-2); }

/* ── Activity Log tab ───────────────────────────────────────── */
.activity-heading { margin-top: 0; }

.activity-feed {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0 var(--space-4);
}

.activity-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-border);
}
.activity-row:last-child { border-bottom: none; }

.activity-type {
    flex-shrink: 0;
    width: 100px;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
}

.activity-main { display: flex; flex-direction: column; gap: 2px; }
.activity-desc { font-size: 0.875rem; }
.activity-meta { font-size: 0.75rem; color: var(--color-text-subtle); }

/* ── Payment tab ────────────────────────────────────────────── */
.payment-order-table { margin-bottom: var(--space-5); }
.payment-order-table tbody tr { cursor: pointer; }
.payment-order-table tr.payment-row-selected td { background: var(--app-accent-bg); }
.payment-order-table td:nth-child(3), .payment-order-table td:nth-child(4), .payment-order-table td:nth-child(5),
.payment-order-table th:nth-child(3), .payment-order-table th:nth-child(4), .payment-order-table th:nth-child(5) { text-align: right; }

.payment-profile-list { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-3); }

.payment-profile-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
}
.payment-profile-selected { border-color: var(--app-accent); border-width: 2px; }

.payment-profile-main { display: flex; align-items: baseline; gap: var(--space-3); }
.payment-profile-card { font-weight: 700; font-size: 0.9375rem; }
.payment-profile-card-sub { font-weight: 400; font-size: 0.8125rem; color: var(--color-text-muted); margin-left: var(--space-1); }
.payment-profile-expiry { font-size: 0.8125rem; color: var(--color-text-muted); }

.payment-profile-badges { display: flex; gap: var(--space-2); flex-wrap: wrap; }

.validation-badge {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
}
.validation-badge.green { background: var(--color-success-bg); color: var(--color-success); }
.validation-badge.amber { background: var(--color-warning-bg); color: var(--color-warning); }
.validation-badge.red   { background: var(--color-danger-bg); color: var(--color-danger); }
.validation-badge.grey  { background: var(--color-bg); color: var(--color-text-subtle); }

.payment-history-header { margin-top: var(--space-5); }

.payment-history-table tbody tr { cursor: pointer; }
.payment-history-table tr.payment-row-selected td { background: var(--app-accent-bg); }
.payment-history-table tr.payment-row-donor td { font-style: italic; color: var(--color-text-subtle); }
.payment-history-table tr.payment-row-donor.payment-row-selected td { color: inherit; }

.payment-source-other { font-size: 0.75rem; color: var(--color-text-subtle); }

.payment-action-row {
    display: flex;
    align-items: flex-end;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-top: var(--space-4);
}

.payment-outstanding { display: flex; flex-direction: column; gap: 2px; }
.payment-amount-field { margin-bottom: 0; max-width: 160px; }

/* ── App update banner ──────────────────────────────────── */
/* Persistent bottom-centre pill shown while a newer deployment is waiting (see AppLifecycleService).
   z-index sits above the fixed top-nav (100) but below modal overlays (200), so an open modal takes
   precedence and the banner reappears once it closes. No dismiss control by design. */
.update-banner {
    position: fixed;
    left: 50%;
    bottom: var(--space-4);
    transform: translateX(-50%);
    z-index: 150;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    max-width: calc(100vw - 2 * var(--space-4));
    padding: var(--space-3) var(--space-5);
    background: var(--color-near-black);
    color: #fff;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    font-size: 0.875rem;
}
.update-banner-text { font-weight: 500; }
.update-banner-btn {
    flex: 0 0 auto;
    background: var(--app-accent);
    color: #fff;
    border: none;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius);
    font-weight: 600;
    font-size: 0.8125rem;
    white-space: nowrap;
    cursor: pointer;
}
.update-banner-btn:hover { background: var(--app-accent-dark); }

/* Compact card for the in-flight payment spinner overlay — reuses .modal's surface but sized to just
   the spinner + label rather than the default 480px modal width. */
.payment-processing-modal { max-width: 260px; }
.payment-processing-modal .crm-detail-loading { padding: 0; }

/* ── Segmented control (reused: OrderEntry order type) ─────── */
.segmented-control {
    display: inline-flex;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 3px;
}

.segment, .segment-active {
    background: transparent;
    border: none;
    height: 32px;
    padding: 0 var(--space-4);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-text-muted);
    border-radius: var(--radius-sm);
}
.segment-active { background: var(--color-surface); color: var(--color-text); box-shadow: var(--shadow-sm); }

/* ── OrderEntry — classification strip ─────────────────────── */
/* The order's settings: a single wrapping row of controls, sitting in the strip directly above the Add
   buttons (see .order-entry-settings). Wrapping rather than a fixed set of columns, so a narrow window
   drops toggles onto a second line instead of squeezing them. */
.order-classification {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    flex: 1 1 auto;
    min-width: 0;
}

.order-classification-field { margin-bottom: 0; min-width: 160px; }

.order-classification-check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.875rem;
    height: 40px;
    white-space: nowrap;
}
.order-classification-check input { width: auto; }

.order-classification-locked { opacity: 0.6; }

/* ── OrderEntry — line entry strip ──────────────────────────── */
.line-entry {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
    margin-bottom: var(--space-5);
}

/* Live unit-conversion helper under the entry fields (legacy's lblConvert). An informational cue, so
   it uses the semantic info tokens (tinted = state) rather than the app accent. */
.line-entry-conversion {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin: calc(-1 * var(--space-2)) 0 var(--space-4);
    padding: var(--space-1) var(--space-3);
    background: var(--color-info-bg);
    border: 1px solid var(--color-info-border);
    border-radius: var(--radius-sm);
    color: var(--color-info);
    font-size: 0.8125rem;
    font-weight: 600;
}
.line-entry-conversion-icon { font-weight: 700; }

/* One row of buttons. The rule that used to separate these from the entry panel's fields went with the
   fields — there's nothing above them to divide from now. */
.line-entry-addons {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.line-entry-addons-mobile { display: none; }

.addons-menu { position: relative; }
.addons-menu-dropdown { min-width: 180px; }

.moulding-filter-input { display: block; width: 100%; margin-bottom: var(--space-3); }
.picker-list { display: flex; flex-direction: column; gap: var(--space-1); max-height: 320px; overflow-y: auto; margin-bottom: var(--space-2); }
.picker-item {
    text-align: left;
    justify-content: flex-start;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    font-size: 0.875rem;
}
.picker-item:hover { border-color: var(--app-accent); }

.notes-textarea {
    width: 100%;
    resize: vertical;
    font-family: inherit;
    font-size: 0.875rem;
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

.notes-readonly-text { white-space: pre-wrap; font-size: 0.875rem; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-bg); }

.modal-notes { max-width: 620px; }

.notes-presets { margin-bottom: var(--space-4); }
.notes-presets-label { display: block; text-transform: uppercase; font-size: 0.6875rem; letter-spacing: 0.06em; color: var(--color-text-muted); margin-bottom: var(--space-2); }
.notes-preset-pills { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.notes-preset-pill {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: var(--space-1) var(--space-3);
    font-size: 0.8125rem;
    color: var(--color-text);
    cursor: pointer;
}
.notes-preset-pill:hover { border-color: var(--app-accent); color: var(--app-accent); }

/* ── OrderEntry — Product Picker (Browse + Search) ───────────── */
/* overflow-x here (not on .product-picker-browse-desktop) is deliberate: panes size to their own
   content with no cap, so if the row of panes together exceeds the modal's width, the whole modal
   scrolls horizontally rather than an inner row scrolling under a truncated view. */
/* 1200px (was 960): with A-Team point pills on styles and colours, four panes no longer fit in 960
   (user, 2026-09-25). Same per-modal width convention as .modal-customer-info / .modal-paykeeper-preview. */
.modal-product-picker { max-width: 1200px; width: 95vw; overflow-x: auto; }

.product-picker-toprow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
}

.product-picker-discontinued { font-size: 0.8125rem; color: var(--color-text-muted); display: flex; align-items: center; gap: var(--space-2); }
/* Keep the two browse toggles together (the toprow is space-between, which would otherwise push them apart). */
.product-picker-toggles { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }

.product-picker-browse-desktop { display: flex; gap: var(--space-3); padding-bottom: var(--space-2); }
/* Panes are sized to their content, so any sideways overflow inside a list is only sub-pixel text
   rounding, which still drew a useless horizontal scrollbar (user, 2026-09-25). Same fix as
   .pricelist-display-list. Desktop only: the mobile lists are full-width and may need it. */
.product-picker-browse-desktop .product-picker-pane-list { overflow-x: hidden; }
/* Trailing room after the last pane: when the row overflows and the modal scrolls right, the
   modal's own padding isn't part of the scroll area, so the last pane sat flush against the edge. */
.product-picker-browse-desktop::after { content: ""; flex: 0 0 var(--space-2); }
.product-picker-browse-mobile { display: none; }

.product-picker-pane { flex: 0 0 auto; width: max-content; min-width: 170px; }
.product-picker-pane-header {
    text-transform: uppercase;
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
    margin-bottom: var(--space-2);
}
.product-picker-pane-list {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    max-height: 300px;
    overflow-y: auto;
}
.product-picker-mobile-list { max-height: 340px; }

.product-picker-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--color-border);
    padding: var(--space-2) var(--space-3);
    font-size: 0.8125rem;
    color: var(--color-text);
    cursor: pointer;
}
.product-picker-item:last-child { border-bottom: none; }
.product-picker-item:hover { background: var(--color-bg); }
.product-picker-item-selected, .product-picker-item-selected:hover { background: var(--app-accent-bg); color: var(--app-accent); font-weight: 600; }

.product-picker-breadcrumb {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}
.product-picker-crumb { background: transparent; border: none; padding: 0; font-size: 0.8125rem; color: var(--color-text-muted); cursor: pointer; }
.product-picker-crumb-active { color: var(--app-accent); font-weight: 600; }

.product-picker-search-fields { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.product-picker-search-input {
    flex: 1 1 140px;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: 0.8125rem;
}
.product-picker-search-input-code { flex: 0 1 90px; }
/* Roll numbers are usually 8 digits; the shared 90px code width only shows 7. Sized in ch (one digit in
   this font) plus the input's padding and border, so it fits 8 digits with room for the caret. */
.product-picker-search-input-roll { flex-basis: calc(9ch + 2 * var(--space-3) + 2px); }

.product-picker-results-scroll { max-height: 320px; overflow-y: auto; }
.product-picker-results-table thead th { cursor: pointer; user-select: none; }
.product-picker-results-table tbody tr { cursor: pointer; }
.product-picker-results-table tbody tr:hover td { background: var(--color-bg); }
.product-picker-row-selected td { background: var(--app-accent-bg) !important; }

/* A-Team Rewards chip in the product browsers (Pricelist, PriceLister Displays, Add Product): always
   A-Team indigo whatever app it sits in. Screen only — never on a printed list. */
.ateam-chip {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--color-ateamrewards) 10%, white);
    border: 1px solid color-mix(in srgb, var(--color-ateamrewards) 30%, white);
    color: var(--color-ateamrewards);
    font-size: 0.6875rem;
    font-weight: 600;
    white-space: nowrap;
    vertical-align: 1px;
}
.product-picker-item-selected .ateam-chip { background: white; }
/* Display lists: a star in a small chip (same tint as the points pills), so long display names don't
   wrap or push the list wider. */
.ateam-star {
    display: inline-block;
    margin-left: 5px;
    padding: 0 4px;
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--color-ateamrewards) 10%, white);
    border: 1px solid color-mix(in srgb, var(--color-ateamrewards) 30%, white);
    color: var(--color-ateamrewards);
    font-size: 0.6875rem;
    line-height: 1.4;
    vertical-align: 1px;
}
.product-picker-item-selected .ateam-star { background: white; }
/* "Hide A-Team Points" toggle on PriceLister and Add Product. */
.hide-ateam .ateam-chip, .hide-ateam .ateam-star { display: none; }
@media print { .ateam-chip, .ateam-star { display: none; } }

.product-picker-instock-badge {
    background: var(--color-success-bg);
    color: var(--color-success);
    border-radius: var(--radius-sm);
    padding: 2px 6px;
    font-size: 0.75rem;
    font-weight: 600;
}

/* ── Stock Check (read-only — shares .modal-product-picker + .product-picker-* with Product Picker) */
.stock-check-discontinued { margin-bottom: var(--space-3); }
.stock-check-item-heading { margin-bottom: var(--space-3); font-size: 0.9375rem; }
.stock-check-table tbody tr:hover td { background: transparent; }
/* Two distinct indicators, matching legacy's own two separate cues (StockChecker4's asterisk column
   and its unrelated bold-row rule) rather than conflating them into one: bold = stocked anywhere in the
   company; the subtle green tint = in stock at the relevant store (see StockCheck.razor's OverrideStore
   doc comment for what "relevant" means per caller). */
.stock-check-row-stocked td { font-weight: 600; }
.stock-check-row-inhouse td { background: var(--color-success-bg); }

/* ── Pricelist (own page, opens in a new tab — reference tool kept open in the background) ──── */
.pricelist-shell h2 { margin-bottom: var(--space-4); }

.pricelist-toprow { display: flex; gap: var(--space-4); margin-bottom: var(--space-4); align-items: center; }
.pricelist-new-btn { margin-left: auto; }   /* category managers: New Pricelist, pushed to the right of the toggles */

.pricelist-body { display: flex; gap: var(--space-4); align-items: flex-start; }

.pricelist-nav-desktop { display: flex; gap: var(--space-3); flex-shrink: 0; }
.pricelist-nav-mobile { display: none; }
.pricelist-nav-list { max-height: 420px; }

/* Display list can run to 50-100+ items with long names — grow to fit content (both directions)
   up to a sane cap, then fall back to the inherited scroll (.product-picker-pane-list) once even
   that cap is exceeded. */
.pricelist-display-pane { flex: 0 1 auto; width: max-content; min-width: 170px; max-width: min(420px, 32vw); }
.pricelist-display-pane .product-picker-item { overflow-wrap: break-word; }
.pricelist-display-list { max-height: min(640px, calc(100vh - 260px)); overflow-x: hidden; }

/* Stack the producer/consumer blocks (actions bar, panels, heading, the pricelist itself, the QR bar)
   vertically and full-width. The main-table / Mouldings side-by-side "dock" now lives one level down in
   .pricelist-grids-inner (the shared renderer), so this level is a simple column. */
.pricelist-grids { display: flex; flex-direction: column; gap: var(--space-4); flex: 1; min-width: 0; align-items: stretch; }
/* No overflow/min-width:0 clipping here — a wide table is allowed to overflow past this box (and
   past .crm-shell's full-bleed 100vw) so the page itself scrolls horizontally, rather than hunting
   for a scrollbar buried at the bottom of a tall internal scroll container. */
/* The side-by-side dock: the pricelist table and the Mouldings table share a row and the Mouldings
   block wraps beneath only when the row can't hold both. (The standalone refactor moved the dock here
   from .pricelist-grids but left this element unstyled, so it had been stacking.) align-items:flex-start
   keeps the shorter Mouldings table pinned to the top rather than stretched to the pricelist's height. */
.pricelist-grids-inner { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-start; }
/* Neither table grows to fill: the pricelist stays at its content width (full-view sizing above) and the
   Mouldings table stays compact, so the leftover row space sits to their right. */
.pricelist-grid-main { flex: 0 1 auto; min-width: 0; }
.pricelist-grid-mouldings { flex: 0 1 auto; min-width: 0; max-width: 320px; overflow-x: auto; }
.pricelist-mobile-tabs { display: none; }

/* Denser than the default .summary-table — these lists can run long, so every row counts. */
.pricelist-table th, .pricelist-table td { padding: var(--space-1) var(--space-2); font-size: 0.75rem; line-height: 1.25; }
.pricelist-table tbody tr:nth-child(even) td { background: var(--color-bg); }
/* Full view: size the table to its content and stop — as wide as the columns need for the data and
   headers, no wider. Overrides .summary-table's width:100% so it neither squeezes columns into the
   container nor stretches to fill it; a genuinely wide list still grows past the container (page
   scrolls). Mobile re-fills to the container width in the media query below. */
.pricelist-grid-main .pricelist-table { width: max-content; }

/* ── Sample Log (own page, opens in a new tab — store-wide sample browsing/search tool,
   distinct from CrmDashboard's per-lead Sample Log tab) ─────────────────────────────── */
.samplelog-shell h2 { margin-bottom: var(--space-4); }

.samplelog-body { display: flex; gap: var(--space-4); align-items: flex-start; }

/* Capped relative to viewport (nav bar + this page's own "Sample Log" heading above it, plus a
   bottom buffer) so a long record list can't push the page taller than the screen — the table itself
   then flex-fills whatever room is left under its own header/search panel, same pattern as
   .crm-list-pane/.lead-card-list. */
.samplelog-list-pane {
    flex: 3 1 480px;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* 56px nav bar + 32px .main-content top padding + 46px "Sample Log" h2 (30px + 16px margin) + 24px
       .crm-shell bottom padding + 32px .main-content bottom padding = 190px of fixed chrome around this
       pane, measured directly rather than guessed — a too-small offset here (180px was 10px short)
       leaves just enough page-level overflow to trigger an unwanted whole-page scrollbar. */
    max-height: calc(100vh - 190px);
}
.samplelog-detail-pane {
    flex: 2 1 360px;
    min-width: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: var(--space-5) var(--space-6);
}

.samplelog-table-scroll { flex: 1 1 auto; min-height: 120px; overflow: auto; }

/* "All Outstanding" modal — wider than the default .modal-notes cap (4 data columns) and its table
   scrolls internally, same fixed-cap convention as .picker-list/.order-lookup-results-scroll, so a long
   outstanding-samples list can't push the modal past the viewport. */
.modal-outstanding { max-width: 760px; }
.samplelog-outstanding-scroll { max-height: 420px; overflow-y: auto; margin-bottom: var(--space-3); }
.sortable-th { cursor: pointer; user-select: none; white-space: nowrap; }

/* Sticky header inside a scrolling wrapper — the standard technique every data-grid library uses
   internally (AG Grid, MUI DataGrid, etc.): one <table>, one column-width computation (so header and
   body cells can never drift out of alignment, unlike splitting thead/tbody into separate block boxes),
   with just the header row pinned via position:sticky as its content scrolls underneath. .summary-table's
   own overflow:hidden (for its rounded corners) would otherwise become the sticky positioning context
   instead of the actual scroll wrapper, so overflow/radius/shadow move from the table onto the wrapper —
   an overflow:auto container with its own border-radius clips its scrolling content just as cleanly. */
.samplelog-table-scroll,
.manager-dash-table-area .admin-table-scroll,
.admin-users-table-area .admin-table-scroll,
.samplelog-outstanding-scroll {
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}
.samplelog-table-scroll table,
.manager-dash-table-area table,
.admin-users-table-area table,
.samplelog-outstanding-scroll table {
    overflow: visible;
    border-radius: 0;
    box-shadow: none;
}
.samplelog-table-scroll table thead th,
.manager-dash-table-area table thead th,
.admin-users-table-area table thead th,
.samplelog-outstanding-scroll table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
}
.samplelog-table tbody tr { cursor: pointer; }

.samplelog-search-panel {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
    margin-bottom: var(--space-4);
}
.samplelog-search-actions { justify-content: flex-start; }

.samplelog-detail-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-2); }
.samplelog-detail-meta { font-size: 0.8125rem; color: var(--color-text-muted); }

.samplelog-pending-item { display: flex; align-items: center; justify-content: space-between; cursor: default; }
.samplelog-pending-item:hover { border-color: var(--color-border); }

/* ── Generic sortable table header (Sample Log, Order Lookup, ...) ──────────── */
.sortable-th { cursor: pointer; user-select: none; white-space: nowrap; }

/* ── Generic inline confirm banner (yes/no prompt without a native dialog) ──── */
.confirm-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    background: var(--color-info-bg);
    border-left: 3px solid var(--color-info);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-4);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--color-info);
}
.confirm-banner-actions { display: flex; gap: var(--space-2); flex-shrink: 0; }

/* ── Order Lookup (dialog — Tools menu, store-wide order search with/without a lead) ────── */
.order-lookup-search { margin-bottom: var(--space-4); }

/* 4-column grid (label, field, label, field) so every field lines up to the same column widths
   across rows, regardless of label text length — a flex .form-row per line can't guarantee that. */
.order-lookup-search-grid {
    display: grid;
    grid-template-columns: max-content 1fr max-content 1fr;
    gap: var(--space-3) var(--space-3);
    align-items: center;
    margin-bottom: var(--space-3);
}
.order-lookup-search-grid label {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    white-space: nowrap;
}
.order-lookup-search-grid input[type="text"] { width: 100%; }

.date-range-field { display: flex; align-items: center; gap: var(--space-2); }
.date-range-field input[type="date"] { flex: 1; min-width: 0; }
.date-range-toggle { flex-shrink: 0; }

.order-lookup-checks { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-3); }
.order-lookup-permission-note { font-size: 0.75rem; }
.order-lookup-search-actions { justify-content: flex-start; margin-top: var(--space-2); }

.order-lookup-results-scroll { max-height: 420px; overflow-y: auto; overflow-x: auto; }
.order-lookup-table th, .order-lookup-table td { white-space: nowrap; padding: var(--space-1) var(--space-2); font-size: 0.75rem; line-height: 1.25; }
.order-lookup-table tbody tr { cursor: pointer; }
.order-lookup-table tbody tr:nth-child(even) td { background: var(--color-bg); }

/* Action bar sits directly under the table and only appears once a row is selected — ties the
   actions to their context instead of floating disabled buttons at the bottom of the whole dialog. */
.selected-row-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
    flex-shrink: 0;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-top: var(--space-3);
}
.selected-row-label { font-size: 0.875rem; }

/* ── Admin (Tools menu, ManagerOnly + future AdminOnly flag — Users + Reference Tables tabs) ──── */
/* This input borrows .product-picker-search-input, whose `flex: 1 1 140px` is meant for a ROW flex
   container. Here the parent (.admin-users-body) is a COLUMN flex, so that flex-basis becomes a 140px
   HEIGHT and flex-grow stretches the box vertically — the input balloons. Pin it to its natural height. */
.admin-users-filter { display: block; width: 100%; max-width: 360px; margin-bottom: var(--space-3); flex: 0 0 auto; }
.admin-table-scroll { overflow-x: auto; }

/* Same pinned-action-bar pattern as .manager-dash-body: cap the Users tab to the viewport so a long
   user list scrolls inside the table area instead of pushing .selected-row-bar off-page — the bar
   stays reachable right below the table rather than needing a full-page scroll. */
.admin-users-body {
    display: flex;
    flex-direction: column;
    /* 270px of fixed chrome, measured in-browser rather than guessed: 214px above this element
       (56px nav + 32px .main-content top padding + 32px "‹ Home" btn-sm + 30px h2 + 64px .tab-bar
       incl. its 24px margin) + 56px below it (24px .crm-shell + 32px .main-content bottom padding). */
    max-height: calc(100vh - 270px);
}
.admin-users-table-area { flex: 1 1 auto; min-height: 120px; overflow: hidden; display: flex; flex-direction: column; }
.admin-users-table-area .admin-table-scroll { flex: 1 1 auto; overflow: auto; }
.admin-users-table tbody tr { cursor: pointer; }

.admin-manage-user-modal { max-width: 560px; }
.admin-modal-subheader { margin: var(--space-5) 0 var(--space-3); font-size: 0.9375rem; }

/* Fixed label column so every field in a form lines up down the modal. .form-row on its own is flex,
   so each input starts wherever its own label ends — fine for a couple of rows, ragged for a form of
   a dozen. The label column is wide enough for the longest label here ("Next Order #"). */
.admin-form-aligned .form-row { display: grid; grid-template-columns: 10rem 1fr; align-items: center; gap: var(--space-3); }
.admin-form-aligned .form-row input,
.admin-form-aligned .form-row select { width: 100%; flex: none; min-width: 0; }

.admin-toggle-grid { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-5); margin-bottom: var(--space-2); }

.admin-store-checklist { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.admin-store-check { display: inline-flex; align-items: center; gap: var(--space-1); font-size: 0.875rem; }
.admin-store-check input { width: auto; }

.admin-reset-password-panel {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
}
.admin-reset-password-actions { justify-content: flex-start; margin-top: var(--space-2); }
.admin-reset-password-confirm { color: var(--color-success); font-size: 0.875rem; font-weight: 600; }

.admin-reference-body { display: flex; gap: var(--space-4); align-items: flex-start; }
.admin-reference-nav { flex-shrink: 0; }
.admin-reference-editor { flex: 1; min-width: 0; }

.admin-reference-list { display: flex; flex-direction: column; gap: var(--space-2); max-width: 420px; }
.admin-reference-row { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2); }
.admin-reference-row input, .admin-reference-row textarea { flex: 1; }

.admin-terms-category-bar { margin-bottom: var(--space-4); }
.admin-terms-hint { color: var(--color-text-muted); font-size: 0.8125rem; margin-bottom: var(--space-3); }

/* Lead Types editor. Rows are edited in place, so cells hold controls: keep them vertically centred
   and the reorder arrows compact enough that the name column gets the width. */
.admin-lead-types-table td { vertical-align: middle; }
.admin-lead-types-table input[type="text"] { width: 100%; min-width: 10rem; }
.admin-lead-types-table select { width: auto; min-width: 9rem; }
.admin-lead-types-table .toggle-switch { margin: 0; }
.admin-lead-type-order { white-space: nowrap; }
.admin-lead-type-order .btn-icon { padding: 0 4px; font-size: 0.75rem; }
/* Number + unit on one line; the input is only wide enough for a 3-digit period, so the "days"
   label reads as part of the field rather than a separate column. */
.admin-lead-type-expiry { white-space: nowrap; }
.admin-lead-type-expiry input { width: 5rem; margin-right: var(--space-2); }

/* Tax Exemption Reasons reuses the Lead Types table; the confirmation is a paragraph, so it gets a
   textarea wide enough to read, and the rows top-align so a tall textarea doesn't float the rest. */
.admin-tax-reasons-table td { vertical-align: top; }
.admin-tax-reasons-table input[type="text"] { min-width: 18rem; }
.admin-tax-reason-confirmation textarea { width: 100%; min-width: 18rem; resize: vertical; }

/* ── Admin ▸ Accounting: GL journal posting ───────────────
   Semantic tokens only (never an app accent): good/bad are state, and the posted banner is success. */
.admin-gl-target { color: var(--color-text); }
.admin-gl-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-top: var(--space-3); }
.admin-gl-file { display: flex; flex-direction: column; gap: var(--space-1); font-size: 0.875rem; }
.admin-gl-hint { color: var(--color-text-muted); font-size: 0.8125rem; margin: var(--space-2) 0 var(--space-3); }
.admin-gl-locked-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-2); }
.admin-gl-summary { max-width: 32rem; margin-bottom: var(--space-3); }
.admin-gl-summary td:first-child { color: var(--color-text-muted); width: 10rem; }
.admin-gl-summary .num,
.admin-gl-table .num { text-align: right; }
.admin-gl-table tfoot td { font-weight: 600; }
.admin-gl-good { color: var(--color-success); }
.admin-gl-bad { color: var(--color-danger); }
.admin-gl-row-problem td { background: var(--color-danger-bg); }
.admin-gl-problem { display: block; color: var(--color-danger); font-size: 0.8rem; font-weight: 600; }
.admin-gl-posted {
    background: var(--color-success-bg);
    border: 1px solid var(--color-success-border);
    color: var(--color-success);
    border-radius: 0.4rem;
    padding: 0.6rem 0.75rem;
    margin: 0.5rem 0;
    font-size: 0.9rem;
}
.admin-gl-history-title { margin-top: var(--space-5); }

/* Admin ▸ Accounting ▸ Month-end close */
.admin-accounting-switch { margin-bottom: var(--space-4); }
.admin-monthend-current {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    margin: var(--space-3) 0;
}
.admin-monthend-current h4 { margin: 0 0 var(--space-1); }
.admin-monthend-table .num,
.admin-monthend-stores .num { text-align: right; white-space: nowrap; }
.admin-monthend-table td { white-space: nowrap; }
.admin-monthend-actions { display: flex; gap: var(--space-2); justify-content: flex-end; }
.admin-monthend-stores-row > td { background: var(--color-bg); padding: var(--space-3); }
.admin-monthend-stores { margin: 0; }

/* ── Office + Manager Dashboards (Tools menu, own page/new tab — non-modal singletons in the original) ── */
.dashboard-filters { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-4); flex-shrink: 0; }
.dashboard-filters .form-row { margin-bottom: 0; }
.office-dash-table tbody tr { cursor: pointer; }
.office-dash-row-ready td { background: var(--color-success-bg) !important; }
/* Print button toolbar above the Open Orders table. */
.office-dash-print-row { margin-bottom: var(--space-3); justify-content: flex-end; }

.manager-dash-close-rate { font-size: 0.9375rem; font-style: italic; font-weight: 700; white-space: nowrap; }
.manager-dash-note-cell {
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Capped relative to viewport (nav bar + the page's own "Manager Dashboard" heading above it, plus a
   bottom buffer) so a long lead list can't push the action bar off-page — the table area flex-fills
   whatever room is left under the filters/tabs, and the selected-row action bar stays pinned right
   below it instead of requiring a full-page scroll to reach. Same pattern as .crm-list-pane. */
.manager-dash-body {
    display: flex;
    flex-direction: column;
    /* 56px nav bar + 32px .main-content top padding + 30px "Manager Dashboard" h2 (no margin-bottom on
       this page's plain h2, unlike Sample Log's) + 24px .crm-shell bottom padding + 32px .main-content
       bottom padding = 174px of fixed chrome, measured directly rather than guessed. */
    max-height: calc(100vh - 174px);
}
.manager-dash-table-area { flex: 1 1 auto; min-height: 120px; overflow: hidden; display: flex; flex-direction: column; }
.manager-dash-table-area .admin-table-scroll { flex: 1 1 auto; overflow: auto; }

/* ── OrderEntry — totals & completion ────────────────────────── */
.order-totals {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
    max-width: 360px;
    margin-left: auto;
}

.order-totals-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--space-2) 0;
    font-size: 0.875rem;
}
.order-totals-row + .order-totals-row { border-top: 1px solid var(--color-border); }

.order-totals-total { font-weight: 700; font-size: 1rem; }
.order-totals-balance { font-weight: 700; font-size: 1.0625rem; color: var(--color-text); }

.order-totals-deposit-input { display: flex; gap: var(--space-2); align-items: center; }
.order-totals-deposit-input input { width: 100px; text-align: right; }

.order-complete-btn { width: 100%; margin-top: var(--space-4); }

/* .summary-table sets overflow:hidden (to clip content to its rounded corners), but that also clips
   any per-line kebab dropdown that needs to extend below the table's own bounds. Override it here and
   round the header row's own corners directly instead, so the visual look is unaffected. */
.order-lines-table { table-layout: fixed; overflow: visible; }
.order-lines-table thead tr th:first-child { border-top-left-radius: var(--radius); }
.order-lines-table thead tr th:last-child { border-top-right-radius: var(--radius); }
.order-lines-table col.col-select { width: 4%; }
.order-lines-table col.col-style { width: 8%; }
.order-lines-table col.col-colour { width: 7%; }
.order-lines-table col.col-desc { width: 18%; }
.order-lines-table col.col-colourdesc { width: 13%; }
.order-lines-table col.col-qty { width: 6%; }
.order-lines-table col.col-unit { width: 6%; }
.order-lines-table col.col-unitprice { width: 8%; }
.order-lines-table col.col-linetotal { width: 9%; }
/* Roll # holds an 8-digit roll number, not the 1-3 digits the old 4% assumed — at 4% the cell was 57px
   and its editor 49px, too narrow to read one. Now 8%, paid for by col-actions (18%->15%) and
   colourdesc (13%->12%).
   The actions column was widened to 18% when it held 4 icon buttons AND a per-row Edit button stacked
   with the move arrows; with Edit gone and the arrows side by side it needs ~198px, its widest case
   being an editing row's three icon buttons (~112px, where the same three as word buttons needed ~198px
   and wrapped) — so 13%, and below ~1300px
   the col-secondary columns start dropping out anyway, freeing far more than this. */
.order-lines-table col.col-rollno { width: 8%; }
.order-lines-table col.col-actions { width: 13%; }

/* Per-line unit conversion note (the frozen ItemInfo.getConversion string). Neutral/muted — distinct
   from the info-accent live entry helper.
   Desktop: sits INSIDE the Qty cell, absolutely positioned into the vertical whitespace the stacked
   action buttons already create, so the row height is unchanged and no column widens. */
.order-line-qty-cell { position: relative; }

/* ── Inline (in-row) line editing ────────────────────────────────────────────
   Same approach as ShiftKeeper's timecard grid (.sk-tm-table's input rule): a native input/select uses
   an intrinsic minimum width, which in a table-layout:fixed grid overflows the cell and, worse, makes
   the row look different from the read-only rows. Filling the cell instead keeps every column exactly
   the width its <col> sets, in both modes. The editing row's cells also tighten their side padding, so
   the boxes have room without the columns moving (fixed layout ignores content width). */
.order-lines-table .order-line-edit-input {
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    height: 1.9rem;
    padding: 0.2rem 0.35rem;
    font: inherit;
    font-size: 0.8125rem;
    line-height: normal;
    vertical-align: middle;
}
.order-line-edit-num { text-align: right; font-variant-numeric: tabular-nums; }
/* Spinners would eat a third of a 6%-wide cell. */
.order-line-edit-num::-webkit-outer-spin-button,
.order-line-edit-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.order-line-edit-num { -moz-appearance: textfield; appearance: textfield; }
.order-lines-table tr.order-line-row-editing td { padding-left: var(--space-1); padding-right: var(--space-1); vertical-align: middle; }
/* …except the checkbox and actions cells. They hold the same controls as a display row, so the tighter
   padding shifted both 12px left of the rows above and below. Only the cells that gained inputs need it. */
.order-lines-table tr.order-line-row-editing td:first-child,
.order-lines-table tr.order-line-row-editing td:last-child { padding-left: var(--space-4); padding-right: var(--space-4); }
/* A row is one click from editing — say so, and tint the row under the pointer. */
.order-lines-table tr.order-line-row-clickable { cursor: pointer; }
.order-lines-table tr.order-line-row-clickable:hover td { background: var(--app-accent-ring); }
.tools-menu-item-danger { color: var(--color-danger); }

/* The actions column sets a line row's height. With the per-row Edit button gone there's width to spare,
   so the move arrows sit side by side instead of stacked — one ~30px band in display mode, the same as
   the editing row's Done/Cancel/Delete. Rows are shorter, and still identical in both modes (reserving
   the band's height here is what stops a row changing size as it opens). */
.order-lines-actions-desktop .btn-icon-stack { flex-direction: row; }
.order-lines-actions-desktop { min-height: 2rem; }
/* Line rows centre their cells vertically (the table's own default is top). An editing row's controls
   are centred in their cells, so against top-aligned text each value visibly jumped up the row as the
   row switched modes; centred, every input opens exactly where its text was. Data rows only — group
   header and conversion rows keep the table's alignment. (The alternative is top-aligning the controls
   instead, which leaves read rows untouched: swap this rule for vertical-align:top + a trimmed
   padding-top on .order-line-row-editing td.) */
.order-lines-table tbody tr[data-line-id] > td { vertical-align: middle; }
/* What's left of the entry panel now that lines are typed in the table: one row of buttons. The card
   padding goes, since there are no fields to frame — just the actions, where the panel's own were. */
.line-entry-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
}
.line-entry-toolbar .quick-actions-row { margin: 0; }

/* The row being added. Same controls as an editing row (it reuses .order-line-edit-input), with a left
   accent so it reads as pending rather than part of the order yet. */
.order-lines-table tr.order-line-row-new td:first-child { box-shadow: inset 3px 0 0 var(--app-accent); }
/* The "Installed?" switch under a new row: a group decision, not a column, so it gets its own sub-row. */
.order-lines-table tr.order-line-new-extra-row td { padding-top: 0; border-top: none; }
.order-line-installed-check { display: inline-flex; align-items: center; gap: var(--space-2); font-size: 0.8125rem; color: var(--color-text-muted); }

/* Row actions while editing: icon buttons in the same footprint as the row's own icons, so the actions
   column doesn't have to carry three word-buttons. Colour marks intent — keeping the change reads
   positive, deleting the line destructive — and every one keeps a title/aria-label, since an icon on
   its own says less than the word did. */
.order-line-action-done { color: var(--color-success); }
.order-line-action-done:hover:not(:disabled) { border-color: var(--color-success); }
.order-line-action-delete:hover:not(:disabled) { color: var(--color-danger); border-color: var(--color-danger); }
.order-line-installed-check input { width: auto; }

/* Phone line editor — the table can't hold a full line at that width. */
.line-editor-modal { max-width: 520px; }
.line-editor-modal .modal-actions { flex-wrap: wrap; }
.line-editor-modal-delete { margin-right: auto; }

/* Lookup error under the row being edited (Style/Colour Code didn't resolve). */
.order-lines-table tr.order-line-error-row td { padding-top: 0; border-top: none; }
.order-line-error-cell { color: var(--color-danger); font-size: 0.8125rem; font-weight: 500; white-space: normal; }
.order-line-conversion-inline {
    position: absolute;
    left: var(--space-2);
    bottom: var(--space-1);
    /* No overflow:hidden/ellipsis: it clips the trailing italic character's overhang (the ")" ). The
       string is capped at nvarchar(50) (~275px) and there's ~600px of empty runway across Unit/Price/
       Total before the Actions buttons, so nowrap alone never reaches them. */
    white-space: nowrap;
    font-size: 0.7rem;
    font-style: italic;
    line-height: 1.1;
    color: var(--color-text-muted);
    pointer-events: none;
}

/* Mobile fallback: mobile rows have only a single kebab button (no spare vertical space), so there the
   note drops to a compact sub-row instead. Hidden on desktop; the 900px block flips both. */
.order-line-conversion-row-mobile { display: none; }
.order-lines-table tr.order-line-conversion-row td {
    padding-top: 0;
    padding-bottom: var(--space-2);
}
.order-line-conversion-cell {
    font-size: 0.75rem;
    font-style: italic;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Generic utility — used across many tables (Pricelist, Office Dashboard, Compufloor History, Admin,
   Order Lookup, Sample Log, Stock Check, etc.), not just order-lines-table. */
.align-right { text-align: right; }

/* Every table already marks its <th> with align-right to match its right-aligned <td> cells, but
   .summary-table th/.report-table th (an element+class selector, specificity 0,1,1) was silently
   beating the plain .align-right class (0,1,0) and forcing every one of those headers back to
   text-align: left. Bumping this override to a class+element+class selector wins outright. */
.summary-table th.align-right, .report-table th.align-right { text-align: right; }

.order-lines-table .order-lines-group-header td {
    background: var(--color-bg);
    font-weight: 700;
    font-size: 0.8125rem;
    color: var(--color-text);
}

.order-lines-table .order-lines-group-header .order-lines-group-total-cell {
    font-style: italic;
    color: var(--app-accent);
    font-weight: 600;
}

.order-lines-table tr.order-line-row-grouped.group-accent-a td:first-child {
    box-shadow: inset 3px 0 0 var(--app-accent);
}
.order-lines-table tr.order-line-row-grouped.group-accent-b td:first-child {
    box-shadow: inset 3px 0 0 var(--app-accent-border);
}
/* Indents member lines' Description cell so they read as nested under their group header. Excludes
   the header rows themselves — the desktop header's name cell is td:first-child (colspan="5", not
   nth-child(4)) since it spans from the table's left edge rather than starting after 3 blank leading
   cells (fixes the group name visually starting under the Description column), so this selector
   would otherwise hit one of its *trailing total* cells instead. */
.order-lines-table tr.order-line-row-grouped:not(.order-lines-group-header) td:nth-child(4) { padding-left: calc(var(--space-3) + 6px); }

/* Two full <tr> versions of the group-header row exist (see OrderEntry.razor) — desktop's name cell
   spans colspan="5" from the table's left edge (columns 1-5: select/style/colour/desc/colourdesc) so
   the text doesn't start indented under Description; mobile keeps 3 separate leading (hidden) cells +
   colspan="2" since only desc/colourdesc are visible there anyway. Only one is shown per breakpoint. */
.order-lines-group-header-mobile { display: none; }

.order-line-row-editing td { background: var(--app-accent-bg); }

.order-lines-bulk-actions { display: flex; align-items: center; gap: var(--space-2); }
/* Pushed to the right end of the Add strip, so the buttons that create lines and the ones that act on
   ticked lines stay visually apart inside the one container. */
.line-entry-toolbar .order-lines-bulk-actions { margin-left: auto; }

/* The group name is its own edit target, like a line row — clicking it opens the input in place. The
   dotted underline on hover says it's editable without adding a button to the header. */
.group-name-editable { cursor: pointer; }
.group-name-editable:hover { text-decoration: underline dotted; text-underline-offset: 3px; }
.group-rename-row { display: flex; align-items: center; gap: var(--space-2); }
/* Scoped through .order-lines-table for the same reason .order-line-edit-input is: the global input rule
   matches on `input:not([type])`, which outranks a lone class, so the field came out at 1rem/40px — the
   name visibly grew the moment you clicked it. Same metrics as a line's in-row editor now, keeping the
   header's bold weight so the text itself doesn't change character either. */
.order-lines-table .group-rename-input {
    flex: 1;
    min-width: 0;
    box-sizing: border-box;
    height: 1.9rem;
    padding: 0.2rem 0.35rem;
    font: inherit;
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: normal;
    border: 1px solid var(--app-accent);
    border-radius: var(--radius-sm);
}

.order-lines-actions { white-space: nowrap; }

.order-lines-actions-desktop { display: flex; align-items: center; gap: var(--space-2); }
.order-lines-actions-mobile { display: none; position: relative; align-items: center; }

.btn-icon-stack { display: flex; flex-direction: column; gap: 2px; }

.btn-icon {
    width: 26px;
    height: 24px;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    border-radius: var(--radius-sm);
    font-size: 0.625rem;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.btn-icon:disabled { opacity: 0.35; cursor: default; }
.btn-icon:not(:disabled):hover { background: var(--color-bg); }

.line-kebab-trigger {
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    border-radius: var(--radius-sm);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}
.line-kebab-trigger:hover { background: var(--color-bg); }

/* Desktop-only per-line action icons (Stock Check / Add-ons) — replaces the old desktop "Add-ons for
   this line" kebab with two direct square icon buttons, same sizing/visual language as the kebab. */
.line-icon-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    border-radius: var(--radius-sm);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    color: var(--color-text);
}
.line-icon-btn:disabled { opacity: 0.35; cursor: default; }
.line-icon-btn:not(:disabled):hover { background: var(--color-bg); }
.line-icon-btn svg { flex-shrink: 0; width: 14px; height: 14px; }

.line-kebab-dropdown { min-width: 160px; }

.invoice-row-actions { position: relative; text-align: right; }

/* ── Documents tab ──────────────────────────────────────────── */
.documents-upload-zone { position: relative; }
.doc-dropzone {
    border: 2px dashed var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-6);
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.875rem;
    margin-bottom: var(--space-4);
    transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.doc-dropzone-active { border-color: var(--app-accent); background: var(--app-accent-bg); color: var(--app-accent); }

.document-list { display: flex; flex-direction: column; gap: var(--space-2); }

.document-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
}

.document-icon { font-size: 1.5rem; flex-shrink: 0; }

.document-main { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.document-name { font-weight: 600; font-size: 0.875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.document-meta { font-size: 0.75rem; color: var(--color-text-subtle); }

.document-actions { display: flex; gap: var(--space-2); flex-shrink: 0; }

/* ── Responsive: master-detail collapse on mobile ──────────── */
@media (max-width: 900px) {
    .crm-shell { padding: 0 var(--space-4) var(--space-4); }

    .crm-header-toggle { display: inline-flex; }
    .crm-header-content { display: none; }
    .crm-header.expanded .crm-header-content { display: flex; flex-direction: column; align-items: stretch; }

    .tools-menu-desktop { display: none; }
    .tools-menu-mobile { display: block; }

    .crm-body { flex-direction: column; }
    .crm-list-pane, .crm-detail-pane { width: 100%; }

    .crm-body.has-selection .crm-list-pane { display: none; }
    .crm-body:not(.has-selection) .crm-detail-pane { display: none; }

    .crm-body.has-selection .crm-back-btn { display: inline-flex; }

    /* No Expand on a phone: the leads list is already the whole screen there. Collapse stays, for a
       desktop window narrowed while the table was open. */
    .crm-body:not(.list-expanded) .crm-list-title-row > button { display: none; }

    /* Phone: Customer, Status, Appointment, Last activity, and Expiry stay; the rest drop out. The
       pane is the screen's width here, not the table's (the desktop rule's width:auto would let the
       table push the whole page sideways). */
    .crm-body.list-expanded .crm-list-pane { width: 100%; }
    /* Nor capped to the screen's height: under the header and filters that left room for about four
       rows. The page scrolls instead, like any phone list; the table box only scrolls sideways. */
    .crm-body.list-expanded .crm-list-pane { max-height: none; }
    .lead-table-scroll { flex: none; }
    .lead-table .col-secondary { display: none; }
    .lead-table-customer { white-space: normal; max-width: 130px; }
    .lead-table-shipto { display: block; margin-left: 0; }
    /* The customer column stays put while the rest scroll sideways under it, so you always know whose
       dates you're reading. Needs its own background, or the scrolled cells show through. */
    .lead-table thead th:first-child, .lead-table tbody td:first-child { position: sticky; left: 0; }
    .lead-table thead th:first-child { z-index: 2; }
    .lead-table tbody td:first-child { z-index: 1; background: var(--color-surface); box-shadow: 1px 0 0 var(--color-border); }

    /* The header and the tab row are too narrow for one line each here: the title keeps Collapse
       beside it on its own line, and the filters go under the tabs, two to a line. */
    .crm-body.list-expanded .crm-list-title-row { display: flex; flex: 1 1 100%; }
    .crm-body.list-expanded .crm-list-header .form-row { flex: 1 1 100%; margin-left: 0; }
    .crm-body.list-expanded .crm-list-filters { flex-wrap: wrap; }
    .lead-table-filters { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-left: 0; width: 100%; }
    .lead-table-filters select { width: 100%; min-width: 0; }
    .lead-table-filters .toggle-switch { grid-column: 1 / -1; }

    .crm-summary-grid { grid-template-columns: 1fr; }
    .contact-info-groups { grid-template-columns: 1fr; }

    .order-tile { width: 100%; }
    .invoice-table .col-secondary { display: none; }
    .payment-order-table .col-secondary { display: none; }
    /* table-layout:fixed + a <colgroup> where some <col>s are near-zero width is genuinely buggy in
       Chrome too (not just Safari, as first suspected) — confirmed live via devtools: each visible
       cell's width silently comes from the col N positions *earlier* (N = count of collapsed cols),
       shifting every column's width onto the wrong cell and causing severe overlap. Switching this
       table to table-layout:auto for mobile sidesteps the whole buggy width-list computation — column
       widths are then sized from actual (visible-only) cell content instead, live-verified to render
       correctly with no overlap and no horizontal overflow — PROVIDED the hidden columns are removed
       properly (see below). The percentage hints originally left here turned out NOT to be harmless on
       their own, but the real bug wasn't width:100% itself — it was that `td.col-secondary { display:
       none }` hides the *cells* but leaves their <col> elements in the colgroup. This engine assigns
       each *visible* <td>'s rendered width from the colgroup's <col> list by raw ordinal position, not
       by matching DOM index, and it does NOT skip <col>s whose own cells are display:none. So with 3
       hidden leading columns (select/style/colour), the 4th <td> (Description, first visible cell) was
       silently being sized from the 1st <col> (col-select) instead of its own col-desc, ColourDesc was
       sized from col-style, Qty from col-colour, and so on — every visible column shifted 3 slots early
       — while the real col-desc/col-colourdesc/etc. widths at the *end* of that shifted range went
       completely unclaimed, rendering as blank table width after the last visible cell (Actions), and
       getting worse as the viewport grew. This is the exact same "off-by-N" <col> bug documented above
       for table-layout:fixed, just recurring under auto layout too. The fix is `display: none` on the
       <col> itself (not just its cells) below — that removes it from the ordinal list entirely.
       Confirmed live: once that's in place, width:100% behaves correctly again — leftover space flows
       to Description/ColourDesc (the columns that actually need it) instead of Unit/Line Total, and the
       last visible cell's right edge lands exactly on the table's own right edge. */
    .order-lines-table { table-layout: auto; }
    .order-lines-table td.col-secondary, .order-lines-table th.col-secondary { display: none; }
    .order-lines-table col.col-secondary { display: none; }
    /* Same denser treatment used by .pricelist-table/.order-lookup-table on mobile — the remaining
       columns (Description, Qty, Line Total, etc.) are still narrow even after collapsing the
       secondary ones, so a smaller font + tighter padding buys real headroom before large priced/
       quantity values wrap. */
    .order-lines-table th, .order-lines-table td { font-size: 0.75rem; padding: var(--space-1) var(--space-2); }
    .order-lines-table col.col-desc { width: auto; }
    .order-lines-table col.col-colourdesc { width: auto; }
    .order-lines-table col.col-qty { width: 50px; }
    .order-lines-table col.col-unit { width: 50px; }
    .order-lines-table col.col-linetotal { width: 70px; }
    .order-lines-table col.col-actions { width: 48px; }
    /* Swap to the mobile group-header row (colspan="2", Description+Colour Desc. only — a plain
       colspan spanning the hidden secondary columns pushed the table wider than the viewport,
       confirmed live: 466px vs a 390px window). Its name cell sits at the same position (4) as a
       member row's Description cell, so the accent-bar rules below cover both row types. */
    .order-lines-group-header-desktop { display: none; }
    .order-lines-group-header-mobile { display: table-row; }
    /* Conversion note: hide the desktop in-cell version, show the compact sub-row, and drop the line's
       own bottom border so the sub-row reads as part of that line (divider falls under the note). */
    .order-line-conversion-inline { display: none; }
    .order-line-conversion-row-mobile { display: table-row; }
    .order-lines-table tr.order-line-row-has-conversion td { border-bottom: none; }
    .order-lines-table tr.order-line-row-grouped td:first-child { box-shadow: none; }
    .order-lines-table tr.order-line-row-grouped.group-accent-a td:nth-child(4) {
        box-shadow: inset 3px 0 0 var(--app-accent);
    }
    .order-lines-table tr.order-line-row-grouped.group-accent-b td:nth-child(4) {
        box-shadow: inset 3px 0 0 var(--app-accent-border);
    }
    .order-lines-actions-desktop { display: none; }
    .order-lines-actions-mobile { display: inline-flex; }

    .line-entry-addons-desktop { display: none; }
    .line-entry-addons-mobile { display: flex; }

    .modal-product-picker { width: 100%; }
    .product-picker-browse-desktop { display: none; }
    .product-picker-browse-mobile { display: block; }
    .modal-customer-info { width: 100%; }
    .customer-info-panels { flex-direction: column; }
    .product-picker-results-table .col-secondary { display: none; }
    .stock-check-table .col-secondary { display: none; }
    .pricelist-table .col-secondary { display: none; }

    .pricelist-nav-desktop { display: none; }
    .pricelist-nav-mobile { display: block; }
    .pricelist-body { flex-direction: column; align-items: stretch; min-width: 0; }
    .pricelist-grids { flex-direction: column; align-items: stretch; min-width: 0; }
    .pricelist-grid-main, .pricelist-grid-mouldings { flex: 1 1 auto; width: 100%; max-width: none; min-width: 0; }
    /* Mobile fills (user preference): re-add the min-width the full-view rule drops. */
    .pricelist-grid-main .pricelist-table { min-width: 100%; }
    .pricelist-mobile-tabs { display: block; margin-bottom: var(--space-3); }
    .pricelist-hide-mobile { display: none; }

    .activity-row { flex-direction: column; gap: 2px; }
    .activity-type { width: auto; }

    .document-row { flex-wrap: wrap; }
    .document-actions { width: 100%; justify-content: flex-end; }

    .samplelog-table .col-secondary { display: none; }
    .samplelog-body { flex-direction: column; }
    .samplelog-list-pane, .samplelog-detail-pane { width: 100%; }
    .samplelog-body.has-selection .samplelog-list-pane { display: none; }
    .samplelog-body:not(.has-selection) .samplelog-detail-pane { display: none; }
    .samplelog-body.has-selection .crm-back-btn { display: inline-flex; }

    .order-lookup-table .col-secondary { display: none; }
    .order-lookup-search-grid { grid-template-columns: max-content 1fr; }
    .selected-row-bar { flex-direction: column; align-items: stretch; }

    .admin-users-table .col-secondary { display: none; }
    .admin-reference-body { flex-direction: column; }

    /* Narrow screens: label above the field, since a 10rem label column leaves too little for the input. */
    .admin-form-aligned .form-row { grid-template-columns: 1fr; gap: var(--space-1); }

    .office-dash-table .col-secondary { display: none; }
    .dashboard-filters { flex-direction: column; align-items: stretch; }
}

/* ── Contextual Help ────────────────────────────────────── */
.help-btn {
    background: transparent;
    border: 1px solid rgba(255,255,255,0.25);
    color: rgba(255,255,255,0.75);
    font-family: var(--font);
    font-size: 0.875rem;
    font-weight: 700;
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 50%;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
    flex-shrink: 0;
}
.help-btn:hover { border-color: rgba(255,255,255,0.6); color: #fff; }

.help-task-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.help-task-row {
    text-align: left;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    font-weight: 600;
    color: var(--color-text);
    height: auto;
    transition: border-color 0.15s, background 0.15s;
}
.help-task-row:hover { border-color: var(--app-accent-border); background: var(--app-accent-bg); }

/* Neither brand colour (deep red, dark navy) reads as "look here" on its own — both are muted
   corporate tones already carrying other meaning (red = action/danger, blue = brand emphasis). Help
   mode gets its own dedicated accent instead: a bright, pure yellow (not amber/gold — no orange lean).
   Combined with a slow pulse (motion catches the eye more reliably than colour alone) rather than a
   static outline. */
:root {
    --color-help-accent: #FACC15;
    --color-help-accent-dark: #713F12;
}

@keyframes help-pulse {
    0%, 100% { box-shadow: 0 0 0 4px rgba(250,204,21,0.4); }
    50%      { box-shadow: 0 0 0 9px rgba(250,204,21,0.55); }
}

/* Applied directly to the real target element (table/list/field/button) — no separate positioned
   overlay element, so it just moves with the page naturally on scroll/resize/layout changes. */
.help-highlighted {
    outline: 2px solid var(--color-help-accent);
    outline-offset: 3px;
    border-radius: var(--radius-sm);
    animation: help-pulse 1.8s ease-in-out infinite;
}

/* Rendered inline in normal document flow right before its target — no JS measurement needed. */
.help-chip {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    max-width: 420px;
    background: var(--color-help-accent);
    color: var(--color-help-accent-dark);
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.5;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-2);
    box-shadow: var(--shadow);
}

.help-chip-number {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--color-help-accent-dark);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 700;
}

.help-exit-btn {
    position: fixed;
    z-index: 300;
    bottom: var(--space-6);
    right: var(--space-6);
    background: var(--color-help-accent-dark);
    color: #fff;
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}
.help-exit-btn:hover { background: var(--color-help-accent); color: var(--color-help-accent-dark); }

/* ---------- PayKeeper ---------- */

.paykeeper-home {
    padding: 1.5rem;
    max-width: 68rem;
    margin: 0 auto;
}

.paykeeper-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}

.paykeeper-role-badge {
    background: var(--app-accent);
    color: #fff;
    border-radius: 999px;
    padding: 0.15rem 0.7rem;
    font-size: 0.8rem;
    font-weight: 600;
}

/* Whose record/report this is — the page's subject, sat beside the title. Deliberately NOT the role
   pill: that pill is the app accent and marks the viewer's ROLE, so spending it on a person's name
   made one treatment carry two meanings. Reads as "My Record — Braden Alexanian". */
.paykeeper-header-subject {
    font-size: 1rem;
    color: var(--color-text-muted);
    font-weight: 500;
}
.paykeeper-header-subject::before {
    content: "— ";
}

/* Employee-type badges — see EmployeeTypeBadge.razor for why these colours and not others. Tinted
   rather than solid: this is a fact about the person, so it should sit quieter than the solid
   role pill, which is chrome (the app accent). */
.paykeeper-type-badge {
    border-radius: 999px;
    padding: 0.15rem 0.7rem;
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
}
.paykeeper-type-independent {
    background: var(--color-info-bg);
    color: var(--color-info);
    border: 1px solid var(--color-info-border);
}
.paykeeper-type-franchise {
    background: var(--color-orange-bg);
    color: var(--color-orange);
    border: 1px solid var(--color-orange-border);
}
/* Corporate — legacy's black, i.e. no colour. Plain text so the badges above stay meaningful. */
.paykeeper-type-plain {
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* ── PayKeeper: data-dense pages ─────────────────────────────
   The global cap is .main-content { max-width: 1024px }, which is right for forms and record pages
   but starves a 12-column report. The established way out is OrderWriter's .crm-shell: a full-bleed
   breakout, commented there as being for "a data-dense app view, not a narrow form page". Same
   pattern, reused rather than reinvented.

   ⚠️ Note .paykeeper-home's own max-width:68rem (1088px) and .paykeeper-reference's 84rem (1344px)
   are BOTH INERT — they exceed the 1024px parent cap, so they never applied. Someone had already
   tried to widen Reference Tables and it silently did nothing. This class is what actually works. */
.paykeeper-wide {
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    width: 100vw;
    max-width: 100vw;
    padding-left: var(--space-6);
    padding-right: var(--space-6);
}

/* Denser rows and slightly smaller type, for tables whose job is comparison across many columns.
   Deliberately a modifier, not a change to .summary-table: record and form pages read better roomy,
   and this trades comfort for fitting the whole row on screen. */
.paykeeper-table-compact { font-size: 0.8125rem; }
.paykeeper-table-compact th {
    font-size: 0.625rem;
    padding: var(--space-2) var(--space-3);
}
.paykeeper-table-compact td {
    padding: 6px var(--space-3);
    vertical-align: middle;
}
/* Buttons inside a compact row shouldn't reimpose the global 40px button height. */
.paykeeper-table-compact td .btn-sm { height: 26px; padding: 0 var(--space-3); }

.paykeeper-section {
    margin-bottom: 2rem;
}

.paykeeper-section h3 {
    border-bottom: 1px solid #e5e7eb;
    padding-bottom: 0.35rem;
    margin-bottom: 0.75rem;
    /* Flex so the icon centres on the text rather than sitting on the baseline. */
    display: flex;
    align-items: center;
    gap: 0.45rem;
}

/* Sized in em so the glyph tracks the heading if its font-size ever changes. Muted rather than the
   text colour: it is a landmark, not something to read. */
.paykeeper-section-icon {
    width: 1.15em;
    height: 1.15em;
    flex-shrink: 0;
    color: var(--color-text-muted);
}

/* A section heading with an action button on its right. ⚠️ The h3 must NOT keep its own
   margin-bottom here — as a flex item beside the button it would space the two unevenly — so the ROW
   carries the gap instead. Without it the button sits directly on whatever follows, which is what
   "New Payroll" was doing to the runs table. */
.paykeeper-section-head {
    display: flex;
    flex-wrap: wrap;
    gap: 0.85rem;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--space-4);
}
.paykeeper-section-head h3 { margin: 0; }

.paykeeper-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.75rem;
}

.paykeeper-tile {
    border: 1px solid #e5e7eb;
    border-radius: 0.5rem;
    padding: 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

/* Pending features read as clearly not-yet-built rather than as broken buttons. */
.paykeeper-tile-pending {
    background: #f9fafb;
    color: #9ca3af;
    cursor: not-allowed;
}

/* A built feature. Unlike .paykeeper-tile-pending it is an <a>, so the colour has to be reasserted —
   the app's global link colour would otherwise win and make it the odd one out among the tiles. */
.paykeeper-tile-ready {
    background: #fff;
    color: var(--color-text);
    text-decoration: none;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.paykeeper-tile-ready:hover {
    /* Hover affordance = chrome, so it follows the app accent (blue), not a state colour. Was
       --color-success back when PayKeeper's accent was green. */
    border-color: var(--app-accent);
    box-shadow: var(--shadow-sm);
}

.paykeeper-tile-label {
    font-weight: 600;
}

.paykeeper-tile-phase {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Work waiting behind a tile. Replaces legacy's cmdEmployeeChanges turning yellow
   (Employee_Menu.vb:205-210) — same signal, but a count instead of a colour.

   AMBER, deliberately, per the phase-6 badge rule: this is "something needs you", not an alert.
   It must NOT be the red .paykeeper-alert-badge, which is reserved for something wrong that costs
   the reader, and must not be the accent .paykeeper-current-badge, which means "in force today" — a
   tile permanently wearing a state colour stops reading as a state at all. Sits in the same slot as
   .paykeeper-tile-phase so the tile's layout is identical whether or not there is a count. */
.paykeeper-tile-badge {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

/* ── ShiftKeeper: home shell ─────────────────────────────
   ShiftKeeper is its own app (own route, tile, accent), so it carries its own shell classes rather
   than borrowing PayKeeper's. They deliberately mirror the PayKeeper shell's layout, and all chrome
   colour comes from --app-accent — which .app-shell.app-shiftkeeper rebinds to purple — so nothing
   here names a colour. The two apps' shells can now evolve independently. */
.shiftkeeper-home {
    padding: 1.5rem;
    max-width: 68rem;
    margin: 0 auto;
}
.shiftkeeper-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}
.shiftkeeper-role-badge {
    background: var(--app-accent);
    color: #fff;
    border-radius: 999px;
    padding: 0.15rem 0.7rem;
    font-size: 0.8rem;
    font-weight: 600;
}
.shiftkeeper-section {
    margin-bottom: 2rem;
}
.shiftkeeper-section h3 {
    border-bottom: 1px solid #e5e7eb;
    padding-bottom: 0.35rem;
    margin-bottom: 0.75rem;
    /* Flex so the icon centres on the text rather than sitting on the baseline (mirrors PayKeeper). */
    display: flex;
    align-items: center;
    gap: 0.45rem;
}
/* Sized in em so the glyph tracks the heading; muted — it's a landmark, not something to read. */
.shiftkeeper-section-icon {
    width: 1.15em;
    height: 1.15em;
    flex-shrink: 0;
    color: var(--color-text-muted);
}
.shiftkeeper-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.75rem;
}
.shiftkeeper-tile {
    border: 1px solid #e5e7eb;
    border-radius: 0.5rem;
    padding: 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
/* Pending features read as clearly not-yet-built rather than as broken buttons. */
.shiftkeeper-tile-pending {
    background: #f9fafb;
    color: #9ca3af;
    cursor: not-allowed;
}
/* A built feature — an <a>, so its colour is reasserted against the global link colour. */
.shiftkeeper-tile-ready {
    background: #fff;
    color: var(--color-text);
    text-decoration: none;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.shiftkeeper-tile-ready:hover {
    border-color: var(--app-accent);
    box-shadow: var(--shadow-sm);
}
.shiftkeeper-tile-label { font-weight: 600; }

/* ── ShiftKeeper: My Timeclock (mobile-first) ─────────────
   Decision #4: this is the one PK/SK screen that lives on a phone in someone's hand. Designed
   thumb-first — a narrow single column, a big state-appropriate punch button, generous touch
   targets — not a desktop grid. Accent (purple) comes from --app-accent as everywhere else. */
.shiftkeeper-timeclock {
    max-width: 30rem;
    margin: 0 auto;
    padding: 1rem;
}
.sk-tc-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 1rem;
}
.sk-tc-header h2 { margin: 0; }
.sk-tc-date { color: var(--color-text-muted); font-size: 0.9rem; }

.sk-tc-card {
    border: 1px solid #e5e7eb;
    border-radius: 0.75rem;
    padding: 1.1rem;
    background: #fff;
}
.sk-tc-status { margin-bottom: 1.5rem; }
.sk-tc-store {
    display: block;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    margin-bottom: 0.35rem;
}
.sk-tc-statusline {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 1.15rem;
    margin-bottom: 0.25rem;
}
/* A small live-status dot; green while clocked in. State, so it is a semantic colour, not the accent. */
.sk-tc-dot {
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 50%;
    background: var(--color-success);
    flex-shrink: 0;
}
.sk-tc-flash {
    margin: 0.6rem 0 0;
    font-size: 0.9rem;
    color: var(--color-success);
}

.sk-tc-actions {
    margin-top: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
/* The big primary punch target — full width, tall enough for a thumb. */
.sk-tc-punch {
    width: 100%;
    min-height: 3.5rem;
    border: none;
    border-radius: 0.75rem;
    font-size: 1.15rem;
    font-weight: 700;
    color: #fff;
    cursor: pointer;
    transition: background 0.15s, opacity 0.15s;
}
.sk-tc-punch:disabled { opacity: 0.55; cursor: default; }
/* Punch In = the app accent (the action to take when clocked out). Punch Out = a distinct, calmer
   slate so the two directions never look alike under a thumb, and neither borrows a danger red. */
.sk-tc-punch-in { background: var(--app-accent); }
.sk-tc-punch-in:hover:not(:disabled) { background: var(--app-accent-dark); }
/* A deliberate calm slate for clock-OUT — intentionally NOT var(--app-accent) (that's the punch-IN
   action) and NOT --color-admin* (a raw neutral, decoupled from Admin's accent despite the value match). */
.sk-tc-punch-out { background: #475569; }
.sk-tc-punch-out:hover:not(:disabled) { background: #334155; }
/* The unusual direction — a quiet text button, present but not competing with the primary. */
.sk-tc-punch-alt {
    background: none;
    border: none;
    color: var(--color-text-muted);
    font-size: 0.85rem;
    padding: 0.35rem;
    cursor: pointer;
    text-decoration: underline;
}
.sk-tc-punch-alt:disabled { opacity: 0.5; cursor: default; }

/* Location-request modal fields (enforcement-blocked punch). */
.sk-tc-req-label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    margin: 0.5rem 0 0.3rem;
}
.sk-tc-req-input {
    width: 100%;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--color-border);
    border-radius: 0.5rem;
    font-size: 0.95rem;
    /* Also used for the reason <textarea> — inherit the app font (textareas default to monospace) and
       keep padding inside the width; allow a vertical drag only. */
    font-family: inherit;
    box-sizing: border-box;
    resize: vertical;
}
.sk-tc-req-input:focus { outline: none; border-color: var(--app-accent); box-shadow: 0 0 0 3px var(--app-accent-ring); }
.sk-tc-req-hint { margin: 0.5rem 0 0; font-size: 0.8rem; color: var(--color-text-muted); }

/* The tucked-away "Request my IP be added" link — deliberately quiet, at the top of the blocked screen. */
.sk-tc-request-link {
    display: inline-block;
    margin: 0 0 0.75rem;
    background: none;
    border: none;
    padding: 0;
    color: var(--color-text-muted);
    font-size: 0.8rem;
    text-decoration: underline;
    cursor: pointer;
}
.sk-tc-request-link:hover { color: var(--app-accent); }

/* The "you can't punch from here" notice inside the status card, and a matching card accent. */
.sk-tc-blocked {
    margin: 0.6rem 0 0;
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--color-warning-text, #b45309);
}
.sk-tc-status.is-blocked { border-color: var(--color-warning-border); }

.sk-tc-recent { margin-top: 1.75rem; }
.sk-tc-recent h3 {
    font-size: 0.95rem;
    margin-bottom: 0.6rem;
    padding-bottom: 0.3rem;
    border-bottom: 1px solid #e5e7eb;
}
.sk-tc-day { margin-bottom: 0.9rem; }
.sk-tc-day-label {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    margin-bottom: 0.25rem;
}
.sk-tc-punchrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.45rem 0;
    border-bottom: 1px solid #f1f2f4;
}
.sk-tc-times { font-variant-numeric: tabular-nums; }
.sk-tc-arrow { color: var(--color-text-muted); margin: 0 0.2rem; }
.sk-tc-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
}
.sk-tc-hours { font-variant-numeric: tabular-nums; font-weight: 600; }
.sk-tc-storenum { color: var(--color-text-muted); font-size: 0.8rem; }
.sk-tc-badge {
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    white-space: nowrap;
}
.sk-tc-badge-stat { background: var(--color-info-bg); color: var(--color-info); }
.sk-tc-badge-pending { background: var(--color-warning-bg); color: var(--color-warning); }

/* Muted inline helper — used across the ShiftKeeper/PayKeeper shells for secondary lines. Defined here
   (it had been used but never styled) so those lines actually read as subdued rather than body text. */
.muted-inline { color: var(--color-text-muted); font-size: 0.9rem; }

/* ── ShiftKeeper: IP Allow-List (slice 1b) ────────────────
   An admin surface (desktop-shaped, unlike the mobile timeclock): the enforcement switch, the
   reconciliation "recently seen" table, and the approved / pending lists. Chrome colour is the purple
   --app-accent; state colours are the shared semantic tokens (never the accent). */
.sk-ip {
    padding: 1.5rem;
    max-width: 64rem;
    margin: 0 auto;
}
.sk-ip-header { margin-bottom: 1.25rem; }
.sk-ip-header h2 { margin: 0 0 0.35rem; }
.sk-ip-header .muted-inline { max-width: 46rem; }

.sk-ip-card {
    border: 1px solid #e5e7eb;
    border-radius: 0.75rem;
    padding: 1.1rem 1.25rem;
    background: #fff;
    margin-bottom: 1.25rem;
}
.sk-ip-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}
.sk-ip-section-head h3 { margin: 0; }
.sk-ip-card > h3 { margin: 0 0 0.5rem; }

/* Enforcement panel — a tinted state block so its on/off status reads at a glance. The left edge is
   coloured by state (success-green when on = actively guarding, muted when off). */
.sk-ip-enforce { border-left: 4px solid var(--color-text-subtle); }
.sk-ip-enforce.is-on { border-left-color: var(--color-success); background: var(--color-success-bg); }
.sk-ip-enforce.is-off { border-left-color: var(--color-warning); background: var(--color-warning-bg); }
.sk-ip-enforce-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.sk-ip-enforce-row h3 { margin: 0 0 0.25rem; }
.sk-ip-enforce-state {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9rem;
    flex-wrap: wrap;
}
.sk-ip-enforce-hint {
    margin: 0.9rem 0 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    border-top: 1px dashed var(--color-warning-border);
    padding-top: 0.7rem;
}

/* Per-store enforcement exemption list. */
.sk-ip-store-hint { margin: 0 0 0.85rem; font-size: 0.85rem; color: var(--color-text-muted); }
.sk-ip-store-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 0.3rem 1rem;
}
.sk-ip-store-toggle {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.35rem 0.5rem;
    border-radius: 0.375rem;
    cursor: pointer;
    border: 1px solid transparent;
}
.sk-ip-store-toggle:hover { background: rgba(109, 63, 163, 0.05); }
.sk-ip-store-toggle input { cursor: pointer; }
.sk-ip-store-label { flex: 1; font-size: 0.9rem; }
.sk-ip-store-state {
    font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--color-success);
}
/* An exempt store stands out so the exceptions are obvious at a glance. */
.sk-ip-store-toggle.is-exempt {
    background: var(--color-warning-bg, #fef3c7);
    border-color: var(--color-warning-border);
}
.sk-ip-store-toggle.is-exempt .sk-ip-store-state { color: var(--color-warning-text, #b45309); }

.sk-ip-table-scroll { overflow-x: auto; }
.sk-ip-table { width: 100%; }
.sk-ip-mono { font-variant-numeric: tabular-nums; font-family: ui-monospace, "Cascadia Code", monospace; }
.sk-ip-name-input {
    width: 100%;
    max-width: 20rem;
    padding: 0.35rem 0.55rem;
    border: 1px solid var(--color-border);
    border-radius: 0.375rem;
    font-size: 0.9rem;
}
.sk-ip-name-input:focus { outline: none; border-color: var(--app-accent); box-shadow: 0 0 0 3px var(--app-accent-ring); }
/* Applied directly to <td> cells, so it must NOT set display: flex — that pulls the cell out of the
   table row and detaches it (and the row's background tint) from the rest of the row. The buttons are
   inline-block; keep them on one line and space them, right-aligned via the cell's .align-right. */
.sk-ip-actions { white-space: nowrap; }
.sk-ip-actions button { vertical-align: middle; }
.sk-ip-actions button + button { margin-left: 0.4rem; }
/* An unknown observed IP is the thing to act on — a faint warning tint draws the eye without shouting. */
.sk-ip-row-unknown td { background: var(--color-warning-bg); }
/* Pending requests sit inside the Approved view; a soft info tint sets them apart from the settled list. */
.sk-ip-pending { border-left: 4px solid var(--color-info); }

.sk-ip-badge {
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    white-space: nowrap;
}
.sk-ip-badge-on, .sk-ip-badge-approved { background: var(--color-success-bg); color: var(--color-success); }
.sk-ip-badge-off, .sk-ip-badge-unknown { background: var(--color-warning-bg); color: var(--color-warning); }
.sk-ip-badge-pending { background: var(--color-info-bg); color: var(--color-info); }

/* Per-IP punches drill-down modal — wider than the default message modal, with its own scroll so a
   busy IP's list scrolls inside the dialog rather than the page. */
.sk-ip-punches-modal {
    width: min(46rem, 94vw);
    max-width: 94vw;
    max-height: 82vh;
    display: flex;
    flex-direction: column;
}
/* "Approve location" name prompt. */
.sk-ip-approve-modal { width: min(26rem, 94vw); }
.sk-ip-approve-label { display: block; margin: 0.85rem 0 0.3rem; font-size: 0.85rem; font-weight: 600; }
.sk-ip-approve-modal .sk-ip-name-input { max-width: none; }
.sk-ip-punches-modal .sk-ip-section-head { margin-bottom: 0.25rem; }
.sk-ip-punches-scroll { overflow: auto; margin-top: 0.5rem; }
/* Small "in"/"out" tag when the IP was only on one end of a punch record. */
.sk-ip-dir {
    margin-left: 0.4rem;
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    background: #f1f5f9;
    padding: 0.05rem 0.35rem;
    border-radius: 0.25rem;
}

/* ── ShiftKeeper: Timecard Approval + Correction (Phase 2) ─
   One editable grid, two loads (unapproved queue / one employee). Desktop-shaped; the grid scrolls
   horizontally on a phone. Chrome from --app-accent (purple). */
.sk-tm {
    padding: 1.5rem;
    max-width: 76rem;
    margin: 0 auto;
}
.sk-tm-header { margin-bottom: 1.25rem; }
.sk-tm-header h2 { margin: 0 0 0.35rem; }
.sk-tm-header .muted-inline { max-width: 48rem; }
.sk-tm-card {
    border: 1px solid #e5e7eb;
    border-radius: 0.75rem;
    padding: 1.1rem 1.25rem;
    background: #fff;
    margin-bottom: 1.25rem;
}

/* Scope bar: the needs-approval toggle + employee search. */
.sk-tm-scope-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.sk-tm-search { position: relative; flex: 1; min-width: 15rem; }
.sk-tm-search > input {
    width: 100%;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: 0.375rem;
    font-size: 0.9rem;
}
.sk-tm-search > input:focus { outline: none; border-color: var(--app-accent); box-shadow: 0 0 0 3px var(--app-accent-ring); }
/* Search results float over the content below — an absolute dropdown, not a layout push. */
.sk-tm-search-list {
    position: absolute;
    z-index: 20;
    top: calc(100% + 0.25rem);
    left: 0; right: 0;
    margin: 0; padding: 0.25rem;
    list-style: none;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: 0.5rem;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    max-height: 18rem;
    overflow: auto;
}
.sk-tm-search-list button {
    width: 100%;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.4rem 0.5rem;
    background: none;
    border: none;
    border-radius: 0.375rem;
    text-align: left;
    cursor: pointer;
    font-size: 0.9rem;
}
.sk-tm-search-list button:hover { background: var(--app-accent-ring); }
.sk-tm-search-store { color: var(--color-text-muted); font-size: 0.8rem; white-space: nowrap; }
.sk-tm-emp-tag { font-size: 0.9rem; color: var(--color-text-muted); }
.sk-tm-emp-tag strong { color: var(--color-text); }

/* Period bar. */
.sk-tm-period { display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap; }
.sk-tm-period-steps { display: flex; gap: 0.4rem; }
.sk-tm-period-dates { display: flex; gap: 1rem; flex-wrap: wrap; }
.sk-tm-period-dates label {
    display: flex; align-items: center; gap: 0.4rem;
    font-size: 0.85rem; color: var(--color-text-muted);
}
.sk-tm-period-dates input {
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--color-border);
    border-radius: 0.375rem;
    font-size: 0.9rem;
}

/* Store filter — a compact dropdown living in the period bar (unapproved view). */
.sk-tm-storedd { position: relative; }
.sk-tm-caret { font-size: 0.7rem; }
.sk-tm-storedd-panel {
    position: absolute;
    z-index: 20;
    top: calc(100% + 0.3rem);
    left: 0;
    min-width: 14rem;
    max-height: 20rem;
    overflow: auto;
    padding: 0.5rem 0.6rem;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: 0.5rem;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.sk-tm-storedd-actions {
    display: flex; align-items: center; gap: 0.4rem;
    font-size: 0.8rem; color: var(--color-text-muted);
    padding-bottom: 0.35rem; margin-bottom: 0.15rem;
    border-bottom: 1px solid var(--color-border);
}
.sk-tm-linkbtn {
    background: none; border: none; padding: 0; cursor: pointer;
    color: var(--app-accent); font-size: 0.8rem;
}
.sk-tm-linkbtn:hover { text-decoration: underline; }
.sk-tm-filter-chip { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; white-space: nowrap; }
.sk-tm-emp-tag { font-size: 0.9rem; color: var(--color-text-muted); }
.sk-tm-emp-tag strong { color: var(--color-text); }

/* Action bar. */
.sk-tm-actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1rem; }
.sk-tm-flash { font-size: 0.85rem; color: var(--color-text-muted); }
.sk-tm-error-summary { margin: -0.25rem 0 1rem; font-size: 0.85rem; color: var(--color-warning); }

/* The grid. */
.sk-tm-table-scroll { overflow-x: auto; }
.sk-tm-table { width: 100%; }
.sk-tm-mono { font-variant-numeric: tabular-nums; }
.sk-tm-table input[type="date"], .sk-tm-table input[type="time"], .sk-tm-table select {
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--color-border);
    border-radius: 0.375rem;
    font-size: 0.85rem;
    background: #fff;
    /* Fill the cell instead of forcing an intrinsic width — so a row switched into edit mode stays within
       the column widths the display rows set, rather than pushing the table wider and overflowing. */
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    /* Uniform height + font: a global 40px input rule was hitting date/select but not input[type=time],
       which fell back to ~30px and, on its own, to a monospace font — so the four boxes didn't match. Pin
       them all so the row reads as one set of controls. */
    height: 2rem;
    line-height: normal;
    font-family: inherit;
    vertical-align: middle;
}
/* A display row is one click away from editing — show it. Locked/editing rows aren't clickable. */
.sk-tm-row-clickable { cursor: pointer; }
.sk-tm-row-clickable:hover td { background: rgba(109, 63, 163, 0.05); }
/* The single selected (editing) row gets a faint tint so it reads as active, and its cells centre
   vertically so the inputs line up with the read-only employee/hours text (the table is top-aligned). */
.sk-tm-row-editing td { background: rgba(109, 63, 163, 0.06); vertical-align: middle; }
/* A row with a pending (unsaved) correction that's collapsed back to read-only — a left accent flags it
   until Save. (Skipped when the row also has an error, whose danger accent takes that column.) */
.sk-tm-row-dirty td:first-child { box-shadow: inset 3px 0 0 var(--app-accent); }

/* This is a dense, many-column grid (9 columns incl. the "Where" location, native date/time/select
   controls with hard minimum widths). The default 16px cell padding overflowed; tightened to 4px each
   side so an editing row — X and all — fits on a narrower window without a horizontal scrollbar. */
.sk-tm-table th, .sk-tm-table td {
    padding-left: var(--space-1);
    padding-right: var(--space-1);
}
.sk-tm-table input:focus, .sk-tm-table select:focus {
    outline: none; border-color: var(--app-accent); box-shadow: 0 0 0 2px var(--app-accent-ring);
}
/* An invalid row is tinted red with a solid left accent, and its message row carries the reason. */
.sk-tm-row-error td { background: rgba(220,38,38,0.07); }
.sk-tm-row-error td:first-child { box-shadow: inset 3px 0 0 var(--color-danger); }
.sk-tm-row-errmsg td { padding-top: 0; color: var(--color-danger); font-size: 0.8rem; font-weight: 500; border-top: none; }
.sk-tm-rowactions { white-space: nowrap; }
.sk-tm-rowactions button { vertical-align: middle; }
.sk-tm-rowactions button + button { margin-left: 0.35rem; }
.sk-tm-del {
    background: none; border: none; cursor: pointer;
    color: var(--color-text-muted); padding: 0.2rem 0.3rem; font-size: 1rem; line-height: 1;
}
.sk-tm-del:hover:not(:disabled) { color: var(--color-danger); }
.sk-tm-edit {
    background: none; border: none; cursor: pointer;
    color: var(--color-text-muted); padding: 0.2rem 0.3rem; font-size: 1rem; line-height: 1;
}
.sk-tm-edit:hover:not(:disabled) { color: var(--app-accent); }
.sk-tm-lock { color: var(--color-text-muted); }

/* Read-only "Where" (resolved punch location). Muted, and CAPPED so a long value — chiefly the
   "In: … · Out: …" two-IP case — can't stretch the column and push the grid into a horizontal scroll.
   Store names fit; anything longer ellipsizes, with the full raw IP(s) in the title tooltip. */
.sk-tm-loc {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    max-width: 7rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sk-tm-badge {
    font-size: 0.7rem; font-weight: 600;
    padding: 0.1rem 0.5rem; border-radius: 999px; white-space: nowrap;
}
.sk-tm-badge-approved { background: var(--color-success-bg); color: var(--color-success); }
.sk-tm-badge-pending { background: var(--color-warning-bg); color: var(--color-warning); }
.sk-tm-badge-stat { background: var(--color-info-bg); color: var(--color-info); margin-right: 0.3rem; }

/* Notify-managers result modal. */
.sk-tm-notify-modal { width: min(38rem, 94vw); max-width: 94vw; max-height: 82vh; overflow: auto; }
.sk-tm-notify-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.5rem; }
.sk-tm-notify-head h3 { margin: 0; }

/* ── ShiftKeeper: View Store Schedule (slice 1c) ──────────
   Read-only week view — an employees × 7-day matrix (the same shape as the PDF). Desktop-shaped;
   scrolls horizontally on a phone rather than wrapping. Chrome from --app-accent (purple). */
.sk-sch {
    padding: 1.5rem;
    max-width: 72rem;
    margin: 0 auto;
}
.sk-sch-card {
    border: 1px solid #e5e7eb;
    border-radius: 0.75rem;
    padding: 1.1rem 1.25rem;
    background: #fff;
    margin-bottom: 1.25rem;
}
.sk-sch-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.sk-sch-header h2 { margin: 0; }
/* Store picker + Export button share one right-aligned row with a gap between them, instead of the button
   dropping onto a second line tucked under the dropdown's left edge (the wrapper was display:block).
   nowrap keeps them side by side; the whole header still wraps as a unit on a narrow screen. */
.sk-sch-controls {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    justify-content: flex-end;
    gap: 0.75rem;
}
.sk-sch-controls .sk-sch-store { flex: 0 1 auto; }
/* Don't let the Export button be squeezed or wrapped — it keeps its size on the right. */
.sk-sch-controls > button { flex: none; }
.sk-sch-store {
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: 0.5rem;
    font-size: 0.9rem;
    background: #fff;
    min-width: 12rem;
}

.sk-sch-weeknav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.85rem;
}
.sk-sch-weeklabel {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    text-align: center;
}
.sk-sch-thisweek {
    background: none;
    border: none;
    color: var(--app-accent);
    font-size: 0.75rem;
    cursor: pointer;
    text-decoration: underline;
    padding: 0;
}
.sk-sch-thisweek:disabled { opacity: 0.5; cursor: default; }

.sk-sch-effective {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    margin-bottom: 0.85rem;
}
.sk-sch-rotation {
    margin-left: 0.75rem;
    font-weight: 600;
    color: var(--app-accent);
}

/* The view switch sits above the schedule; nudge it tight to the table/timeline below. */
.sk-sch-viewswitch { margin-bottom: 0.6rem; }

/* Read-only timeline reuses Manage's inner .sk-mg-* bar/axis classes for an identical look, but needs its
   own scroll wrapper: Manage's .sk-mg-timeline-scroll is hidden under 760px by a media query (its mobile
   auto-fallback to the matrix). Here the switch chooses the view, so the timeline must stay visible at any
   width and simply scroll horizontally on a phone. */
.sk-sch-timeline-scroll {
    overflow-x: auto;
    border: 1px solid #e5e7eb;
    border-radius: 0.75rem;
    background: #fff;
}

.sk-sch-table-scroll { overflow-x: auto; }
.sk-sch-table { width: 100%; min-width: 44rem; }
.sk-sch-table th, .sk-sch-table td { vertical-align: top; }
.sk-sch-empcol { min-width: 9rem; }
.sk-sch-daycol { text-align: center; white-space: nowrap; }
.sk-sch-hrscol { min-width: 3rem; }
.sk-sch-emp { font-weight: 600; white-space: nowrap; }
/* Per-employee colour chip — identity across the week, so a semantic-free palette colour, not the accent. */
.sk-sch-dot {
    display: inline-block;
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 50%;
    margin-right: 0.5rem;
    vertical-align: middle;
}
/* Shift cells: centred, tabular, and pre-line so a day's multiple shifts stack on their own lines. */
.sk-sch-cell {
    text-align: center;
    white-space: pre-line;
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
}
.sk-sch-hrs { font-variant-numeric: tabular-nums; font-weight: 600; }
.sk-sch-export-error {
    margin: 0.5rem 0 0;
    font-size: 0.85rem;
    color: var(--color-danger, #b91c1c);
}

/* ── ShiftKeeper: Manage Store Schedule (Phase 3) ─────────
   The template editor. Reframes legacy ScheduleForm's pixel Gantt into a CSS timeline: seven stacked
   day rows sharing a 9am–9pm (auto-widening) axis, shifts as absolutely-positioned colour bars, greedy
   lane-packed. A matrix fallback shows on narrow screens. Bar colours are the per-employee palette
   (identity, semantic-free) — never the accent; chrome (selects, focus) comes from --app-accent. */
.sk-mg {
    /* Full-bleed breakout of .main-content's centred 1024px cap (same technique as .crm-shell) — this is a
       data-heavy timeline where every extra pixel of width is more schedule on screen and less vertical
       pressure, so it spans the full viewport rather than a centred reading column. */
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    width: 100vw;
    padding: 1.25rem var(--space-6);
}
.sk-mg-card {
    border: 1px solid #e5e7eb;
    border-radius: 0.75rem;
    padding: 1.1rem 1.25rem;
    background: #fff;
    margin-bottom: 1.25rem;
}
.sk-mg-header { margin-bottom: 1rem; }
.sk-mg-header h2 { margin: 0 0 0.75rem; }
.sk-mg-controls { display: flex; gap: 1.25rem; flex-wrap: wrap; align-items: flex-end; }
.sk-mg-ctl { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.8rem; color: var(--color-text-muted); }
.sk-mg-select {
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: 0.5rem;
    font-size: 0.9rem;
    background: #fff;
    min-width: 14rem;
}
.sk-mg-select:focus { outline: none; border-color: var(--app-accent); box-shadow: 0 0 0 3px var(--app-accent-ring); }
.sk-mg-empty-inline { font-size: 0.9rem; color: var(--color-text-muted); padding: 0.4rem 0; }

.sk-mg-effective { font-size: 0.85rem; color: var(--color-text-muted); margin-bottom: 0.85rem; }
.sk-mg-rot { margin-left: 0.75rem; font-weight: 600; color: var(--app-accent); }

/* Timeline */
.sk-mg-timeline-scroll { overflow-x: auto; border: 1px solid #e5e7eb; border-radius: 0.75rem; background: #fff; }
.sk-mg-timeline { padding: 0; }
.sk-mg-axis { display: flex; border-bottom: 1px solid #ececf1; position: sticky; top: 0; z-index: 5; }
.sk-mg-axis-track { height: 22px; background: #f8f8fa; }
/* The corner pins in BOTH directions (its own sticky-left + the axis's sticky-top), so it must sit above
   the other sticky day-labels. */
.sk-mg-axis-corner { background: #f2f2f6; z-index: 6; }
.sk-mg-dayrow { display: flex; border-top: 1px solid #f0f0f3; }
.sk-mg-dayrow:first-of-type { border-top: none; }
.sk-mg-daylabel {
    flex: 0 0 140px;
    width: 140px;
    padding: 0.5rem 0.75rem;
    background: #f7f7fb;
    border-right: 1px solid #ececf1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.1rem;
    /* Stay pinned to the left while the timeline scrolls horizontally, so the day name is always visible. */
    position: sticky;
    left: 0;
    z-index: 3;
}
.sk-mg-dayname { font-weight: 700; font-size: 0.9rem; color: #2a2a2a; }
.sk-mg-daystat { font-size: 0.72rem; color: var(--color-text-muted); font-style: italic; }
.sk-mg-track { position: relative; flex: 1 1 auto; min-height: 46px; background: #fff; }
.sk-mg-tick {
    position: absolute; top: 0; transform: translateX(-1px);
    font-size: 0.68rem; color: #9a9a9a; padding-left: 3px;
    border-left: 1px solid #ededf1; height: 22px; line-height: 22px;
}
.sk-mg-gridline { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px solid #f2f2f5; }
.sk-mg-bar {
    position: absolute;
    height: 30px;
    border-radius: 4px;
    color: #fff;
    display: flex;
    align-items: center;
    padding: 0 6px;
    overflow: hidden;
    box-shadow: inset 0 0 0 1px rgba(0,0,0,0.08);
}
.sk-mg-bar-text {
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-shadow: 0 1px 1px rgba(0,0,0,0.25);
}

/* Matrix fallback (narrow screens) */
.sk-mg-matrix-scroll { display: none; overflow-x: auto; }
.sk-mg-matrix { width: 100%; min-width: 40rem; margin-top: 0.5rem; }
.sk-mg-matrix th, .sk-mg-matrix td { vertical-align: top; }
.sk-mg-mx-empcol { min-width: 9rem; }
.sk-mg-mx-daycol { text-align: center; }
.sk-mg-mx-emp { font-weight: 600; white-space: nowrap; }
.sk-mg-mx-cell { text-align: center; white-space: pre-line; font-variant-numeric: tabular-nums; font-size: 0.82rem; }

@media (max-width: 760px) {
    .sk-mg-timeline-scroll { display: none; }
    .sk-mg-matrix-scroll { display: block; }
}

/* Legend */
.sk-mg-legend { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
.sk-mg-chip {
    display: inline-flex; align-items: center;
    border: 1px solid #e5e7eb; border-radius: 0.5rem;
    padding: 0.3rem 0.6rem; font-size: 0.82rem; background: #fff;
}
.sk-mg-chip-hrs { color: var(--color-text-muted); margin-left: 0.35rem; }
.sk-mg-chip-orphan { border-style: dashed; opacity: 0.75; }
.sk-mg-dot {
    display: inline-block; width: 0.7rem; height: 0.7rem;
    border-radius: 50%; margin-right: 0.5rem; vertical-align: middle;
}

/* Editor chrome */
.sk-mg-editbar { display: flex; gap: 0.5rem; align-items: flex-end; }
.sk-mg-saveerror { margin-top: 0.5rem; font-size: 0.85rem; color: var(--color-danger, #b91c1c); }
.sk-mg-hint { margin-left: 0.6rem; font-style: italic; color: var(--color-text-muted); }
.sk-mg-daybtns { display: flex; gap: 0.3rem; margin-top: 0.3rem; }
/* Compact icon buttons (copy / paste) — small so the day-label row stays short. */
.sk-mg-iconbtn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 22px; padding: 0;
    background: none; border: 1px solid #d7d7dd; border-radius: 0.35rem;
    color: var(--color-text-muted); cursor: pointer;
}
.sk-mg-iconbtn:hover { border-color: var(--app-accent); color: var(--app-accent); background: var(--app-accent-ring); }
.sk-mg-iconbtn svg { display: block; }
.sk-mg-newbadge {
    display: inline-block; background: var(--app-accent); color: #fff;
    font-size: 0.72rem; font-weight: 600; border-radius: 0.35rem;
    padding: 0.05rem 0.4rem; margin-right: 0.5rem;
}
.sk-mg-radio { display: block; font-size: 0.88rem; margin: 0.15rem 0; cursor: pointer; }
.sk-mg-radio input { margin-right: 0.4rem; }
.sk-mg-track-edit { cursor: copy; }
.sk-mg-bar-edit { cursor: pointer; }
.sk-mg-bar-edit:hover { box-shadow: inset 0 0 0 2px rgba(255,255,255,0.9); }
.sk-mg-mx-cell-edit { cursor: pointer; }
.sk-mg-mx-cell-edit:hover { background: var(--app-accent-ring); }

/* Shift modal */
.sk-mg-modal { max-width: 420px; }
.sk-mg-field { display: flex; flex-direction: column; gap: 0.25rem; margin-bottom: 0.8rem; }
.sk-mg-field label { font-size: 0.78rem; color: var(--color-text-muted); font-weight: 600; }
.sk-mg-field-row { display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap; margin-bottom: 0.4rem; }
.sk-mg-field-row .sk-mg-field { margin-bottom: 0.4rem; }
.sk-mg-select-narrow { min-width: 8rem; }
.sk-mg-duration { font-size: 0.8rem; color: var(--color-text-muted); padding-bottom: 0.5rem; }
.sk-mg-modal-error {
    font-size: 0.83rem; color: var(--color-danger, #b91c1c);
    background: var(--color-danger-bg, #fef2f2); border: 1px solid var(--color-danger-border, #fecaca);
    border-radius: 0.4rem; padding: 0.4rem 0.6rem; margin-top: 0.3rem;
}
.sk-mg-modal-warn { font-size: 0.85rem; color: var(--color-warning, #92400e); margin: 0; }
.sk-mg-modal-del { margin-right: auto; }   /* push Delete to the far left of the actions row */

/* Group chooser */
.sk-mg-group { max-width: 440px; }
.sk-mg-grouplist { list-style: none; padding: 0; margin: 0.5rem 0; }
.sk-mg-grouplist li { display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0; border-top: 1px solid #f0f0f3; }
.sk-mg-groupname { font-weight: 600; }
.sk-mg-groupweek { font-size: 0.78rem; color: var(--color-text-muted); }
.sk-mg-groupactions { margin-left: auto; display: flex; gap: 0.4rem; }

/* ── PayKeeper: employee record (read-only) ─────────────── */

/* Tabs need NO PayKeeper rule any more. The shared .tab-active follows --app-accent, which
   .app-shell.app-paykeeper rebinds (to blue) — this used to be a selector-level override, and the
   fact that it existed while every btn-primary stayed red is exactly why the variable replaced it. */

/* ⚠️ Was `grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr))`, which made every section an
   EQUAL-WIDTH column regardless of what was in it. Work Information carries both the longest labels
   ("Compufloor salesperson") and the longest values (work email), so it was the one that wrapped —
   while Personal Information sat in an identically-sized column with room to spare.
   Flex instead: each section takes the width its content needs and wraps to a new row when there
   isn't room, so a long value costs that section width rather than forcing a line break. */
.paykeeper-record-groups {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem 2.5rem;
    align-items: flex-start;
}

.paykeeper-record-group {
    flex: 0 1 auto;
    /* Caps a section with one unusually long value from crowding out its neighbours entirely — it
       wraps to its own row instead. */
    max-width: min(100%, 34rem);
}

.paykeeper-record-group h4 {
    text-transform: uppercase;
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
    margin-bottom: 0.5rem;
}

/* Two columns of label/value. Labels sized to the content rather than a fixed width so a long label
   doesn't force its value off the grid on a narrow viewport. */
/* Both columns size to content now that the section itself does. With `1fr` the value column absorbed
   whatever the equal-width grid handed it, which is how a work email ended up wrapping inside a
   section that had no say in its own width. */
.paykeeper-field-list {
    display: grid;
    grid-template-columns: auto auto;
    gap: 0.35rem 1rem;
    margin: 0;
    justify-content: start;
}
.paykeeper-field-list dt {
    color: var(--color-text-muted);
    font-size: 0.875rem;
    white-space: nowrap;
}
.paykeeper-field-list dd {
    margin: 0;
    font-size: 0.875rem;
    overflow-wrap: anywhere;
}
.paykeeper-field-list dd.paykeeper-field-empty { color: var(--color-text-subtle); }

.paykeeper-record-table .num { text-align: right; }

/* Payline edit grid: the inline <select>/<input> controls otherwise render at the browser-default
   (~16px) font — larger than the table's own text — which widens every column and forces a horizontal
   scrollbar in edit mode. Match the table font and tighten padding so the editable rows stay as narrow
   as the read-only view. */
.paykeeper-record-table .form-control {
    font: inherit;
    padding: 0.2rem 0.35rem;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
}

/* ⚠️ Do NOT let these tables compress to fit. Measured at 375px: the wrapper already scrolled
   (overflow-x:auto) but the table squeezed itself into 620px anyway, wrapping every cell — "Apr 7,
   2026" over 5 lines, rows 108px instead of 21px. The columns are all things someone checking their
   own pay record needs, so hiding or narrowing them isn't an option; the right trade is to keep every
   cell on one line, let the table be as wide as it needs, and scroll it inside .admin-table-scroll.
   Vertical space is the scarcer resource on a phone. */
.paykeeper-record-table { width: max-content; min-width: 100%; }
.paykeeper-record-table th,
.paykeeper-record-table td { white-space: nowrap; }

/* ⚠️ A sticky first column was tried here and REMOVED (user, phase 6). It assumed column 1 is the
   row's identity, which held on the record tabs but broke on the commission report — the widest table
   in PayKeeper and the one that most needs it — where column 1 is the store number, so it pinned "40"
   and nothing useful. Rather than special-case per table, the width is fixed properly below: dense
   pages break out of the 1024px cap and use a compact table, so there is far less to scroll past. */

/* A fact about the row that carries no in-force/status meaning (e.g. "off-cycle"). Distinct from the
   accent .paykeeper-current-badge, which specifically means "this is the row in force today". */
/* Something on this row needs attention and is COSTING the reader something — used for a timecard
   whose punch is missing or reversed, whose hours are therefore excluded from the period total. */
.paykeeper-alert-badge {
    display: inline-block;
    margin-left: 0.4rem;
    margin-right: 0.4rem;
    background: var(--color-danger-bg);
    border: 1px solid var(--color-danger-border);
    color: var(--color-danger);
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
    font-size: 0.7rem;
    font-weight: 700;
}

/* margin-right too: a badge is often followed by plain status text in the same cell, which otherwise
   butts straight against it and reads as one word ("statunapproved"). */
.paykeeper-neutral-badge {
    display: inline-block;
    margin-left: 0.4rem;
    margin-right: 0.4rem;
    background: var(--color-surface-alt, #f3f4f6);
    border: 1px solid #e5e7eb;
    color: var(--color-text-muted);
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
    font-size: 0.7rem;
    font-weight: 600;
}

/* Tabular figures so a revealed SIN or account doesn't reflow the row as it swaps in, and the digits
   stay countable — these get read aloud and typed into bank forms. */
.paykeeper-sensitive {
    font-variant-numeric: tabular-nums;
    font-family: var(--font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
}

/* Styled as a text link, but it IS a <button>, and the global button rule sets height:40px +
   inline-flex. Without resetting that, this 12px link became a 40px-tall box inside a 21px field row:
   it forced the SIN row to nearly double height and pushed the value 11px below its own "SIN" label,
   which read as the value being misaligned. Reset the box back to inline text. */
.paykeeper-reveal-btn {
    background: none;
    border: none;
    padding: 0 0 0 0.5rem;
    height: auto;
    display: inline;
    line-height: inherit;
    vertical-align: baseline;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--app-accent);
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.paykeeper-reveal-btn:hover { text-decoration: underline; }

.paykeeper-reveal-bar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.5rem;
}

/* These tables are change logs, so several rows are historical and only one is in force. Tint the
   live row: without it the reader has to work out which row applies today from the dates, and
   future-dated rows sort above the current one. Uses the accent SELECTION tint (--app-accent-bg),
   not a semantic colour — "the row in force" is an active-selection state, the same family as an
   active tab or nav item, so it wears the app's identity rather than a green that read as "success". */
.paykeeper-row-current { background: var(--app-accent-bg); }

/* A negative money figure in a report table (guarantee true-up: a month/accumulated shortfall).
   Uses the brand red as a read-only signal, not the alert --color-danger, since nothing is wrong —
   it just marks a number below zero. */
.paykeeper-negative { color: var(--color-danger); }

/* ⚠️ A TINTED PILL, not a solid fill — a state is tinted; a solid fill reads as an ACTION (a button).
   Its siblings (.paykeeper-alert-badge, .paykeeper-neutral-badge) are tinted too. Uses the accent
   SELECTION tint (--app-accent-bg/-border), NOT the semantic success green (user, 2026-07-27):
   "in force today" is an active-selection state — the same family as an active tab/nav item — so it
   wears the app's identity. The tint (not a solid fill) still keeps it reading as a state, not an
   action, so the badge policy holds. */
.paykeeper-current-badge {
    background: var(--app-accent-bg);
    border: 1px solid var(--app-accent-border);
    color: var(--app-accent-dark);
    border-radius: 999px;
    padding: 0.05rem 0.45rem;
    margin-left: 0.4rem;
    font-size: 0.7rem;
    font-weight: 600;
}

/* The commission report's date range and period buttons. Wraps rather than scrolls: this screen is
   opened on a phone by salespeople on the floor, and a horizontally-scrolled control bar hides the
   Load button that makes the rest of it work. */
.paykeeper-commission-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.5rem;
}

.paykeeper-commission-controls label {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

.paykeeper-commission-controls input {
    width: auto;
    min-width: 9rem;
}

.admin-inline-warning {
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: 0.4rem;
    padding: 0.6rem 0.75rem;
    margin: 0.5rem 0;
    font-size: 0.85rem;
    color: #78350f;
}

/* Same shape as .admin-inline-warning but neutral, for explaining an expected state rather than
   flagging a problem. The terminated-record notice is the case it was added for: amber read as
   "something is wrong with this record" when the message is simply telling you why it is still here. */
/* Lets a problem list show EVERY entry without running the page off the screen. The alternative —
   capping with .Take(n) — silently understates how much is wrong, so the reader fixes what they can
   see and meets the next batch on re-import. Bound the height, never the list. */
.paykeeper-issue-list {
    margin: 0.25rem 0 0 1rem;
    max-height: 12rem;
    overflow-y: auto;
}

.paykeeper-inline-note {
    background: var(--color-surface-alt, #f9fafb);
    border: 1px solid #e5e7eb;
    border-radius: 0.4rem;
    padding: 0.6rem 0.75rem;
    margin: 0.5rem 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* The "‹ PayKeeper" back button sits immediately above a page header on every PayKeeper subpage and
   was butting straight into the title. One rule here rather than a class on all 13 pages. */
.paykeeper-home > button:first-child { margin-bottom: 1rem; }

/* ── PayKeeper: Employees browse (phase 2a) ─────────────── */

/* ⚠️ This page used to carry `max-width: 82rem`, which was INERT — .main-content caps everything at
   1024px, so the widest, densest screen in PayKeeper was silently rendering at 64rem with a 20rem
   list eating a third of it. Third instance of that trap (after .paykeeper-home and
   .paykeeper-reference). The fix is .paykeeper-wide on the page element, never a max-width. */

.paykeeper-browse {
    display: flex;
    gap: 1.5rem;
    align-items: flex-start;
}

/* The Record/History switch. ⚠️ This MUST NOT look like the tab strip it sits above — that visual
   difference is the entire mechanism keeping the two levels legible. A segmented button group reads
   as a mode switch; underlined tabs read as siblings. If these ever converge, the nested-tabs problem
   is back regardless of what the markup says. */
.paykeeper-group-switch {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    margin-bottom: 0.75rem;
    background: #f1f5f9;
    border-radius: 0.5rem;
}

.paykeeper-group-switch button {
    /* Resets the global 40px button. */
    height: auto;
    padding: 0.3rem 0.9rem;
    border: none;
    border-radius: 0.375rem;
    background: none;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
}
.paykeeper-group-switch button:hover { color: var(--color-text); }
.paykeeper-group-switch button.selected {
    background: var(--color-surface);
    color: var(--app-accent);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}

/* ⚠️ At ALL widths, not just on a phone. The Record group is 8 tabs spanning ~819px; the content pane
   is 873px at 1280 viewport, so anything under ~1226px would WRAP them onto a second row — and a
   wrapped tab row reads as two rows of peers, which is precisely the confusion this layout exists to
   remove. Scroll sideways instead. */
.paykeeper-browse-detail .paykeeper-tabs {
    overflow-x: auto;
    flex-wrap: nowrap;
}
.paykeeper-browse-detail .paykeeper-tabs button { white-space: nowrap; }

.paykeeper-browse-list {
    width: 20rem;
    flex-shrink: 0;
    border: 1px solid #e5e7eb;
    border-radius: 0.5rem;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    max-height: 40rem;
}

.paykeeper-browse-filters {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.75rem;
    border-bottom: 1px solid #e5e7eb;
}

.paykeeper-browse-search,
.paykeeper-browse-store { width: 100%; }

/* Regional Managers only — the legacy Active Date. Stacked label above input to match the other
   filters in this narrow pane rather than sitting inline like the checkbox. */
.paykeeper-browse-asof {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.75rem;
    color: var(--color-text-muted);
}
.paykeeper-browse-asof input { width: 100%; }

.paykeeper-browse-terminated {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}
.paykeeper-browse-terminated input { width: auto; }

.paykeeper-browse-count {
    padding: 0.4rem 0.75rem;
    margin: 0;
    font-size: 0.75rem;
    color: var(--color-text-subtle);
    border-bottom: 1px solid #f1f5f9;
}

.paykeeper-browse-employees {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-y: auto;
}

/* .paykeeper-browse-item is the same control with a neutral name — the payroll run page lists PAY
   GROUPS in this rail, not employees. Shared rather than duplicated so the two browse pages can't
   drift apart. */
.paykeeper-browse-employee,
.paykeeper-browse-item {
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-bottom: 1px solid #f1f5f9;
    padding: 0.55rem 0.75rem;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    position: relative;
    /* The global button rule sets align-items/justify-content:center and a fixed 40px height. In a
       COLUMN flex container align-items is the horizontal axis, so those centred the name and meta
       rather than left-aligning them, and text-align:left could not win because each span is only
       as wide as its own text. Same trap as the 40px SIN Reveal button — reset both explicitly. */
    align-items: flex-start;
    justify-content: flex-start;
    height: auto;
}
/* Hover/selected are selection chrome, so the tint tracks the app accent (a pale blue on PayKeeper).
   Was #f0fdf4 (pale green) from when the accent was green. Uses the background-color LONGHAND, not the
   `background` shorthand — a var() inside the shorthand is dropped to transparent at computed-value time
   here (the base rule's `background: none` makes it a shorthand-vs-shorthand cascade). */
.paykeeper-browse-employee:hover,
.paykeeper-browse-item:hover { background-color: var(--app-accent-ring); }
.paykeeper-browse-employee.selected,
.paykeeper-browse-item.selected {
    background-color: var(--app-accent-ring);
    box-shadow: inset 3px 0 0 var(--app-accent);
}
.paykeeper-browse-employee.terminated .paykeeper-browse-employee-name { color: var(--color-text-muted); }

.paykeeper-browse-employee-name,
.paykeeper-browse-item-name { font-weight: 600; font-size: 0.875rem; }
.paykeeper-browse-employee-meta,
.paykeeper-browse-item-meta { font-size: 0.75rem; color: var(--color-text-muted); }

/* "Calculated" is a fact about the row, not a fault — so it takes the muted treatment, like the
   "Moved" tag, and never the red the Terminated tag uses. */
.paykeeper-browse-item-tag {
    position: absolute;
    top: 0.55rem;
    right: 0.75rem;
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

.paykeeper-browse-employee-tag {
    position: absolute;
    top: 0.55rem;
    right: 0.75rem;
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-danger);
}

/* "Moved" is a neutral fact about the row (they transferred), not a fault — so it must not borrow
   the red the Terminated tag uses. Same distinction as neutral-badge vs alert-badge. */
.paykeeper-browse-employee-tag.moved { color: var(--color-text-muted); }

/* A button that reads as a link. Resets the global button rule's 40px height and padding, which
   would otherwise make each list entry a full-height control. */
.link-button {
    background: none;
    border: none;
    padding: 0;
    height: auto;
    font-size: inherit;
    font-weight: 600;
    color: inherit;
    text-decoration: underline;
    cursor: pointer;
}

/* Orphaned-sales-number list inside the warning banner. */
.paykeeper-orphan-list {
    margin: 0.5rem 0 0;
    padding-left: 1.1rem;
    font-weight: 400;
}
.paykeeper-orphan-list li { margin-bottom: 0.15rem; }

.paykeeper-browse-empty,
.paykeeper-browse-count:empty { padding: 0.75rem; color: var(--color-text-subtle); font-size: 0.85rem; }

.paykeeper-browse-detail { flex: 1; min-width: 0; }

/* Narrow screens swap panes rather than stacking them — picking someone replaces the list with their
   record, and .crm-back-btn returns. Mirrors OrderWriter's CRM Dashboard / Sample Log exactly,
   including its 900px breakpoint, so the two apps behave the same on a phone. */
@media (max-width: 900px) {
    .paykeeper-browse { flex-direction: column; }
    .paykeeper-browse-list, .paykeeper-browse-detail { width: 100%; }

    .paykeeper-browse.has-selection .paykeeper-browse-list { display: none; }
    .paykeeper-browse:not(.has-selection) .paykeeper-browse-detail { display: none; }

    .paykeeper-browse.has-selection .crm-back-btn { display: inline-flex; }
}

/* The outer surface selector (Record / Payroll History / …). The Record surface renders its own inner
   tab strip directly below, so give this one a heavier underline and a gap to keep the two levels
   legible rather than reading as one run of tabs. */
.paykeeper-browse-surface {
    border-bottom-width: 2px;
    margin-bottom: 1rem;
    font-weight: 600;
}

/* ── PayKeeper: one payroll run (phase 6, page 9) ───────── */

/* Everything that acts on the RUN, above the group/payline panes. Wraps rather than scrolls — these
   are destinations, not a tab strip, so a second row reads fine here. */
.paykeeper-run-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin: var(--space-3) 0;
}

/* Renaming a pay group is housekeeping, not a payroll action, so the affordance is a muted pencil
   beside the name rather than another button in the run's action row. Resets the global button rule's
   40px height, which would otherwise make it a full-size control next to an h2. */
.paykeeper-rename-btn {
    background: none;
    border: none;
    height: auto;
    padding: 0 0.15rem;
    font-size: 0.9rem;
    line-height: 1;
    color: var(--color-text-subtle);
    cursor: pointer;
}
.paykeeper-rename-btn:hover { color: var(--app-accent); }

/* Sits where the h2 was, so the heading does not jump when the field opens. */
.paykeeper-rename-input { max-width: 22rem; font-size: 1rem; }

/* Anchored LEFT, unlike the header Tools menu — this trigger sits at the start of a wrapping row of
   actions, so a right-anchored panel would open away from its own button. */
.paykeeper-download-dropdown { right: auto; left: 0; min-width: 15rem; }

/* Preview modals carry full report tables, so they need far more than the 480px default. */
.modal-paykeeper-preview { max-width: 62rem; width: 95vw; }
.modal-paykeeper-preview h3 { margin-bottom: var(--space-3); }

/* The flat payline view (page 9) — every line in the run, not one group's. Unlike the previews
   above, which are short enough to scroll as a whole, this is 600+ rows on a full run, so the
   modal itself does NOT scroll: the filters and the total are pinned and only the table moves.
   Without that, narrowing to one employee means scrolling back up to change the filter and back
   down to read the total, which is the whole job this view exists to do. */
.modal-paykeeper-flat {
    max-width: 72rem;
    width: 96vw;
    display: flex;
    flex-direction: column;
    overflow: hidden; /* the table area owns the scroll, not .modal's own overflow-y */
}

.paykeeper-flat-scroll { flex: 1 1 auto; min-height: 8rem; overflow: auto; }

/* Column headers survive the scroll. Sticky ROWS only — sticky COLUMNS were tried on the record
   tables and removed, because column 1 is not always the row's identity. The header already has an
   opaque near-black background, so nothing needs repainting underneath it. */
.paykeeper-flat-scroll thead th { position: sticky; top: 0; z-index: 1; }

/* Reads as the table's own footer even though it sits outside the scrolling element. */
.paykeeper-flat-total {
    display: flex;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    margin: 0;
    border-top: 2px solid var(--color-near-black);
    font-weight: 600;
    font-size: 0.875rem;
}

/* ── PayKeeper: Post Employee Changes form (phase 2c) ───── */
.paykeeper-form {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
    max-width: 44rem;
}

.paykeeper-form-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.85rem;
}
.paykeeper-form-row > .paykeeper-form-field { flex: 1 1 12rem; }

.paykeeper-form-field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-muted);
}
.paykeeper-form-field .form-control { font-weight: 400; }

.paykeeper-form-inline {
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
}
.paykeeper-form-inline input[type="date"] { width: auto; }

.paykeeper-form-radios {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    font-weight: 400;
}
.paykeeper-form-radios label { display: flex; align-items: center; gap: 0.3rem; }
.paykeeper-form-radios input { width: auto; }

.paykeeper-post-success {
    background: var(--color-success-bg);
    border: 1px solid var(--color-success-border);
    border-radius: 0.4rem;
    padding: 0.6rem 0.75rem;
    margin: 0.5rem 0;
    font-size: 0.85rem;
    color: var(--color-success);
}

.paykeeper-change-actions {
    display: flex;
    gap: 0.4rem;
    white-space: nowrap;
}

/* Wider than the default 480px modal — the pay-records table needs the room. */
.paykeeper-pay-modal { max-width: 640px; width: 95vw; }

/* Banking modal: the employee's other active accounts, edited in the same save. */
.paykeeper-banking-others-head { margin: 1rem 0 0.25rem; font-size: 0.95rem; }
.paykeeper-form-hint { font-size: 0.8rem; color: var(--color-text-muted); margin: 0.25rem 0 0.5rem; }
.paykeeper-banking-others { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.paykeeper-banking-others th { text-align: left; font-weight: 600; color: var(--color-text-muted); padding: 0.25rem 0.4rem; }
.paykeeper-banking-others td { padding: 0.25rem 0.4rem; vertical-align: middle; }
.paykeeper-banking-others input[type="checkbox"] { width: auto; }

.paykeeper-contract-line { margin-top: 0.35rem; font-weight: 400; }

/* ── PayKeeper: reference tables (phase 5) ─────────────── */

/* These grids run to a dozen columns (PayCode has eleven), so horizontal scrolling inside
   .admin-table-scroll should be the fallback, not the normal case.
   ⚠️ The width comes from .paykeeper-wide on the page element, NOT from here: a max-width cannot
   widen anything while .main-content caps its children at 1024px, which is why the `max-width: 84rem`
   that used to sit on this rule had no effect at all. Cross-cutting rule 4. */
.paykeeper-reference { min-width: 0; }

.paykeeper-reference-layout {
    display: grid;
    grid-template-columns: minmax(11rem, 14rem) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
}

@media (max-width: 60rem) {
    /* ⚠️ minmax(0, 1fr), NOT 1fr. A bare `1fr` track takes an automatic minimum of min-content, so
       once the table is allowed to overflow (page-level horizontal scroll, see
       .paykeeper-reference-grid) the track grew to the TABLE's width and dragged the nav out to
       1651px with it — every nav button stretched far off-screen. The explicit 0 minimum pins the
       track to the viewport and lets only the table overflow. The desktop rule above already had it. */
    .paykeeper-reference-layout { grid-template-columns: minmax(0, 1fr); }
}

.paykeeper-reference-nav h4 {
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
    margin: 1rem 0 0.35rem;
}
.paykeeper-reference-nav h4:first-child { margin-top: 0; }

.paykeeper-reference-nav ul { list-style: none; margin: 0; padding: 0; }

.paykeeper-reference-nav-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-left: 2px solid transparent;
    padding: 0.3rem 0.5rem;
    font-size: 0.875rem;
    color: var(--color-text);
    cursor: pointer;
    border-radius: 0 0.25rem 0.25rem 0;
}
.paykeeper-reference-nav-item:hover { background: #f9fafb; }
.paykeeper-reference-nav-item.is-active {
    background: #f3f4f6;
    border-left-color: var(--app-accent);
    font-weight: 600;
}

/* Marks a table that feeds the calculation engine, so the risk is visible before you open it rather
   than only once you're inside. */
.paykeeper-reference-warn {
    flex: none;
    width: 1.05rem;
    height: 1.05rem;
    line-height: 1.05rem;
    text-align: center;
    border-radius: 999px;
    background: #fef3c7;
    color: #92400e;
    font-size: 0.7rem;
    font-weight: 700;
}

.paykeeper-reference-desc {
    color: var(--color-text-muted);
    font-size: 0.875rem;
    max-width: 52rem;
    margin-bottom: 0.75rem;
}

.paykeeper-reference-callout {
    background: #fffbeb;
    border: 1px solid #fde68a;
    color: #92400e;
    border-radius: 0.375rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.8125rem;
    max-width: 52rem;
    margin-bottom: 0.75rem;
}

.paykeeper-reference-note {
    display: block;
    color: var(--color-text-subtle);
    font-size: 0.75rem;
}

.paykeeper-reference-confirm {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: 0.375rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.8125rem;
    color: #92400e;
    max-width: 52rem;
    margin-bottom: 0.75rem;
    cursor: pointer;
}

.paykeeper-reference-errors {
    background: #fef2f2;
    border: 1px solid #fecaca;
    border-radius: 0.375rem;
    padding: 0.6rem 0.85rem;
    font-size: 0.8125rem;
    color: #991b1b;
    max-width: 52rem;
    margin-bottom: 0.75rem;
}
.paykeeper-reference-errors ul { margin: 0.35rem 0 0; padding-left: 1.1rem; }

/* Inputs sit tighter in a grid cell than they do in a form. */
.paykeeper-reference-edit .form-input {
    min-width: 6rem;
    padding: 0.2rem 0.35rem;
    font-size: 0.8125rem;
}
.paykeeper-reference-edit td { vertical-align: middle; }

.paykeeper-reference-ro { color: var(--color-text-muted); font-size: 0.8125rem; }

.paykeeper-reference-req { color: var(--color-danger); margin-left: 0.15rem; }

.paykeeper-reference-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 0.85rem;
    max-width: 60rem;
}
/* ⚠️ DELIBERATELY NO overflow AND NO min-width: 0 — the opposite of .admin-table-scroll, and the
   same trade the Pricelist grids make. A wide table is allowed to overflow this box (and past
   .paykeeper-wide's 100vw) so the PAGE scrolls horizontally. An inner scroll container puts its
   scrollbar at the bottom of the table, which on a table taller than the viewport means scrolling
   down to find the control that scrolls sideways; the window's scrollbar is always in reach. */
.paykeeper-reference-grid { min-width: 100%; }

/* The employee-level actions, on the NAME line. margin-left:auto pushes them to the far end, so the
   row reads identity-left / actions-right rather than a run-on of name, badge and buttons. */
.paykeeper-record-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-left: auto;
}
/* ⚠️ Anchored RIGHT (the .tools-menu-dropdown default), NOT left. The trigger is the LAST item in a
   right-aligned group, so a left-anchored panel opens rightward and runs off the viewport — measured
   at 1414px against a 1265px viewport. This is the mirror image of the payroll run page's Download
   menu, which anchors left precisely because its trigger STARTS its row. */
.paykeeper-actions-dropdown { min-width: 16rem; }

/* ⚠️ Name and its attributes line are ONE unit and belong tight together; the air goes BELOW them,
   before the Record/History switch. The shared .paykeeper-header's 1.5rem bottom margin put the gap
   in exactly the wrong place — a big space between the name and its own subtitle, then none at all
   between that subtitle and the next control. Scoped to this header so every other PayKeeper page
   keeps the standard spacing. */
.paykeeper-record-head { margin-bottom: 0.15rem; flex-wrap: wrap; }
.paykeeper-record-subject { margin: 0 0 1.5rem; }

.paykeeper-reference-field { display: flex; flex-direction: column; gap: 0.2rem; }

/* The singleton edit form's labels. They previously wore .paykeeper-label, which is defined nowhere,
   so they rendered as plain body text while the read-only view of the same fields (.paykeeper-field-list
   dt) was styled — the same record looked like two different screens depending on the mode. Matches
   .paykeeper-form-field's label treatment without nesting a second flex column inside this one. */
.paykeeper-reference-field-label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

.btn-link-danger {
    background: none;
    border: none;
    color: var(--color-danger);
    cursor: pointer;
    font-size: 0.9rem;
    line-height: 1;
    padding: 0.2rem 0.35rem;
    border-radius: 0.25rem;
}
.btn-link-danger:hover { background: #fef2f2; }

/* A pending row that has a saved-but-unfiled draft — tinted so the whole line reads as in-progress,
   with a single accent bar on the far-left cell (the app's warning-highlight convention). */
.paykeeper-row-draft > td { background: var(--color-warning-bg); }
.paykeeper-row-draft > td:first-child { border-left: 3px solid var(--color-warning); }
.paykeeper-row-draft:hover > td { background: var(--color-warning-border); }

/* Neutral inline text button — e.g. "Reset to calculated" beside an overridden field. */
.btn-link {
    background: none;
    border: none;
    color: var(--color-accent, #2563eb);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
    padding: 0.2rem 0.35rem;
    border-radius: 0.25rem;
}
.btn-link:hover:not(:disabled) { text-decoration: underline; }
.btn-link:disabled { color: var(--color-text-muted); cursor: default; }

/* Advisory, not a failure — the save succeeded. Distinct from the red error panel. */
.paykeeper-reference-warnings {
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: 0.375rem;
    padding: 0.6rem 0.85rem;
    font-size: 0.8125rem;
    color: #92400e;
    max-width: 52rem;
    margin-bottom: 0.75rem;
}
.paykeeper-reference-warnings ul { margin: 0; padding-left: 1.1rem; }

/* ============================================================================
   PriceLister — cost grid (Route B: native Blazor grid, no grid library)
   Fixed-height scroller + sticky header + fixed-width flex cells so the <Virtualize>
   body and the header column-align without a grid library. Editable cells (New Roll /
   New Cut) are tinted; only the focused cell ever mounts an <input>.
   ============================================================================ */
/* Full-bleed breakout of .main-content's centered cap — the cost grid is a wide, many-column data view.
   A flex column pinned to a FIXED viewport height (calc, not min-height — min-height lets it grow past
   the fold when the grid content is tall). The grid (flex:1, min-height:0) fills whatever space is left
   below the pickers, so it and its horizontal scrollbar stay on screen and it adapts when Settings opens. */
/* Fill from just below the nav to the very bottom of the window with NO page scrollbar: height subtracts
   only the TOP chrome (nav 56 + .main-content top padding 32 = 88), and a negative bottom margin CANCELS
   .main-content's 32px bottom padding — so the grid sits tight to the window's bottom edge (rather than
   the earlier approach, which shrank the grid to leave that padding hanging below it). */
.pl-proto { margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); width: 100vw; margin-bottom: -32px;
    padding: 16px var(--space-6) 8px;
    display: flex; flex-direction: column; height: calc(100vh - 88px); }
/* The page is a fixed-height flex column. Its children default to flex-shrink:1, which was squashing the
   fixed-height back button (and could squash the header/bar). Pin every non-grid child to its natural
   size; only the grid (flex:1, min-height:0) absorbs the leftover space. The back button also gets
   align-self:flex-start so it doesn't stretch full-width. */
.pl-proto > :not(.pl-grid) { flex-shrink: 0; }
.pl-proto > .app-back-btn { align-self: flex-start; }

/* Expand mode — hide the explanatory chrome (back button, description, key-hints) and slim the header so
   the flex grid grows to fill nearly the whole viewport. Toggled by the Expand/Collapse button. */
/* Expanded also pulls the header up under the nav (negative top margin cuts the ~32px nav-clearance gap)
   and adds the reclaimed height back so it still reaches the window bottom. */
.pl-proto.pl-expanded { margin-top: -20px; height: calc(100vh - 68px); padding: 4px var(--space-2) 6px; }
.pl-proto.pl-expanded .app-back-btn,
.pl-proto.pl-expanded .pl-proto-sub,
.pl-proto.pl-expanded .pl-proto-hint { display: none; }
.pl-proto.pl-expanded .pl-proto-head { margin-bottom: 2px; }
.pl-proto.pl-expanded .pl-proto-head h2 { font-size: 15px; margin: 0; }
.pl-expand-btn { margin-left: auto; }   /* push to the right end of the toolbar */
.pl-proto-head h2 { margin: 0 0 2px; }
.pl-proto-sub { margin: 0; max-width: 760px; color: var(--color-text-muted); font-size: 13px; }
.pl-proto-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 14px 0 6px; }
.pl-proto-label { font-size: 13px; color: var(--color-text-muted); }
.pl-proto-stat { font-size: 13px; margin-left: 8px; }
.pl-proto-hint { font-size: 12px; color: var(--color-text-subtle); margin-bottom: 8px; }
.pl-muted { color: var(--color-text-muted) !important; }

.pl-btn {
    font: inherit; font-size: 13px; padding: 5px 11px; border-radius: var(--radius-sm);
    border: 1px solid var(--color-border); background: var(--color-surface); color: var(--color-text);
    cursor: pointer;
}
.pl-btn:hover { border-color: var(--app-accent-border); }
.pl-btn-on { background: var(--app-accent); border-color: var(--app-accent); color: #fff; }

/* flex:1 fills the space left in the viewport-height .pl-proto column; min-height:0 is the canonical
   flexbox fix that lets it shrink below content size so the internal scroll (not the page) handles rows. */
.pl-grid {
    flex: 1 1 auto; min-height: 0; border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-surface); outline: none; overflow: hidden;
}
.pl-scroll { height: 100%; overflow: auto; }
/* Every body cell is now clickable to select it (read-only cells included), so give them all the same
   cell cursor the editable ones have — signals selectability consistently. */
.pl-row:not(.pl-head) .pl-cell { cursor: cell; }

/* width:max-content so each row grows to encompass ALL its cells (not just the visible viewport width) —
   otherwise the row-level background (hover / selected / zebra) and bottom border stop at the viewport
   edge and the columns that overflow to the right render with no row highlight or gridline. min-width:100%
   keeps a narrow class filling the grid. */
.pl-row { display: flex; height: 28px; box-sizing: border-box; width: max-content; min-width: 100%; }
.pl-head {
    position: sticky; top: 0; z-index: 10; height: 30px;
    background: var(--color-bg); border-bottom: 1px solid var(--color-border);
    font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .02em;
    color: var(--color-text-muted);
}
/* Each header cell paints its own opaque background so a virtualized row can never show THROUGH the
   sticky header while scrolling (belt-and-suspenders with the row-level background + high z-index). */
.pl-head .pl-cell { background: var(--color-bg); }
.pl-row:not(.pl-head) { border-bottom: 1px solid var(--color-border); font-size: 13px; }
.pl-row:not(.pl-head):hover { background: color-mix(in srgb, var(--app-accent) 4%, white); }
.pl-row-sel, .pl-row-sel:hover { background: var(--app-accent-bg) !important; }

.pl-cell {
    flex: 0 0 auto; padding: 0 8px; display: flex; align-items: center;
    border-right: 1px solid var(--color-border); overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.pl-head .pl-cell { align-items: center; }
.pl-c-code { width: 74px; }
.pl-c-desc { width: var(--pl-desc-w, 190px); display: block; line-height: 27px; }
.pl-c-num  { width: 86px; justify-content: flex-end; text-align: right; font-variant-numeric: tabular-nums; }
.pl-c-num-wide { width: 96px; justify-content: flex-end; text-align: right; font-variant-numeric: tabular-nums; }
.pl-c-uom  { width: 52px; justify-content: center; color: var(--color-text-muted); }
.pl-c-uom-wide { width: 80px; justify-content: center; color: var(--color-text-muted); }
.pl-head .pl-c-num, .pl-head .pl-c-num-wide { justify-content: flex-end; }

/* Sticky-left identity columns (Style / colour / desc / Roll W) — stay pinned while the numeric columns
   scroll horizontally. `left` offsets are set inline per column (see FrozenLeft). Opaque backgrounds so
   scrolling cells never show through; the header's frozen cells sit above everything (top-left corner). */
.pl-cell-frozen { position: sticky; z-index: 3; background: var(--color-surface); }
.pl-row:not(.pl-head):hover .pl-cell-frozen { background: color-mix(in srgb, var(--app-accent) 4%, white); }
.pl-row-sel .pl-cell-frozen { background: var(--app-accent-bg); }
.pl-head .pl-cell-frozen { background: var(--color-bg); z-index: 12; }

.pl-c-edit { background: color-mix(in srgb, var(--app-accent) 5%, white); cursor: cell; }
.pl-head .pl-c-edit { background: color-mix(in srgb, var(--app-accent) 10%, var(--color-bg)); color: var(--color-text); }
.pl-cell-sel { outline: 2px solid var(--app-accent); outline-offset: -2px; z-index: 1; }

/* .pl-grid prefix raises specificity to (0,2,0) so this beats the global input[type=...] rule (0,1,1),
   which was otherwise forcing font-size:1rem (16px) onto the cell editor instead of the cell's 13px. */
.pl-grid .pl-edit-input {
    width: 100%; height: 100%; border: none; outline: 2px solid var(--app-accent); outline-offset: -2px;
    padding: 0 6px; margin: 0; text-align: right; font: inherit; font-size: 13px; font-variant-numeric: tabular-nums;
    background: var(--color-surface); color: var(--color-text); box-sizing: border-box;
}

/* Cost went UP vs the current baseline = red; down = green. */
.pl-up   { color: var(--color-danger); }
.pl-down { color: var(--color-success); }

/* PriceLister Phase-1 cost grid: pickers + read-only grid extras (reuses the .pl-* grid styles). */
.pl-select {
    font: inherit; font-size: 13px; padding: 4px 8px; border-radius: var(--radius-sm);
    border: 1px solid var(--color-border); background: var(--color-surface); color: var(--color-text);
}
.pl-select:disabled { color: var(--color-text-subtle); background: var(--color-bg); }
.pl-check { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; color: var(--color-text); }
.pl-sortable { cursor: pointer; user-select: none; }
.pl-sortable:hover { color: var(--color-text); }
/* Discontinued items: still cost-editable, but visually de-emphasised. */
.pl-disc .pl-cell { color: var(--color-text-subtle); font-style: italic; }

/* PriceLister Phase-2b: per-class settings panel. */
.pl-settings { border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface); padding: 12px 14px; margin-bottom: 10px; }
.pl-settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; }
.pl-settings fieldset { border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: 8px 10px; margin: 0; }
.pl-settings legend { font-size: 12px; font-weight: 600; color: var(--color-text-muted); padding: 0 4px; }
.pl-settings label { display: flex; align-items: center; gap: 6px; font-size: 13px; margin: 4px 0; }
.pl-settings input[type=number], .pl-settings input[type=text] {
    font: inherit; font-size: 12px; width: 90px; margin-left: auto; padding: 2px 5px;
    border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); color: var(--color-text);
}
/* Rate/amount box greys out when its gating checkbox is off (the setting doesn't apply). */
.pl-settings input:disabled { opacity: .45; background: var(--color-bg); cursor: not-allowed; }
/* Settings toggle row: switch+label on the left grows to fill, its value box sits at the right. */
.pl-set-row { display: flex; align-items: center; gap: 8px; margin: 6px 0; }
.pl-set-toggle { flex: 1; font-size: 13px; }
.pl-set-label { flex: 1; font-size: 13px; color: var(--color-text-muted); }
.pl-set-seg { margin: 4px 0 6px; }
.pl-set-seg .segment, .pl-set-seg .segment-active { font-size: 12px; padding: 3px 8px; }
/* "Stamp Pad/Labour → grid" button sits below the Pad/Labour fields in its fieldset. */
.pl-stamp-btn { margin-top: 8px; width: 100%; font-size: 12px; }
.pl-settings-actions { display: flex; align-items: center; gap: 10px; margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--color-border); font-size: 13px; }

/* ---- PriceLister write-back review panel (Phase 3a) ---- */
.pl-review { border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface); padding: 12px 14px; margin-bottom: 10px; }
.pl-review-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.pl-banner { border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: 8px 10px; font-size: 13px; margin-bottom: 10px; }
.pl-banner-info { background: var(--color-info-bg); border-color: var(--color-info-border); color: var(--color-text); }
.pl-banner-ok { background: var(--color-success-bg); border-color: var(--color-success-border); color: var(--color-text); }
.pl-banner-danger { background: var(--color-danger-bg); border-color: var(--color-danger-border); color: var(--color-text); }
.pl-ok { color: var(--color-success); font-weight: 600; }
.pl-danger { color: var(--color-danger); }
.pl-warn { color: var(--color-warning); }
.pl-review-scroll { max-height: 40vh; overflow: auto; border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
.pl-review-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.pl-review-table th, .pl-review-table td { text-align: left; padding: 3px 8px; border-bottom: 1px solid var(--color-border); white-space: nowrap; }
.pl-review-table thead th { position: sticky; top: 0; background: var(--color-surface-raised, var(--color-surface)); font-weight: 600; color: var(--color-text-muted); }
.pl-review-table .pl-num { text-align: right; font-variant-numeric: tabular-nums; }
.pl-review-table .pl-new { font-weight: 600; }
.pl-review-table .pl-mono { font-family: var(--font-mono, monospace); color: var(--color-text-muted); }
.pl-review-table tr.pl-conflict td { color: var(--color-warning); text-decoration: line-through; }
.pl-review-table tr.pl-conflict td.pl-mono { text-decoration: none; }
.pl-review-line { font-size: 12px; margin: 2px 0; }
.pl-review-sub { margin-top: 12px; margin-bottom: 4px; font-size: 12px; font-weight: 600; color: var(--color-text-muted); }
.pl-review-extra { margin-top: 10px; font-size: 12px; }
.pl-review-extra summary { cursor: pointer; color: var(--color-text-muted); }
.pl-review-actions { display: flex; align-items: center; gap: 10px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--color-border); font-size: 13px; flex-wrap: wrap; }
.pl-revert { width: 100%; margin-top: 6px; font-family: var(--font-mono, monospace); font-size: 11px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); color: var(--color-text); padding: 6px 8px; resize: vertical; }

/* Phase 4: producer catalog actions bar + record modal */
.pl-actions-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
    border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface);
    padding: 10px 12px; margin-bottom: 12px; }
.pl-actions-buttons { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pl-record-chip { display: flex; flex-direction: column; gap: 1px; }
.pl-record-chip-name { font-weight: 600; }
.pl-record-chip-meta { font-size: 12px; color: var(--color-text-muted); }
.pl-record-missing { font-size: 13px; color: var(--color-text-muted); max-width: 46ch; }
/* Consumer pricelist heading — record name + printed note, above the price tables. */
.pricelist-consumer-head { margin: 0 0 12px; }
.pricelist-consumer-head h3 { margin: 0; font-size: 18px; }
.pricelist-consumer-note { margin: 3px 0 0; color: var(--color-text-muted); font-size: 13px; max-width: 70ch; }

/* Consumer self-serve QR bar (Phase 5b) — store managers reprint a display sticker on plain paper.
   Sits below the price tables and stays deliberately quiet: no boxed surface, muted, a plain button. */
.pl-consumer-qr { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-top: 18px; padding-top: 12px; border-top: 1px solid var(--color-border);
    font-size: 13px; color: var(--color-text-muted); }
.pl-consumer-qr-label { font-weight: 500; color: var(--color-text-muted); }
.pl-consumer-qr .pl-qr-qty { margin: 0; }
.pl-record-missing strong { color: var(--color-text); display: block; }

.pl-record-form { display: flex; flex-direction: column; gap: 10px; margin: 8px 0 14px; }
.pl-record-form label { display: flex; flex-direction: column; gap: 3px; font-size: 13px; }
.pl-record-form label > span { color: var(--color-text-muted); }
/* The fields borrow .product-picker-search-input (flex: 1 1 140px, built for a ROW flex). Each label
   here is a COLUMN flex, so that flex-basis becomes a 140px HEIGHT and the box balloons — same trap the
   Admin filter hit. Pin them to natural height, full width. */
.pl-record-form input, .pl-record-form textarea, .pl-record-form select { flex: 0 0 auto; width: 100%; box-sizing: border-box; }
.pl-record-note { resize: vertical; }
.pl-record-stores-head { font-size: 13px; color: var(--color-text-muted); margin-bottom: 6px; }
/* Multi-column (not grid) so the stores fill top-to-bottom down column 1, then column 2 — vertical
   order, which reads as a single alphabetised/numbered list split in two. */
.pl-record-stores-grid { column-count: 2; column-gap: 16px;
    max-height: 34vh; overflow: auto; border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: 8px; }
.pl-record-store { display: flex; align-items: center; gap: 6px; font-size: 13px; break-inside: avoid; margin-bottom: 4px; }

/* Edit Mouldings modal — inline Type/Price editor. */
.pl-mould-edit-hint { font-size: 12px; color: var(--color-text-muted); margin: 4px 0 0; }
.pl-mould-edit { margin-top: 14px; display: flex; flex-direction: column; gap: 6px;
    max-height: 42vh; overflow-y: auto; }
.pl-mould-edit-head, .pl-mould-edit-row { display: grid; grid-template-columns: 1fr 120px 34px; gap: 8px; align-items: center; }
.pl-mould-edit-head { font-size: 11px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
    color: var(--color-text-muted); }
.pl-mould-edit-head span:nth-child(2) { text-align: right; }
.pl-mould-edit-row input[type="number"] { text-align: right; }
.pl-mould-edit-del { padding: 6px 0; }

.pl-publish { margin-bottom: 12px; }
.pl-publish-warn { font-size: 13px; color: var(--color-warning); border: 1px solid var(--color-warning);
    border-radius: var(--radius-sm); background: color-mix(in srgb, var(--color-warning) 8%, transparent);
    padding: 8px 10px; margin: 10px 0 4px; }
.pl-publish-ok { font-size: 14px; font-weight: 600; color: var(--color-success); margin-top: 10px; }

.pl-qr { margin-bottom: 12px; }
.pl-qr-body { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-start; margin-top: 8px; }
.pl-qr-preview { flex: 0 0 auto; }
.pl-qr-preview img { width: 160px; height: 160px; image-rendering: pixelated; border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
.pl-qr-meta { flex: 1 1 220px; min-width: 220px; }
.pl-qr-qty { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; margin: 8px 0; }
.pl-qr-qty input { width: 72px; padding: 4px 6px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); color: var(--color-text); }
.pl-qr-note { font-size: 12px; color: var(--color-text-muted); margin-top: 8px; max-width: 44ch; }
.pl-qr-status { font-size: 13px; font-weight: 600; margin-top: 8px; }

/* Reporter development-analysis metric tiles: a stacked label / value / caption card. */
.reporter-stat { display: flex; flex-direction: column; gap: 0.15rem; padding: 0.75rem 0.9rem; background: var(--color-surface); border: 0.5px solid var(--color-border); border-radius: 12px; }
.reporter-stat > span { font-size: 0.8rem; color: var(--color-text-muted); }
.reporter-stat > strong { font-size: 1.4rem; font-weight: 500; }
.reporter-stat > em { font-size: 0.72rem; color: var(--color-text-muted); font-style: normal; }

/* Click-to-expand rows in the Reporter workforce count tables. */
.drill-row { cursor: pointer; }
.drill-row:hover { background: var(--color-surface-hover, rgba(0,0,0,0.03)); }
.drill-detail > td { background: var(--color-surface); padding: 0.5rem 0.75rem; }
.drill-inner { margin: 0; width: auto; min-width: 22rem; }
.drill-inner th, .drill-inner td { font-size: 0.8rem; }

/* Admin ▸ Accounting ▸ Month-end close */
.admin-accounting-switch { margin-bottom: var(--space-4); flex-wrap: wrap; max-width: 100%; }
.admin-monthend-current {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    margin: var(--space-3) 0;
}
.admin-monthend-current h4 { margin: 0 0 var(--space-1); }
.admin-monthend-table .num,
.admin-monthend-stores .num { text-align: right; white-space: nowrap; }
.admin-monthend-table td { white-space: nowrap; }
/* Compact: each cell's secondary detail (fiscal year, "imported", who took it, $ behind a count, the 20050
   difference) stacks under the main value instead of beside it, so eleven columns fit a normal screen. */
.admin-monthend-table th,
.admin-monthend-table td { padding: var(--space-2) var(--space-3); }
.admin-monthend-sub { display: block; font-size: 0.75rem; color: var(--color-text-muted); }
.admin-monthend-actions { display: flex; flex-direction: column; gap: var(--space-1); align-items: stretch; }
.admin-monthend-stores-row > td { background: var(--color-bg); padding: var(--space-3); }
.admin-monthend-stores { margin: 0; }


/* ── PriceLister: Add Item modal ─────────────────────────────────────────────────────────────── */
/* Two columns so the ~10 fields fit without scrolling on a laptop; the wide ones (description,
   vendor) span both. Collapses to one column on a phone like every other modal here. */
.modal-add-item { max-width: 720px; width: 95vw; }
.add-item-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--space-4); }
.add-item-grid .add-item-wide { grid-column: 1 / -1; }
/* Stacked, not the global inline form-row: label above, field full width, hint below — so fields side by side
   line up whatever their label length (the inline layout wrapped long labels and staggered the pairs). */
.add-item-grid .form-row { margin-bottom: var(--space-3); flex-direction: column; align-items: stretch; gap: var(--space-1); }
.add-item-grid .form-row input, .add-item-grid .form-row select { flex: none; width: 100%; min-width: 0; }
.add-item-grid p.muted { margin: var(--space-1) 0 0; font-size: 0.8rem; }
.modal-add-item .req { color: var(--color-danger); font-weight: 400; font-size: 0.8rem; }
.add-item-errors, .add-item-warnings { margin-top: var(--space-3); }
.add-item-errors p, .add-item-warnings p { margin: 0 0 var(--space-1); }
.add-item-created { margin-top: var(--space-3); color: var(--color-success); }
/* The fixed-value note sits directly above the docked actions, so it reads as part of the commit. */
.add-item-fixed { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--color-border); font-size: 0.8rem; }
@media (max-width: 600px) { .add-item-grid { grid-template-columns: 1fr; } }

/* ── BankSitter ──────────────────────────────────────────── */
.bs-lead { color: var(--color-text-muted); max-width: 60rem; }
.bs-toolbar { display: flex; gap: var(--space-2); align-items: flex-end; flex-wrap: wrap; margin-bottom: var(--space-3); }
.bs-toolbar label { display: flex; flex-direction: column; gap: 2px; font-size: 0.8rem; color: var(--color-text-muted); }
.bs-toolbar .bs-check { flex-direction: row; align-items: center; gap: var(--space-1); padding-bottom: var(--space-2); }
.bs-toolbar .form-control { height: 32px; }
.bs-error, .bs-off-text { color: var(--color-danger); }
.bs-summary { display: flex; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-2); font-size: 0.9rem; }
.bs-grid-wrap { overflow-x: auto; border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
.bs-grid { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.bs-grid th { position: sticky; top: 0; background: #f8f9fa; padding: var(--space-1) var(--space-2); border-bottom: 2px solid var(--color-border); white-space: nowrap; text-align: left; }
.bs-grid th.num, .bs-grid td.num, .bs-lines .num { text-align: right; white-space: nowrap; }
.bs-grid td { padding: 3px var(--space-2); border-bottom: 1px solid var(--color-border); }
.bs-store-col { white-space: nowrap; position: sticky; left: 0; background: #fff; z-index: 1; }
.bs-grid th.bs-store-col { background: #f8f9fa; z-index: 2; }
.bs-acct { display: block; font-size: 0.65rem; font-weight: 400; color: var(--color-text-muted); }
.bs-lines .bs-acct { display: inline; margin-left: var(--space-1); }
.bs-cell { cursor: pointer; }
.bs-cell:hover { background: var(--app-accent-bg); }
.bs-cell.bs-empty { cursor: default; }
.bs-cell.bs-empty:hover { background: none; }
.bs-off { color: var(--color-danger); font-weight: 600; }
.bs-cell.bs-off { background: var(--color-danger-bg); }
.bs-selected { box-shadow: inset 0 0 0 2px var(--app-accent); }
.bs-zero, .bs-dim { color: var(--color-text-muted); }
.bs-operating { color: var(--color-text-muted); font-style: italic; }
.bs-row-ok td { color: var(--color-text-muted); }
.bs-net { border-left: 2px solid var(--color-border); }
.bs-grid tfoot td { font-weight: 600; background: #f8f9fa; border-top: 2px solid var(--color-border); }
.bs-grid tfoot .bs-store-col { background: #f8f9fa; }
.bs-tag { display: inline-block; margin-left: var(--space-1); padding: 0 var(--space-1); border-radius: var(--radius-sm); font-size: 0.65rem; font-weight: 600; color: var(--color-warning); border: 1px solid var(--color-warning-border); background: var(--color-warning-bg); }
/* Drill-down: a very wide modal (the shared .modal is 480px) with the accent on its left edge. */
.modal.bs-ledger { max-width: min(1400px, 96vw); padding: var(--space-4) var(--space-5); border-left: 4px solid var(--app-accent); }
.bs-ledger-head { display: flex; gap: var(--space-2); align-items: flex-end; flex-wrap: wrap; margin-bottom: var(--space-2); }
.bs-ledger-head h3 { margin: 0 auto 0 0; font-size: 1rem; }
.bs-ledger-head label { display: flex; flex-direction: column; gap: 2px; font-size: 0.75rem; color: var(--color-text-muted); }
.bs-ledger-head .form-control { height: 30px; }
.bs-months { display: flex; gap: 2px; flex-wrap: wrap; margin-bottom: var(--space-3); }
.bs-month { display: flex; flex-direction: column; align-items: flex-end; min-width: 5.5rem; height: auto; padding: var(--space-1); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: #fff; cursor: pointer; font-size: 0.7rem; }
.bs-month:hover { border-color: var(--app-accent); }
.bs-month-name { color: var(--color-text-muted); font-weight: 400; }
.bs-month.bs-off { background: var(--color-danger-bg); }
.bs-zero-month .bs-month-bal { color: var(--color-text-muted); }
.bs-lines { width: 100%; border-collapse: collapse; font-size: 0.75rem; }
.bs-lines th { text-align: left; color: var(--color-text-muted); font-weight: 600; padding: var(--space-1); border-bottom: 1px solid var(--color-border); white-space: nowrap; }
.bs-lines td { padding: 2px var(--space-1); border-bottom: 1px solid var(--color-border); }
.bs-ref { max-width: 26rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bs-opening td { background: #f8f9fa; font-weight: 600; }
/* Cash that is all undeposited cash / cheques: timing, not an error. */
.bs-cell.bs-timing { background: var(--color-info-bg); color: var(--color-info); }
.bs-timing-text { color: var(--color-info); }
.bs-sub { display: block; font-size: 0.62rem; font-weight: 400; opacity: 0.85; }
.bs-open { margin-bottom: var(--space-3); padding-bottom: var(--space-2); border-bottom: 1px solid var(--color-border); }
/* BankSitter ▸ Bank feed (NBC BAI statements) */
.bf-status { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; margin-bottom: var(--space-2); font-size: 0.85rem; }
.bf-fetch { margin-bottom: var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); background: var(--color-success-bg); border: 1px solid var(--color-success-border); font-size: 0.8rem; }
.bf-fetch.bf-fetch-problem { background: var(--color-warning-bg); border-color: var(--color-warning-border); }
.bf-h { margin: var(--space-4) 0 var(--space-2); font-size: 1rem; }
.bf-h .muted-inline { font-size: 0.8rem; font-weight: 400; margin-left: var(--space-2); }
.bf-summary { display: flex; gap: var(--space-5); flex-wrap: wrap; align-items: flex-start; margin-bottom: var(--space-3); }
.bf-summary .bs-lines { width: auto; min-width: 18rem; }
.bf-txns td { white-space: nowrap; }
.bf-debit { color: var(--color-danger); }
.bf-unidentified td { background: var(--color-warning-bg); }
.bs-open-head { display: flex; gap: var(--space-2); align-items: flex-end; flex-wrap: wrap; margin-bottom: var(--space-1); }
.bs-open-head h4 { margin: 0 auto 0 0; font-size: 0.9rem; }
.bs-open-head label { display: flex; flex-direction: column; gap: 2px; font-size: 0.75rem; color: var(--color-text-muted); }
.bs-open-head .form-control { height: 30px; }
.bs-open-sum { margin: var(--space-1) 0; font-size: 0.85rem; }
.bs-open-note { margin: 0 0 var(--space-2); font-size: 0.75rem; }
.bs-late { color: var(--color-warning); font-weight: 600; }
.bs-deposits { margin-bottom: var(--space-3); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-info-border); border-radius: var(--radius-sm); background: var(--color-info-bg); }
.bs-deposit { margin-top: var(--space-2); padding: var(--space-2); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); }
.bs-deposit-head { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; margin-bottom: var(--space-1); font-size: 0.85rem; }
.bs-deposit-actions { margin-left: auto; display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.bs-deposit-ok { color: var(--color-success); }
.bs-target { font-size: 0.75rem; padding: 0 var(--space-1); border: 1px solid var(--color-border); border-radius: var(--radius-sm); color: var(--color-text-muted); }
.bs-target-demo { color: var(--color-warning); border-color: var(--color-warning-border); background: var(--color-warning-bg); font-weight: 600; }
.bs-lines .bs-day-end td { border-bottom: 1px solid var(--color-text-muted); }
/* BankSitter drill-down: what the matching made of each line. */
.bs-analysis { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; margin-bottom: var(--space-2); font-size: 0.85rem; }
.bs-analysis .bs-check { display: flex; align-items: center; gap: var(--space-1); margin-left: auto; font-size: 0.8rem; }
.bs-st-problem-text { color: var(--color-danger); }
.bs-st-adjustment-text { color: var(--color-warning); }
.bs-lines tr.bs-st-problem td { background: var(--color-danger-bg); }
.bs-lines tr.bs-st-problem .bs-note { color: var(--color-danger); font-weight: 600; }
.bs-lines tr.bs-st-adjustment td { background: var(--color-warning-bg); }
.bs-lines tr.bs-st-matched td, .bs-lines tr.bs-st-internal td { color: var(--color-text-muted); }
.bs-lines tr.bs-hide { display: none; }
.bs-note { font-size: 0.7rem; max-width: 22rem; }
.bs-month-change { font-size: 0.62rem; color: var(--color-text-muted); }
.bs-lines tr.bs-st-mismatch td { background: var(--color-danger-bg); }
.bs-lines tr.bs-st-mismatch .bs-note { color: var(--color-danger); font-weight: 600; }
.bs-month-selected { box-shadow: inset 0 0 0 2px var(--app-accent); }
.bs-clean { margin-bottom: var(--space-3); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); }
.bs-clean h5 { margin: var(--space-3) 0 var(--space-1); font-size: 0.8rem; }
.bs-clean-steps { border-collapse: collapse; font-size: 0.85rem; min-width: 26rem; }
.bs-clean-steps td { padding: 2px var(--space-2); }
.bs-clean-steps .num { text-align: right; white-space: nowrap; }
.bs-clean-total td { font-weight: 700; border-top: 1px solid var(--color-text-muted); }
.bs-view { display: flex; gap: 0; }
.bs-view button:first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.bs-view button:last-child { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.bs-cell.bs-gl-only { font-style: italic; opacity: 0.75; }
.bs-grid-loading { opacity: 0.45; transition: opacity 0.15s; pointer-events: none; }

/* ── Admin ▸ Accounting ▸ GL reconciliations (20050 / 20000 / 11000 / 24400) ──────────────
   Ported from PurchaseMatcher (invoice-rec) with the reconciliation tools, 2026-10-02: the pm- layout helpers
   they use and the r20- / r2k- classes, unchanged. */
.pm-lead { color: var(--color-text-muted); max-width: 52rem; }
.pm-demo-banner { max-width: 52rem; }
.pm-toolbar { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; margin-bottom: var(--space-3); }
.pm-error { color: var(--color-danger); }
.pm-filters { display: flex; gap: var(--space-3); align-items: flex-end; flex-wrap: wrap; margin-bottom: var(--space-3); }
.pm-filters label { display: flex; flex-direction: column; gap: var(--space-1); font-size: 0.8rem; color: var(--color-text-muted); }
.pm-filters .pm-search input { width: 16rem; max-width: 100%; }
.pm-filters .pm-check { flex-direction: row; align-items: center; gap: var(--space-2); padding-bottom: var(--space-2); }
.pm-summary { display: flex; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-2); font-size: 0.9rem; }
.pm-tag { display: inline-block; margin-left: var(--space-1); padding: 0 var(--space-1); border-radius: var(--radius-sm); font-size: 0.7rem; color: var(--color-warning); border: 1px solid var(--color-warning-border); }
.pm-tag-plain { color: var(--color-text-muted); border-color: var(--color-border); }
/* ── Invoices ▸ 20050 reconciliation (admin) ─────────────
   Semantic tokens only: good/bad are state; the posted banner is success. */
.r20-summary { max-width: 42rem; margin-bottom: var(--space-3); }
.r20-summary td:first-child { width: 20rem; }
.r20-summary .num, .r20-table .num { text-align: right; white-space: nowrap; }
.r20-total td { font-weight: 600; }
.r20-post { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; margin-bottom: var(--space-3); }
.r20-post label { display: flex; flex-direction: column; gap: var(--space-1); font-size: 0.875rem; }
.r20-posted { background: var(--color-success-bg); border: 1px solid var(--color-success-border); color: var(--color-success);
              border-radius: 0.4rem; padding: 0.6rem 0.75rem; margin: 0.5rem 0; font-size: 0.9rem; }
.r20-table td { vertical-align: top; }
.r20-suggest { color: var(--color-info); font-size: 0.8rem; }
.r20-cleared { display: inline-block; margin: 0 0.4rem; color: var(--color-success); font-size: 0.8rem; font-weight: 600; }
.r20-clearbar { position: sticky; bottom: 0; display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center;
                background: var(--color-surface); border-top: 1px solid var(--color-border); padding: var(--space-3) 0; }
.r20-clearbar input { flex: 1 1 18rem; }
.r20-code { color: var(--color-text-muted); font-size: 0.8rem; margin-left: 0.25rem; }
.r20-cleanup-modal { max-width: 760px; }
.r20-cleanup-form { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; margin-bottom: var(--space-3); }
.r20-cleanup-form > label { display: flex; flex-direction: column; gap: var(--space-1); font-size: 0.85rem; }
.r20-cleanup-offset { border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: var(--space-1) var(--space-3); display: flex; gap: var(--space-3); font-size: 0.85rem; }
.r20-cleanup-offset legend { font-size: 0.8rem; color: var(--color-text-muted); padding: 0 var(--space-1); }
.r20-cleanup-gl { margin-top: var(--space-3); }
.r20-cleanup-gl summary { cursor: pointer; color: var(--color-text-muted); font-size: 0.85rem; }
/* ── Invoices ▸ 20000 reconciliation (admin) — builds on the r20- classes above ── */
.r2k-h { font-size: 1rem; margin: var(--space-4) 0 var(--space-2); }
.r2k-indent { padding-left: var(--space-4) !important; }
.r2k-detail { color: var(--color-text-muted); font-size: 0.8rem; margin-top: 0.15rem; max-width: 48rem; }
.r2k-quick { margin: 0; align-self: flex-end; }
.r2k-summary { max-width: 60rem; }
.r2k-summary td:first-child { width: 34rem; }
/* Admin ▸ Accounting ▸ Year-end adjustments (SnapshotAdjustmentsTab) */
.saj-bridge { min-width: 64rem; }
.saj-bridge th.num, .saj-bridge td.num { text-align: right; white-space: nowrap; }
.saj-area-row { cursor: pointer; }
.saj-area-row td:first-child, .saj-area-row td:last-child { white-space: nowrap; }
.saj-area-row:hover td { background: var(--color-surface-hover, rgba(0, 0, 0, 0.03)); }
.saj-untagged { color: var(--color-warning); font-weight: 600; }
.saj-detail > td { background: var(--color-surface-muted, rgba(0, 0, 0, 0.02)); }
.saj-detail-grid { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-start; }
.saj-detail-grid table { width: auto; }
.saj-memo td { color: var(--color-text-muted); }
.saj-group-input { flex: 0 1 16rem !important; }
.saj-method { flex: 0 0 auto; width: auto; }
.saj-wide { flex: 1 1 100%; }
.saj-spacer { flex: 1; }
.r2k-what { min-width: 26rem; }
/* ---------- A-Team Rewards ----------
   Layout reuses the PayKeeper shell classes (paykeeper-home / -section / -tiles) and the shared
   summary-table + stat-card. Only what those don't cover lives here, all on the semantic tokens so
   dark mode follows. State = tinted pill; actions stay on the solid --app-accent buttons. */
/* "What earns points": category band above its displays (Carpet, Hardwood, …) — matches the PDF. */
.ateam-category-heading {
    margin: var(--space-6) 0 var(--space-2);
    padding-bottom: var(--space-1);
    border-bottom: 2px solid var(--color-ateamrewards);
    color: var(--color-ateamrewards);
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
/* Points list builder: category buttons, then displays (left) and the style editor (right). */
.ateam-category-bar { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.ateam-category-btn {
    border: 1px solid var(--color-border); background: var(--color-surface); color: var(--color-text);
    border-radius: 999px; padding: 0.3rem 0.85rem; font-size: 0.8125rem; cursor: pointer;
}
.ateam-category-btn:hover { border-color: var(--color-ateamrewards); }
.ateam-category-btn.active { background: var(--color-ateamrewards); border-color: var(--color-ateamrewards); color: white; }
.ateam-ready-tick { margin-left: 5px; font-weight: 700; color: var(--color-success); }
.ateam-category-btn.active .ateam-ready-tick { color: white; }
.ateam-builder { display: grid; grid-template-columns: minmax(200px, 260px) 1fr; gap: var(--space-4); align-items: start; }
.ateam-builder-display-list { border: 1px solid var(--color-border); border-radius: var(--radius-sm); max-height: calc(100vh - 280px); overflow-y: auto; }
.ateam-builder-editor { min-width: 0; }
.ateam-builder-tools { position: sticky; top: 0; z-index: 2; background: var(--color-bg, #F3F4F6); padding: var(--space-2) 0; }
.ateam-toolbar label.ateam-check, label.ateam-check { flex-direction: row; align-items: center; gap: 0.4rem; display: flex; }
/* Wider than the 1024px .main-content cap (a max-width alone is inert inside it — see .paykeeper-wide):
   the same full-bleed breakout, but capped at 88rem and centred, since the style table needs room for
   name, code, vendor and the inputs. */
.paykeeper-home.ateam-builder-page {
    width: min(100vw, 88rem);
    max-width: none;
    margin-left: calc(50% - min(50vw, 44rem));
    margin-right: calc(50% - min(50vw, 44rem));
}
/* The global form rules make inputs/selects full-width and 40px tall — too big for table rows. */
input.ateam-points-input { width: 6rem; height: 32px; text-align: right; padding: 0 var(--space-2); }
.ateam-builder-table select { width: 5.75rem; height: 32px; padding: 0 1.6rem 0 var(--space-2); background-position: right 0.45rem center; font-size: 0.875rem; }
.ateam-builder-table input.ateam-points-input { font-size: 0.875rem; }
.ateam-builder-tools label.ateam-check { color: var(--color-text); }
.ateam-builder-table td { vertical-align: middle; }
.ateam-row-selected td { background: color-mix(in srgb, var(--color-ateamrewards) 5%, white); }
.modal-ateam-picker { max-width: 560px; width: 95vw; }
.ateam-picker-list { max-height: 55vh; }
@media (max-width: 768px) { .ateam-builder { grid-template-columns: 1fr; } }

.ateam-toolbar { display: flex; gap: var(--space-3); align-items: flex-end; flex-wrap: wrap; margin-bottom: var(--space-4); }
.ateam-toolbar label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.8125rem; color: var(--color-text-muted); }
.ateam-toolbar input[type="search"] { font: inherit; font-size: 1rem; color: var(--color-text); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: 0 var(--space-3); height: 40px; outline: none; }
.ateam-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.summary-table th.ateam-num { text-align: right; }
.ateam-pill { display: inline-block; padding: 0.05rem 0.5rem; border-radius: 999px; font-size: 0.72rem; font-weight: 600; border: 1px solid transparent; white-space: nowrap; }
.ateam-pill-draft     { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning); }
.ateam-pill-approved,
.ateam-pill-published { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success); }
.ateam-pill-muted     { background: var(--color-bg); color: var(--color-text-muted); border-color: var(--color-border); }
.ateam-pill-issue     { background: var(--color-danger-bg); color: var(--color-danger); border-color: var(--color-danger); }
.ateam-pill-info      { background: var(--color-info-bg); color: var(--color-info); border-color: var(--color-info); }
.ateam-msg { padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); margin: var(--space-3) 0; border: 1px solid; }
.ateam-msg-error { background: var(--color-danger-bg); color: var(--color-danger); border-color: var(--color-danger); }
.ateam-msg-ok    { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success); }
.ateam-msg-warn  { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning); }
.summary-table tr.ateam-row-issue td { background: var(--color-danger-bg); }
.summary-table tr.ateam-row-excluded td { color: var(--color-text-subtle); text-decoration: line-through; }
.summary-table tr.ateam-row-excluded td:last-child { text-decoration: none; }
.ateam-sub { display: block; font-size: 0.75rem; color: var(--color-text-muted); }
.ateam-table-wrap { overflow-x: auto; }
.ateam-points-neg { color: var(--color-danger); }

/* A-Team Rewards ▸ Targets */
/* Full-width (user 2026-09-27): .paykeeper-wide breaks out of the 1024px .main-content cap. */
.targets-page { max-width: none; }
.targets-fy { display: flex; align-items: center; gap: var(--space-2); font-size: 0.875rem; }
.targets-fy select { width: auto; height: 34px; }
.targets-header-actions { margin-left: auto; display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* The file picker lies invisibly over its button, so the button keeps the app's button styling. */
.targets-file-button { position: relative; display: inline-flex; }
.targets-file-button input[type=file] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.targets-file-button input[type=file]:disabled { cursor: not-allowed; }
.targets-grid th, .targets-grid td { white-space: nowrap; }
.targets-grid .num { text-align: right; }
.targets-grid td.num { font-variant-numeric: tabular-nums; }
.targets-locked { color: var(--color-text-muted); }
.targets-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3); }
.targets-tiers { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: var(--space-3); max-width: 60rem; align-items: end; }
.targets-log-summary { white-space: pre-line; font-size: 0.8125rem; }
.targets-modal { max-width: 900px; width: 95vw; }
.targets-fill { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); font-size: 0.875rem; }
.targets-fill select, .targets-fill input { width: auto; height: 32px; }
.targets-fill input { width: 6.5rem; }
.targets-edit .num { text-align: right; }
.targets-edit input { width: 7rem; height: 32px; text-align: right; }
.targets-row-off td { color: var(--color-text-muted); }

/* A-Team Rewards ▸ Personal results */
.personal-results th, .personal-results td { white-space: nowrap; }
.personal-results .num { text-align: right; font-variant-numeric: tabular-nums; }
.personal-hit { color: var(--color-success); font-weight: 700; margin-right: 0.25rem; }
.personal-miss { color: var(--color-text-muted); margin-right: 0.25rem; }
.personal-zero td { color: var(--color-text-muted); }
.personal-note { display: block; font-size: 0.75rem; color: var(--color-warning, #b45309); white-space: normal; }

/* A-Team Rewards ▸ My targets */
.my-targets-card { max-width: 36rem; }
.my-targets-card .num, .my-targets-year .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.my-targets-total { margin: var(--space-3) 0 var(--space-1); font-size: 1rem; }
.my-targets-tiers { font-size: 0.8125rem; }
.my-targets-year td { white-space: nowrap; }
.my-targets-selected td { background: var(--color-bg); font-weight: 600; }
.my-targets-layout { display: grid; grid-template-columns: minmax(0, 36rem) minmax(14rem, 20rem); gap: var(--space-5); align-items: start; }
.my-targets-points { border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-3) var(--space-4); }
.my-targets-points h4 { margin: 0 0 var(--space-2); }
.my-targets-points .num { text-align: right; white-space: nowrap; }
.my-targets-points p { font-size: 0.8125rem; margin: var(--space-2) 0 0; }
.my-targets-step-current td { background: var(--color-success-bg); font-weight: 700; }
@media (max-width: 760px) { .my-targets-layout { grid-template-columns: 1fr; } }
/* My targets — summary strip, target bars, five dots (user, 2026-09-25). A-Team indigo is used as the BRAND
   colour here (--color-ateamrewards), not --app-accent, which is reserved for controls; a hit is success green. */
.my-targets-stats { margin: var(--space-3) 0 var(--space-4); }
.my-targets-stat-month { font-size: 1.25rem; }
.my-targets-of { font-size: 0.9rem; font-weight: 600; color: var(--color-text-muted); }
.my-targets-stat-earned .stat-number { color: var(--color-ateamrewards); }
.my-targets-stats .stat-label { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

.my-targets-bars { display: flex; flex-direction: column; gap: var(--space-3); }
.my-targets-bar-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); margin-bottom: 0.3rem; }
.my-targets-bar-label { font-weight: 600; }
.my-targets-bar-figures { white-space: nowrap; font-variant-numeric: tabular-nums; }
.my-targets-bar { height: 10px; border-radius: 999px; background: color-mix(in srgb, var(--color-ateamrewards) 10%, var(--color-bg)); overflow: hidden; }
/* A missed target's progress is a SOFT indigo (user, 2026-09-25) so it doesn't read as success; a hit is solid green. */
.my-targets-bar-fill { height: 100%; border-radius: 999px; background: color-mix(in srgb, var(--color-ateamrewards) 35%, white); transition: width 0.4s ease; }
.my-targets-bar-row.is-hit .my-targets-bar-fill { background: var(--color-success); }

.my-targets-dots { display: inline-flex; gap: 4px; vertical-align: middle; margin-right: var(--space-1); }
.my-targets-dot { width: 10px; height: 10px; border-radius: 50%; border: 1.5px solid color-mix(in srgb, var(--color-ateamrewards) 45%, white); background: transparent; }
.my-targets-dot.is-hit { background: var(--color-ateamrewards); border-color: var(--color-ateamrewards); }
.my-targets-pill { display: inline-block; padding: 0.1rem 0.55rem; border-radius: 999px; font-weight: 700; font-variant-numeric: tabular-nums;
    background: color-mix(in srgb, var(--color-ateamrewards) 12%, white); color: var(--color-ateamrewards); }
/* A-Team Rewards home make-over (user, 2026-09-25). Points SOURCES get categorical colours — deliberately not the
   semantic success/warning/info tokens, which mean something else: Vendor = the A-Team indigo, Personal = teal,
   Team = magenta. The same pills colour the History table. */
.ateam-pill-vendor   { background: color-mix(in srgb, var(--color-ateamrewards) 10%, white); color: var(--color-ateamrewards); border-color: color-mix(in srgb, var(--color-ateamrewards) 40%, white); }
.ateam-pill-personal { background: color-mix(in srgb, #0f766e 10%, white); color: #0f766e; border-color: color-mix(in srgb, #0f766e 40%, white); }
.ateam-pill-team     { background: color-mix(in srgb, #be185d 10%, white); color: #be185d; border-color: color-mix(in srgb, #be185d 40%, white); }
.home-source-fill.ateam-pill-vendor   { background: var(--color-ateamrewards); }
.home-source-fill.ateam-pill-personal { background: #0f766e; }
.home-source-fill.ateam-pill-team     { background: #be185d; }
.home-source-fill.ateam-pill-muted    { background: var(--color-text-muted); }

.home-payout-bar { margin-top: var(--space-2); align-self: stretch; }   /* stat cards centre their children — a bar needs the full width */
.home-payout-bar.is-hit .my-targets-bar-fill { background: var(--color-success); }
.home-personal-card { text-decoration: none; color: inherit; transition: border-color 0.15s ease, box-shadow 0.15s ease; }
.home-personal-card:hover { border-color: color-mix(in srgb, var(--color-ateamrewards) 45%, white); box-shadow: var(--shadow-sm); }
.home-sources { max-width: 40rem; margin-top: var(--space-2); }
.home-sources h4 { margin: 0 0 var(--space-2); }
.home-source-row { display: grid; grid-template-columns: 5.5rem 1fr 6rem; align-items: center; gap: var(--space-3); margin-bottom: var(--space-2); }
.home-source-row .ateam-pill { justify-self: start; }
.home-source-points { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }

/* Reporter ▸ Manager reports check screen: dense month grid, grey every other month like the workbook. */
.manager-reports-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: var(--space-3) 0; }
.manager-reports-controls label { display: flex; align-items: center; gap: var(--space-2); }
.manager-reports-warnings { margin: var(--space-3) 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface); }
.manager-reports-warnings summary { cursor: pointer; font-weight: 600; }
.manager-reports-table { font-size: 0.8rem; font-variant-numeric: tabular-nums; }
.manager-reports-table th, .manager-reports-table td { padding: var(--space-2) var(--space-3); white-space: nowrap; }
.manager-reports-table td:first-child { white-space: normal; min-width: 9rem; }
.manager-reports-table tfoot td { font-weight: 700; border-top: 2px solid var(--color-near-black); }
.manager-reports-table td.num, .manager-reports-table th.num { text-align: right; }

/* A-Team Rewards ▸ Targets ▸ Team points / Store staff */
.team-points-grid td input[type=number] { width: 7rem; text-align: right; }
.team-points-grid th, .team-points-grid td { white-space: nowrap; }
.store-staff-grid td { vertical-align: top; }
.store-staff-person { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.store-staff-person.is-ended { opacity: 0.55; }
.store-staff-heading { margin-top: var(--space-6); }
.store-staff-succession { max-width: 44rem; }
.store-staff-succession input[type=number] { width: 8rem; }

/* A-Team Rewards ▸ Team results (batch page, standings) */
.team-results { font-variant-numeric: tabular-nums; }
.team-results td.num, .team-results th.num { text-align: right; }
.team-results tr.team-results-winner td { font-weight: 600; }
.team-results tr.team-results-out td { opacity: 0.55; }

/* A-Team Rewards ▸ Standings: a podium for the top 3, then the rest (user 2026-09-26: highlight top performers). */
.standings-head { display: flex; align-items: center; gap: var(--space-3); }
.standings-head h3 { margin: 0; }
.standings-podium { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: var(--space-3); margin: var(--space-3) 0; }
.standings-card { border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface); padding: var(--space-4);
    display: flex; flex-direction: column; gap: var(--space-1); box-shadow: var(--shadow-sm); border-top: 4px solid var(--color-ateamrewards); }
.standings-card.place-1 { border-top-color: #C9A227; background: color-mix(in srgb, #C9A227 7%, var(--color-surface)); }
.standings-card.place-2 { border-top-color: #9CA3AF; }
.standings-card.place-3 { border-top-color: #B87333; }
.standings-place { font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-text-muted); }
.standings-name { font-size: 1.1rem; font-weight: 700; }
.standings-value { font-size: 1.25rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.standings-card .my-targets-pill { align-self: flex-start; }
.standings-table { font-variant-numeric: tabular-nums; }   /* full width, lined up with the podium (user 2026-09-27) */
.standings-table td.num { text-align: right; white-space: nowrap; }
.standings-table tr.standings-mine td { font-weight: 700; background: color-mix(in srgb, var(--color-ateamrewards) 8%, var(--color-surface)); }
.standings-table tr.standings-gap td { text-align: center; color: var(--color-text-muted); padding: 0.1rem; }

/* ── PayKeeper: pending changes list (Post Changes) ─────── */
/* One row per proposal instead of the old 11-column table. Type chips are tinted (state, not action); an
   overdue row (effective date passed, still not accepted) gets the warning tint — those are the ones the
   approver needs first. See PostEmployeeChanges.razor. */
.pk-pending-heading .pk-pending-count,
.pk-pending-heading .pk-pending-overdue-count { font-size: 0.8125rem; font-weight: 400; color: var(--color-text-muted); }
.pk-pending-heading .pk-pending-overdue-count { color: var(--color-warning); }
.pk-pending-list { border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface); }
.pk-pending-item {
    display: flex;
    gap: var(--space-4);
    align-items: flex-start;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-border);
}
.pk-pending-item:last-child { border-bottom: none; }
.pk-pending-item:first-child { border-top-left-radius: var(--radius); border-top-right-radius: var(--radius); }
.pk-pending-item:last-child { border-bottom-left-radius: var(--radius); border-bottom-right-radius: var(--radius); }
.pk-pending-item-overdue { background: var(--color-warning-bg); }
.pk-pending-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.pk-pending-title { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); }
.pk-pending-name { font-weight: 600; font-size: 0.95rem; }
.pk-pending-type {
    font-size: 0.75rem;
    font-weight: 600;
    padding: 1px var(--space-2);
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    white-space: nowrap;
}
.pk-pending-type-1 { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success-border); }
.pk-pending-type-3 { background: var(--color-info-bg); color: var(--color-info); border-color: var(--color-info-border); }
.pk-pending-type-2 { background: var(--color-danger-bg); color: var(--color-danger); border-color: var(--color-danger-border); }
.pk-pending-when { font-size: 0.8125rem; color: var(--color-text-muted); }
.pk-pending-when-overdue { color: var(--color-warning); font-weight: 600; }
.pk-pending-what { font-size: 0.875rem; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.35rem; }
.pk-pending-from { color: var(--color-text-muted); text-decoration: line-through; }
.pk-pending-arrow { color: var(--color-text-muted); }
.pk-pending-muted { color: var(--color-text-muted); }
.pk-pending-sep { color: var(--color-text-muted); }
.pk-pending-meta { font-size: 0.8125rem; color: var(--color-text-muted); display: flex; flex-wrap: wrap; gap: 0 0.35rem; }
.pk-pending-notes { font-size: 0.8125rem; color: var(--color-text-muted); font-style: italic; overflow-wrap: anywhere; }
.pk-pending-actions { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; }
.pk-pending-more { position: relative; }
.pk-pending-cancel-item { color: var(--color-danger); }
@media (max-width: 700px) {
    .pk-pending-item { flex-direction: column; align-items: stretch; }
    .pk-pending-actions { justify-content: flex-end; }
}
/* The row just posted from the form below the queue — an accent edge so it's findable after the scroll. */
.pk-pending-item-new { box-shadow: inset 3px 0 0 var(--color-info); }
.pk-pending-item { position: relative; }
/* Scroll target only: absolutely placed so it spans the row without taking part in the flex layout. */
.pk-pending-anchor { position: absolute; top: 0; left: 0; width: 0; height: 100%; pointer-events: none; }
/* ── Compufloor outage banner ───────────────────────────── */
/* Top of the page content (normal flow, so it pushes content down rather than covering it) while the API
   can't reach Compufloor. See CompufloorBanner / CompufloorStatusService. Danger tint: most of OrderWriter
   is broken while it shows. */
.cuf-banner {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--color-danger-bg);
    border: 1px solid var(--color-danger-border);
    border-left: 4px solid var(--color-danger);
    border-radius: var(--radius);
    color: var(--color-text);
    font-size: 0.875rem;
}
.cuf-banner-text { flex: 1; }
.cuf-banner-text strong { color: var(--color-danger); }
.cuf-banner-btn {
    flex: 0 0 auto;
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-danger-border);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius);
    font-weight: 600;
    font-size: 0.8125rem;
    white-space: nowrap;
    cursor: pointer;
}
.cuf-banner-btn:hover:not(:disabled) { border-color: var(--color-danger); }
@media (max-width: 600px) { .cuf-banner { flex-direction: column; align-items: stretch; } }

/* ── PriceLister ▸ Stocking Programs ───────────────────────────────────────────────────────────── */
.stock-toolbar { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; margin: var(--space-3) 0; }
.stock-toolbar-spacer { flex: 1; }
.stock-grow { flex: 1 1 16rem; }
.stock-grow input { width: 100%; }
.stock-message { margin: var(--space-2) 0; font-weight: 600; }
.stock-table-wrap { overflow-x: auto; margin-bottom: var(--space-4); }
.stock-table td { vertical-align: middle; }
.stock-sub { display: block; font-size: 0.75rem; color: var(--color-text-muted); font-weight: 400; }
.stock-uom { font-size: 0.75rem; color: var(--color-text-muted); }
.stock-qty-line { display: block; }
.stock-ho-input { display: inline-flex; align-items: center; gap: 2px; white-space: nowrap; }
.stock-ho-input input { width: 4rem; text-align: right; }
.stock-warn-text { color: var(--color-warning); }
.stock-total-row td { font-weight: 700; border-top: 2px solid var(--color-border); }
/* Programs list: the Program column wraps within a fixed range instead of growing to fit long names and vendor lines. */
.stock-programs-table thead th:first-child, .stock-programs-table tr.drill-row td:first-child { min-width: 11rem; max-width: 17rem; white-space: normal; overflow-wrap: anywhere; }
.stock-programs-table thead th.stock-sortable { white-space: normal; vertical-align: bottom; }
/* A category's header row carries its subtotals; the category name folds the group away. */
.stock-group-row td { background: var(--color-bg); font-weight: 600; border-top: 1px solid var(--color-border); }
.stock-fold { display: inline-flex; align-items: baseline; gap: var(--space-2); background: none; border: none; padding: 0; height: auto; cursor: pointer; font: inherit; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text); text-align: left; }
.stock-fold-count { text-transform: none; letter-spacing: normal; font-weight: 400; color: var(--color-text-muted); }
/* Annual ROI against the hurdle: pays for itself (green), getting there (amber), not (red). */
.stock-roi { display: inline-block; padding: 0 var(--space-2); border-radius: 999px; }
.stock-roi-pass { background: var(--color-success-bg); color: var(--color-success); font-weight: 600; }
.stock-roi-near { background: var(--color-warning-bg); color: color-mix(in srgb, var(--color-warning) 75%, black); font-weight: 600; }
.stock-roi-fail { background: var(--color-danger-bg); color: var(--color-danger); font-weight: 600; }
.stock-flag { color: var(--color-warning); margin-left: var(--space-1); cursor: help; }
.stock-howto { max-width: 70ch; margin: 0 0 var(--space-3); }
.stock-howto summary { cursor: pointer; color: var(--app-accent-dark); font-size: 0.875rem; font-weight: 600; }
.stock-howto p { color: var(--color-text-muted); font-size: 0.875rem; margin: var(--space-2) 0 0; }
.stock-built-line { font-size: 0.8125rem; }
/* Status is a state, so a tinted pill: "Active" is the in-force selection family (accent tint), the others neutral. */
.stock-status { display: inline-block; padding: 0 var(--space-2); border-radius: 999px; font-size: 0.75rem; font-weight: 600; border: 1px solid var(--color-border); color: var(--color-text-muted); }
.stock-status-active { background: var(--app-accent-bg); border-color: var(--app-accent-border); color: var(--app-accent-dark); }
.stock-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-3); align-items: flex-start; }
.stock-head h2 { margin-bottom: var(--space-1); }
.stock-head-sub { color: var(--color-text-muted); margin: 0; }
.stock-head-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.stock-built { margin: var(--space-2) 0; }
.stock-notes-link { margin-left: var(--space-2); color: color-mix(in srgb, var(--color-warning) 75%, black); }
.stock-notes-pre { white-space: pre-wrap; font-size: 0.75rem; max-height: 16rem; overflow: auto; background: var(--color-bg); padding: var(--space-3); border-radius: var(--radius-sm); margin: 0 0 var(--space-4); }
.stock-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: var(--space-6); }
.stock-two-col { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-6); margin-bottom: var(--space-6); }
@media (max-width: 900px) { .stock-two-col { grid-template-columns: minmax(0, 1fr); } }
.stock-walk td:first-child { color: var(--color-text-muted); }
.stock-walk-sub td { font-weight: 600; }
.stock-walk-sub td:first-child, .stock-walk-total td:first-child { color: var(--color-text); }
.stock-walk-total td { font-weight: 700; border-top: 2px solid var(--color-border); }
.stock-spark { vertical-align: middle; }
.stock-spark-base { stroke: var(--color-border); stroke-width: 1; }
.stock-spark-line { fill: none; stroke: var(--app-accent); stroke-width: 1.5; }
.stock-spark-label { font-size: 0.8125rem; margin-left: var(--space-1); }
.stock-ledger td, .stock-ledger th { padding: var(--space-2) var(--space-3); font-size: 0.8125rem; }
.stock-ref span { margin-right: var(--space-2); }
.stock-nowrap-cell { white-space: nowrap; }
.stock-editor-modal { max-width: 720px; width: 95vw; }
.stock-editor-delete { margin-right: auto; }
.stock-other-link { display: block; max-width: 100%; height: auto; margin-top: var(--space-3); text-align: left; white-space: normal; line-height: 1.4; }

/* By month: net profit columns over a month-end stock line, two small charts sharing the month axis. */
.stock-chart { display: block; width: 100%; height: auto; }
.stock-chart-readout { font-size: 0.8125rem; margin: 0 0 var(--space-2); color: var(--color-text-muted); }
.stock-chart-readout strong { color: var(--color-text); }
.stock-chart-title { fill: var(--color-text); font-size: 13px; font-weight: 600; }
.stock-chart-tick { fill: var(--color-text-muted); font-size: 12px; }
.stock-chart-axis { stroke: var(--color-border); stroke-width: 1; }
.stock-chart-bar { fill: var(--app-accent); }
.stock-chart-bar-neg { fill: var(--color-orange); }
.stock-chart-dim { opacity: 0.45; }
.stock-chart-line { fill: none; stroke: var(--app-accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.stock-chart-area { fill: var(--app-accent); opacity: 0.1; }
.stock-chart-cross { stroke: var(--color-text-subtle); stroke-width: 1; }
.stock-chart-dot { fill: var(--app-accent); stroke: var(--color-surface); stroke-width: 2; }
.stock-chart-hit { fill: transparent; cursor: crosshair; }

/* Breakdown: by buy / store / colour. */
.stock-by { display: inline-flex; border: 1px solid var(--color-border); border-radius: var(--radius-sm); overflow: hidden; margin-bottom: var(--space-3); }
.stock-by button { height: 34px; padding: 0 var(--space-4); background: var(--color-surface); border: none; border-radius: 0; cursor: pointer; font-weight: 600; font-size: 0.8125rem; color: var(--color-text); }
.stock-by button + button { border-left: 1px solid var(--color-border); }
.stock-by button span { font-weight: 400; color: var(--color-text-muted); margin-left: var(--space-1); }
.stock-by button.stock-by-on { background: var(--app-accent-bg); color: var(--app-accent-dark); box-shadow: inset 0 0 0 1px var(--app-accent-border); }

/* Movements: a side panel over the page, opened from any figure. */
.stock-panel-backdrop { position: fixed; inset: 0; background: rgba(31,33,36,0.35); z-index: 205; }
.stock-panel { position: fixed; top: 0; right: 0; bottom: 0; width: min(820px, 100vw); background: var(--color-surface); box-shadow: var(--shadow-lg); z-index: 210; overflow-y: auto; padding: var(--space-4) var(--space-5); outline: none; }
.stock-panel-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-2); }
.stock-panel-head h3 { margin: 0; }
.stock-panel-close { background: none; border: none; font-size: 1.75rem; line-height: 1; height: auto; padding: 0 var(--space-2); cursor: pointer; color: var(--color-text-muted); }
.stock-panel-close:hover { color: var(--color-text); }
.stock-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; margin-bottom: var(--space-2); }
.stock-chip { display: inline-flex; align-items: center; gap: var(--space-1); padding: 0 var(--space-2); border-radius: 999px; font-size: 0.8125rem; background: var(--app-accent-bg); border: 1px solid var(--app-accent-border); color: var(--app-accent-dark); }
.stock-panel-filters { margin-bottom: var(--space-2); }
.stock-panel-filters summary { cursor: pointer; color: var(--app-accent-dark); font-size: 0.8125rem; font-weight: 600; }
.stock-panel-hint { font-size: 0.75rem; margin-top: 0; }

/* Setup: the program's facts, its colours, the costs Compufloor doesn't carry. */
.stock-setup-section { margin-bottom: var(--space-6); }
.stock-setup-head { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
.stock-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-1) var(--space-4); margin: var(--space-2) 0; font-size: 0.875rem; }
.stock-facts dt { color: var(--color-text-muted); }
.stock-facts dd { margin: 0; }
.stock-notes-text { white-space: pre-wrap; }
.stock-store-picks { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: var(--space-1) var(--space-3); max-height: 14rem; overflow-y: auto; }
.stock-store-pick { display: flex; gap: var(--space-2); align-items: center; font-size: 0.8125rem; font-weight: 400; }
/* The shared .add-item-grid stretches every input to full width; checkboxes and radios must keep their own size. */
.stock-editor-modal .add-item-grid input[type=checkbox], .stock-editor-modal .add-item-grid input[type=radio] { width: auto; flex: none; }
.stock-segmented { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid var(--color-border); border-radius: var(--radius-sm); overflow: hidden; }
.stock-segmented button { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; height: auto; background: var(--color-surface); border: none; border-radius: 0; padding: var(--space-2) var(--space-3); text-align: left; cursor: pointer; font-weight: 600; color: var(--color-text); }
.stock-segmented button + button { border-left: 1px solid var(--color-border); }
.stock-segmented button span { display: block; font-weight: 400; font-size: 0.75rem; color: var(--color-text-muted); }
.stock-segmented button.stock-seg-on { background: var(--app-accent-bg); color: var(--app-accent-dark); box-shadow: inset 0 0 0 1px var(--app-accent-border); }
.stock-link-btn { background: none; border: none; padding: 0; color: var(--app-accent-dark); text-decoration: underline; cursor: pointer; font: inherit; }
.stock-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.stock-sortable:hover { text-decoration: underline; }
.stock-start-callout { border: 1px solid var(--app-accent-border); background: var(--app-accent-bg); border-radius: var(--radius-sm); padding: var(--space-3); margin: var(--space-3) 0; display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.stock-vendor-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-bottom: var(--space-1); }
.stock-vendor-chip { display: inline-flex; align-items: center; gap: var(--space-1); padding: 0 var(--space-2); border-radius: 999px; font-size: 0.8125rem; background: var(--app-accent-bg); border: 1px solid var(--app-accent-border); color: var(--app-accent-dark); }
.stock-chip-x { background: none; border: none; padding: 0 2px; cursor: pointer; color: inherit; font-size: 1rem; line-height: 1; }
.stock-vendor-results { display: flex; flex-direction: column; border: 1px solid var(--color-border); border-radius: var(--radius-sm); max-height: 12rem; overflow-y: auto; margin-top: var(--space-1); }
.stock-vendor-result { text-align: left; background: var(--color-surface); border: none; border-bottom: 1px solid var(--color-border); padding: var(--space-2) var(--space-3); cursor: pointer; font-size: 0.8125rem; }
.stock-vendor-result:hover { background: var(--color-bg); }

/* ── GoalTender ──────────────────────────────────────────── */
.gt-intro { max-width: 70ch; margin-bottom: var(--space-4); }
.gt-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: var(--space-3); margin-top: var(--space-3); }
.gt-tile { display: flex; flex-direction: column; gap: var(--space-1); text-align: left; padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); color: inherit; font: inherit; }
/* The global button rule makes buttons 40px, centred and nowrap; a tile is a card, so undo all three. */
button.gt-tile { cursor: pointer; height: auto; align-items: flex-start; justify-content: flex-start; white-space: normal; line-height: 1.4; }
button.gt-tile:hover { border-color: var(--app-accent); box-shadow: 0 0 0 3px var(--app-accent-ring); }
.gt-tile-title { font-weight: 600; color: var(--app-accent-dark); }
.gt-tile-text { font-size: 0.875rem; color: var(--color-text-muted, #6b7280); }
.gt-tile-soon { opacity: 0.6; }
.gt-summaries { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: var(--space-3); margin-bottom: var(--space-4); }
.gt-summary { padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); display: flex; flex-direction: column; gap: var(--space-2); }
.gt-summary-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-2); }
.gt-summary-name { font-weight: 600; }
.gt-summary-figures { display: flex; gap: var(--space-5, 1.5rem); }
.gt-summary-figures > div { display: flex; flex-direction: column; }
.gt-figure { font-size: 1.375rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--app-accent-dark); }
.gt-not-visited { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; }
.gt-chip { display: inline-flex; padding: 0 var(--space-2); border-radius: 999px; font-size: 0.75rem; background: var(--app-accent-bg); border: 1px solid var(--app-accent-border); color: var(--app-accent-dark); }
.gt-notes { font-size: 0.8125rem; margin-top: 2px; }
.gt-visit-modal { max-width: 40rem; width: 100%; }
.gt-visit-modal .add-item-grid input[type=checkbox] { width: auto; flex: none; }
/* The form-row label style (uppercase, small caps spacing) would otherwise apply to each attendee. */
.gt-visit-modal .stock-store-picks { grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.gt-visit-modal .stock-store-pick { text-transform: none; letter-spacing: normal; font-size: 0.875rem; color: var(--color-text); }
.gt-visit-modal .stock-store-pick .muted-inline { font-size: 0.75rem; }

/* GoalTender target setting */
.gt-plan-head { display: flex; justify-content: space-between; align-items: center; margin: var(--space-2) 0 var(--space-3); }
.gt-plan-head > div { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline; }
.gt-status { font-size: 0.75rem; font-weight: 600; padding: 1px var(--space-2); border-radius: 999px; }
.gt-status-draft { background: var(--color-warning-bg, #fef3c7); color: #92400e; }
.gt-status-agreed { background: var(--color-success-bg, #dcfce7); color: #166534; }
.gt-unsaved { font-size: 0.75rem; color: #92400e; font-weight: 600; }
.gt-panel { border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); padding: var(--space-3); margin-bottom: var(--space-3); }
.gt-h3 { font-size: 0.9375rem; margin: 0 0 var(--space-2); }
.gt-presets { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; margin-bottom: var(--space-3); }
/* The Year to date / This month switch sits on the toolbar row, the height of the As-of date box beside it. */
.stock-toolbar .gt-period { margin-bottom: 0; flex-wrap: nowrap; }
.stock-toolbar .gt-period .btn-sm { height: 40px; }
.gt-on { background: var(--app-accent) !important; color: #fff !important; border-color: var(--app-accent) !important; }
.gt-kpis { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-5, 20px); align-items: flex-end; }
.gt-kpis > div { display: flex; flex-direction: column; gap: 2px; }
.gt-kpis b { font-size: 1.125rem; font-variant-numeric: tabular-nums; font-weight: 600; }
.gt-kpis input { width: 9rem; }
.gt-kpi-total b { color: var(--app-accent-dark); font-size: 1.375rem; }
.gt-curves { margin-top: var(--space-2); display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); font-variant-numeric: tabular-nums; }
.gt-curve-on { font-weight: 700; color: var(--color-text); }
.gt-settings { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: var(--space-2) var(--space-3); }
.gt-settings label { display: flex; flex-direction: column; gap: 2px; font-size: 0.8125rem; }
.gt-metric-table input, .gt-panel table input { width: 7rem; text-align: right; font-variant-numeric: tabular-nums; }
.gt-metric-table input.gt-in-s { width: 5.5rem; }
/* Every number box on the target page right-aligns, so figures line up with the tables (user, 2026-10-08). */
.gt-panel input[type=number], .gt-panel input.gt-num { text-align: right; font-variant-numeric: tabular-nums; }
/* Static numbers in the target tables line up with the numbers typed in the boxes beside them (user,
   2026-10-08): the boxes get a fixed inner padding and border, and a static figure is inset by the same amount.
   Rows centre vertically so a figure sits level with the box next to it. */
.gt-panel table input { padding: 6px 10px; border-width: 1px; font-size: 0.875rem; }
.gt-panel table td { vertical-align: middle; }
.gt-static { display: inline-block; padding-right: 11px; font-variant-numeric: tabular-nums; }
.gt-mname { font-weight: 600; }
.gt-mdesc { font-size: 0.75rem; }
.gt-missed { font-size: 0.75rem; color: var(--color-danger, #b91c1c); font-weight: 600; }
.gt-link { background: none; border: none; padding: 0; color: var(--app-accent-dark); text-decoration: underline; cursor: pointer; font: inherit; }
.gt-notes-box { width: 100%; }
.gt-drill { max-height: 60vh; overflow-y: auto; }
.gt-drill.gt-drill-full { max-height: none; overflow-y: visible; }
/* Target setting: long column names wrap so the drill-down fits the page width. */
.gt-sc .gt-drill-full .gt-sc-table.gt-sc-drill th { white-space: normal; vertical-align: bottom; }

/* GoalTender results */
.gt-warnings { margin: var(--space-3) 0 0; padding-left: 1.2rem; font-size: 0.8125rem; color: #92400e; }
.gt-drill-panel { background: var(--color-bg); border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: var(--space-3); cursor: default; }
.gt-drill-panel .gt-presets { margin-bottom: var(--space-2); }
.gt-caret { display: inline-block; width: 1.1em; color: var(--app-accent-dark); }
.gt-subrow td { background: var(--app-accent-bg); font-size: 0.8125rem; }
.gt-subrow td:first-child { padding-left: 2.2em; }
/* GoalTender dashboard */
.gt-dash-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); gap: var(--space-3); margin-bottom: var(--space-3); }
.gt-dash-card { display: flex; flex-direction: column; gap: 2px; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); }
.gt-dash-card b { font-size: 1.375rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.gt-dash-hero { border-color: var(--app-accent); box-shadow: inset 4px 0 0 var(--app-accent); }
.gt-dash-hero b { color: var(--app-accent-dark); font-size: 1.75rem; }
.gt-pace { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-2); }
.gt-pace-row { display: grid; grid-template-columns: minmax(10rem, 14rem) 1fr 4.5rem 6rem; gap: var(--space-3); align-items: center; padding: 4px 0; }
.gt-pace-name { font-weight: 600; font-size: 0.875rem; }
.gt-pace-track { position: relative; height: 14px; background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 999px; overflow: visible; }
.gt-pace-bar { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 999px; }
.gt-pace-bar.gt-ok { background: #15803d; } .gt-pace-bar.gt-mid { background: #d97706; } .gt-pace-bar.gt-low { background: #b91c1c; }
.gt-pace-gate { position: absolute; top: -3px; bottom: -3px; width: 2px; background: #6b7280; }
.gt-pace-target { position: absolute; top: -5px; bottom: -5px; width: 2px; background: var(--color-text, #111827); }
.gt-pace-val, .gt-pace-pay { text-align: right; font-variant-numeric: tabular-nums; font-size: 0.875rem; }
.gt-pace-pay { font-weight: 600; }
.gt-heat td.gt-heat-cell, span.gt-heat-cell { font-variant-numeric: tabular-nums; font-weight: 600; }
span.gt-heat-cell { display: inline-block; padding: 0 6px; border-radius: 4px; }
.gt-h0 { background: #fee2e2; color: #991b1b; } .gt-hmid { background: #fef3c7; color: #92400e; } .gt-hfull { background: #dcfce7; color: #166534; }
.gt-hgate { background: #e0e7ff; color: #3730a3; } .gt-hnone { color: var(--color-text-muted, #6b7280); } .gt-hblank { background: transparent; }
.gt-heat-legend { margin-top: var(--space-2); font-size: 0.75rem; }
.gt-dash-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: var(--space-3); }
.gt-attention { margin: 0; padding-left: 1.1rem; font-size: 0.875rem; display: flex; flex-direction: column; gap: 4px; }
@media (max-width: 700px) { .gt-pace-row { grid-template-columns: 1fr 3.5rem; } .gt-pace-track { grid-column: 1 / -1; order: 3; } .gt-pace-pay { display: none; } }

/* GoalTender scorecard (.gt-sc) — the look of the F2027 scenarios page: quiet chrome, tabular numbers, colour
   only where it carries meaning (red = the gate and misses, amber = partial / no data, green = full credit,
   bronze = GoalTender's own accent). Scoped to .gt-sc so the rest of AlexanianOS is untouched. */
.gt-sc {
    --gt-line: #d9e1e7; --gt-muted: #5d6d79; --gt-ink: #14212b;
    --gt-red: #c62f3b; --gt-red-soft: #fbe7e9; --gt-good: #23794a; --gt-good-soft: #e2f2e8;
    --gt-warn: #9a6a05; --gt-warn-soft: #fbf1da;
    --gt-soft: color-mix(in srgb, var(--app-accent) 10%, white);
    max-width: 1480px; font-size: 14px; line-height: 1.45; color: var(--gt-ink);
}
/* .crm-shell spans the whole window from its left edge, so a max-width alone left GoalTender pages hugging the left.
   Centre the content instead: the side padding grows to keep it at most 1480px wide in the middle. */
.crm-shell.gt-sc { max-width: none; padding-left: max(var(--space-6), calc((100vw - 1480px) / 2)); padding-right: max(var(--space-6), calc((100vw - 1480px) / 2)); }
.gt-sc h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 0; }
.gt-sc .gt-num { font-variant-numeric: tabular-nums; }
.gt-sc-muted { color: var(--gt-muted); }
.gt-sc .gt-small { font-size: 12px; }
.gt-eyebrow { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--gt-muted); font-weight: 600; }
.gt-sc-head { display: flex; flex-wrap: wrap; gap: 12px 24px; align-items: flex-end; justify-content: space-between;
              padding-bottom: 12px; margin-bottom: 16px; border-bottom: 2px solid var(--app-accent); }
.gt-sc-who { display: grid; gap: 2px; }
/* Segmented switch: one bordered group, only the chosen option filled. */
.gt-seg { display: inline-flex; border: 1px solid var(--gt-line); border-radius: 6px; overflow: hidden; background: #fff; flex: none; }
.gt-seg button { font: inherit; font-size: 13px; border: none; border-right: 1px solid var(--gt-line); background: transparent; color: var(--gt-ink); padding: 6px 12px; cursor: pointer; }
.gt-seg button:last-child { border-right: none; }
.gt-seg button:hover { background: var(--gt-soft); }
.gt-seg button.on { background: var(--app-accent); color: #fff; }
.gt-seg-sm button { font-size: 12px; padding: 4px 10px; }
.gt-sc-card { background: #fff; border: 1px solid var(--gt-line); border-radius: 10px; padding: 16px; }
.gt-sc-kpis { display: flex; flex-wrap: wrap; gap: 8px 28px; margin-bottom: 14px; }
.gt-kpi { display: grid; gap: 1px; }
.gt-kpi small { color: var(--gt-muted); font-size: 12px; }
.gt-kpi b { font-weight: 600; font-size: 18px; font-variant-numeric: tabular-nums; }
.gt-kpi-hero b { font-size: 22px; color: var(--app-accent-dark); }
.gt-kpi b.gt-sc-muted { font-size: 15px; line-height: 27px; }
/* The gate band (red goal line) and the stretch band (bronze). */
.gt-band { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px 18px; align-items: center; padding: 12px 14px;
           border-radius: 8px; background: var(--gt-red-soft); border-left: 4px solid var(--gt-red); margin-bottom: 10px; }
.gt-band-stretch { background: var(--gt-soft); border-left-color: var(--app-accent); }
.gt-band-body { display: grid; gap: 6px; min-width: 0; }
.gt-band-lbl { font-weight: 600; }
.gt-band-out { text-align: right; display: grid; }
.gt-band-out b { font-size: 20px; font-weight: 600; }
.gt-meter { position: relative; height: 8px; border-radius: 4px; background: rgba(20, 33, 43, 0.1); margin: 4px 0; }
.gt-meter i { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 4px; background: var(--gt-red); }
.gt-meter-tick { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--gt-muted); }
.gt-meter-goal { position: absolute; top: -5px; bottom: -5px; width: 3px; background: var(--gt-ink); }
.gt-sc-bar { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; margin: 16px 0 8px; }
.gt-sc-select { display: inline-flex; gap: 8px; align-items: center; font-size: 13px; color: var(--gt-muted); }
.gt-sc-select select { font: inherit; color: var(--gt-ink); padding: 5px 8px; border: 1px solid var(--gt-line); border-radius: 6px; background: #fff; }
/* Scorecard tables: small uppercase headers over a hairline, compact rows. */
.gt-sc-wrap { overflow-x: auto; }
.gt-sc-table { border-collapse: collapse; width: 100%; min-width: 680px; }
.gt-sc-table th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--gt-muted); font-weight: 600;
                  text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--gt-line); white-space: nowrap; background: none; }
.gt-sc-table td { padding: 8px; border-bottom: 1px solid var(--gt-line); vertical-align: middle; }
.gt-sc-table .r { text-align: right; white-space: nowrap; }
.gt-sc-table .gt-result { font-weight: 600; }
/* The metric column takes whatever width is left, and its description truncates to fit, so the numbers never scroll away. */
.gt-sc-table .gt-mcell { width: 100%; max-width: 0; min-width: 13rem; }
.gt-sc .gt-mname { font-weight: 600; }
.gt-desc { color: var(--gt-muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gt-swatch { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 7px; vertical-align: 1px; }
.gt-swatch-gate { background: var(--gt-red); }
.gt-nodata { color: var(--gt-warn); font-size: 12px; }
.gt-click { cursor: pointer; }
.gt-click:hover { background: #f7f9fa; }
.gt-open, .gt-open:hover { background: var(--gt-soft); }
.gt-credit { font-variant-numeric: tabular-nums; font-weight: 600; display: inline-block; min-width: 54px; text-align: right; padding: 2px 6px; border-radius: 4px; font-size: 13px; }
.gt-credit.c0 { background: var(--gt-red-soft); color: var(--gt-red); }
.gt-credit.cmid { background: var(--gt-warn-soft); color: var(--gt-warn); }
.gt-credit.cfull { background: var(--gt-good-soft); color: var(--gt-good); }
.gt-gated { display: block; font-size: 11px; color: var(--gt-red); }
.gt-drill-row > td { background: #f7f9fa; padding: 10px 12px; }
.gt-sc .gt-drill-panel { background: none; border: none; padding: 0; }
.gt-sc .gt-drill-panel .gt-sc-bar { margin: 0 0 8px; }
.gt-sc-drill { width: auto; min-width: min(100%, 28rem); background: #fff; border: 1px solid var(--gt-line); border-radius: 6px; }
.gt-sc-drill td:first-child { min-width: 14rem; padding-right: 24px; }
.gt-sc-drill td.r, .gt-sc-drill th.r { padding-left: 24px; }
.gt-sc-drill td { padding: 5px 8px; font-size: 13px; }
.gt-sc-drill tr:last-child td { border-bottom: none; }
.gt-sc .gt-subrow td { background: var(--gt-soft); font-size: 12px; }
/* Floors: one line each with a pill. */
.gt-floors { display: grid; gap: 8px; margin-top: 18px; }
.gt-floor { display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: center; justify-content: space-between; padding: 8px 12px; border: 1px solid var(--gt-line); border-radius: 8px; }
.gt-floor-out { display: flex; gap: 10px; align-items: center; }
.gt-floor-drill { padding: 10px 12px; background: #f7f9fa; border-radius: 8px; }
.gt-pill { font-size: 12px; padding: 2px 8px; border-radius: 999px; font-weight: 600; white-space: nowrap; }
.gt-pill.ok { background: var(--gt-good-soft); color: var(--gt-good); }
.gt-pill.miss { background: var(--gt-red-soft); color: var(--gt-red); }
.gt-pill.wait { background: #eef1f4; color: var(--gt-muted); }
/* Where the bonus comes from: each metric's earnings as a slice of the pool. */
.gt-breakdown { display: grid; gap: 6px; margin-top: 18px; }
.gt-stack { display: flex; height: 16px; border-radius: 4px; overflow: hidden; background: rgba(20, 33, 43, 0.08); }
.gt-stack span { display: block; height: 100%; border-right: 1px solid #fff; }
.gt-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 12px; color: var(--gt-muted); }
.gt-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; vertical-align: 0; }
.gt-legend .gt-swatch-stretch { background: var(--app-accent); opacity: 0.45; }
.gt-sc-foot { margin-top: 14px; color: var(--gt-muted); font-size: 12px; display: grid; gap: 4px; max-width: 80ch; }
@media (max-width: 640px) {
    .gt-sc-card { padding: 12px; }
    .gt-band { grid-template-columns: minmax(0, 1fr); }
    .gt-band-out { text-align: left; }
    /* The exec scorecard on a phone: Metric, Target, Result and Credit only, at the screen's width. */
    .gt-sc-table.gt-scorecard { min-width: 0; }
    .gt-scorecard .gt-m-hide { display: none; }
    .gt-sc .gt-sc-table.gt-scorecard .gt-mcell { min-width: 0; }
    .gt-sc-table.gt-scorecard th, .gt-sc-table.gt-scorecard td { padding-left: 4px; padding-right: 4px; }
    .gt-scorecard .gt-desc { display: none; }
}

/* Scorecard roster: every exec down the left, the selected one marked with a bronze edge; stacks on phones. */
.gt-sc-grid { display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: 18px; align-items: start; }
@media (max-width: 960px) { .gt-sc-grid { grid-template-columns: minmax(0, 1fr); } }
.gt-roster { display: grid; gap: 8px; position: sticky; top: 76px; }
.gt-roster > .gt-eyebrow { margin-top: 6px; }
.gt-roster > .gt-eyebrow:first-child { margin-top: 0; }
.gt-rexec { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 10px; text-align: left; width: 100%; padding: 10px 12px;
            border-radius: 8px; border: 1px solid var(--gt-line); background: #fff; color: var(--gt-ink); font: inherit; cursor: pointer;
            height: auto; white-space: normal; line-height: 1.35; }
.gt-rexec:hover { border-color: var(--app-accent); }
.gt-rexec.sel { border-color: var(--app-accent); box-shadow: inset 3px 0 0 var(--app-accent); background: var(--gt-soft); }
.gt-rwho { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gt-rrole { color: var(--gt-muted); font-size: 12px; }
.gt-rpay { font-size: 15px; text-align: right; }
.gt-rof { font-size: 12px; color: var(--gt-muted); text-align: right; }
.gt-rmeter { grid-column: 1 / -1; height: 5px; border-radius: 3px; background: rgba(20, 33, 43, 0.1); overflow: hidden; margin-top: 6px; }
.gt-rmeter i { display: block; height: 100%; background: var(--app-accent); }
.gt-rpeople { margin-top: 6px; padding: 10px 12px; border: 1px dashed var(--gt-line); border-radius: 8px; display: grid; gap: 4px; font-size: 13px; }
.gt-rpeople div { display: flex; justify-content: space-between; gap: 8px; }
@media (max-width: 960px) { .gt-roster { position: static; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
                            .gt-roster > .gt-eyebrow, .gt-rpeople { grid-column: 1 / -1; } }
/* Phones: the roster is one swipeable row of cards, so the scorecard is right below it. */
@media (max-width: 640px) {
    .gt-roster { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 13.5rem; overflow-x: auto; padding-bottom: 4px; scroll-snap-type: x proximity; }
    .gt-roster > .gt-eyebrow, .gt-rpeople { display: none; }
    .gt-rexec { scroll-snap-align: start; }
}

/* GoalTender pages in the scorecard style: header with its tools on the right, titled cards, compact controls. */
.gt-sc .gt-seg button { height: 32px; line-height: 1; letter-spacing: 0; font-weight: 600; white-space: nowrap; }
.gt-sc .gt-seg-sm button { height: 28px; }
.gt-sc-tools { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-end; }
.gt-sc-field { display: grid; gap: 2px; font-size: 12px; color: var(--gt-muted); }
.gt-sc .gt-sc-field input, .gt-sc .gt-sc-field select { width: auto; height: 32px; font-size: 13px; padding: 0 8px; border: 1px solid var(--gt-line); border-radius: 6px; background-color: #fff; color: var(--gt-ink); }
.gt-sc .gt-sc-field select { padding-right: 28px; background-position: right 8px center; min-width: 14rem; }
.gt-sc-intro { color: var(--gt-muted); font-size: 13px; max-width: 90ch; margin: -6px 0 14px; }
.gt-sc-card + .gt-sc-card, .gt-sc-two + .gt-sc-card, .gt-sc-card + .gt-sc-two { margin-top: 14px; }
.gt-sc-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: 14px; align-items: start; }
.gt-sc-h { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; justify-content: space-between; margin: 0 0 10px; }
.gt-sc-h h2 { font-size: 15px; font-weight: 700; margin: 0; }
.gt-sc-msg { margin: 0 0 12px; font-size: 13px; color: var(--gt-muted); }
.gt-sc-msg.err { color: var(--gt-red); font-weight: 600; }
.gt-sc-table tr.gt-group td { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--gt-muted); font-weight: 600; padding-top: 14px; border-bottom: 1px solid var(--gt-line); }
/* GoalTender meeting groups (CRM / GP / Operations, GP / PK / Inventory): a heading row inside the metric tables. */
.gt-sc-table tr.gt-mgroup td { color: var(--gt-ink); font-size: 12px; }
.gt-sc-table tr.gt-mgroup .gt-ro { margin-left: 6px; text-transform: none; letter-spacing: 0; font-weight: 400; color: var(--gt-muted); }
.gt-sc-table tr.gt-mgroup .gt-ro .gt-link { font-size: 12px; margin-left: 2px; }
.gt-sc-table th.gt-mgroup-h { text-align: left; color: var(--gt-ink); border-bottom: 1px solid var(--gt-line); padding-bottom: 2px; }
.gt-swatch-floor { background: transparent; border: 1.5px solid var(--gt-muted); }
.gt-sc-table tfoot td { font-weight: 600; border-bottom: none; border-top: 2px solid var(--gt-line); }
.gt-sc-table .gt-who { font-weight: 600; }
.gt-sc-table .gt-role { color: var(--gt-muted); font-size: 12px; margin-left: 6px; }
.gt-credit.cgate { background: var(--gt-soft); color: var(--app-accent-dark); }
.gt-credit.cnone { background: none; color: var(--gt-muted); }
.gt-credit.cfloor { min-width: 0; font-family: inherit; }
.gt-chips-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; margin-top: 10px; font-size: 12px; color: var(--gt-muted); }
.gt-chips-legend .gt-credit { min-width: 0; font-size: 11px; padding: 1px 6px; }
/* Pace rows: one meter per exec — the bar coloured by where it stands against the gate and the target. */
.gt-pace2 { display: grid; gap: 2px; }
.gt-pace2-row { display: grid; grid-template-columns: minmax(9rem, 15rem) minmax(0, 1fr) 4.5rem 6.5rem; gap: 14px; align-items: center; padding: 7px 8px; border-radius: 6px; }
.gt-pace2-row .gt-meter { margin: 0; }
.gt-meter i.ok { background: var(--gt-good); }
.gt-meter i.mid { background: var(--gt-warn); }
.gt-meter i.low { background: var(--gt-red); }
.gt-pace2-row .r { text-align: right; }
@media (max-width: 640px) { .gt-pace2-row { grid-template-columns: minmax(0, 1fr) 4rem 5.5rem; } .gt-pace2-row .gt-meter { grid-column: 1 / -1; grid-row: 2; } }
/* Needs attention: one line each, with what kind of problem it is. */
.gt-attn { display: grid; gap: 6px; }
.gt-attn-row { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; justify-content: space-between; padding: 7px 10px; border: 1px solid var(--gt-line); border-radius: 8px; }
.gt-attn-row { flex-wrap: nowrap; align-items: flex-start; }
.gt-attn-text { display: grid; gap: 1px; min-width: 0; }
.gt-attn-text .gt-sc-muted { font-size: 12px; }
.gt-attn-pills { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }
.gt-sc-table .gt-who, .gt-pace2-row .gt-mname, .gt-rpeople-table td:first-child { white-space: nowrap; }
.gt-rpeople-table td { padding: 6px 8px; }
/* Editable numbers (target setting): compact boxes on a pale ground, right-aligned. Read-only (agreed) plans show
   them as plain text. A static number beside them is padded to line up with the text inside a box. */
.gt-sc .gt-sc-table input, .gt-sc .gt-band input, .gt-sc .gt-sc-set input, .gt-sc .gt-sc-set select, .gt-sc .gt-kpi input.gt-kpi-in {
    width: 7.5rem; height: 30px; font: inherit; font-size: 13px; padding: 0 6px; border: 1px solid var(--gt-line); border-radius: 5px;
    background-color: #f4f7f9; color: var(--gt-ink); text-align: right; font-variant-numeric: tabular-nums; }
.gt-sc .gt-sc-set select { text-align: left; width: auto; padding-right: 26px; background-position: right 7px center; }
.gt-sc input.gt-in-s { width: 4.75rem; }
.gt-sc .gt-kpi input.gt-kpi-in { width: 9rem; height: 32px; margin-top: 2px; font-size: 16px; font-weight: 600; }
.gt-sc .gt-floor input { width: 4.75rem; height: 30px; font: inherit; font-size: 13px; padding: 0 6px; border: 1px solid var(--gt-line); border-radius: 5px; background-color: #f4f7f9; color: var(--gt-ink); text-align: right; font-variant-numeric: tabular-nums; }
/* In the target-setting table the boxes are narrower, so the whole row fits beside the roster. */
.gt-sc .gt-sc-table input.gt-num { width: 6.25rem; }
.gt-sc .gt-sc-table .gt-mcell { min-width: 10rem; }
/* No spinner arrows: they reserve space inside the box, which pushed the numbers off the right edge. */
.gt-sc input[type=number] { -moz-appearance: textfield; }
.gt-sc input[type=number]::-webkit-inner-spin-button, .gt-sc input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.gt-scen .gt-seg { flex-wrap: wrap; }
.gt-sc input:disabled, .gt-sc select:disabled { background-color: transparent; border-color: transparent; opacity: 1; cursor: default; color: var(--gt-ink); background-image: none; }
.gt-sc .gt-static { display: inline-block; padding-right: 7px; font-variant-numeric: tabular-nums; }
.gt-sc-set { display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: flex-start; }
.gt-sc-set label { display: grid; gap: 2px; align-content: start; justify-items: start; font-size: 12px; color: var(--gt-muted); }
.gt-sc .gt-sc-set input, .gt-sc .gt-sc-set select { box-sizing: border-box; height: 30px; margin: 0; }
.gt-sc-set label > span { font-size: 11px; }
.gt-band .gt-band-edit { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: center; }
.gt-band .gt-band-edit label { display: inline-flex; gap: 6px; align-items: center; font-size: 12px; color: var(--gt-muted); }
.gt-band input.gt-in-s { width: 4.25rem; }
.gt-sc-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 10px; }
.gt-sc textarea.gt-sc-notes { width: 100%; font: inherit; font-size: 13px; padding: 8px 10px; border: 1px solid var(--gt-line); border-radius: 6px; background: #f4f7f9; }
.gt-sc textarea.gt-sc-notes:disabled { background: transparent; }
.gt-scen { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; margin-bottom: 12px; }
.gt-curves2 { font-size: 12px; color: var(--gt-muted); display: flex; flex-wrap: wrap; gap: 4px 14px; margin: -6px 0 12px; }
.gt-curves2 .on { color: var(--gt-ink); font-weight: 600; }
.gt-rexec .gt-rstatus { justify-self: end; }
.gt-unsaved2 { font-size: 12px; font-weight: 600; color: var(--gt-warn); }
.gt-sc h2.gt-sc-name { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 0; }
/* Target setting needs the width for its input table, so below 1280px its roster becomes a strip across the top. */
@media (max-width: 1280px) {
    .gt-grid-edit { grid-template-columns: minmax(0, 1fr); }
    .gt-grid-edit .gt-roster { position: static; grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 13.5rem; overflow-x: auto; padding-bottom: 4px; }
    .gt-grid-edit .gt-roster > .gt-eyebrow { display: none; }
}

/* GoalTender home tiles and the visit log, in the scorecard style. */
.gt-sc-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 12px; margin-bottom: 14px; }
button.gt-sc-tile { display: grid; gap: 4px; align-content: start; text-align: left; height: auto; white-space: normal; line-height: 1.4; letter-spacing: 0;
    padding: 14px 16px; border: 1px solid var(--gt-line); border-radius: 10px; background: #fff; color: var(--gt-ink); font: inherit; font-weight: 400; cursor: pointer; }
button.gt-sc-tile:hover { border-color: var(--app-accent); box-shadow: inset 3px 0 0 var(--app-accent); }
.gt-sc-tile-title { font-size: 16px; font-weight: 700; color: var(--app-accent-dark); }
.gt-sc-tile-text { font-size: 13px; color: var(--gt-muted); }
.gt-visit-cards { grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); }
.gt-visit-card { display: grid; gap: 10px; align-content: start; }
.gt-sc-tiles > .gt-sc-card { margin-top: 0; }
.gt-visit-card .gt-sc-kpis { margin-bottom: 0; }
.gt-visit-card .gt-rmeter { margin-top: 0; }
.gt-visit-card .gt-kpi b .gt-sc-muted { font-size: 13px; font-weight: 400; }
.gt-visit-todo { display: grid; gap: 4px; }
.gt-visit-todo > div { display: flex; flex-wrap: wrap; gap: 4px; }
.gt-sc-tools .btn-sm { align-self: flex-end; }

/* Target setting: a metric name opens its F2026 detail; each figure there is coloured against the draft's threshold and target. */
button.gt-mtoggle { display: inline-flex; align-items: center; height: auto; padding: 0; border: none; background: none; font: inherit; font-weight: 600; letter-spacing: 0; color: var(--gt-ink); cursor: pointer; text-align: left; white-space: normal; }
button.gt-mtoggle:disabled { cursor: default; opacity: 1; }
button.gt-mtoggle:not(:disabled):hover { color: var(--app-accent-dark); }
.gt-mtoggle .gt-caret { width: 1em; }
.gt-vs { display: inline-block; padding: 0 5px; border-radius: 4px; }
.gt-sc .gt-sc-table input.gt-wi { width: 6.5rem; height: 26px; }
.gt-sc .gt-sc-table input.gt-wi.changed { background-color: var(--gt-warn-soft); border-color: var(--gt-warn); font-weight: 600; }
.gt-vs.good { background: var(--gt-good-soft); color: var(--gt-good); }
.gt-vs.mid { background: var(--gt-warn-soft); color: var(--gt-warn); }
.gt-vs.low { background: var(--gt-red-soft); color: var(--gt-red); }
.gt-band-out .gt-link { justify-self: end; margin-top: 4px; }
.gt-sc-drill tr.gt-total-row td { font-weight: 600; border-top: 2px solid var(--gt-line); }
.gt-sc-drill tr.gt-group td { padding-top: 12px; text-transform: none; letter-spacing: 0; font-size: 12px; color: var(--app-accent-dark); }
/* A store target's GP window: compact month boxes; blank reads as the whole year. */
.gt-sc .gt-sc-table input.gt-month { width: 8.5rem; text-align: left; }
/* Store GP targets: headers and the totals pill wrap, and the month boxes slim down, so the table fits without a scroll bar. */
.gt-sc .gt-sc-table.gt-store-targets th { white-space: normal; vertical-align: bottom; }
.gt-sc .gt-sc-table.gt-store-targets .gt-pill { white-space: normal; }
.gt-sc .gt-store-targets select.gt-month { width: 6.75rem; height: 30px; font: inherit; font-size: 13px; padding: 0 22px 0 6px; border: 1px solid var(--gt-line);
    border-radius: 5px; background-color: #f4f7f9; background-position: right 6px center; color: var(--gt-ink); }
.gt-sc .gt-store-targets select.gt-month.blank { color: var(--gt-muted); }
/* A blank month box shows only its calendar button, not "--------, ----"; typing or picking fills it. */
.gt-sc input.gt-month.blank:not(:focus)::-webkit-datetime-edit { opacity: 0; }
.gt-sc input.gt-month.blank:not(:focus) { color: transparent; }
.gt-sc .gt-sc-table td div.gt-static { display: block; }
/* The "counts toward attainment" tick on a category store target: a plain checkbox, not a number box. */
.gt-sc .gt-sc-table input.gt-check { width: 16px; height: 16px; padding: 0; accent-color: var(--app-accent); cursor: pointer; }
.gt-sc .gt-sc-table input.gt-check:disabled { cursor: default; }
button.gt-mtoggle.gt-store { white-space: nowrap; }
/* Manager Dashboard opened from GoalTender: a banner saying which figure the locked list explains. */
.gt-md-banner { display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: baseline; padding: 10px 14px; margin-bottom: 12px;
                border-radius: 8px; background: color-mix(in srgb, var(--color-goaltender) 10%, white); border-left: 4px solid var(--color-goaltender); }
.gt-md-eyebrow { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; color: var(--color-goaltender-dark); width: 100%; }
.gt-md-note { flex-basis: 100%; font-size: 12px; color: var(--color-text-muted); }
.tab-bar .gt-md-export { margin-left: auto; }
/* GoalTender drill-downs: every column sorts on click. */
.gt-sc-table th.gt-sortable { cursor: pointer; user-select: none; }
.gt-sc-table th.gt-sortable:hover { color: var(--gt-ink); }
.gt-records { padding: 4px 0; }
/* Links out of GoalTender (Compufloor, Manager Dashboard): plain text with the tools menu's ↗, which takes the accent on hover. */
a.gt-ext, a.gt-ext:visited { color: inherit; text-decoration: none; }
a.gt-ext .gt-ext-icon { margin-left: 4px; color: var(--color-text-muted, #6b7280); font-size: 0.9em; }
a.gt-ext:hover .gt-ext-icon, a.gt-ext:focus-visible .gt-ext-icon { color: var(--app-accent); }
/* Item history and survey pop-ups over the GoalTender drill-downs. */
.modal.gt-item-modal { max-width: min(1100px, 96vw); width: 100%; max-height: 90vh; display: flex; flex-direction: column; }
.gt-item-modal .gt-drill { max-height: 60vh; }
.gt-item-modal .gt-sc-kpis { margin: 4px 0 10px; }
.gt-sc-table td.gt-ref { max-width: 26rem; }
.gt-sc-table td.gt-feedback { min-width: 18rem; max-width: 34rem; white-space: normal; font-size: 12px; }
.gt-sc-table td.gt-neg { color: var(--gt-red); }

/* Admin ▸ Regions: a card per region (stores by name), the move panel, then the per-store table. The page scrolls
   normally — no viewport-capped body (the table is short and there is no pinned action bar). */
.regions-body { display: block; }
.regions-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: var(--space-3); margin: var(--space-3) 0 var(--space-5); align-items: start; }
.regions-card { border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); padding: var(--space-3); font-size: 0.875rem; }
.regions-card-empty { background: var(--color-bg); color: var(--color-text-muted); }
.regions-card-none { border-style: dashed; background: var(--color-bg); }
.regions-card-head { display: flex; align-items: baseline; gap: var(--space-2); margin-bottom: var(--space-2); }
.regions-card-empty .regions-card-head { margin-bottom: 0; }
.regions-manager { font-weight: 600; color: var(--color-text); }
.regions-count { margin-left: auto; font-size: 0.75rem; color: var(--color-text-muted); white-space: nowrap; }
.regions-code { display: inline-block; min-width: 2.2rem; text-align: center; padding: 0.05rem 0.4rem; border-radius: var(--radius-sm); background: color-mix(in srgb, var(--app-accent) 10%, white); color: var(--app-accent); font-weight: 700; font-size: 0.75rem; letter-spacing: 0.04em; }
.regions-store-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.regions-store-num { display: inline-block; min-width: 1.8rem; color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
/* Admin ▸ Shop at Home: reuses the Regions cards. */
.shopathome-card-off { background: var(--color-bg); }
.shopathome-status { font-size: 0.75rem; font-weight: 600; color: var(--app-accent); margin-top: var(--space-2); }
.shopathome-warning { margin: 0 0 var(--space-2); font-size: 0.8rem; }
.shopathome-person { display: flex; align-items: baseline; gap: var(--space-2); cursor: pointer; }
.shopathome-person input { margin: 0; }
.regions-move { border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-5); }
.regions-move h4 { margin: 0 0 var(--space-3); }
.regions-move-fields { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); }
.regions-move-fields > .paykeeper-form-field { flex: 1 1 11rem; }
.regions-move-fields > .regions-move-date { flex: 0 0 10.5rem; }
.regions-move-fields > .regions-move-note { flex: 2 1 16rem; }
.regions-move-hint { margin: var(--space-2) 0 0; }
.regions-table td { vertical-align: middle; }
.regions-row-inactive td { color: var(--color-text-muted); }
.regions-payroll-drift { font-size: 0.75rem; color: var(--color-warning); margin-top: 2px; }
.regions-actions { white-space: nowrap; text-align: right; }
.regions-actions .btn-sm + .btn-sm { margin-left: var(--space-2); }

/* Admin ▸ Accounting ▸ Accrual 20050 ▸ Explain a period */
.r50x-details { margin-top: 0.2rem; font-size: 0.8rem; color: var(--color-text-muted); }
.r50x-details summary { cursor: pointer; }
.r50x-details ul { margin: 0.2rem 0 0.3rem 1.1rem; padding: 0; max-width: 60rem; }
.r50x-details li { margin: 0.1rem 0; }
.r20-defer { display: flex; align-items: center; gap: 0.4rem; align-self: flex-end; max-width: 28rem; font-size: 0.85rem; }

/* ---- Admin ▸ Accounting ▸ Store wind-down ---- */
.wd-h { margin: var(--space-4) 0 var(--space-2); font-size: 1rem; }
.wd-store { width: 5.5rem; }
.wd-qty { width: 6.5rem; }
.wd-note { min-width: 10rem; }
.wd-table td { vertical-align: top; }
.wd-table tr.wd-over td { background: var(--color-danger-bg); }
.wd-bridge { margin-bottom: var(--space-1); }
.wd-actions { display: flex; gap: var(--space-2); align-items: center; margin-top: var(--space-2); }

/* ── Appointments app (placeholder name): Booking problems and Online bookings ───────────────────── */
.ap-header { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-4); }
.ap-header h2 { margin: 0; }
.ap-header .tab-bar a { text-decoration: none; }
.ap-layout { display: grid; grid-template-columns: minmax(16rem, 22rem) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
.ap-list-head { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-3); }
.ap-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.ap-item { width: 100%; height: auto; min-height: 0; text-align: left; display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start;
    gap: 2px; padding: var(--space-2) var(--space-3); line-height: 1.35; white-space: normal; font-weight: 400; color: var(--color-text);
    background: var(--color-bg); border: 1px solid var(--color-border); border-radius: var(--radius); cursor: pointer; }
.ap-item:hover { border-color: #c0c4cc; }
.ap-item-selected { background: var(--app-accent-bg); border-color: var(--app-accent-border); }
.ap-item-resolved { opacity: 0.7; }
.ap-item-title { font-weight: 700; font-size: 0.875rem; }
.ap-item-who { font-size: 0.8125rem; }
.ap-item-when { font-size: 0.75rem; color: var(--color-text-muted); }
.ap-detail { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-4) var(--space-5); min-width: 0; }
.ap-detail-head { display: flex; align-items: center; gap: var(--space-3); }
.ap-detail-head h3 { margin: 0; }
.ap-status { font-size: 0.75rem; font-weight: 700; padding: 2px var(--space-2); border-radius: var(--radius-sm); }
.ap-status-open { background: var(--color-warning-bg); color: var(--color-warning); border: 1px solid var(--color-warning-border); }
.ap-status-resolved { background: var(--color-success-bg); color: var(--color-success); border: 1px solid var(--color-success-border); }
.ap-detail-text { margin: var(--space-2) 0 var(--space-4); }
.ap-subhead { margin: var(--space-4) 0 var(--space-2); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-muted); }
.ap-booking { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-1) var(--space-4); margin: 0; font-size: 0.875rem; }
.ap-booking dt { color: var(--color-text-muted); }
.ap-booking dd { margin: 0; }
.ap-note { white-space: pre-wrap; }
.ap-raw { margin-top: var(--space-3); font-size: 0.8125rem; }
.ap-raw pre { white-space: pre-wrap; word-break: break-word; background: var(--color-bg); padding: var(--space-2); border-radius: var(--radius-sm); max-height: 12rem; overflow: auto; }
.ap-other { margin-top: var(--space-3); }
.ap-form { display: flex; flex-direction: column; gap: var(--space-2); max-width: 28rem; }
.ap-field { display: flex; flex-direction: column; gap: 2px; }
.ap-label { font-size: 0.75rem; font-weight: 600; color: var(--color-text-muted); }
.ap-hint { font-size: 0.75rem; }
.ap-choice { display: flex; align-items: flex-start; gap: 6px; font-size: 0.875rem; cursor: pointer; }
.ap-choice input { margin-top: 3px; }
.ap-form button { align-self: flex-start; }
.ap-resolved { margin-top: var(--space-4); }
.ap-table td { vertical-align: top; }
.ap-row-closed { color: var(--color-text-muted); }
.ap-not-confirmed { font-weight: 600; color: var(--color-warning); }
@media (max-width: 760px) { .ap-layout { grid-template-columns: 1fr; } }

/* The lead card's gold reminder bell, reused inline: on the Notes tab when a reminder is due, and in the
   note feed's "Reminder due" / "Reminder set for" lines (they were an emoji). */
.tab .tab-bell, .tab-active .tab-bell { display: inline-flex; margin-left: 6px; vertical-align: middle; }
.note-bell { display: inline-flex; vertical-align: -2px; margin-right: 4px; }
.note-reminder-badge .note-bell .lead-card-icon { width: 13px; height: 13px; }

/* Appointments ▸ Booking problems tab: how many are still open. Amber, like a reminder: something waiting. */
.ap-tab-badge {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 18px; height: 18px; padding: 0 5px; margin-left: 6px;
    border-radius: 9px; font-size: 0.6875rem; font-weight: 700; line-height: 1;
    color: #fff; background: var(--color-warning);
}
