/*
 * Bedrock design tokens — structural scale (type, spacing, radius, shadow,
 * z-index). Colors are NOT defined here; they're owned entirely by the
 * palette block at the top of styles.css (light default + dark via
 * prefers-color-scheme + explicit [data-theme] override). Standalone app —
 * no external package dependency, safe to eject as-is.
 */

:root {
  color-scheme: light dark;

  --text-xs: 11px;
  --text-sm: 13px;
  --text-base: 15px;
  --text-md: 16px;
  --text-lg: 18px;
  --text-xl: 22px;
  --text-2xl: 28px;
  --text-3xl: 36px;

  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  --leading-tight: 1.2;
  --leading-normal: 1.5;
  --leading-relaxed: 1.7;

  /* ---- spacing (padding, gap, and margin all draw from this one scale) ---- */
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;

  /* ---- radius ---- */
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-full: 999px;

  /* ---- shadow ---- */
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12);
  --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.18);
  --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.28);

  /* ---- z-index scale — pick from here instead of inventing a number ---- */
  --z-dropdown: 10;
  --z-sticky: 20;
  --z-overlay: 100;
  --z-modal: 200;
  --z-toast: 300;
  --z-max: 2147483000;

  /* ---- motion (2026-08-02 UI polish pass, MVP.md §10) — one shared
     vocabulary so every hover/press/enter feels like the same tool, not a
     collection of screens. --duration-fast for hover/press feedback,
     --duration-base for things entering/leaving (modals, dropdowns,
     revealed sections). prefers-reduced-motion is already handled
     globally in styles.css. ---- */
  --duration-fast: 120ms;
  --duration-base: 180ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.35);
    --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.5);
  }
}

:root[data-theme="dark"] {
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.5);
}

:root[data-theme="light"] {
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12);
  --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.18);
  --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.28);
}

/* ---- Bedrock identity, layered over the shared platform tokens ----
   Design brief: an insurance agency's paper-folder filing system, digitized.
   Every customer used to be a manila folder in a drawer; the signature
   device here — a colored tab down the left spine of each customer card —
   is that same folder tab, carrying real information (renewal urgency)
   instead of decoration. Cool steel-ledger paper in light mode, ink-slate
   in dark. Newsreader (serif, sparing use) for headers with some editorial
   authority; Public Sans — a government-forms face — for UI chrome, apt
   for ACORD-adjacent paperwork; Space Mono for every data field (policy
   numbers, dates, phone) so they read like stamped ledger entries, not
   generic app text.

   --color-text-muted (2026-08-02, contrast pass): most of the actual
   audience is 40-60yo agents, not designers — the original muted gray
   (#5B6660 light / #9AA6A0 dark) measured 4.58:1 against the raised
   surface, barely over the 4.5:1 AA floor for normal text and not a
   comfortable margin for smaller labels/dates. Darkened (light theme)
   and lightened (dark theme, already decent but given the same margin)
   to a real ~7:1+ (AAA-range) against every surface it's used on. */
:root {
  --font-display: 'Newsreader', ui-serif, Georgia, serif;
  --font-sans: 'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'Space Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --color-bg: #E9ECE6;
  --color-surface: #FFFFFF;
  --color-surface-raised: #DEE3DA;
  --color-border: #C7CEC2;
  --color-text: #1C2321;
  --color-text-muted: #3A4440;
  --color-accent: #1B3A5C;
  --color-accent-contrast: #FFFFFF;
  --color-link: #1B3A5C;
  --color-ok: #3E7C4A;
  --color-warn: #A9631B;
  --color-danger: #A3372B;
  --color-stamp: #A9631B;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #14181A;
    --color-surface: #1C2224;
    --color-surface-raised: #242B2D;
    --color-border: #343C3E;
    --color-text: #E9ECE8;
    --color-text-muted: #ADB8B1;
    --color-accent: #7FA8D9;
    --color-accent-contrast: #0F1417;
    --color-link: #7FA8D9;
    --color-ok: #6FBF7E;
    --color-warn: #D9A15A;
    --color-danger: #E08579;
    --color-stamp: #D9A15A;
  }
}

:root[data-theme="dark"] {
  --color-bg: #14181A;
  --color-surface: #1C2224;
  --color-surface-raised: #242B2D;
  --color-border: #343C3E;
  --color-text: #E9ECE8;
  --color-text-muted: #ADB8B1;
  --color-accent: #7FA8D9;
  --color-accent-contrast: #0F1417;
  --color-link: #7FA8D9;
  --color-ok: #6FBF7E;
  --color-warn: #D9A15A;
  --color-danger: #E08579;
  --color-stamp: #D9A15A;
}

:root[data-theme="light"] {
  --color-bg: #E9ECE6;
  --color-surface: #FFFFFF;
  --color-surface-raised: #DEE3DA;
  --color-border: #C7CEC2;
  --color-text: #1C2321;
  --color-text-muted: #3A4440;
  --color-accent: #1B3A5C;
  --color-accent-contrast: #FFFFFF;
  --color-link: #1B3A5C;
  --color-ok: #3E7C4A;
  --color-warn: #A9631B;
  --color-danger: #A3372B;
  --color-stamp: #A9631B;
}

* {
  box-sizing: border-box;
}

html, body, #root {
  height: 100%;
  margin: 0;
}

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--color-link);
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ---- UI polish pass (2026-08-02, MVP.md §10) — one shared motion
   vocabulary instead of one-off transitions per component. Every
   clickable control gets the same subtle state-change feel; a second,
   slightly slower group covers things entering the screen (cards, rows).
   Kept deliberately quiet — color/border/shadow shifts and a hairline
   press, nothing that draws attention to itself. ---- */
button,
a,
input,
select,
textarea {
  transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease,
    color var(--duration-fast) ease, box-shadow var(--duration-fast) ease,
    opacity var(--duration-fast) ease, filter var(--duration-fast) ease,
    transform var(--duration-fast) ease;
}

button:active:not(:disabled) {
  transform: scale(0.97);
}

.customer-card,
.policy-row,
.admin-card,
.review-doc-row,
.match-option,
.upload-progress-row {
  transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease,
    box-shadow var(--duration-fast) ease, transform var(--duration-fast) ease;
}

.app {
  display: flex;
  flex-direction: column;
  height: 100%;
  position: relative;
}

/* ---- impersonation banner (App.jsx — was in components/admin/admin.css,
   which the app bundle never loads, so this rendered fully unstyled for
   every impersonated session; moved here, the stylesheet main.jsx
   actually imports, John 2026-08-02). Exit is red (a destructive-feeling
   "leave this session" action, not a neutral one) with real gap from the
   text next to it. */
.impersonation-banner {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky, 20);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  padding: var(--space-2) var(--space-3);
  background: var(--color-stamp);
  color: var(--color-accent-contrast);
  font-size: var(--text-sm);
  text-align: center;
}

.impersonation-banner button {
  background: var(--color-danger);
  color: var(--color-accent-contrast);
  border: none;
  border-radius: var(--radius-sm, 4px);
  padding: var(--space-1) var(--space-3);
  font-weight: var(--font-weight-medium);
  flex-shrink: 0;
}

.impersonation-banner button:hover {
  filter: brightness(1.1);
}

/* ---- desktop-agent download nudge (App.jsx, 2026-08-07) — deliberately
   calm: raised surface + a thin accent rule underneath, not a colored
   alert bar. This is an invitation to a useful feature, not a warning, so
   it shouldn't compete visually with the (much rarer, much more urgent)
   impersonation banner above it. Disappears entirely once any user in the
   company has a device — never a dismiss button to wire up/persist. */
.desktop-agent-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--color-surface-raised);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-align: center;
}

.desktop-agent-banner a {
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
}

/* AccountPanel.jsx's stronger "no coverage at all" CTA — same idea, list
   context instead of a full-width bar, so it reads as a plain paragraph
   with a bit more presence than the quiet .subtitle sibling it replaces. */
.download-cta {
  font-size: var(--text-sm);
  color: var(--color-text);
  background: var(--color-surface-raised);
  border-left: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
}

/* ---- header ---- */
.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface);
}

.app-header-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  flex-shrink: 0;
}

.app-header h1 {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--font-weight-semibold);
  letter-spacing: -0.01em;
  color: var(--color-accent);
  white-space: nowrap;
  /* Without this, the h1's inherited line-height (1.5) makes its line box
     much taller than the LogoMark svg next to it — align-items: center
     on .app-header-brand centers the two boxes correctly, but the glyphs
     inside that tall, asymmetric line box don't sit centered within it,
     so the icon and the text read as misaligned even though the boxes
     technically are (John, 2026-08-02: "logo and the title don't
     align"). line-height: 1 collapses the box to the glyphs themselves. */
  line-height: 1;
}

.app-header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 1;
  min-width: 0;
}

/* ---- mobile: shrink the header chrome a bit so the brand + 5 icon
   buttons stay comfortable at narrow widths. The old text buttons here
   ("LOG OUT" wrapping mid-word, found via 390px screenshot 2026-08-02;
   still overflowing off-screen even after that fix) are gone — replaced
   with fixed-size icon buttons (.icon-btn) that don't need font-size
   shrinking tricks to fit. ---- */
@media (max-width: 480px) {
  .app-header {
    padding: var(--space-2) var(--space-3);
    gap: var(--space-2);
    /* Was nowrap-only, tuned before the SearchModeToggle pill existed
       (2026-08-07 fix, John: "header and search features are going off
       the side of the screen") — the toggle plus all 5 icon buttons
       genuinely don't fit on one line at 390px/360px no matter how tight
       the gaps get, so this now allows the whole header to wrap to a
       second line rather than spill horizontally past the viewport —
       same "stack instead of cram" mobile pattern already used
       elsewhere in this file (.results/.search-bar-wrap's own comment).
       This was also the root cause of a second, subtler bug: real
       horizontal document overflow from this row was pushing the
       browser's effective mobile layout width wider than the true
       viewport, which was ALSO throwing off the fixed-position search
       bar's own sizing even after its own unrelated min-width fix. */
    flex-wrap: wrap;
  }

  .app-header h1 {
    font-size: var(--text-lg);
  }

  .app-header-actions {
    gap: var(--space-1);
    flex-wrap: wrap;
    justify-content: flex-end;
  }
}

/* ---- header icon buttons (2026-08-03) — theme/feedback/account/logout,
   replacing small uppercase-mono text buttons that overflowed the header
   at mobile widths (John: "too small... make sure hover shows a
   tooltip"). Same square-icon-button shape as .upload-status below (kept
   in sync — both bumped from 36px to 40px together, "bigger so users can
   clearly see them"), native title attribute for the hover tooltip
   rather than a custom component, matching UploadStatus.jsx's existing
   pattern. Icon glyphs are Font Awesome (@fortawesome/react-fontawesome +
   free-solid-svg-icons). ---- */
.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  color: var(--color-text);
  font-size: 18px;
  flex-shrink: 0;
}

.icon-btn:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

/* Log out / sign out is the one icon-btn that hints red on hover instead
   of accent-blue — a leaving action, not neutral like theme/feedback/
   account (used in both the main app header and AdminPanel's). */
.icon-btn-danger:hover {
  border-color: var(--color-danger);
  color: var(--color-danger);
}

/* ---- document upload status indicator (App.jsx header) ---- */
.upload-status {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  color: var(--color-text-muted);
}

.upload-status svg {
  width: 20px;
  height: 20px;
}

.upload-status:disabled {
  opacity: 1;
  cursor: default;
}

.upload-status-uploading,
.upload-status-processing {
  border-color: currentColor;
  cursor: pointer;
}

.upload-status-uploading:hover,
.upload-status-processing:hover {
  filter: brightness(1.15);
}

.upload-status-uploading { color: var(--color-ok); }
.upload-status-processing { color: var(--color-link); }
.upload-status-idle { color: var(--color-ok); cursor: pointer; }

.upload-status-idle:hover {
  border-color: var(--color-ok);
  background: color-mix(in srgb, var(--color-ok) 12%, var(--color-surface-raised));
}

.upload-status-attention {
  color: var(--color-accent-contrast);
  background: var(--color-danger);
  border-color: var(--color-danger);
  cursor: pointer;
}

.upload-status-attention svg circle:first-child {
  fill: var(--color-danger);
}

.upload-status-attention rect,
.upload-status-attention circle:not(:first-child) {
  fill: var(--color-accent-contrast);
}

.upload-status-attention:hover {
  filter: brightness(1.08);
}

.upload-status-spinner {
  animation: upload-status-spin 900ms linear infinite;
}

.upload-status-spinner circle {
  stroke: currentColor;
}

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

@media (prefers-reduced-motion: reduce) {
  .upload-status-spinner { animation: none; }
}

.upload-status-count {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border-radius: var(--radius-full, 999px);
  background: var(--color-danger);
  color: var(--color-accent-contrast);
  font-size: 10px;
  font-family: var(--font-mono);
  line-height: 16px;
  text-align: center;
  border: 2px solid var(--color-surface);
  animation: badge-pop var(--duration-base) var(--ease-out);
}

@keyframes badge-pop {
  from { transform: scale(0); }
  to { transform: scale(1); }
}

/* ---- results area ---- */
.results {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4);
  padding-bottom: calc(var(--space-4) + 108px);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Graph search's secondary tier (2026-08-04) — customers reached only via
   a shared phone number, deliberately NOT styled like a CustomerCard (no
   folder-tab, no policy list) so it reads as "maybe, click to check" and
   never gets mistaken for a confirmed part of the main result group. */
.related-via-phone {
  border-top: 1px dashed var(--color-border);
  padding-top: var(--space-3);
  margin-top: var(--space-2);
}

.related-via-phone-label {
  display: block;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: var(--space-2);
}

.related-via-phone-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.related-via-phone-link {
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text);
}

.related-via-phone-link:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.results-empty {
  color: var(--color-text-muted);
  text-align: center;
  margin-top: var(--space-6);
  font-size: var(--text-sm);
  max-width: 32ch;
  margin-left: auto;
  margin-right: auto;
}

/* Home-page empty-state stat (2026-08-03) — "# Policies over #
   Customers", shown only when no search term is present. Own font size
   (not constrained to .results-empty's 32ch/text-sm), same muted color. */
.results-stat {
  font-size: var(--text-xl);
  color: var(--color-text);
  margin-bottom: var(--space-3);
}

.results-stat strong {
  font-weight: var(--font-weight-bold);
  color: var(--color-accent);
}

/* PniGroup.jsx/PniView.jsx (graph search's default results + the PNI
   click-through pivot) deliberately have NO styling of their own
   (2026-08-05, John: "literally what we had before was perfect... let's
   change these results to look like the classic results") — both reuse
   .customer-card/.customer-card-header/.policy-list etc. directly. See
   those components for how. */

/* ---- customer card: the folder-tab signature ----
   A solid spine down the left edge stands in for a manila folder's tab.
   Its color is load-bearing, not decorative: green = nothing due soon,
   amber = a policy renews within 30 days, red = something's already
   lapsed. --tab-color is set inline per card from real policy data. */
.customer-card {
  --tab-color: var(--color-border);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 5px solid var(--tab-color);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
}

.customer-card:hover {
  box-shadow: var(--shadow-sm);
}

.customer-card-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  cursor: pointer;
}

.customer-card-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-3);
}

/* Left column: name + address stacked, address on the same row as the
   phone number in the right-hand .customer-card-meta column (John,
   2026-08-02 — previously its own full-width line under everything;
   before that, inside the right column, where a long address wrapped
   badly and read as clutter). min-width: 0 lets the name/address ellide
   instead of forcing the card wider. */
.customer-card-left {
  min-width: 0;
  flex: 1;
}

.customer-card-header:hover .customer-card-name {
  color: var(--color-accent);
}

.customer-card-name {
  font-weight: var(--font-weight-semibold);
  font-size: calc(var(--text-md) * var(--results-scale, 1));
  transition: color var(--duration-fast) ease;
}

/* Space Mono here (and nowhere in a policy row anymore — see below) is
   deliberate: John, 2026-08-02 — this distinctive treatment on the
   customer-level info is "what makes the profile stand out visually...
   easier to visually identify a profile vs. something else (like a
   policy)." Policies get a plain, fast-to-scan font instead — the
   CONTRAST between the two is the point, not just readability alone. */
.customer-card-meta {
  text-align: right;
  color: var(--color-text-muted);
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  font-family: var(--font-mono);
  flex-shrink: 0;
}

.customer-card-meta div {
  white-space: nowrap;
}

.customer-card-merge {
  margin-top: var(--space-2);
}

.customer-card-merge .btn-outline {
  font-family: var(--font-sans);
}

.customer-card-policy-count {
  color: var(--color-text);
  font-weight: var(--font-weight-medium);
}

.customer-card-address {
  font-family: var(--font-mono);
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  color: var(--color-text-muted);
}

/* Identities (2026-08-06) — click-to-edit placeholder/input styling shared
   by PhonePickerModal.jsx's text input and EditableAddress.jsx (a
   policy's PNI mailing address). Sized/positioned to sit inline with the
   plain text it replaces, not a full form input. */
.editable-placeholder {
  font-style: italic;
  opacity: 0.6;
}

/* A filled-in editable value (a phone number, a mailing address once
   set) previously had zero visual cue that it was clickable — read as
   plain static text, same as any other label on the card, with no way
   to tell it apart from something you can't edit (2026-08-08 polish
   pass). Dotted rather than solid underline deliberately — distinct
   from a real navigational link (solid underline, .policy-row-detail a
   above) so "click to edit" and "click to go somewhere" read as two
   different affordances, not the same one twice. */
.editable-value {
  cursor: pointer;
  border-bottom: 1px dotted var(--color-text-muted);
}

.editable-value:hover {
  border-bottom-color: var(--color-accent);
  color: var(--color-accent);
}

.editable-field-input {
  font: inherit;
  color: inherit;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-1);
  width: 12em;
  max-width: 100%;
}

/* A policy's mailing address (2026-08-06, EditableAddress.jsx) — four
   narrow fields inline instead of one wide one, matching the same
   street/city/state/zip shape DocumentEditor.jsx already edits. */
.editable-address-fields {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  align-items: center;
}

.editable-address-fields .editable-field-input {
  width: 9em;
}

.editable-address-fields .editable-field-input-state {
  width: 4em;
}

.editable-address-fields .editable-field-input-zip {
  width: 5.5em;
}

.policy-list {
  margin-top: var(--space-3);
  border-top: 1px dashed var(--color-border);
  padding-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  animation: reveal-down var(--duration-base) ease;
}

.policy-row {
  background: var(--color-surface-raised);
  border-radius: var(--radius-sm, 6px);
  padding: var(--space-2) var(--space-3);
}

.policy-row:hover {
  box-shadow: var(--shadow-sm);
}

.policy-row-archived {
  opacity: 0.6;
}

.policy-row-actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-1);
}

/* Real buttons, not underlined links (John, 2026-08-02: controls should
   read as controls) — border + surface fill instead of link styling,
   same hover convention as .modal-actions .secondary elsewhere. */
.btn-outline {
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm, 6px);
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-sm);
  /* Used inside flex ROWS (.policy-row-actions) and flex COLUMNS
     (.policy-list, for the merge button) — without this, a column
     context stretches it to the full container width by default. */
  align-self: center;
}

.btn-outline:hover:not(:disabled) {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.btn-outline:disabled {
  opacity: 0.6;
}

/* Policies switch to the plain UI sans (John, 2026-08-02: "highly easy
   to read, easy visual processing" — Space Mono's personality is right
   for the sparse customer-level info above, wrong for a denser list of
   policies someone's actually scanning). Hierarchy now comes from
   weight/size/color instead of font-family: carrier bold and a touch
   larger, policy number smaller and lighter right next to it, policy
   type centered, exp date bold and floated right.

   Grid, plain (no subgrid/display:contents — 2026-08-02: tried sharing
   the carrier column across rows via subgrid + a display:contents
   .policy-row-summary; real-world testing turned up rows silently not
   filling the card and a later padding change not visibly applying,
   most likely browser-specific subgrid/contents edge cases. Reverted to
   this: every row is its own ordinary grid, and column 1 reads
   --carrier-col-width, a plain px value CustomerCard.jsx measures across
   every carrier span in the list (scrollWidth, so it survives that
   span's own overflow:hidden) and writes onto the list container via
   ref.style.setProperty — plain CSS custom property inheritance then
   gives every row in the list the identical value. Ordinary grid/var()/
   calc(), no exotic layout features, so it behaves the same everywhere.
   Column 3 (type) is the flexible one — it absorbs whatever width is
   left so every row still fills the full card width, the same job
   carrier's old 1fr used to do; its minimum is the old fixed width so it
   never gets narrower than before. Column 2 (number) works the same way
   as column 1 — --number-col-width, measured alongside carrier width in
   CustomerCard.jsx — instead of a fixed px width, so a long policy
   number is never truncated (John, 2026-08-02). */
.policy-row-summary {
  display: grid;
  grid-template-columns: minmax(0, var(--carrier-col-width, max-content)) minmax(0, var(--number-col-width, max-content)) minmax(calc(64px * var(--results-scale, 1)), 1fr) calc(86px * var(--results-scale, 1));
  align-items: baseline;
  column-gap: var(--space-2);
  font-family: var(--font-sans);
  cursor: pointer;
  /* Baseline color for any child that isn't one of the specific
     .policy-row-carrier/-number/-type/-exp classes below (those override
     this). Without it, an unclassed child inherits whatever ambient
     color its container happens to be in. */
  color: var(--color-text);
}

/* Narrow screens: drop the policy-type column from the summary line
   entirely rather than let it and the carrier name both truncate to
   illegibility ("Fa...", "Umbr..." — found via a real 390px screenshot,
   2026-08-02). Type is still visible in the expanded detail below;
   carrier + policy number + date are the three things worth keeping on
   one line at this width. */
@media (max-width: 480px) {
  .policy-row-summary {
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--number-col-width, max-content)) calc(86px * var(--results-scale, 1));
  }

  .policy-row-type {
    display: none;
  }
}

.policy-row-summary:hover .policy-row-carrier {
  color: var(--color-accent);
}

.policy-row-carrier {
  font-weight: var(--font-weight-semibold);
  font-size: calc(var(--text-md) * var(--results-scale, 1));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: color var(--duration-fast) ease;
}

.policy-row-number {
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Pill tag, not plain text (John, 2026-08-02) — sized to its own content
   (justify-self: center, rather than stretching + text-align: center)
   so the border hugs the word instead of spanning the whole flexible
   column. Border only, no fill — the column already sits on the row's
   own surface color, so a filled pill would just be a second background
   competing with it. */
.policy-row-type {
  justify-self: center;
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  padding: 2px var(--space-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.policy-row-exp {
  font-weight: var(--font-weight-semibold);
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  white-space: nowrap;
  text-align: right;
  padding-right: var(--space-3);
}

/* "Exp." on its own is a label, not the fact itself — kept light/normal
   weight so the date it's attached to (still bold, on .policy-row-exp) is
   the thing the eye actually lands on (John, 2026-08-02: "preceeded by
   Exp. so the user understands", "beautiful AND easy to comprehend"). */
.policy-row-exp-label {
  font-weight: var(--font-weight-normal);
  color: var(--color-text-muted);
}

.policy-row-detail {
  margin-top: var(--space-2);
  font-family: var(--font-sans);
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  line-height: var(--leading-relaxed);
  color: var(--color-text);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2) var(--space-4);
  animation: reveal-down var(--duration-fast) ease;
}

.policy-row-label {
  display: block;
  font-size: calc(var(--text-xs) * var(--results-scale, 1));
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

.policy-row-detail-wide {
  grid-column: 1 / -1;
}

/* Lazy-loaded coverage/party/item detail fetch (2026-08-07) — brief,
   quiet, matches .policy-row-label's muted tone rather than a spinner. */
.policy-row-detail-loading {
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  color: var(--color-text-muted);
  font-style: italic;
}

/* Coverages/parties/vehicles lists (2026-08-03) — compact rows under a
   .policy-row-label heading, same shape as the label+value convention
   above but one row per list entry instead of one value. */
.policy-row-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 2px;
}

.policy-row-list-item {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
}

.policy-row-list-meta {
  font-size: calc(var(--text-xs) * var(--results-scale, 1));
  color: var(--color-text-muted);
}

@media (min-width: 640px) {
  .policy-row-detail {
    grid-template-columns: 1fr 1fr;
  }
}

@keyframes reveal-down {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

.policy-row-detail a,
.policy-row-detail .link-button {
  color: var(--color-link);
  font-size: calc(var(--text-sm) * var(--results-scale, 1));
  text-decoration: underline;
}

/* Button that should read as a plain inline link (PolicyRow.jsx's "View
   policy document" — opens a modal, so it can't be a real <a href>). */
.link-button {
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
}

/* ---- search-mode toggle (2026-08-04, experimental) ---- */
.search-mode-toggle {
  display: flex;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
  flex-shrink: 0;
}

.search-mode-toggle button {
  background: none;
  border: none;
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.search-mode-toggle button:not(:first-child) {
  border-left: 1px solid var(--color-border);
}

.search-mode-toggle button.active {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-weight: var(--font-weight-medium);
}

/* ---- advanced search field select (2026-08-07) — a small utility
   control, deliberately plain, sized to match the mode toggle beside it
   rather than getting its own visual treatment. ---- */
.advanced-search-select {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface);
  color: var(--color-text-muted);
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  flex-shrink: 0;
}

/* ---- infinite-scroll pagination (2026-08-07) ---- */
.load-more-sentinel {
  height: 1px;
}

.results-loading-more {
  text-align: center;
  padding: var(--space-3);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* ---- bottom chat input ---- */
.search-bar-wrap {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--space-3);
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}

.search-bar {
  display: flex;
  gap: var(--space-2);
}

.search-hint {
  text-align: center;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.search-bar input {
  flex: 1;
  /* Mobile overflow fix (2026-08-07, John: "header and search features
     are going off the side of the screen") — a flex item's default
     min-width is its own intrinsic content width, not 0, so `flex: 1`
     alone doesn't let this actually shrink below that on a narrow
     screen; the fixed-width Search button + FontSizeControl (flex-
     shrink: 0, 90px together) then push the whole bar past the
     viewport. min-width: 0 is what makes flex: 1 actually mean "take
     whatever's left," down to nothing if it has to. */
  min-width: 0;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3) var(--space-4);
  color: var(--color-text);
  font-size: var(--text-md);
}

.search-bar input:focus {
  outline: 2px solid var(--color-accent);
  outline-offset: -1px;
}

.search-bar button {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  border: none;
  border-radius: var(--radius-md, 8px);
  padding: 0 var(--space-4);
  font-weight: var(--font-weight-medium);
}

.search-bar button:hover {
  filter: brightness(1.1);
}

/* ---- search-results font-size control (John, 2026-08-02) ---- */
.font-size-control {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}

.font-size-control button {
  width: 44px;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  color: var(--color-text);
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.font-size-control button:first-child {
  border-radius: var(--radius-md, 8px) 0 0 var(--radius-md, 8px);
}

.font-size-control button:last-child {
  border-radius: 0 var(--radius-md, 8px) var(--radius-md, 8px) 0;
  border-left: none;
}

.font-size-control button svg {
  width: 18px;
  height: 18px;
}

.font-size-control button:hover:not(:disabled) {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.font-size-control button:disabled {
  opacity: 0.4;
}

/* ---- drop overlay ---- */
.drop-overlay {
  position: fixed;
  inset: 0;
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
  border: 3px dashed var(--color-stamp);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-semibold);
  color: var(--color-accent);
  z-index: var(--z-overlay, 40);
  pointer-events: none;
  animation: fade-in var(--duration-fast) ease;
}

/* ---- confirm modal ---- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 20, 18, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: var(--z-modal, 50);
  animation: fade-in var(--duration-fast) ease;
}

.modal-sheet {
  background: var(--color-surface);
  border-radius: var(--radius-lg, 12px);
  border-top: 3px solid var(--color-stamp);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 520px;
  max-height: 85vh;
  overflow-y: auto;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  animation: modal-sheet-in var(--duration-base) var(--ease-out);
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes modal-sheet-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.modal-sheet h2 {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--font-weight-semibold);
}

.field-row {
  display: flex;
  justify-content: space-between;
  font-size: var(--text-sm);
  gap: var(--space-3);
  border-bottom: 1px dashed var(--color-border);
  padding-bottom: var(--space-2);
}

.field-row span:first-child {
  color: var(--color-text-muted);
  font-family: var(--font-sans);
}

.match-option {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-2) var(--space-3);
}

.match-option:hover {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-sm);
}

.match-option button, .modal-actions button {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  border: none;
  border-radius: var(--radius-md, 8px);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
}

.match-option button:hover:not(:disabled), .modal-actions button:hover:not(:disabled) {
  filter: brightness(1.1);
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
}

.modal-actions .secondary {
  background: var(--color-surface-raised);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}

.modal-actions .secondary:hover:not(:disabled) {
  border-color: var(--color-accent);
  color: var(--color-accent);
  filter: none;
}

/* DocumentEditor.jsx's "Discard document" was sitting as plain .secondary
   — identical weight to "Reprocess"/"Close" right next to it, so a
   genuinely destructive action (removes the document) read as no more
   consequential than a safe one (2026-08-08 polish pass). Same
   explicit-opt-in .btn-danger convention already used for "Remove" in
   .user-row — not applied broadly, only to buttons that actually are
   destructive. */
.modal-actions .btn-danger {
  color: var(--color-danger);
  border-color: var(--color-danger);
}

.modal-actions .btn-danger:hover:not(:disabled) {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: var(--color-accent-contrast);
}

.status-badge {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm, 4px);
  background: var(--color-stamp);
  color: var(--color-accent-contrast);
  align-self: flex-start;
}

/* ---- mobile-first: base styles above are single-column and touch-sized
   already; layer up for wider screens ---- */
@media (min-width: 700px) {
  .results {
    max-width: 640px;
    margin: 0 auto;
    width: 100%;
  }

  .search-bar-wrap {
    max-width: 640px;
    margin: 0 auto;
    left: 0;
    right: 0;
  }
}

/* ---- auth screens: plain, quiet, no folder-tab flourish here — the
   signature belongs to the working CRM, not the login gate ---- */
.auth-screen {
  min-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}

.auth-card {
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.auth-card h1, .auth-card h2 {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  color: var(--color-accent);
  text-align: center;
}

.auth-card p.subtitle {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  text-align: center;
  margin-top: calc(-1 * var(--space-2));
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.field label {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.field-pair {
  display: flex;
  gap: var(--space-2);
}

.field-pair .field {
  flex: 1;
}

/* ---- desktop app download page (DownloadPage.jsx, 2026-08-07) ----
   Same centered, generous layout as .auth-screen but wider (this isn't a
   form, it's two side-by-side choices) and deliberately calmer — this
   page's one job is "pick your OS, get the file," nothing to second-guess.
   Cards reuse the folder-tab left-spine motif from .customer-card, here
   marking "which platform" instead of renewal urgency. */
.download-page {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-16) var(--space-4) var(--space-12);
  gap: var(--space-10);
}

.download-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
  max-width: 480px;
}

.download-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  color: var(--color-accent);
  margin-bottom: var(--space-4);
}

.download-hero h1 {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
  margin: 0;
}

.download-hero .subtitle {
  color: var(--color-text-muted);
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
  margin: 0;
}

.download-version {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  padding: var(--space-1) var(--space-3);
  margin-top: var(--space-2);
}

.download-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(220px, 260px));
  gap: var(--space-4);
  width: 100%;
  max-width: 860px;
}

@media (max-width: 860px) {
  .download-grid {
    grid-template-columns: repeat(2, minmax(220px, 280px));
    max-width: 600px;
  }
}

@media (max-width: 560px) {
  .download-grid {
    grid-template-columns: 1fr;
    max-width: 340px;
  }
}

.download-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--tab-color, var(--color-border));
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-5);
  text-decoration: none;
  color: inherit;
  transition: box-shadow var(--duration-fast) ease, transform var(--duration-fast) ease, border-color var(--duration-fast) ease;
}

.download-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.download-card:active {
  transform: translateY(0) scale(0.98);
}

.download-card-label {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
}

.download-card-detail {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  flex: 1;
}

.download-card-cta {
  font-family: var(--font-sans);
  font-weight: var(--font-weight-medium);
  font-size: var(--text-sm);
  color: var(--color-accent);
}

.download-card-cta::after {
  content: ' →';
}

.download-footnote {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  text-align: center;
  max-width: 420px;
  line-height: var(--leading-relaxed);
}

/* ---- company/user profile sections (AccountPanel.jsx, AdminMyProfile.jsx, 2026-08-02) ---- */
.company-profile-view {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
}

.company-profile-logo {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
  flex-shrink: 0;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
}

.company-profile-logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.company-profile-logo-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  color: var(--color-text-muted);
}

.company-profile-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.company-profile-name {
  font-family: var(--font-display);
  font-weight: var(--font-weight-semibold);
  font-size: var(--text-lg);
  margin-bottom: 2px;
}

.company-profile-info .btn-link {
  align-self: flex-start;
  margin-top: var(--space-1);
}

.user-profile-view {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.user-profile-name {
  font-weight: var(--font-weight-semibold);
}

.user-profile-view .btn-link {
  align-self: flex-start;
  margin-top: var(--space-1);
}

.field input {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3);
  color: var(--color-text);
  font-size: var(--text-md);
}

.field input:focus {
  outline: 2px solid var(--color-accent);
  outline-offset: -1px;
}

.btn-primary {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  border: none;
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3);
  font-size: var(--text-md);
  font-weight: var(--font-weight-medium);
}

.btn-primary:hover:not(:disabled) {
  filter: brightness(1.1);
}

.btn-primary:disabled {
  opacity: 0.6;
}

.btn-link {
  background: none;
  border: none;
  color: var(--color-link);
  font-size: var(--text-sm);
  text-decoration: underline;
  padding: 0;
  align-self: center;
}

.btn-link:hover {
  opacity: 0.7;
}

.auth-error {
  color: var(--color-danger);
  font-size: var(--text-sm);
  text-align: center;
  animation: fade-in var(--duration-base) ease;
}

.tier-picker {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.tier-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  text-align: left;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3);
  text-decoration: none;
  color: var(--color-text);
}

.tier-card:hover:not(:disabled) {
  border-color: var(--color-accent);
}

.tier-card:disabled {
  opacity: 0.6;
  cursor: default;
}

.tier-card-name {
  font-weight: var(--font-weight-semibold);
  font-size: var(--text-md);
}

.tier-card-range {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.tier-card-price {
  font-weight: var(--font-weight-semibold);
  color: var(--color-accent);
}

.tier-card-enterprise {
  border-style: dashed;
}

.tier-card-enterprise .tier-card-price {
  color: var(--color-text-muted);
  font-weight: var(--font-weight-normal);
}

.mfa-qr {
  align-self: center;
  border-radius: var(--radius-md, 8px);
  border: 1px solid var(--color-border);
}

/* ---- feedback modal (FeedbackModal.jsx, 2026-08-02) ---- */
.mic-meter {
  height: 16px;
  border-radius: var(--radius-full, 999px);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  overflow: hidden;
}

.mic-meter-fill {
  height: 100%;
  background: var(--color-ok);
  transition: width 80ms linear;
}

.feedback-recording {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-6) 0;
}

.feedback-recording-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-danger);
  animation: feedback-pulse 1.2s ease-in-out infinite;
}

@keyframes feedback-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.8); }
}

.feedback-countdown {
  font-family: var(--font-mono);
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-semibold);
  min-width: 4ch;
}

.feedback-preview {
  width: 100%;
  max-height: 320px;
  border-radius: var(--radius-md, 8px);
  background: #000;
}

/* ---- toggle switch (ToggleSwitch.jsx) ---- */
.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  flex-shrink: 0;
}

.switch-disabled {
  cursor: default;
  opacity: 0.5;
}

.switch input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.switch-track {
  width: 40px;
  height: 22px;
  background: var(--color-border);
  border-radius: var(--radius-full, 999px);
  position: relative;
  transition: background-color var(--duration-fast) ease;
}

.switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
  transition: transform var(--duration-base) var(--ease-out);
}

.switch input:checked + .switch-track {
  background: var(--color-ok);
}

.switch input:checked + .switch-track .switch-thumb {
  transform: translateX(18px);
}

.switch input:focus-visible + .switch-track {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* ---- account panel ---- */
.account-panel .field-row {
  padding: var(--space-2) 0;
}

.field-row:has(input[type="checkbox"]) {
  cursor: pointer;
}

.field-row:has(input[type="checkbox"]):hover span:first-child {
  color: var(--color-accent);
}

.account-section {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-3);
  margin-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* The section directly under the identity summary (Company profile) — no
   rule needed there, the summary rows above already read as a distinct
   block and the section's own uppercase label carries the break (John,
   2026-08-02: "there is an HR between Company and Company Profile
   header, remove it, but keep the spacing"). Later sections (Security,
   Users, Billing, Data) keep their divider — those genuinely are a
   sequence of separate settings groups, not identity summary vs. form. */
.field-row + .account-section {
  border-top: none;
}

.account-section h3 {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

/* A plain <form> has no layout of its own — without this, fields and the
   trailing submit button just stack edge-to-edge with zero gap (found in
   AccountPanel.jsx's Company-profile and add-user forms, the only two
   forms in the app that weren't already using .auth-card's flex+gap). */
.settings-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.user-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.user-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: var(--text-sm);
}

/* Neutral by default (2026-08-03: every button in a .user-row — "Change
   password", "Set up" 2FA, "Turn off" MFA — was rendering in
   --color-danger just because it shared this class with the one button
   that actually IS destructive ("Remove" user), reading as alarming for
   completely benign actions). Only .btn-danger (applied explicitly to
   Remove, below) gets the red treatment now. */
.user-row button {
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm, 4px);
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-text);
}

.user-row button:hover:not(:disabled) {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.user-row .btn-danger {
  color: var(--color-danger);
  border-color: var(--color-danger);
}

.user-row .btn-danger:hover:not(:disabled) {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: #fff;
}

.danger-zone {
  border: 1px solid var(--color-danger);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.danger-zone button {
  background: var(--color-danger);
  color: #fff;
  border: none;
  border-radius: var(--radius-md, 8px);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}

.danger-zone button:hover:not(:disabled) {
  filter: brightness(1.1);
}

/* ---- document review modal (DocumentReview.jsx) ---- */
.review-sheet {
  max-width: 960px;
  width: 100%;
}

.review-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.review-filename {
  display: block;
  color: var(--color-text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  word-break: break-all;
}

.review-back {
  background: none;
  border: none;
  color: var(--color-link);
  font-size: var(--text-sm);
  padding: 0 0 var(--space-1);
  display: block;
}

.review-back:hover {
  opacity: 0.7;
}

.review-list-intro {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  margin: 0 0 var(--space-3);
}

.review-doc-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.review-doc-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3);
  text-align: left;
}

.review-doc-row:hover {
  border-color: var(--color-danger);
  background: color-mix(in srgb, var(--color-danger) 6%, var(--color-surface-raised));
}

.review-doc-row-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.review-doc-filename {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  word-break: break-all;
}

.review-doc-reason {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.review-explanation {
  background: var(--color-surface-raised);
  border: 1px solid var(--color-danger);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3);
  font-size: var(--text-sm);
}

.review-explanation ul {
  margin: var(--space-1) 0 0;
  padding-left: var(--space-4);
}

.review-duplicate-link {
  display: inline-block;
  margin-top: var(--space-2);
  font-size: var(--text-sm);
}

.review-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  min-height: 0;
  flex: 1;
  overflow: hidden;
}

.review-preview {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
  min-height: 260px;
  display: flex;
  flex: 1;
}

/* ---- duplicate-compare: existing vs. new, clearly labeled (found via
   John testing: it wasn't obvious which document was which) ---- */
.review-compare {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-height: 0;
}

.review-compare-pane {
  display: flex;
  flex-direction: column;
  min-height: 220px;
  flex: 1;
}

.review-compare-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm, 4px) var(--radius-sm, 4px) 0 0;
}

.review-compare-label-existing {
  background: var(--color-surface-raised);
  color: var(--color-text-muted);
}

.review-compare-label-new {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.review-compare-filename {
  text-transform: none;
  letter-spacing: normal;
  opacity: 0.8;
}

@media (min-width: 860px) {
  .review-compare {
    flex-direction: row;
  }
}

.review-preview iframe,
.review-preview img {
  width: 100%;
  height: 100%;
  min-height: 260px;
  border: none;
  object-fit: contain;
}

.review-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  overflow-y: auto;
  padding-right: var(--space-1);
}

.review-form select,
.review-form input {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm, 4px);
  padding: var(--space-2);
  color: var(--color-text);
  font-size: var(--text-sm);
  width: 100%;
}

.review-row3 {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: var(--space-2);
  margin-top: var(--space-1);
}

.review-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.review-list-row {
  display: grid;
  grid-template-columns: 90px 1fr 1fr auto;
  gap: var(--space-2);
  align-items: center;
  margin-top: var(--space-2);
}

.review-list-row:has(select + input:only-of-type) {
  grid-template-columns: 90px 1fr auto;
}

.review-address-row {
  grid-template-columns: 90px 1.4fr 1fr 0.6fr 0.7fr auto;
}

/* Coverages/Items rows (2026-08-03) — three plain text inputs, no label
   select, so unlike .review-list-row's default (90px first column, sized
   for a short select) every column should share space evenly. */
.review-list-row-even3 {
  grid-template-columns: 1fr 1fr 1fr auto;
}

/* Policy parties row (2026-08-03) — role select + name + full address +
   license number, always rendered (not conditional per role) so the row
   shape never changes as the agent picks a different role. */
.review-party-row {
  grid-template-columns: 130px 1.1fr 1fr 0.8fr 0.5fr 0.6fr 0.9fr auto;
}

.review-row-remove {
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm, 4px);
  color: var(--color-text-muted);
  width: 26px;
  height: 26px;
  font-size: var(--text-md);
  line-height: 1;
  flex-shrink: 0;
}

.review-row-remove:hover {
  border-color: var(--color-danger);
  color: var(--color-danger);
}

/* ---- mobile: the names/phones/addresses editor rows pack 3-6 columns
   into one grid line on desktop — on a phone-width modal there isn't
   room for that without truncating every field. Stack each row's
   inputs instead; the label select and remove button share a line so
   the row still reads as one unit. ---- */
@media (max-width: 600px) {
  .review-list-row,
  .review-list-row:has(select + input:only-of-type),
  .review-address-row,
  .review-list-row-even3,
  .review-party-row,
  .review-row3 {
    grid-template-columns: 1fr;
  }

  .review-list-row > select,
  .review-address-row > select,
  .review-party-row > select {
    grid-column: 1 / -2;
  }

  .review-row-remove {
    grid-row: 1;
    grid-column: -2 / -1;
    justify-self: end;
  }
}

@media (min-width: 860px) {
  .review-split {
    grid-template-columns: 1fr 1fr;
  }
}

/* ---- policy document viewer (PolicyDocumentModal.jsx) ---- */
.document-view-sheet {
  max-width: 900px;
  width: 100%;
  height: 85vh;
}

.document-view-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.document-view-filename {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  word-break: break-all;
}

.document-view-actions {
  display: flex;
  gap: var(--space-2);
  flex-shrink: 0;
}

.document-view-preview {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
  flex: 1;
  min-height: 0;
  display: flex;
}

.document-view-preview iframe,
.document-view-preview img {
  width: 100%;
  height: 100%;
  border: none;
  object-fit: contain;
}

/* ---- household relationship map (RelationshipMap.jsx, 2026-08-24) ----
   Coverage-stamp row is the signature element — a literal stamped/
   unstamped badge per canonical coverage category, extending the same
   "stamp" accent (--color-stamp) already used on modal-sheet's top
   border, not a new color introduced just for this screen. */
.relationship-map-sheet {
  max-width: 720px;
  width: 100%;
  max-height: 85vh;
}

.relationship-map-title {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
}

.relationship-map-title-name {
  font-family: var(--font-mono);
}

.relationship-map-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  overflow-y: auto;
}

.gap-banner-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.gap-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  background: color-mix(in srgb, var(--color-warn) 14%, var(--color-surface));
  border-left: 3px solid var(--color-warn);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--color-text);
}

.gap-banner svg {
  color: var(--color-warn);
  flex-shrink: 0;
  margin-top: 2px;
}

.relationship-map-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.relationship-map-heading {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.household-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.household-member {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.household-member-header {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.household-member-name {
  font-family: var(--font-mono);
  font-size: var(--text-base);
  color: var(--color-text);
}

.household-member-tag {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  color: var(--color-accent);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-full);
  padding: 1px var(--space-2);
}

.household-member-contact {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.stamp-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.stamp-row-empty {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  font-style: italic;
}

.stamp {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.02em;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  line-height: var(--leading-tight);
}

.stamp-held {
  background: var(--color-stamp);
  color: var(--color-accent-contrast);
  border: 1px solid var(--color-stamp);
}

.stamp-other {
  background: var(--color-surface-raised);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

.stamp-gap {
  background: transparent;
  color: var(--color-text-muted);
  border: 1px dashed var(--color-border);
}

.other-connections-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.other-connection {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-bottom: 1px dashed var(--color-border);
  padding-bottom: var(--space-2);
  font-size: var(--text-sm);
}

.other-connection-name {
  font-family: var(--font-mono);
  color: var(--color-text);
}

.other-connection-detail {
  font-family: var(--font-sans);
  color: var(--color-text-muted);
}

/* ---- recent-uploads dropdown (RecentUploads.jsx) ---- */
.upload-status-anchor {
  position: relative;
}

.recent-uploads {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  width: 320px;
  max-height: 420px;
  overflow-y: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  box-shadow: var(--shadow-md);
  padding: var(--space-3);
  z-index: var(--z-dropdown, 10);
  transform-origin: top right;
  animation: dropdown-in var(--duration-base) var(--ease-out);
}

@keyframes dropdown-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.recent-uploads-head {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin-bottom: var(--space-2);
}

.recent-uploads-empty {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  margin: var(--space-2) 0;
}

.recent-uploads-batch {
  padding: var(--space-2) 0;
  border-top: 1px dashed var(--color-border);
}

.recent-uploads-batch:first-of-type {
  border-top: none;
}

.recent-uploads-batch-time {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  margin-bottom: var(--space-1);
}

.recent-uploads-doc {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--text-sm);
  padding: 2px 0;
}

.recent-uploads-filename {
  word-break: break-all;
}

.recent-uploads-customer {
  color: var(--color-text-muted);
  white-space: nowrap;
  font-size: var(--text-xs);
}

/* ---- live upload-progress dropdown (UploadProgress.jsx) ---- */
.upload-progress {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  width: 300px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  box-shadow: var(--shadow-md);
  padding: var(--space-3);
  z-index: var(--z-dropdown, 10);
  transform-origin: top right;
  animation: dropdown-in var(--duration-base) var(--ease-out);
}

.upload-progress-head {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin-bottom: var(--space-2);
}

.upload-progress-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 260px;
  overflow-y: auto;
}

.upload-progress-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-1);
  border-radius: var(--radius-sm, 4px);
  font-size: var(--text-sm);
}

.upload-progress-row-processing,
.upload-progress-row-uploading {
  background: var(--color-surface-raised);
}

.upload-progress-row-pending {
  color: var(--color-text-muted);
}

.upload-progress-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-link);
}

.upload-progress-row-uploading .upload-progress-icon,
.upload-progress-row-uploaded .upload-progress-icon,
.upload-progress-row-done .upload-progress-icon {
  color: var(--color-ok);
}

.upload-progress-icon svg {
  width: 16px;
  height: 16px;
}

.upload-progress-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full, 999px);
}

.upload-progress-dot-warn {
  background: var(--color-warn);
}

.upload-progress-filename {
  word-break: break-all;
}

