/* ==========================================================================
   THEME — PAGE CHROME  (1 of 3)
   ==========================================================================
   Sidebar, cards and panels, buttons, inputs, badges, the confirm modal.
   The shell a page sits inside.

   ⛔ SPLIT FROM ONE 2,708-LINE FILE (2026-09-04) so no stylesheet is too long to
   review. Cut at DEPTH-0 BOUNDARIES — points where no rule, media query or
   comment was open — and reconstruction was verified byte-identical.

   ⛔ THE LOAD ORDER IN base.html IS THE CASCADE. These three are separate
   `<link>`s that load AFTER styles.css, so a rule here beats an equally specific
   rule in any @import'ed module on source order. Measured twice while fixing an
   icon leak: a rule in _10-components.css could not win against one here.

   Every rule is scoped `body.laser-theme`, gated by LASER_THEME_ENABLED — which
   defaults to False, so this whole layer is inert unless the flag is on.
   ========================================================================== */

/* ============================================================================
   LASER Holographic — component layer
   ============================================================================

   Companion to laser.css (which holds the tokens). This file styles the shared
   partials in templates/partials/ and ENHANCES the structures styles.css already
   owns — it does not restate them.

   ⛔ WHAT THIS FILE DELIBERATELY DOES NOT DO. Recon found the interaction work
   already shipped and it is good; duplicating it would create a second, drifting
   definition (AGENTS.md §5: "Reuse the canonical helper. This is the most-repeated
   defect in this repo"). Specifically NOT re-implemented here:

     tabs        `record-tabs.js` + `.record-tabs` (#1627) — full WAI-ARIA:
                 roving tabindex, arrow/Home/End keys, deep links, localStorage,
                 progressive with JS off. This file only RESKINS `.record-tab`.
     tables      `table`, `.table-scroll`, `td.numeric` already exist and are
                 token-driven. Only the head/hover/hairline are repainted.
     modals      `_confirm_modal.html` + `modal-focus.js` already handle focus.
     status pill `.status-badge` (styles.css:983) stays for existing call sites;
                 `.laser-badge` is the new shape the partial emits.
     type/space  `--spacing-*` and `--font-size-*` scales already exist (#1628)
                 and are consumed here rather than redefined.

   Every rule is scoped to `body.laser-theme` so the layer is opt-in and the
   previous look stays reachable for comparison.
   ============================================================================ */

/* ─── Page chrome ────────────────────────────────────────────────────────── */

/* An ambient cyan wash at the top of the page — "gradients as ambient light"
   rather than a hard band. Fixed and non-interactive so it never intercepts a
   click or scrolls out of relation with the content.
   Uses the SURFACE gradient token, not the rainbow: the holographic sweep is
   reserved for headings and accents, or it stops reading as an accent. */
body.laser-theme::before {
    content: "";
    position: fixed;
    inset: 0 0 auto 0;
    height: 320px;
    background: var(--laser-surface-gradient);
    pointer-events: none;
    z-index: 0;
}

/* ─── Sidebar (the LASER AppBar/Drawer signature) ────────────────────────── */

/* MuiAppBar in LASER is `borderBottom: 2px solid PRIMARY`; the Drawer is
   `borderRight: 1px solid BORDER_CYAN`. The portal's nav is a left rail, so it
   takes the Drawer treatment plus the AppBar's solid-cyan edge as a 2px accent —
   that bright edge is the most recognisable single line in the LASER UI. */
body.laser-theme .app-sidebar {
    background-color: var(--laser-bg-appbar);
    border-right: 1px solid var(--laser-border-cyan);
    box-shadow: inset -1px 0 0 rgba(0, 229, 255, 0.06);
}

body.laser-theme .sidebar-header {
    border-bottom: 2px solid var(--laser-primary);
}

body.laser-theme .sidebar-brand-name {
    font-weight: 700;
    letter-spacing: -0.01em;
}

/* Nav items. Selected state mirrors MuiListItemButton exactly: an 8%-cyan wash
   plus a 3px cyan edge. The edge does the work — a wash alone is too quiet on a
   long rail, and colour alone would be the only signal (WCAG 1.4.1). */
body.laser-theme .sidebar-nav a,
body.laser-theme .sidebar-nav button {
    border-radius: var(--border-radius-sm);
    transition: background-color var(--laser-transition), color var(--laser-transition);
}

body.laser-theme .sidebar-nav a:hover,
body.laser-theme .sidebar-nav button:hover {
    background-color: var(--laser-wash-4);
    color: var(--laser-primary);
}

body.laser-theme .sidebar-nav a[aria-current="page"],
body.laser-theme .sidebar-nav a.active {
    background-color: var(--laser-wash-8);
    border-right: 3px solid var(--laser-primary);
    color: var(--laser-primary);
    font-weight: 600;
}

/* Section labels in the rail — MuiListSubheader: cyan, upper, tracked out. */
body.laser-theme .sidebar-nav-heading,
body.laser-theme .sidebar-section-label {
    color: var(--laser-primary);
    font-size: var(--font-size-caption);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

/* ⛔ THE APP SHELL MUST NOT PAINT, or the page ground is invisible. `.app-main-wrapper`
   sets `background-color: var(--background-color)` (_03-layout-and-admin.css:61), which
   under this theme resolves to `--laser-bg-page` — an OPAQUE sheet of #0A0A0A stretched
   over the entire viewport, above `body`.

   MEASURED when the grid/top-lit ground was added: every layer computed correctly on
   `body` and NONE of it was visible, because this wrapper covered all of it. Probing the
   paint stack at the page centre showed `div.app-main-wrapper` at `rgb(10, 10, 10)` with
   the body's `background-image` sitting uselessly beneath.

   ⚠️ The fix is `transparent`, NOT removing the declaration in `_03`: that file is the
   unthemed baseline and a light-theme page still needs an opaque shell. Only the themed
   case wants the body's ground to read through.
   ★ The same trap applies to any full-bleed wrapper added later — if the page ground
   stops showing, look for a new opaque ancestor before touching the gradients. */
body.laser-theme .app-main-wrapper {
    background-color: transparent;
}

/* ─── Cards / panels ─────────────────────────────────────────────────────── */

/* ⛔ NO PADDING HERE, and that is the point of the merge. This rule used to read
   `.laser-card` and set `padding: var(--spacing-2)` on the box itself. The class it
   now names has the OPPOSITE contract — _10-components.css: "`.section-card` carries
   NO padding. A table fills the panel edge to edge; an inset would put a second
   gutter inside the box." Carrying the old padding across the rename would have put
   16px around every table on every converted panel.

   The spacing lives on `.section-card-body` instead, which is the opt-in the
   section-card family already had. The MARGIN stays: the gap BETWEEN cards is what
   separates one panel from the next. */
body.laser-theme .section-card {
    position: relative;
    z-index: 1;
    margin-bottom: var(--spacing-3);
}

/* ⛔ DELIBERATELY NOT REDECLARING THE BAND. This rule was `.laser-card-head`: a bare
   flex row with a bottom margin and no background, no padding, no divider. The
   section-card head it now names is the opposite — `12px 16px`, a raised background
   and a hairline under it (_10-components.css) — and that band IS the design the
   owner chose.

   ⚠️ Left as-is this would have silently won and erased it: `_11` loads after `_10`,
   and `body.laser-theme .section-card-head` is (0,2,1) against that file's (0,1,0),
   so it beats it on BOTH specificity and order. The margin is dropped because the
   band's own border now separates head from body; only the flex behaviour the icon
   and count rely on is kept, and it matches what _10 already sets. */
body.laser-theme .section-card-head {
    display: flex;
    align-items: center;
}

body.laser-theme .section-card-title {
    margin: 0;
    font-size: var(--font-size-section);
    font-weight: 600;
    color: var(--laser-text-primary);
    letter-spacing: -0.01em;
}

/* The span holds a real inline SVG again (#2223), so the display is RESTORED —
   this rule's previous comment said to do exactly that "when a real mechanism
   exists", and `partials/_icon.html` is that mechanism.

   ⛔ History, kept because the failure was invisible rather than loud: the markup
   was `<span class="section-card-icon" aria-hidden="true">users</span>` — the icon's
   NAME as text, with no font, sprite or SVG behind it — so the DSC pipeline page
   read "users By rep" and "layers By firm". Hiding it here was the interim measure
   while the icon set was undecided; the partial now includes `_icon.html`, which
   draws nothing for an unregistered name, so no name can render as text again.

   ⚠️ Kept in THIS file, not _10-components.css. These parts load as their own
   `<link>` AFTER `styles.css`, so a rule of equal specificity in an @import'ed
   module loses on source order — measured: `display` stayed `inline-flex` twice.

   `inline-flex` + `align-items: center` so the 16px glyph sits on the heading's
   optical centre rather than the text baseline. */
body.laser-theme .section-card-icon {
    align-items: center;
    color: var(--laser-primary);
    display: inline-flex;
    font-size: var(--font-size-section);
    line-height: 1;
}

/* A count belongs beside its heading, not in the body: it answers "is there
   anything in here?" before the panel is read or expanded. */
body.laser-theme .section-card-count {
    background: var(--laser-wash-12);
    border: 1px solid var(--laser-border-cyan);
    border-radius: 999px;
    color: var(--laser-primary);
    font-size: var(--font-size-caption);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    padding: 1px var(--spacing-1);
}

body.laser-theme .section-card-actions {
    margin-left: auto;
    display: flex;
    gap: var(--spacing-1);
}

body.laser-theme .section-card-subtitle {
    margin: 0 0 var(--spacing-2);
    color: var(--laser-text-secondary);
    font-size: var(--font-size-body-small);
    line-height: 1.5;
}

/* Existing panel classes inherit the glass treatment, so surfaces that were
   never converted to the partial still match. This is the lever that makes a
   36,630-line template estate affordable to re-skin. */
body.laser-theme .card,
body.laser-theme .panel,
body.laser-theme .account-summary,
body.laser-theme .record-panel > .section,
body.laser-theme .dashboard-card,
body.laser-theme .stat-card,
body.laser-theme .payment-detail-section {
    background: var(--laser-glass-sheen);
    -webkit-backdrop-filter: var(--laser-glass-filter);
    backdrop-filter: var(--laser-glass-filter);
    border: 1px solid var(--laser-glass-border);
    border-radius: var(--border-radius-md);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    body.laser-theme .card,
    body.laser-theme .panel,
    body.laser-theme .account-summary,
    body.laser-theme .dashboard-card,
    body.laser-theme .stat-card,
    body.laser-theme .payment-detail-section {
        background: var(--laser-bg-card);
    }
}

/* ─── Buttons (glassComponents.ts → LaserButton) ─────────────────────────── */

/* The signature interaction: transparent with a cyan edge, inverting to a solid
   cyan fill with near-black text and a glow on hover. */
body.laser-theme .laser-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-1);
    min-height: 44px;                 /* pointer-target floor (WCAG 2.5.8) */
    padding: var(--spacing-1) var(--spacing-3);
    border-radius: var(--border-radius-sm);
    font-size: var(--font-size-body);
    font-weight: 600;
    text-transform: none;             /* MuiButton sets textTransform: "none" */
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--laser-transition),
                color var(--laser-transition),
                border-color var(--laser-transition),
                box-shadow var(--laser-transition);
}

body.laser-theme .laser-btn-primary {
    background: var(--laser-primary);
    border: 1px solid var(--laser-primary);
    color: var(--laser-bg-page);
}

body.laser-theme .laser-btn-primary:hover {
    background: var(--laser-primary-dark);
    border-color: var(--laser-primary-dark);
    box-shadow: var(--laser-glow);
}

body.laser-theme .laser-btn-outline,
body.laser-theme .btn-secondary {
    background: transparent;
    border: 1px solid var(--laser-primary);
    color: var(--laser-primary);
}

body.laser-theme .laser-btn-outline:hover,
body.laser-theme .btn-secondary:hover {
    background: var(--laser-primary);
    color: var(--laser-bg-page);
    box-shadow: var(--laser-glow);
}

/* The repo's existing primary button keeps its own fill token but gains LASER's
   hover glow, so converted and unconverted surfaces behave alike. */
body.laser-theme .btn-primary {
    border-radius: var(--border-radius-sm);
    transition: background-color var(--laser-transition), box-shadow var(--laser-transition);
}

body.laser-theme .btn-primary:hover {
    box-shadow: var(--laser-glow);
}

/* Destructive actions must NOT read as brand-cyan — the colour has to carry the
   consequence, and this is the one place the identity yields to safety. */
body.laser-theme .laser-btn-danger,
body.laser-theme .btn-danger {
    background: transparent;
    border: 1px solid var(--laser-error);
    color: var(--laser-error);
}

body.laser-theme .laser-btn-danger:hover,
body.laser-theme .btn-danger:hover {
    background: var(--laser-error);
    color: var(--laser-bg-page);
    box-shadow: 0 0 20px rgba(255, 82, 82, 0.3);
}

/* Focus. NEVER removed, and deliberately not the same visual as hover: a keyboard
   user has to be able to tell where focus IS, not just that something is warm. */
body.laser-theme .laser-btn:focus-visible,
body.laser-theme .btn-primary:focus-visible,
body.laser-theme .sidebar-nav a:focus-visible,
body.laser-theme .record-tab:focus-visible,
body.laser-theme a:focus-visible,
body.laser-theme button:focus-visible,
body.laser-theme input:focus-visible,
body.laser-theme select:focus-visible,
body.laser-theme textarea:focus-visible {
    outline: 2px solid var(--laser-primary);
    outline-offset: 2px;
}

/* ─── Inputs (glassComponents.ts → GlassTextField) ───────────────────────── */

body.laser-theme input[type="text"],
body.laser-theme input[type="email"],
body.laser-theme input[type="password"],
body.laser-theme input[type="number"],
body.laser-theme input[type="tel"],
body.laser-theme input[type="date"],
body.laser-theme input[type="search"],
body.laser-theme select {
    background: rgba(26, 26, 26, 0.7);
    border: 1px solid var(--laser-border-cyan);
    border-radius: var(--border-radius-md);
    color: var(--laser-text-primary);
    /* ⚠️ Must stay >= 16px or iOS auto-zooms the field on focus (#1628 AC4). */
    font-size: var(--fs-input);
    /* One control height, owner ruling 2026-09-04 — see the note on
       `.form-group input` in _01-base-and-tokens.css. This layer loads as its own
       <link> AFTER styles.css, so it WINS: without the height here the base rule's
       height would never apply on a themed page, which is every page. */
    height: var(--h-input);
    padding: 0 var(--s-3);
    transition: border-color var(--laser-transition), box-shadow var(--laser-transition);
}

/* `textarea` shares the field's look but never its height — it is sized by `rows`,
   and a fixed height would collapse a multi-line note to one line. */
body.laser-theme textarea {
    background: rgba(26, 26, 26, 0.7);
    border: 1px solid var(--laser-border-cyan);
    border-radius: var(--border-radius-md);
    color: var(--laser-text-primary);
    font-size: var(--fs-input);
    padding: var(--s-2) var(--s-3);
    transition: border-color var(--laser-transition), box-shadow var(--laser-transition);
}

body.laser-theme input:hover,
body.laser-theme select:hover,
body.laser-theme textarea:hover {
    border-color: var(--laser-primary);
}

body.laser-theme input:focus,
body.laser-theme select:focus,
body.laser-theme textarea:focus {
    border-color: var(--laser-primary);
    box-shadow: var(--laser-glow-subtle);
    outline: none;                    /* replaced by :focus-visible above */
}

body.laser-theme ::placeholder {
    color: var(--laser-text-disabled);
    opacity: 1;                       /* Firefox dims placeholders again */
}

body.laser-theme label {
    color: var(--laser-text-secondary);
    font-size: var(--font-size-body-small);
    font-weight: 500;
}

/* ─── Badges (partials/_status_badge.html) ───────────────────────────────── */

body.laser-theme .laser-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border-radius: 999px;             /* RADIUS.CHIP is a pill at chip height */
    font-size: var(--font-size-caption);
    font-weight: 600;
    letter-spacing: 0.01em;
    padding: 3px var(--spacing-1);
    white-space: nowrap;
}

/* A tinted fill + the hue as text + a matching edge. The 1px border is what keeps
   a chip legible for a colour-blind reader: the SHAPE and position carry state as
   well as the hue, and the border meets the 3:1 non-text contrast bar. */
body.laser-theme .laser-badge-success { background: var(--success-bg-color); color: var(--laser-success); border: 1px solid var(--success-border-color); }
body.laser-theme .laser-badge-error   { background: var(--error-bg-color);   color: var(--laser-error);   border: 1px solid var(--error-border-color); }
body.laser-theme .laser-badge-warning { background: var(--warning-bg-color); color: var(--laser-warning); border: 1px solid var(--warning-border-color); }
body.laser-theme .laser-badge-info    { background: var(--info-bg-color);    color: var(--laser-info);    border: 1px solid var(--info-border-color); }
body.laser-theme .laser-badge-neutral { background: rgba(255,255,255,0.06);  color: var(--laser-text-secondary); border: 1px solid rgba(255,255,255,0.14); }

body.laser-theme .laser-badge-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}

/* Existing status pills inherit the pill shape so unconverted surfaces match. */
body.laser-theme .status-badge {
    border-radius: 999px;
    font-weight: 600;
}

/* ─── Money (partials/_money.html) ───────────────────────────────────────── */

body.laser-theme .laser-money {
    font-feature-settings: var(--font-numeric);   /* "tnum" 1, "lnum" 1 (#1630) */
    font-variant-numeric: tabular-nums lining-nums;
    font-weight: 600;
}

body.laser-theme .laser-money-right { display: block; text-align: right; }
body.laser-theme .laser-money-positive { color: var(--laser-success); }
body.laser-theme .laser-money-negative { color: var(--laser-error); }
body.laser-theme .laser-money-muted    { color: var(--laser-text-secondary); }

/* ─── Metrics (partials/_metric.html) ────────────────────────────────────── */

body.laser-theme .laser-metric {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--spacing-2) var(--spacing-3);
    background: var(--laser-glass-sheen);
    -webkit-backdrop-filter: var(--laser-glass-filter);
    backdrop-filter: var(--laser-glass-filter);
    border: 1px solid var(--laser-glass-border);
    border-radius: var(--border-radius-md);
    transition: box-shadow var(--laser-transition), transform var(--laser-transition);
}

body.laser-theme .laser-metric:hover {
    box-shadow: var(--laser-glow);
    transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
    body.laser-theme .laser-metric:hover { transform: none; }
}

/* Label ABOVE the value, small and tracked: the number is the thing being
   scanned, so it must not compete with its own caption for the first fixation. */
body.laser-theme .laser-metric-label {
    color: var(--laser-text-secondary);
    font-size: var(--font-size-caption);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

body.laser-theme .laser-metric-value {
    color: var(--laser-text-primary);
    font-size: var(--font-size-metric);
    font-weight: 700;
    font-variant-numeric: tabular-nums lining-nums;
    letter-spacing: -0.02em;
    line-height: 1.15;
}

body.laser-theme .laser-metric-success { color: var(--laser-success); }
body.laser-theme .laser-metric-error   { color: var(--laser-error); }
body.laser-theme .laser-metric-warning { color: var(--laser-warning); }
body.laser-theme .laser-metric-info    { color: var(--laser-info); }
body.laser-theme .laser-metric-muted   { color: var(--laser-text-secondary); }

body.laser-theme .laser-metric-delta,
body.laser-theme .laser-metric-hint {
    font-size: var(--font-size-caption);
}

body.laser-theme .laser-metric-hint { color: var(--laser-text-disabled); }

/* A responsive metric row that needs no per-page grid. `auto-fit` + `minmax`
   reflows by available width instead of by breakpoint, so a rail collapsing or a
   window resize is handled without a media query. */
body.laser-theme .laser-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--spacing-2);
    margin-bottom: var(--spacing-3);
}

/* ─── Tables — reskin only; structure stays in styles.css ────────────────── */

/* MuiTableHead: recessed ground, CYAN heading text. The cyan head is the single
   change that makes a dense table read as LASER. */
body.laser-theme table th {
    background-color: var(--laser-bg-appbar);
    color: var(--laser-primary);
    font-size: var(--font-size-caption);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-bottom: 1px solid var(--laser-border-cyan);
}

body.laser-theme table td {
    border-bottom: 1px solid var(--laser-border-divider);
}

/* ─── Row density and the hover rail (owner ruling 2026-09-09: samples F + G) ──

   G — DENSITY. Cells drop from `--cell-pad-y` 6px to 4px, which takes a row from
   ~41px to ~29px and fits roughly 40% more rows per screen. These are queue and
   audit surfaces where the operator is scanning for one row among hundreds, so rows
   per screen is the thing being optimised.

   ⚠️ NOT applied to touch. A 29px row is well under the 44px target and these tables
   carry row actions, so the density is gated to fine pointers below — the same
   split `_09-a11y-and-touch.css` already makes for toolbars.

   F — THE HOVER RAIL. A 3px cyan edge is painted on the row's first cell on hover,
   in ADDITION to the wash. On a wide table the wash alone is a weak cue: the eye is
   at the far right column reading a balance while the tint is a 4% shift it has to
   notice across the full width. The rail gives the row a hard left anchor.

   ⛔ `box-shadow: inset`, NOT `border-left`. A border changes the cell's box and
   shifts every following column by 3px on hover — a whole table twitching sideways
   as the pointer moves down it. An inset shadow paints inside the existing box and
   moves nothing. The transparent resting value is declared so the shadow TRANSITIONS
   rather than appearing instantly. */
@media (pointer: fine) {
    /* ⚠️ The HEADER keeps a taller cell than the body rows. Measured against the CSR
       dashboard — the reference the owner picked — its head is `6px 16px` against `4px
       16px` cells, and that 2px is what separates the header band from the first row.
       Matching them exactly (both 4px) made the head read as just another row. */
    body.laser-theme table th {
        padding-top: 6px;
        padding-bottom: 6px;
    }

    body.laser-theme table td {
        padding-top: 4px;
        padding-bottom: 4px;
    }

    /* ⛔ THE PADDING ALONE CHANGES NOTHING ON A ROW THAT HAS ACTIONS, and finding this
       is the only reason the density is real. MEASURED after cutting the cells to
       4px: the row stayed 53px. No CSS rule set a row height — the ROW-ACTIONS
       BUTTON did. `.btn-actions-trigger` carries `min-height: var(--h-touch)` (44px,
       _10h-csr-dashboard.css:812), and 44 + 4 + 4 = 52. The tallest cell sets the
       row, so every other cell's padding was irrelevant.

       ⚠️ That 44px is a REAL touch target, not an oversight, so it is relaxed ONLY
       inside `pointer: fine` — a mouse can hit a 28px control, a finger cannot. On
       touch the button keeps its full size and the row stays tall, which is correct:
       density is a desktop-scanning optimisation and the touch floor outranks it. */
    body.laser-theme table .btn-actions-trigger {
        min-height: 28px;
        min-width: 28px;
        padding: 2px 6px;
    }
}

body.laser-theme table tbody tr {
    transition: background-color var(--laser-transition-fast);
}

body.laser-theme table tbody tr > td:first-child {
    box-shadow: inset 3px 0 0 transparent;
    transition: box-shadow var(--laser-transition-fast);
}

body.laser-theme table tbody tr:hover {
    background-color: var(--laser-wash-4);
}

body.laser-theme table tbody tr:hover > td:first-child {
    box-shadow: inset 3px 0 0 var(--laser-primary);
}

/* ⛔ Numeric columns are RIGHT-aligned with tabular figures, so digits share a
   vertical edge and can be compared down the column. The audit found 119
   `text-align: center` uses — more than left and right combined — and a centred
   money column is the single worst offender for scanning. */
body.laser-theme table td.numeric,
body.laser-theme table th.numeric,
body.laser-theme table td.money,
body.laser-theme table th.money {
    text-align: right;
    font-variant-numeric: tabular-nums lining-nums;
}

/* ─── Tabs — reskin only; behaviour stays in record-tabs.js (#1627) ─────── */

body.laser-theme .record-tabs {
    border-bottom: 1px solid var(--laser-border-cyan);
    gap: var(--spacing-2);
}

body.laser-theme .record-tab {
    color: var(--laser-text-secondary);
    border-radius: var(--border-radius-sm) var(--border-radius-sm) 0 0;
}

body.laser-theme .record-tab:hover {
    background-color: var(--laser-wash-4);
    color: var(--laser-primary);
}

/* MuiTabs indicator: 3px cyan, rounded at the top only. */
body.laser-theme .record-tab[aria-selected="true"] {
    color: var(--laser-primary);
    border-bottom: 3px solid var(--laser-primary);
    font-weight: 600;
}

body.laser-theme .record-tab-count {
    background: var(--laser-wash-12);
    border-radius: 999px;
    color: var(--laser-primary);
    font-size: var(--font-size-caption);
    font-variant-numeric: tabular-nums;
    margin-left: 6px;
    padding: 1px 6px;
}

/* ─── Empty states (partials/_empty_state.html) ─────────────────────────── */

body.laser-theme .laser-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-1);
    padding: var(--spacing-5) var(--spacing-3);
    text-align: center;                /* centre IS right here: short display text */
}

body.laser-theme .laser-empty-icon {
    color: var(--laser-primary);
    font-size: var(--font-size-metric);
    opacity: 0.5;
}

/* Body-text size and the SECONDARY colour, never a shrunken footnote: on an
   investigation surface "nothing here" is the answer, not chrome. */
body.laser-theme .laser-empty-message {
    margin: 0;
    color: var(--laser-text-secondary);
    font-size: var(--font-size-body);
    line-height: 1.5;
}

body.laser-theme .laser-empty-hint {
    margin: 0;
    color: var(--laser-text-disabled);
    font-size: var(--font-size-body-small);
}

/* ─── Modals / dialogs ──────────────────────────────────────────────────── */

/* MuiDialog: glass paper, cyan edge, 16px radius, scale-in. Behaviour (focus
   trap, restore) stays with modal-focus.js. */
/* ⛔ SAME FIX AS THE `More` MENU, and modals are the worse case. A card sits ON the page,
   so the 4.5% white glass fill reads correctly against the page ground. A modal covers
   ARBITRARY page content — a dense table, a paragraph, a KPI row — and at that fill the
   content behind it read straight through the dialog's own text.

   The blur is kept (a modal should still separate from what it covers), but the fill is the
   card surface at high opacity so the worst-case backdrop is suppressed. A dialog asking for
   a destructive confirmation has to be legible over anything.

   ⚠️ This is deliberately NOT `--laser-glass-sheen` with a raised alpha: that token is the
   CARD ground and nine on-page surfaces consume it. Raising it there to fix overlays would
   make every card more opaque — the opposite of the owner's 2026-09-09 ruling that cards
   should be MORE transparent. Overlay and card are two different jobs. */
body.laser-theme .modal-content,
body.laser-theme .confirm-modal,
body.laser-theme dialog {
    background: color-mix(in srgb, var(--laser-bg-card) 94%, transparent);
    -webkit-backdrop-filter: var(--laser-glass-filter);
    backdrop-filter: var(--laser-glass-filter);
    border: 1px solid var(--laser-glass-border);
    border-radius: var(--border-radius-lg);
    color: var(--laser-text-primary);
    animation: laser-fade-in-scale 300ms cubic-bezier(0.4, 0, 0.2, 1) both;
}

body.laser-theme .modal-overlay,
body.laser-theme dialog::backdrop {
    background: rgba(0, 0, 0, 0.7);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

/* ─── Scrollbars (theme.ts → MuiCssBaseline) ────────────────────────────── */

body.laser-theme * {
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 229, 255, 0.35) transparent;
}

body.laser-theme *::-webkit-scrollbar { width: 10px; height: 10px; }
body.laser-theme *::-webkit-scrollbar-track { background: transparent; }

body.laser-theme *::-webkit-scrollbar-thumb {
    background-color: rgba(0, 229, 255, 0.25);
    border: 2px solid transparent;
    border-radius: 8px;
    background-clip: content-box;
}

body.laser-theme *::-webkit-scrollbar-thumb:hover {
    background-color: rgba(0, 229, 255, 0.5);
}

body.laser-theme *::-webkit-scrollbar-corner { background: transparent; }
body.laser-theme *::-webkit-scrollbar-button { display: none; }

/* ─── Alerts / messages ─────────────────────────────────────────────────── */

/* A 4px leading rail plus the hue as text. The rail is the accessible part: it
   survives greyscale, where a 12%-alpha tint alone would not. */
body.laser-theme .alert,
body.laser-theme .message,
body.laser-theme .messages li {
    border-radius: var(--border-radius-sm);
    border-left-width: 4px;
    border-left-style: solid;
    padding: var(--spacing-2);
}

/* ─── The classes actually in use ────────────────────────────────────────────

   Everything above styles the new partials. This block reaches the vocabulary the
   existing 108 templates already use, counted from the tree rather than guessed:

     form-group 185 · btn-action 71 · btn-success 57 · detail-row/label/value 48
     each · status-badge 31 · metric-card / metric-value / metric-label · card-header

   ⛔ This is the difference between "the new pages look like LASER" and "the product
   looks like LASER". Restyling the shared classes converts every surface at once —
   including the ~90 templates nobody will hand-edit — which is why it beats rewriting
   markup page by page (and why no page in this change needed its HTML restructured).
   -------------------------------------------------------------------------- */

/* Metric tiles — the dashboards' top row. */
body.laser-theme .metric-card {
    background: var(--laser-glass-sheen);
    -webkit-backdrop-filter: var(--laser-glass-filter);
    backdrop-filter: var(--laser-glass-filter);
    border: 1px solid var(--laser-glass-border);
    border-radius: var(--border-radius-md);
    transition: box-shadow var(--laser-transition), transform var(--laser-transition);
}

body.laser-theme .metric-card:hover {
    box-shadow: var(--laser-glow);
    transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
    body.laser-theme .metric-card:hover { transform: none; }
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    body.laser-theme .metric-card { background: var(--laser-bg-card); }
}

/* The figure is what the page is opened for: tabular so a changing value cannot
   shift the layout, and tight tracking so a long dollar amount stays compact. */
body.laser-theme .metric-value {
    color: var(--laser-text-primary);
    font-variant-numeric: tabular-nums lining-nums;
    font-weight: 700;
    letter-spacing: -0.02em;
}

body.laser-theme .metric-label {
    color: var(--laser-text-secondary);
    font-size: var(--font-size-caption);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* `.highlight` marks the metric that matters most on the page (outstanding balance). */
body.laser-theme .metric-card.highlight {
    border-color: var(--laser-primary);
    box-shadow: var(--laser-glow-subtle);
}

body.laser-theme .metric-card.highlight .metric-value {
    color: var(--laser-primary);
}

/* Detail rows — the label/value grid on every record page (48 uses each). */
body.laser-theme .detail-label,
body.laser-theme .summary-item .label {
    color: var(--laser-text-secondary);
}

body.laser-theme .detail-value,
body.laser-theme .summary-item .value {
    color: var(--laser-text-primary);
}

body.laser-theme .detail-row {
    border-bottom: 1px solid var(--laser-border-divider);
}

/* Card/section headers. */
body.laser-theme .card-header,
body.laser-theme .section-header,
body.laser-theme .summary-header {
    border-bottom: 1px solid var(--laser-border-divider);
}

/* Headings. `h1` takes the holographic sweep (handled in laser.css); h2/h3 stay solid
   so a data-dense page does not turn into a wall of gradients — LASER's own theme
   gradients h1/h2 only and leaves h3-h6 at plain weight. */
body.laser-theme h2,
body.laser-theme h3,
body.laser-theme h4 {
    color: var(--laser-text-primary);
    letter-spacing: -0.01em;
}

/* The repo's own button vocabulary, given LASER's hover glow. `.btn-action` (71) and
   `.btn-success` (57) keep their existing fills — only the interaction is added, so no
   button changes meaning. */
body.laser-theme .btn-action,
body.laser-theme .btn-success,
body.laser-theme .btn-logout-sidebar {
    border-radius: var(--border-radius-sm);
    transition: background-color var(--laser-transition),
                border-color var(--laser-transition),
                box-shadow var(--laser-transition);
}

body.laser-theme .btn-action:hover,
body.laser-theme .btn-success:hover {
    box-shadow: var(--laser-glow);
}

/* Form fields — 185 `.form-group`s, so the label/help rhythm here is most of the
   product's form surface. */
body.laser-theme .form-group label {
    color: var(--laser-text-secondary);
    font-weight: 500;
}

body.laser-theme .help-text {
    color: var(--laser-text-disabled);
    font-size: var(--font-size-body-small);
}

body.laser-theme .error-message {
    color: var(--laser-error);
}

/* Standalone error pages (400/403/404/405/500/503). They do not extend base.html —
   an error page must not depend on the shell that may itself be broken — so they get
   the card treatment here rather than inheriting it. */
body.laser-theme .standalone-error-container {
    background: var(--laser-glass-sheen);
    -webkit-backdrop-filter: var(--laser-glass-filter);
    backdrop-filter: var(--laser-glass-filter);
    border: 1px solid var(--laser-glass-border);
    border-radius: var(--border-radius-lg);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    body.laser-theme .standalone-error-container { background: var(--laser-bg-card); }
}

/* The error CODE is the page's one big number — it takes the holographic sweep, which
   is the clearest signal that even a 500 is still inside the product. */
body.laser-theme .standalone-error-code {
    background: var(--laser-holographic);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    font-weight: 700;
    letter-spacing: -0.03em;
}

@media (forced-colors: active) {
    body.laser-theme .standalone-error-code {
        background: none;
        -webkit-text-fill-color: currentColor;
        color: CanvasText;
    }
}

body.laser-theme .standalone-error-title { color: var(--laser-text-primary); }
body.laser-theme .standalone-error-message { color: var(--laser-text-secondary); }
body.laser-theme .standalone-error-footer,
body.laser-theme .request-id { color: var(--laser-text-disabled); }

/* ─── Debtor-facing surfaces ────────────────────────────────────────────── */

/* ⚠️ ONE deliberate restraint inside "full holographic everywhere".
   The identity is unchanged here — same cyan, same glass, same dark ground — but
   two INFINITE effects are dropped on the pages where a person is entering card
   details and reading an amount they owe:

     · `laser-shimmer` on headings (a moving rainbow over a payable figure)
     · `laser-pulse` (a breathing glow around a submit button)

   Reason: 2026 fintech-UX guidance is consistent that motion near a monetary
   figure reads as instability at exactly the moment a payer is deciding to trust
   the page, and doc 13's T2-4 reaches the same conclusion from the product side
   ("debtor: anxious, infrequent, mobile-likely… one obvious next action").
   Entrance animations, hover glow and the static holographic heading all remain.

   This is a targeted, reversible exception, not a second theme: delete this block
   and the debtor pages animate exactly like the console. */
body.laser-theme.debtor-surface .laser-holo-animate {
    animation: none;
}

body.laser-theme.debtor-surface .laser-active {
    animation: none;
    box-shadow: var(--laser-glow);
}

/* A payment form is a decision, not a dashboard: give it a single readable
   column instead of the console's full width. */
body.laser-theme.debtor-surface .laser-flow {
    max-width: 560px;
    margin-inline: auto;
}

/* ─── Print ─────────────────────────────────────────────────────────────── */

/* A receipt or an LOA gets printed. Dark grounds waste toner and glass renders as
   grey mud, so print reverts to ink on white. */
@media print {
    body.laser-theme,
    body.laser-theme .section-card,
    body.laser-theme .laser-glass,
    body.laser-theme .laser-metric {
        background: #fff !important;
        color: #000 !important;
        box-shadow: none !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        border-color: #999 !important;
    }

    body.laser-theme::before { display: none; }

    body.laser-theme .laser-holo,
    body.laser-theme .page-header h1 {
        background: none !important;
        -webkit-text-fill-color: #000 !important;
        color: #000 !important;
    }

    body.laser-theme .app-sidebar { display: none !important; }
}

/* ─── TopBar — the LASER AppBar (templates/partials/_top_bar.html) ───────────

   Owner, 2026-09-03: have "the similar top nav same as the laser". Values ported from
   laser-platform/packages/frontend/src/components/layout/TopBar.tsx and the
   `MuiAppBar` override in theme.ts:

     backgroundColor: COLORS.BG_APPBAR      #0D0D0D
     borderBottom: `2px solid PRIMARY`      the single most recognisable line in LASER
     ...GLASS                               rgba(26,26,26,.7) + blur(16px)
     position: fixed, zIndex: drawer + 1    sits above the rail

   The 2px solid-cyan bottom edge is the signature: a 1px tinted border reads as a generic
   dark theme, the 2px full-saturation one reads as LASER.
   -------------------------------------------------------------------------- */

/* ⛔ THE APP BAR IS THE SAME GLASS AS A CARD, and the fill already was — what broke
   the match was the EDGE. It carried `border-bottom: 2px solid var(--laser-primary)`:
   a hard, fully-opaque cyan chrome rule, twice the weight of any other line in the
   product, against cards whose edge is a 16%-white hairline with a soft top-lit lip.
   Same material, two different treatments, and the bar read as a separate component
   bolted above the page rather than the nearest surface in the same stack.

   ⚠️ The 2px cyan is NOT simply deleted — a sticky bar needs a visible bottom edge or
   content scrolls up and dissolves into it with nothing marking where the chrome
   ends. It is replaced by the card's own vocabulary: the glass hairline, plus the
   specular lip and cast shadow from `--laser-glass-edge` reused as the separation.
   That is the same trick the cards use to sit above the page, so the bar now sits
   above the content the way a card sits above the ground.

   ★ Consuming the tokens rather than restating values also means the two
   accessibility opt-outs (`prefers-reduced-transparency`, the no-backdrop-filter
   `@supports`) already cover this surface — they re-point the tokens once. */
body.laser-theme .laser-topbar {
    position: sticky;
    top: 0;
    z-index: 1100;              /* above the rail, below modals (2000) */
    background: var(--laser-glass-sheen);
    -webkit-backdrop-filter: var(--laser-glass-filter);
    backdrop-filter: var(--laser-glass-filter);
    border-bottom: 1px solid var(--laser-glass-border);
    box-shadow: var(--laser-glass-edge);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    body.laser-theme .laser-topbar { background: var(--laser-bg-appbar); }
}

body.laser-theme .topbar-inner {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-1) var(--page-gutter);
    min-height: 56px;
}

body.laser-theme .topbar-spacer { flex: 1 1 auto; }

/* The hamburger drives the EXISTING rail toggle; hidden where the rail is always visible. */
body.laser-theme .topbar-menu-btn {
    display: none;
    background: none;
    border: 0;
    color: var(--laser-text-secondary);
    font-size: 20px;
    line-height: 1;
    min-height: 44px;
    min-width: 44px;
    border-radius: var(--border-radius-sm);
    cursor: pointer;
}

body.laser-theme .topbar-menu-btn:hover {
    background: var(--laser-wash-8);
    color: var(--laser-primary);
}
