/*
 * Entry stylesheet for the request flow (public/request/), 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/request.css. The footer, challenge, stepper
 * and hero components are customer only (the hero band is the request flow
 * refresh's, docs/specs/2026-10-13-request-flow-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)
 * 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);
}

/* 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 {
/*
 * 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.
 * 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);
}

}
@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;
}

}
@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 {
/*
 * File drop zone (CSS consolidation phase 4, forms PR 3). Spec:
 * docs/specs/2026-10-05-css-phase-4-forms-design.md
 * Markup (buildDropZone() in common/drop-zone.js, or static HTML):
 *   div.cm-drop-zone__group >
 *     label.cm-drop-zone > input.cm-drop-zone__input[type=file],
 *       i.cm-drop-zone__icon, span.cm-drop-zone__text > span.cm-drop-zone__browse,
 *       span.cm-drop-zone__hint
 *     p.cm-drop-zone__count[role=status]
 *     ul.cm-drop-zone__files > li.cm-drop-zone__file.cm-tag.cm-tag--removable[data-state] >
 *       span.cm-drop-zone__file-name, span.cm-drop-zone__file-status,
 *       button.cm-drop-zone__file-remove.cm-tag__remove
 *   or, with options inside the frame (buildDropZone's footer):
 *     div.cm-drop-zone.cm-drop-zone--options >
 *       label.cm-drop-zone__target (the input, icon, text and hint above),
 *       div.cm-drop-zone__footer > label.cm-field.cm-field--check.cm-drop-zone__option
 * buildDropZone() appends the label, count and list into a parent that
 * carries .cm-drop-zone__group (the caller's element). Static markup must
 * match buildDropZone()'s structure, ids and ARIA: the input's
 * aria-labelledby names the __text span, its aria-describedby lists the
 * __hint and the __count (manual_upload.html, import_csv.html).
 * wireDropZone() without onFiles writes a drop into input.files and
 * dispatches change, so a page's existing change handler runs for drops
 * too; with onFiles the input is emptied after each choice.
 * --active is set by wireDropZone() while a drag is over the zone.
 * A file chip is a removable tag (components/tag.css, imported after this
 * file in the same layer): its look and its remove button are the tag's.
 * The rules below that must beat a tag rule (widths, upload state borders,
 * status colors) carry a second class; the state borders carry the list's
 * class too, to beat the removable tag's hover.
 */

.cm-drop-zone__group {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--cm-space-2);
  width: 100%;
}

.cm-drop-zone {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--cm-space-1);
  box-sizing: border-box;
  width: 100%;
  min-height: 100px;
  padding: var(--cm-space-4);
  border: 1px dashed var(--cm-border-strong);
  border-radius: var(--cm-radius-lg);
  background: var(--cm-bg-surface);
  text-align: center;
  cursor: pointer;
  transition:
    border-color 120ms ease,
    background-color 120ms ease;
}

/* --wide: opt in to today's ~370px target (23rem) inside a shrink-wrapped
   card. buildDropZone()'s wide option adds this modifier; UploadContainer
   (common/request-widgets.js) always asks for it, so its mounts (Batch
   Upload, Upload Requests, Preload Tool, Upload Records, the Review Batches
   and PDF editor append/replace popups) keep today's width. A shrink-to-fit
   parent measures the preferred 23rem, since a percentage min or max size
   counts as 0 or none while it measures; at layout the 100% min and max
   make the zone fill its parent, wider or narrower (Upload Records' 300px
   mounts, the Payer Audits form column). Below 600px the 23rem would become
   the card's minimum, so small screens keep width: 100% alone.
   Without this modifier a plain zone (Manual Upload, Import CSV static
   markup) never asks for more than its own column gives it: it just fills
   whatever width: 100% resolves to, so it cannot force a shrink-to-fit
   ancestor (and the legacy row/column it sits in) wider than that column's
   own content. */
@media (min-width: 600px) {
  .cm-drop-zone--wide {
    inline-size: 23rem;
    min-inline-size: 100%;
    max-inline-size: 100%;
  }
}

.cm-drop-zone__input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.cm-drop-zone:hover {
  border-color: var(--cm-interactive);
}

/* The ring is for keyboard focus: a label click focuses the input too, so
   :focus-within would keep the ring after choosing files with the mouse. */
.cm-drop-zone:has(.cm-drop-zone__input:focus-visible) {
  border-color: var(--cm-interactive);
  box-shadow: var(--cm-focus-ring);
}

.cm-drop-zone--active {
  border-color: var(--cm-interactive);
  background: var(--cm-drop-zone-active-bg);
}

/* --lg: a customer page's zone (the request flow, docs/specs/
   2026-10-13-request-flow-refresh-design.md section 5): a 2px dashed edge
   on a slate-50 fill, 14px corners, more room, the icon in a 48px accent
   tile and 15px text with a bold browse link. Staff zones keep the look
   above. */
.cm-drop-zone--lg {
  gap: 6px;
  padding: 26px var(--cm-space-5);
  border: 2px dashed var(--cm-gray-300);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-gray-50);
}

.cm-drop-zone--lg .cm-drop-zone__icon {
  display: inline-grid;
  place-items: center;
  width: 48px;
  height: 48px;
  margin-bottom: var(--cm-space-1);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-accent-50);
  color: var(--cm-accent-700);
  font-size: var(--cm-text-xl);
}

.cm-drop-zone--lg .cm-drop-zone__text {
  font-size: var(--cm-text-base);
}

.cm-drop-zone--lg .cm-drop-zone__browse {
  color: var(--cm-accent-700);
  font-weight: var(--cm-fw-semibold);
}

.cm-drop-zone--lg .cm-drop-zone__hint {
  font-size: var(--cm-text-sm);
}

/* A zone whose input a page's check rejected (aria-invalid: the request
   flow's "Please select a file"): the danger edge, until a file comes. */
.cm-drop-zone:has(> .cm-drop-zone__input[aria-invalid='true']) {
  border-color: var(--cm-danger-500);
}

.cm-drop-zone__icon {
  font-size: var(--cm-text-xl);
  color: var(--cm-text-muted);
}

.cm-drop-zone--active .cm-drop-zone__icon {
  color: var(--cm-interactive);
}

.cm-drop-zone__text {
  font-size: var(--cm-text-sm);
  color: var(--cm-text-body);
}

.cm-drop-zone__browse {
  color: var(--cm-interactive);
  font-weight: var(--cm-fw-medium);
  text-decoration: underline;
}

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

.cm-drop-zone__count {
  margin: 0;
  font-size: var(--cm-text-sm);
  color: var(--cm-text-muted);
  text-align: center;
}

/* The chip list (moved from stylesheetv3.css .file-chips, same look). Large
   batches scroll inside a fixed area instead of pushing the buttons below
   the fold (Automate-uzxo). */
.cm-drop-zone__files {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cm-space-1);
  max-height: 220px;
  margin: 0;
  padding: 0 var(--cm-space-1) 0 0;
  overflow-y: auto;
  list-style: none;
}

/* Not :empty, so whitespace left in static markup cannot keep an empty
   list in the group's flow. */
.cm-drop-zone__files:not(:has(> li)) {
  display: none;
}

/* Long names stop at a fixed width (wider once a status shows). */
.cm-drop-zone__files .cm-drop-zone__file {
  max-width: 120px;
}

.cm-drop-zone__files .cm-drop-zone__file[data-state] {
  max-width: 170px;
}

.cm-drop-zone__file-name {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cm-drop-zone__file .cm-drop-zone__file-status {
  color: var(--cm-text-muted);
  white-space: nowrap;
}

.cm-drop-zone__file-status:empty {
  display: none;
}

.cm-drop-zone__files--busy .cm-drop-zone__file-remove {
  display: none;
}

/* The remove button is gone, so give the chip matching right padding
   (two classes to outrank .cm-tag--removable's own padding). */
.cm-drop-zone__files--busy .cm-drop-zone__file {
  padding-right: var(--cm-space-2);
}

.cm-drop-zone__files .cm-drop-zone__file[data-state='uploading'] {
  border-color: var(--cm-interactive);
}

.cm-drop-zone__file[data-state='uploading'] .cm-drop-zone__file-status {
  color: var(--cm-interactive);
}

.cm-drop-zone__file[data-state='done'] .cm-drop-zone__file-status {
  color: var(--cm-success-text);
}

.cm-drop-zone__file[data-state='done'] .cm-drop-zone__file-status::before {
  content: '\2713 ';
}

/* Chosen and ready to send (the request flow's files, upload-tiles.js):
   the check and the word a little apart. */
.cm-drop-zone__file[data-state='ready'] .cm-drop-zone__file-status {
  display: inline-flex;
  gap: var(--cm-space-1);
  color: var(--cm-success-text);
  font-weight: var(--cm-fw-semibold);
}

.cm-drop-zone__file[data-state='ready'] .cm-drop-zone__file-status::before {
  content: '\2713 ';
}

.cm-drop-zone__files .cm-drop-zone__file[data-state='failed'] {
  border-color: var(--cm-danger-500);
}

.cm-drop-zone__file[data-state='failed'] .cm-drop-zone__file-status {
  color: var(--cm-danger-text);
}

/* __files--rows: each chosen file a full-width row (the request flow): its
   whole name, its state at the end, a 32px remove button. Two classes beat
   the removable tag's own sizes. */
.cm-drop-zone__files--rows {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: var(--cm-space-2);
  padding: 0;
}

.cm-drop-zone__files--rows .cm-drop-zone__file[data-state] {
  max-width: none;
}

.cm-drop-zone__files--rows .cm-drop-zone__file {
  gap: var(--cm-space-3);
  max-width: none;
  min-height: 48px;
  padding: 6px 6px 6px 14px;
  border-color: var(--cm-gray-200);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-bg-surface);
  color: var(--cm-text-heading);
  font-size: var(--cm-text-sm);
}

.cm-drop-zone__files--rows .cm-drop-zone__file-name {
  flex: 1 1 auto;
  font-weight: var(--cm-fw-medium);
}

.cm-drop-zone__files--rows .cm-drop-zone__file-remove {
  width: 32px;
  height: 32px;
  border-color: transparent;
  font-size: var(--cm-text-lg);
}

/* --options (CSS phase 5.5 redesign review): a zone with options inside
   its frame (Compress PDFs). The frame is a div and the drop target; the
   click-to-browse label (__target) fills its top, and the options sit in
   __footer, outside that label (a label cannot hold another control's
   label), so a click on them never opens the file dialog. */
.cm-drop-zone--options {
  justify-content: flex-start;
  padding: 0;
  cursor: default;
}

.cm-drop-zone__target {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--cm-space-1);
  box-sizing: border-box;
  width: 100%;
  padding: var(--cm-space-4) var(--cm-space-4) var(--cm-space-3);
  cursor: pointer;
}

.cm-drop-zone__footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--cm-space-2);
  box-sizing: border-box;
  width: 100%;
  padding: var(--cm-space-2) var(--cm-space-3);
  border-top: 1px dashed var(--cm-border);
}

/* An option (UploadContainer's Compress PDFs check chip) sits centered like
   the zone's text, and its label shrinks to its text so a click beside it
   does not toggle the box. */
.cm-drop-zone__option {
  align-self: center;
}

/* UploadContainer's Clear and Submit under its drop zone. Not a .row: inside
   a popup the popup's .row rule would add a gap and a bottom margin. */
.cm-drop-zone__actions {
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  width: 100%;
}

}
@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 {
/*
 * Option cards (CSS phase 5, from the legacy CNR and Add Affidavit cards):
 * a column of radio choices drawn as cards. The label wraps the radio and
 * its text, so the whole card toggles it; a hovered card and the checked
 * one take the teal edge and tint. --with-input puts a text field under the
 * card's label (CNR's Other). --danger is a choice that rejects (the
 * Preload Tool's "Not a ChartMate facility"): the danger edge and tint.
 * Markup: p.cm-option-card-prompt, div.cm-option-card-list >
 *   label.cm-option-card[--with-input|--danger] > input[type=radio], span
 *   (+ input[type=text] for --with-input).
 * Used by the CNR reason picker (Upload Records and Manual Upload shells,
 * CnrPopup in common/request-widgets.js) and Add Affidavit
 * (common/pdf/pdf-actions.js), and the Preload Tool's Match facilities
 * (features/batches/facility-panel.js).
 */

.cm-option-card-prompt {
  margin: 0 0 var(--cm-space-4);
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
}

.cm-option-card-list {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-2);
  width: 100%;
}

.cm-option-card {
  display: flex;
  align-items: center;
  gap: var(--cm-space-3);
  padding: var(--cm-space-2) var(--cm-space-3);
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-md);
  cursor: pointer;
  user-select: none;
  transition:
    background 120ms ease,
    border-color 120ms ease;
}

.cm-option-card:hover {
  border-color: var(--cm-teal-500);
  background: color-mix(in srgb, var(--cm-teal-500) 6%, var(--cm-bg-surface));
}

.cm-option-card:has(input[type='radio']:checked) {
  border-color: var(--cm-teal-500);
  background: color-mix(in srgb, var(--cm-teal-500) 10%, var(--cm-bg-surface));
}

.cm-option-card > input[type='radio'] {
  flex: 0 0 auto;
  margin: 0;
  cursor: pointer;
}

.cm-option-card > span {
  flex: 1;
  font-weight: var(--cm-fw-medium);
}

.cm-option-card--with-input {
  flex-wrap: wrap;
}

.cm-option-card--with-input > input[type='text'] {
  flex: 1 1 100%;
  margin: var(--cm-space-2) 0 0;
}

.cm-option-card--danger:hover,
.cm-option-card--danger:has(input[type='radio']:checked) {
  border-color: var(--cm-danger-text);
  background: var(--cm-bg-danger-soft);
}

}
@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 {
/*
 * 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;
}

.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 {
/*
 * 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 {
/*
 * The signature pad and the phone's signing sheet (request flow refresh,
 * docs/specs/2026-10-13-request-flow-refresh-design.md section 10).
 * Customer only: request.css imports it, portal.css and staff.css do not.
 *
 * Pad markup: div.cm-signature[--fill] > canvas.cm-signature__canvas;
 * createSignaturePad() in _shared/components/signature-pad.js adds the
 * guide before the canvas: div.cm-signature__guide (aria-hidden) >
 * span.__hint ("Sign here", hidden after the first stroke), span.__x,
 * span.__line, span.__name (the printed name, hidden when empty). The
 * guide is markup under the canvas, never drawn on it. The pad keeps its
 * strokes anchored where __line starts (left 7%, 74% down): keep the two
 * in step (ANCHOR in signature-pad.js).
 *
 * Sheet markup (built by openSignatureSheet() in signature-sheet.js,
 * removed on close): div.cm-signature-sheet (role=dialog) >
 *   header.__header > button (Cancel), h2.__title, button (Done);
 *   div.__body > p.__tip (portrait only), div.cm-signature.cm-signature--fill;
 *   footer.__footer > p.__agree, button (Clear).
 * While it is open, the root carries .cm-signature-sheet-open (no page
 * scroll under the sheet).
 *
 * A saved signature: div.cm-signature > img.cm-signature__image (the
 * saved 600 by 200 image in the 3:1 box). On a phone, the way to the sheet:
 * button.cm-signature-tap (a dashed accent box) > i.__icon, span ("Tap to
 * sign"), span.__hint; and once signed, div.cm-signature-signed >
 * span.__status ("Signed" with a check), a text button (Sign again).
 */

.cm-signature {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  aspect-ratio: 3 / 1;
  border: 1px solid var(--cm-border-strong);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-bg-surface);
  overflow: hidden;
}

/* The sheet's pad: whatever room the sheet has left. */
.cm-signature--fill {
  flex: 1;
  min-height: 0;
  aspect-ratio: auto;
}

.cm-signature__canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: crosshair;
}

.cm-signature__guide {
  position: absolute;
  inset: 0;
  pointer-events: none;
  user-select: none;
}

.cm-signature__hint {
  position: absolute;
  inset: 0 0 26% 0;
  display: grid;
  place-items: center;
  font-size: var(--cm-text-lg);
  letter-spacing: 0.02em;
  color: var(--cm-text-muted);
}

.cm-signature__x {
  position: absolute;
  left: 7%;
  bottom: calc(26% + var(--cm-space-1));
  font-size: var(--cm-text-xl);
  font-weight: var(--cm-fw-regular);
  line-height: 1;
  color: var(--cm-text-muted);
}

.cm-signature__line {
  position: absolute;
  left: 7%;
  right: 7%;
  bottom: 26%;
  border-top: 2px solid var(--cm-gray-300);
}

.cm-signature__name {
  position: absolute;
  top: calc(74% + var(--cm-space-1));
  left: 7%;
  right: 7%;
  overflow: hidden;
  font-size: var(--cm-text-sm);
  color: var(--cm-text-muted);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* A saved signature shown in the pad's box. */
.cm-signature__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* ---------- On a phone: Tap to sign, and Signed ---------- */

.cm-signature-tap {
  display: grid;
  place-items: center;
  gap: 6px;
  box-sizing: border-box;
  width: 100%;
  padding: 26px var(--cm-space-4);
  border: 2px dashed var(--cm-accent-700);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-accent-50);
  color: var(--cm-accent-800);
  font: inherit;
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-semibold);
  text-align: center;
  cursor: pointer;
}

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

.cm-signature-tap__icon {
  font-size: var(--cm-text-2xl);
}

.cm-signature-tap__hint {
  color: var(--cm-text-body);
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-regular);
}

.cm-signature-signed {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
  font-size: var(--cm-text-sm);
}

.cm-signature-signed__status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--cm-success-text);
  font-weight: var(--cm-fw-semibold);
}

/* ---------- The phone's signing sheet ---------- */

.cm-signature-sheet-open {
  overflow: hidden;
  overscroll-behavior: none;
}

.cm-signature-sheet {
  position: fixed;
  inset: 0;
  z-index: var(--cm-z-modal);
  display: flex;
  flex-direction: column;
  height: 100dvh;
  background: var(--cm-gray-50);
}

.cm-signature-sheet__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
  padding: max(var(--cm-space-3), env(safe-area-inset-top)) var(--cm-space-4) var(--cm-space-3);
  border-bottom: 1px solid var(--cm-gray-200);
  background: var(--cm-bg-surface);
}

.cm-signature-sheet__title {
  margin: 0;
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-bold);
  color: var(--cm-text-heading);
}

.cm-signature-sheet__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--cm-space-3);
  min-height: 0;
  padding: var(--cm-space-4) max(var(--cm-space-4), env(safe-area-inset-right)) var(--cm-space-2)
    max(var(--cm-space-4), env(safe-area-inset-left));
}

.cm-signature-sheet__tip {
  display: flex;
  align-items: center;
  gap: var(--cm-space-3);
  margin: 0;
  padding: var(--cm-space-3);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-bg-info-soft);
  font-size: var(--cm-text-sm);
  color: var(--cm-info-text);
}

.cm-signature-sheet__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cm-space-3);
  padding: var(--cm-space-2) var(--cm-space-4) max(var(--cm-space-4), env(safe-area-inset-bottom));
}

.cm-signature-sheet__agree {
  margin: 0;
  font-size: var(--cm-text-sm);
  color: var(--cm-text-muted);
}

/* Sideways: no tip, tighter edges, the pad gets the height. */
@media (orientation: landscape) {
  .cm-signature-sheet__tip {
    display: none;
  }

  .cm-signature-sheet__header {
    padding-block: max(var(--cm-space-2), env(safe-area-inset-top)) var(--cm-space-2);
  }

  .cm-signature-sheet__body {
    padding-block: var(--cm-space-2) var(--cm-space-1);
  }

  .cm-signature-sheet__footer {
    padding-block: var(--cm-space-1) max(var(--cm-space-2), env(safe-area-inset-bottom));
  }
}

}
@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 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 {
/*
 * The request flow's own layout (public/request/; CSS phase 6,
 * docs/specs/2026-10-12-css-phase-6-customer-design.md, and the request
 * flow refresh, docs/specs/2026-10-13-request-flow-refresh-design.md): the
 * customer sizing, the page shell (the header bar common/site-header.js
 * renders, the main column under each page's hero band, the footer's
 * placement), the wait screen, and what the pages place around the
 * components (cards, fields, buttons, the stepper, the drop zone): the
 * chooser, a step card's sections, field grid and footer, the signature
 * pad, and the confirmation and 404 cards. request.css imports it into
 * layer(pages).
 * Every page keeps a 16px gutter and reflows to 320px wide. Text that sits
 * on the page background (outside a card) uses body text, not muted.
 */

/* ---------- Customer sizing ----------
   The same tokens, with the same values, as the portal's customer sizing
   (pages/portal.css; change both together): 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 slate-50 page.
   Staff pages keep the defaults (tokens.css). */
: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);
  --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), as on the portal. */
:is(input:not([type='checkbox'], [type='radio'], [type='file']), select, textarea) {
  font-size: var(--cm-text-base);
}

/* ---------- 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 header bar ----------
   common/site-header.js renders it into #site-header: the ChartMate logo
   at the start, the facility's logo or its name at the end (filled by
   applyFacilityBranding). As tall as the portal's app bar. */
.request-bar {
  position: relative;
  z-index: var(--cm-z-float);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  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);
}

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

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

/* A facility's uploaded logo, kept inside the bar's height. */
.request-bar__facility-logo {
  min-width: 0;
  max-width: 240px;
  max-height: 44px;
  object-fit: contain;
}

/* The facility's name, when it has no logo: a building icon and the name. */
.request-bar__facility {
  display: inline-flex;
  align-items: center;
  gap: var(--cm-space-2);
  min-width: 0;
  color: var(--cm-text-heading);
  font-size: var(--cm-button-font-size);
  font-weight: var(--cm-fw-semibold);
  text-align: right;
}

.request-bar__facility i {
  color: var(--cm-gray-500);
}

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

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

  .request-bar__facility-logo {
    max-width: 140px;
    max-height: 36px;
  }

  .request-bar__facility {
    font-size: var(--cm-text-caption);
  }

  .request-bar__facility i {
    display: none;
  }
}

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

/* ---------- The wait screen ----------
   #loaderBody, shown through its hidden attribute while a request runs: a
   light wash over the window, three accent rings turning, and on the upload
   page "Please wait" over them and the current step's message under them. */
.request-loader {
  position: fixed;
  z-index: var(--cm-z-modal);
  width: 100%;
  height: 100%;
  background-image: radial-gradient(
    circle farthest-corner at center,
    var(--cm-bg-surface) 0%,
    var(--cm-bg-body) 100%
  );
  opacity: 0.8;
}

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

.request-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. */
.request-loader__ring--one {
  top: 0%;
  left: 0%;
  border-bottom: 5px solid var(--cm-accent-900);
  animation: request-loader-one 1s linear infinite;
}

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

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

.request-loader__wait,
.request-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%);
}

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

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

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

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

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

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

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

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

/* The staff popup (the signature's Clear dialog, ConfirmDialog) leaves room
   for the staff nav rail on its left; this site has none. */
:root {
  --sidebar-width: 0px;
}

/* An accent icon on a soft tile: 40px (the confirmations' next steps),
   56px (--lg, the chooser's cards). The portal's .portal-icon
   (pages/portal.css), the same values. */
.request-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);
}

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

/* ---------- The chooser (index.html) ----------
   Two action cards side by side (one column on a phone), as on the
   portal's start: the icon, title, a line and the button, at the start. */

.request-chooser__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--cm-space-5);
  width: 100%;
}

/* The text takes the spare height so both buttons line up when one card's
   text runs longer. */
.request-chooser__card {
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  align-content: start;
  justify-items: start;
  gap: var(--cm-space-3);
  padding: 28px;
}

.request-chooser__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);
}

.request-chooser__text {
  margin: 0;
  padding: 0;
  color: var(--cm-text-muted);
  text-align: left;
}

@media (max-width: 600px) {
  .request-chooser__grid {
    gap: var(--cm-space-4);
  }

  .request-chooser__card {
    padding: var(--cm-space-5);
  }
}

/* ---------- A link without a valid facility ----------
   common/link-problem.js fills the page's #link-problem card: the danger
   banner and Contact support, in place of the page's own cards. */

.request-problem {
  display: grid;
  gap: var(--cm-space-5);
  padding: var(--cm-space-8);
}

.request-problem__contact {
  justify-self: start;
}

@media (max-width: 600px) {
  .request-problem {
    padding: var(--cm-space-5);
  }
}

/* ---------- A step card (authorization steps, the upload card) ----------
   The title over its line, the body, and the footer with Back and Next,
   each with a 32px inset (20px on a phone) and soft dividers (spec
   section 5). */

.request-step__header {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--cm-space-1);
  padding: 26px var(--cm-space-8) 18px;
  border-bottom-color: var(--cm-gray-200);
}

.request-step__lede {
  padding: 0;
  font-size: var(--cm-text-sm);
  line-height: var(--cm-lh-normal);
}

.request-step__body {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-6);
  padding: var(--cm-space-6) var(--cm-space-8);
}

/* A group of fields under a section title (a role=group labelled by it). */
.request-section {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-4);
  min-width: 0;
}

/* A section's title and the hint under it. */
.request-section__head {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-1);
}

.request-section__title {
  margin: 0;
  color: var(--cm-text-heading);
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-semibold);
  line-height: var(--cm-lh-snug);
}

.request-section__hint {
  margin: 0;
  padding: 0;
  color: var(--cm-text-muted);
  font-size: var(--cm-text-sm);
  text-align: left;
}

/* The Required or Optional pill beside a section title. */
.request-section__tag {
  margin-left: var(--cm-space-2);
  vertical-align: middle;
}

/* Fields one per row on a phone, two per row from 600px. */
.request-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--cm-space-4) var(--cm-space-5);
}

.request-grid__full {
  grid-column: 1 / -1;
}

@media (min-width: 600px) {
  .request-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Back at the start, Next (or Submit) at the end; a lone Next sits at the
   end. On a phone the two share the row. */
.request-step__footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--cm-space-3);
  padding: 18px var(--cm-space-8);
  border-top-color: var(--cm-gray-200);
}

.request-step__footer > :only-child {
  margin-left: auto;
}

@media (max-width: 600px) {
  .request-step__header,
  .request-step__body,
  .request-step__footer {
    padding-inline: var(--cm-space-5);
  }

  .request-step__footer > * {
    flex: 1 1 0;
  }
}

/* "Same as patient": a check row at the field's height in sentence case,
   not the staff check chip (components/field.css). */
.request-check {
  gap: 10px;
  padding: 0 var(--cm-space-4) 0 var(--cm-space-3);
  border-color: var(--cm-gray-300);
  border-radius: var(--cm-control-radius);
  color: var(--cm-text-heading);
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-regular);
  text-transform: none;
  letter-spacing: normal;
}

.request-check > input {
  width: 18px;
  height: 18px;
}

/* A records choice (an option card, components/option-card.css): roomier,
   the radio at the title's line, the title over its explanation. */
.request-choice {
  align-items: flex-start;
  padding: 14px var(--cm-space-4);
  border-radius: var(--cm-radius-xl);
}

.request-choice > input {
  width: 18px;
  height: 18px;
  margin-top: 3px;
}

.request-option {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.request-option__title {
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-heading);
}

.request-option__text {
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-regular);
  line-height: var(--cm-lh-normal);
  /* Body text: muted gray falls under 4.5:1 on the option card's tint. */
  color: var(--cm-text-body);
}

/* A line under the page's card, on the page background (the upload's
   "If you're a patient"): body text. */
.request-below {
  margin: 0;
  padding: 0;
  color: var(--cm-text-body);
  text-align: center;
}

/* ---------- The signature step ---------- */

/* The terms in a quiet box over the fields, shown in full: a signer must
   be able to read every disclosure without scrolling a box. */
.request-consent {
  display: grid;
  gap: var(--cm-space-2);
  box-sizing: border-box;
  padding: 14px 18px;
  border: 1px solid var(--cm-gray-200);
  border-radius: var(--cm-radius-xl);
  background: var(--cm-gray-50);
}

.request-consent__lede {
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-heading);
  text-align: left;
}

.request-consent__list {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0 0 0 18px;
  font-size: var(--cm-text-sm);
  line-height: var(--cm-lh-normal);
  color: var(--cm-text-body);
}

.request-consent__note {
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-xs);
  line-height: var(--cm-lh-normal);
  color: var(--cm-text-body);
  text-align: left;
}

.request-signature {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-3);
}

.request-signature__hint {
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-sm);
  line-height: var(--cm-lh-normal);
}

.request-signature__label {
  margin: 0;
  padding: 0;
}

/* The pad's pen cursor. */
.signature-canvas {
  cursor:
    url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="24" height="24"><path d="M368.5 18.3l-50.1 50.1 125.3 125.3 50.1-50.1c21.9-21.9 21.9-57.3 0-79.2L447.7 18.3c-21.9-21.9-57.3-21.9-79.2 0zM279.3 97.2l-.5 .1-144.1 43.2c-19.9 6-35.7 21.2-42.3 41L3.8 445.8c-2.9 8.7-1.9 18.2 2.5 26L161.7 316.4c-1.1-4-1.6-8.1-1.6-12.4 0-26.5 21.5-48 48-48s48 21.5 48 48-21.5 48-48 48c-4.3 0-8.5-.6-12.4-1.6L40.3 505.7c7.8 4.4 17.2 5.4 26 2.5l264.3-88.6c19.7-6.6 35-22.4 41-42.3l43.2-144.1 .1-.5-135.5-135.5z" fill="%23000000"/></svg>')
      0 24,
    auto;
}

.request-signature__saved {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-2);
}

.request-signature__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--cm-space-2);
}

/* Which controls the width shows (the state is each one's hidden): under
   600px the "Signature" label, Tap to sign, and Signed with Sign again;
   from 600px up the instructions, the pad, and Clear and Save. */
.request-signature__wide {
  display: none;
}

@media (min-width: 600px) {
  .request-signature__narrow {
    display: none;
  }

  .request-signature__hint,
  .request-signature__pad {
    display: block;
  }

  .request-signature__actions {
    display: flex;
  }
}

/* ---------- The confirmation card (patient and customer) ----------
   Its check, title and line are in the page's band (the hero's __check);
   the card lists what happens next (an accent icon, a short title over
   its line, spec section 7), then the patient's thanks or the third
   party's Submit another request. */

.request-confirmation {
  display: grid;
  gap: var(--cm-space-5);
  padding: var(--cm-space-8);
}

.request-confirmation__next {
  display: grid;
  gap: var(--cm-space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  line-height: var(--cm-lh-normal);
  color: var(--cm-text-body);
}

.request-confirmation__next li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 14px;
}

.request-confirmation__step {
  display: block;
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-semibold);
}

.request-confirmation__thanks {
  margin: 0;
  padding: 0;
  font-size: var(--cm-text-sm);
  color: var(--cm-text-muted);
  text-align: center;
}

/* ---------- The 404 card ----------
   "404", the title and the line are in the band; the card holds the two
   links, Return to home first. */

.request-not-found {
  padding: var(--cm-space-8);
}

.request-not-found__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cm-space-3);
}

/* A page card keeps its 32px inset on a tablet or desktop; a phone takes 20px. */
@media (max-width: 600px) {
  .request-confirmation,
  .request-not-found {
    padding: var(--cm-space-5);
  }
}

}
