/*
 * Portal-local stylesheet (Phase 2.0 trim).
 *
 * Shared layer is canonical for primitives — load order is:
 *   1. tokens.css       (--cm-* design tokens)
 *   2. typography.css   (Inter @font-face + base type rules)
 *   3. stylesheetv3.css (.button, .field, .results-table, .status-pill,
 *                        .actions-dropdown, .navigation-div, .container,
 *                        .row/.column/.cell, .error/.warning/.info/.success,
 *                        .closebtn, .messageText, .loader-*, input/select
 *                        primitives, table#searchTable / table.searchTable, …)
 *   4. portal/stylesheet.css  (this file — portal-only overrides)
 *   5. portal/loader.css      (loader keyframes)
 *
 * Per-page leaves (Phases 2.1–2.5) will retire most of what is left below
 * to shared primitives. This file's job is to stop duplicating shared
 * rules and to use --cm-* tokens for color.
 */

/* stylesheetv3.css ships `body { display: none }` (FOUC suppression for
   /api, which flips it on via initializePage.js → .display-block once
   navbar + role config are ready). Portal pages don't load that helper
   and don't have navbar/role logic to wait for, so we re-show the body
   unconditionally here. Theme/dark-mode FOUC is handled separately by
   the inline <head> theme bootstrap script in each portal HTML — see
   public/_shared/theme.js for the shared module form. Refactoring v3
   to scope `body { display: none }` behind a class would touch every
   /api page's init flow; deferred to a future design-system pass. */
/* Sticky footer for portal pages whose body holds the layout column
   directly (index.html, portal/login.html, portal/change-password.html,
   portal/forgot-password.html). Body becomes a flex column with
   min-height: 100vh so header + main + footer stack to fill the
   viewport; <main class="page-container"> grows to absorb the leftover
   space. Without this, stylesheetv3.css's `.page-container { min-height:
   100vh; }` makes the main alone fill the viewport, so the
   header-above + footer-below combine to push the footer below the
   fold on short content (the trust-band footer disappeared). app.html
   uses a nested .page-wrapper > .main-container layout and is
   unaffected — `body > main.page-container` doesn't match there. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

body > main.page-container {
  flex: 1 0 auto;
  min-height: 0;
}

/* ---------- Page chrome ---------- */

/* Logo header: centered, transparent background, no separator shadow.
   The previous treatment (white bar pinned to viewport top with the logo
   left-aligned and a box-shadow underneath) read as a disconnected utility
   chrome bar above the centered card. Removing the bg-surface fill lets it
   blend with the page bg, and centering the logo pairs visually with the
   centered card below. (Automate-i98f.2.11) */
.logo-div {
  position: static;
  top: auto;
  left: auto;
  padding: 16px 10px;
  background-color: transparent;
  width: 100%;
  box-sizing: border-box;
  display: flex;
  justify-content: center;
  align-items: center;
}

.page-wrapper {
  position: relative;
  width: 100vw;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.main-container {
  width: 100vw;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: start;
  height: 100vh;
}

.header-div {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-bottom: 32px;
  gap: 8px;
}

/* Portal landing hero: scale the heading up so the surface reads as a
   welcome page rather than a tool screen. Default h1 is --cm-text-2xl
   (24px); bump to 30px on desktop, 26px on mobile. (Automate-i98f.2.9) */
.header-div h1 {
  margin-top: 0px;
  font-size: var(--cm-text-3xl);
  text-align: center;
}

@media (max-width: 600px) {
  .header-div h1 {
    font-size: 1.625rem; /* 26px */
  }
}

/* Single conversational lede under the h1, centered + slightly muted so
   the heading carries the visual weight. */
.header-div .hero-lede {
  margin: 0;
  text-align: center;
  color: var(--cm-text-muted);
  font-size: var(--cm-text-base);
  max-width: 44ch;
}

.body-div {
  display: flex;
  flex-direction: column;
  border-radius: var(--cm-radius-lg);
  box-shadow: var(--cm-shadow-md);
  padding: 50px;
  align-items: center;
  justify-content: space-evenly;
  background-color: var(--cm-bg-surface);
}

.container-wrapper {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
}

/* Park the card near the top instead of vertically centered. With main's
   default `justify-content: center`, the card sat ~40% down the viewport on
   tall screens, making the eye hunt for it. Top-aligned with breathing room
   feels more decisive. */
.page-container {
  justify-content: flex-start;
  padding-top: 80px;
  /* Horizontal breathing room from viewport edges so contents don't sit
     flush against the screen on the dashboard (.search-bar, table, nav).
     On the auth pages this just adds room around the centered .container
     card — harmless. */
  padding-left: 24px;
  padding-right: 24px;
  box-sizing: border-box;
}

/* Portal cards: fill available width up to a focused single-column max.
   560px keeps the card readable without overscaling for content that's
   really just a heading + a few CTAs. Without `width: 100%`, v3's flex-shrink
   lets the card collapse to its intrinsic content width regardless of
   viewport — the page appears identical on a phone and a 4K monitor. */
.container {
  width: 100%;
  max-width: 560px;
  padding: 40px 48px;
  margin: 16px;
  box-sizing: border-box;
}

@media (max-width: 600px) {
  /* Mobile: more breathing room from viewport edges + tighter top offset. */
  .page-container {
    padding-top: 24px;
  }

  .container {
    padding: 32px 20px;
    margin: 16px 20px;
  }
}

.container .row {
  width: 100%;
  display: flex;
  justify-content: center;
}

/* Section break between the primary CTAs (Pay / Download) and the secondary
   "Have an account? → Login" path. Previously rendered as a full-width <hr>
   which read as an overly heavy barrier; spacing alone (with the h2 acting
   as the section label) communicates the same group-then-group hierarchy
   without the visual heaviness. (Automate-i98f.2.10) */
.container .row.login-section-break {
  margin-top: 20px;
}

/* CTAs: cap at a comfortable width so they don't span the full card —
   Pay/Download/Login feel like decisive actions rather than long thin pills.
   On mobile (where the card itself is narrow) they fall back to filling the
   row naturally. */
.container .row > .button,
.container .row > a.button {
  width: 100%;
  max-width: 320px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Multi-button row (Pay/Back, Download/Back inside the action card forms).
   Override the single-button width:100% rule above — when two buttons share
   the row they need to flex-share its width rather than each demanding 100%
   (which causes the trailing button to overflow the card on the right). */
.container .row.button-row {
  justify-content: space-between;
  gap: 12px;
}

.container .row.button-row > .button {
  flex: 1 1 0;
  width: auto;
  max-width: 200px;
}

/* ---------- Portal landing action tiles (Pay / Download) ----------
   Two side-by-side icon tiles instead of stacked text buttons. Each tile
   shows an icon, a primary action label, and a small sublabel. Hover
   lifts the tile + deepens the teal. Mobile collapses to a single column
   with horizontal icon-left layout (more compact than two stacked
   squares). */
.action-tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  width: 100%;
  margin-top: 8px;
}

.action-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 28px 16px;
  background: var(--cm-interactive);
  color: var(--cm-text-on-interactive);
  border: 1px solid transparent;
  border-radius: var(--cm-radius-lg);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--cm-text-base);
  text-align: center;
  text-decoration: none;
  transition:
    background-color 120ms ease,
    transform 120ms ease,
    box-shadow 120ms ease;
  user-select: none;
  min-height: 140px;
}

.action-tile:hover {
  background: var(--cm-interactive-hover);
  box-shadow: var(--cm-shadow-md);
  transform: translateY(-2px);
}

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

.action-tile:active {
  background: var(--cm-interactive-active);
  transform: translateY(0);
}

.action-tile__icon {
  font-size: 28px;
  margin-bottom: 4px;
  color: var(--cm-text-on-interactive);
}

/* v3 ships `* { color: var(--text-color) }` which defeats inheritance from
   .action-tile { color: var(--cm-text-on-interactive) }. Set color explicitly
   on label + sublabel so they render white on the teal tile. */
.action-tile__label {
  font-size: var(--cm-text-lg);
  font-weight: var(--cm-fw-bold);
  line-height: 1.2;
  color: var(--cm-text-on-interactive);
}

.action-tile__sublabel {
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-regular);
  opacity: 0.9;
  line-height: 1.2;
  color: var(--cm-text-on-interactive);
}

@media (max-width: 600px) {
  .action-tiles {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .action-tile {
    flex-direction: row;
    justify-content: flex-start;
    text-align: left;
    padding: 16px 20px;
    min-height: 0;
    gap: 16px;
  }

  .action-tile__icon {
    font-size: 24px;
    margin-bottom: 0;
    flex-shrink: 0;
  }

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

/* ---------- Auth-flow primary CTA (portal-local — per-page leaf will
   migrate to .button shared primitive). ---------- */

.authButtonDiv {
  display: flex;
  flex-direction: column;
  height: 100%;
  justify-content: end;
}

.authButton {
  /* Light mode: teal-700 (#0F766E, 5.47:1 with white) → teal-900 (#134E4A,
     9.48:1). In dark mode the raw teal-700 token is remapped to a much
     lighter shade (#99F6E4) which would put white-on-light at 1.2:1. The
     :root.dark override below pins the gradient to teal-900 on both ends
     so contrast holds. */
  background-image: linear-gradient(92.88deg, var(--cm-teal-700) 0%, var(--cm-teal-900) 80%);
  border-radius: var(--cm-radius-lg);
  border-style: none;
  box-sizing: border-box;
  color: var(--cm-text-on-dark);
  cursor: pointer;
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-bold);
  padding: 0.5rem 1rem;
  text-align: center;
  transition: all 0.5s;
  user-select: none;
}

.authButton:hover {
  box-shadow: var(--cm-shadow-md);
  transition-duration: 0.1s;
}

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

:root.dark .authButton,
:root.dark .filterButton.selected {
  /* teal-900 is not redefined in :root.dark, so this resolves to #134E4A
     in both modes — keeps the dark portal CTA legible. */
  background-image: linear-gradient(92.88deg, var(--cm-teal-900) 0%, var(--cm-teal-900) 80%);
  color: var(--cm-text-on-dark);
}

hr.solid {
  border: 0;
  clear: both;
  display: block;
  width: 200px;
  background-color: var(--cm-border);
  height: 1px;
}

/* ---------- Single-invoice / pay-records views ---------- */

.main-container-single-invoice {
  display: flex;
  flex-direction: row;
  justify-content: center;
  gap: 20px;
  align-items: center;
  min-height: 600px;
  width: 100vw;
  height: 100%;
}

.main-container-single-invoice h3 {
  color: var(--cm-text-heading);
  margin: 0px;
}

.main-container-single-invoice .row {
  display: flex;
  gap: 5px;
  justify-content: space-evenly;
  flex-direction: row;
  margin: 10px;
}

.main-container-single-invoice .column {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
  text-align: center;
}

.main-container-single-invoice .singleInvoiceContainer {
  display: flex;
  flex-direction: column;
  border-radius: var(--cm-radius-xl);
  background: var(--cm-bg-surface);
  border: solid 1px var(--cm-border);
  padding: 20px;
}

.main-container-single-invoice .singleInvoiceContainer label {
  font-weight: var(--cm-fw-bold);
  text-align: left;
  width: 100%;
  color: var(--cm-text-heading);
  padding: 0px;
  margin: 0px;
}

.main-container-single-invoice .payInput {
  height: 30px;
  width: 100%;
  border: 1px solid var(--cm-border);
  border-radius: var(--cm-radius-sm);
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-regular);
  background: var(--cm-bg-muted);
  color: var(--cm-text-body);
  transition: all 0.15s ease;
  text-align: left;
  vertical-align: middle;
}

.main-container-single-invoice .invoiceInfoTable {
  border-spacing: 15px;
}

.main-container-single-invoice .invoiceInfoTable td {
  text-align: left;
  vertical-align: middle;
}

.main-container-single-invoice .dividerRow {
  border-bottom: 1px solid var(--cm-border-strong);
  border-collapse: collapse;
  width: 100%;
  vertical-align: middle;
}

/* ---------- Toast/banner positioning override (shared layer ships the
   look — error/warning/info/success — but portal floats them above page
   content rather than rendering inline).

   Default-hidden: the legacy banners ship their text from JS (index.js
   displaySuccess/displayError/etc set `display: block` inline before
   populating .messageText). Without this baseline they render at
   page-load with empty text — but the absolute-positioned .closebtn
   still paints, so the user sees a stray "X" near the top of the page.
   Matches the request-site pattern (.fail / .warning / .info /
   .success default to display: none in request/stylesheet.css). ---------- */

.error,
.warning,
.info,
.success {
  display: none;
  position: absolute;
  top: 10%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 999999;
}

/* ---------- Page footer ----------
   The reCAPTCHA v3 badge is fixed-positioned bottom-right by Google's
   api.js (~80px tall). The portal page-footer is a dark band that the
   badge would otherwise overlap at narrower widths. Bumping z-index puts
   the footer above the badge so footer text is never clipped, and 90px
   of bottom padding on .page-container ensures the badge floats over the
   page background rather than the footer when content is tall enough to
   scroll. (Automate-i98f.2.12)

   Note: position: relative (replacing the prior `bottom: 0` with no
   position which had no effect) gives the footer a stacking context so
   z-index applies. */
.page-footer {
  position: relative;
  z-index: 2;
  width: 100%;
  background-color: var(--cm-bg-sidebar);
  color: var(--cm-text-on-dark);
  text-align: center;
  padding: 10px;
  box-sizing: border-box;
  box-shadow: 0 -6px 2px 1px var(--cm-bg-sidebar) !important;
}

/* Bottom breathing room so the recaptcha badge has clearance from the
   primary card on tall viewports + clearance from the footer on short
   ones. ~90px matches the badge's rendered height. */
.page-container {
  padding-bottom: 90px;
}

.page-footer h4,
.page-footer p {
  /* Override stylesheetv3.css's `* { color: var(--text-color); }` reset, which
     would otherwise leave footer text rendering as body text on the dark
     surface (slate-700 on slate-900 = 1.72:1 fail). Anchor to text-on-dark. */
  margin: 0px;
  padding: 5px;
  font-size: 10pt;
  color: var(--cm-text-on-dark);
}

/* v3 ships `#navbar i, a { color: var(--dark-text-color); }` which paints
   anchors white — fine on dark navbar / footer, but inline links inside a
   light `.page-container` (e.g. forgot-password.html's mailto, login.html's
   "Forgot Password?") become invisible on white card surfaces. Pin to
   --cm-interactive-active (teal-700, ~5.47:1 on white) and bump to teal-900
   on hover/focus. Skips .button anchors so styled CTAs (like a future "Back
   to Sign In" button-link) keep their button paint. */
.page-container p a:not(.button) {
  color: var(--cm-interactive-active);
  text-underline-offset: 2px;
}

.page-container p a:not(.button):hover,
.page-container p a:not(.button):focus-visible {
  color: var(--cm-teal-900);
}

.page-footer a {
  color: var(--cm-text-on-dark);
}

.titleRow {
  width: 100%;
  text-align: center;
}

.titleShadow {
  box-shadow: inset 10px 0px 0px 0px var(--cm-interactive);
  padding: 20px;
}

.downloadButtonContainer {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
}

/* ---------- /portal/app.html search/filter inputs ---------- */

.inputTable {
  text-align: center;
  width: 100%;
  border-collapse: collapse;
  max-width: 100%;
  padding: 10px;
}

.inputTable input {
  height: 35px;
  padding: 0px 0px 0px 10px;
  appearance: none;
  width: 80%;
  border: 1px solid var(--cm-border-strong);
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-regular);
  background: var(--cm-bg-surface);
  border-radius: var(--cm-radius-sm);
  color: var(--cm-text-body);
  transition: all 0.15s ease;
  text-align: left;
  line-height: 25px;
}

.filterButton {
  background-image: none;
  color: var(--cm-text-body);
  border-radius: var(--cm-radius-lg);
  border-style: none;
  box-sizing: border-box;
  cursor: pointer;
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-bold);
  height: 35px;
  padding: 0 1.6rem;
  text-align: center;
  transition: all 0.5s;
  user-select: none;
  box-shadow: var(--cm-shadow-sm);
}

.filterButton.selected {
  background-image: linear-gradient(92.88deg, var(--cm-teal-700) 0%, var(--cm-teal-900) 80%);
  color: var(--cm-text-on-dark);
}

.filterButton.unselected {
  background-image: none;
  color: var(--cm-text-body);
  box-shadow: var(--cm-shadow-md);
}

/* Filter buttons keep their click semantics on focus too — surface a visible
   focus ring so keyboard users see the active control. */
.filterButton:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

/* ---------- /portal/app.html search form (Phase 2.5 — Automate-i98f.2.6)
   The page used to use <table class="inputTable"> as a layout container
   for 5 placeholder-only inputs; the leaf refresh promotes it to a real
   <form> with .field children. Inputs themselves inherit the global
   v3 input rules + the .field wrapper renders the uppercase label. */

.search-form {
  display: flex;
  flex-direction: column;
  gap: var(--cm-space-3);
  width: 100%;
}

.search-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--cm-space-3);
  width: 100%;
}

.search-fields .field {
  margin-bottom: 0;
}

.search-fields .field input {
  height: 35px;
  padding: 0 var(--cm-space-2);
  border: 1px solid var(--cm-border-strong);
  border-radius: var(--cm-radius-sm);
  background: var(--cm-bg-surface);
  color: var(--cm-text-body);
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-regular);
  transition: all 0.15s ease;
}

.search-fields .field input:focus-visible {
  outline: none;
  box-shadow: var(--cm-focus-ring);
}

.search-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--cm-space-3);
}

/* ---------- /portal/app.html actions dropdown — keyboard-open state ----------
   The shared .actions-dropdown uses :hover to open .action-content (CSS-only,
   fails WCAG 2.1.1 keyboard). app.js toggles a .open class on the container
   when the trigger is activated via Enter/Space; this rule surfaces the menu
   while .open is set so keyboard users see it. */
.actions-dropdown.open .action-content {
  display: block;
}

/* ---------- /portal/app.html pagination icon buttons ----------
   Prev/next pagination used to be raw <i class="fa-..."> glyphs; the leaf
   refresh wraps each in a real <button> for keyboard reachability + a real
   aria-label. This rule strips the default button chrome so the visual
   matches the prior icon-only look, and provides a focus ring + disabled
   styling so the state of the control is visible. */
.pagination-icon-button {
  background: transparent;
  border: 0;
  padding: 4px 8px;
  font-size: 30px;
  color: var(--cm-text-on-dark);
  cursor: pointer;
  border-radius: var(--cm-radius-sm);
  line-height: 1;
}

.pagination-icon-button:hover {
  background: rgba(255, 255, 255, 0.08);
}

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

.pagination-icon-button:disabled,
.pagination-icon-button[disabled] {
  color: var(--cm-text-muted);
  cursor: default;
  background: transparent;
}

/* ---------- a11y helpers ----------
   .visually-hidden hides text from sighted users while keeping it in the
   accessibility tree (used by /portal/app.html for the <h1> and the
   results <caption>). Equivalent to the canonical Bootstrap/HTML5BP rule. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- /portal/login.html — auth card (Phase 2.6) ----------
   Login page now hosts 4 view states (Sign In / Set Password / 2FA Enroll /
   2FA Verify) inside the same card chrome. Patterns:

   - .auth-card narrows the .container max-width to 440px (focused auth feel
     vs landing's 560px),
   - .auth-form lays out fields stacked + full-width with a consistent gap,
   - .auth-field replaces the old .row > label / .row > input pattern so the
     label sits flush-left above its input with no centered-flex weirdness,
   - .auth-submit caps primary CTA width inside the card while staying
     full-width on mobile,
   - .auth-secondary holds the inline "Forgot password?" / "Back to sign in"
     links and uses .page-container p a teal pin from above,
   - .auth-steps renders a small numbered breadcrumb above multi-step views,
   - .password-input-wrap + .password-toggle mounts an FA eye icon inside
     password inputs (toggles between fa-eye and fa-eye-slash via JS),
   - .qr-frame wraps the 2FA QR code in a soft surface with a caption,
   - .otp-input centers + monospaces the 2FA code input.
   (Automate-i98f.2.13 / .2.14 / .2.15) */

/* Tighter max-width for auth (440 vs 560 landing). Single-column form +
   short copy doesn't need the same breathing room as the landing's tile
   grid. */
.container.auth-card {
  max-width: 440px;
  padding: 32px 40px;
  align-items: stretch;
}

/* Tighten the gap between the heading block and the form inside auth-card —
   the global 32px margin-bottom from .header-div leaves too much air above
   a single short form. Scoped so the landing's tile grid keeps its room. */
.container.auth-card .header-div {
  margin-bottom: 16px;
}

/* Stacked, full-width form. Replaces the legacy row/column wrappers from
   stylesheetv3 which centered children and content-sized inputs. */
.auth-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.auth-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
}

/* Override v3's `* { color: var(--text-color) }` reset so labels match the
   form heading weight + don't render light grey on the white card. */
.auth-field label {
  font-size: var(--cm-text-sm);
  font-weight: var(--cm-fw-semibold);
  color: var(--cm-text-heading);
  text-align: left;
  margin: 0;
}

/* Full-width inputs inside the card, with a height bump (40 vs v3's 36) to
   match modern auth surfaces. */
.auth-form input[type='email'],
.auth-form input[type='password'],
.auth-form input[type='text'] {
  width: 100%;
  height: 40px;
  font-size: var(--cm-text-base);
}

/* Real-time validation hint (e.g., "Enter a valid email"). Default empty;
   .is-invalid on the input flips both border + hint to red. */
.auth-field-hint {
  margin: 0;
  min-height: 1em;
  font-size: var(--cm-text-xs);
  color: var(--cm-text-muted);
  text-align: left;
}

.auth-form input.is-invalid {
  border-color: var(--cm-danger, #b91c1c);
}

.auth-form input.is-invalid + .auth-field-hint,
.auth-field-hint.is-invalid {
  color: var(--cm-danger, #b91c1c);
}

/* Inline form-level error (above the submit button). Hidden by default;
   login.js sets .hidden = false + textContent to surface. */
.auth-form-error {
  margin: 0;
  padding: 10px 12px;
  background: rgba(185, 28, 28, 0.08);
  border-left: 3px solid var(--cm-danger, #b91c1c);
  border-radius: var(--cm-radius-sm);
  color: var(--cm-danger, #b91c1c);
  font-size: var(--cm-text-sm);
  text-align: left;
}

.auth-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
  margin-top: 4px;
}

/* Primary CTA inside the auth card. Full-width on mobile, capped on
   desktop to mirror the landing's CTA treatment. Height bumped to match
   the input height so the form reads as a unit. */
.auth-form .auth-submit,
.container.auth-card .auth-submit {
  width: 100%;
  height: 44px;
  font-size: var(--cm-text-base);
  font-weight: var(--cm-fw-semibold);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

/* Loading state: replace label with spinner + disable. login.js sets
   .loading on the button and toggles aria-busy. The spinner is a CSS-only
   FA-style ring (no extra glyph needed). */
.auth-submit.loading {
  cursor: progress;
  opacity: 0.85;
}

.auth-submit.loading::before {
  content: '';
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: auth-spin 0.7s linear infinite;
}

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

/* Tertiary link row under the submit (Forgot password / Back to sign in).
   Override .page-container p a teal pin still applies — these inherit it. */
.auth-secondary {
  margin: 0;
  text-align: center;
  font-size: var(--cm-text-sm);
}

/* Forgot Password body copy — single paragraph centered inside the auth
   card. Without this, the paragraph inherits .container's flex centering
   and reads as floating mid-card. */
.container.auth-card .forgot-body {
  margin: 0;
  text-align: center;
  font-size: var(--cm-text-base);
  color: var(--cm-text-body);
}

/* Step indicator above multi-step view states. Compact pill row that reads
   "Sign in › Set password" with the current step weighted. Mirrors the
   patient/authorization wizard's <ol class="steps"> pattern in feel. */
.auth-steps {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  list-style: none;
  margin: 0 0 4px 0;
  padding: 0;
  font-size: var(--cm-text-xs);
  color: var(--cm-text-muted);
}

.auth-steps .step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.auth-steps .step + .step::before {
  content: '›';
  margin-right: 6px;
  color: var(--cm-text-muted);
}

.auth-steps .step.is-current {
  color: var(--cm-text-heading);
  font-weight: var(--cm-fw-semibold);
}

.auth-steps .step.is-complete {
  color: var(--cm-interactive-active);
}

/* Password input + visibility toggle. The toggle is absolutely positioned
   inside the wrap so the input fills the row width. Padding-right on the
   input reserves space so typed characters don't slide under the button. */
.password-input-wrap {
  position: relative;
  width: 100%;
}

.password-input-wrap input {
  padding-right: 44px;
}

.password-toggle {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  color: var(--cm-text-muted);
  cursor: pointer;
  border-radius: var(--cm-radius-sm);
}

.password-toggle:hover {
  color: var(--cm-text-body);
}

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

/* QR code frame for 2FA enrollment. Soft surface + caption so the canvas
   reads as "scan this" not a raw bitmap. */
.qr-frame {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin: 4px 0;
  padding: 16px;
  background: var(--cm-bg-muted);
  border-radius: var(--cm-radius-md);
  border: 1px solid var(--cm-border);
}

.qr-frame #qrEnrollmentBarcode {
  background: #ffffff;
  padding: 8px;
  border-radius: var(--cm-radius-sm);
  display: inline-flex;
}

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

/* OTP input — centered text, monospace, large characters with letter
   spacing so individual digits are easy to read at a glance. Single-input
   pattern (vs 6-box) keeps the autocomplete=one-time-code flow simple. */
.auth-form input.otp-input {
  text-align: center;
  font-family: var(--cm-font-mono, 'SFMono-Regular', Menlo, Consolas, monospace);
  font-size: var(--cm-text-xl);
  letter-spacing: 0.4em;
  height: 48px;
}

@media (max-width: 600px) {
  .container.auth-card {
    max-width: 100%;
  }

  .auth-form .auth-submit,
  .container.auth-card .auth-submit {
    height: 48px;
  }
}
