/*
 * Entry stylesheet for the customer portal (public/portal/), one per
 * site as staff.css is for the staff app, with the same layer order. The
 * site's pages link this file only, and Font Awesome through a
 * <style>@import ... layer(legacy)</style> after it.
 *
 * CSS phase 6 (docs/specs/2026-10-12-css-phase-6-customer-design.md): the
 * components this site uses over base.css, as on staff pages, and the
 * site's own layout in pages/portal.css. The footer, challenge, hero,
 * stepper and skeleton components are customer only (the hero band, the
 * result's steps and the loading placeholders are the portal refresh's,
 * docs/specs/2026-10-12-portal-refresh-design.md). layout.css is the staff shell (the sidenav,
 * the hidden-until-ready body) and is not imported.
 */
@layer tokens, base, legacy, layout, components, utilities, pages;

@layer legacy {
:root {
  /* ── Accent ramp (Layer 1). Themeable: overridden per [data-accent]. ───────
     Default = ChartMate brand teal. --cm-accent-ring is a space-separated RGB
     triple so --cm-focus-ring can vary its alpha per mode.
     NOTE: 800 and 900 are intentionally NOT redefined in dark mode: some
     surfaces put white text on them (layout.css, base.css). */
  --cm-accent-50: #ecfdf5;
  --cm-accent-100: #ccfbf1;
  --cm-accent-300: #5eead4;
  --cm-accent-500: #14b8a6;
  --cm-accent-600: #0d9488;
  --cm-accent-700: #0f766e;
  --cm-accent-800: #115e59;
  --cm-accent-900: #134e4a;
  --cm-accent-ring: 20 184 166;

  /* Back-compat: 58 call sites still say var(--cm-teal-N). Do not remove
     without migrating them. */
  --cm-teal-50: var(--cm-accent-50);
  --cm-teal-100: var(--cm-accent-100);
  --cm-teal-300: var(--cm-accent-300);
  --cm-teal-500: var(--cm-accent-500);
  --cm-teal-600: var(--cm-accent-600);
  --cm-teal-700: var(--cm-accent-700);
  --cm-teal-800: var(--cm-accent-800);
  --cm-teal-900: var(--cm-accent-900);

  /* ---------- Color: neutrals ---------- */
  --cm-gray-0: #ffffff;
  --cm-gray-50: #f8fafc;
  --cm-gray-100: #f1f5f9;
  --cm-gray-200: #e2e8f0;
  --cm-gray-300: #cbd5e1;
  --cm-gray-400: #94a3b8;
  --cm-gray-500: #64748b;
  --cm-gray-700: #334155;
  --cm-gray-900: #0f172a;
  --cm-scrollbar-track: #595959;

  /* ---------- Color: accent + semantic ---------- */
  --cm-blue-100: #dbeafe;
  --cm-blue-500: #3b82f6;
  --cm-blue-600: #2563eb;
  --cm-navy: #1e3a8a;
  --cm-success-500: #10b981;
  --cm-warning-500: #f59e0b;
  --cm-warning-700: #b45309; /* WCAG: dark amber for warning surfaces (white-text bg) */
  --cm-danger-500: #ef4444;
  --cm-danger-700: #b91c1c; /* WCAG: dark red for error surfaces (white-text bg) */

  /* ---------- Typography ---------- */
  --cm-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --cm-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;

  --cm-text-xs: 0.75rem; /* 12px */
  --cm-text-sm: 0.875rem; /* 14px */
  --cm-text-base: 1rem; /* 16px */
  --cm-text-lg: 1.125rem; /* 18px */
  --cm-text-xl: 1.25rem; /* 20px */
  --cm-text-2xl: 1.5rem; /* 24px */
  --cm-text-3xl: 1.875rem; /* 30px */

  --cm-lh-tight: 1.2;
  --cm-lh-snug: 1.35;
  --cm-lh-normal: 1.5;

  /* Fixed root font size (base.css html). rem sizing across the app assumes
     16px; a relative value would follow the viewer's browser setting. */
  --cm-font-size-root: 16px;
  --cm-font-size-avatar-xs: 10px; /* initials in an 18px disc (the assignee chip) */
  --cm-font-size-help-glyph: 10px; /* the "?" in the 14px help icon */

  --cm-fw-regular: 400;
  --cm-fw-medium: 500;
  --cm-fw-semibold: 600;
  --cm-fw-bold: 700;

  /* ---------- Radius / shadow / focus ring ---------- */
  --cm-radius-sm: 4px;
  --cm-radius-md: 6px;
  --cm-radius-lg: 8px;
  --cm-radius-xl: 12px;
  --cm-radius-pill: 999px;

  /* Z-index scale, reworked in CSS consolidation phase 3d to the product
     owner's approved stacking order: "The sidenav stays usable over
     popups: content < sticky headers < in-page menus < popup backdrop <
     popup < popup opened from a popup < sidenav < context menus < toasts."
     Loader, What's New and the session-timeout modal stay below the sidenav.
     Every tier keeps the value it had before this rework except the
     sidenav (was 10000000, now sits below context menus and toasts), the
     context menu (new tier, now above the sidenav; the right-click menu
     previously shared the modal tier) and the session modal (was 1000000,
     now between the priority modal and the sidenav). */
  --cm-z-raised: 1; /* sticky headers, focus rings, in-flow lifts */
  --cm-z-raised-2: 2; /* close buttons over raised content */
  --cm-z-hover: 10; /* hover-raised panels, draggable popups */
  --cm-z-float: 20; /* in-page menus and popovers */
  --cm-z-panel: 30; /* AI insights panel */
  --cm-z-overlay: 100; /* popup container, loader messages, action menus */
  --cm-z-overlay-menu: 101; /* dropdowns and badges over overlays */
  --cm-z-popup-stacked: 110; /* a popup opened over another popup (override/confirm popups) */
  --cm-z-popup-stacked-2: 120; /* CNR popup and the duplicate-check list popup */
  --cm-z-popup-stacked-3: 125; /* duplicate-check compare pane, opened over popup-stacked-2 */
  --cm-z-modal: 1000; /* loader, magnifier glass, what's new; .cm-menu--modal (QA hotkeys popover, below the session-timeout box) */
  --cm-z-modal-progress: 1001;
  --cm-z-modal-priority: 1100; /* patient-alert gate overlay and PatientAlertPopup (common/patient-alerts.js) */
  --cm-z-session: 1500; /* session timeout modal; above every popup and modal, below the sidenav */
  --cm-z-sidenav: 2000; /* was 10000000; now below context menus and toasts */
  --cm-z-context-menu: 3000; /* .cm-menu--fixed: ContextMenu (common/dom-helpers.js); above the sidenav */
  --cm-z-toast: 9999;
  --cm-z-page-drawer: 200; /* Preload Tool's side drawer */
  /* Customer pages only (portal and request flow). */
  --cm-z-challenge: 99999; /* the reCAPTCHA challenge overlay (recaptcha.js): above toasts */
  --cm-z-customer-loader: 99990; /* the portal's wait screen (pages/portal.css): above toasts, below the challenge overlay, so a reCAPTCHA challenge raised during a lookup can be solved */

  /* Breakpoints. Custom properties cannot be used in @media conditions, so
     these are documented constants, enforced by
     tests/unit/frontend/stylesheets/tokens-usage.test.mjs:
       600px  mobile
       768px  tablet
       960px  narrow desktop
       1280px wide
     Off-scale widths still in use are listed in BREAKPOINT_EXCEPTIONS there. */

  --cm-shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.04);
  --cm-shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
  --cm-shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08), 0 2px 4px rgba(15, 23, 42, 0.04);
  --cm-shadow-lg: 0 12px 24px rgba(15, 23, 42, 0.1), 0 4px 8px rgba(15, 23, 42, 0.06);
  --cm-shadow-popup:
    0 0 0 4px rgb(var(--cm-accent-ring) / 0.28), var(--cm-shadow-lg); /* popup box: accent glow (owner, 2026-09-30) */
  --cm-shadow-tooltip:
    0 0 0 1px rgb(var(--cm-accent-ring) / 0.5), 0 3px 10px rgb(var(--cm-accent-ring) / 0.22); /* tooltip and help icon bubbles: accent ring */
  --cm-bg-backdrop: rgba(15, 23, 42, 0.5); /* popup overlay (was --popup-background-color) */

  --cm-focus-ring: 0 0 0 3px rgb(var(--cm-accent-ring) / 0.35);
  /* A selected card's ring (components/card.css .cm-card--selected; was the
     System Health strip's expanded ring). Follows the accent in both themes
     through --cm-accent-ring, so no :root.dark copy is needed. */
  --cm-shadow-selected: 0 0 0 3px rgb(var(--cm-accent-ring) / 0.15);

  /* Toggle chip "on" state (components/chip-toggle.css, CSS consolidation
     phase 4 forms PR 2): one look in both themes, no :root.dark override
     needed - each re-resolves its nested var(--cm-accent-ring) per theme
     the same way the semantic grays below do. */
  --cm-chip-selected-border: rgb(var(--cm-accent-ring) / 0.8);
  --cm-chip-selected-bg: rgb(var(--cm-accent-ring) / 0.12);
  /* Drop zone drag tint; follows the accent theme. */
  --cm-drop-zone-active-bg: rgb(var(--cm-accent-ring) / 0.08);

  /* ---------- Spacing ---------- */
  --cm-space-1: 4px;
  --cm-space-2: 8px;
  --cm-space-3: 12px;
  --cm-space-4: 16px;
  --cm-space-5: 20px;
  --cm-space-6: 24px;
  --cm-space-8: 32px;
  --cm-space-10: 40px;

  /* ---------- Layout primitives (kept from legacy v3) ---------- */
  --scrollbar-thickness: 12px;
  --sidebar-width: 70px;

  /* ---------- Semantic tokens (light mode) ---------- */
  --cm-bg-body: var(
    --cm-gray-100
  ); /* Was gray-50 (white cards sat at 1.05:1 on it); gray-100 lifts surfaces 1.10:1, matching dark mode. */
  --cm-bg-surface: var(--cm-gray-0);
  --cm-bg-raised: var(--cm-gray-0);
  --cm-bg-muted: var(
    --cm-gray-200
  ); /* Was gray-100, which --cm-bg-body now uses; gray-200 keeps muted areas (table headers, chips, disabled controls) one step past the page like dark mode: surface 1.23:1, body 1.13:1. */
  --cm-bg-sidebar: var(--cm-gray-900);
  --cm-bg-readonly: var(
    --cm-gray-100
  ); /* Tint behind locked/read-only form fields (#f1f5f9 light, #1e293b dark via the gray scale). */

  /* Form field height (phase 3c field design); buttons adopt it in phase 4. */
  --cm-control-height: 24px;
  /* Taller fields where a form is the whole page (the sign-in card, owner
     2026-10-13): the pre-redesign 36px, level with --cm-button-height. */
  --cm-control-height-lg: var(--cm-button-height);
  /* One height for every status pill (phase 4 pills). */
  --cm-pill-height: 20px;

  /* One button height for every button (owner decision 2026-10-07, after
     reviewing 32px with a 24px small size: keep the original 36px). */
  --cm-button-height: 36px;
  /* Small icon buttons only (owner decision 2026-10-07): a square at the
     field height, for icon buttons that sit beside a field or in a header
     (Invoice's field icons, the comments table +, the report builder's
     move and remove icons). */
  --cm-button-height-sm: var(--cm-control-height);

  --cm-text-body: var(--cm-gray-700);
  --cm-text-heading: var(--cm-gray-900);
  --cm-text-muted: var(--cm-gray-500);
  --cm-text-on-dark: var(--cm-gray-0);
  --cm-text-on-interactive: #ffffff; /* Foreground on .cm-button bg; flips dark in :root.dark for AA. */

  --cm-border: var(
    --cm-gray-400
  ); /* Was gray-200 (1.23:1 on white). slate-400 is 2.56:1, so tables, cards, chips and popups read as shapes; dark mode keeps its own value below. */
  --cm-border-strong: var(
    --cm-gray-500
  ); /* Was gray-300; needed slate-500 for input-border 4.76:1 vs surface (UI 3:1 AA). */
  /* Menu frame and row hairline (components/menu.css, CSS phase 5.5 restyle).
     The frame mixes --cm-border toward --cm-border-strong, about 3:1 on the
     surface in both themes (--cm-border alone is 1.9:1 in dark). Each
     re-resolves its nested tokens per theme, so no :root.dark copy. */
  --cm-menu-border: color-mix(in srgb, var(--cm-border) 70%, var(--cm-border-strong));
  --cm-menu-separator: color-mix(in srgb, var(--cm-border) 55%, transparent);
  /* A hovered, focused or active menu row's left edge. */
  --cm-menu-edge: inset 3px 0 0 var(--cm-interactive);
  --cm-menu-edge-danger: inset 3px 0 0 var(--cm-danger-500);

  /* Interactive accent — teal-700 keeps white-on-teal AA (5.47:1) and link
     text on white AA (5.47:1). hover/active step darker for visible feedback. */
  --cm-interactive: var(--cm-teal-700);
  --cm-interactive-hover: var(--cm-teal-800);
  --cm-interactive-active: var(--cm-teal-900);
  --cm-control-accent: var(--cm-accent-800); /* checkbox and radio fill; follows the accent theme */

  --cm-bg-warning: var(
    --cm-warning-700
  ); /* Surface for .warning banners — white-on-amber-700 = 5.02:1 AA. */
  --cm-bg-danger: var(
    --cm-danger-700
  ); /* Surface for .error/.fail banners — white-on-red-700 = 5.94:1 AA. */

  /* Foreground success/warning/danger text (dot + label) on a neutral chip
     background (--cm-bg-muted) and on the status pill tints below
     (components/pill.css), not the white-on-color surface tokens above.
     Not tied to the tenant-configurable accent scale - success should read
     as green regardless of which accent a tenant picked. */
  --cm-success-text: #166534; /* green-800: 6.49:1 on its tint, 5.78:1 on --cm-bg-muted (was #15803d, 4.07:1 on muted, Automate-774m) */
  --cm-warning-text: #92400e; /* amber-800: 6.37:1 on its tint, 5.75:1 on --cm-bg-muted (was #b45309) */
  --cm-danger-text: #b91c1c;
  --cm-info-text: var(--cm-navy);
  --cm-accent-text: var(--cm-accent-700); /* follows the accent theme */

  /* Status pill tints (components/pill.css): opaque, so a pill's contrast
     does not depend on what it sits on. Dark values mix the hue over the
     surface (:root.dark). */
  --cm-bg-info-soft: var(--cm-blue-100);
  --cm-bg-accent-soft: var(--cm-accent-100);
  --cm-bg-success-soft: #dcfce7;
  --cm-bg-warning-soft: #fef3c7;

  /* Initials discs (components/avatar.css). */
  --cm-avatar-bg: var(--cm-gray-200);
  --cm-avatar-fg: var(--cm-gray-700);
  --cm-avatar-chip-disc-bg: var(--cm-accent-300);
  --cm-avatar-chip-disc-fg: var(--cm-accent-900);
  --cm-avatar-you-disc-bg: var(--cm-accent-800);

  /* --cm-bg-danger-soft: status pill danger tint (Delivery Failed,
     release restriction counts) and the System Health hot-chip surface. */
  --cm-bg-danger-soft: #fee2e2;

  /* App shell values with no match on the scales above (layout.css, CSS
     consolidation phase 3d). Kept at the values the shell rendered with in
     stylesheetv3.css; phase 4 decides whether they snap to a scale. No
     dark-mode overrides: the shell rendered them the same in both modes. */
  --cm-bg-nav-hover: rgba(255, 255, 255, 0.1); /* sidenav link hover */
  --cm-bg-nav-active: rgba(20, 184, 166, 0.12); /* active nav item (fixed teal, not the accent) */
  --cm-bg-on-dark-hover: rgba(255, 255, 255, 0.06); /* hover tint on the dark shell chrome */
  --cm-bg-on-dark-soft: rgba(255, 255, 255, 0.16); /* a tag on the dark profile banner */
  --cm-bg-on-dark-soft-hover: rgba(255, 255, 255, 0.24);
  --cm-attention-ring: 0 0 0 3px var(--cm-accent-100); /* a dot that wants attention (What's New unseen) */
  --cm-border-on-dark: rgba(255, 255, 255, 0.12); /* dividers on the pinned dark chrome */
  --cm-border-on-dark-strong: rgba(255, 255, 255, 0.25); /* the profile disc's ring */
  --cm-border-translucent: rgba(
    127,
    127,
    127,
    0.25
  ); /* a divider that reads on either theme (the esMD details header) */
  /* The PDF viewer (components/pdf-viewer.css): the page status rings on
     thumbnails and on QA's current page, the magnifier, fill and sign's
     floating box, the AI insights panel. Fixed in both themes. */
  --cm-page-ring-selected: 0 0 0 5px var(--cm-accent-800);
  --cm-page-ring-ok: 0 0 0 5px #009900;
  --cm-page-ring-new: 0 0 0 5px #64d6d7;
  --cm-page-ring-rejected: 0 0 0 5px #e7b90c;
  --cm-page-ring-misfiled: 0 0 0 5px #7d0d5c;
  --cm-page-ring-deleted: 0 0 0 5px #cd3915;
  --cm-page-ring-image-flag: 0 0 0 5px #e7620c;
  --cm-magnifier-border: #000000;
  --cm-fill-sign-action: #ffffff;
  --cm-fill-sign-text: #000000;
  --cm-shadow-fill-sign: 0 0 5px 2px #303030 inset;
  --cm-fill-sign-size: var(--cm-text-xl); /* the + and - actions set it on each text line */
  --cm-radius-fill-sign: 10px;
  --cm-shadow-insights: 0 6px 24px rgba(0, 0, 0, 0.35);
  --cm-shadow-switch-knob: 0 1px 2px rgba(15, 23, 42, 0.2); /* the task switch's knob */
  --cm-shadow-invalid: 0 0 2px 2px red; /* a field that failed a page's check (aria-invalid) */
  --cm-task-person-selected-bg: rgb(
    var(--cm-accent-ring) / 0.18
  ); /* the task popup's picked person, dark mode */
  --cm-task-person-selected-border: rgb(var(--cm-accent-ring) / 0.4);
  /* The page manager's drop marker: an accent bar on the side a dragged page lands. */
  --cm-shadow-pdfpm-drop-before: 5px 0 0 0 var(--cm-accent-800) inset;
  --cm-shadow-pdfpm-drop-after: -5px 0 0 0 var(--cm-accent-800) inset;
  --cm-shadow-nav-hover: inset 3px 0 0 var(--cm-accent-500); /* a hovered nav link's left edge */
  --cm-shadow-drawer: -4px 0 16px rgba(0, 0, 0, 0.25); /* right sidebar panel */
  --cm-shadow-drawer-tab: -4px 0 12px rgba(0, 0, 0, 0.2); /* right sidebar tab */
  --cm-radius-accent-bar: 2px; /* right-sidebar action row accent bar */
  --cm-radius-progress-bar: 3px; /* loader progress bar */
  --cm-radius-session-countdown: 5px; /* session-timeout countdown chip */

  /* Tables (components/table.css). */
  --cm-table-cell-max: 180px; /* the one width a --truncate cell stops at */
  --cm-table-marker-selected: inset var(--cm-space-1) 0 0 var(--cm-interactive);
  --cm-table-marker-urgent: inset var(--cm-space-1) 0 0 var(--cm-danger-text);
  --cm-table-marker-locked: inset var(--cm-space-1) 0 0 var(--cm-warning-text);
  --cm-table-marker-deleted: inset var(--cm-space-1) 0 0 var(--cm-text-muted);

  /* Progress bars (components/progress.css). */
  --cm-progress-height: 5px;

  /* Customer pages (portal and request flow, CSS phase 6). */
  --cm-loader-wash-edge: #d9d9d9; /* the portal wait screen's wash, its outer stop (pages/portal.css) */
  /* The reCAPTCHA challenge overlay (components/challenge.css). */
  --cm-bg-backdrop-challenge: rgba(0, 0, 0, 0.55);
  --cm-challenge-text: #1f2937;
  --cm-challenge-cancel: #6b7280; /* the Cancel link */
  --cm-shadow-challenge: 0 10px 30px rgba(0, 0, 0, 0.3);
  /* Sizing a customer site can change on its :root (the portal's
     pages/portal.css, portal refresh): the parts of the field, button, card,
     banner and pill looks the components read through these. The defaults
     are the staff look, so a site that sets none of them is unchanged. */
  --cm-control-radius: var(--cm-radius-sm); /* text fields and selects (base.css) */
  --cm-field-gap: var(--cm-space-1); /* label to control (components/field.css) */
  --cm-field-label-size: var(--cm-text-xs);
  --cm-field-label-color: var(--cm-text-muted);
  --cm-field-label-case: uppercase;
  --cm-field-label-tracking: 0.04em;
  --cm-button-radius: var(--cm-radius-md); /* components/button.css */
  --cm-button-font-size: var(--cm-text-sm);
  --cm-button-font-weight: var(--cm-fw-medium);
  --cm-button-padding-x: var(--cm-space-4);
  --cm-card-radius: var(--cm-radius-xl); /* components/card.css */
  --cm-card-border: var(--cm-border);
  --cm-card-shadow: var(--cm-shadow-md);
  --cm-banner-radius: var(--cm-radius-lg); /* components/banner.css */
  --cm-pill-font-size: var(--cm-text-xs); /* components/pill.css */
  --cm-pill-padding-x: var(--cm-space-2);
  /* A rejected field on a customer page: a red edge and a soft red halo
     (the portal sets --cm-shadow-invalid to it). */
  --cm-shadow-invalid-customer: 0 0 0 1px var(--cm-danger-700), 0 0 0 4px rgba(185, 28, 28, 0.12);
  --cm-text-caption: 0.8125rem; /* 13px: the portal's eyebrows, pills and light footer */
  --cm-text-total: 2.5rem; /* 40px: the amount in the portal's invoice total */
  --cm-text-total-phone: 2.125rem; /* 34px */
  /* The selected option of the portal's two-way switch, raised off its
     track: a lift and a slate-500 edge (4.3:1 on the track, so the choice
     shows without the color change, WCAG 1.4.11). */
  --cm-shadow-switch-selected:
    0 1px 3px rgba(15, 23, 42, 0.12), inset 0 0 0 1px var(--cm-border-strong);
  /* A portal card's lift, in place of its border. */
  --cm-shadow-card-customer: 0 1px 2px rgba(15, 23, 42, 0.05), 0 10px 32px rgba(15, 23, 42, 0.1);
  /* The Midnight hero band (components/hero.css): navy with a teal glow in
     its top corner, the same in both themes (customer pages are light only).
     On #0f172a: white title 17.9:1, #cbd5e1 text 12.0:1, teal-300 eyebrow
     and focus ring 12.1:1, teal-200 links 14.2:1 (customer.contrast.test.mjs
     checks them, on the glow too). */
  --cm-hero-bg: #0f172a;
  --cm-hero-glow: radial-gradient(
    60% 150% at 100% 0%,
    rgba(20, 184, 166, 0.26) 0%,
    rgba(20, 184, 166, 0) 60%
  );
  --cm-hero-title: #ffffff;
  --cm-hero-text: #cbd5e1;
  --cm-hero-eyebrow: #5eead4;
  --cm-hero-link: #99f6e4;
  --cm-hero-focus: #5eead4;
  --cm-hero-title-size: 2.375rem; /* 38px */
  --cm-hero-title-size-short: 2rem; /* 32px, results and the list */
  --cm-hero-title-size-phone: 1.6875rem; /* 27px */
  /* The steps on the band (components/stepper.css, --on-dark): a pending
     step's ring and the connector before it, slate-500 (3.75:1 on the
     navy), and its label, slate-400 (7.0:1). Done and current take the
     eyebrow's teal-300; the labels the link and title colors. */
  --cm-hero-step-ring: #64748b;
  --cm-hero-step-muted: #94a3b8;
  /* The request flow's compact progress bar on the band
     (components/progress.css --on-dark): a slate-700 track under the
     teal-300 fill (7.0:1). */
  --cm-hero-track: #334155;
  /* Loading placeholders (components/skeleton.css): a soft bar with a
     lighter band sweeping across it, on the page and on the hero band. */
  --cm-skeleton: var(--cm-gray-100);
  --cm-skeleton-shine: var(--cm-gray-200);
  --cm-skeleton-on-dark: #1e293b;
  --cm-skeleton-on-dark-shine: #334155;
  /* A secondary button on the band (components/button.css, --on-dark with
     --secondary): a translucent fill and ring, white text. */
  --cm-button-on-dark-bg: rgba(255, 255, 255, 0.08);
  --cm-button-on-dark-bg-hover: rgba(255, 255, 255, 0.16);
  --cm-button-on-dark-border: rgba(255, 255, 255, 0.35);
  /* Pinned dark chrome for the PDF editor and right-sidebar surfaces: one
     step lighter than --cm-bg-sidebar (#0f172a), the value dark mode's
     --cm-bg-surface resolves to, so chrome surfaces do not blend into the
     navbar and sidebar. Same in light and dark mode. */
  --cm-bg-chrome: #131c2e;
}

:root.dark {
  /* Raw gray scale flipped — 0 is now deepest, 900 is the lightest visible.
     Surface steps spaced wider than the original palette so cards / rows /
     headers read as distinct elevation tiers, and borders bumped lighter
     so they're visible against the (still dark) surface they sit on. */
  --cm-gray-0: #0b1220;
  --cm-gray-50: #131c2e;
  --cm-gray-100: #1e293b;
  --cm-gray-200: #3b4a63;
  --cm-gray-300: #4b5c76;
  --cm-gray-400: #5f7290;
  --cm-gray-500: #b6c2d2;
  --cm-gray-700: #e8eef5;
  --cm-gray-900: #ffffff;

  /* Accent — lighter steps for AA on dark surfaces. 800/900 deliberately absent. */
  --cm-accent-500: #2dd4bf;
  --cm-accent-600: #5eead4;
  --cm-accent-700: #99f6e4;
  --cm-accent-ring: 45 212 191;

  /* QA chip: dark keeps the lighter blue (light mode's --cm-blue-500) so it
     still reads on the dark surface. */
  --cm-blue-600: #3b82f6;

  /* Background semantic tokens — REMAPPED so layered surfaces get
     progressively lighter (visual-depth direction is inverted vs light) */
  --cm-bg-body: var(--cm-gray-0);
  --cm-bg-surface: var(--cm-gray-50);
  --cm-bg-raised: var(--cm-gray-100);
  --cm-bg-muted: var(--cm-gray-100);
  /* --cm-bg-sidebar would inherit --cm-gray-900 from :root, which after this
     scale redefinition resolves to #F8FAFC — that would invert the sidebar
     to LIGHT in dark mode, which is wrong. Pin it explicitly: */
  --cm-bg-sidebar: #0f172a;

  /* Text-on-dark: in dark mode, the gray scale flipped, so --cm-gray-0 = #0B1020
     (deepest). We need text-on-dark to STILL mean "light text", so re-anchor it
     to the lightest end of the redefined scale. */
  --cm-text-on-dark: var(--cm-gray-900);

  /* Text-on-interactive: dark-mode .cm-button bg resolves to teal-500 dark =
     #2DD4BF (bright accent). White text on it is 1.86:1 (FAIL). Pin foreground
     to deep slate (#0F172A) — 9.59:1 AAA. This is the inverse of light mode,
     where --cm-interactive is teal-700 and white text reads. */
  --cm-text-on-interactive: #0f172a;

  /* Interactive remap for dark-mode .cm-button: keep the bright dark-mode teals
     (already redefined above) so the button reads as a vivid accent against
     the near-black surface. Hover lightens, active lightens further — opposite
     direction from light mode but consistent with the inverted scale. */
  --cm-interactive: var(--cm-teal-500); /* dark = #2DD4BF */
  --cm-interactive-hover: var(--cm-teal-600); /* dark = #5EEAD4 */
  --cm-interactive-active: var(--cm-teal-700); /* dark = #99F6E4 */
  --cm-control-accent: var(--cm-interactive); /* dark: --cm-accent-800 is 2.25:1 on the surface */

  /* Border-strong: light-mode value (gray-500) re-resolves through the dark
     scale to #94A3B8 — that hits 6.92:1 vs bg-surface, which is correct.
     The base :root rule already maps via raw scale, so no override needed
     here — listed for clarity. */
  /* --cm-border-strong: var(--cm-gray-500);   inherited */

  /* Border: light mode moved --cm-border to gray-400 for contrast. Dark keeps
     gray-200 (#3b4a63, 1.90:1 on the surface), which is what it always was. */
  --cm-border: var(--cm-gray-200);

  /* --cm-text-heading currently re-resolves to gray-900 = #F8FAFC (light) which
     is correct for headings. Same for --cm-text-body (gray-700 = #E2E8F0).
     --cm-text-muted (gray-500 = #94A3B8) — fine. No additional overrides needed. */

  /* Text semantic tokens are NOT redefined here: they re-resolve through the
     redefined raw scale: --cm-text-body still points at --cm-gray-700, which
     in this mode = #E2E8F0 (light text). Same for headings (--cm-gray-900 →
     #F8FAFC). --cm-border is the exception, pinned above, because light mode
     points it at gray-400. */

  /* Shadows — slate alpha doesn't read on dark, use black */
  --cm-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --cm-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4);
  --cm-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.55), 0 2px 4px rgba(0, 0, 0, 0.4);
  --cm-shadow-lg: 0 12px 24px rgba(0, 0, 0, 0.6), 0 4px 8px rgba(0, 0, 0, 0.45);
  --cm-focus-ring: 0 0 0 3px rgb(var(--cm-accent-ring) / 0.45);

  /* Re-lightened from the light-mode values for contrast against the
     dark chip background. --cm-warning-text is also the warning pill's
     dark text (components/pill.css). */
  --cm-success-text: #4ade80;
  --cm-warning-text: #fcd34d;
  --cm-danger-text: #f87171;
  --cm-info-text: #93c5fd;
  --cm-accent-text: var(--cm-accent-300);
  /* Status pill tints (components/pill.css): the hue mixed over the dark
     surface, so a pill stays opaque instead of relying on a translucent
     fill composited over whatever it sits on. */
  --cm-bg-info-soft: color-mix(in srgb, var(--cm-blue-500) 20%, var(--cm-bg-surface));
  --cm-bg-accent-soft: color-mix(in srgb, rgb(var(--cm-accent-ring)) 20%, var(--cm-bg-surface));
  --cm-bg-success-soft: color-mix(in srgb, var(--cm-success-500) 22%, var(--cm-bg-surface));
  --cm-bg-warning-soft: color-mix(in srgb, var(--cm-warning-500) 22%, var(--cm-bg-surface));
  --cm-bg-danger-soft: color-mix(in srgb, var(--cm-danger-500) 22%, var(--cm-bg-surface));

  --cm-avatar-bg: var(--cm-gray-700); /* a light disc in dark mode, as today */
  --cm-avatar-fg: var(--cm-gray-100);
  --cm-avatar-chip-disc-bg: var(--cm-gray-200);
  --cm-avatar-chip-disc-fg: var(--cm-accent-300);
  --cm-avatar-you-disc-bg: var(--cm-accent-600);
}

/*
 * ChartMate design tokens (light mode).
 *
 * Two layers:
 *   1. Raw scales (--cm-teal-*, --cm-gray-*, --cm-blue-*, semantic colors,
 *      typography, spacing, radius, shadow). Numerically consistent: low =
 *      light, high = dark.
 *   2. Semantic tokens (--cm-bg-*, --cm-text-*, --cm-border, --cm-interactive)
 *      that map raw scale steps to roles. Consumed by the staff stylesheets.
 *
 * Dark-mode overrides redefine the raw gray scale and re-map background
 * semantic tokens (text/border tokens re-resolve through the redefined
 * scale). See the :root.dark block above.
 */

:root[data-accent='orange'] {
  --cm-accent-50: #fff7ed;
  --cm-accent-100: #ffedd5;
  --cm-accent-300: #fdba74;
  --cm-accent-500: #f97316;
  --cm-accent-600: #ea580c;
  --cm-accent-700: #c2410c;
  --cm-accent-800: #9a3412;
  --cm-accent-900: #7c2d12;
  --cm-accent-ring: 249 115 22;
}
:root.dark[data-accent='orange'] {
  --cm-accent-500: #fb923c;
  --cm-accent-600: #fdba74;
  --cm-accent-700: #fed7aa;
  --cm-accent-ring: 251 146 60;
}

:root[data-accent='green'] {
  --cm-accent-50: #f0fdf4;
  --cm-accent-100: #dcfce7;
  --cm-accent-300: #86efac;
  --cm-accent-500: #22c55e;
  --cm-accent-600: #16a34a;
  --cm-accent-700: #15803d;
  --cm-accent-800: #166534;
  --cm-accent-900: #14532d;
  --cm-accent-ring: 34 197 94;
}
:root.dark[data-accent='green'] {
  --cm-accent-500: #4ade80;
  --cm-accent-600: #86efac;
  --cm-accent-700: #bbf7d0;
  --cm-accent-ring: 74 222 128;
}

:root[data-accent='violet'] {
  --cm-accent-50: #f5f3ff;
  --cm-accent-100: #ede9fe;
  --cm-accent-300: #c4b5fd;
  --cm-accent-500: #8b5cf6;
  --cm-accent-600: #7c3aed;
  --cm-accent-700: #6d28d9;
  --cm-accent-800: #5b21b6;
  --cm-accent-900: #4c1d95;
  --cm-accent-ring: 139 92 246;
}
:root.dark[data-accent='violet'] {
  --cm-accent-500: #a78bfa;
  --cm-accent-600: #c4b5fd;
  --cm-accent-700: #ddd6fe;
  --cm-accent-ring: 167 139 250;
}

:root[data-accent='fuchsia'] {
  --cm-accent-50: #fdf4ff;
  --cm-accent-100: #fae8ff;
  --cm-accent-300: #f0abfc;
  --cm-accent-500: #d946ef;
  --cm-accent-600: #c026d3;
  --cm-accent-700: #a21caf;
  --cm-accent-800: #86198f;
  --cm-accent-900: #701a75;
  --cm-accent-ring: 217 70 239;
}
:root.dark[data-accent='fuchsia'] {
  --cm-accent-500: #e879f9;
  --cm-accent-600: #f0abfc;
  --cm-accent-700: #f5d0fe;
  --cm-accent-ring: 232 121 249;
}

:root[data-accent='rose'] {
  --cm-accent-50: #fff1f2;
  --cm-accent-100: #ffe4e6;
  --cm-accent-300: #fda4af;
  --cm-accent-500: #f43f5e;
  --cm-accent-600: #e11d48;
  --cm-accent-700: #be123c;
  --cm-accent-800: #9f1239;
  --cm-accent-900: #881337;
  --cm-accent-ring: 244 63 94;
}
:root.dark[data-accent='rose'] {
  --cm-accent-500: #fb7185;
  --cm-accent-600: #fda4af;
  --cm-accent-700: #fecdd3;
  --cm-accent-ring: 251 113 133;
}

/* The neutral slot. Warm-cast on purpose: the dark ground is navy (220°), so a
   cool blue-grey neutral — the old Slate — was the background's own hue with the
   chroma drained out, and disappeared. Chroma here is low enough not to collide
   with Orange, but the warmth gives it somewhere to stand. */
:root[data-accent='stone'] {
  --cm-accent-50: #fafaf9;
  --cm-accent-100: #f5f5f4;
  --cm-accent-300: #d6d3d1;
  --cm-accent-500: #78716c;
  --cm-accent-600: #57534e;
  --cm-accent-700: #44403c;
  --cm-accent-800: #292524;
  --cm-accent-900: #1c1917;
  --cm-accent-ring: 120 113 108;
}
:root.dark[data-accent='stone'] {
  --cm-accent-500: #a8a29e;
  --cm-accent-600: #d6d3d1;
  --cm-accent-700: #e7e5e4;
  /* Unlike every other hue, the neutral MUST re-darken 800/900 for dark mode.
     Its light 800/900 (#292524/#1c1917) are near-black — on the navy ground they
     measure 1.12:1 and the button simply vanishes, while white-on-them scores 15:1
     so no contrast test complains. These values restore parity with the chromatic
     hues (2.23:1 vs bg-surface) while keeping white text readable at 7.63:1. */
  --cm-accent-800: #57534e;
  --cm-accent-900: #44403c;
  --cm-accent-ring: 168 162 158;
}

/*
 * ── Accent hues ──────────────────────────────────────────────────────────────
 * Selected via <html data-accent="…">, set pre-paint by theme-bootstrap.js.
 * Teal needs no block: :root / :root.dark already carry its values.
 *
 * INVARIANT: each :root.dark[data-accent] block MUST restate every literal
 * :root.dark sets (--cm-accent-500/600/700, --cm-accent-ring), because
 * :root.dark and :root[data-accent] have equal specificity (0,2,0).
 * Do NOT add --cm-focus-ring here (it indirects through --cm-accent-ring).
 * Do NOT add 800/900 for a chromatic hue — they must stay dark in both modes.
 * EXCEPTION: stone (the neutral slot) re-darkens 800/900 in dark mode — see
 * the block above. Its light 800/900 are near-black and read as invisible on
 * the navy dark ground even though white-on-them still scores AA; every other
 * hue's light 800/900 stays dark enough to keep working unmodified.
 * Enforced by tests/unit/frontend/theme/tokens.contrast.test.mjs.
 */

}
@layer base {
/*
 * Element defaults and typography (CSS consolidation phase 3c). staff.css,
 * portal.css and request.css import this file into layer(base), which sits
 * BELOW layer(legacy): a legacy rule that targets the same element wins over
 * these defaults whatever its specificity. Only element, pseudo-element, html
 * and body selectors belong here (tests/unit/frontend/stylesheets); component
 * styling goes in components/.
 * Spec: docs/specs/2026-09-29-css-phase-3-base-layout-design.md
 */

/* Inter, self-hosted, Latin subset */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/_shared/assets/fonts/Inter-Regular.woff2') format('woff2');
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/_shared/assets/fonts/Inter-Medium.woff2') format('woff2');
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/_shared/assets/fonts/Inter-SemiBold.woff2') format('woff2');
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/_shared/assets/fonts/Inter-Bold.woff2') format('woff2');
}

html {
  font-family: var(--cm-font-sans);
  font-size: var(--cm-font-size-root);
}

body {
  margin: 0;
  padding: 0;
  background: var(--cm-bg-body);
  color: var(--cm-text-body);
  font-family: var(--cm-font-sans);
  line-height: var(--cm-lh-normal);
  font-feature-settings: 'cv11', 'ss01';
  /* Safety net: tooltip pseudo-elements positioned with absolute x-offsets
     can momentarily overflow the viewport before the JS positioner runs.
     overflow-x: clip stops them from widening the page; clip (not hidden)
     does not create a containing block, so position: fixed children (toasts,
     modals) keep working. */
  overflow-x: clip;
}

/* Text color inherits from body. Only the elements the browser colors on
   its own (form controls, dialog, mark) are set back to body text here, so
   an icon or inline SVG inside a colored container takes that container's
   color through currentColor. */
button,
input,
select,
textarea,
dialog,
mark {
  color: var(--cm-text-body);
}

/* Links default to the interactive color (the dark rail sets its own);
   a link in text also takes .cm-link for its underline (components/link.css). */
a {
  color: var(--cm-interactive);
}

h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0;
  padding: 0;
  color: var(--cm-text-heading);
  line-height: var(--cm-lh-tight);
}

h1 {
  font-size: var(--cm-text-2xl);
  font-weight: var(--cm-fw-semibold);
}

h2 {
  font-size: var(--cm-text-xl);
  font-weight: var(--cm-fw-semibold);
}

h3 {
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-semibold);
}

h4 {
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-semibold);
}

p {
  margin: 2px;
  padding: 2px;
}

hr {
  width: 100%;
  margin: 0;
  padding: 0;
  border-color: var(--cm-text-body);
}

table,
td,
th {
  font-feature-settings: 'tnum';
}

input,
button,
select,
textarea {
  font-family: var(--cm-font-sans);
  font-size: inherit;
}

/* Form fields: outlined, 24px (owner decision 2026-09-29, border kept after
   reviewing the underline-only version). The focus and disabled states come
   after the field rules below, so they win at equal specificity. */
input:not([type]),
input[type='text'],
input[type='email'],
input[type='password'],
input[type='number'],
input[type='search'],
input[type='date'],
input[type='tel'],
input[type='url'],
select,
textarea {
  box-sizing: border-box;
  height: var(--cm-control-height);
  margin: 0;
  padding: 0 var(--cm-space-3);
  border: 1px solid var(--cm-border-strong);
  border-radius: var(--cm-control-radius);
  background: var(--cm-bg-surface);
  box-shadow: none;
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  transition:
    border-color 120ms ease,
    box-shadow 120ms ease,
    background-color 120ms ease;
}

select {
  appearance: none;
  cursor: pointer;
  padding-right: var(--cm-space-5);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--cm-text-muted) 50%),
    linear-gradient(135deg, var(--cm-text-muted) 50%, transparent 50%);
  background-position:
    calc(100% - 10px) 50%,
    calc(100% - 6px) 50%;
  background-size: 4px 4px;
  background-repeat: no-repeat;
}

select[multiple] {
  height: auto;
  padding-right: var(--cm-space-3);
  background-image: none;
}

textarea {
  height: auto;
  min-height: calc(var(--cm-control-height) * 2.5);
  padding: var(--cm-space-1) var(--cm-space-3);
  line-height: var(--cm-lh-normal);
}

:is(input, select, textarea):is([readonly], [aria-readonly='true']) {
  background-color: var(--cm-bg-readonly);
  cursor: default;
}

/* Focus and disabled states for every field (moved from stylesheetv3.css in
   CSS phase 5). After the field and read-only rules, so they win. */
input:focus,
input:focus-visible,
select:focus,
select:focus-visible,
textarea:focus,
textarea:focus-visible {
  border-color: var(--cm-interactive);
  box-shadow: var(--cm-focus-ring);
  outline: none;
}

input:disabled,
select:disabled:not([aria-readonly='true']),
textarea:disabled {
  background: var(--cm-bg-muted);
  color: var(--cm-text-muted);
  cursor: not-allowed;
}

/* The keyboard focus ring for links and anything focusable by tabindex. */
a:focus-visible,
[role='button']:focus-visible,
[tabindex]:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
  border-radius: var(--cm-radius-sm);
}

input::placeholder {
  opacity: 0.7;
}

input::placeholder,
textarea::placeholder {
  color: var(--cm-text-muted);
}

input[type='checkbox'],
input[type='radio'] {
  height: 18px;
  width: 18px;
  accent-color: var(--cm-control-accent);
}

input[type='file']::file-selector-button {
  margin-right: 20px;
  border: none;
  padding: 10px;
  border-radius: var(--cm-radius-lg);
  background: var(--cm-accent-800);
  background-image: linear-gradient(92.88deg, var(--cm-accent-800) 0%, var(--cm-accent-900) 80%);
  cursor: pointer;
  transition: background 0.2s ease-in-out;
  color: var(--cm-text-on-dark);
  line-height: 18px;
}

::-webkit-scrollbar {
  width: var(--scrollbar-thickness);
  height: var(--scrollbar-thickness);
}

::-webkit-scrollbar-track {
  background: var(--cm-scrollbar-track);
}

::-webkit-scrollbar-thumb {
  background: var(--cm-accent-900);
  border-radius: var(--cm-radius-md);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--cm-accent-800);
}

}

@layer components {
/* Buttons (phase 4, docs/specs/2026-10-07-css-phase-4-buttons-design.md).
 *   .cm-button                  main action: teal fill
 *   --secondary / --danger      gray outline / red outline
 *   --text                      teal text
 *   --icon (+ --on-dark)        square icon button (aria-label required)
 *   --secondary --on-dark       a secondary button on a dark band (the portal's hero)
 *   --block                     full width (one height for every button: --cm-button-height)
 *   --icon --sm                 a small icon square at the field height (--cm-button-height-sm)
 *   --busy                      waiting on its action: a spinner in place of the label
 * Radius, text size and weight and side padding come from tokens
 * (--cm-button-*, tokens.css), which the portal resizes on its :root.
 * An icon button hovers in a teal border, the selected tint and a teal icon,
 * the same hover as the popup, drawer and toast closes (CSS phase 5.5
 * restyle); --on-dark keeps its own.
 * Disabled comes last so it wins for every look.
 * [aria-disabled="true"] is a look and assistive-tech state only: it does not
 * stop focus or clicks, the caller must block activation itself.
 */

.cm-button {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--cm-space-2);
  flex-shrink: 0;
  height: var(--cm-button-height);
  margin: 0;
  padding: 0 var(--cm-button-padding-x);
  border: 1px solid transparent;
  border-radius: var(--cm-button-radius);
  background: var(--cm-interactive);
  color: var(--cm-text-on-interactive);
  font-family: inherit;
  font-size: var(--cm-button-font-size);
  font-weight: var(--cm-button-font-weight);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color 120ms ease,
    border-color 120ms ease;
}

.cm-button * {
  color: inherit;
}

.cm-button:hover {
  background: var(--cm-interactive-hover);
}

.cm-button:active {
  background: var(--cm-interactive-active);
}

.cm-button:focus-visible {
  outline: none;
  border-radius: var(--cm-button-radius);
  box-shadow: var(--cm-focus-ring);
}

.cm-button--secondary,
.cm-button--danger,
.cm-button--text {
  background: transparent;
}

.cm-button--secondary {
  border-color: var(--cm-border-strong);
  color: var(--cm-text-body);
}

.cm-button--danger {
  border-color: var(--cm-danger-text);
  color: var(--cm-danger-text);
}

/* :is(:hover, :active) so holding Space on a focused button (:active with no
 * :hover) gets the same look as a mouse hover, instead of falling through to
 * the base .cm-button:active rule's primary accent fill. */
.cm-button--secondary:is(:hover, :active),
.cm-button--danger:is(:hover, :active) {
  background: var(--cm-bg-muted);
}

.cm-button--icon:is(:hover, :active) {
  border-color: var(--cm-interactive);
  background: var(--cm-chip-selected-bg);
  color: var(--cm-interactive);
}

.cm-button--text {
  padding: 0 var(--cm-space-1);
  color: var(--cm-interactive);
}

.cm-button--text:is(:hover, :active) {
  background: transparent;
}

.cm-button--text:hover {
  text-decoration: underline;
}

.cm-button--icon {
  width: var(--cm-button-height);
  padding: 0;
  border-color: var(--cm-border-strong);
  background: var(--cm-bg-surface);
  color: var(--cm-text-body);
}

.cm-button--on-dark {
  background: transparent;
  border-color: transparent;
  color: var(--cm-text-on-dark);
}

.cm-button--on-dark:is(:hover, :active) {
  border-color: transparent;
  background: var(--cm-bg-on-dark-hover);
  color: var(--cm-text-on-dark);
}

/* --on-dark with --secondary: a secondary button on a dark band (the
   portal's hero band, components/hero.css): a translucent fill and ring,
   white text. */
.cm-button--secondary.cm-button--on-dark {
  border-color: var(--cm-button-on-dark-border);
  background: var(--cm-button-on-dark-bg);
  color: var(--cm-text-on-dark);
}

.cm-button--secondary.cm-button--on-dark:is(:hover, :active) {
  border-color: var(--cm-button-on-dark-border);
  background: var(--cm-button-on-dark-bg-hover);
}

.cm-button--icon.cm-button--sm {
  width: var(--cm-button-height-sm);
  height: var(--cm-button-height-sm);
}

.cm-button--block {
  width: 100%;
}

.cm-button:is(:disabled, [aria-disabled='true']) {
  background: var(--cm-bg-muted);
  border-color: transparent;
  color: var(--cm-text-muted);
  cursor: not-allowed;
}

.cm-button:is(.cm-button--text, .cm-button--on-dark):is(:disabled, [aria-disabled='true']) {
  background: transparent;
  text-decoration: none;
}

/* --busy: a submit waiting on its action (the portal's sign-in steps). The
   caller empties the label, disables the button and sets aria-busy; a
   spinner in the text color takes the label's place. After the disabled
   rules so its cursor wins. */
.cm-button.cm-button--busy {
  cursor: progress;
}

.cm-button--busy::before {
  content: '';
  box-sizing: border-box;
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: cm-button-spin 0.7s linear infinite;
}

@keyframes cm-button-spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .cm-button--busy::before {
    animation-duration: 2s;
  }
}

}
@layer components {
/*
 * Field (CSS consolidation phase 4, forms PR 1). Spec:
 * docs/specs/2026-10-05-css-phase-4-forms-design.md
 * Markup:
 *   div.cm-field > label.cm-field__label (+ span.cm-field__required),
 *     control, p.cm-field__hint?, p.cm-field__error?
 *   label.cm-field > span.cm-field__label (+ span.cm-field__required) +
 *     control (wrapping shape; patient alerts)
 *   label.cm-field.cm-field--check[.cm-field--plain] >
 *     input[type=checkbox|radio] + text
 *   span.cm-field__help-row > (label.cm-field__label | label.cm-field--check)
 *     + span.cm-help-icon (addFieldHelp(); in a div.cm-field the row takes
 *     the label's place, before the control)
 *   span.cm-field__help-row.cm-field__help-row--spread > label + end item
 *     (the row spans the field, its last child at the end)
 * A checkbox row is a chip (CSS phase 5.5 restyle, docs/specs/
 * 2026-10-12-css-phase-5-5-restyle-design.md); with a help icon the
 * help row is the chip. Radio rows and --plain rows (long checklists, the
 * report builder's) stay plain.
 *   div.cm-field > span.cm-field__label#id + div.cm-field__choices[--stacked]
 *     [role=group][aria-labelledby=id] > one label.cm-chip-toggle--pill per
 *     choice (buildPillChip(); e.g. the merge popup's customer checks,
 *     stacked). A section heading can name the group instead (the Customer
 *     popup's Customer Type pills).
 * The control's own look (outlined, --cm-control-height) comes from
 * base.css; nothing here restates it.
 */

.cm-field {
  display: flex;
  flex-direction: column;
  gap: var(--cm-field-gap);
  min-width: 0;
}

/* Excludes checkbox/radio: they keep base.css's 18px square (components
   always outranks base by layer, so even "width: auto" here would beat it;
   see .cm-field--check > input below, which only resets their margin). The
   exclusion lives inside :where() so it costs no specificity (a bare :not()
   here would out-rank the other rules in this file for no reason). */
.cm-field > :where(input:not([type='checkbox'], [type='radio']), select, textarea) {
  width: 100%;
}

/* A tight line box (CSS phase 5.5 restyle) so the label sits about 4px
   above its control rather than 7px. Size, color, case and tracking come
   from tokens: small caps here, sentence case on the portal (pages/portal.css). */
.cm-field__label {
  font-size: var(--cm-field-label-size);
  line-height: var(--cm-lh-tight);
  font-weight: var(--cm-fw-medium);
  color: var(--cm-field-label-color);
  text-transform: var(--cm-field-label-case);
  letter-spacing: var(--cm-field-label-tracking);
  text-align: left;
}

.cm-field__required {
  margin-left: 2px;
  color: var(--cm-danger-text);
}

.cm-field__hint {
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-xs);
  color: var(--cm-text-muted);
}

.cm-field__error {
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-sm);
  color: var(--cm-danger-text);
}

/* A checkbox or radio with its option text: the text is a choice, not a
   field label, so it stays sentence case body text. Declares its own case,
   tracking and weight rather than inheriting them, so a --check label
   dropped inside a legacy uppercase label context (e.g.
   a search bar field) is not left shouting. */
.cm-field--check {
  flex-direction: row;
  align-items: center;
  gap: var(--cm-space-2);
  font-size: var(--cm-text-sm);
  color: var(--cm-text-body);
  text-transform: none;
  letter-spacing: normal;
  font-weight: var(--cm-fw-regular);
  cursor: pointer;
  user-select: none;
}

.cm-field--check > input {
  margin: 0;
  /* Option text can wrap to two or more lines (narrow containers, long
     option copy); without this the checkbox is a flex item with the
     default flex-shrink: 1 and shrinks along with the row, collapsing
     well below its 18px square (base.css) instead of staying put beside
     the wrapped text. */
  flex-shrink: 0;
}

/* The check chip: a pill at the field height around a 14px box and the
   option text in the field label's small caps. A row with a help icon
   (.cm-field__help-row) is the chip instead, its label plain inside it and
   the icon beside the label. width: fit-content keeps a chip at its text in
   a stretching column, so blank space beside it is not a click target.
   The :where() keeps these at one class of specificity. */
.cm-field--check:where(
  :not(.cm-field--plain, .cm-field__help-row > *):has(> input[type='checkbox'])
),
.cm-field__help-row:where(:has(> .cm-field--check:not(.cm-field--plain) > input[type='checkbox'])) {
  box-sizing: border-box;
  width: fit-content;
  max-width: 100%;
  min-height: var(--cm-control-height);
  padding: 2px 10px;
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-pill);
  background: var(--cm-bg-surface);
  transition:
    background-color 120ms ease,
    border-color 120ms ease;
}

.cm-field--check:where(:not(.cm-field--plain):has(> input[type='checkbox'])) {
  gap: 6px;
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.cm-field--check:where(:not(.cm-field--plain)) > input[type='checkbox'] {
  width: 14px;
  height: 14px;
}

.cm-field__help-row:where(:has(> .cm-field--check:not(.cm-field--plain) > input[type='checkbox'])) {
  gap: 0;
  padding: 0 var(--cm-space-1) 0 0;
}

/* ...and its label takes the chip's padding and full height, so the whole
   pill but the icon toggles the box, as a plain chip does. */
.cm-field__help-row > .cm-field--check:where(:not(.cm-field--plain):has(> input[type='checkbox'])) {
  align-self: stretch;
  padding: 0 6px 0 10px;
}

/* The help icon (components/help-icon.css, its [data-tooltip] chip) is
   spaced by the label's own padding, not a margin. */
.cm-field__help-row:has(> .cm-field--check) > [data-tooltip] {
  margin-left: 0;
}

/* Hover sits inside :where() too, so a checked chip keeps its border. */
.cm-field--check:where(
  :not(.cm-field--plain, .cm-field__help-row > *):has(> input[type='checkbox']):hover
),
.cm-field__help-row:where(
  :has(> .cm-field--check:not(.cm-field--plain) > input[type='checkbox']):hover
) {
  border-color: var(--cm-border-strong);
}

.cm-field--check:where(
  :not(.cm-field--plain, .cm-field__help-row > *):has(> input[type='checkbox']:checked)
),
.cm-field__help-row:where(
  :has(> .cm-field--check:not(.cm-field--plain) > input[type='checkbox']:checked)
) {
  border-color: var(--cm-chip-selected-border);
  background: var(--cm-chip-selected-bg);
  color: var(--cm-text-heading);
}

.cm-field--check:where(:not(.cm-field--plain):has(> input[type='checkbox']:checked)) {
  color: var(--cm-text-heading);
}

.cm-field--check:where(
  :not(.cm-field--plain, .cm-field__help-row > *):has(> input[type='checkbox']:disabled)
),
.cm-field__help-row:where(
  :has(> .cm-field--check:not(.cm-field--plain) > input[type='checkbox']:disabled)
) {
  opacity: 0.55;
  cursor: not-allowed;
}

.cm-field--check:where(:has(> input:disabled)) {
  cursor: not-allowed;
}

/* Pairs a field's label, or a whole check row, with an inline
   .cm-help-icon (components/help-icon.css) on one line. Built by
   addFieldHelp() in dom-helpers.js, which keeps the icon a sibling of the
   label/check row rather than a descendant of it (see that function's doc
   for why). */
.cm-field__help-row {
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-1);
}

/* --spread: the row spans its field and puts its last child at the end
   (Manual Upload's Facility Code label, with the facility notes chip at the
   end of the row). */
.cm-field__help-row--spread {
  display: flex;
  width: 100%;
}

.cm-field__help-row--spread > :last-child {
  margin-left: auto;
}

/* A field's control replaced by a row of choice chips (role=group; e.g.
   the Customer popup's Customer Type picker, buildPillChip() per choice):
   wraps instead of overflowing, rather than restating chip-toggle.css's
   own layout. */
.cm-field__choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cm-space-2);
}

/* One choice per line, each at its own width (the merge popup's customer
   checks). */
.cm-field__choices--stacked {
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 6px;
}

/* A control a page's own check rejected (Invoice's SSA Site Code): the page
   sets aria-invalid="true" on it. */
.cm-field [aria-invalid='true'] {
  box-shadow: var(--cm-shadow-invalid);
}

}
@layer components {
/*
 * Toggle chip (CSS consolidation phase 4, forms PR 2). Spec:
 * docs/specs/2026-10-05-css-phase-4-forms-design.md
 * Markup:
 *   label.cm-chip-toggle > input[type=checkbox] + span (+ i.fa-lock)
 *   button.cm-chip-toggle (a chip with no checkbox, e.g. the esMD status)
 *   label.cm-chip-toggle.cm-chip-toggle--pill > input[type=checkbox]
 *     + span.cm-chip-toggle__check[aria-hidden] + span   (buildPillChip())
 * One on state for every chip in both themes: the accent tint and border
 * (--cm-chip-selected-bg/--cm-chip-selected-border, tokens.css). Those
 * tokens re-resolve under :root.dark through --cm-accent-ring, so no
 * dark override lives here.
 * --locked: forced by another control (e.g. the delivery method); the
 * reason shows in the .cm-tooltip bubble the chip already carries.
 * --in-field: the chip sits inside a field's right edge (the fax Override
 * limit chip in .address-input-wrap, which is the positioned wrapper).
 */

.cm-chip-toggle {
  display: flex;
  align-items: center;
  gap: var(--cm-space-1);
  padding: 1px 6px;
  border-radius: var(--cm-radius-sm);
  background: var(--cm-bg-muted);
  border: 1px solid var(--cm-border);
  color: var(--cm-text-body);
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-regular);
  text-transform: none;
  letter-spacing: normal;
  /* 18px tall in all: fits inside a 24px field with 3px to spare. */
  line-height: 14px;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}

button.cm-chip-toggle {
  font-family: inherit;
  appearance: none;
  margin: 0;
}

.cm-chip-toggle input[type='checkbox'] {
  width: 11px;
  height: 11px;
  margin: 0;
}

.cm-chip-toggle:has(input:checked),
.cm-chip-toggle:has(input:indeterminate) {
  border-color: var(--cm-chip-selected-border);
  background: var(--cm-chip-selected-bg);
}

.cm-chip-toggle .fa-lock {
  display: none;
  /* Exactly 10px (0.625rem), matching the legacy lock icon size. Written
     as calc() against --cm-text-base rather than a literal 0.625rem so
     the raw-value guardrail (tests/unit/frontend/stylesheets/rules.mjs)
     still sees a --cm-* token, not a bare font-size literal. */
  font-size: calc(var(--cm-text-base) * 0.625);
}

/* Centered by its insets, not a transform: a transform would make the chip
   the containing block of its --fixed tooltip bubble, which then lands
   off the chip and widens the scrolling box around it (the Invoice rail). */
.cm-chip-toggle--in-field {
  position: absolute;
  top: 0;
  bottom: 0;
  right: var(--cm-space-1);
  height: fit-content;
  margin-block: auto;
}

.cm-chip-toggle--locked {
  opacity: 0.55;
  cursor: not-allowed;
}

.cm-chip-toggle--locked .fa-lock {
  display: inline;
}

/* Pill: a rounded chip at the field height. The real checkbox is hidden
   but not display: none, so Tab reaches it and Space toggles it. */
.cm-chip-toggle--pill {
  position: relative;
  display: inline-flex;
  /* The base .cm-chip-toggle rule's 1px border is content-box by default
     on a label; without border-box, height: var(--cm-control-height)
     renders 2px taller than the field height it's meant to match. */
  box-sizing: border-box;
  gap: var(--cm-space-2);
  height: var(--cm-control-height);
  padding: 0 var(--cm-space-3);
  border-radius: var(--cm-radius-pill);
  background: var(--cm-bg-surface);
  font-size: var(--cm-text-sm);
  /* No line-height override here: the base .cm-chip-toggle rule's 14px
     already fits inside the pill's 22px content box (24px border-box
     minus the 1px top/bottom border); the pill's own height (set above)
     drives its 24px, not line-height, and align-items: center (also from
     the base rule) keeps the text and check mark centered regardless. */
}

.cm-chip-toggle--pill input[type='checkbox'] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.cm-chip-toggle--pill:hover {
  border-color: var(--cm-border-strong);
}

.cm-chip-toggle--pill:has(input:focus-visible) {
  box-shadow: var(--cm-focus-ring);
}

.cm-chip-toggle--pill:has(input:checked),
.cm-chip-toggle--pill:has(input:indeterminate) {
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-medium);
}

.cm-chip-toggle__check {
  display: none;
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E")
    center / 14px 14px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E")
    center / 14px 14px no-repeat;
}

.cm-chip-toggle--pill:has(input:checked) .cm-chip-toggle__check,
.cm-chip-toggle--pill:has(input:indeterminate) .cm-chip-toggle__check {
  display: block;
}

.cm-chip-toggle--pill:has(input:indeterminate) .cm-chip-toggle__check {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3.5 8h9'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3.5 8h9'/%3E%3C/svg%3E");
}

/* High Contrast Mode / forced colors: the check mark is a masked
   background (currentColor), which a forced-colors palette can otherwise
   wash out to the same color as the chip face. Pin it to the system
   CanvasText color and opt the chip out of further forced-colors repaint,
   and give a checked/indeterminate pill a system Highlight border so it
   reads as selected without relying on the (also forced-colors-flattened)
   accent tint. System color keywords, not literals: the tokens guardrail
   only forbids the standard CSS named colors. */
@media (forced-colors: active) {
  .cm-chip-toggle__check {
    forced-color-adjust: none;
    background: CanvasText;
  }

  .cm-chip-toggle--pill:has(input:checked),
  .cm-chip-toggle--pill:has(input:indeterminate) {
    border-color: Highlight;
  }
}

/* The positioned field wrap a --in-field chip sits in (moved from
   stylesheetv3.css, CSS phase 5). Fax-limit override: in-input adornment chip.
   DeliveryPanel's overrideFaxRow/overrideFaxCheckbox render as a small
   checkbox chip inside the right edge of the delivery-address input on
   Upload Records, Manual Upload, Payer Audits and the Resend popup (the
   Invoice page keeps its chip beside the Deliver To label instead). The
   panel only toggles the chip's hidden attribute on method change; the
   wrapper stays in the layout permanently. */
.address-input-wrap {
  position: relative;
  display: block;
  width: 100%;
}
.address-input-wrap input {
  width: 100%;
  margin: 0;
  box-sizing: border-box;
}
/* Room for the chip only while one shows in the wrap (fax): reserved
   always, it cut a long address off with empty space beside it on every
   other method and on the Invoice page, where no chip sits in the field
   (Automate-oyth). rem (7rem = 112px at the default root size) so a user
   font-size preference scales the room along with the chip text.
   This is the documented exception to "no component or page restates a
   field's border, background, radius, padding or height" (global
   constraints, forms PR 1): a partial padding override to make room for
   the fax-override chip, not a restatement of the field's look. */
.address-input-wrap:has(> .cm-chip-toggle--in-field:not([hidden])) input {
  padding-right: 7rem;
}

}
@layer components {
/* Card (components/card.css): the one card look (the dashboard card),
   its parts, and the inset panel used inside cards and popup bodies.
   Decisions: docs/specs/2026-10-08-css-phase-4-cards-design.md. */

/* Radius, border and shadow come from tokens (--cm-card-*, tokens.css):
   the portal drops the border for a softer lift (pages/portal.css). */
.cm-card {
  background: var(--cm-bg-surface);
  border: 1px solid var(--cm-card-border);
  border-radius: var(--cm-card-radius);
  box-shadow: var(--cm-card-shadow);
  color: var(--cm-text-body);
  min-width: 0;
  box-sizing: border-box;
}

.cm-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
  padding: var(--cm-space-3) var(--cm-space-4);
  border-bottom: 1px solid var(--cm-border);
}

.cm-card__title {
  display: flex;
  align-items: center;
  gap: var(--cm-space-2);
  margin: 0;
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-semibold);
  line-height: var(--cm-lh-tight);
  color: var(--cm-text-heading);
}

/* --lg: the title of a card that is the page's main content (a request
   flow step, CSS phase 6). */
.cm-card__title--lg {
  font-size: var(--cm-text-xl);
}

/* A help icon beside the card's title (a .cm-help-icon,
   components/help-icon.css; CSS phase 5.5 restyle): it hugs the title
   instead of the header's far end. Two classes beat help-icon.css's
   margin. */
.cm-card__header > .cm-card__help {
  margin-left: calc(var(--cm-space-2) - var(--cm-space-3));
  margin-right: auto;
}

.cm-card__subtitle,
.cm-card__hint {
  margin: 0;
  font-size: var(--cm-text-xs);
  color: var(--cm-text-muted);
}

.cm-card__end {
  display: flex;
  align-items: center;
  gap: var(--cm-space-2);
  margin-left: auto;
  font-size: var(--cm-text-xs);
}

.cm-card__body {
  padding: var(--cm-space-4);
}

.cm-card__footer {
  padding: var(--cm-space-2) var(--cm-space-4);
  border-top: 1px solid var(--cm-border);
  font-size: var(--cm-text-xs);
  color: var(--cm-text-muted);
}

/* Figures stay side by side; in a narrow card their labels wrap instead
   (.cm-card__figure has min-width: 0). */
.cm-card__figures {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--cm-space-5);
}

.cm-card__figure {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-1);
  min-width: 0;
}

.cm-card__value {
  font-size: var(--cm-text-2xl);
  font-weight: var(--cm-fw-semibold);
  line-height: var(--cm-lh-tight);
  color: var(--cm-text-heading);
  font-variant-numeric: tabular-nums;
}

.cm-card__value--lg {
  font-size: var(--cm-text-3xl);
}

/* Figures beside buttons in a page header (Post Payments' queue, CSS phase
   5.5 redesigns): a smaller value, so the header keeps its height. */
.cm-card__figures--compact .cm-card__value {
  font-size: var(--cm-text-lg);
}

.cm-card__label {
  font-size: var(--cm-text-xs);
  color: var(--cm-text-muted);
}

.cm-card__label--good {
  color: var(--cm-success-text);
}

.cm-card__label--bad {
  color: var(--cm-warning-text);
}

.cm-card--padded {
  padding: var(--cm-space-4);
}

.cm-card--page {
  padding: var(--cm-space-8);
}

.cm-card--link {
  display: block;
  color: inherit;
  text-decoration: none;
  transition:
    box-shadow 120ms ease,
    transform 120ms ease;
}

.cm-card--link:hover,
.cm-card--link:focus-visible {
  box-shadow: var(--cm-shadow-lg);
  transform: translateY(-1px);
}

.cm-card--link:focus-visible {
  outline: 2px solid var(--cm-interactive);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .cm-card--link,
  .cm-card--link:hover,
  .cm-card--link:focus-visible {
    transition: none;
    transform: none;
  }
}

/* The compound selector lets a selected inset panel beat .cm-card-panel's
   own border, which comes later in this file. */
.cm-card--selected,
.cm-card-panel.cm-card--selected {
  border-color: var(--cm-interactive);
  box-shadow: var(--cm-shadow-selected);
}

.cm-card--tile {
  padding: var(--cm-space-3);
  box-shadow: none;
}

.cm-card--tile.cm-card--accent {
  border: 2px solid var(--cm-interactive);
}

.cm-card--tile.cm-card--danger {
  border: 2px solid var(--cm-danger-text);
}

/* Inset panel: a group inside a card or a popup body. Same surface as the
   card, so it never flips depth between themes. */
.cm-card-panel {
  background: var(--cm-bg-surface);
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-lg);
  padding: var(--cm-space-3);
  color: var(--cm-text-body);
  min-width: 0;
  box-sizing: border-box;
}

}
@layer components {
/* Initials discs and the queue assignee chip (phase 4, docs/specs/2026-10-07-css-phase-4-pills-design.md).
 *   .cm-avatar               a 30px gray initials disc (decorative, aria-hidden)
 *   --xs / --lg / --xl       18px (inside a chip), 36px (Open Task banner), 56px (profile)
 *   --accent                 the interactive fill (your own task, "You")
 *   --on-dark                translucent with a light ring, on the dark profile banner
 *   --chip (+ --you)         the assignee chip: an accent-tinted pill with an --xs
 *                            disc and a __name; --you makes it solid
 * Colors are tokens (tokens.css), so this file has no theme or accent rules.
 */

.cm-avatar {
  box-sizing: border-box;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--cm-avatar-bg);
  color: var(--cm-avatar-fg);
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-medium);
  line-height: 1;
}

.cm-avatar * {
  color: inherit;
}

.cm-avatar--xs {
  width: 18px;
  height: 18px;
  font-size: var(--cm-font-size-avatar-xs);
}

.cm-avatar--lg {
  width: 36px;
  height: 36px;
}

.cm-avatar--xl {
  width: 56px;
  height: 56px;
  font-size: var(--cm-text-xl);
  font-weight: var(--cm-fw-bold);
}

.cm-avatar--accent {
  background: var(--cm-interactive);
  color: var(--cm-text-on-interactive);
}

.cm-avatar--on-dark {
  border: 1px solid var(--cm-border-on-dark-strong);
  background: var(--cm-bg-on-dark-soft);
  color: var(--cm-text-on-dark);
}

.cm-avatar--chip {
  width: auto;
  height: auto;
  gap: var(--cm-space-2);
  padding: 2px var(--cm-space-2) 2px 3px;
  border-radius: var(--cm-radius-pill);
  background: var(--cm-bg-accent-soft);
  color: var(--cm-accent-text);
  line-height: var(--cm-lh-tight);
  white-space: nowrap;
}

.cm-avatar--chip > .cm-avatar {
  background: var(--cm-avatar-chip-disc-bg);
  color: var(--cm-avatar-chip-disc-fg);
}

.cm-avatar--chip.cm-avatar--you {
  background: var(--cm-interactive);
  color: var(--cm-text-on-interactive);
}

.cm-avatar--chip.cm-avatar--you > .cm-avatar {
  background: var(--cm-avatar-you-disc-bg);
  color: var(--cm-text-on-interactive);
}

}
@layer components {
/* Status pills and count bubbles (phase 4, docs/specs/2026-10-07-css-phase-4-pills-design.md).
 *   .cm-pill                        neutral status: gray tint, body text
 *   --info / --accent / --success
 *   / --warning / --danger          a tone: its opaque soft tint and --cm-*-text
 *   --solid (with --danger)         a release restriction: solid red
 *   --solid (with --accent)         a count bubble: the interactive fill
 *   --count                         a number: at least as wide as it is tall
 * One height for every pill: --cm-pill-height (its text size and side
 * padding: --cm-pill-font-size, --cm-pill-padding-x; the portal resizes all
 * three). Theme and accent changes live in the tokens, so this file has no
 * theme rules.
 */

.cm-pill {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--cm-space-1);
  height: var(--cm-pill-height);
  padding: 0 var(--cm-pill-padding-x);
  border-radius: var(--cm-radius-pill);
  background: var(--cm-bg-muted);
  color: var(--cm-text-body);
  font-size: var(--cm-pill-font-size);
  font-weight: var(--cm-fw-medium);
  line-height: var(--cm-lh-tight);
  white-space: nowrap;
}

.cm-pill--info {
  background: var(--cm-bg-info-soft);
  color: var(--cm-info-text);
}

.cm-pill--accent {
  background: var(--cm-bg-accent-soft);
  color: var(--cm-accent-text);
}

.cm-pill--success {
  background: var(--cm-bg-success-soft);
  color: var(--cm-success-text);
}

.cm-pill--warning {
  background: var(--cm-bg-warning-soft);
  color: var(--cm-warning-text);
}

.cm-pill--danger {
  background: var(--cm-bg-danger-soft);
  color: var(--cm-danger-text);
}

.cm-pill--danger.cm-pill--solid {
  background: var(--cm-bg-danger);
  color: var(--cm-text-on-dark);
}

.cm-pill--accent.cm-pill--solid {
  background: var(--cm-interactive);
  color: var(--cm-text-on-interactive);
}

.cm-pill--count {
  min-width: var(--cm-pill-height);
  padding: 0 var(--cm-space-1);
  font-weight: var(--cm-fw-semibold);
  font-variant-numeric: tabular-nums;
}

}
@layer components {
/* Tags and chips (phase 4, docs/specs/2026-10-07-css-phase-4-pills-design.md).
 *   .cm-tag                a gray bordered label (report mode, column type, host)
 *   --muted                quieter: surface fill, muted text (column type badges)
 *   --accent-border        an accent border (the scheduled count)
 *   --danger               danger tint and text (a failing host)
 *   --link                 clickable (<a> or <button>): surface fill, interactive text, 24px
 *   --removable            holds a .cm-tag__remove button, 24px; its __text may wrap
 *   --on-dark              translucent, on the dark profile banner
 *   --mono                 monospace text (an id)
 *   __text, __remove, __dot (--attention)
 * A container recolors its tags by setting --cm-tag-bg, --cm-tag-fg and
 * --cm-tag-border (the Reports sidebar's selected row); never with a
 * .cm-tag selector outside this file.
 */

.cm-tag {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-1);
  height: var(--cm-pill-height);
  padding: 0 var(--cm-space-2);
  border: 1px solid var(--cm-tag-border, var(--cm-border));
  border-radius: var(--cm-radius-pill);
  background: var(--cm-tag-bg, var(--cm-bg-muted));
  color: var(--cm-tag-fg, var(--cm-text-body));
  font-family: inherit;
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-regular);
  line-height: var(--cm-lh-tight);
  white-space: nowrap;
  text-decoration: none;
}

.cm-tag--muted {
  background: var(--cm-tag-bg, var(--cm-bg-surface));
  color: var(--cm-tag-fg, var(--cm-text-muted));
}

.cm-tag--accent-border {
  border-color: var(--cm-tag-border, var(--cm-accent-500));
}

.cm-tag--danger {
  background: var(--cm-tag-bg, var(--cm-bg-danger-soft));
  color: var(--cm-tag-fg, var(--cm-danger-text));
}

.cm-tag--link {
  height: var(--cm-control-height);
  padding: 0 var(--cm-space-3);
  background: var(--cm-bg-surface);
  color: var(--cm-interactive);
  font-weight: var(--cm-fw-medium);
  cursor: pointer;
}

.cm-tag--link:hover {
  background: var(--cm-bg-muted);
}

.cm-tag--link:focus-visible,
.cm-tag--on-dark:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

.cm-tag--removable {
  height: auto;
  min-height: var(--cm-control-height);
  max-width: 100%;
  padding: 2px var(--cm-space-1) 2px var(--cm-space-2);
}

/* A removable chip answers the pointer (CSS phase 5.5 restyle): a firmer
   border and the surface fill. A drop zone chip's upload state border wins
   (components/drop-zone.css). */
.cm-tag--removable:hover {
  border-color: var(--cm-border-strong);
  background: var(--cm-bg-surface);
}

.cm-tag__text {
  min-width: 0;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* A bordered circle (CSS phase 5.5 restyle: the other icon buttons are
   squares, the chip's x stays round). */
.cm-tag__remove {
  flex: none;
  display: inline-grid;
  place-items: center;
  box-sizing: border-box;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 1px solid var(--cm-border-strong);
  border-radius: 50%;
  background: transparent;
  color: var(--cm-text-muted);
  font: inherit;
  line-height: 1;
  cursor: pointer;
}

.cm-tag__remove:hover {
  border-color: var(--cm-danger-text);
  background: var(--cm-bg-danger);
  color: var(--cm-text-on-dark);
}

.cm-tag__remove:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

.cm-tag--on-dark {
  border-color: transparent;
  background: var(--cm-bg-on-dark-soft);
  color: var(--cm-text-on-dark);
}

button.cm-tag--on-dark {
  cursor: pointer;
}

button.cm-tag--on-dark:hover {
  background: var(--cm-bg-on-dark-soft-hover);
}

.cm-tag--mono {
  font-family: var(--cm-font-mono);
}

.cm-tag__dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--cm-border-strong);
}

.cm-tag__dot--attention {
  background: var(--cm-accent-500);
  box-shadow: var(--cm-attention-ring);
}

}
@layer components {
/*
 * Text links (CSS consolidation phase 4, batch 3a). Spec:
 * docs/specs/2026-10-10-css-phase-4-batch3a-design.md
 * .cm-link: a link inside text or a table cell, in the interactive color
 * and always underlined (teal is 1.9:1 against body text, so color alone
 * does not mark it, WCAG 1.4.1).
 * --quiet: a standalone link in a card header or footer ("All batches",
 * "View all"): no underline until hover or keyboard focus.
 * --danger: an overdue or failing item, in the danger text color; combine
 * with --quiet for a standalone one.
 * --dotted: a <button> that reads as the text around it, in the body
 * color, marked clickable by a dotted underline (the facility notes chip on
 * a facility code, common/facility-notes.js).
 * base.css gives every bare <a> the interactive color too, so a link with
 * no class is never the near-white the dark rail uses.
 */

.cm-link {
  color: var(--cm-interactive);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.cm-link:hover {
  text-decoration-thickness: 2px;
}

.cm-link:focus-visible {
  outline: 2px solid var(--cm-interactive);
  outline-offset: 2px;
  border-radius: var(--cm-radius-sm);
}

.cm-link--quiet {
  text-decoration: none;
}

.cm-link--quiet:hover,
.cm-link--quiet:focus-visible {
  text-decoration: underline;
}

.cm-link--danger {
  color: var(--cm-danger-text);
}

.cm-link--danger:focus-visible {
  outline-color: var(--cm-danger-text);
}

/* --line: a link on its own line in small text under a table cell's value
   (the Payer Audit link under a request number). */
.cm-link--line {
  display: block;
  font-size: var(--cm-text-xs);
}

/* --dotted: a <button> reset to inline text (the facility notes chip). Its
   mark, a .cm-status-dot (components/status.css), sits after the code; the
   flex row keeps the underline under the code alone and centers the mark on
   the text. */
.cm-link--dotted {
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-1);
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--cm-text-body);
  font: inherit;
  text-align: inherit;
  text-decoration-style: dotted;
  text-decoration-color: var(--cm-border-strong);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}

.cm-link--dotted:hover,
.cm-link--dotted[aria-expanded='true'] {
  text-decoration-color: var(--cm-interactive);
}

/* Inset ring: the chip sits in the page header's subtitle, whose overflow:hidden
   (for the ellipsis) would clip an outside ring above and below the text. */
.cm-link--dotted:focus-visible {
  outline-offset: -2px;
}

}
@layer components {
/*
 * In-page banners (CSS consolidation phase 4, batch 3a). Spec:
 * docs/specs/2026-10-10-css-phase-4-batch3a-design.md
 * A message that stays on the page (a toast floats and leaves): a surface
 * box with a gray border and a 4px left edge in the tone color, an icon in
 * the tone's text color, the words, and any actions at the end.
 * Markup (buildBanner() in _shared/components/banner.js builds it):
 *   div.cm-banner.cm-banner--<tone>[role] >
 *     i.cm-banner__icon.fa-solid.<icon>[aria-hidden],
 *     div.cm-banner__body > span.cm-banner__title, text,
 *     div.cm-banner__actions > buttons.
 * Tones: the gray default, --info, --success, --warning, --danger. The
 * edges use the tone's -500, as toasts do; the meaning rides the icon and
 * the words, which use the tone's text color and heading text.
 * --accent: an open task that is yours (the teal tint). --stack: children
 * in a column (the task banner's row and its Done form). --compact: the
 * tighter padding of a narrow column.
 */

.cm-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cm-space-2) var(--cm-space-3);
  box-sizing: border-box;
  width: 100%;
  padding: var(--cm-space-3) var(--cm-space-4);
  border: 1px solid var(--cm-border);
  border-left: 4px solid var(--cm-border);
  border-radius: var(--cm-banner-radius);
  background: var(--cm-bg-surface);
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  line-height: var(--cm-lh-normal);
}

.cm-banner__icon {
  flex: none;
  font-size: var(--cm-text-base);
  line-height: 1;
  color: var(--cm-text-muted);
}

.cm-banner__body {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-1);
  flex: 1 1 16rem;
  min-width: 0;
}

.cm-banner__title {
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-heading);
}

.cm-banner__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cm-space-2);
  margin-left: auto;
}

.cm-banner__actions:empty {
  display: none;
}

.cm-banner--info {
  border-left-color: var(--cm-blue-500);
}

.cm-banner--info .cm-banner__icon {
  color: var(--cm-info-text);
}

.cm-banner--success {
  border-left-color: var(--cm-success-500);
}

.cm-banner--success .cm-banner__icon {
  color: var(--cm-success-text);
}

.cm-banner--warning {
  border-left-color: var(--cm-warning-500);
}

.cm-banner--warning .cm-banner__icon {
  color: var(--cm-warning-text);
}

.cm-banner--danger {
  border-left-color: var(--cm-danger-500);
}

.cm-banner--danger .cm-banner__icon {
  color: var(--cm-danger-text);
}

.cm-banner--accent {
  border-color: var(--cm-chip-selected-border);
  border-left-color: var(--cm-interactive);
  background: var(--cm-bg-accent-soft);
}

.cm-banner--stack {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
}

.cm-banner--compact {
  padding: var(--cm-space-2) var(--cm-space-3);
}

}
@layer components {
/*
 * Toasts (CSS consolidation phase 4, feedback). Spec:
 * docs/specs/2026-10-10-css-phase-4-feedback-design.md
 * Built by showToast() in common/common.js into #cm-toast-host
 * (loader.html): div.cm-toast.cm-toast--<tone> > i.cm-toast-icon,
 * p.cm-toast-message, button.cm-toast-close and, when the toast has a
 * timeout, div.cm-toast-progress > div.cm-toast-progress-bar. The part
 * names are hyphenated, not BEM, because the customer _shared/cm-toast.js
 * writes the same names (portal.css and request.css import this file).
 * Info is the default look; --info stays as a hook. The edge, tint and
 * countdown use the tone's -500; the icon uses the tone's --cm-*-text so
 * it reads on the tint. The countdown pauses on hover and on keyboard
 * focus, matching the JS timer in showToast().
 */

.cm-toast-host {
  position: fixed;
  top: var(--cm-space-4);
  right: var(--cm-space-4);
  z-index: var(--cm-z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-2);
  max-width: calc(100vw - var(--cm-space-8));
  /* The stack stays inside the window: showToast() drops the oldest toast
     that has a timeout while the stack is taller than this. */
  max-height: calc(100vh - 2 * var(--cm-space-4));
  pointer-events: none; /* Toasts opt back in, so clicks pass through the gaps. */
}

.cm-toast {
  pointer-events: auto;
  position: relative;
  /* Never shrink to fit the capped host: overflow: hidden would let a flex
     item squash below its content. showToast() drops toasts instead. */
  flex: none;
  box-sizing: border-box;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--cm-space-3);
  width: min(380px, calc(100vw - var(--cm-space-8)));
  padding: var(--cm-space-3) var(--cm-space-4);
  border: 1px solid var(--cm-border);
  border-left: 4px solid var(--cm-blue-500);
  border-radius: var(--cm-radius-lg);
  background: color-mix(in srgb, var(--cm-blue-500) 10%, var(--cm-bg-surface));
  color: var(--cm-text-body);
  box-shadow: var(--cm-shadow-md);
  overflow: hidden;
  animation: cm-toast-enter 220ms cubic-bezier(0.21, 1.02, 0.73, 1) both;
}

.cm-toast--leaving {
  animation: cm-toast-leave 180ms ease-in both;
}

.cm-toast-icon {
  font-size: var(--cm-text-lg);
  line-height: 1;
  color: var(--cm-info-text);
}

.cm-toast-message {
  margin: 0;
  font-size: var(--cm-text-sm);
  line-height: 1.4;
  word-break: break-word;
}

.cm-toast-close {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 24px;
  height: 24px;
  margin: 0;
  padding: 0;
  border: 1px solid var(--cm-border-strong);
  border-radius: var(--cm-radius-md);
  background: transparent;
  color: var(--cm-text-body);
  font: inherit;
  font-size: var(--cm-text-lg);
  line-height: 1;
  cursor: pointer;
  transition:
    background 120ms ease,
    color 120ms ease;
}

/* The icon buttons' hover (components/button.css .cm-button--icon). */
.cm-toast-close:hover {
  border-color: var(--cm-interactive);
  background: var(--cm-chip-selected-bg);
  color: var(--cm-interactive);
}

.cm-toast-close:focus-visible {
  outline: 2px solid var(--cm-interactive);
  outline-offset: 2px;
}

.cm-toast-progress {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 3px;
  overflow: hidden;
  background: transparent;
}

.cm-toast-progress-bar {
  width: 100%;
  height: 100%;
  transform-origin: left center;
  background: var(--cm-blue-500);
  animation-name: cm-toast-progress;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

.cm-toast:is(:hover, :focus-within) .cm-toast-progress-bar {
  animation-play-state: paused;
}

/* Tones. Listed after the info default so each wins its equal-specificity
   tie. */
.cm-toast--success {
  border-left-color: var(--cm-success-500);
  background: color-mix(in srgb, var(--cm-success-500) 10%, var(--cm-bg-surface));
}

.cm-toast--success .cm-toast-icon {
  color: var(--cm-success-text);
}

.cm-toast--success .cm-toast-progress-bar {
  background: var(--cm-success-500);
}

.cm-toast--warning {
  border-left-color: var(--cm-warning-500);
  background: color-mix(in srgb, var(--cm-warning-500) 10%, var(--cm-bg-surface));
}

.cm-toast--warning .cm-toast-icon {
  color: var(--cm-warning-text);
}

.cm-toast--warning .cm-toast-progress-bar {
  background: var(--cm-warning-500);
}

.cm-toast--error {
  border-left-color: var(--cm-danger-500);
  background: color-mix(in srgb, var(--cm-danger-500) 10%, var(--cm-bg-surface));
}

.cm-toast--error .cm-toast-icon {
  color: var(--cm-danger-text);
}

.cm-toast--error .cm-toast-progress-bar {
  background: var(--cm-danger-500);
}

@keyframes cm-toast-enter {
  from {
    transform: translateX(16px);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

@keyframes cm-toast-leave {
  from {
    transform: translateX(0);
    opacity: 1;
  }
  to {
    transform: translateX(20px);
    opacity: 0;
  }
}

@keyframes cm-toast-progress {
  from {
    transform: scaleX(1);
  }
  to {
    transform: scaleX(0);
  }
}

/* Last in the file, so it wins its equal-specificity ties without
   !important. showToast()'s JS timer still dismisses each toast. */
@media (prefers-reduced-motion: reduce) {
  .cm-toast,
  .cm-toast--leaving,
  .cm-toast-progress-bar {
    animation: none;
  }
}

}
@layer components {
/*
 * Section titles (CSS consolidation phase 4, batch 3a). Spec:
 * docs/specs/2026-10-10-css-phase-4-batch3a-design.md
 * A heading that labels a section inside a page card, popup body or panel,
 * one step under a card title: 12px semibold small caps in muted text, with
 * a divider under it so a section never reads as a field label (field
 * labels share the small caps). Any element: h2 to h4, a legend, a div.
 * A legend sits on its fieldset's top border, which is its divider, so it
 * takes only its text's width and draws no rule of its own.
 * --spaced: space above, for a title that follows content in a plain block
 * flow with no gap (What's New groups, the QA hotkeys popover).
 * --plain: the caption type alone, no divider and no box of its own, on
 * its host's line height: a label inline before its value (the Upload
 * Records header, the Invoice total), over a tile figure (Import CSV) or
 * beside a control in a row that draws the divider (the report builder).
 */

.cm-section-title {
  display: block;
  box-sizing: border-box;
  width: 100%;
  margin: 0 0 var(--cm-space-2);
  padding: 0 0 var(--cm-space-1);
  border-bottom: 1px solid var(--cm-border);
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-semibold);
  line-height: var(--cm-lh-snug);
  letter-spacing: 0.06em;
  text-align: left;
  text-transform: uppercase;
  color: var(--cm-text-muted);
}

legend.cm-section-title {
  width: auto;
  padding-bottom: 0;
  border-bottom: 0;
}

.cm-section-title--spaced {
  margin-top: var(--cm-space-3);
}

.cm-section-title--plain {
  display: inline;
  width: auto;
  margin: 0;
  padding: 0;
  border-bottom: 0;
  line-height: inherit;
}

}
@layer components {
/* Progress bar (components/progress.css): the dashboard mini rows, the
   Review Batches bars and the loader's upload bar (components/loader.css
   .cm-loader__progress); --on-dark, the request flow's steps on the hero
   band. The width is set inline by the builder. */

.cm-progress {
  height: var(--cm-progress-height);
  border-radius: var(--cm-radius-pill);
  background: var(--cm-bg-muted);
  overflow: hidden;
  min-width: 0;
}

.cm-progress__fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--cm-accent-500);
}

.cm-progress__fill--warning {
  background: var(--cm-warning-500);
}

.cm-progress__fill--danger {
  background: var(--cm-danger-500);
}

.cm-progress__fill--muted {
  background: var(--cm-text-muted);
}

/* The interactive fill (the loader's upload bar), easing between updates. */
.cm-progress__fill--interactive {
  background: var(--cm-interactive);
  transition: width 200ms ease;
}

/* --on-dark: on the customer pages' dark hero band (the records request
   flow's compact steps): a 6px slate track, the fill teal-300 whatever its
   tone. */
.cm-progress--on-dark {
  height: 6px;
  background: var(--cm-hero-track);
}

.cm-progress--on-dark > .cm-progress__fill {
  background: var(--cm-hero-eyebrow);
}

/* Indeterminate: a 35% fill slides across the track; a static full fill
   under reduced motion. The builder clears the inline width. */
.cm-progress--indeterminate {
  position: relative;
}

.cm-progress--indeterminate > .cm-progress__fill {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 35%;
  animation: cm-progress-slide 1.2s ease-in-out infinite;
}

@keyframes cm-progress-slide {
  from {
    left: -35%;
  }
  to {
    left: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cm-progress--indeterminate > .cm-progress__fill {
    left: 0;
    width: 100%;
    animation: none;
  }
}

.cm-progress-list {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cm-progress-list__row {
  display: flex;
  align-items: center;
  gap: var(--cm-space-2);
  font-size: var(--cm-text-xs);
  color: var(--cm-text-body);
}

.cm-progress-list__row > .cm-progress {
  flex: 1 1 auto;
}

.cm-progress-list__label {
  flex: 0 0 64px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cm-progress-list__count {
  flex: 0 0 22px;
  text-align: right;
  font-weight: var(--cm-fw-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--cm-text-heading);
}

}
@layer components {
/* Empty states (phase 4, docs/specs/2026-10-07-css-phase-4-tables-design.md):
 * a muted italic centered message, as a table row's cell (td.cm-empty-state,
 * which wins over the :where() cell rules) or as a block (p.cm-empty-state). */

/* margin: 0 so the block form owns its box (base.css gives p a margin). */
.cm-empty-state {
  margin: 0;
  padding: var(--cm-space-8) var(--cm-space-4);
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
  font-style: italic;
  text-align: center;
  white-space: normal;
}

/* A row form needs its own background: without one, hovering its parent
   .cm-table row let the hover wash (components/table.css) show through,
   since .cm-empty-state alone never declared a background to compete with
   it. One class plus a type selector outranks the hover rule's type-only
   chain, so this wins regardless of source order. */
td.cm-empty-state {
  background: var(--cm-bg-surface);
}

}
@layer components {
/*
 * Inline row (CSS consolidation phase 5): controls side by side with a
 * small gap inside a column cell, flush left. Not .row (layout.css), which
 * centers its content. Markup: div.cm-inline-row > controls.
 */

.cm-inline-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--cm-space-2);
  width: 100%;
}

/* --fill: the row's field takes what its icon buttons or chip leave, on
   one line (Invoice's Customer Code and Bill Type). */
.cm-inline-row--fill {
  flex-wrap: nowrap;
}

.cm-inline-row--fill > input,
.cm-inline-row--fill > select {
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
}

/* --fields: labelled fields side by side, with icon buttons on the
   controls' line (the held delivery review's Edit patient row). Wraps on a
   narrow window. */
.cm-inline-row--fields {
  align-items: flex-end;
  flex-wrap: wrap;
}

/* The fields (buildField's div wrappers); the buttons keep their size. */
.cm-inline-row--fields > div {
  flex: 0 1 11rem;
}

}
@layer components {
/*
 * Help icon (CSS consolidation phase 4, forms PR 1). Spec:
 * docs/specs/2026-10-05-css-phase-4-forms-design.md
 * Markup:
 *   span.cm-help-icon.cm-tooltip.cm-tooltip--fixed[tabindex=0][role=button]
 *     [aria-label][data-tooltip] "?"
 * A small "?" chip whose data-tooltip text shows on hover or keyboard focus
 * in the shared bubble (components/tooltip.css, --fixed, placed by the
 * positioner in common/common.js). This file owns only the chip. Beside a
 * field label or check row it sits in a .cm-field__help-row (addFieldHelp()
 * in common/dom-helpers.js).
 */

.cm-help-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* As tall as the text beside it (CSS phase 5.5 restyle review): a field
     label's 14.4px line box, a check chip's small caps, a 14px card or
     esMD title. A popup title restates it larger (popup.css). */
  box-sizing: border-box;
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  margin-left: var(--cm-space-1);
  border-radius: var(--cm-radius-pill);
  /* A muted-but-visible chip so the affordance reads as "click for help"
     instead of disappearing into the card background. */
  background: var(--cm-bg-muted);
  color: var(--cm-text-body);
  border: 1px solid var(--cm-border);
  font-size: var(--cm-font-size-help-glyph);
  font-weight: var(--cm-fw-semibold);
  line-height: 1;
  cursor: help;
  position: relative;
  user-select: none;
}

/* A touch target (WCAG 2.2 AA 2.5.8, 24px): the customer pages, which
   patients use on phones. Same chip, sized to the minimum target. */
.cm-help-icon--touch {
  width: 24px;
  height: 24px;
}

.cm-help-icon:hover,
.cm-help-icon:focus-visible {
  background: var(--cm-bg-surface);
  color: var(--cm-interactive);
  border-color: var(--cm-interactive);
  outline: none;
}

/* Inside an element that shows its own data-tooltip bubble (a locked
   control explaining why it is locked), the icon stands down so the two
   bubbles never stack. */
[data-tooltip] .cm-help-icon {
  pointer-events: none;
}

}
@layer components {
/*
 * Tooltips (CSS consolidation phase 4, batch 3a). Spec:
 * docs/specs/2026-10-10-css-phase-4-batch3a-design.md
 * One bubble: navy (--cm-bg-sidebar, the same in both themes) with white
 * 12px text, left-aligned, the accent ring (--cm-shadow-tooltip) for its
 * edge on a dark page. Line breaks in the text are kept.
 * .cm-tooltip[data-tooltip]: the bubble is the element's ::after, above
 *   it, on hover and keyboard focus.
 * --fixed: the bubble is position: fixed and placed by the positioner in
 *   common/common.js (--tt-x, --tt-y), so a scrolling table or a popup body
 *   cannot clip it. Help icons and table cell hints use it.
 * --left: the bubble opens to the left (the PDF action rails).
 * .cm-tooltip__bubble: the same bubble as a real element (role="tooltip",
 *   tied by aria-describedby), shown under its field while a --focus host
 *   holds keyboard focus.
 * The ::after text is drawn but kept out of the accessibility tree (the
 * empty alt text after the slash), so a hint never joins its element's
 * accessible name; an element that needs its hint read gets an
 * aria-label or aria-description (addTooltip() sets one on focusable
 * elements).
 */

/* The anchor has no specificity, so a component that positions the
   element itself (an in-field chip) keeps its position. */
:where(.cm-tooltip) {
  position: relative;
}

.cm-tooltip[data-tooltip]::after,
.cm-tooltip__bubble {
  width: max-content;
  min-width: 220px;
  max-width: min(460px, calc(100vw - var(--cm-space-8)));
  padding: var(--cm-space-2) var(--cm-space-3);
  border-radius: var(--cm-radius-md);
  background: var(--cm-bg-sidebar);
  box-shadow: var(--cm-shadow-tooltip);
  color: var(--cm-text-on-dark);
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-regular);
  line-height: var(--cm-lh-snug);
  text-align: left;
  text-transform: none;
  letter-spacing: normal;
  white-space: pre-line;
  pointer-events: none;
  z-index: var(--cm-z-hover);
}

.cm-tooltip[data-tooltip]::after {
  content: attr(data-tooltip) / '';
  position: absolute;
  bottom: 130%;
  left: 50%;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 120ms ease;
}

.cm-tooltip[data-tooltip]:hover::after,
.cm-tooltip[data-tooltip]:focus-visible::after {
  opacity: 1;
}

.cm-tooltip--fixed[data-tooltip]::after {
  position: fixed;
  top: var(--tt-y);
  bottom: auto;
  left: var(--tt-x);
  transform: none;
}

.cm-tooltip--left[data-tooltip]::after {
  top: 50%;
  right: calc(100% + 10px);
  bottom: auto;
  left: auto;
  transform: translateY(-50%);
}

.cm-tooltip--focus {
  position: relative;
}

.cm-tooltip__bubble {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: var(--cm-space-1);
}

.cm-tooltip--focus:focus-within .cm-tooltip__bubble {
  display: block;
}

}
@layer components {
/*
 * Menu (CSS consolidation phase 4, PR 3). Spec:
 * docs/specs/2026-09-30-css-phase-4-popups-design.md
 * Markup:
 *   div.cm-menu[--hover|--list|--fixed|--modal|--wrap][role=menu|listbox] >
 *     button.cm-menu__item[--danger|--active], div.cm-menu__divider
 *   div.cm-menu--popover[--popover-wide][role=dialog] > div.cm-menu__body >
 *     text, div.cm-menu__note (> p.cm-menu__note-text),
 *     details.cm-menu__more > summary + notes (the facility notes popover)
 * Rows are separated (CSS phase 5.5 restyle, docs/specs/
 * 2026-10-12-css-phase-5-5-restyle-design.md): the card has no inner
 * padding, a hairline runs between adjacent rows, and a hovered, focused or
 * --active row takes the selected tint with a 3px edge on its left.
 * Row and toolbar Actions menus come from common/menu.js buildActionsMenu().
 * A menu shows unless it has the hidden attribute, except --hover menus,
 * which show only while their .actions-dropdown wrapper is hovered or
 * holds focus, and not after Escape dismissed it (wireHoverMenu sets
 * data-menu-dismissed on the wrapper until the pointer or focus comes back
 * in). An autocomplete list (--list) is a div or a ul whose rows
 * (div or li, role=option) keep their own element.
 */

.cm-menu {
  position: absolute;
  top: calc(100% + var(--cm-space-2));
  right: 0;
  z-index: var(--cm-z-overlay-menu);
  display: flex;
  flex-direction: column;
  min-width: 180px;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  /* Clips the square rows' tints to the card's corners. --list and
     --popover scroll on y. */
  overflow: hidden;
  list-style: none;
  background-color: var(--cm-bg-surface);
  color: var(--cm-text-body);
  border: 1px solid var(--cm-menu-border);
  border-radius: var(--cm-radius-lg);
  box-shadow: var(--cm-shadow-lg);
  text-align: left;
}

/* Revealed by its .actions-dropdown wrapper (the trigger's wrapper,
   position: relative), and flush against it so the pointer can travel from
   trigger to menu. Sits at --cm-z-overlay (100, as the legacy Actions menu
   did), not --cm-z-overlay-menu, so a popup opened from one of its items
   (also z 100, appended later) covers it. */
.cm-menu--hover {
  display: none;
  top: 100%;
  z-index: var(--cm-z-overlay);
}

/* :not([hidden]) keeps a menu that buildActionsMenu set hidden (no
   surviving items) hidden even while its wrapper is hovered or focused.
   Qualified with .actions-dropdown (the only wrapper class that carries a
   --hover menu) rather than a bare :hover/:focus-within, which would be
   enough on every staff page that declares a doctype, but not on one that
   doesn't: a doctype-less page (requests.html today; see tests/component/
   menu.spec.mjs's no-doctype test) renders in quirks mode, where the
   legacy HTML ":hover quirk" makes a compound selector made only of
   :hover (an implicit *:hover, which is what a bare ancestor-combinator
   :hover is) never match a non-link, non-classed element. A selector
   qualified with a class, like .actions-dropdown:hover, is exempt from
   that quirk and matches correctly either way, so qualifying is the
   robust choice regardless of which pages currently lack a doctype.
   :not([data-menu-dismissed]): Escape closed it (wireHoverMenu in
   _shared/components/menu.js), and it stays closed while the pointer and
   focus that were there stay (WCAG 1.4.13). */
.actions-dropdown:not([data-menu-dismissed]):hover > .cm-menu--hover:not([hidden]),
.actions-dropdown:not([data-menu-dismissed]):focus-within > .cm-menu--hover:not([hidden]) {
  display: flex;
}

/* An autocomplete list under its input's wrapper (position: relative).
   common/menu.js placeListUnder() overrides left, top and min-width inline
   when the wrapper is not directly under the input. */
.cm-menu--list {
  top: calc(100% + var(--cm-space-1));
  left: 0;
  right: auto;
  min-width: 100%;
  max-height: 220px;
  overflow-y: auto;
}

/* Rows wrap instead of overflowing past the menu's width when a row's
   text is too long for one line (the Patient Alert facility search, where
   a long facility name must stay readable rather than push the row's
   trailing code past the card's edge). white-space is inherited by the
   row's child spans. */
.cm-menu--wrap .cm-menu__item {
  white-space: normal;
}

/* Placed at a point by JS (style.left/top): the right-click menu and the QA
   hotkeys popover. Above the sidenav. */
.cm-menu--fixed {
  position: fixed;
  top: auto;
  right: auto;
  z-index: var(--cm-z-context-menu);
}

/* A popover card of text rather than items (the hotkeys list opened from a
   page header's keyboard icon, and the authorization form builder's
   checklist; common/header-tools.js createHeaderPopover): a --fixed --modal
   menu with a padded __body that scrolls when the list is long. */
.cm-menu--popover {
  width: 320px;
  max-height: 70vh;
  overflow-y: auto;
}

/* --popover-wide: a popover of notes, 380px (the facility notes popover,
   common/facility-notes.js). */
.cm-menu--popover-wide {
  width: 380px;
}

.cm-menu__body {
  padding: var(--cm-space-4);
}

.cm-menu__body p {
  margin: 2px 0;
  font-size: var(--cm-text-sm);
  color: var(--cm-text-body);
}

.cm-menu__body kbd {
  padding: 1px 4px;
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-sm);
  background: var(--cm-bg-surface);
  color: var(--cm-text-muted);
  font-size: var(--cm-text-xs);
}

/* A --fixed menu that must stay below the session-timeout box
   (--cm-z-session, 1500), e.g. the QA hotkeys popover. */
.cm-menu--modal {
  z-index: var(--cm-z-modal);
}

.cm-menu__item {
  display: flex;
  align-items: center;
  gap: var(--cm-space-2);
  width: 100%;
  min-height: 36px;
  box-sizing: border-box;
  margin: 0;
  padding: 0 var(--cm-space-3);
  border: 0;
  border-radius: 0;
  background-color: transparent;
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

/* An item's leading icon (addMenuItems' `icon`): a fixed-width slot so the
   labels line up, in the item's own color. color: inherit is load-bearing
   in the PDF viewer, where pdf_viewer.css's .actionBar i { color: white }
   (injected into the legacy layer by the editor) would otherwise paint the
   PdfActions icons white on the white card. */
.cm-menu__item > i {
  flex: none;
  width: 1.25em;
  color: inherit;
  text-align: center;
}

/* A hairline on a row that follows a visible row: a list that filters by
   hiding rows (CustomDropdown) must not draw one under the frame's top
   edge. None right under a divider. */
.cm-menu__item:not([hidden]) ~ .cm-menu__item {
  border-top: 1px solid var(--cm-menu-separator);
}

.cm-menu__divider + .cm-menu__item:not([hidden]) {
  border-top: 0;
}

.cm-menu__item:hover,
.cm-menu__item:focus-visible,
.cm-menu__item--active {
  background-color: var(--cm-chip-selected-bg);
  color: var(--cm-text-heading);
  box-shadow: var(--cm-menu-edge);
}

.cm-menu__item:focus-visible {
  outline: 2px solid var(--cm-interactive);
  outline-offset: -2px;
}

.cm-menu__item--danger {
  color: var(--cm-danger-text);
}

.cm-menu__item--danger:hover,
.cm-menu__item--danger:focus-visible,
.cm-menu__item--danger.cm-menu__item--active {
  background-color: var(--cm-bg-danger-soft);
  color: var(--cm-danger-text);
  box-shadow: var(--cm-menu-edge-danger);
}

.cm-menu__divider {
  flex: none;
  height: 1px;
  margin: 0;
  background-color: var(--cm-border-strong);
}

/* Menu anchors (moved from stylesheetv3.css, CSS phase 5): the wrapper a
   --hover menu hangs from, and the wrapper an input's --list sits in. */
.actions-dropdown {
  position: relative;
  display: inline-block;
}

.input-dropdown {
  display: flex;
  margin: 0;
  padding: 0;
  position: relative;
}

/* A group label inside a menu (the Preload Tool's column tag menu): small
   muted caps, not an item. */
.cm-menu__heading {
  padding: 6px 10px 2px;
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cm-text-muted);
}

/* A note in a popover (the facility notes popover): a row with its pill and
   date, its text, then who added it and when; a hairline between notes. */
.cm-menu__note {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-1);
  padding: var(--cm-space-2) 0;
}

.cm-menu__note + .cm-menu__note {
  border-top: 1px solid var(--cm-menu-separator);
}

.cm-menu__note > p {
  margin: 0;
  padding: 0;
}

/* The note's text as it was typed: its line breaks show (it is set through
   textContent, so markup-looking text stays text). */
.cm-menu__note-text {
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* A folded group at the end of a popover (a <details>: "Other notes at this
   facility"), under a divider. */
.cm-menu__more {
  margin-top: var(--cm-space-2);
  border-top: 1px solid var(--cm-border);
}

.cm-menu__more > summary {
  padding: var(--cm-space-2) 0;
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-body);
  cursor: pointer;
}

}
@layer components {
/* Tables (phase 4, docs/specs/2026-10-07-css-phase-4-tables-design.md).
 *   .cm-table                       a data table: caps header band, 14px cells,
 *                                   gray row lines, hover wash, centered
 *   __row--selected/--urgent/
 *          --locked/--deleted       a 4px marker bar (urgent wins); selected keeps the wash
 *                                   (a --highlight cell inside it keeps its own tint instead)
 *   __row--danger / --dim           red semibold text / muted text; element children
 *                                   in their cells take the row's color
 *   __row--clickable                pointer
 *   __row--checked                  a row whose checkbox is checked: the accent wash (row selection)
 *   __cell--num / --start           right (money) / left (long free text)
 *   __cell--truncate                marks a cell that holds a .cm-table__truncate span; carries
 *                                   no styling of its own (a td's max-width is not honored by
 *                                   table auto-layout except during a column squeeze, so the
 *                                   actual ellipsis cap lives on the inner span, set by
 *                                   setCellText/common/table.js)
 *   __truncate                      the inline element that stops at --cm-table-cell-max with
 *                                   an ellipsis; the cell's title carries the full value
 *   __cell--fill                    a column that takes the spare width, its truncated lines
 *                                   stopping at its edge (a name with its address under it)
 *   __sub                           a muted second line under a cell's value (Browse Requests'
 *                                   reference and DOB); with __truncate it stays one line
 *   __cell--fit                     as narrow as its content, on one line (a comments
 *                                   table's User and Date)
 *   __cell--muted / --highlight     muted text / accent tint (Current Due)
 *   __cell--danger                  red semibold text (a failure note, a pending count)
 *   __cell--actions                 lets a row menu escape the cell
 *   __cell--flag                    a narrow leading column holding only a flag (Urgent)
 *   __cell--select                  the leading checkbox column of row selection, the whole cell a hit area
 *   __sort                          the sort button filling a sortable th (aria-sort on the th);
 *                                   in print only the sorted column keeps its arrow
 *   __header-action                 an icon button pinned to the end of a header cell
 *                                   (the comments table's add button)
 *   __totals                        a totals row; __caption a caption with a heading and a button
 *   --dense                         tighter cells (the claims grid)
 *   --nowrap-head                   header labels stay on one line (Browse Requests)
 *   --flush                         square header corners, for a table that runs
 *                                   edge to edge in its box (the patient alert list)
 *   --selecting                     rows are checked: the header row is the action row
 *                                   (components/selection-row.css)
 *   .cm-table-scroll                a framed scroll box for a table in a fixed-height box
 * Cell and header rules use :where(.cm-table) so modifiers and .cm-empty-state win
 * without id selectors.
 */

:where(.cm-table) {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-variant-numeric: tabular-nums;
}

:where(.cm-table) > thead > tr > th {
  position: sticky;
  top: 0;
  z-index: var(--cm-z-raised);
  padding: var(--cm-space-3);
  border-bottom: 1px solid var(--cm-border);
  background: var(--cm-bg-muted);
  color: var(--cm-text-body);
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-semibold);
  letter-spacing: 0.04em;
  line-height: var(--cm-lh-tight);
  text-align: center;
  text-transform: uppercase;
  vertical-align: bottom;
  white-space: normal;
}

:where(.cm-table) > thead > tr > th * {
  color: inherit;
}

:where(.cm-table) > thead > tr > th:first-child {
  border-top-left-radius: var(--cm-radius-xl);
}

:where(.cm-table) > thead > tr > th:last-child {
  border-top-right-radius: var(--cm-radius-xl);
}

:where(.cm-table) > tbody > tr > td,
:where(.cm-table) > tfoot > tr > td {
  padding: var(--cm-space-2) var(--cm-space-3);
  border-bottom: 1px solid var(--cm-border);
  background: var(--cm-bg-surface);
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  text-align: center;
  white-space: nowrap;
}

/* :where(:hover) keeps this at the base cell rule's specificity (a type
   selector chain, no classes), so a rule with any class in its selector -
   __cell--highlight, td.cm-empty-state (components/empty-state.css) - wins
   over the hover wash regardless of source order. */
:where(.cm-table) > tbody > tr:where(:hover) > td {
  background: var(--cm-bg-muted);
}

/* :not() excludes a --highlight cell from this selector entirely, so the
   row's wash never competes with it: __cell--highlight's own background
   applies unopposed instead of losing to this rule's class-plus-type
   specificity (a plain `> td` previously did lose a --highlight cell's tint
   this way). */
.cm-table__row--selected > td:not(.cm-table__cell--highlight) {
  background: var(--cm-bg-muted);
}

.cm-table__row--selected > td:first-child {
  box-shadow: var(--cm-table-marker-selected);
}

.cm-table__row--locked > td:first-child {
  box-shadow: var(--cm-table-marker-locked);
}

.cm-table__row--deleted > td:first-child {
  box-shadow: var(--cm-table-marker-deleted);
}

/* Last of the markers so a selected urgent row shows red. */
.cm-table__row--urgent > td:first-child {
  box-shadow: var(--cm-table-marker-urgent);
}

.cm-table__row--danger > td {
  color: var(--cm-danger-text);
  font-weight: var(--cm-fw-semibold);
}

.cm-table__row--dim > td {
  color: var(--cm-text-muted);
}

.cm-table__row--clickable {
  cursor: pointer;
}

.cm-table__row--checked > td:not(.cm-table__cell--highlight) {
  background: var(--cm-bg-accent-soft);
}

.cm-table__cell--num {
  text-align: right;
}

.cm-table__cell--start {
  text-align: left;
  white-space: normal;
}

/* Marker only: a table auto-layout td's max-width is not honored except
   during a column squeeze (verified: an isolated truncate td in a roomy
   2-column table rendered past 1000px). The ellipsis cap lives on the inner
   .cm-table__truncate span below, which setCellText() inserts. */
.cm-table__cell--truncate {
}

.cm-table__truncate {
  display: inline-block;
  max-width: var(--cm-table-cell-max);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

/* A muted second line under a cell's main value (CSS phase 5.5 redesigns:
   Browse Requests' customer reference and DOB, Customer Details' Cust Ref).
   After .cm-table__truncate, so a truncated sub line is still a block in
   the muted color. */
.cm-table__sub {
  display: block;
  margin-top: 2px;
  font-size: var(--cm-text-xs);
  color: var(--cm-text-muted);
  white-space: nowrap;
}

/* A sub line of free text that wraps and keeps its line breaks (the Notes
   tab's note reason). */
.cm-table__sub--wrap {
  white-space: pre-line;
}

/* A column that takes the table's spare width (Browse Facilities' and
   Browse Customers' name with its address under it): 40% of the table, and
   max-width: 0 so its text never widens it, so a truncated line in it stops
   at the column's edge instead of at --cm-table-cell-max beside empty space.
   The name wraps; the address line ends in an ellipsis. */
.cm-table__cell--fill {
  width: 40%;
  max-width: 0;
}

.cm-table__cell--fill .cm-table__truncate {
  display: block;
  max-width: 100%;
}

/* A column as narrow as its content (CSS phase 5.5 redesign review: the
   full-width comments table's User and Date, so Comment takes the rest). */
.cm-table__cell--fit {
  width: 1%;
  white-space: nowrap;
}

.cm-table__cell--muted {
  color: var(--cm-text-muted);
}

.cm-table__cell--danger {
  color: var(--cm-danger-text);
  font-weight: var(--cm-fw-semibold);
}

.cm-table__cell--highlight {
  background: var(--cm-bg-accent-soft);
  color: var(--cm-accent-text);
  font-weight: var(--cm-fw-semibold);
}

.cm-table__cell--actions {
  overflow: visible;
}

/* A narrow leading column that holds only a flag (the Urgent pill): as
   wide as its content, with 8px sides; its cells keep no top or bottom
   padding. */
.cm-table__cell--flag {
  width: 1%;
  padding-left: var(--cm-space-2);
  padding-right: var(--cm-space-2);
  white-space: nowrap;
}

td.cm-table__cell--flag {
  padding-top: 0;
  padding-bottom: 0;
}

/* The leading checkbox column of row selection (common/row-selection.js):
   as narrow as the box, the whole cell a click target, centered in its row
   (header cells otherwise sit at the bottom). */
.cm-table__cell--select {
  width: 1%;
  padding-left: var(--cm-space-3);
  padding-right: var(--cm-space-3);
  text-align: center;
  vertical-align: middle;
  cursor: pointer;
}

/* Rows checked (common/row-selection.js): the header row becomes the action
   row. The cells take the accent tint and their labels and sort buttons hide
   but keep their widths, so no column moves; the checkbox cell holds the
   .cm-selection-row (components/selection-row.css), which spills over the
   cells after it, so it paints above them. */
.cm-table--selecting > thead > tr > th {
  border-bottom-color: var(--cm-accent-300);
  background: var(--cm-bg-accent-soft);
}

.cm-table--selecting > thead > tr > th:not(.cm-table__cell--select) {
  color: transparent;
}

.cm-table--selecting > thead > tr > th:not(.cm-table__cell--select) > * {
  visibility: hidden;
}

.cm-table--selecting > thead > tr > th.cm-table__cell--select {
  z-index: var(--cm-z-raised-2);
}

/* The button fills its header so the whole label column is a click target;
   its label and arrow follow the header's alignment (centered by default,
   left on a --start header, right on a --num header). text-align: inherit
   undoes the button's UA centering, so a label that wraps to two lines
   lines up with its column too, not only the label block. */
.cm-table__sort {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  gap: var(--cm-space-1);
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-align: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.cm-table__cell--start > .cm-table__sort {
  justify-content: flex-start;
}

.cm-table__cell--num > .cm-table__sort {
  justify-content: flex-end;
}

/* The arrow is decoration (aria-sort on the th carries the state), so the
   alt-text form ( / '') keeps it out of the button's accessible name. */
.cm-table__sort::after {
  content: '\2195' / '';
  color: var(--cm-text-muted);
}

/* Hover brightens the idle arrow; the aria-sort rules below outrank this
   one, so an active arrow keeps --cm-interactive. */
.cm-table__sort:hover::after {
  color: var(--cm-text-body);
}

/* A printout cannot be re-sorted, so the idle arrow goes; the aria-sort
   rules below outrank this one (an attribute and a type selector more), so
   the sorted column keeps its arrow on paper. */
@media print {
  .cm-table__sort::after {
    content: none;
  }
}

th[aria-sort='ascending'] > .cm-table__sort::after {
  content: '\2191' / '';
  color: var(--cm-interactive);
}

th[aria-sort='descending'] > .cm-table__sort::after {
  content: '\2193' / '';
  color: var(--cm-interactive);
}

.cm-table__sort:focus-visible {
  outline: none;
  border-radius: var(--cm-radius-sm);
  box-shadow: var(--cm-focus-ring);
}

/* An icon button pinned to the end of a header cell (the comments table's
   add button). Header cells are sticky, so the th is its containing block;
   the th keeps room on its right so the label never runs under it. */
.cm-table__header-action {
  position: absolute;
  top: 50%;
  right: var(--cm-space-2);
  transform: translateY(-50%);
  z-index: var(--cm-z-raised-2);
}

:where(.cm-table) > thead > tr > th:has(> .cm-table__header-action) {
  padding-right: calc(var(--cm-space-3) + var(--cm-button-height-sm));
}

.cm-table__totals > td {
  border-top: 1px solid var(--cm-border);
  background: var(--cm-bg-muted);
  font-weight: var(--cm-fw-semibold);
}

/* Inset like a cell, so a caption inside a .cm-table-scroll frame keeps its
   heading and button off the frame's edges and lines the heading up with
   the first column's text. */
.cm-table__caption {
  caption-side: top;
  padding: var(--cm-space-2) var(--cm-space-3);
  text-align: left;
}

.cm-table--dense > tbody > tr > td {
  padding: var(--cm-space-1) var(--cm-space-2);
}

/* Header labels on one line: a table whose columns carry short labels and
   second lines (Browse Requests, CSS phase 5.5 redesigns). */
.cm-table--nowrap-head > thead > tr > th {
  white-space: nowrap;
}

/* After the base corner rules: equal specificity, so source order wins. */
.cm-table--flush > thead > tr > th {
  border-radius: 0;
}

.cm-table-scroll {
  overflow: auto;
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-xl);
}

.cm-table-scroll:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

}
@layer components {
/* Search bar (components/search-bar.css): the one filter bar, composed on
   the card:
     div.cm-card.cm-card--padded.cm-search-bar
       > div.cm-search-bar__fields > div.cm-field (label + control) ...
       + div.cm-search-bar__filters? (checks and chips under a divider)
       + div.cm-search-bar__actions (Search and Clear, or Run)
   Fields left in an auto-fit grid, actions in their own right column.
   Page actions (Add, New, batch menus) belong in the page header, not here.
   Decisions: docs/specs/2026-10-11-css-phase-4-batch3b-design.md. */

.cm-search-bar {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: stretch;
  gap: var(--cm-space-3);
  /* The page column's width, like the page header and the results tables. */
  width: 95%;
  box-sizing: border-box;
}

/* In a page column (layout.css) the column sets the width. */
.page-column > .cm-search-bar {
  width: auto;
}

/* align-self: center keeps a single short row of fields level with the
   middle of a taller action column instead of sinking to its bottom. */
.cm-search-bar__fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--cm-space-3);
  align-items: end;
  align-self: center;
  min-width: 0;
}

/* A select gets two columns so its longest option ("All statuses",
   "Open + Suspected") is not cut off at 1fr. */
.cm-search-bar__fields > :has(select) {
  grid-column: span 2;
}

/* Fields with several inline controls (the Complete Date filter: operator
   plus one or two dates). min-width: 0 lets the track shrink below the
   controls' own minimum instead of pushing into the action column. Two
   classes outrank the :has(select) rule above. */
.cm-search-bar__fields > .cm-search-bar__field--wide {
  grid-column: span 3;
  min-width: 0;
}

/* Tight label lines so a row of fields lines up on its controls. */
.cm-search-bar__fields > * > label {
  line-height: 1;
  padding-left: 2px;
}

.cm-search-bar__filters {
  grid-column: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cm-space-3) var(--cm-space-5);
  padding-top: var(--cm-space-3);
  border-top: 1px solid var(--cm-border);
}

.cm-search-bar__actions {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  gap: var(--cm-space-2);
  min-width: 110px;
  padding-left: var(--cm-space-3);
  border-left: 1px solid var(--cm-border);
}

/* With a filter row showing, the column spans it too, so it stays full
   height beside the fields and the filters. */
.cm-search-bar:has(> .cm-search-bar__filters:not([hidden])) > .cm-search-bar__actions {
  grid-row: 1 / span 2;
}

}
@layer components {
/* Page header (components/page-header.css): the one page title look, the
   QA-style header card. Composed on the card:
     header.cm-card.cm-card--padded.cm-page-header
       > div.cm-page-header__titles
           > h1.cm-page-header__title + p.cm-page-header__subtitle
             (+ div.cm-page-header__meta for pills and links)
       + div.cm-page-header__end (the page's actions, main action last)
   --plain drops the card for a header that already sits inside one (QA,
   Invoice): no outer width or margins, no wrap, an ellipsis subtitle.
   Decisions: docs/specs/2026-10-11-css-phase-4-batch3b-design.md. */

.cm-page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cm-space-3) var(--cm-space-4);
  /* The page column's width, like the search bar and the results tables
     under it (the page container centers its children). */
  width: 95%;
  margin: var(--cm-space-5) 0 var(--cm-space-4);
  box-sizing: border-box;
}

/* In a page column (layout.css) the column sets the width and spacing. */
.page-column > .cm-page-header {
  width: auto;
  margin: 0;
}

.cm-page-header__titles {
  flex: 1 1 auto;
  min-width: 0;
}

.cm-page-header__title {
  margin: 0;
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-semibold);
  line-height: var(--cm-lh-snug);
  color: var(--cm-text-heading);
  text-align: left;
}

.cm-page-header__subtitle {
  margin: 2px 0 0;
  padding: 0;
  font-size: var(--cm-text-sm);
  line-height: var(--cm-lh-snug);
  color: var(--cm-text-muted);
}

.cm-page-header__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cm-space-2);
  margin-top: var(--cm-space-1);
}

/* Out of the way while everything in it is hidden (QA's and Invoice's
   queue pills show only for a carried queue filter). */
.cm-page-header__meta:not(:has(> :not([hidden]))) {
  display: none;
}

/* margin-left: auto keeps the group on the right, also after it wraps
   under the titles. */
.cm-page-header__end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--cm-space-2);
  margin-left: auto;
}

/* align-self: stretch fills a flex column that centers its children
   (Invoice's form column). */
.cm-page-header--plain {
  flex-wrap: nowrap;
  column-gap: var(--cm-space-2);
  align-self: stretch;
  width: auto;
  margin: 0;
}

.cm-page-header--plain .cm-page-header__subtitle {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cm-page-header--plain .cm-page-header__end {
  flex: 0 0 auto;
  flex-wrap: nowrap;
}

}
@layer components {
/*
 * Pagination strip (CSS consolidation phase 5): the light pill pinned to
 * the bottom of a browse page, built by PageNavigation in
 * common/pagination.js into the page's #navigationDiv mount: previous and
 * next carets, the page select and the result count. The legacy rules moved
 * here from stylesheetv3.css in their old order, so the #navigationDiv rules
 * still win over the .navigation-div ones; PageNavigation's inline styles
 * became the __side, __caret, __results and __export parts.
 */

/* The mount PageNavigation builds into (the page's #navigationDiv). */
.pagination-mount {
  display: flex;
  justify-content: center;
}

.navigation-div {
  display: flex;
  height: 50px;
  position: fixed;
  z-index: var(--cm-z-raised);
  bottom: 0px;
  left: 70px;
  right: 0px;
  justify-content: center;
  align-items: center;
  width: fit-content;
  margin-inline: auto;
}

/* The previous and next halves, each holding its caret. */
.navigation-div__side {
  display: flex;
  justify-content: center;
  width: 50%;
}

.navigation-div__caret {
  font-size: var(--cm-text-3xl);
}

/* "Display [n] Results" and Export. */
.navigation-div__results {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
}

.navigation-div__export {
  display: flex;
  justify-content: center;
  width: 150px;
}

.navigation-div p {
  width: 100px;
  text-align: center;
}

.navigation-div i {
  color: var(--cm-text-on-dark);
}

.navigation-div select {
  cursor: pointer;
  width: auto;
}

.display-results-div {
  display: flex;
  justify-content: center;
  align-items: center;
  padding-left: 10px;
  padding-right: 10px;
}

.display-results-div p {
  padding-left: 10px;
  padding-right: 10px;
  text-align: right;
}

/* Body text for everything in the strip but its buttons (Export): in this
   layer the id would beat the button component's own color, which the
   legacy layer never did. Its id also outranks the caret rules below, so
   the carets stay body text too, as they always have. */
#navigationDiv :not(button, button *) {
  color: var(--cm-text-body);
}

#navigationDiv select,
#navigationDiv input {
  height: var(--cm-control-height);
}

/* The light pill (Automate-274y). */
.navigation-div {
  background-color: var(--cm-bg-surface);
  border: 1px solid var(--cm-border);
  border-bottom: none;
  border-top-left-radius: var(--cm-radius-xl);
  border-top-right-radius: var(--cm-radius-xl);
  box-shadow: var(--cm-shadow-md);
  padding: 0 var(--cm-space-8);
}

.navigation-div p {
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-medium);
}

.navigation-div select {
  color: var(--cm-text-body);
  height: var(--cm-control-height);
}

/* Caret arrows (prev / next): their color loses to the #navigationDiv
   rule above; .nav-arrow-disabled (pagination.js) hides one with no page
   to go to. */
.navigation-div .fa-caret-left,
.navigation-div .fa-caret-right {
  color: var(--cm-interactive);
  cursor: pointer;
  transition:
    color 120ms ease,
    opacity 120ms ease;
}

.navigation-div .fa-caret-left:hover,
.navigation-div .fa-caret-right:hover {
  color: var(--cm-interactive-hover);
}

.navigation-div .fa-caret-left.nav-arrow-disabled,
.navigation-div .fa-caret-right.nav-arrow-disabled {
  /* Hide the prev/next arrow when there's nowhere to navigate. Use
     visibility instead of display:none so the surrounding
     50%/center/50% layout stays balanced. */
  visibility: hidden;
  pointer-events: none;
}

/* After the .navigation-div p and .display-results-div p rules above. */
.navigation-div .navigation-div__display {
  text-align: right;
}

.navigation-div .navigation-div__count {
  text-align: left;
}

}
@layer components {
/*
 * Popup (CSS consolidation phase 4). Spec:
 * docs/specs/2026-09-30-css-phase-4-popups-design.md
 * Markup: common/popup-shell.js buildPopupShell(), or by hand in page HTML:
 *   div.cm-popup[--size][--stack] > div.cm-popup__box >
 *     header.cm-popup__header > h2.cm-popup__title, p.cm-popup__subtitle?,
 *       span.cm-popup__help?, div.cm-popup__actions?, button.cm-popup__close?
 *     (__help is a .cm-help-icon beside the title, components/help-icon.css)
 *     div.cm-popup__body, div.cm-popup__footer?
 * A closed popup carries the hidden attribute ([hidden] in utilities.css);
 * openPopup() and closePopup() in common/popup-shell.js open and close it.
 */

.cm-popup {
  display: flex;
  position: fixed;
  inset: 0 0 0 var(--sidebar-width);
  justify-content: center;
  align-items: center;
  background-color: var(--cm-bg-backdrop);
  z-index: var(--cm-z-overlay);
}

/* A floating popup (draggable panels): no backdrop, the page stays usable. */
.cm-popup--floating {
  position: absolute;
  background-color: transparent;
  pointer-events: none;
  z-index: var(--cm-z-float);
}

.cm-popup--floating > .cm-popup__box {
  pointer-events: all;
}

.cm-popup--floating > .cm-popup__box > .cm-popup__header {
  cursor: move;
}

/* Stacking: a popup opened over a popup, confirm prompts, patient alerts.
   After --floating so a floating panel can also be stacked. */
.cm-popup--stacked {
  z-index: var(--cm-z-popup-stacked);
}

.cm-popup--stacked-2 {
  z-index: var(--cm-z-popup-stacked-2);
}

.cm-popup--stacked-3 {
  z-index: var(--cm-z-popup-stacked-3);
}

.cm-popup--modal {
  z-index: var(--cm-z-modal);
}

.cm-popup--priority {
  z-index: var(--cm-z-modal-priority);
}

/* The session-timeout box: above every popup and modal, below the sidenav. */
.cm-popup--session {
  z-index: var(--cm-z-session);
}

/* The default, sm, md and wide sizes name the content width, as the legacy
   content-box .popup did: each adds the body's side padding and the box's
   1px borders. Full sizes the box to the window and tall sets its height,
   so neither adds padding. Modifiers reach only their own box (child
   combinator), so a popup opened from inside another (nested in its overlay
   to stack above it) keeps its own size. */
.cm-popup__box {
  display: flex;
  flex-direction: column;
  position: relative;
  box-sizing: border-box;
  min-width: min(calc(480px + 2 * var(--cm-space-6) + 2px), 98vw);
  max-width: min(calc(720px + 2 * var(--cm-space-6) + 2px), 98vw);
  max-height: 95vh;
  overflow: hidden;
  background-color: var(--cm-bg-surface);
  color: var(--cm-text-body);
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-xl);
  box-shadow: var(--cm-shadow-popup);
}

.cm-popup--sm > .cm-popup__box {
  max-width: min(calc(480px + 2 * var(--cm-space-6) + 2px), 98vw);
}

/* Md: a fixed width for two-column popups (Task, the add/edit patient alert
   form, patient detail) so the box does not resize while its lists load,
   capped to the overlay like wide. */
.cm-popup--md > .cm-popup__box {
  width: min(
    calc(880px + 2 * var(--cm-space-6) + 2px),
    calc(100vw - var(--sidebar-width) - 2 * var(--cm-space-4))
  );
  max-width: none;
}

/* Wide also caps to the overlay (right of the sidenav rail) with a small
   margin on each side, as full does, for windows narrower than the box. */
.cm-popup--wide > .cm-popup__box {
  max-width: min(
    calc(1180px + 2 * var(--cm-space-6) + 2px),
    calc(100vw - var(--sidebar-width) - 2 * var(--cm-space-4))
  );
}

/* A body holding the customer form (components/customer-form.css) takes a
   fixed width inside the wide cap, so its two columns keep one width
   whichever fields show (Fax, SFTP, a stored Customer Type pill). */
.cm-popup--wide > .cm-popup__box:has(> .cm-popup__body > .customer-form) {
  width: min(
    calc(960px + 2 * var(--cm-space-6) + 2px),
    calc(100vw - var(--sidebar-width) - 2 * var(--cm-space-4))
  );
}

/* Full: 95% of the window, capped to the overlay (which starts right of the
   sidenav rail) with a small margin on each side. */
.cm-popup--full > .cm-popup__box {
  width: min(95vw, calc(100vw - var(--sidebar-width) - 2 * var(--cm-space-4)));
  max-width: min(98vw, 1800px);
}

.cm-popup--tall > .cm-popup__box {
  height: 95vh;
}

/* A header whose actions take the spare width between the title and the
   close button (the held-delivery Review popup's reason banner), so a
   message that would sit above the body stays out of the body's height. */
.cm-popup--actions-fill > .cm-popup__box > .cm-popup__header {
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
}

.cm-popup--actions-fill > .cm-popup__box > .cm-popup__header > .cm-popup__actions > * {
  flex: 1 1 auto;
  min-width: 0;
}

.cm-popup__header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: start;
  column-gap: var(--cm-space-3);
  padding: var(--cm-space-4) var(--cm-space-4) var(--cm-space-3) var(--cm-space-6);
  border-bottom: 1px solid var(--cm-border);
}

.cm-popup__title {
  grid-column: 1;
  margin: 0;
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-semibold);
  line-height: 1.3;
  color: var(--cm-text-heading);
}

.cm-popup__subtitle {
  grid-column: 1;
  margin: var(--cm-space-1) 0 0;
  font-size: var(--cm-text-sm);
  color: var(--cm-text-muted);
}

.cm-popup__actions {
  grid-column: 2;
  grid-row: 1 / span 2;
  display: flex;
  align-items: center;
  gap: var(--cm-space-2);
}

/* A help icon beside the title (CSS phase 5.5 restyle): the popup's
   instructions, on hover or focus. A header with one grows a column for it
   between the title and the actions, so the icon stays out of the title
   and so out of the dialog's name. */
.cm-popup__header:has(> .cm-popup__help) {
  grid-template-columns: auto minmax(0, 1fr) auto auto;
}

.cm-popup__header:has(> .cm-popup__help) > .cm-popup__subtitle {
  grid-column: 1 / 3;
}

.cm-popup__header:has(> .cm-popup__help) > .cm-popup__actions {
  grid-column: 3;
}

.cm-popup__header:has(> .cm-popup__help) > .cm-popup__close {
  grid-column: 4;
}

/* Two classes so the 8px from the title (the column gap less the icon's own
   margin) beats help-icon.css's margin, and the icon takes the 18px
   title's height. */
.cm-popup__header > .cm-popup__help {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  justify-self: start;
  width: 16px;
  height: 16px;
  margin-left: calc(var(--cm-space-2) - var(--cm-space-3));
  font-size: var(--cm-text-xs);
}

/* A bordered square with the icon buttons' hover (components/button.css
   .cm-button--icon, CSS phase 5.5 restyle). */
.cm-popup__close {
  grid-column: 3;
  grid-row: 1 / span 2;
  box-sizing: border-box;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-color: transparent;
  border: 1px solid var(--cm-border-strong);
  border-radius: var(--cm-radius-md);
  color: var(--cm-text-body);
  font-size: var(--cm-text-lg);
  line-height: 1;
  cursor: pointer;
  transition:
    background-color 120ms ease,
    border-color 120ms ease,
    color 120ms ease;
}

.cm-popup__close:hover,
.cm-popup__close:focus-visible {
  border-color: var(--cm-interactive);
  background-color: var(--cm-chip-selected-bg);
  color: var(--cm-interactive);
}

.cm-popup__close:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

.cm-popup__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--cm-space-3);
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--cm-space-4) var(--cm-space-6) var(--cm-space-6);
  overflow-x: hidden;
  overflow-y: auto;
}

.cm-popup__footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--cm-space-2);
  padding: var(--cm-space-3) var(--cm-space-6);
  border-top: 1px solid var(--cm-border);
}

/* A footer item that sits at the left edge, apart from the right-aligned
   actions (e.g. What's New "Full changelog", a text button). */
.cm-popup__footer-start {
  margin-right: auto;
}

/* Content inside popups: ported from the legacy ".popup ..." rules
   (stylesheetv3.css "Modal / popup polish"). Builders now emit the field
   component (components/field.css) for every label; what's left here is
   layout only (row/cell spacing, control width) for the
   static popups built straight in page HTML. Forms PR 1 (Task 7) deleted
   the label rule this comment used to describe: the last markup that
   needed it (Post Payments' allocation-summary captions) now carries
   cm-field__label itself. The paragraph rule below stays: it styles
   plain paragraphs in popup cells, e.g. the Hotkeys popup's (invoice.html)
   nine-row shortcut list, the only remaining case. A classed or
   inline-styled <p> (every other popup's) already has its own look, so
   the plain :not([class]) guard is enough; no field-class coupling
   needed. */
.cm-popup__box .row {
  gap: var(--cm-space-4);
  width: 100%;
  align-items: center;
  margin-bottom: var(--cm-space-2);
  justify-content: stretch;
}

/* Field columns in a popup body (the SaaS Owner popup): a row
   of __column s sharing its width evenly, each stacking its fields at full
   width with their labels on the left edge. Two classes deep, after the
   .row rule above, so the row's own alignment and gap win. */
.cm-popup__box .cm-popup__columns {
  align-items: flex-start;
  gap: 10px;
}

.cm-popup__column {
  justify-content: flex-start;
  align-items: stretch;
  gap: var(--cm-space-3);
}

.cm-popup__columns > .cm-popup__column {
  flex: 1 1 0;
}

/* A single 340px field column the body centers (the Tax Code override):
   labels left-aligned, every control one width, 14px between fields. */
.cm-popup__box .cm-popup__form {
  width: 340px;
  max-width: 100%;
}

.cm-popup__form-column {
  align-items: stretch;
  width: 340px;
  max-width: 100%;
}

.cm-popup__form-column > * {
  margin-bottom: 14px;
}

.cm-popup__form-column input:disabled {
  opacity: 0.6;
}

/* A two-column field grid spanning the body (Mark Problem): fields in
   reading order, labels on the left edge, 12px between rows and 16px between
   columns; __grid-span takes a whole row. One column on a narrow window. */
.cm-popup__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--cm-space-3) var(--cm-space-4);
  align-self: stretch;
}

.cm-popup__grid-span {
  grid-column: 1 / -1;
}

@media (max-width: 600px) {
  .cm-popup__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* A prompt's message (CustomPrompt) wraps at 400px. */
.cm-popup__prompt-text {
  max-width: 400px;
}

/* A block that spans the body's width instead of centering on its own
   (ConfirmDialog's renderDetail slot, the portal's fee total). */
.cm-popup__block {
  align-self: stretch;
}

/* A full-width divider between sections of a popup body. */
.cm-popup__rule {
  width: 100%;
  margin: 6px 0;
}

.cm-popup__box .cell {
  flex: 1 1 0;
  align-items: stretch;
  gap: var(--cm-space-1);
}

.cm-popup__box .cell p:not([class]) {
  margin: 0;
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-medium);
  color: var(--cm-text-body);
  text-align: left;
}

/* Excludes checkbox/radio inside :where() so the exclusion costs no
   specificity (same pattern as field.css): a check row's input keeps
   base.css's 18px square instead of stretching to the cell's width. */
.cm-popup__box .cell :where(input:not([type='checkbox'], [type='radio'])),
.cm-popup__box .cell select,
.cm-popup__box .cell textarea,
.cm-popup__box td :where(input:not([type='checkbox'], [type='radio'])),
.cm-popup__box td select,
.cm-popup__box td textarea {
  width: 100%;
  box-sizing: border-box;
}

/* Unclassed body headings only: a classed heading (What's New release
   titles, a .cm-section-title) keeps its own look, which this rule would
   beat (a legacy rule by layer, a component class by specificity). */
.cm-popup__body h1:not([class]) {
  font-size: var(--cm-text-2xl);
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-heading);
  margin: 0;
}

.cm-popup__body h2:not([class]) {
  font-size: var(--cm-text-xl);
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-heading);
  margin: 0 0 var(--cm-space-3);
}

.cm-popup__body h3:not([class]) {
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-heading);
  margin: 0 0 var(--cm-space-2);
}

/* Read-only label and value rows (esMD Submission Detail, Additional Fax
   Info), built by buildPopupDetails() in common/popup-shell.js: bold row
   headers on one line, values beside them. The label column shrinks to
   its widest label (width: 1% with nowrap), so short values start right
   after it instead of the spare width splitting between the columns. The
   row header inherits the value's alignment rather than the user agent's
   centered th. */
.cm-popup__details {
  width: 100%;
  border-spacing: 0 var(--cm-space-1);
}

.cm-popup__details-label {
  width: 1%;
  padding-right: var(--cm-space-3);
  font-weight: var(--cm-fw-bold);
  text-align: inherit;
  white-space: nowrap;
}

/* A section title row across both columns (buildPopupDetails' heading(),
   the read-only customer popup); a section after the first starts with
   space above it. */
.cm-popup__details-heading:not(:first-child) > td {
  padding-top: var(--cm-space-4);
}

/* Request Details (common/popups.js) keeps a width floor so switching its
   tabs does not resize the popup, capped to the overlay (right of the
   sidenav rail) with a small margin on each side, as wide and full are. A
   feature rule kept here: a legacy-layer rule cannot beat .cm-popup__box's
   min-width. */
.cm-popup__box.request-details-popup {
  min-width: min(
    calc(960px + 2 * var(--cm-space-6) + 2px),
    calc(100vw - var(--sidebar-width) - 2 * var(--cm-space-4))
  );
}

/* Edit Facility (features/facilities/facilities.html) gains the same
   floor: switching tabs stops resizing and re-centering the popup.
   Measured at 1440 with an e2e run after the tabs-component rebuild (each
   tab's own content width, floor disabled): Details 1230px (the widest),
   Additional Features 997px, Users 976px, Locations 1056px. Details'
   1230px is exactly .cm-popup--wide's own max-width cap below (its box
   already carries cm-popup--wide), not a coincidence of its content: this
   floor is written as that same expression so the two pin the box at the
   --wide cap together and cannot drift apart if --cm-space-6 changes. */
.cm-popup__box.facility-edit-popup {
  min-width: min(
    calc(1180px + 2 * var(--cm-space-6) + 2px),
    calc(100vw - var(--sidebar-width) - 2 * var(--cm-space-4))
  );
}

/* What's New (common/whats-new.js) puts each release section straight in
   the body; it spans it, as it did before the popup moved onto this
   component, rather than shrinking to its content and centering. Kept here
   beside the body rule it adjusts; the release's own rules are
   components/whats-new.css. */
.cm-popup__body > .whats-new__release {
  align-self: stretch;
}

}
@layer components {
/*
 * Drawer (CSS consolidation phase 4): a fixed panel at the edge of the page
 * that leaves the rest of the page usable (no backdrop). Spec:
 * docs/specs/2026-09-30-css-phase-4-popups-design.md
 * Markup:
 *   div.cm-drawer.cm-drawer--bottom|--right[.cm-drawer--chrome] >
 *     header.cm-drawer__header > h2.cm-drawer__title, button.cm-drawer__close
 *     div.cm-drawer__body
 * Hidden until the page shows it (style.display = "flex").
 * --inset: a panel inside a .cm-drawer-host parent, over its content. It shows
 * while it lacks the hidden attribute (utilities.css hides it).
 */

.cm-drawer {
  display: none;
  flex-direction: column;
  position: fixed;
  z-index: var(--cm-z-page-drawer);
  box-sizing: border-box;
  background-color: var(--cm-bg-surface);
  color: var(--cm-text-body);
  box-shadow: var(--cm-shadow-lg);
}

/* Bottom sheet across the page, right of the sidenav rail. */
.cm-drawer--bottom {
  inset: auto 0 0 var(--sidebar-width);
  min-height: 500px;
  max-height: 60vh;
  border-top: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-xl) var(--cm-radius-xl) 0 0;
}

/* Side panel against the right edge, sized by its content. */
.cm-drawer--right {
  top: var(--cm-space-5);
  right: 0;
  max-height: calc(100vh - 2 * var(--cm-space-5));
  border-radius: var(--cm-radius-xl) 0 0 var(--cm-radius-xl);
}

/* Panel inside a positioned parent (.cm-drawer-host), against its right edge. */
.cm-drawer-host {
  position: relative;
}

.cm-drawer--inset {
  position: absolute;
  inset: 0 0 0 auto;
  width: min(380px, 100%);
  /* Below the dialogs stacked over the review (they sit inside its overlay). */
  z-index: var(--cm-z-panel);
}

.cm-drawer--inset:not([hidden]) {
  display: flex;
}

/* Pinned dark chrome, like the PDF viewers (owner decision 2026-09-30). */
.cm-drawer--chrome {
  background-color: var(--cm-bg-chrome);
  color: var(--cm-text-on-dark);
}

.cm-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
  padding: var(--cm-space-4) var(--cm-space-4) var(--cm-space-3) var(--cm-space-6);
  border-bottom: 1px solid var(--cm-border);
}

.cm-drawer--chrome > .cm-drawer__header {
  border-bottom-color: var(--cm-border-on-dark);
}

.cm-drawer__title {
  margin: 0;
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-semibold);
  line-height: 1.3;
  color: var(--cm-text-heading);
}

.cm-drawer--chrome .cm-drawer__title {
  color: var(--cm-text-on-dark);
}

/* Same 32px bordered square as the popup's close. */
.cm-drawer__close {
  flex-shrink: 0;
  box-sizing: border-box;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-color: transparent;
  border: 1px solid var(--cm-border-strong);
  border-radius: var(--cm-radius-md);
  color: var(--cm-text-body);
  font-size: var(--cm-text-lg);
  line-height: 1;
  cursor: pointer;
  transition:
    background-color 120ms ease,
    border-color 120ms ease,
    color 120ms ease;
}

.cm-drawer__close:hover,
.cm-drawer__close:focus-visible {
  border-color: var(--cm-interactive);
  background-color: var(--cm-chip-selected-bg);
  color: var(--cm-interactive);
}

.cm-drawer__close:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

.cm-drawer--chrome .cm-drawer__close {
  border-color: transparent;
  color: var(--cm-text-on-dark);
}

.cm-drawer--chrome .cm-drawer__close:hover,
.cm-drawer--chrome .cm-drawer__close:focus-visible {
  border-color: transparent;
  background-color: var(--cm-bg-on-dark-hover);
  color: var(--cm-text-on-dark);
}

.cm-drawer__body {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--cm-space-4) var(--cm-space-6) var(--cm-space-6);
  overflow-y: auto;
}

}
@layer components {
/*
 * The customer pages' footer (portal refresh, docs/specs/
 * 2026-10-12-portal-refresh-design.md section 10; the request flow uses it
 * too): one slim row on the page's surface, the trust line at the start,
 * the copyright in the middle, the links at the end, the reCAPTCHA line on
 * its own row; stacked on a phone. Customer only: portal.css and
 * request.css import it, staff.css does not.
 * Markup (built by _shared/cm-footer.js into the page's #cm-footer slot):
 *   footer.cm-footer > div.cm-footer__trust > (a.cm-footer__badge,
 *   p.cm-footer__statement > svg.cm-footer__lock), p.cm-footer__copy,
 *   p.cm-footer__links > a, a, p.cm-footer__recaptcha.
 */

.cm-footer {
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--cm-space-4);
  width: 100%;
  padding: 14px 40px;
  border-top: 1px solid var(--cm-gray-200);
  background-color: var(--cm-bg-surface);
  color: var(--cm-text-muted);
  font-size: var(--cm-text-caption);
  text-align: left;
}

.cm-footer a {
  color: var(--cm-interactive);
}

/* The badge inline with the HIPAA line, centered as a unit. */
.cm-footer__trust {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
}

/* The HITRUST badge, a link to HITRUST Alliance. The artwork is a data URI
   so it ships with the stylesheet; it carries its own text ("CERTIFIED",
   "e1"). */
.cm-footer__badge {
  box-sizing: border-box;
  display: block;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  padding: 2px;
  border-radius: var(--cm-radius-md);
  background-image: url("data:image/svg+xml;utf8,%3C?xml version='1.0' encoding='UTF-8'?%3E%3Csvg id='Layer_1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 966.61 966.61'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfont-family:Uniform-Regular2, Uniform;font-size:70.63px;letter-spacing:.05em;%7D.cls-1,.cls-2%7Bfill:%23c23227;%7D.cls-3%7Bfill:%23232964;%7D.cls-3,.cls-4,.cls-5,.cls-2,.cls-6%7Bstroke-width:0px;%7D.cls-4%7Bfill:%2322214a;%7D.cls-5%7Bfill:%23d9f5fe;%7D.cls-6%7Bfill:%23fff;%7D%3C/style%3E%3C/defs%3E%3Cpath class='cls-5' d='M317.04,135.59h377.02v960.61h-377.02c-24.55,0-44.47-19.93-44.47-44.47V180.06c0-24.55,19.93-44.47,44.47-44.47Z' transform='translate(-132.59 1099.2) rotate(-90)'/%3E%3Cpath class='cls-6' d='M385.53-198.07h240.04v960.61h-240.04c-24.55,0-44.47-19.93-44.47-44.47V-153.6c0-24.55,19.93-44.47,44.47-44.47Z' transform='translate(765.54 -201.07) rotate(90)'/%3E%3Cpath class='cls-2' d='M138.85,682.85c-3.18,0-5.2-.12-8.08-.12-3.05,0-4.29-.43-4.29-1.52,0-.87.8-2.17,2.12-4.01,3.77-5.29,6.46-11.35,7.11-19.33.65-8.05.78-14.95.88-23.49.07-6.46.43-13.27.43-19.57,0-10.82-.57-20.97-.32-33.41.08-4.04.11-7.36.11-10.26,0-7.32-.19-11.96-.19-18.57,0-10.37-.13-21.3-.35-31.54-.19-8.8-4.43-17.68-9.03-23.79-.68-.89-.63-1.76.7-2.14.77-.22,1.8-.27,2.66-.27,4.44,0,9.2.08,13.96.16,1.52.03,3.03.03,4.55.03,4.81,0,9.63-.19,14.46-.19,3.18,0,5.2.12,8.07.12,3.05,0,4.29.43,4.29,1.52,0,.87-.8,2.17-2.12,4.01-3.77,5.29-6.46,11.35-7.11,19.33-.65,8.05-.78,14.95-.87,23.48-.03,3.15-.05,6.24-.05,9.31,0,3.92.02,7.81.04,11.71,0,1.29.8,2.38,1.83,2.38,3.91-.03,6.86-.02,12.02-.06,3.87,0,7.75,0,11.63,0,2.58,0,5.16.01,7.74.03,1.01,0,1.78-1.07,1.78-2.32-.05-3.97-.14-7.46-.14-11.82,0-10.33-.14-21.26-.35-31.51-.19-8.8-4.43-17.68-9.03-23.79-.68-.89-.63-1.76.7-2.14.77-.22,1.8-.27,2.66-.27,5.63,0,11.24.15,16.88.15s10.73-.15,16.09-.15c3.18,0,5.2.13,8.07.13,3.05,0,4.29.43,4.29,1.52,0,.87-.8,2.17-2.12,4.01-3.77,5.29-6.47,11.35-7.11,19.33-.65,8.05-.78,14.95-.88,23.48-.08,7.53-.44,14.1-.44,21.34,0,9.73.56,20.41.33,31.65-.08,4.04-.11,7.36-.11,10.27,0,7.32.19,11.96.19,18.57,0,10.37.14,21.3.35,31.54.19,8.8,4.43,17.68,9.03,23.79.68.89.63,1.76-.7,2.14-.77.22-1.8.27-2.66.27-4.44,0-9.2-.08-13.96-.16-1.51-.02-3.02-.03-4.53-.03-4.82,0-9.64.19-14.48.19-3.18,0-5.2-.12-8.07-.12-3.05,0-4.29-.43-4.29-1.52,0-.87.8-2.17,2.12-4.01,3.77-5.29,6.47-11.35,7.11-19.33.65-8.05.78-14.95.87-23.49.03-3.15.05-6.24.05-9.31,0-9.95-.13-19.62-.09-30.15,0-1.29-.79-2.4-1.83-2.4-3.59.05-7.17.19-10.76.19-6.74,0-13.49-.26-20.25-.17-1.07.02-2,1.01-2.02,2.34,0,.47-.02.93-.03,1.41-.08,4.03-.11,7.36-.11,10.26,0,7.34.19,11.98.19,18.62,0,10.33.14,21.26.35,31.5.19,8.8,4.43,17.68,9.03,23.79.68.89.63,1.76-.7,2.14-.77.22-1.8.27-2.66.27-5.63,0-11.24-.14-16.88-.14s-10.72.14-16.08.14h-.01Z'/%3E%3Cpath class='cls-2' d='M265.41,682.85c-3.18,0-5.2-.12-8.08-.12-3.05,0-4.29-.43-4.29-1.52,0-.87.8-2.17,2.12-4.01,3.77-5.29,6.46-11.35,7.11-19.33.65-8.05.78-14.95.88-23.49.03-3.15.05-6.23.05-9.28,0-8.7-.1-17.19-.1-26.23,0-5.55.04-11.32.16-17.47.08-4.04.11-7.36.11-10.26,0-7.32-.19-11.96-.19-18.57,0-10.37-.14-21.3-.35-31.54-.19-8.8-4.43-17.68-9.03-23.79-.68-.89-.63-1.76.7-2.14.77-.22,1.8-.27,2.66-.27,4.44,0,9.2.08,13.96.16,1.52.03,3.03.03,4.55.03,4.81,0,9.63-.19,14.46-.19,3.18,0,5.2.12,8.07.12,3.05,0,4.29.43,4.29,1.52,0,.87-.8,2.17-2.12,4.01-3.77,5.29-6.47,11.35-7.11,19.33-.65,8.05-.78,14.95-.87,23.48-.08,7.81-.28,15.52-.28,23.15,0,9.55.4,18.88.17,29.83-.08,4.03-.11,7.36-.11,10.26,0,7.34.19,11.98.19,18.62,0,10.33.14,21.26.36,31.5.19,8.8,4.43,17.68,9.03,23.79.68.89.63,1.76-.7,2.14-.77.22-1.8.27-2.66.27-5.63,0-11.24-.14-16.88-.14s-10.72.14-16.08.14h0Z'/%3E%3Cpath class='cls-4' d='M345.22,682.76c-3.18,0-5.2-.12-8.08-.12-3.05,0-4.29-.43-4.29-1.52,0-.87.8-2.17,2.12-4.01,3.77-5.29,6.47-11.35,7.11-19.33.65-8.05.78-14.95.87-23.49.1-9,.19-17.4.19-26.17,0-8.3-.28-17.19-.08-26.81.08-4.03.11-7.36.11-10.26,0-7.34-.19-11.98-.19-18.61,0-5.67.04-12.16.04-18.56,0-3.64-.01-7.25-.06-10.66,0-1.31-.89-2.32-1.95-2.32-3.47.02-6.92.08-10.32.19-7.08.24-14.43,5.77-19.33,11.49-.72.84-1.42.79-1.72-.87-.18-.96-.21-2.24-.21-3.3,0-5.53.07-11.45.13-17.37.02-1.72.02-3.44.02-5.15,0-2.15-.01-5.71-.03-7.86-.02-2.59,1.26-3.29,3.34-3.29h14.64c7.65.14,15.3.29,22.95.29s14.93-.19,22.43-.19c3.58,0,8.88.14,12.07.11l17.41-.21c2.26,0,3.21.64,3.21,3.82,0,6.24.13,14.49.13,19.55,0,3.96-.1,6.47-.1,10.05,0,3.79-.34,5.34-1.22,5.34-.7,0-1.75-1-3.23-2.63-4.26-4.68-9.13-8.54-15.55-9.34-3.95-.49-7.56-.56-11.34-.56-1.02,0-1.88.98-1.88,2.25-.06,7.28-.15,14.85-.21,20-.03,3.15-.05,6.23-.05,9.29,0,8.69.1,17.16.1,26.19,0,5.56-.04,11.34-.16,17.5-.08,4.03-.11,7.36-.11,10.26,0,7.34.19,11.98.19,18.62,0,10.33.14,21.26.35,31.5.19,8.8,4.43,17.68,9.03,23.78.68.89.63,1.76-.7,2.14-.77.22-1.8.27-2.66.27-5.63,0-11.25-.15-16.87-.15s-10.73.15-16.09.15l-.03.02Z'/%3E%3Cpath class='cls-4' d='M491.3,682.75c-3.9,0-7.81-.04-11.71-.08-.22,0-.81.03-1.52.03-.86,0-1.91-.05-2.68-.27-1.35-.38-1.39-1.25-.71-2.14,2.81-3.68,6.06-7.34,7.69-12.28.39-1.18.55-2.37.55-3.56,0-3.33-1.26-6.72-2.27-10.38-1.68-6.11-2.98-11.4-4.39-16-2.39-7.79-4.84-14.26-8.2-24.24-.19-.55-.6-2.16-1.34-4.26-.48-1.37-1.5-1.78-2.7-1.8-2.01-.03-3.86.06-5.31.06-.47,0-4.15.12-4.58.12-1.08,0-1.96.82-1.96,2.16-.05,6.77-.15,10.33-.14,11.45.04,6.62.03,11.3.07,19.83.1,15.82-.2,17.68,1.36,23.32,1.62,5.88,4.6,11.37,7.76,15.56.68.89.63,1.76-.7,2.14-.77.22-1.8.27-2.66.27-7.23,0-14.41-.22-21.63-.22-5.96,0-12.1.26-17.8.19-.21,0-.8.03-1.51.03-.86,0-1.89-.05-2.66-.27-1.33-.38-1.38-1.25-.7-2.14,4.6-6.1,8.84-14.98,9.03-23.78.21-9.52.36-19.63.36-29.31,0-7.6.2-12.35.2-20,0-3.09-.03-6.65-.12-11.06-.22-10.57.14-19.39.14-28.72,0-7.99-.16-16.12-.24-24.26-.09-8.53-.22-15.43-.87-23.48-.65-7.98-3.34-14.04-7.11-19.33-1.31-1.84-2.12-3.22-2.12-4.14s.83-1.4,2.8-1.4c3.55,0,5.64-.12,9.01-.12,4.56,0,9.07.18,13.59.18,11.63,0,1.57-.18,28.03-.18,3.81,0,7.76.5,11.54,1.05,10.12,1.46,20.82,6.86,27.67,16.58,6.1,8.66,8.52,19.47,8.76,30.33.32,15.24-.49,25.23-3.85,36.81-2.11,7.26-6.41,12.92-11.58,16.83-.92.69-1.85,1.33-2.8,1.93-1.26.8-1.29,2.44-.82,3.88,2.14,6.52,4.26,13.52,6.49,20.13,2.28,6.81,4.12,11.43,7.11,20.37,6.84,20.84,7.74,25.24,13.95,32.77,1.35,1.63,2.08,2.72,3.38,4.42.69.89.99,2.39-.07,2.59-1.19.22-2.96.24-3.81.24-10.32,0-20.61.08-30.88.08h-.01ZM453.81,582.06c.65-.02,1.33-.04,2.01-.04,2.56,0,6.6.05,7.9-.03,10.51-.62,13.23-1.36,17.98-8.35,2.4-3.53,3.02-8.48,3.27-12.79.2-3.49.36-7,.36-10.5,0-4.86-.3-9.7-1.2-14.48-.67-3.58-2.23-7.21-4.45-9.79-4.69-5.47-12.51-5.65-18.12-5.65-2.18,0-4.49.1-6.61.25-.95.07-1.74.25-2.42.95-.47.48-.52,1.56-.52,2.42,0,1.83,0,3.6,0,4.62,0,3.03,0,5.99,0,8.93,0,3.51-.01,7-.07,10.61-.05,3.34-.08,8.65-.08,14.3,0,6.03.03,12.42.09,17.18.02,1.29.8,2.41,1.84,2.37h0Z'/%3E%3Cpath class='cls-4' d='M578.58,685.32c-7.19,0-14.74-1.19-20.99-5.7-7.01-5.06-13.23-11.98-17.3-22.42-6.51-16.71-7.02-35.49-7.08-53.68-.02-7.05-.24-14.51-.08-22.47.08-4.02.11-7.34.11-10.23,0-7.27-.19-11.89-.19-18.46,0-10.36-.13-21.24-.35-31.45-.19-8.77-4.43-17.61-9.03-23.69-.68-.89-.63-1.75.7-2.13.77-.21,1.8-.26,2.65-.26,5.46,0,11.39.19,17.24.19,5.39,0,10.78-.19,16.18-.19,3.19,0,5.21.13,8.08.13,3.05,0,4.3.43,4.3,1.51,0,.87-.8,2.16-2.12,4-3.77,5.27-6.46,11.31-7.11,19.26-.65,8.02-.78,14.89-.87,23.39-.05,4.83-.07,7.92-.07,10.27,0,4.35.06,6.18.06,11.82,0,2.64-.04,6.1-.04,11.06,0,6.43.11,27.42.13,31.01.04,9.15.07,18.54.74,24.73,1.3,12.05,4.58,18.78,12.3,23.35,2.41,1.43,5.18,2.14,8,2.14,6.2,0,12.64-3.42,16.04-10.14,1.87-3.7,2.67-7.49,3.53-11.55,1.62-7.64,1.76-18.7,1.76-28.2,0-8.4-.09-15.33-.1-16.57-.02-2.52-.11-5.57-.11-8.28,0-14.57-.06-20.22-.06-28.81,0-10.77-.12-22.29-.35-33.04-.19-8.77-4.37-17.61-8.91-23.69-.67-.89-.63-1.75.69-2.13.76-.21,1.77-.26,2.62-.26,6.84,0,13.64.2,20.45.2,3.22,0,6.44-.04,9.66-.08h.16c1.94,0,2.76.46,2.76,1.39s-.79,2.29-2.09,4.12c-3.72,5.27-6.38,11.31-7.02,19.26-.64,8.02-.77,14.89-.86,23.39-.08,7.71-.13,15-.13,22.42,0,9.43.08,19.07.25,30.05.05,2.95.07,5.9.07,8.85,0,3.18.02,6.39.02,9.59,0,15.11-.52,30.37-6.42,43.99-3.84,8.87-9.76,16.77-16.39,21.43-7.02,4.94-13.44,5.89-20.84,5.89h0Z'/%3E%3Cpath class='cls-4' d='M685.42,685.31c-8.42,0-16.54-2.36-22.74-7.28-3.46-2.75-6.21-4.71-8.99-4.71-2.95,0-5.95,2.21-9.89,8.02-1.09,1.61-2.27,2.76-3.19,2.76s-1.58-1.19-1.58-4.29c0-6.11.18-14.08.18-22.21,0-6.62-.08-13.24-.03-18.25.03-3.53,0-7.07,0-10.6,0-.31,0-.67,0-1.05,0-1.82.1-4.2,1.19-4.73,1.02-.49,2.48-.6,3.9-.6,2.97,0,4.86-.08,6.19-.08s2.12.08,2.84.4c1.03.46,1.2,2.18,2.75,7.29.83,2.74,1.66,5.48,2.67,8.13,1.93,5.06,4.36,9.94,7.65,13.96,4.26,5.21,11.18,8.27,17.79,8.27,9.66,0,18.92-6.72,18.92-19.49,0-15.29-11.26-24.42-21.55-29.44-7.41-3.62-14.22-7.61-20.17-12.29-5.95-4.68-10.97-10.26-14.91-16.6-5.74-9.22-8.73-19.94-8.73-31.61,0-10.77,1.51-21.97,5.47-31.64,3.46-8.46,8.84-15.68,16.09-20.62,6.47-4.4,14.44-7,23.86-7,8.18,0,16.08,2.36,22.1,7.28,3.36,2.75,6.03,4.71,8.74,4.71,2.87,0,5.78-2.21,9.61-8.02,1.06-1.61,2.21-2.76,3.1-2.76s1.54,1.19,1.54,4.29c0,6.13-.17,14.15-.17,22.26,0,6.6.07,13.2.03,18.21-.03,3.53,0,7.07,0,10.6,0,.31,0,.66,0,1.03,0,1.83-.09,4.23-1.15,4.76-.99.49-2.41.6-3.79.6-2.88,0-4.72.08-6.01.08s-2.06-.08-2.77-.4c-1-.46-1.17-2.18-2.67-7.28-.81-2.74-1.61-5.48-2.6-8.13-1.87-5.06-4.24-9.94-7.43-13.95-4.18-5.26-10.97-8.28-17.46-8.28-4.36,0-8.78,1.31-11.92,3.84-4.9,3.96-7.37,10.36-7.37,16.91,0,4.29,1.06,8.64,3.2,12.41,4.91,8.63,14.17,13.04,21.89,16.67,11.66,5.47,21.7,10.66,29.28,19.27,8.85,10.05,12.9,24.55,12.9,39.31,0,8.01-1.06,16.06-2.92,23.5-3.06,12.28-9.05,23.02-19.28,29.79-6.66,4.41-14.86,7-24.56,7h0Z'/%3E%3Cpath class='cls-4' d='M776.05,682.76c-3.19,0-5.2-.12-8.08-.12-3.05,0-4.29-.43-4.29-1.52,0-.87.8-2.17,2.12-4.01,3.77-5.29,6.46-11.35,7.11-19.33.65-8.05.78-14.95.88-23.49.1-9,.19-17.4.19-26.17,0-8.3-.28-17.19-.08-26.81.08-4.03.11-7.36.11-10.26,0-7.34-.19-11.98-.19-18.61,0-5.67.04-12.16.04-18.56,0-3.64-.01-7.25-.06-10.66,0-1.31-.89-2.32-1.95-2.32-3.47.02-6.92.08-10.32.19-7.08.24-14.43,5.77-19.33,11.49-.72.84-1.42.79-1.72-.87-.18-.96-.21-2.24-.21-3.3,0-5.53.07-11.45.13-17.37.02-1.72.02-3.44.02-5.15,0-2.15,0-5.71-.03-7.86-.02-2.59,1.26-3.29,3.34-3.29h14.64c7.65.14,15.3.29,22.95.29s14.93-.19,22.43-.19c3.58,0,8.88.14,12.07.11l17.41-.21c2.26,0,3.21.64,3.21,3.82,0,6.24.13,14.49.13,19.55,0,3.96-.1,6.47-.1,10.05,0,3.79-.34,5.34-1.22,5.34-.7,0-1.75-1-3.23-2.63-4.26-4.68-9.13-8.54-15.55-9.34-3.95-.49-7.56-.56-11.34-.56-1.02,0-1.87.98-1.87,2.25-.06,7.28-.15,14.85-.21,20-.04,3.15-.05,6.23-.05,9.29,0,8.69.1,17.16.1,26.19,0,5.56-.04,11.34-.16,17.5-.08,4.03-.11,7.36-.11,10.26,0,7.34.19,11.98.19,18.62,0,10.33.14,21.26.35,31.5.19,8.8,4.43,17.68,9.03,23.78.68.89.63,1.76-.7,2.14-.77.22-1.8.27-2.66.27-5.63,0-11.24-.15-16.87-.15s-10.73.15-16.09.15l-.03.02Z'/%3E%3Cpath class='cls-4' d='M867.28,505.39c0,6.14-4.82,10.96-11.09,10.96s-11.16-4.82-11.16-10.96,4.95-10.83,11.16-10.83,11.09,4.82,11.09,10.83ZM847.8,505.39c0,4.82,3.57,8.65,8.45,8.65s8.25-3.83,8.25-8.58-3.5-8.72-8.32-8.72-8.38,3.9-8.38,8.65ZM854.47,511.07h-2.51v-10.83c.99-.2,2.38-.33,4.16-.33,2.05,0,2.97.33,3.76.79.59.46,1.06,1.32,1.06,2.38,0,1.19-.92,2.11-2.24,2.51v.13c1.06.4,1.65,1.19,1.98,2.64.33,1.65.53,2.31.79,2.71h-2.71c-.33-.4-.53-1.39-.86-2.64-.2-1.19-.86-1.72-2.24-1.72h-1.19v4.36ZM854.54,504.93h1.19c1.39,0,2.51-.46,2.51-1.58,0-.99-.73-1.65-2.31-1.65-.66,0-1.12.07-1.39.13v3.1Z'/%3E%3Ctext class='cls-1' transform='translate(280.98 770.75)'%3E%3Ctspan x='0' y='0'%3ECERTIFIED%3C/tspan%3E%3C/text%3E%3Cpath class='cls-3' d='M493.94,303.85h-85.52c1.19,7.76,4.62,13.99,10.3,18.69,5.67,4.7,12.76,7.05,21.27,7.05,5.97,0,11.49-1.15,16.57-3.47,5.07-2.31,8.65-4.66,10.75-7.05l3.13-3.36,19.25,18.58c-.45.6-1.08,1.42-1.9,2.46-.82,1.05-2.76,2.91-5.82,5.6-3.06,2.69-6.42,5.08-10.07,7.16-3.66,2.09-8.55,3.96-14.66,5.6-6.12,1.64-12.61,2.46-19.48,2.46-17.91,0-32.73-5.67-44.44-17.02-11.72-11.34-17.58-25.52-17.58-42.54s6.01-31.34,18.02-42.99c12.01-11.64,26.83-17.46,44.44-17.46,15.97,0,29.55,5.45,40.75,16.34,11.19,10.9,16.79,23.96,16.79,39.18,0,1.94-.15,3.81-.45,5.6-.3,1.79-.6,3.06-.9,3.81l-.45,1.34ZM437.52,261.31c-7.16,0-13.36,2.09-18.58,6.27-5.23,4.18-8.51,9.63-9.85,16.34h55.3c-1.05-6.42-4.11-11.79-9.18-16.12-5.08-4.33-10.97-6.49-17.69-6.49Z'/%3E%3Cpath class='cls-3' d='M506.93,238.47l57.1-39.85h26.86v156.72h-32.46v-118.68l-36.05,23.53-15.45-21.72Z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  text-decoration: none;
  transition:
    transform 120ms ease,
    opacity 120ms ease;
}

.cm-footer__badge:hover,
.cm-footer__badge:focus-visible {
  transform: translateY(-1px);
  opacity: 0.9;
  outline: none;
}

.cm-footer__statement {
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-2);
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-caption);
  line-height: var(--cm-lh-snug);
  letter-spacing: 0.01em;
  text-align: left;
}

.cm-footer__lock {
  flex: 0 0 auto;
}

.cm-footer__links {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--cm-space-4);
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-caption);
  line-height: var(--cm-lh-snug);
}

.cm-footer__copy {
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-caption);
}

/* The reCAPTCHA line, on its own row under the others. Google allows
   hiding the badge it pins to the window's bottom right (it sat over the
   footer) as long as the page says the site is protected by reCAPTCHA,
   which this line does. */
.cm-footer__recaptcha {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--cm-text-caption);
}

.grecaptcha-badge {
  visibility: hidden;
}

@media (max-width: 600px) {
  .cm-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--cm-space-2);
    padding: var(--cm-space-4) 18px;
  }
}

}
@layer components {
/*
 * The verification challenge (CSS phase 6): the reCAPTCHA v2 checkbox in a
 * card over a dark backdrop, shown when the backend asks a customer to
 * prove they are human. Customer only: portal.css and request.css import
 * it, staff.css does not.
 * Markup (built by solveChallenge() in recaptcha.js, removed when solved or
 * cancelled): div.cm-challenge > div.cm-challenge__card >
 *   div.cm-challenge__title, div.cm-challenge__widget (Google renders the
 *   checkbox into it), button.cm-challenge__cancel.
 */

.cm-challenge {
  position: fixed;
  inset: 0;
  z-index: var(--cm-z-challenge);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cm-bg-backdrop-challenge);
}

.cm-challenge__card {
  max-width: 360px;
  padding: var(--cm-space-6);
  border-radius: var(--cm-radius-lg);
  background: var(--cm-bg-surface);
  box-shadow: var(--cm-shadow-challenge);
  color: var(--cm-challenge-text);
  text-align: center;
}

.cm-challenge__title {
  margin-bottom: var(--cm-space-3);
  font-weight: var(--cm-fw-semibold);
}

.cm-challenge__widget {
  display: flex;
  justify-content: center;
  margin-bottom: var(--cm-space-3);
}

.cm-challenge__cancel {
  border: none;
  background: none;
  color: var(--cm-challenge-cancel);
  text-decoration: underline;
  cursor: pointer;
}

}
@layer components {
/*
 * Hero band (portal refresh, docs/specs/2026-10-12-portal-refresh-design.md
 * section 3): the Midnight band across the top of a customer page, behind
 * its title, with the page's cards pulled up onto its lower edge. Navy with
 * a teal glow in its top corner (the --cm-hero-* tokens); the page around it
 * stays light.
 * Markup:
 *   section.cm-hero[--short] > div.cm-hero__wrap[--narrow|--mid|--list] >
 *     (a|button).cm-hero__back?, span.cm-hero__check?, p.cm-hero__eyebrow?,
 *     h1.cm-hero__title, p.cm-hero__text?,
 *     nav.cm-stepper.cm-stepper--on-dark(-wizard)?
 *   or, with the page's own actions at the band's end:
 *     div.cm-hero__wrap > div.cm-hero__row > (div.cm-hero__titles > the
 *     parts above), div.cm-hero__end > buttons
 *   then div.cm-hero-body.cm-hero__wrap[--narrow|--mid|--list] > the page's
 *   cards
 * Widths: --narrow (480px, centered: the forms), --mid (720px, centered: the
 * records request flow's pages), the default (1040px, left aligned: start
 * and results), --list (1184px: the signed-in list). --short trims the
 * padding (results, the list). Under 600px every band is left aligned, with
 * a 27px title and 16px gutters. __check: a teal-300 disc with a navy check
 * over a confirmation's title.
 * Customer only: portal.css and request.css import it, staff.css does not.
 */

.cm-hero {
  padding: 52px 0 104px;
  background: var(--cm-hero-glow), var(--cm-hero-bg);
  color: var(--cm-hero-text);
}

.cm-hero--short {
  padding: 36px 0 88px;
}

/* The band's column and the body's: one width, centered in the window,
   with a gutter on each side. */
.cm-hero__wrap {
  box-sizing: border-box;
  width: 100%;
  max-width: calc(1040px + 2 * var(--cm-space-6));
  margin-inline: auto;
  padding-inline: var(--cm-space-6);
}

.cm-hero__wrap--narrow {
  max-width: calc(480px + 2 * var(--cm-space-6));
}

.cm-hero__wrap--mid {
  max-width: calc(720px + 2 * var(--cm-space-6));
}

.cm-hero__wrap--list {
  max-width: calc(1184px + 2 * var(--cm-space-6));
}

/* The lines keep their own widths (a back link is only as wide as its
   text), at the start of a default band and centered in a narrow one. */
.cm-hero > .cm-hero__wrap,
.cm-hero__titles {
  display: grid;
  justify-items: start;
  gap: 10px;
}

/* A narrow or mid band (a form, the request flow) centers its lines. */
.cm-hero > .cm-hero__wrap--narrow,
.cm-hero > .cm-hero__wrap--mid {
  justify-items: center;
  text-align: center;
}

/* The titles at the start, the page's actions at the end, level with the
   last line. */
.cm-hero__row {
  justify-self: stretch;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--cm-space-4);
}

.cm-hero__end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cm-space-2);
}

.cm-hero__title {
  margin: 0;
  padding: 0;
  color: var(--cm-hero-title);
  font-size: var(--cm-hero-title-size);
  font-weight: var(--cm-fw-semibold);
  line-height: 1.15;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.cm-hero--short .cm-hero__title {
  font-size: var(--cm-hero-title-size-short);
}

.cm-hero__text {
  max-width: 62ch;
  margin: 0;
  padding: 0;
  color: var(--cm-hero-text);
  font-size: var(--cm-text-lg);
}

.cm-hero--short .cm-hero__text {
  font-size: var(--cm-text-base);
}

.cm-hero__wrap--narrow .cm-hero__text,
.cm-hero__wrap--mid .cm-hero__text {
  margin-inline: auto;
}

/* "Request submitted": a teal-300 disc with a navy check over the title. */
.cm-hero__check {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin-bottom: var(--cm-space-1);
  border-radius: 50%;
  background: var(--cm-hero-eyebrow);
  color: var(--cm-hero-bg);
  font-size: var(--cm-text-2xl);
}

.cm-hero__eyebrow {
  margin: 0;
  padding: 0;
  color: var(--cm-hero-eyebrow);
  font-size: var(--cm-text-caption);
  font-weight: var(--cm-fw-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* "Back", "Look up another", "Back to sign in": a link above the title, or
   a button drawn as one when it changes the view in place. */
.cm-hero__back {
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-2);
  min-height: 24px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--cm-hero-link);
  font: inherit;
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-medium);
  text-decoration: none;
  cursor: pointer;
}

.cm-hero__back:hover {
  text-decoration: underline;
}

.cm-hero a {
  color: var(--cm-hero-link);
}

/* Focus on the band: a teal-300 ring (12:1 on the navy) instead of the
   page's teal one. */
.cm-hero :is(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--cm-hero-focus);
  outline-offset: 2px;
}

/* The content after the band: its cards sit on the band's lower edge. */
.cm-hero-body {
  position: relative;
  display: grid;
  align-content: start;
  gap: 18px;
  margin-top: -68px;
  padding-bottom: 48px;
}

@media (max-width: 600px) {
  .cm-hero {
    padding: 28px 0 80px;
  }

  .cm-hero--short {
    padding: 24px 0 76px;
  }

  .cm-hero__wrap {
    padding-inline: var(--cm-space-4);
  }

  .cm-hero > .cm-hero__wrap--narrow,
  .cm-hero > .cm-hero__wrap--mid {
    justify-items: start;
    text-align: left;
  }

  .cm-hero__wrap--narrow .cm-hero__text,
  .cm-hero__wrap--mid .cm-hero__text {
    margin-inline: 0;
  }

  .cm-hero__check {
    width: 48px;
    height: 48px;
    font-size: var(--cm-text-xl);
  }

  .cm-hero__title,
  .cm-hero--short .cm-hero__title {
    font-size: var(--cm-hero-title-size-phone);
  }

  .cm-hero__text {
    font-size: var(--cm-text-base);
  }

  .cm-hero-body {
    margin-top: -56px;
    padding-bottom: var(--cm-space-6);
  }
}

}
@layer components {
/*
 * Stepper (CSS phase 6, docs/specs/2026-10-12-css-phase-6-customer-design.md):
 * the request flow's numbered steps. Markup (static in the page):
 *   nav.cm-stepper[aria-label] >
 *     ol.cm-stepper__list > li.cm-stepper__step (--done, --current with
 *       aria-current="step") > span.cm-stepper__dot[aria-hidden]
 *       (span.cm-stepper__num and i.cm-stepper__check: the number, or the
 *       check once the step is done) + span.cm-stepper__label
 *     div.cm-stepper__compact > p.cm-stepper__compact-row
 *       (b.cm-stepper__compact-title "Step 2 of 5: Recipient",
 *       span.cm-stepper__compact-next "Next: Records") and a .cm-progress
 *       (components/progress.css) whose fill width is the share done
 * From 600px up the numbered circles show; under 600px the compact line
 * shows instead. The page renders both and CSS picks one (display: none
 * also keeps the other from assistive tech); setStepperStep()
 * (_shared/components/stepper.js) keeps them in step.
 * A connector runs from each step's circle back to the one before it; it
 * turns the interactive color once that step is reached.
 * The labels and the compact line sit on the page background, where muted
 * text falls under 4.5:1, so they use body text (the current step is
 * heading text and semibold); only the number inside a white circle is muted.
 * --on-dark: the same steps on the portal's dark hero band, one row at every
 * width; --on-dark-wizard: the request flow's wizard on its band, both views
 * (the end of this file).
 */

.cm-stepper {
  box-sizing: border-box;
  width: 100%;
}

/* ---------- The numbered circles (600px and up) ---------- */

.cm-stepper__list {
  display: none;
  grid-auto-columns: minmax(0, 1fr);
  grid-auto-flow: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cm-stepper__step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: var(--cm-text-xs);
  font-weight: var(--cm-fw-medium);
  line-height: var(--cm-lh-tight);
  color: var(--cm-text-body);
  text-align: center;
}

/* The connector, center to center behind the two circles. */
.cm-stepper__step + .cm-stepper__step::before {
  content: '';
  position: absolute;
  top: 14px;
  right: 50%;
  left: -50%;
  height: 2px;
  background: var(--cm-border-strong);
}

.cm-stepper__step--done::before,
.cm-stepper__step--current::before {
  background: var(--cm-interactive);
}

.cm-stepper__dot {
  position: relative;
  z-index: var(--cm-z-raised);
  box-sizing: border-box;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 2px solid var(--cm-border-strong);
  border-radius: 50%;
  background: var(--cm-bg-surface);
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-semibold);
  line-height: 1;
}

.cm-stepper__dot > * {
  color: inherit;
}

.cm-stepper__check {
  display: none;
}

.cm-stepper__step--done .cm-stepper__dot {
  border-color: var(--cm-interactive);
  background: var(--cm-interactive);
  color: var(--cm-text-on-interactive);
}

.cm-stepper__step--done .cm-stepper__num {
  display: none;
}

.cm-stepper__step--done .cm-stepper__check {
  display: inline-block;
}

.cm-stepper__step--current .cm-stepper__dot {
  border-color: var(--cm-interactive);
  color: var(--cm-interactive);
  box-shadow: var(--cm-shadow-selected);
}

.cm-stepper__label {
  max-width: 100%;
  overflow-wrap: anywhere;
}

.cm-stepper__step--done .cm-stepper__label {
  color: var(--cm-text-body);
}

.cm-stepper__step--current .cm-stepper__label {
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-semibold);
}

/* ---------- The compact line (under 600px) ---------- */

.cm-stepper__compact {
  display: grid;
  gap: var(--cm-space-2);
}

.cm-stepper__compact-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--cm-space-1) var(--cm-space-2);
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-sm);
  line-height: var(--cm-lh-snug);
  color: var(--cm-text-body);
  text-align: left;
}

.cm-stepper__compact-title {
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-semibold);
}

.cm-stepper__compact-next {
  color: var(--cm-text-body);
}

@media (min-width: 600px) {
  .cm-stepper__list {
    display: grid;
  }

  .cm-stepper__compact {
    display: none;
  }
}

/* ---------- --on-dark: the steps on the portal's hero band ----------
   One row at every width (circle, then label, a short connector between),
   only the numbered circles (the page renders no compact line). Done is a
   teal-300 disc with a navy check, current a teal-300 ring with a white
   label, pending a slate ring; the check or number and the current step's
   aria-current carry the state, not the color alone. The portal's result
   band (portal refresh, docs/specs/2026-10-12-portal-refresh-design.md). */
.cm-stepper--on-dark .cm-stepper__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cm-space-2);
}

.cm-stepper--on-dark .cm-stepper__compact {
  display: none;
}

.cm-stepper--on-dark .cm-stepper__step {
  flex-direction: row;
  gap: var(--cm-space-2);
  color: var(--cm-hero-step-muted);
  font-size: var(--cm-text-sm);
}

.cm-stepper--on-dark .cm-stepper__step + .cm-stepper__step::before {
  position: static;
  width: 36px;
  margin-right: var(--cm-space-1);
  background: var(--cm-hero-step-ring);
}

.cm-stepper--on-dark .cm-stepper__step--done::before,
.cm-stepper--on-dark .cm-stepper__step--current::before {
  background: var(--cm-hero-eyebrow);
}

.cm-stepper--on-dark .cm-stepper__dot {
  width: 26px;
  height: 26px;
  border-color: var(--cm-hero-step-ring);
  background: transparent;
  color: var(--cm-hero-text);
  font-size: var(--cm-text-xs);
}

.cm-stepper--on-dark .cm-stepper__step--done .cm-stepper__dot {
  border-color: var(--cm-hero-eyebrow);
  background: var(--cm-hero-eyebrow);
  color: var(--cm-hero-bg);
}

.cm-stepper--on-dark .cm-stepper__step--current .cm-stepper__dot {
  border-color: var(--cm-hero-eyebrow);
  box-shadow: none;
  color: var(--cm-hero-eyebrow);
}

.cm-stepper--on-dark .cm-stepper__step--done .cm-stepper__label {
  color: var(--cm-hero-link);
}

.cm-stepper--on-dark .cm-stepper__step--current .cm-stepper__label {
  color: var(--cm-hero-title);
}

@media (max-width: 600px) {
  .cm-stepper--on-dark .cm-stepper__step + .cm-stepper__step::before {
    width: 16px;
  }
}

/* ---------- --on-dark-wizard: the request flow's steps on its band ----------
   The wizard layout above (numbered circles over their labels, a connector
   center to center, from 600px up; the compact line over its bar under
   600px), in the band's colors: done a teal-300 disc with a navy check,
   current a teal-300 ring with a white label, pending a slate ring. The
   compact bar is a .cm-progress--on-dark (components/progress.css). The
   records request flow refresh,
   docs/specs/2026-10-13-request-flow-refresh-design.md section 4. */
.cm-stepper--on-dark-wizard {
  max-width: 640px;
  margin-top: var(--cm-space-2);
}

.cm-stepper--on-dark-wizard .cm-stepper__step {
  gap: var(--cm-space-2);
  color: var(--cm-hero-step-muted);
  font-size: var(--cm-text-sm);
}

/* The connector runs through the middle of the 28px circles, which hide it
   behind them with the band's navy. */
.cm-stepper--on-dark-wizard .cm-stepper__step + .cm-stepper__step::before {
  top: 13px;
  background: var(--cm-hero-step-ring);
}

.cm-stepper--on-dark-wizard .cm-stepper__step--done::before,
.cm-stepper--on-dark-wizard .cm-stepper__step--current::before {
  background: var(--cm-hero-eyebrow);
}

.cm-stepper--on-dark-wizard .cm-stepper__dot {
  width: 28px;
  height: 28px;
  border-color: var(--cm-hero-step-ring);
  background: var(--cm-hero-bg);
  color: var(--cm-hero-text);
  font-size: var(--cm-text-caption);
}

.cm-stepper--on-dark-wizard .cm-stepper__step--done .cm-stepper__dot {
  border-color: var(--cm-hero-eyebrow);
  background: var(--cm-hero-eyebrow);
  color: var(--cm-hero-bg);
}

.cm-stepper--on-dark-wizard .cm-stepper__step--current .cm-stepper__dot {
  border-color: var(--cm-hero-eyebrow);
  box-shadow: none;
  color: var(--cm-hero-eyebrow);
}

.cm-stepper--on-dark-wizard .cm-stepper__step--done .cm-stepper__label {
  color: var(--cm-hero-link);
}

.cm-stepper--on-dark-wizard .cm-stepper__step--current .cm-stepper__label {
  color: var(--cm-hero-title);
}

.cm-stepper--on-dark-wizard .cm-stepper__compact-row,
.cm-stepper--on-dark-wizard .cm-stepper__compact-next {
  color: var(--cm-hero-text);
}

.cm-stepper--on-dark-wizard .cm-stepper__compact-title {
  color: var(--cm-hero-title);
}

}
@layer components {
/*
 * Skeleton (portal refresh, docs/specs/2026-10-12-portal-refresh-design.md
 * section 6): a placeholder bar in the shape of content still loading, a
 * lighter band sweeping across it. It holds still when the reader turns
 * motion off. Placeholders are decoration: the page says what is loading in
 * a role="status" line, and the placeholders' container is aria-hidden.
 * Markup: span.cm-skeleton (a 14px text line, full width) with
 *   --title (a band title line), --block (a 76px box: a total), --button
 *   (a button's height), --pill (a status pill), --on-dark (on the hero
 *   band), and a width: --w30, --w45, --w60, --w80.
 * Customer only: portal.css imports it, staff.css does not.
 */

.cm-skeleton {
  display: block;
  width: 100%;
  height: 14px;
  border-radius: var(--cm-radius-pill);
  background: linear-gradient(
    90deg,
    var(--cm-skeleton) 0%,
    var(--cm-skeleton-shine) 50%,
    var(--cm-skeleton) 100%
  );
  background-size: 200% 100%;
  animation: cm-skeleton-sweep 1.4s ease-in-out infinite;
}

.cm-skeleton--on-dark {
  background-image: linear-gradient(
    90deg,
    var(--cm-skeleton-on-dark) 0%,
    var(--cm-skeleton-on-dark-shine) 50%,
    var(--cm-skeleton-on-dark) 100%
  );
}

.cm-skeleton--title {
  max-width: 360px;
  height: 34px;
  border-radius: var(--cm-radius-lg);
}

.cm-skeleton--block {
  height: 76px;
  border-radius: var(--cm-radius-xl);
}

.cm-skeleton--button {
  height: var(--cm-button-height);
  border-radius: var(--cm-button-radius);
}

.cm-skeleton--pill {
  width: 110px;
  height: var(--cm-pill-height);
}

.cm-skeleton--w30 {
  width: 30%;
}

.cm-skeleton--w45 {
  width: 45%;
}

.cm-skeleton--w60 {
  width: 60%;
}

.cm-skeleton--w80 {
  width: 80%;
}

@keyframes cm-skeleton-sweep {
  from {
    background-position: 100% 0;
  }

  to {
    background-position: -100% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cm-skeleton {
    animation: none;
  }
}

}

@layer utilities {
/*
 * Utilities (CSS consolidation phase 5): the reviewed set of single-purpose
 * classes, in layer utilities (above components, below pages), so none
 * needs !important to win over a component. Spec:
 * docs/specs/2026-10-11-css-phase-5-design.md
 */

/* Show and hide go through the hidden attribute (el.hidden). Without
   !important a component's own display (a flex popup, a grid card) would
   beat the user agent's [hidden] rule and the element would still show. */
[hidden] {
  display: none !important;
}

/* Flex alignment. */
.jc-space-evenly {
  justify-content: space-evenly;
}
.jc-space-between {
  justify-content: space-between;
}
.jc-space-around {
  justify-content: space-around;
}
.jc-center {
  justify-content: center;
}
.jc-start {
  justify-content: flex-start;
}
.jc-end {
  justify-content: flex-end;
}
.align-center {
  align-items: center;
}
.align-start {
  align-items: flex-start;
}
.align-end {
  align-items: flex-end;
}
.align-self-center {
  align-self: center;
}
.cursor-pointer {
  cursor: pointer;
}
.align-self-start {
  align-self: flex-start;
}
.align-stretch {
  align-items: stretch;
}
/* Takes the free space of a flex column and may shrink under its content
   (a PDF viewer pane filling a tall popup body). */
.flex-fill {
  flex: 1 1 0;
  min-height: 0;
}
.flex-wrap {
  flex-wrap: wrap;
}

/* Sizes. */
.width-100 {
  width: 100%;
}
.width-50 {
  width: 50%;
}
.width-auto {
  width: auto;
}
.max-width-100 {
  max-width: 100%;
}
.max-width-95 {
  max-width: 95%;
}
.height-100 {
  height: 100%;
}
.max-height-100 {
  max-height: 100%;
}

/* Spacing. */
.pd-medium {
  padding: 5px;
}
.pd-large {
  padding: 10px;
}
.pd-top-xlarge {
  padding-top: 20px;
}
.pd-bottom-large {
  padding-bottom: 10px;
}
.pd-bottom-xlarge {
  padding-bottom: 20px;
}
.mg-none {
  margin: 0;
}
.mg-medium {
  margin: 5px;
}
.mg-large {
  margin: 10px;
}
.mg-xlarge {
  margin: 20px;
}
.mg-top-large {
  margin-top: 10px;
}
.mg-bottom-medium {
  margin-bottom: 5px;
}
.mg-bottom-large {
  margin-bottom: 10px;
}
.gap-medium {
  gap: 5px;
}
.gap-large {
  gap: 10px;
}
.gap-xlarge {
  gap: 20px;
}

/* Overflow. */
.overflow-auto {
  overflow: auto;
}
.overflow-y-auto {
  overflow-y: auto;
}
.overflow-x-auto {
  overflow-x: auto;
}

/* Read by screen readers, not drawn. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Muted secondary/meta copy (timestamps, captions) (moved from stylesheetv3.css in CSS phase 5). --cm-text-muted already
   re-resolves through the redefined :root.dark gray scale, so no separate
   dark-mode override is needed here, see tokens.css. */
.secondary-text {
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

}

@layer pages {
/*
 * Customer portal page layout (CSS phase 6,
 * docs/specs/2026-10-12-css-phase-6-customer-design.md, and the portal
 * refresh, docs/specs/2026-10-12-portal-refresh-design.md): the customer
 * sizing, the page shell (the app bar site-header.js renders, the main
 * column, the footer's placement), the wait screen, and what the portal's
 * pages arrange around the staff components (cards, fields, buttons, the
 * hero band, the browse page parts), imported by portal.css into
 * layer(pages). Looks come from base.css and the components; this file
 * places them, plus the few parts only the portal has (the app bar, the
 * payment-mode picker, the sign-in steps, the QR frame).
 */

/* ---------- Customer sizing ----------
   The tokens the components read (tokens.css), set for every portal page:
   44px fields and buttons, 10px field and button corners, 16px cards with a
   soft lift instead of a border, sentence case 14px field labels, 28px
   pills. The request flow sets the same tokens to the same values
   (pages/request.css; change both together); staff pages keep the
   defaults. */
:root {
  --cm-control-height: 44px;
  --cm-button-height: 44px;
  --cm-control-radius: 10px;
  --cm-button-radius: 10px;
  --cm-button-font-size: 0.9375rem; /* 15px */
  --cm-button-font-weight: var(--cm-fw-semibold);
  --cm-button-padding-x: var(--cm-space-5);
  --cm-field-gap: 6px;
  --cm-field-label-size: var(--cm-text-sm);
  --cm-field-label-color: var(--cm-text-heading);
  --cm-field-label-case: none;
  --cm-field-label-tracking: normal;
  --cm-card-radius: 16px;
  --cm-card-border: transparent;
  --cm-card-shadow: var(--cm-shadow-card-customer);
  --cm-banner-radius: 12px;
  --cm-pill-height: 28px;
  --cm-pill-font-size: var(--cm-text-caption);
  --cm-pill-padding-x: var(--cm-space-3);
  --cm-shadow-invalid: var(--cm-shadow-invalid-customer);
  /* The page behind the cards: the mockup's slate-50. */
  --cm-bg-body: var(--cm-gray-50);
}

/* 16px field text at every width (iOS Safari zooms in on a field whose text
   is under 16px when it is tapped). */
:is(input:not([type='checkbox'], [type='radio'], [type='file']), select, textarea) {
  font-size: var(--cm-text-base);
}

/* A one-time code field: 56px tall, its digits 24px and spaced
   (the sign-in steps' verification code). */
input.portal-code {
  --cm-control-height: 56px;
  font-size: var(--cm-text-2xl);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.4em;
  text-align: center;
}

/* ---------- Page shell ---------- */

/* Header, main and footer stack in a column at least the window's height;
   the main grows into the spare height, so the footer sits at the bottom
   of a short page. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* The main column: each page's hero band and the cards on it, full width
   (components/hero.css sets the columns), with room above the footer. */
.portal-main {
  flex: 1 0 auto;
  padding-bottom: var(--cm-space-10);
}

/* ---------- The app bar ----------
   site-header.js renders it into #site-header: the logo, the site's links
   and, signed in, the organization and the account menu. Under 600px the
   links fold into a menu the bar's menu button opens (data-nav-open). */
.portal-bar {
  position: relative;
  z-index: var(--cm-z-float);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: var(--cm-space-5);
  min-height: 68px;
  padding: var(--cm-space-3) 40px;
  border-bottom: 1px solid var(--cm-gray-200);
  background: var(--cm-bg-surface);
}

.portal-bar__logo {
  display: inline-flex;
  flex: 0 0 auto;
}

.portal-bar__logo img {
  display: block;
  width: auto;
  height: 28px;
}

/* The signed-in organization, after a divider. */
.portal-bar__org {
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-2);
  padding-left: var(--cm-space-5);
  border-left: 1px solid var(--cm-gray-200);
  color: var(--cm-text-heading);
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-semibold);
  white-space: nowrap;
}

.portal-bar__org i {
  color: var(--cm-gray-500);
}

.portal-bar__nav {
  display: flex;
  align-items: center;
  gap: 22px;
  margin-left: auto;
}

.portal-bar--app .portal-bar__nav {
  margin-left: var(--cm-space-2);
}

.portal-bar__link {
  color: var(--cm-gray-700);
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-medium);
  text-decoration: none;
}

.portal-bar__link:hover {
  text-decoration: underline;
}

.portal-bar__link[aria-current='page'] {
  color: var(--cm-accent-800);
}

/* The menu button: under 600px only. */
.portal-bar__menu-button {
  display: none;
  margin-left: auto;
}

/* The account menu's trigger: the user's name, the initials disc and a
   chevron; the menu hangs under its right edge. */
.portal-bar__account {
  position: relative;
  margin-left: auto;
}

.portal-bar__account-button {
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-2);
  min-height: 44px;
  margin: 0;
  padding: 0 var(--cm-space-2);
  border: 0;
  border-radius: var(--cm-button-radius);
  background: transparent;
  color: var(--cm-gray-700);
  font: inherit;
  font-size: var(--cm-text-sm);
  cursor: pointer;
}

.portal-bar__account-button:hover {
  background: var(--cm-gray-100);
}

.portal-bar__chevron {
  font-size: var(--cm-text-xs);
}

@media (max-width: 600px) {
  .portal-bar {
    min-height: 60px;
    padding: var(--cm-space-2) var(--cm-space-4);
  }

  .portal-bar__menu-button {
    display: inline-flex;
  }

  .portal-bar__logo img {
    height: 24px;
  }

  .portal-bar__org,
  .portal-bar__name,
  .portal-bar__chevron,
  .portal-bar--app .portal-bar__nav {
    display: none;
  }

  /* The links fold into a panel under the bar, shown while the menu button
     holds it open. */
  .portal-bar__nav {
    position: absolute;
    top: 100%;
    right: 0;
    left: 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--cm-space-2) var(--cm-space-4) var(--cm-space-4);
    border-bottom: 1px solid var(--cm-gray-200);
    background: var(--cm-bg-surface);
    box-shadow: var(--cm-shadow-md);
  }

  .portal-bar[data-nav-open] .portal-bar__nav {
    display: flex;
  }

  .portal-bar__link {
    display: flex;
    align-items: center;
    min-height: 44px;
  }

  .portal-bar__signin {
    margin-top: var(--cm-space-2);
  }
}

/* A page's views (index.html's start, lookups and result; login.html's
   steps): each its own band and cards, one shown at a time. */
.portal-view {
  display: block;
}

/* ---------- The wait screen ----------
   #loaderBody, shown through its hidden attribute while a file downloads
   (the lookup page) or a request runs (the other pages): a
   white wash over the first screen, three accent rings turning, "Please
   wait" over them and the current step's message under them. */
.portal-loader {
  position: absolute;
  z-index: var(--cm-z-customer-loader);
  width: 100%;
  height: 100%;
  background-image: radial-gradient(
    circle farthest-corner at center,
    var(--cm-gray-0) 0%,
    var(--cm-loader-wash-edge) 100%
  );
  opacity: 0.8;
}

.portal-loader__spinner {
  position: absolute;
  top: calc(50% - 105px);
  left: calc(50% - 32px);
  z-index: var(--cm-z-customer-loader);
  width: 64px;
  height: 64px;
  border-radius: 50%;
  perspective: 800px;
}

.portal-loader__ring {
  position: absolute;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

/* The arcs step dark to bright through the accent ramp. */
.portal-loader__ring--one {
  top: 0%;
  left: 0%;
  border-bottom: 5px solid var(--cm-accent-900);
  animation: portal-loader-one 1s linear infinite;
}

.portal-loader__ring--two {
  top: 0%;
  right: 0%;
  border-right: 5px solid var(--cm-accent-700);
  animation: portal-loader-two 1s linear infinite;
}

.portal-loader__ring--three {
  right: 0%;
  bottom: 0%;
  border-top: 5px solid var(--cm-accent-500);
  animation: portal-loader-three 1s linear infinite;
}

.portal-loader__wait,
.portal-loader__message {
  position: absolute;
  left: 50%;
  z-index: var(--cm-z-overlay);
  font-size: var(--cm-text-2xl);
  text-align: center;
  transform: translate(-50%, -50%);
}

.portal-loader__wait {
  top: calc(50% - 128px);
}

.portal-loader__message {
  top: calc(50% - 8px);
}

@keyframes portal-loader-one {
  0% {
    transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
  }

  100% {
    transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
  }
}

@keyframes portal-loader-two {
  0% {
    transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
  }

  100% {
    transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
  }
}

@keyframes portal-loader-three {
  0% {
    transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
  }

  100% {
    transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
  }
}

/* ---------- One-card pages (the lookup forms, the sign-in pages) ---------- */

/* A page's card on the band's edge: one column at the band's width, its
   parts 20px apart. */
.portal-card {
  display: grid;
  gap: var(--cm-space-5);
  width: 100%;
  padding: var(--cm-space-8);
}

/* A form's fields, one column. */
.portal-form {
  display: grid;
  gap: var(--cm-space-4);
}

/* A field's help bubble (its "?" icon, .portal-help) spans the field
   (.portal-help-field) instead of centering on the icon, so it stays
   inside the card on a 320px phone (WCAG reflow): the field is the
   bubble's containing block. */
.portal-help-field {
  position: relative;
}

.portal-help {
  position: static;
}

.portal-help::after {
  left: 0;
  right: 0;
  width: auto;
  min-width: 0;
  max-width: none;
  transform: none;
}

/* An accent icon on a soft tile: 40px (the start page's strip), 56px
   (--lg, the action cards). */
.portal-icon {
  display: inline-grid;
  flex: 0 0 auto;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--cm-radius-xl);
  background: var(--cm-accent-50);
  color: var(--cm-accent-700);
  font-size: var(--cm-text-base);
}

.portal-icon--lg {
  width: 56px;
  height: 56px;
  font-size: var(--cm-text-2xl);
}

/* ---------- Start: Pay and Download, then the strip ---------- */

/* The two action cards side by side, one column on a phone. */
.portal-start {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--cm-space-5);
}

/* An action card: its icon, title, a line of explanation and its button,
   all at the start. */
.portal-action {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: var(--cm-space-3);
  padding: 28px;
}

.portal-action__title {
  margin: 0;
  padding: 0;
  color: var(--cm-text-heading);
  font-size: var(--cm-text-xl);
  font-weight: var(--cm-fw-semibold);
  line-height: var(--cm-lh-tight);
}

.portal-action__text {
  margin: 0;
  padding: 0;
  color: var(--cm-text-muted);
}

/* "Have an account? ... Sign in": a quiet strip under the cards. */
.portal-strip {
  display: flex;
  align-items: center;
  gap: var(--cm-space-4);
  padding: var(--cm-space-4) var(--cm-space-5);
  border: 1px solid var(--cm-gray-200);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-bg-surface);
}

.portal-strip__text {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  padding: 0;
  color: var(--cm-text-body);
}

.portal-strip__text b {
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-semibold);
}

/* ---------- Pay: the payment-mode switch ----------
   Two radio options on a gray track (Automate-tlyq), the checked one raised
   on white with a slate edge (--cm-shadow-switch-selected) and accent text.
   The radio inside each label is visually hidden but stays focusable and
   announced; keyboard focus draws a ring around its option (WCAG 2.4.7). */
.segmented-control {
  box-sizing: border-box;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--cm-space-1);
  width: 100%;
  padding: var(--cm-space-1);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-gray-100);
}

.segmented-control__option {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: var(--cm-space-1) var(--cm-space-2);
  border-radius: var(--cm-button-radius);
  color: var(--cm-gray-700);
  font-size: var(--cm-button-font-size);
  font-weight: var(--cm-fw-medium);
  line-height: var(--cm-lh-snug);
  text-align: center;
  cursor: pointer;
  user-select: none;
  transition:
    background-color 120ms ease,
    color 120ms ease,
    box-shadow 120ms ease;
}

.segmented-control__option:hover {
  color: var(--cm-text-heading);
}

.segmented-control__option:has(input[type='radio']:checked) {
  background: var(--cm-bg-surface);
  box-shadow: var(--cm-shadow-switch-selected);
  color: var(--cm-accent-800);
}

.segmented-control__option:has(input[type='radio']:focus-visible) {
  outline: 2px solid var(--cm-teal-500);
  outline-offset: 2px;
}

.segmented-control__option > input[type='radio'] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Sign in ---------- */

/* A field label with a link at the row's end (Password, Forgot password?). */
.portal-label-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-1) var(--cm-space-3);
}

.portal-label-row__link {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  font-size: var(--cm-text-sm);
}

/* The two-factor QR code in a quiet gray frame with its caption, the code
   itself on white so it scans. */
.qr-frame {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 18px;
  border-radius: var(--cm-radius-xl);
  background: var(--cm-gray-50);
}

.qr-frame #qrEnrollmentBarcode {
  display: inline-flex;
  border-radius: var(--cm-radius-sm);
  background: var(--cm-bg-surface);
}

.qr-frame figcaption {
  color: var(--cm-text-muted);
  font-size: var(--cm-text-caption);
  text-align: center;
}

/* Forgot password: the support address, the focus of the card, in a box
   with its Copy button. */
.portal-mail {
  display: grid;
  justify-items: center;
  gap: var(--cm-space-3);
  text-align: center;
}

.portal-mail__text {
  margin: 0;
  padding: 0;
}

.portal-copy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--cm-space-2) var(--cm-space-3);
  max-width: 100%;
  padding: 10px 14px;
  border: 1px solid var(--cm-gray-200);
  border-radius: var(--cm-control-radius);
  background: var(--cm-gray-50);
}

.portal-copy__address {
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-semibold);
  overflow-wrap: anywhere;
}

/* ---------- A lookup running ---------- */

/* The placeholder subtitle in the band, under the title's. */
.portal-loading__subtitle {
  max-width: 300px;
}

/* "Looking up your request…" under the placeholder cards. */
.portal-loading {
  margin: 0;
  padding: 0;
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  text-align: center;
}

/* ---------- The invoice result ---------- */

/* The invoice card, and Pay by card beside it while something is due:
   side by side from 960px, stacked under it below; the invoice alone (paid,
   nothing owed) keeps a 640px column. */
.portal-result {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: var(--cm-space-6);
  width: 100%;
  max-width: 640px;
}

@media (min-width: 960px) {
  .portal-result--split,
  .portal-result:has(> #paymentContainer:not([hidden])) {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    max-width: none;
  }
}

/* The invoice, receipt style: a title and status pill, the total box, the
   reference and pages, the notices, then the downloads under a divider. */
.portal-receipt,
.portal-pay {
  display: grid;
  align-content: start;
  gap: var(--cm-space-5);
  padding: 28px;
}

.portal-pay {
  gap: var(--cm-space-4);
}

.portal-receipt__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
}

.portal-receipt__title,
.portal-pay__title {
  margin: 0;
  padding: 0;
  color: var(--cm-text-heading);
  font-size: var(--cm-text-xl);
  font-weight: var(--cm-fw-semibold);
  line-height: var(--cm-lh-tight);
}

/* A total box: its label, the amount large, and the parts under it (the
   amount due and the convenience fee). The fee acknowledgment dialog shows
   one too, --compact. */
.portal-total {
  display: grid;
  gap: 2px;
  padding: 18px var(--cm-space-5);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-gray-50);
}

.portal-total__label {
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

.portal-total__value {
  color: var(--cm-text-heading);
  font-size: var(--cm-text-total);
  font-weight: var(--cm-fw-semibold);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* In the dialog: centered at the width of its message (popup.css's prompt
   text), the amount a size down. */
.portal-total--compact {
  box-sizing: border-box;
  max-width: 400px;
  margin-inline: auto;
  padding: 14px var(--cm-space-4);
}

.portal-total--compact .portal-total__value {
  font-size: var(--cm-text-3xl);
}

.portal-total__lines {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cm-space-1) var(--cm-space-5);
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
  font-variant-numeric: tabular-nums;
}

.portal-total__lines b {
  color: var(--cm-text-body);
  font-weight: var(--cm-fw-medium);
}

/* Your reference and Pages: two columns of a small label over its value. */
.portal-meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--cm-space-3) var(--cm-space-6);
  margin: 0;
}

.portal-meta dt {
  color: var(--cm-text-muted);
  font-size: var(--cm-text-caption);
}

.portal-meta dd {
  margin: 0;
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-medium);
  overflow-wrap: anywhere;
}

/* Download records, full width, once the records are free to download. */
.portal-receipt__records {
  display: grid;
}

/* The affidavit note over the downloads, under a divider. */
.portal-receipt__foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--cm-space-3);
  padding-top: 18px;
  border-top: 1px solid var(--cm-gray-200);
}

.portal-receipt__note {
  margin: 0;
  padding: 0;
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

.portal-receipt__downloads {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cm-space-2) var(--cm-space-3);
}

/* An imaging part's label ("Download part 1 of 3 (1.0 GB)") is longer than the
   card at 320px: it wraps there instead of pushing the page wider. */
.portal-receipt__downloads .portal-receipt__download {
  height: auto;
  min-height: var(--cm-button-height);
  padding-block: var(--cm-space-2);
  white-space: normal;
  line-height: 1.25;
}

/* "Confirming payment" under the pay button; while empty it takes back
   the card's gap, so the card does not grow. */
.portal-pay__status {
  margin: 0;
  padding: 0;
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  text-align: center;
}

.portal-pay__status:empty {
  margin-top: calc(var(--cm-space-4) * -1);
}

@media (max-width: 600px) {
  .portal-start,
  .portal-result {
    gap: 14px;
  }

  .portal-start {
    grid-template-columns: minmax(0, 1fr);
  }

  .portal-card,
  .portal-action,
  .portal-receipt,
  .portal-pay {
    padding: var(--cm-space-5);
  }

  .portal-total__value {
    font-size: var(--cm-text-total-phone);
  }

  .segmented-control__option {
    font-size: var(--cm-text-sm);
  }
}

/* The label and value rows of the signed-in list's side panel. */
.portal-details {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--cm-space-2) var(--cm-space-5);
  margin: 0;
  font-size: var(--cm-text-sm);
}

.portal-details dt {
  color: var(--cm-text-muted);
}

.portal-details dd {
  margin: 0;
  color: var(--cm-text-body);
  overflow-wrap: anywhere;
}

/* ---------- Signed-in pages ---------- */

/* The browse page: the search bar and the results share the band's column
   (staff layout.css .page-column, which the portal does not load;
   search-bar.css sizes its card in it). */
.page-column {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  row-gap: var(--cm-space-4);
  width: 100%;
}

.portal-app__count {
  margin: 0;
  padding: 0;
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  text-align: center;
}

/* The staff pager strip and popup overlays leave room for the staff nav
   rail on their left; the portal has none. */
:root {
  --sidebar-width: 0px;
}

.pagination-mount > .navigation-div {
  left: 0;
}

}
@layer pages {
/*
 * The portal's signed-in list (public/portal/portal/app.html; portal
 * refresh, docs/specs/2026-10-12-portal-refresh-design.md section 11): the
 * tiles on the band's edge, the search box and the filter chips, the
 * results card with its pager, and the request side panel. Looks come from
 * the components (cards, buttons, the table, pills, menus, the drawer);
 * this file places them. portal.css imports it into layer(pages) after
 * pages/portal.css. Desktop only (business users), so no phone layout.
 */

/* ---------- The tiles: the organization's counts, each a filter ---------- */

.portal-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--cm-space-4);
}

/* A whole-card button (.cm-card--link): the icon over two rows, the figure
   over its label. The pressed tile is the card's --selected. */
.portal-tile {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 14px;
  row-gap: 2px;
  width: 100%;
  margin: 0;
  padding: 18px var(--cm-space-5);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* The soft square behind a tile's icon (also the empty state's). */
.portal-tile__icon {
  display: grid;
  grid-row: span 2;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--cm-radius-xl);
  background: var(--cm-bg-accent-soft);
  color: var(--cm-accent-text);
  font-size: var(--cm-text-lg);
}

.portal-tile__icon--due {
  background: var(--cm-bg-warning-soft);
  color: var(--cm-warning-text);
}

.portal-tile__icon--done {
  background: var(--cm-bg-muted);
  color: var(--cm-text-body);
}

.portal-tile__value {
  color: var(--cm-text-heading);
  font-size: var(--cm-text-2xl);
  font-weight: var(--cm-fw-semibold);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.portal-tile__label {
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

/* ---------- The search box and the filter chips ---------- */

.portal-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.portal-search {
  position: relative;
  flex: 0 1 420px;
  min-width: 240px;
}

.portal-search__icon {
  position: absolute;
  top: 50%;
  left: 14px;
  color: var(--cm-text-muted);
  transform: translateY(-50%);
  pointer-events: none;
}

/* Room for the magnifier inside the field: the one place this site sets a
   field's padding (the field's look is base.css's). */
.portal-search__input {
  width: 100%;
  padding-inline-start: 40px;
}

/* A chip: a pill button that opens its panel under it. data-active marks
   a chip whose filter is set (Status always is). */
.portal-chip {
  position: relative;
}

.portal-chip__button {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-2);
  min-height: 36px;
  margin: 0;
  padding: 0 14px;
  border: 1px solid var(--cm-border-strong);
  border-radius: var(--cm-radius-pill);
  background: var(--cm-bg-surface);
  color: var(--cm-text-body);
  font: inherit;
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-medium);
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color 120ms ease,
    border-color 120ms ease;
}

.portal-chip__button:hover {
  border-color: var(--cm-interactive);
}

.portal-chip__button:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

.portal-chip__button[data-active] {
  border-color: var(--cm-chip-selected-border);
  background: var(--cm-chip-selected-bg);
  color: var(--cm-accent-text);
}

.portal-chip__chevron {
  font-size: var(--cm-text-xs);
}

/* The chip's panel (a .cm-menu card) opens under the chip's start. */
.portal-chip__panel {
  left: 0;
  right: auto;
  min-width: 220px;
}

/* The Date of birth panel holds a field rather than choices. */
.portal-chip__panel--field {
  padding: var(--cm-space-3);
}

.portal-tools__clear {
  margin-left: var(--cm-space-1);
}

/* ---------- The results card ---------- */

.portal-results {
  overflow: hidden;
}

/* A row's request number: a button that reads as the cell's main line. */
.portal-results__open {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--cm-text-heading);
  font: inherit;
  font-weight: var(--cm-fw-medium);
  text-align: left;
  cursor: pointer;
}

.portal-results__open:hover {
  text-decoration: underline;
}

.portal-results__open:focus-visible {
  outline: 2px solid var(--cm-interactive);
  outline-offset: 2px;
  border-radius: var(--cm-radius-sm);
}

/* A cell's main line over its __sub line (the patient over the DOB). */
.portal-results__main {
  display: block;
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-medium);
}

/* The row whose side panel is open: the lightest teal, so the muted DOB
   and reference lines keep 4.5:1 (the table's own selected wash is darker),
   and the table's selected marker on its first cell. */
.portal-results__row--open > td {
  background: var(--cm-accent-50);
}

.portal-results__row--open > td:first-child {
  box-shadow: var(--cm-table-marker-selected);
}

/* The chevron column: narrow, at the row's end. */
.portal-results__go {
  width: 1%;
  color: var(--cm-text-muted);
  text-align: right;
}

/* Nothing matches: the icon, the title, today's line, Clear filters. */
.portal-results__empty {
  display: grid;
  justify-items: center;
  gap: 10px;
  padding: 56px var(--cm-space-6);
  text-align: center;
}

.portal-results__empty-icon {
  grid-row: auto;
  width: 56px;
  height: 56px;
  font-size: var(--cm-text-2xl);
}

.portal-results__empty-title {
  margin: 0;
  color: var(--cm-text-heading);
  font-size: var(--cm-text-lg);
}

.portal-results__empty-text {
  margin: 0;
  padding: 0;
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

/* The caption at the start, the staff pager strip (pagination.css, built by
   PageNavigation) at the end, in the card's last row instead of a pill
   pinned to the window's bottom. */
.portal-results__pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
  padding: 10px var(--cm-space-4);
  border-top: 1px solid var(--cm-border);
}

.portal-results__count {
  margin: 0;
  padding: 0;
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

.portal-results__pager .navigation-div {
  position: static;
  gap: var(--cm-space-2);
  width: auto;
  height: auto;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}

.portal-results__pager .navigation-div__side {
  width: auto;
}

.portal-results__pager .display-results-div {
  padding: 0;
}

.portal-results__pager .navigation-div p {
  width: auto;
  padding: 0 var(--cm-space-2);
}

/* The previous and next carets as square buttons. */
.portal-results__pager .navigation-div__caret {
  box-sizing: border-box;
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-md);
  font-size: var(--cm-text-base);
}

/* ---------- The request side panel ---------- */

/* The drawer (components/drawer.css --right) as a full-height side sheet,
   over the app bar too (the bar scrolls away, so a panel under it would
   leave a gap at the top), shown and hidden through its hidden attribute. */
.portal-panel {
  display: flex;
  top: 0;
  bottom: 0;
  width: min(400px, 100vw);
  max-height: none;
  border-left: 1px solid var(--cm-border);
  border-radius: 0;
}

.portal-panel__header {
  align-items: flex-start;
  padding: var(--cm-space-6) var(--cm-space-6) var(--cm-space-2);
  border-bottom: 0;
}

.portal-panel__titles {
  display: grid;
  gap: var(--cm-space-1);
  min-width: 0;
}

.portal-panel__eyebrow {
  margin: 0;
  padding: 0;
  color: var(--cm-accent-text);
  font-size: var(--cm-text-caption);
  font-weight: var(--cm-fw-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.portal-panel__title {
  font-size: var(--cm-text-xl);
}

.portal-panel__dob {
  margin: 0;
  padding: 0;
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

.portal-panel__body {
  display: grid;
  align-content: start;
  gap: 18px;
  padding-top: var(--cm-space-3);
}

.portal-panel__status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
}

.portal-panel__due {
  color: var(--cm-text-heading);
  font-size: var(--cm-text-2xl);
  font-weight: var(--cm-fw-semibold);
  font-variant-numeric: tabular-nums;
}

/* The downloads share a row (two fit at the panel's width with a slimmer
   button side padding), and wrap when a third comes. */
.portal-panel__downloads {
  --cm-button-padding-x: var(--cm-space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--cm-space-2);
}

.portal-panel__downloads > * {
  flex: 1 1 auto;
}

/* The records note while an owed invoice holds them back. */
.portal-panel__note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0;
  padding: var(--cm-space-3) 14px;
  border-radius: var(--cm-radius-xl);
  background: var(--cm-bg-body);
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
}

.portal-panel__note > i {
  margin-top: 3px;
  color: var(--cm-text-muted);
}

}
