@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(/static/fonts/publicsans-var-latin.woff2) format("woff2");
}
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url(/static/fonts/fraunces-var-latin.woff2) format("woff2");
}

/* Dark is the base theme now — every visitor sees it until they explicitly
   pick Light (below), regardless of OS preference. No prefers-color-scheme
   media query drives this default on purpose; it's a product choice, not a
   device-following one. */
:root {
  --page: #0a111c;
  --surface: #111c2c;
  --surface-2: #182740;
  --ink: #eef3fa;
  --ink-2: #a8b6c9;
  --muted: #6d7d92;
  --line: #1e2c42;
  --line-strong: #2e415f;
  --accent: #7aa7f7;
  --accent-hover: #94b8f9;
  --accent-contrast: #081120;
  --accent-soft: #1a2c4c;
  --accent-wash: #101b2e;
  --focus: #7aa7f7;
  --good: #21b421;       --good-text: #55cd55;    --good-tint: rgba(33,180,33,.13);
  --warn: #fab219;       --warn-text: #f5c04d;    --warn-tint: rgba(250,178,25,.12);
  --serious: #ec835a;    --serious-text: #f0996f; --serious-tint: rgba(236,131,90,.12);
  --crit: #e05252;       --crit-text: #ea7676;    --crit-tint: rgba(224,82,82,.12);
  --neutral-dot: #6d7d92; --neutral-text: #a8b6c9; --neutral-tint: rgba(238,243,250,.07);

  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  --sans: "Public Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --serif: "Fraunces", Georgia, serif;
  --shadow-sm: 0 1px 2px rgba(0,0,0,.3), 0 2px 8px rgba(0,0,0,.25);
  --shadow-md: 0 1px 2px rgba(0,0,0,.35), 0 12px 32px rgba(0,0,0,.35);
  --shadow-lg: 0 2px 6px rgba(0,0,0,.4), 0 24px 64px rgba(0,0,0,.5);
}

:root[data-theme="dark"] {
  --page: #0a111c;
  --surface: #111c2c;
  --surface-2: #182740;
  --ink: #eef3fa;
  --ink-2: #a8b6c9;
  --muted: #6d7d92;
  --line: #1e2c42;
  --line-strong: #2e415f;
  --accent: #7aa7f7;
  --accent-hover: #94b8f9;
  --accent-contrast: #081120;
  --accent-soft: #1a2c4c;
  --accent-wash: #101b2e;
  --focus: #7aa7f7;
  --good: #21b421;       --good-text: #55cd55;    --good-tint: rgba(33,180,33,.13);
  --warn: #fab219;       --warn-text: #f5c04d;    --warn-tint: rgba(250,178,25,.12);
  --serious: #ec835a;    --serious-text: #f0996f; --serious-tint: rgba(236,131,90,.12);
  --crit: #e05252;       --crit-text: #ea7676;    --crit-tint: rgba(224,82,82,.12);
  --neutral-dot: #6d7d92; --neutral-text: #a8b6c9; --neutral-tint: rgba(238,243,250,.07);
  --shadow-sm: 0 1px 2px rgba(0,0,0,.3), 0 2px 8px rgba(0,0,0,.25);
  --shadow-md: 0 1px 2px rgba(0,0,0,.35), 0 12px 32px rgba(0,0,0,.35);
  --shadow-lg: 0 2px 6px rgba(0,0,0,.4), 0 24px 64px rgba(0,0,0,.5);
}
:root[data-theme="light"] {
  --page: #f6f8fb;
  --surface: #ffffff;
  --surface-2: #eef2f8;
  --ink: #0f1b2d;
  --ink-2: #44536a;
  --muted: #8393a8;
  --line: #e3e9f2;
  --line-strong: #c8d3e2;
  --accent: #2056c7;
  --accent-hover: #1b49a9;
  --accent-contrast: #ffffff;
  --accent-soft: #e9f0fc;
  --accent-wash: #f2f6fd;
  --focus: #2056c7;
  --good: #0ca30c;       --good-text: #0a7a0a;    --good-tint: rgba(12,163,12,.09);
  --warn: #fab219;       --warn-text: #7d5300;    --warn-tint: rgba(250,178,25,.15);
  --serious: #ec835a;    --serious-text: #a1441f; --serious-tint: rgba(236,131,90,.13);
  --crit: #d03b3b;       --crit-text: #b02525;    --crit-tint: rgba(208,59,59,.09);
  --neutral-dot: #8393a8; --neutral-text: #44536a; --neutral-tint: rgba(15,27,45,.06);
  --shadow-sm: 0 1px 2px rgba(15,27,45,.04), 0 2px 8px rgba(15,27,45,.04);
  --shadow-md: 0 1px 2px rgba(15,27,45,.05), 0 12px 32px rgba(15,27,45,.08);
  --shadow-lg: 0 2px 6px rgba(15,27,45,.06), 0 24px 64px rgba(15,27,45,.12);
}

* { box-sizing: border-box; }
/* No text in this app should ever read as underlined -- most links already
   reset this individually, but that left gaps (.subtle-link, any future
   unclassed <a>) that fell back to the browser's default underline. One
   rule here closes all of them at once, app-wide. */
a { text-decoration: none; }
html, body {
  /* The off-canvas mobile sidebar sits at its full width and is only moved
     off-screen via transform: translateX(100%) — transforms don't remove an
     element from the layout box that determines scrollable area, so without
     this the whole page gained ~20px of real horizontal scroll on mobile,
     exposing a sliver of the closed drawer at the right edge. Wide content
     (tables etc.) still scrolls fine — those use overflow-x: auto on their
     own container, a level below this. */
  overflow-x: hidden;
}
body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14.5px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
button { font-family: inherit; font-size: inherit; cursor: pointer; }
:is(button, a, input, select, textarea):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}
.wrap { max-width: 1100px; margin: 0 auto; padding: 0 28px; }
.hidden { display: none !important; }
.spacer { flex: 1; }

/* ── shared bits ─────────────────────────────────────── */
.logo { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; color: var(--ink); }
.logo-mark {
  width: 26px; height: 26px; flex: none; color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center;
}
.logo-mark svg { width: 26px; height: 26px; }
.portal-logo-img { height: 28px; max-width: 170px; object-fit: contain; display: block; }
.logo-preview-row { display: flex; align-items: center; gap: 14px; margin: 6px 0 10px; }
.logo-preview {
  height: 40px; max-width: 200px; object-fit: contain;
  border: 1px solid var(--line); border-radius: 8px; padding: 6px; background: var(--surface);
}
.logo-name { font-family: var(--serif); font-size: 19px; font-weight: 560; letter-spacing: .005em; }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--accent-contrast);
  border: 1px solid var(--accent); border-radius: 9px;
  padding: 9px 18px; font-weight: 600; font-size: 14px; line-height: 1.2;
  text-decoration: none; box-sizing: border-box; vertical-align: middle;
  white-space: nowrap; flex: none;
  transition: background .12s, border-color .12s, transform .12s, box-shadow .12s;
}
/* Buttons get real physical feedback, not just a color swap: a small lift on
   hover, and a press-down on :active that undershoots the rest position —
   the undershoot (not just returning to 0) is what reads as "pressed" rather
   than "released early". */
.btn:hover { background: var(--accent-hover); border-color: var(--accent-hover);
  transform: translateY(-1px); box-shadow: 0 4px 10px color-mix(in srgb, var(--accent) 24%, transparent); }
.btn:active { transform: translateY(0); box-shadow: none; }
.btn-ghost {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 9px 16px; font-weight: 550; font-size: 14px; line-height: 1.2;
  text-decoration: none; box-sizing: border-box; vertical-align: middle;
  white-space: nowrap; flex: none;
  transition: color .12s, border-color .12s, transform .12s, box-shadow .12s;
}
.btn-ghost:hover { color: var(--ink); border-color: var(--muted); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.btn-ghost:active { transform: translateY(0); box-shadow: none; }
.btn-danger {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; color: var(--crit-text);
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 9px 16px; font-weight: 550; font-size: 14px; line-height: 1.2;
  text-decoration: none; box-sizing: border-box; vertical-align: middle;
  white-space: nowrap; flex: none;
  transition: background .12s, border-color .12s, transform .12s;
}
.btn-danger:hover { border-color: var(--crit); background: var(--crit-tint); transform: translateY(-1px); }
.btn-danger:active { transform: translateY(0); }
.btn-sm { padding: 5px 12px; font-size: 13px; border-radius: 7px; }
.btn-lg { padding: 12px 24px; font-size: 15px; border-radius: 10px; }
.btn:disabled, .btn-ghost:disabled, .btn-danger:disabled { opacity: .7; cursor: default; }

/* Shine-text CTA (landing hero "Request access") — plain text, no button
   chrome; the sweep is the only visual weight it carries. Base color is
   --ink (this page's normal readable text, since there's no button fill to
   contrast against anymore) with an --accent glint sweeping through, so it
   stays legible and on-brand in both light and dark mode without a separate
   override for either. */
.btn-shine-link { display: inline-block; text-decoration: none; }
.btn-shine-text {
  display: inline-block;
  font-weight: 600; font-size: 16px; text-decoration: none;
  /* A *repeating* gradient, not a one-off — its 0%/100% edges are
     identical by construction, so sliding it by exactly one tile-width
     (background-size, below) lands back on a pixel-identical frame. That's
     what makes the loop seamless: no snap-back, because there's nothing to
     snap — the "end" state already equals the "start" state. Linear timing
     (not ease-in-out) for constant speed throughout, with no holds, so
     nothing ever looks paused or jumpy. */
  background-image: repeating-linear-gradient(
    100deg,
    var(--ink) 0%, var(--ink) 40%,
    var(--accent) 50%,
    var(--ink) 60%, var(--ink) 100%
  );
  background-size: 300% 100%;
  background-position: 0% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: btn-shine-sweep 10s linear infinite;
}
@keyframes btn-shine-sweep {
  /* Starts on a flat, glint-free stretch of the tile (0%-40% above is pure
     --ink) so the very first frame reads as plain text, not a highlight
     caught mid-sweep -- then travels one full tile-width before wrapping. */
  from { background-position: 0% 0; }
  to   { background-position: -300% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .btn-shine-text {
    animation: none; background-image: none; -webkit-background-clip: initial;
    background-clip: initial; color: var(--ink); -webkit-text-fill-color: currentcolor;
  }
}
.btn-spinner {
  display: inline-block; width: 12px; height: 12px; margin-right: 7px;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  vertical-align: -2px; animation: btn-spin .7s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .btn-spinner { animation: none; } }
@keyframes btn-spin { to { transform: rotate(360deg); } }
.link-btn {
  background: none; border: none; color: var(--accent);
  font-weight: 600; padding: 0; font-size: 13.5px; text-decoration: none;
}


.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; white-space: nowrap;
  border-radius: 999px; padding: 3px 11px 3px 9px;
}
.pill .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.pill-current    { background: var(--good-tint);    color: var(--good-text); }
.pill-current    .dot { background: var(--good); }
.pill-due_soon   { background: var(--warn-tint);    color: var(--warn-text); }
.pill-due_soon   .dot { background: var(--warn); }
.pill-delinquent { background: var(--crit-tint);    color: var(--crit-text); }
.pill-delinquent .dot { background: var(--crit); }
.pill-error      { background: var(--serious-tint); color: var(--serious-text); }
.pill-error      .dot { background: var(--serious); }
.pill-dissolved  { background: var(--neutral-tint); color: var(--neutral-text); }
.pill-dissolved  .dot { background: var(--neutral-dot); }
.pill-unknown    { background: none; color: var(--muted); box-shadow: inset 0 0 0 1px var(--line-strong); }
.pill-unknown    .dot { background: var(--neutral-dot); opacity: .6; }

/* Scoped to the dashboard's scanning table, not every pill in the app: on a
   single-entity detail page you already know why you're there, and a dot
   pulsing forever while you read adds nothing. Here, where a firm scans many
   rows, it's the fastest way to say "start here". Only urgent statuses move —
   movement itself is the signal, so it can't mean "everything's fine" too.
   Animates transform+opacity, not box-shadow: box-shadow forces a repaint
   every frame instead of running on the compositor, and on a row of several
   simultaneously-pulsing dots on real mobile Safari that was enough to make
   the browser skip almost the entire 2.45s fade — confirmed by pulling a
   user's screen recording frame-by-frame, where the "pulse" rendered as a
   ~33ms flash-and-vanish instead of a smooth ripple. transform/opacity are
   compositor-only, so this can't happen no matter how many rows are pulsing
   at once. */
#client-rows .pill-delinquent .dot, #client-rows .pill-error .dot { position: relative; }
#client-rows .pill-delinquent .dot::after, #client-rows .pill-error .dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; background: currentColor;
}
#client-rows .pill-delinquent .dot::after { color: var(--crit); }
#client-rows .pill-error .dot::after { color: var(--serious); }
@media (prefers-reduced-motion: no-preference) {
  #client-rows .pill-delinquent .dot::after,
  #client-rows .pill-error .dot::after { animation: dot-pulse 3.5s ease-out infinite; }
}
@keyframes dot-pulse {
  /* Same net effect as the old box-shadow ring (0 -> 8px spread on a 7px
     dot, i.e. a final radius ~3.3x the dot's own) via scale instead. */
  0%   { transform: scale(1); opacity: .55; }
  70%  { transform: scale(3.3); opacity: 0; }
  100% { transform: scale(3.3); opacity: 0; }
}

.tag {
  font-size: 10.5px; font-weight: 600; letter-spacing: .05em;
  color: var(--muted); border: 1px solid var(--line-strong);
  border-radius: 4px; padding: 1px 6px; margin-left: 7px;
  text-transform: uppercase; white-space: nowrap; vertical-align: 1px;
}
.tag--warn { color: var(--warn-text); border-color: var(--warn); background: var(--warn-tint); }
.mono { font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.dim { color: var(--muted); }

.form-error {
  background: var(--crit-tint); color: var(--crit-text);
  border: 1px solid var(--crit); border-radius: 9px;
  padding: 9px 13px; font-size: 13px; font-weight: 550;
}
.form-notice {
  background: var(--good-tint); color: var(--good-text);
  border: 1px solid var(--good); border-radius: 9px;
  padding: 9px 13px; font-size: 13px; font-weight: 550; margin-bottom: 14px;
}
.form-notice--warn {
  background: var(--warn-tint); color: var(--warn-text); border-color: var(--warn);
}
/* Inline per-field validation message (themed replacement for browser bubbles). */
.field-error { color: var(--crit-text); font-size: 12px; font-weight: 550; margin: 2px 0 0; }

/* Live password-requirements checklist -- password-checklist.js toggles
   .pw-check-met on each item as the user types. The known-breach check
   deliberately isn't one of these items (backend-only, see
   auth.password_requirement_error / is_pwned_password) since it can't be
   evaluated live without hitting HIBP on every keystroke; a breach
   rejection surfaces as a normal top-of-form error on submit instead. */
.pw-checklist { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.pw-checklist li { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); transition: color .15s; }
.pw-checklist li::before {
  content: ""; width: 15px; height: 15px; border-radius: 50%; flex: none;
  border: 1.5px solid var(--line-strong); display: flex; align-items: center; justify-content: center;
  font-size: 10px; line-height: 1; color: transparent;
}
.pw-checklist li.pw-check-met { color: var(--good-text); }
.pw-checklist li.pw-check-met::before {
  content: "✓"; border-color: var(--good); background: var(--good); color: var(--accent-contrast);
}
.form-row-end { display: flex; justify-content: flex-end; margin: -6px 0 4px; }
.form-row-end .link-btn { font-size: 13px; }

/* ── landing ─────────────────────────────────────────── */
.land-nav { padding: 22px 0; }
.land-nav .wrap { display: flex; align-items: center; gap: 16px; }
.hero { padding: 64px 0 72px; }
.hero .wrap { display: grid; grid-template-columns: 1.05fr .95fr; gap: 56px; align-items: center; }
@media (max-width: 860px) { .hero .wrap { grid-template-columns: 1fr; } }
.eyebrow {
  font-size: 12px; font-weight: 650; letter-spacing: .09em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 14px;
}
.hero h1 {
  font-family: var(--serif); font-weight: 480; font-size: clamp(38px, 5vw, 54px);
  line-height: 1.08; letter-spacing: -.012em; margin: 0 0 18px; text-wrap: balance;
}
.hero .lede { font-size: 17px; color: var(--ink-2); max-width: 46ch; margin: 0 0 28px; }
.hero-ctas { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }

/* .ring/.ring-good/.ring-bad are shared with the owner portal's verdict
   badge (owner_home.html) — kept here even though the landing page's own
   vignette that introduced them is gone. */
.ring {
  width: 46px; height: 46px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
}
.ring-good { background: var(--good-tint); color: var(--good-text); box-shadow: inset 0 0 0 1.5px var(--good); }
.ring-bad  { background: var(--crit-tint); color: var(--crit-text); box-shadow: inset 0 0 0 1.5px var(--crit); }
.ring-neutral { background: var(--neutral-tint); color: var(--neutral-text); box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.ring svg { width: 22px; height: 22px; }

.features { padding: 8px 0 72px; }
.features .wrap { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
@media (max-width: 760px) { .features .wrap { grid-template-columns: 1fr; } }
.feature {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 22px 22px 20px; box-shadow: var(--shadow-sm);
}
.feature h3 { font-family: var(--serif); font-weight: 540; font-size: 19px; margin: 0 0 8px; letter-spacing: -.005em; }
.feature p { margin: 0; color: var(--ink-2); font-size: 14px; }
.f-ico {
  width: 34px; height: 34px; border-radius: 10px; background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center; margin-bottom: 14px;
}
.f-ico svg { width: 17px; height: 17px; }

.personas-band { padding: 8px 0 72px; }
.band-title { font-family: var(--serif); font-weight: 500; font-size: 30px; letter-spacing: -.01em; margin: 0 0 6px; }
.band-sub { color: var(--ink-2); font-size: 15px; margin: 0 0 26px; }
.persona-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 760px) { .persona-cards { grid-template-columns: 1fr; } }
.persona-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow-sm); padding: 28px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
}
.persona-card .f-ico { margin-bottom: 2px; }
.persona-card h3 { font-family: var(--serif); font-weight: 540; font-size: 22px; margin: 0; letter-spacing: -.006em; }
.persona-card p { margin: 0; color: var(--ink-2); font-size: 14.5px; }
.persona-card .btn { margin-top: 10px; }

.land-cta { padding: 0 0 80px; text-align: center; }
.land-cta .inner {
  background: var(--accent-wash); border: 1px solid var(--line); border-radius: 18px;
  padding: 48px 28px;
}
.land-cta h2 { font-family: var(--serif); font-weight: 500; font-size: 30px; margin: 0 0 8px; letter-spacing: -.01em; }
.land-cta p { color: var(--ink-2); margin: 0 0 22px; }
.land-foot { border-top: 1px solid var(--line); padding: 20px 0 36px; font-size: 12.5px; color: var(--muted); }
.land-foot .wrap { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }

/* ── login ───────────────────────────────────────────── */
.login-wrap {
  min-height: 88vh; display: flex; align-items: center; justify-content: center;
  padding: 40px 20px;
}
.login-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 18px;
  box-shadow: var(--shadow-md); padding: 36px 36px 30px; width: 100%; max-width: 400px;
}
.login-card .logo { margin-bottom: 22px; }
.login-card h2 { font-family: var(--serif); font-weight: 520; font-size: 26px; margin: 0 0 4px; letter-spacing: -.008em; }
.login-card .sub { color: var(--muted); font-size: 13.5px; margin: 0 0 24px; }
.login-card .form-error { margin: -8px 0 16px; }
.login-card form { display: grid; gap: 14px; }
.login-card label { display: grid; gap: 6px; font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.login-card .name-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 420px) {
  .login-card .name-row { grid-template-columns: 1fr; }
}
/* :not([type=checkbox]):not([type=radio]) -- this rule is meant for the
   text-like fields (name/email/password/select), not the agree-checkbox
   sitting in .agree-check lower down. Without the exclusion, width:100%
   stretched the checkbox itself to fill the whole row and pushed its
   label text outside the card entirely -- a real regression, caught by
   screenshot, not just a hypothetical one. */
.login-card :is(input, select, textarea):not([type="checkbox"]):not([type="radio"]) {
  background: var(--page); color: var(--ink); width: 100%; min-width: 0;
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 10px 12px; font-family: inherit; font-size: 14px;
}
.login-card textarea { resize: vertical; min-height: 76px; }
.login-card .btn { width: 100%; margin-top: 4px; padding: 11px; }
/* privacy_request.html is the one .login-card with more than a couple of
   fields (name/email/dropdown/notes), so it's noticeably taller than the
   login/forgot/reset cards this component was built for — let it breathe. */
.login-card.wide { max-width: 460px; }
/* Same specificity fix as .form-card .agree-check below (`.login-card
   label {display:grid}` outranks `.agree-check {display:flex}` on
   specificity) -- without this, the trust-device checkbox and its label
   text each land in their own grid row instead of sitting inline. */
.login-card .agree-check { display: flex; align-items: center; }
/* Verify-2FA screen only (both the emailed-code and authenticator-app
   variants share this template) -- centers the logo/heading/sub-line and
   the "Not you? Sign out" link, while the form itself (code input, trust
   -device checkbox, button) stays left-aligned/full-width like every other
   .login-card form. Scoped here rather than on .login-card itself so
   login.html/signup.html keep their left-aligned copy. */
.verify2fa-center { text-align: center; }
.login-back { text-align: center; margin-top: 18px; }

/* Signup account-type chooser */
.choose-grid { display: grid; gap: 12px; }
.choose-opt {
  display: block; text-decoration: none;
  background: var(--surface-2); border: 1px solid var(--line-strong); border-radius: 12px;
  padding: 16px 18px; transition: border-color .12s, background .12s;
}
.choose-opt:hover { border-color: var(--accent); background: var(--page); }
.choose-opt-title { display: block; font-size: 15px; font-weight: 640; color: var(--ink); }
.choose-opt-sub { display: block; font-size: 12.5px; color: var(--muted); margin-top: 3px; }

/* Scroll-to-agree hint (shown by signup.js until the agreement is read). */
.agree-hint { font-size: 12px; color: var(--muted); margin: 2px 0 4px; }

/* ── app chrome: persistent left rail + topbar ──────────
   Replaces the old top appbar + slide-in drawer (a single hamburger-reached
   overlay at every width) with a Stripe/Render-style layout: the rail is
   permanently visible and part of the page flow on desktop, and only
   becomes an off-canvas drawer (same toggle/backdrop pattern as before)
   below the mobile breakpoint. .app-shell/.main are opened in
   _partials/topbar.html and closed by the extending page's app_base.html —
   see the comment there. */
:root { --rail-w: 248px; }
.app-shell { display: flex; align-items: flex-start; min-height: 100vh; }
/* Fixed, not sticky/flex-item: sticky still lets the rail get dragged
   along with an unusually tall page in some layouts (a long search-results
   list, for instance) before it catches back up to top:0. Fixed pins it to
   the viewport unconditionally, so it truly never moves on scroll -- .main
   gets an explicit margin-left to make room for it now that it's out of
   the flex flow (see .main below). */
.rail {
  width: var(--rail-w); background: var(--surface); border-right: 1px solid var(--line);
  display: flex; flex-direction: column; position: fixed; top: 0; left: 0; height: 100vh;
  overflow-y: auto; z-index: 20;
}
.rail-brand {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 16px 14px; border-bottom: 1px solid var(--line); flex: none;
}
.rail-nav { display: flex; flex-direction: column; padding: 12px; flex: 1; overflow-y: auto; }
.rail-group { display: flex; flex-direction: column; gap: 2px; padding-top: 14px; border-top: 1px solid var(--line); margin-top: 10px; }
.rail-group:first-child { padding-top: 0; border-top: none; margin-top: 0; }
.rail-group-label {
  font-size: 10.5px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); padding: 0 12px 4px;
}
.rail-nav a {
  display: flex; align-items: center; gap: 11px;
  color: var(--ink-2); text-decoration: none;
  padding: 10px 12px; border-radius: 9px; font-weight: 550; font-size: 14.5px;
  transition: background .12s, color .12s;
}
.rail-nav a svg { width: 18px; height: 18px; flex: none; color: var(--ink-3, var(--muted)); }
.rail-nav a:hover { background: var(--surface-2); color: var(--ink); }
.rail-nav a[aria-current="page"] { background: var(--accent-soft); color: var(--accent); font-weight: 650; }
.rail-nav a[aria-current="page"] svg { color: var(--accent); }

/* "Coming soon" pages: the nav link navigates normally (so people can still
   see the built page), and the page itself shows the real, built UI in a
   bordered preview box -- dimmed and non-interactive -- with an actual
   opaque popup card centered on top of it, so "coming soon" reads as a
   real, unmissable notice rather than a small badge that blends in. The
   real content stays visible around the edges of the box; the popup only
   covers its own box, not the whole screen. `.coming-soon-locked` is also
   [inert] in the markup (modern browsers refuse focus/clicks/text-selection
   inside an inert subtree on their own) as belt-and-suspenders for browsers
   that ignore `inert`. */
.coming-soon-box {
  position: relative; border: 1px solid var(--line-strong); border-radius: 16px;
  padding: 22px; background: var(--surface); overflow: hidden;
}
.coming-soon-locked {
  filter: grayscale(.25); opacity: .35; pointer-events: none;
  user-select: none; -webkit-user-select: none;
}
.coming-soon-popup {
  position: absolute; inset: 0; z-index: 5; display: flex; align-items: center;
  justify-content: center; padding: 24px;
}
.coming-soon-card {
  max-width: 380px; text-align: center; background: var(--surface-2);
  border: 1px solid var(--line-strong); border-radius: 14px; box-shadow: var(--shadow-lg);
  padding: 22px 26px;
}
.coming-soon-badge {
  display: inline-block; background: var(--accent-wash); color: var(--accent);
  font-size: 12px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase;
  border-radius: 999px; padding: 4px 11px; margin-bottom: 10px;
}
.coming-soon-card p { margin: 0 0 6px; color: var(--ink); font-size: 14.5px; line-height: 1.45; }
.coming-soon-card .coming-soon-sub { margin-bottom: 0; color: var(--ink-2); font-size: 13.5px; }

/* Rail-foot: the signed-in user's own name/role (never the firm's own
   name -- that's already up in .rail-brand), plus a one-click log out. */
.rail-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 12px 10px 12px 16px; border-top: 1px solid var(--line); flex: none; margin: 0; }
.rail-user { display: flex; align-items: center; gap: 10px; min-width: 0; }
.rail-avatar {
  display: flex; align-items: center; justify-content: center; flex: none;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  font-size: 12px; font-weight: 700;
}
.rail-user-info { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.rail-user-name { font-size: 13px; font-weight: 650; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rail-user-role { font-size: 11.5px; color: var(--muted); }
.rail-foot .icon-btn { width: 32px; height: 32px; flex: none; }
.rail-foot form { margin: 0; }

.rail-toggle, .rail-brand .rail-close { display: none; }
.rail-toggle {
  align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 9px; flex: none;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-2);
  cursor: pointer; padding: 0; transition: color .12s, border-color .12s;
}
.rail-toggle:hover { color: var(--ink); border-color: var(--muted); }
.rail-toggle svg { width: 19px; height: 19px; }
.rail-backdrop {
  position: fixed; inset: 0; background: rgba(10, 14, 22, .38);
  opacity: 0; transition: opacity .18s ease; z-index: 40; display: none;
}
.rail-backdrop.open { opacity: 1; }

.main { flex: 1; min-width: 0; margin-left: var(--rail-w); }
/* No separate topbar bar at all any more -- it used to be its own strip of
   empty space above every page's heading, even after being slimmed down.
   Settings/Add-entity now render inline at the top-right of .content (see
   .page-icons below), sitting on the same visual row as the page's own
   heading instead of a row of their own above it. */
.content { position: relative; }
/* right/top match .wrap's own padding (28px) exactly -- an absolutely
   positioned child's offset is relative to the padding EDGE (the border),
   not inside the padding area, so `right: 0` here would sit 28px further
   right than every other piece of content, which is inset by that padding.
   top is nudged down a few px to land on the heading's own cap-height
   instead of its (taller) line-box top. */
.page-icons { position: absolute; top: 4px; right: 28px; display: flex; align-items: center; gap: 10px; z-index: 5; }
.page-icons form { margin: 0; }
.icon-btn.add { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast, #fff); }
.icon-btn.add:hover { background: var(--accent-hover, var(--accent)); border-color: var(--accent-hover, var(--accent)); color: var(--accent-contrast, #fff); }
/* a.mobile-back (element+class), not just .mobile-back -- otherwise this
   loses the cascade to .icon-btn's own `display: inline-flex` (same single-
   class specificity, but .icon-btn's base rule comes later in the file) and
   the back button leaks onto desktop instead of staying hidden until the
   ≤900px media query turns it back on. Caught live: it was rendering above
   "Add an entity"'s heading at full desktop width, pushing the heading down
   out of line with every other page's. */
a.mobile-back { display: none; }

@media (prefers-reduced-motion: reduce) {
  .rail, .rail-backdrop { transition: none; }
}
@media (max-width: 900px) {
  .main { margin-left: 0; }
  .rail {
    position: fixed; top: 0; right: 0; bottom: 0; left: auto; height: 100%;
    width: 280px; max-width: 86vw; border-right: none; border-left: 1px solid var(--line);
    box-shadow: var(--shadow-md); z-index: 41;
    transform: translateX(100%); transition: transform .2s ease;
  }
  .rail.open { transform: translateX(0); }
  .rail-toggle, .rail-brand .rail-close { display: inline-flex; }
  .rail-backdrop:not([hidden]) { display: block; }
  /* Grouped with Settings/Add-entity on the right instead of sitting alone
     on the far left. Lives inside .content now (moved there from topbar.html)
     so it shares .page-icons' exact positioning context -- both absolute
     children of the same block, both subject to the same heading-margin
     collapse -- instead of drifting apart by that margin like it did when
     .rail-toggle was a sibling of .main. Also scrolls away with the page
     instead of hovering over content, since it's no longer fixed.
     .app-shell:has(.page-icons) shifts it left of the icon row on the 3
     pages that show one (Dashboard/Entities/Client groups); everywhere
     else it just sits at the same right-edge inset the icons would use. */
  .rail-toggle { position: absolute; top: 4px; right: 28px; z-index: 10; margin-top: 0; }
  .app-shell:has(.page-icons) .rail-toggle { right: 120px; }

  /* Mobile-only back button (see mobile_back() macro): sits immediately
     left of the hamburger -- its own width (36px) plus the icon row's
     10px gap, added to wherever the hamburger currently sits. */
  a.mobile-back { display: inline-flex; position: absolute; top: 4px; right: 74px; z-index: 10; color: var(--ink-2); }
  .app-shell:has(.page-icons) a.mobile-back { right: 166px; }

  /* Tiles: shorter labels ("Total entities") and longer ones that wrap to
     two lines ("In good standing") sit in the same 2-column row -- give
     every label the same reserved height so each tile's number lines up
     at the same vertical position regardless of whether its own label
     wrapped. A tile left alone on the last row (odd tile count) spans
     the full width instead of leaving an empty gap beside it. */
  .tile .lbl { min-height: 2.6em; align-items: flex-start; }
  .dash-tiles .tile:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  /* .page-icons' right offset matches .wrap's desktop/tablet padding
     (28px); .wrap itself switches to 16px padding at this width (see the
     ≤640px block further down), so without this the icons would sit
     inset further than every other piece of content on real phones --
     the misalignment the "not centered" feedback was pointing at. */
  .page-icons { right: 16px; }
  .rail-toggle { right: 16px; }
  .app-shell:has(.page-icons) .rail-toggle { right: 108px; }
  a.mobile-back { right: 62px; }
  .app-shell:has(.page-icons) a.mobile-back { right: 154px; }
}

/* Branded confirm dialog (confirm-dialog.js) — replaces the native browser
   confirm() on every destructive form submit, so a "delete this?" prompt
   looks like Standing instead of a bare OS dialog. Built once, on demand,
   the first time any form with a data-confirm attribute is submitted. */
.confirm-backdrop {
  position: fixed; inset: 0; background: rgba(10, 14, 22, .5);
  display: flex; align-items: center; justify-content: center; padding: 20px;
  opacity: 0; transition: opacity .15s ease; z-index: 80;
}
.confirm-backdrop.open { opacity: 1; }
.confirm-dialog {
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow-md); padding: 24px; width: 100%; max-width: 400px;
  transform: translateY(6px) scale(.98); transition: transform .15s ease;
}
.confirm-backdrop.open .confirm-dialog { transform: translateY(0) scale(1); }
.confirm-dialog-body { margin: 0; color: var(--ink); font-size: 15px; line-height: 1.5; }
.confirm-dialog-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }
@media (prefers-reduced-motion: reduce) {
  .confirm-backdrop, .confirm-dialog { transition: none; }
}

/* Dashboard: explain a status. */
.status-reason { font-size: 11.5px; color: var(--muted); margin-top: 3px; line-height: 1.3; max-width: 22ch; }
.row-pending-tag {
  display: flex; align-items: center; gap: 5px; margin-top: 4px;
  font-size: 11.5px; font-weight: 600; color: var(--accent);
}
.row-pending-tag .btn-spinner { width: 10px; height: 10px; margin-right: 0; }

/* Skeleton state for a row with a check in flight: the state/client-group/
   status/due-date/days-left/last-checked cells (columns 4-9 of 10, now that
   Entity # and Client group are their own columns) are about to be
   superseded, so they're dimmed with a slow shimmer sweep — "don't fully
   trust this number" — while the entity name/number and action buttons
   (what you'd still want to click on) stay at full strength. The
   client-detail page tells the same story with a dim-then-flash pair (see
   .just-updated); this is the "dim" half of that pair for the scanning
   table. */
#client-rows tr[data-pending="1"] td:nth-child(n+4):nth-child(-n+9) {
  position: relative; opacity: .55; overflow: hidden;
}
#client-rows tr[data-pending="1"] td:nth-child(n+4):nth-child(-n+9)::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 35%,
    color-mix(in srgb, var(--accent) 14%, transparent) 50%, transparent 65%);
  background-size: 250% 100%;
}
@media (prefers-reduced-motion: no-preference) {
  #client-rows tr[data-pending="1"] td:nth-child(n+3):nth-child(-n+7)::after {
    animation: skeleton-sweep 1.8s ease-in-out infinite;
  }
}
@keyframes skeleton-sweep {
  0%   { background-position: 130% 0; }
  100% { background-position: -130% 0; }
}
.icon-btn {
  width: 36px; height: 36px; border-radius: 9px; flex: none;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-2);
  display: inline-flex; align-items: center; justify-content: center; padding: 0;
  text-decoration: none;
  transition: color .12s, border-color .12s;
}
.icon-btn:hover { color: var(--ink); border-color: var(--muted); }
.icon-btn svg { width: 17px; height: 17px; }
/* App pages (dashboard, client detail, settings) get more width than the
   marketing pages so the client table has room before columns wrap. */
.main-pad { padding-bottom: 72px; max-width: 1600px; }

/* ── owner home ──────────────────────────────────────── */
.owner-head { display: flex; align-items: flex-start; gap: 16px; margin: 40px 0 8px; flex-wrap: wrap; }
.owner-head .grow { flex: 1; }
.owner-hi { color: var(--muted); font-size: 13.5px; margin: 0 0 6px; }
.verdict-title {
  font-family: var(--serif); font-weight: 480; font-size: clamp(30px, 4vw, 40px);
  letter-spacing: -.012em; line-height: 1.12; margin: 0; text-wrap: balance;
}
.verdict-sub { color: var(--ink-2); font-size: 15.5px; margin: 10px 0 0; max-width: 56ch; }
.verdict-ring { margin-top: 42px; }
.company-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 18px; margin-top: 32px; }
.company-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow-sm); padding: 22px 22px 18px;
  display: flex; flex-direction: column; gap: 14px;
  transition: box-shadow .15s, border-color .15s, transform .15s;
}
/* Lifting the whole card is honest here — it summarizes exactly one entity
   and its one action ("Filing history"), unlike e.g. a group card that
   contains several independent links and shouldn't imply a single click
   target by moving as one piece. */
.company-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.company-card .c-top { display: flex; align-items: flex-start; gap: 10px; }
.company-card h3 { margin: 0; font-size: 16.5px; font-weight: 650; letter-spacing: -.005em; flex: 1; }
.c-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 16px; }
.c-fact .k { font-size: 11px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.c-fact .v { font-size: 14px; font-weight: 550; margin-top: 1px; }
.c-fact .v.mono { font-size: 13px; }
.c-fact .note { font-weight: 400; }
.c-foot { display: flex; align-items: center; gap: 12px; border-top: 1px solid var(--line); padding-top: 13px; }
.c-foot .checked { font-size: 12.5px; }
.owner-note { margin-top: 36px; font-size: 13px; color: var(--muted); max-width: 68ch; }
.owner-ask { margin-top: 14px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.owner-ask .owner-note { margin-top: 0; }

/* ── firm dashboard ──────────────────────────────────── */
/* Page title. One rule for every signed-in page — these had drifted to
   28px/500, 27px/520 and 27px/520, which reads as three slightly different
   pages rather than one product. See also .detail-head h2 and h2.page-title,
   which share this. */
.firm-head h2, .detail-head h2, h2.page-title {
  font-family: var(--serif); font-weight: 520; font-size: 27px;
  letter-spacing: -.008em; margin: 0 0 4px; text-wrap: balance;
}
/* Same leading gap on the pages that open with the title, so they don't start
   at different heights. The detail page keeps its own — it has a back-link
   row above the title and would otherwise sit far down the page. */
.firm-head { margin: 36px 0 22px; }

/* Renewals-ahead widget: horizontal strip of the soonest upcoming due dates. */
.upcoming-widget { margin: 0 0 18px; }
.upcoming-head {
  font-size: 11px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-2); margin: 0 0 8px;
}
.upcoming-scroll { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 2px; }
.upcoming-card {
  flex: none; display: flex; flex-direction: column; gap: 3px; min-width: 148px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: 11px 14px; text-decoration: none; color: var(--ink-1);
  box-shadow: var(--shadow-sm); transition: border-color .12s, box-shadow .12s, transform .12s;
}
.upcoming-card:hover { border-color: var(--line-strong); box-shadow: var(--shadow-md); transform: translateY(-2px); }
.upcoming-name { font-weight: 620; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 180px; }
.upcoming-state { font-size: 11px; color: var(--muted); }
.upcoming-days { font-size: 12.5px; font-weight: 650; margin-top: 2px; }
.upcoming-clear {
  display: flex; align-items: center; gap: 12px;
  background: var(--good-tint); border: 1px solid var(--good); border-radius: 12px;
  padding: 12px 16px; color: var(--good-text);
}
.upcoming-clear-icon {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--good); color: var(--surface); font-size: 15px; font-weight: 700;
}
.upcoming-clear-title { font-weight: 650; font-size: 14px; }
.upcoming-clear-sub { font-size: 12.5px; color: var(--ink-2); margin-top: 1px; }
/* Neutral variant: "not fully confirmed yet" is not a clean bill of health
   (green) and not an error (red/amber) — it's simply unresolved, so it gets
   the same muted treatment as the "unknown" status dot elsewhere. */
.upcoming-clear--neutral { background: var(--surface-2); border-color: var(--line-strong); color: var(--ink-2); }
.upcoming-clear--neutral .upcoming-clear-icon { background: var(--muted); }

/* Renewals-ahead widget while a check is in flight for the firm: same
   dim + shimmer language as the table's own pending rows (see
   #client-rows tr[data-pending="1"] above), so "still confirming" reads
   consistently across the page rather than the widget just popping in. */
.upcoming-skeleton {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 16px;
}
.upcoming-skeleton-icon {
  flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--surface-2);
}
.upcoming-skeleton-line {
  border-radius: 5px; background: var(--surface-2);
}
.upcoming-skeleton-line--title { width: 120px; height: 12px; margin-bottom: 7px; }
.upcoming-skeleton-line--sub { width: 220px; height: 10px; }
.upcoming-skeleton-note { font-size: 12px; color: var(--muted); margin: 6px 2px 0; }
.upcoming-widget--pending .upcoming-skeleton-icon,
.upcoming-widget--pending .upcoming-skeleton-line {
  position: relative; overflow: hidden;
}
.upcoming-widget--pending .upcoming-skeleton-icon::after,
.upcoming-widget--pending .upcoming-skeleton-line::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 35%,
    color-mix(in srgb, var(--accent) 14%, transparent) 50%, transparent 65%);
  background-size: 250% 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .upcoming-widget--pending .upcoming-skeleton-icon::after,
  .upcoming-widget--pending .upcoming-skeleton-line::after {
    animation: skeleton-sweep 1.8s ease-in-out infinite;
  }
}

/* Compact status filter (replaces the big tile grid — only non-empty statuses render). */
.status-filter { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; }
.status-filter .chip {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 12px; font-size: 13px; font-weight: 550; color: var(--ink-1);
  cursor: pointer; transition: border-color .12s, box-shadow .12s, background .12s;
}
.status-filter .chip:hover { border-color: var(--line-strong); }
.status-filter .chip[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.status-filter .chip .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.status-filter .chip .chip-n { color: var(--ink-2); font-variant-numeric: tabular-nums; font-weight: 620; }

/* Quick pop-in for the dashboard's headline numbers (chip counts, the
   summary line) — not the landing page's full count-from-zero. That's a
   nice one-time "wow" on a page you visit once; on a page opened many times
   a day it'd be a tic. This is fast (180ms) and plays once on load, no
   scroll-trigger needed since these numbers are always above the fold. */
.stat-pop, .status-filter .chip .chip-n { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .stat-pop, .status-filter .chip .chip-n {
    animation: stat-pop .22s cubic-bezier(.2, .8, .3, 1.1) backwards;
  }
  .status-filter .chip:nth-child(1) .chip-n { animation-delay: 0ms; }
  .status-filter .chip:nth-child(2) .chip-n { animation-delay: 35ms; }
  .status-filter .chip:nth-child(3) .chip-n { animation-delay: 70ms; }
  .status-filter .chip:nth-child(4) .chip-n { animation-delay: 105ms; }
  .status-filter .chip:nth-child(5) .chip-n { animation-delay: 140ms; }
  .status-filter .chip:nth-child(6) .chip-n { animation-delay: 175ms; }
}
@keyframes stat-pop {
  from { opacity: 0; transform: scale(.85) translateY(1px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
.btn-remove { color: var(--ink-2); font-size: 13px; line-height: 1; padding: 6px 9px; }
.btn-remove:hover { color: var(--crit, #c0362c); border-color: var(--crit, #c0362c); }

/* Group / tag chips under a client's name */
.tag-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 4px; }
.tag-chip {
  font-size: 11px; font-weight: 600; letter-spacing: .02em; color: var(--ink-2);
  background: var(--surface-2, rgba(0,0,0,.035)); border: 1px solid var(--line);
  border-radius: 999px; padding: 1px 8px; line-height: 1.5;
}
.tag-chip--assignee { color: var(--accent); border-color: var(--accent); background: var(--accent-weak, transparent); }
/* The client (group) chip is the structural one — filled, so it reads as a
   parent rather than just another free-text label. */
.tag-chip--client {
  background: var(--accent); color: var(--accent-contrast); border-color: var(--accent);
  text-decoration: none; font-weight: 650;
}
.tag-chip--client:hover { background: var(--accent-hover); }

/* --- Clients (groups) page --- */
.group-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 16px; margin-bottom: 26px; }
.group-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  padding: 18px 20px; box-shadow: var(--shadow-sm);
}
.group-card-head { display: flex; align-items: flex-start; gap: 12px; }
.group-card-head .grow { flex: 1; min-width: 0; }
.group-card h3 { font-size: 17px; font-weight: 650; margin: 0 0 3px; color: var(--ink); }
.group-meta { font-size: 12.5px; color: var(--muted); margin: 0; }
.group-entities { list-style: none; margin: 14px 0 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.group-entities li { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.group-entities li a { color: var(--ink); text-decoration: none; font-weight: 550; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.group-notes { font-size: 12.5px; color: var(--ink-2); margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--line); }
.group-edit { margin-top: 14px; }
.group-edit .form-card { max-width: 100%; }
/* Opened only via the card's "⋮" menu (data-open-edit in groups.js) — its own
   native <summary> toggle would be a second, redundant way to reach the same
   form, right after we consolidated card-level actions into one menu. */
details.group-edit > summary { display: none; }

.group-card-head { position: relative; }
.group-card-head .action-menu { flex: none; }
.group-entities li .subtle-link { flex: none; }

/* Live "a check is running" banner on an entity's page. */
.job-banner {
  display: flex; align-items: flex-start; gap: 11px; margin: 16px 0 0;
  background: var(--accent-wash); border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--line));
  border-radius: 12px; padding: 13px 16px; font-size: 13.5px; color: var(--ink-2);
  line-height: 1.5;
}
.job-banner strong { color: var(--ink-1); }
.job-banner-body { flex: 1; min-width: 0; }

/* Copy-to-clipboard row (invite fallback link) */
.copy-row { display: flex; gap: 8px; margin-top: 10px; }
.copy-input {
  flex: 1; min-width: 0; font-family: var(--mono); font-size: 12px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong);
  border-radius: 8px; padding: 7px 10px;
}

/* --- Integrations --- */
.integration-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; margin: 18px 0 6px; }
.integration-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  padding: 20px; box-shadow: var(--shadow-sm); display: flex; flex-direction: column;
}
.integration-card h3 { font-size: 17px; font-weight: 650; margin: 0 0 8px; color: var(--ink); }
.integration-help { font-size: 13px; line-height: 1.55; color: var(--ink-2); margin: 0 0 14px; }
.integration-form { display: grid; gap: 12px; margin-top: auto; }
.integration-form label { display: grid; gap: 5px; font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.integration-form input {
  background: var(--page); color: var(--ink); border: 1px solid var(--line-strong);
  border-radius: 9px; padding: 9px 11px; font-family: inherit; font-size: 13.5px;
}
.integration-note { font-size: 11.5px; color: var(--muted); margin: 10px 0 0; }

/* Import preview: duplicate rows are dimmed since they'll be skipped. */
.row-dupe { opacity: .55; }

/* --- Client + related entities panel on a detail page --- */
.rel-panel { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
.rel-block {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 16px 18px; box-shadow: var(--shadow-sm);
}
.rel-client { font-size: 15px; font-weight: 650; margin-top: 4px; }
.rel-client a { color: var(--accent); text-decoration: none; }

.rel-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.rel-list li { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.rel-list li > a { color: var(--ink); text-decoration: none; font-weight: 550; flex: 1;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rel-entity { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.rel-entity a { color: var(--ink); text-decoration: none; font-weight: 550;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rel-note { font-size: 11.5px; color: var(--muted); }

/* Toolbar row above the table: order-mode note (left) + manage pencil (right) */
.table-toolbar2 { display: flex; align-items: center; gap: 10px; margin: 0 0 10px; flex-wrap: wrap; }
.order-note { font-size: 12.5px; color: var(--ink-2); }
.order-note.dim { color: var(--muted); }
.table-toolbar2 form.inline-form { margin: 0; display: contents; }

/* Manage mode: hide the normal row actions, show reorder/edit/remove instead. */
/* Selection column: only present in manage mode, so the default read-only
   view stays uncluttered. */
.sel-cell { display: none; width: 34px; }
.table-card.manage-mode .sel-cell { display: table-cell; }
.sel-cell input { width: 15px; height: 15px; cursor: pointer; accent-color: var(--accent); }

/* Bulk action bar — appears under the toolbar once rows are selected. */
.bulk-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 12px;
  background: var(--accent-wash); border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--line));
  border-radius: 12px; padding: 10px 14px;
}
.bulk-bar[hidden] { display: none; }
.bulk-bar .spacer { flex: 1; }
.bulk-count { font-size: 13px; color: var(--ink-2); }
.bulk-count strong { color: var(--accent); font-variant-numeric: tabular-nums; }
.bulk-bar select, .bulk-input {
  background: var(--page); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 8px;
  padding: 6px 9px; font-family: inherit; font-size: 13px;
}
.bulk-input { width: 118px; }
/* Shown instead of the group select/button when a firm has no client
   groups yet — otherwise the whole capability is invisible until you've
   already found /groups some other way. Sized down to match the rest of
   the compact bulk bar, not .lp-textlink's larger marketing-page size. */
.bulk-group-hint { font-size: 13px; font-weight: 600; }

.cell-actions.manage-actions { display: none; }
.table-card.manage-mode .cell-actions.view-actions { display: none; }
.table-card.manage-mode .cell-actions.manage-actions { display: flex; }
.icon-btn-sm { width: 28px; height: 28px; border-radius: 7px; font-size: 13px; }
.icon-btn[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
/* Account-type radio choice (Google finish page) */
.choose-radios { border: none; padding: 0; margin: 0 0 6px; display: flex; flex-direction: column; gap: 10px; }
.choose-radios legend { font-size: 13px; font-weight: 600; color: var(--ink-1); padding: 0; margin-bottom: 4px; }
.choose-radio {
  display: flex; align-items: flex-start; gap: 11px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 11px; padding: 12px 14px;
  transition: border-color .12s, box-shadow .12s;
}
.choose-radio:hover { border-color: var(--line-strong); }
.choose-radio:has(input:checked) { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.choose-radio input { margin-top: 3px; flex: none; }
.choose-radio-text { display: flex; flex-direction: column; gap: 1px; }
.choose-radio-title { font-weight: 600; font-size: 14px; color: var(--ink-1); }
.choose-radio-sub { font-size: 12.5px; color: var(--ink-2); }

/* Google sign-in button + "or" separator */
.btn-google {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 11px 16px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line-strong);
  color: var(--ink-1); font-weight: 550; font-size: 15px; cursor: pointer;
  transition: background .12s, border-color .12s;
}
.btn-google:hover { background: var(--surface-2, rgba(0,0,0,.03)); border-color: var(--ink-2); }
.btn-google .g-icon { flex: none; }
.oauth-sep {
  display: flex; align-items: center; gap: 12px; margin: 16px 0;
  color: var(--ink-2); font-size: 12.5px;
}
.oauth-sep::before, .oauth-sep::after { content: ""; flex: 1; height: 1px; background: var(--line); }

.trial-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--surface); border: 1px solid var(--accent); border-radius: 12px;
  padding: 10px 16px; margin: 0 0 18px; font-size: 14px; color: var(--ink-1);
  box-shadow: 0 0 0 1px var(--accent-weak, transparent);
}

/* Toast shown alongside a pending check-form button — reinforces the wait
   with more room to explain than the button label alone. */
.check-toast {
  position: fixed; left: 50%; bottom: 22px; z-index: 50;
  transform: translateX(-50%) translateY(16px); opacity: 0; pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
  display: flex; flex-direction: column; gap: 8px;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 12px;
  box-shadow: var(--shadow-md); padding: 13px 18px; width: min(340px, calc(100vw - 32px));
}
.check-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }
.check-toast-text { display: flex; flex-direction: column; gap: 2px; }
.check-toast-title { font-weight: 620; font-size: 13.5px; color: var(--ink-1); }
.check-toast-note { font-size: 12.5px; color: var(--ink-2); line-height: 1.4; }
.check-toast-eta { font-size: 11.5px; color: var(--muted); margin-top: 1px; }

/* Estimated-progress bar: paced by real elapsed time against a typical
   duration (see startEstimatedProgress in checking.js), not a fabricated
   number — it's honest about being an estimate by design, capping short of
   100% and only reaching full width when the operation actually completes
   (the page navigates or the job-banner stops rendering). */
.progress-bar {
  display: block; width: 100%; height: 6px; border-radius: 999px; overflow: hidden;
  background: var(--line);
}
.progress-bar-fill {
  display: block; height: 100%; width: 0%; border-radius: 999px; background: var(--accent);
  transition: width .3s linear;
}
@media (prefers-reduced-motion: reduce) { .progress-bar-fill { transition: none; } }
.job-banner .progress-bar { margin-top: 8px; }

/* Top-of-viewport loading bar (import verify's "searching" wait) — same
   estimated-progress pacing as .progress-bar-fill, just a slim strip
   pinned across the very top of the window instead of inline content, so
   it reads at a glance without competing with the game below it. */
.top-loading-bar {
  position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 60;
  background: var(--line); overflow: hidden;
}
.top-loading-bar-fill {
  display: block; height: 100%; width: 0%; background: var(--accent);
  transition: width .3s linear;
}
@media (prefers-reduced-motion: reduce) { .top-loading-bar-fill { transition: none; } }

/* Waiting-room game (import verify): a small self-contained canvas runner
   so the wait reads as "here's something to do" instead of dead time.
   Purely decorative -- never blocks or delays the actual search/redirect. */
.wait-game-wrap { margin-top: var(--space-5, 28px); max-width: 640px; }
.wait-game-canvas {
  display: block; width: 100%; height: 200px; border-radius: 12px;
  background: var(--surface-2); border: 1px solid var(--line); touch-action: manipulation;
}
.wait-game-hint { font-size: 12.5px; color: var(--muted); margin-top: 8px; }
.wait-game-score { font-size: 13px; font-weight: 650; color: var(--ink-2); margin-bottom: 8px; }

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 0 0 22px; }
.tile {
  background: var(--surface); border: 1px solid var(--line); border-radius: 13px;
  padding: 14px 16px 12px; text-align: left;
  display: flex; flex-direction: column; gap: 2px;
  box-shadow: var(--shadow-sm);
  transition: border-color .12s, box-shadow .12s;
}
.tile:hover { border-color: var(--line-strong); box-shadow: var(--shadow-md); }
.tile[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), var(--shadow-sm); }
.tile .lbl {
  font-size: 11px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-2); display: flex; align-items: center; gap: 6px;
}
.tile .lbl .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.tile .val { font-size: 27px; font-weight: 620; line-height: 1.2; }
.tile .val.tile-link { color: inherit; text-decoration: none; }
.tile .val.tile-link:hover { color: var(--accent); }
.tile-sub { font-size: 11.5px; color: var(--ink-2); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }

/* Admin founder-metrics: a plain 14-day checks-run bar list -- no chart
   library, just a row per day with a width-scaled fill (same idea as
   .progress-bar-fill elsewhere in the app). */
.admin-daily-checks { display: flex; flex-direction: column; gap: 5px; margin: 0 0 22px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 13px; padding: 14px 18px; }
.admin-daily-checks-row { display: grid; grid-template-columns: 56px 1fr 36px; align-items: center; gap: 12px; }
.admin-daily-checks-date { font-size: 12px; color: var(--muted); }
.admin-daily-checks-bar-wrap { height: 8px; border-radius: 5px; background: var(--surface-2); overflow: hidden; }
.admin-daily-checks-bar { display: block; height: 100%; border-radius: 5px; background: var(--accent); }
.admin-daily-checks-count { font-size: 12px; color: var(--ink-2); text-align: right; font-variant-numeric: tabular-nums; }
/* "Needs review" tile only gets the warning treatment when it's actually
   nonzero -- a red-bordered tile reading "0" would be a false alarm, exactly
   what this app promises never to show. */
.tile--warn { border-color: color-mix(in srgb, var(--crit) 45%, var(--line)); }
.tile--warn .val { color: var(--crit-text); }
/* Amber, not .tile--warn's red -- for tiles flagging something worth a look
   without the same urgency as "Needs review" (e.g. registered agent issues). */
.tile--caution { border-color: color-mix(in srgb, var(--warn) 45%, var(--line)); }
.tile--caution .val { color: var(--warn-text); }
/* Dashboard summary tiles read as the page's headline, so they run a size
   step above the admin-page tiles that share this component. */
.dash-tiles .val { font-size: 32px; }

/* Dashboard charts: status breakdown (part-to-whole) + entities by state
   (ranked magnitude). Same card chrome as .tile/.upcoming-card so the whole
   summary section reads as one system. */
.dash-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px; margin: 0 0 18px; }
.chart-card { background: var(--surface); border: 1px solid var(--line); border-radius: 13px;
  padding: 16px 18px 18px; box-shadow: var(--shadow-sm); }
.chart-card-head { margin: 0 0 14px; }
.chart-card-head h3 { margin: 0; font-size: 14.5px; font-weight: 650; color: var(--ink); }
.chart-card-head p { margin: 2px 0 0; font-size: 12px; color: var(--muted); }
.chart-card-note { margin: 10px 0 0; font-size: 12px; color: var(--muted); }

/* Status breakdown: one horizontal stacked bar, 2px surface gaps between
   segments, rounded only at the two outer ends (overflow:hidden on the
   track clips the flex children to that shape; the segments themselves stay
   square, so the "rounded end / square meet" mark spec falls out for free). */
.status-bar { display: flex; gap: 2px; height: 18px; border-radius: 8px;
  overflow: hidden; background: var(--surface-2); }
.status-bar-seg { display: block; height: 100%; min-width: 0; transition: width .25s ease; }
.status-legend { list-style: none; margin: 14px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 8px 18px; font-size: 12.5px; color: var(--ink-2); }
.status-legend li { display: flex; align-items: center; gap: 7px; }
.status-legend .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.status-legend strong { color: var(--ink); font-weight: 650; }

/* Entities by state: single-hue ranked bars (nominal categories, one
   series -- same accent for every row, no legend needed), value labeled
   outside the bar's end rather than risking a clipped in-bar label. */
.state-bar-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.state-bar-list li { display: flex; align-items: center; gap: 10px; }
.state-bar-label { flex: none; width: 30px; font-size: 12.5px; font-weight: 650; color: var(--ink-2); }
.state-bar-track { flex: 1 1 auto; height: 9px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.state-bar-fill { display: block; height: 100%; border-radius: 999px; background: var(--accent);
  transition: width .25s ease; }
.state-bar-count { flex: none; width: 26px; text-align: right; font-size: 12.5px;
  font-weight: 650; color: var(--ink); font-variant-numeric: tabular-nums; }

.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }
.toolbar form { margin: 0; }
.toolbar input[type="search"], .toolbar select {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 9px 12px; font-family: inherit; font-size: 13.5px;
}
.toolbar input[type="search"] { width: 230px; }
.result-count { font-size: 12.5px; color: var(--muted); }
/* Hairline divider between the action cluster and the filter cluster, so a
   long toolbar still reads as two groups rather than one undifferentiated row. */
.toolbar-sep { width: 1px; align-self: stretch; background: var(--line-strong); margin: 2px 2px; }
/* Pushes the Actions menu to the far right of the toolbar (search/filters
   stay left-aligned) — it sits directly above the first entity row either
   way, since the table starts right below this row. */
.toolbar-actions { margin-left: auto; }
.subtle-link { font-size: 12.5px; font-weight: 550; color: var(--ink-2); }
.subtle-link:hover { color: var(--accent); }

/* "Actions" dropdown (Add entity / Run all checks) — a native <details> so
   it needs no JS to open/close; the page navigates or reloads on every item
   inside it anyway, which closes it for free. */
.action-menu { position: relative; }
.action-menu > summary { list-style: none; }
.action-menu > summary::-webkit-details-marker { display: none; }
.action-menu-btn { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.action-menu-chevron { width: 14px; height: 14px; transition: transform .12s ease; }
.action-menu[open] .action-menu-chevron { transform: rotate(180deg); }
.action-menu-panel {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 30; min-width: 200px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: var(--shadow-md); padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.action-menu-panel form { margin: 0; }
.action-menu-item {
  display: block; width: 100%; text-align: left; padding: 8px 10px; border-radius: 7px;
  background: none; border: none; color: var(--ink); font-size: 13.5px; font-weight: 550;
  font-family: inherit; text-decoration: none; cursor: pointer;
}
.action-menu-item:hover { background: var(--surface-2); }
.action-menu-divider { height: 1px; background: var(--line); margin: 4px 6px; }
/* Right-aligned variant: for a trigger sitting at the end of a row (e.g. the
   groups-page per-entity menu), the panel must hang off the trigger's right
   edge, not its left, or it overflows the row/card. */
.action-menu-panel--right { left: auto; right: 0; min-width: 170px; }

.group-entities li .action-menu { flex: none; }
.group-entities li .action-menu > summary { color: var(--ink-2); }

.table-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  overflow-x: auto; box-shadow: var(--shadow-sm);
}
.table-card table { border-collapse: collapse; width: 100%; min-width: 840px; }
th {
  text-align: left; font-size: 11px; font-weight: 650;
  letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); padding: 12px 16px; border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
/* 11px, not 13: rows carry up to three lines (name, entity #, chips), so
   the padding compounds. At 13 a firm with 200 entities sees about ten per
   screen; this recovers roughly two more rows per viewport without the
   text itself getting tighter. */
td { padding: 11px 16px; border-bottom: 1px solid var(--line); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
td.num { font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; }
td form { margin: 0; }
.client-link { color: var(--ink); text-decoration: none; }

.client-name { font-weight: 620; }
.entity-no { color: var(--muted); font-family: var(--mono); font-size: 11.5px; }
.state-cell { white-space: nowrap; }
/* Dashboard table only: one consistent size/family across every cell
   (name, entity #, state, group, next due, last checked) instead of the
   mix of body/mono/12.5px/11.5px sizes those classes carry everywhere
   else they're reused (client detail, groups, etc., left untouched). */
#client-rows td { font-size: 13.5px; color: var(--ink-2); }
#client-rows td.cell-client .client-name { font-size: 13.5px; color: var(--ink); }
#client-rows .entity-no { font-family: var(--sans); font-size: 13.5px; color: var(--ink-2); }
#client-rows td.num { font-family: var(--sans); font-size: 13.5px; }
#client-rows .fresh { font-size: 13.5px; }
/* Entity #, State, and Client group read as identity/attribute columns, not
   scanning-left-to-right data, so their header + cell contents (including
   the empty-state dash) are centered rather than left-aligned. Desktop only
   — the ≤640px table-as-cards layout right-aligns every value against its
   label instead (see mobile section below), which this would fight with. */
@media (min-width: 641px) {
  #client-table-card thead th:nth-child(3), #client-table-card thead th:nth-child(4), #client-table-card thead th:nth-child(5),
  #client-rows td.entity-no-cell, #client-rows td.state-cell, #client-rows td.group-cell { text-align: center; }
}
/* Countdowns are the number a firm scans for, so they get the display face
   and tabular figures — the column lines up and reads as data, not prose. */
.days-overdue, .days-soon, .days-ok {
  font-family: var(--serif); font-size: 15px; font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.days-overdue { color: var(--crit-text); font-weight: 600; }
.days-soon { color: var(--warn-text); font-weight: 600; }
.days-ok { color: var(--muted); font-weight: 500; }

/* Severity stripe: urgency readable before you parse a single word. It has to
   sit inside the row's first *visible* cell — .sel-cell is display:none outside
   manage mode, and a negative offset off .cell-client lands outside the card,
   where .table-card's overflow-x clips it away. So: paint it at left:0 of
   whichever cell leads the row, inside that cell's own 16px left padding. */
#client-rows td.cell-client, #client-rows td.sel-cell { position: relative; }
/* ":not(.manage-mode) .cell-client" and ".manage-mode .sel-cell" = the leading
   cell in each mode. Only that one paints. */
.table-card:not(.manage-mode) #client-rows tr[data-status="delinquent"] td.cell-client::before,
.table-card:not(.manage-mode) #client-rows tr[data-status="error"] td.cell-client::before,
.table-card:not(.manage-mode) #client-rows tr[data-status="due_soon"] td.cell-client::before,
.table-card.manage-mode #client-rows tr[data-status="delinquent"] td.sel-cell::before,
.table-card.manage-mode #client-rows tr[data-status="error"] td.sel-cell::before,
.table-card.manage-mode #client-rows tr[data-status="due_soon"] td.sel-cell::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  border-radius: 0 2px 2px 0;
}
#client-rows tr[data-status="delinquent"] td.cell-client::before,
#client-rows tr[data-status="delinquent"] td.sel-cell::before { background: var(--crit); }
#client-rows tr[data-status="error"] td.cell-client::before,
#client-rows tr[data-status="error"] td.sel-cell::before { background: var(--serious); }
#client-rows tr[data-status="due_soon"] td.cell-client::before,
#client-rows tr[data-status="due_soon"] td.sel-cell::before { background: var(--warn); }
/* Due dates are short; wrapping them across two lines just adds noise. */
#client-rows td[data-label="Next due"] { white-space: nowrap; }

/* Density: the entity name is the anchor, its metadata recedes. */
.client-name { font-size: 14.5px; letter-spacing: -.005em; }
#client-rows tr { transition: background .14s ease; }
#client-rows tr:hover { background: color-mix(in srgb, var(--accent) 4%, transparent); }
.table-card:not(.manage-mode) #client-rows tr[data-href] { cursor: pointer; }
@media (prefers-reduced-motion: reduce) { #client-rows tr { transition: none; } }

/* Freshness chip: colored dot + "checked N ago" */
.fresh { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--ink-2); white-space: nowrap; }
.fresh-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--muted); }
.fresh-fresh .fresh-dot { background: var(--good); }
.fresh-aging .fresh-dot { background: var(--warn); }
.fresh-stale .fresh-dot { background: var(--serious); }
.fresh-none { color: var(--muted); }
.fresh-none .fresh-dot { background: var(--line-strong); }

/* Detail-page freshness + refresh bar */
.freshness-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: 14px 0 2px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
}
.freshness-bar form { margin: 0; }
.freshness-bar .refresh-link { font-size: 13px; }
.fresh-hint { font-size: 12.5px; color: var(--muted); }
.pulls-left { font-variant-numeric: tabular-nums; }

/* Per-category standings breakdown */
.standings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 8px; }
.standing-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; box-shadow: var(--shadow-sm);
}
/* Set by checking.js exactly once, right after a check you were waiting on
   resolves — closes the loop on "you asked, here's what happened" instead of
   the page just silently reloading with new numbers. A ring, not a color
   change, since the standing itself might be unchanged (still current) and a
   color shift would wrongly imply something moved. */
.standings-grid.just-updated .standing-card {
  animation: standing-flash 1.1s ease-out;
}
.standings-grid.just-updated .standing-card:nth-child(2) { animation-delay: 60ms; }
.standings-grid.just-updated .standing-card:nth-child(3) { animation-delay: 120ms; }
.standings-grid.just-updated .standing-card:nth-child(4) { animation-delay: 180ms; }
@media (prefers-reduced-motion: reduce) {
  .standings-grid.just-updated .standing-card { animation: none; }
}
@keyframes standing-flash {
  0%   { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent), var(--shadow-sm); }
  100% { box-shadow: var(--shadow-sm); }
}
.standing-cat { font-size: 11px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.standing { display: inline-flex; align-items: center; gap: 7px; font-size: 14.5px; font-weight: 600; }
.st-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--muted); }
.st-good { color: var(--good-text); }
.st-good .st-dot { background: var(--good); }
.st-bad { color: var(--crit-text); }
.st-bad .st-dot { background: var(--crit); }
.st-na, .st-unknown { color: var(--muted); }
.st-na .st-dot, .st-unknown .st-dot { background: var(--line-strong); }

/* Branded error page */
.error-card { text-align: center; }
.error-code {
  font-size: 13px; font-weight: 700; letter-spacing: .12em; color: var(--muted);
  margin-bottom: 4px;
}
.error-card .btn { margin-top: 18px; }

/* Entity facts / addresses / filing history */
.facts-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: 12px;
  overflow: hidden; margin-bottom: 12px;
}
.fact { background: var(--surface); padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; }
.fact-lbl { font-size: 11px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.fact-val { font-size: 14.5px; font-weight: 550; color: var(--ink); }
.facts-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; margin-bottom: 12px; }
.addr-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 14px; display: flex; flex-direction: column; gap: 5px; box-shadow: var(--shadow-sm);
}
.addr-name { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.addr-line { font-size: 13.5px; color: var(--ink-2); line-height: 1.45; }
.filing-history { margin-bottom: 4px; }
.filing-history > summary {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 9px 16px; font-weight: 550; font-size: 14px; width: fit-content;
}
.filing-history > summary::-webkit-details-marker { display: none; }
.filing-history > summary::before { content: "+"; font-weight: 600; font-size: 15px; line-height: 1; }
.filing-history[open] > summary::before { content: "−"; }
.filing-history > summary:hover { color: var(--ink); border-color: var(--muted); }
.filing-history[open] > summary { margin-bottom: 12px; }

/* Dashboard row actions (View details + Check now) */
.cell-actions { display: flex; gap: 8px; align-items: center; justify-content: flex-end; }
.cell-actions form { margin: 0; }

/* Add-client search results */
.search-results { display: flex; flex-direction: column; gap: 12px; max-width: 720px; }
.result-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow-sm); padding: 16px 18px;
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
}
.result-main { flex: 1; min-width: 200px; }
.result-name { font-weight: 650; font-size: 15.5px; }
.result-meta { font-size: 13px; color: var(--ink-2); margin-top: 3px; display: flex; gap: 6px; flex-wrap: wrap; }
.result-addr { font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.result-select { margin: 0; }
@media (max-width: 560px) {
  .result-select, .result-select .btn, .result-select .btn-ghost { width: 100%; }
}
.result-card--weak { border-color: var(--warn); background: var(--warn-tint); }
/* Same warn treatment as .result-card--weak, for a weak-match candidate
   shown as a table row instead of a card (import verify walkthrough). */
tr.row-weak { background: var(--warn-tint); }
.result-warn {
  margin-top: 8px; font-size: 12.5px; line-height: 1.4;
  color: var(--warn-text); font-weight: 550;
}
.result-verify { display: inline-block; margin-top: 8px; font-size: 12.5px; }
.confirm-note {
  max-width: 720px; margin-bottom: 14px; padding: 12px 14px;
  background: var(--surface-2, var(--surface)); border: 1px solid var(--line);
  border-radius: 12px; font-size: 13px; color: var(--ink-2);
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
}
.confirm-footer {
  max-width: 720px; margin-top: 20px; padding-top: 18px;
  border-top: 1px solid var(--line);
}

/* Collapsible manual-entry section */
.manual-disclosure { margin-top: 8px; }
.manual-disclosure > summary {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 9px 16px; font-weight: 550; font-size: 14px; width: fit-content;
}
.manual-disclosure > summary::-webkit-details-marker { display: none; }
.manual-disclosure > summary::before { content: "+"; font-weight: 600; font-size: 15px; line-height: 1; }
.manual-disclosure[open] > summary::before { content: "−"; }
.manual-disclosure > summary:hover { color: var(--ink); border-color: var(--muted); }
.manual-disclosure[open] > summary { margin-bottom: 14px; }
.empty-cell { text-align: center; padding: 30px; color: var(--muted); }
/* First-run state: this is the whole first impression, so it explains the
   product's promise and offers every way in — not just a bare sentence. */
.empty-cell.empty-first { padding: 0; border-bottom: none; }
/* With no header row there's no min-width to honour either. */
.table-card--empty table { min-width: 0; }
.empty-wrap {
  max-width: 460px; margin: 0 auto; padding: 46px 24px 50px;
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 12px;
}
.empty-wrap.empty-inline { padding: 30px 24px 34px; }
.empty-mark {
  width: 52px; height: 52px; border-radius: 15px; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); margin-bottom: 2px;
}
.empty-mark svg { width: 26px; height: 26px; }
.empty-wrap h3 {
  font-family: var(--serif); font-weight: 560; font-size: 21px; letter-spacing: -.012em;
  color: var(--ink); margin: 0;
}
.empty-wrap p { font-size: 13.5px; line-height: 1.6; color: var(--ink-2); margin: 0; text-wrap: pretty; }
.empty-actions { display: flex; gap: 9px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }

/* ── detail & forms ──────────────────────────────────── */
.back-row { margin-top: 26px; }
.detail-head { margin: 20px 0 6px; display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.detail-meta { font-size: 13.5px; color: var(--ink-2); margin: 6px 0 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.detail-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.detail-actions form { margin: 0; }
.notes-card {
  background: var(--accent-wash); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 14px; font-size: 13.5px; color: var(--ink-2);
  margin: 16px 0 0; max-width: 640px;
}
.section-lbl {
  font-size: 11px; font-weight: 650; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); margin: 32px 0 12px;
}
.section-lbl--danger { color: var(--crit-text); }

/* Settings tab nav (Preferences / Manage account) — plain links, not JS tabs;
   each tab is its own route, styled to read as one tab bar. */
.settings-tabs { display: flex; gap: 4px; margin: 18px 0 28px; border-bottom: 1px solid var(--line); }
.settings-tabs a {
  padding: 9px 4px; margin-right: 22px; font-size: 14px; font-weight: 600; color: var(--ink-2);
  text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.settings-tabs a:hover { color: var(--ink); }
.settings-tabs a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }
.form-card--danger { border-color: var(--crit); background: var(--crit-tint); }
.form-card--danger .set-hint { color: var(--ink-2); }
.error-text { color: var(--serious-text); font-size: 12.5px; }
.src-link { color: var(--accent); font-weight: 550; font-size: 13px; text-decoration: none; }


.form-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow-sm); padding: 24px; max-width: 580px;
  display: grid; gap: 15px;
}
.form-card label { display: grid; gap: 6px; font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.form-card .opt { font-weight: 400; color: var(--muted); }
.form-card :is(input, select, textarea) {
  background: var(--page); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 9px 11px; font-family: inherit; font-size: 13.5px; font-weight: 400;
}
.form-card textarea { min-height: 72px; resize: vertical; }

.import-cell {
  background: var(--page); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 7px;
  padding: 6px 8px; font-family: inherit; font-size: 13.5px; font-weight: 400;
  width: 100%; min-width: 0;
}
.import-cell-state { text-transform: uppercase; }

/* --- File dropzone --------------------------------------------------------
   One real <input type="file"> covers the whole zone at opacity:0 (z-index
   above the visible layers) rather than a custom role="button" wrapper —
   the native input already does keyboard (Enter/Space), the OS file dialog,
   and accepting a dropped file, for free and correctly. dropzone.js only
   adds the things a plain input can't: drag visual feedback, a filename/size
   readout, and a real upload-progress bar driven by XHR's actual byte
   count — not a canned animation pretending to be progress. */
.dropzone {
  position: relative; border: 1.5px dashed var(--line-strong); border-radius: 12px;
  padding: 22px 20px; text-align: center; background: var(--page);
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.dropzone-input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; z-index: 2; margin: 0;
}
/* opacity:0 hides the input's own focus ring too, so the visible focus state
   lives on the wrapper instead, keyed off the real input's focus-visible. */
.dropzone:has(.dropzone-input:focus-visible) {
  outline: 2px solid var(--focus); outline-offset: 2px;
}
.dropzone.is-dragover {
  border-color: var(--accent); border-style: solid; background: var(--accent-wash);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 16%, transparent),
              0 0 24px color-mix(in srgb, var(--accent) 28%, transparent);
}
.dropzone.has-error { border-color: var(--crit); border-style: solid; }
.dropzone-icon { width: 26px; height: 26px; color: var(--muted); margin: 0 auto 8px; }
.dropzone.is-dragover .dropzone-icon { color: var(--accent); }
.dropzone-text { display: block; font-size: 13px; color: var(--ink-2); font-weight: 500; }
.dropzone-text strong { color: var(--ink); font-weight: 650; }
.dropzone-hint { display: block; font-size: 11.5px; color: var(--muted); margin-top: 3px; }
/* :not([hidden]), not a bare class rule: a class selector and the browser's
   own [hidden]{display:none} are equal specificity, and this stylesheet
   loads after the UA one — so a plain "display: flex" here would win and
   silently defeat `hidden`, showing the file row (and its clear button)
   even while idle. Same trap as the landing nav's hamburger icon earlier
   this project. */
.dropzone-file:not([hidden]) {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 13.5px; color: var(--ink); position: relative; z-index: 3;
}
.dropzone-filename { font-weight: 650; }
.dropzone-filesize { color: var(--muted); font-family: var(--mono); font-size: 11.5px; }
.dropzone-clear {
  background: none; border: none; color: var(--muted); cursor: pointer;
  font-size: 15px; line-height: 1; padding: 2px 5px; border-radius: 5px;
}
.dropzone-clear:hover { color: var(--crit); background: var(--crit-tint); }
.dropzone-progress { margin-top: 10px; position: relative; z-index: 3; }
.dropzone-bar {
  height: 6px; border-radius: 999px; background: var(--line); overflow: hidden;
}
.dropzone-bar-fill {
  height: 100%; width: 0%; background: var(--accent); border-radius: 999px;
  transition: width .15s ease;
}
.dropzone-pct {
  display: inline-block; margin-top: 5px; font-size: 11.5px; font-weight: 650;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.dropzone-error {
  margin: 8px 0 0; font-size: 12px; color: var(--crit-text); position: relative; z-index: 3;
}
@media (prefers-reduced-motion: reduce) { .dropzone-bar-fill { transition: none; } }
.color-field { display: flex; gap: 8px; align-items: stretch; }
.color-field input[type="text"] { flex: 1; }
.color-field input[type="color"] {
  flex: none; width: 44px; padding: 3px; cursor: pointer;
  background: var(--page); border: 1px solid var(--line-strong); border-radius: 9px;
}
.color-field input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.color-field input[type="color"]::-webkit-color-swatch { border: none; border-radius: 6px; }
.color-field input[type="color"]::-moz-color-swatch { border: none; border-radius: 6px; }
.form-card .row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 560px) { .form-card .row2 { grid-template-columns: 1fr; } }
.form-card .actions { display: flex; gap: 10px; margin-top: 2px; }
.form-hint { font-size: 13px; color: var(--muted); max-width: 580px; margin: 0 0 12px; }
h2.page-title { margin: 36px 0 4px; }
.page-sub { color: var(--muted); font-size: 13.5px; margin: 0 0 20px; }

/* Signup-flow progress ("Step 1 of 2" on 2FA setup, "Step 2 of 2" on the
   first-company form) -- neutral, not a status pill, so it doesn't compete
   with the good/warn/crit .pill vocabulary used everywhere else. */
.onboarding-step { display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 6px; }
/* Mobile: center the forced first-time 2FA screen (step indicator, title,
   copy, and the two method cards) rather than leaving it left-aligned. */
@media (max-width: 640px) {
  .onboarding-screen { text-align: center; }
  .onboarding-screen .group-grid { grid-template-columns: 1fr; }
}

/* ── settings ────────────────────────────────────────── */
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 10px; overflow: hidden; }
.seg button {
  background: var(--surface); border: none; color: var(--ink-2);
  padding: 8px 18px; font-weight: 550; font-size: 13.5px;
}
.seg button + button { border-left: 1px solid var(--line-strong); }
.seg button[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); font-weight: 650; }
.set-hint { font-size: 12.5px; color: var(--muted); margin: 10px 0 0; }
.m-rows { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; background: var(--surface); max-width: 580px; }
.m-row { display: flex; justify-content: space-between; gap: 14px; padding: 10px 14px; border-bottom: 1px solid var(--line); font-size: 13.5px; }
.m-row:last-child { border-bottom: none; }
.m-row .k { color: var(--muted); }
.m-row .v { font-weight: 600; text-align: right; }
.inline-form { display: flex; gap: 8px; align-items: center; margin: 0; }
.inline-form input {
  background: var(--page); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 7px;
  padding: 5px 9px; font-family: inherit; font-size: 12.5px; width: 150px;
}

/* ── mobile (≤640px) ─────────────────────────────────── */
@media (max-width: 640px) {
  .wrap { padding: 0 16px; }

  .rail { width: 100%; max-width: 100%; }

  /* Roomier headings */
  .firm-head { margin: 28px 0 18px; }
  .firm-head h2 { font-size: 24px; }

  /* Toolbar: full-width search */
  .toolbar input[type="search"] { flex: 1 1 100%; width: auto; }

  /* Client table → stacked cards (status is never off-screen) */
  .table-card { background: none; border: none; box-shadow: none; overflow: visible; }
  .table-card table { display: block; min-width: 0; width: 100%; }
  .table-card thead { display: none; }
  .table-card tbody { display: block; }
  .table-card tbody tr {
    display: block; background: var(--surface); border: 1px solid var(--line);
    border-radius: 14px; box-shadow: var(--shadow-sm); padding: 4px 16px; margin-bottom: 12px;
  }
  .table-card tbody tr td {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 10px 0; text-align: right; border-bottom: 1px solid var(--line);
  }
  .table-card tbody tr td:last-child { border-bottom: none; }
  .table-card tbody tr td::before {
    content: attr(data-label); text-align: left; white-space: nowrap;
    font-size: 11px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
  }
  .table-card td.cell-client { display: block; text-align: left; padding: 12px 0 11px; }
  .table-card td.cell-client::before { content: none; }
  .table-card td.cell-client .client-name { font-size: 16px; }
  .table-card td.num { justify-content: space-between; }
  .table-card td.row-action { display: block; padding: 12px 0 4px; }
  .table-card td.row-action::before { content: none; }
  .table-card td.row-action .cell-actions { flex-direction: column; gap: 8px; }
  .table-card td.row-action .cell-actions form,
  .table-card td.row-action .cell-actions .btn-sm { width: 100%; text-align: center; }
  .table-card td.empty-cell { display: block; text-align: center; padding: 24px; }
  .table-card td.empty-cell::before { content: none; }

  /* Two bugs the rules above didn't actually win, because the desktop rules
     they're meant to override carry higher specificity (an #client-rows id,
     in the stripe's case) — a media query doesn't add specificity on its
     own, so nesting a weaker selector in here was never enough:

     1. The severity stripe (see "Severity stripe" above) is absolutely
        positioned within td.cell-client, which on desktop is a slim padded
        table cell but on mobile becomes the whole multi-line card header —
        so the 3px bar stretches down and cuts across the entity name/number
        instead of sitting in a gutter. Re-declared at matching specificity
        (same selector list, later in the cascade) so content: none actually
        sticks here.
     2. .sel-cell (the checkbox column) is display:none outside manage mode,
        but the blanket "every td becomes flex" rule above is more specific
        than that base rule and was silently re-showing it — so a checkbox
        floated above every card even when nothing was selectable. */
  .table-card:not(.manage-mode) #client-rows tr[data-status="delinquent"] td.cell-client::before,
  .table-card:not(.manage-mode) #client-rows tr[data-status="error"] td.cell-client::before,
  .table-card:not(.manage-mode) #client-rows tr[data-status="due_soon"] td.cell-client::before,
  .table-card.manage-mode #client-rows tr[data-status="delinquent"] td.sel-cell::before,
  .table-card.manage-mode #client-rows tr[data-status="error"] td.sel-cell::before,
  .table-card.manage-mode #client-rows tr[data-status="due_soon"] td.sel-cell::before {
    content: none;
  }
  .table-card:not(.manage-mode) td.sel-cell { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .tile, .btn, .btn-ghost, .btn-danger, .icon-btn, .company-card, .rail-nav a { transition: none; }
}

/* ============================================================================
   ELEVATED LANDING PAGE
   ========================================================================== */
.lp { --lp-state: var(--accent);
      --lp-state-line: var(--surface);
      --lp-maxw: 1180px; overflow-x: clip; }
.lp .wrap { max-width: var(--lp-maxw); }
.has-js .lp .reveal { opacity: 0; transform: translateY(18px); }
.lp .reveal { transition: opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1); }
.lp .reveal.in { opacity: 1; transform: none; }

/* --- Nav --- */
.lp-nav { position: sticky; top: 0; z-index: 40; padding: 16px 0;
  border-bottom: 1px solid transparent; transition: background .3s, border-color .3s, backdrop-filter .3s; }
.lp-nav.is-stuck { background: color-mix(in srgb, var(--page) 78%, transparent);
  backdrop-filter: saturate(1.6) blur(14px); -webkit-backdrop-filter: saturate(1.6) blur(14px);
  border-bottom-color: var(--line); }
.lp-nav .wrap { display: flex; align-items: center; gap: 22px; }
.lp-nav .spacer { flex: 1; }
.lp-navlink { color: var(--ink-2); font-size: 14.5px; font-weight: 550; text-decoration: none; }
.lp-navlink:hover { color: var(--ink); }
/* Sign in / Request access: same width regardless of label length, so the
   pair reads as one balanced unit rather than two arbitrarily-sized
   buttons. Also pins font-size back to 14px on "Sign in" — .lp-navlink
   (needed there so it hides alongside the other nav links on mobile,
   see the media query below) was quietly overriding .btn-ghost's own
   14px with its own 14.5px, another source of the size mismatch. */
.lp-nav-auth { min-width: 144px; font-size: 14px; }

/* --- Mobile hamburger: below ~720px the nav links + "Sign in" (also
   .lp-navlink) collapse behind a hamburger; the primary CTA stays put in
   the bar, same pattern as most marketing sites (Karbon et al). --- */
.lp-nav-toggle {
  display: none; flex: none; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 9px; border: 1px solid var(--line-strong);
  background: var(--surface); color: var(--ink-2); cursor: pointer;
}
.lp-nav-toggle:hover { color: var(--ink); border-color: var(--muted); }
.lp-nav-toggle-icon { width: 19px; height: 19px; }
/* The `hidden` attribute's UA display:none doesn't reliably apply to <svg>
   in every browser — make it explicit rather than trust the default. */
.lp-nav-toggle-icon[hidden] { display: none; }
.lp-mobile-menu[hidden] { display: none; }
.lp-mobile-menu {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 39;
  display: flex; flex-direction: column;
  background: var(--surface); border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-md); padding: 6px 20px 18px;
}
/* Direct-child combinator -- the plain nav links (Who it's for/Coverage/
   Pricing) are direct children of .lp-mobile-menu, but "Request access"/
   "Sign in" sit one level deeper inside .lp-mobile-menu-actions. A plain
   descendant selector here used to catch those buttons too, overriding
   their intended white .btn text with dark --ink -- black text on the
   blue "Request access" pill. */
.lp-mobile-menu > a {
  color: var(--ink); font-size: 15.5px; font-weight: 600; text-decoration: none;
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
.lp-mobile-menu-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.lp-mobile-menu-actions .btn, .lp-mobile-menu-actions .btn-ghost { width: 100%; padding: 11px; }

@media (max-width: 720px) {
  .lp-navlink { display: none; }
  .lp-nav-toggle { display: inline-flex; }
}
@media (max-width: 480px) {
  /* Once the nav links + Sign in are gone, only the logo, one CTA button,
     and the hamburger remain — tighten the gap so they don't crowd the
     wordmark (white-space:nowrap on .btn already stops label wrapping). */
  .lp-nav .wrap { gap: 10px; }
  .lp-nav .btn { padding: 7px 12px; font-size: 13px; }
  .lp-nav .logo-name { font-size: 17px; }
}

/* --- Hero --- */
.lp-hero { position: relative; padding: clamp(36px, 6vw, 84px) 0 clamp(48px, 7vw, 100px); }
/* A whisper of structure behind the aurora glow — dots, not a starfield, and
   faded toward the edges via the mask so it reads as depth near the headline
   rather than a repeating pattern with a visible cutoff. Sits under the
   aurora so the glow washes over it instead of the two competing. */
.lp-dotgrid { position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(var(--line-strong) 1.5px, transparent 1.5px);
  background-size: 26px 26px; opacity: .65;
  mask-image: radial-gradient(85% 80% at 40% 38%, black, transparent 85%);
  -webkit-mask-image: radial-gradient(85% 80% at 40% 38%, black, transparent 85%); }
/* Two blobs, not one shared background — ::before/::after each carry their
   own gradient and their own animation timing, so they drift at different
   speeds and cross paths rather than moving as a single locked-together
   shape. Same accent hue throughout (--accent vs. --accent-hover, its
   built-in darker/lighter counterpart) — texture from tone, not a new color. */
.lp-aurora { position: absolute; inset: -30% -10% auto -10%; height: 90%; z-index: 0; pointer-events: none;
  filter: blur(30px); }
.lp-aurora::before, .lp-aurora::after { content: ""; position: absolute; border-radius: 50%; opacity: .8; }
.lp-aurora::before { width: 52%; height: 70%; left: 2%; top: 4%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 30%, transparent), transparent 72%); }
.lp-aurora::after { width: 50%; height: 66%; right: 0; top: -6%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent-hover) 26%, transparent), transparent 70%); }
@media (prefers-reduced-motion: no-preference) {
  .lp-aurora::before { animation: lp-drift-a 22s ease-in-out infinite alternate; }
  .lp-aurora::after { animation: lp-drift-b 27s ease-in-out infinite alternate; }
}
@keyframes lp-drift-a { from { transform: translate3d(-4%,-2%,0) scale(1); } to { transform: translate3d(5%,4%,0) scale(1.12); } }
@keyframes lp-drift-b { from { transform: translate3d(4%,3%,0) scale(1.06); } to { transform: translate3d(-5%,-4%,0) scale(.92); } }
/* Same dotgrid + drifting aurora glow as the homepage hero, applied to a
   plain .pr-head header (for_accounting_firms.html, for_business_owners.html)
   instead of .lp-hero — a page-scoped modifier rather than touching .pr-head
   itself, so pricing/coverage (which also use .pr-head, and shouldn't gain
   an unrequested background) are untouched. */
.lp-glow-head { position: relative; z-index: 0; }
.lp-glow-head > .lp-kicker, .lp-glow-head > h1, .lp-glow-head > p, .lp-glow-head > .lp-ctas {
  position: relative; z-index: 1; }
.lp-hero-grid { position: relative; z-index: 1; display: grid;
  grid-template-columns: 1fr 1.08fr; gap: clamp(28px, 4vw, 60px); align-items: center; }
@media (max-width: 900px) { .lp-hero-grid { grid-template-columns: 1fr; } }

.lp-eyebrow { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600;
  letter-spacing: .01em; color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent); padding: 6px 13px; border-radius: 999px; }
.lp-eyebrow-dot { position: relative; width: 7px; height: 7px; border-radius: 50%; background: var(--good);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--good) 22%, transparent); }
.lp-eyebrow-dot::after { content: ""; position: absolute; inset: 0; border-radius: 50%;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--good) 60%, transparent); }
@media (prefers-reduced-motion: no-preference) {
  .lp-eyebrow-dot::after { animation: lp-dot-pulse 2s ease-out infinite; }
}
@keyframes lp-dot-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--good) 55%, transparent); opacity: 1; }
  70%  { box-shadow: 0 0 0 9px color-mix(in srgb, var(--good) 0%, transparent); opacity: 0; }
  100% { box-shadow: 0 0 0 9px color-mix(in srgb, var(--good) 0%, transparent); opacity: 0; }
}
.lp-title { font-family: var(--serif); font-weight: 600; letter-spacing: -.022em; line-height: .98;
  font-size: clamp(40px, 6.9vw, 80px); margin: 22px 0 0; color: var(--ink); }
.lp-title em { font-style: italic; color: var(--accent); }
.lp-lede { margin: 20px 0 0; font-size: clamp(16px, 1.5vw, 19px); line-height: 1.6; color: var(--ink-2); max-width: 30em; }
.lp-beta-note { display: flex; align-items: center; gap: 8px; margin: 16px 0 0;
  font-size: 13.5px; font-weight: 600; color: var(--ink-2); }
.lp-beta-note::before { content: ""; width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--accent); }
.lp-ctas { display: flex; align-items: center; gap: 20px; margin-top: 30px; flex-wrap: wrap; }
.lp-ctas-center { justify-content: center; }
.lp-textlink { color: var(--accent); font-weight: 600; font-size: 15px; text-decoration: none; }

.lp-trust { display: flex; align-items: center; gap: 20px; margin-top: 38px; flex-wrap: wrap; }
.lp-trust-item { display: flex; flex-direction: column; gap: 2px; }
.lp-trust-item strong { font-family: var(--serif); font-size: 26px; font-weight: 600; color: var(--ink); line-height: 1; }
.lp-trust-item span { font-size: 12.5px; color: var(--muted); }
.lp-trust-divider { width: 1px; height: 32px; background: var(--line-strong); }

/* --- Hero visual column: the map is now the lead visual (the vignette
   status-card mockup was retired), so it owns the whole column. --- */
.lp-hero-visual { display: flex; flex-direction: column; }
.lp-hero-map { position: relative; max-width: 540px; margin: 0 0 0 auto; width: 100%; }
/* Desktop-only: at the width where the hero grid stacks to a single column,
   the map reads as clutter under the copy — drop it rather than shrink it. */
@media (max-width: 900px) { .lp-hero-map { display: none; } }
/* Mobile: the hero grid already stacks to one column at this width (see
   .lp-hero-grid above) — center the copy column instead of leaving it
   left-aligned under the now-full-width block. text-align handles the
   eyebrow pill/headline/lede/beta-note; the two flex rows (CTAs, trust
   stats) need justify-content too since text-align doesn't center flex
   items, and margin:auto centers the lede's own max-width cap. */
@media (max-width: 900px) {
  .lp-hero-copy { text-align: center; }
  .lp-hero-copy .lp-lede { margin-left: auto; margin-right: auto; }
  .lp-hero-copy .lp-ctas,
  .lp-hero-copy .lp-trust,
  .lp-hero-copy .lp-beta-note { justify-content: center; }
}
.lp-map-frame { position: relative; filter: drop-shadow(0 24px 40px color-mix(in srgb, var(--accent) 16%, transparent)); }
/* --surface-2 (not --surface, which is pure white in light theme) -- a
   stark white card stood out against the rest of the light palette's soft
   blue-gray tones; --surface-2 blends in the same way every other light-
   theme surface does. */
.lp-hero-map .lp-map-frame {
  filter: drop-shadow(0 12px 22px color-mix(in srgb, var(--accent) 14%, transparent));
  padding: 26px; border-radius: 22px; background: var(--surface-2);
}
/* Rotating glow ring: a `@property`-driven angle animates a conic-gradient,
   masked down to just the ring (content-box cut out of the padding-box) so
   only the border itself glows. Originally lived on the hero map card;
   moved to the nav's "Request access" CTA instead (see .lp-glow-btn below)
   -- reuses the same angle property/keyframes, just retargeted. */
@property --lp-glow-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
.lp-glow-btn { position: relative; }
.lp-glow-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: conic-gradient(from var(--lp-glow-angle),
    transparent 0deg, var(--accent) 70deg, var(--accent-hover) 110deg,
    transparent 200deg, transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: lp-glow-spin 7s linear infinite;
  pointer-events: none;
}
@keyframes lp-glow-spin { to { --lp-glow-angle: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  .lp-glow-btn::before { animation: none; }
}
/* Dark theme's accent (a pale, muted blue) reads as washed-out for the one
   button on the page that's supposed to read as "click this" -- it blends
   into the map's own state-fill blue and the badge/link accents instead of
   standing apart from them. Flip to a solid near-white pill with dark ink
   text here specifically, so the primary CTA actually pops against the
   dark hero; the glow ring above still runs in the page's accent blue. */
:root:not([data-theme="light"]) .lp-nav-auth.lp-glow-btn {
  background: var(--ink); color: var(--page); border-color: var(--ink);
}
:root:not([data-theme="light"]) .lp-nav-auth.lp-glow-btn:hover {
  background: var(--ink-2); border-color: var(--ink-2);
}
/* Sweep: a continuous, per-state glow driven by a requestAnimationFrame loop
   in landing.js/coverage.js, animating `filter: brightness()` directly on
   each real .state path (not a decorative overlay). Two earlier designs
   both broke on real devices/browsers, and both failures traced back to the
   same root cause — animating a property on a <use> clone (an invisible
   accent-filled copy stacked on top of each state) rather than on the real
   element:
     1. CSS @keyframes driving the clone's opacity animated fine in every
        desktop/Chromium test but never repainted at all on an actual
        iPhone (a longstanding Safari bug with keyframe animations on <use>
        content) — fixed by moving timing into the rAF loop.
     2. `filter: brightness()` on the clone tested correctly in headless
        Chromium (confirmed by forcing opacity:1 and sampling the rendered
        pixel) but rendered solid BLACK — not brightened, not unchanged,
        black — in whatever real browser recorded a user's screen capture
        of it. <use> shadow content is a browser-reconstructed proxy for
        the referenced element, and evidently isn't a reliable target for
        filter effects either, on top of the animation bug above.
   Both are symptoms of the same lesson: don't animate effects on a <use>
   clone of an element, animate the element itself. This version has no
   clone at all — the rAF loop selects the real .state paths and toggles
   their own inline `filter` between empty (normal) and `brightness()
   saturate()` at peak, so there's no shadow-content indirection left to
   break. Skipped entirely under reduced-motion: the rAF loop is never
   started, so filter just stays unset. */
.lp-hero-map-cap { display: flex; align-items: center; gap: 7px; margin: 10px 0 0;
  font-size: 12px; font-weight: 600; color: var(--muted); }
.lp-hero-map-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }
.us-map { width: 100%; height: auto; display: block; overflow: visible; }
.us-map .state { fill: var(--lp-state); stroke: var(--lp-state-line); stroke-width: 1;
  transform-box: fill-box; transform-origin: center;
  /* Only transform + fill are animated (cheap, GPU-friendly). The drop-shadow
     is NOT transitioned — animating an SVG filter is what made the lift lag. */
  transition: fill .14s ease, transform .16s ease-out;
  cursor: pointer; }
.us-map .state:hover {
  fill: var(--accent);
  /* Scale from the centre only — no translate, so the shape never moves out
     from under the cursor (that caused the hover flicker/jitter). */
  transform: scale(1.07);
  filter: drop-shadow(0 5px 7px color-mix(in srgb, var(--accent) 42%, transparent));
}
.lp-map-tip { position: absolute; z-index: 5; transform: translate(-50%, calc(-100% - 12px));
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow-md); padding: 8px 13px; pointer-events: none; white-space: nowrap;
  display: flex; flex-direction: column; gap: 1px; }
.lp-map-tip[hidden] { display: none; }
.lp-map-tip::after { content: ""; position: absolute; left: 50%; bottom: -6px; width: 11px; height: 11px;
  background: var(--surface); border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
  transform: translateX(-50%) rotate(45deg); }
.lp-tip-name { font-weight: 650; font-size: 14px; color: var(--ink); }
.lp-tip-sub { font-size: 11.5px; color: var(--accent); font-weight: 550; }

/* --- Shared section chrome --- */
.lp-section-head { text-align: center; max-width: 640px; margin: 0 auto clamp(28px, 4vw, 46px); }
.lp-kicker { display: inline-block; font-size: 12.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 12px; }
.lp-section-head h2 { font-family: var(--serif); font-weight: 600; letter-spacing: -.02em;
  font-size: clamp(26px, 3.4vw, 40px); line-height: 1.1; color: var(--ink); margin: 0; }
.lp-features, .lp-steps, .lp-personas { padding: clamp(48px, 7vw, 96px) 0; }
.lp-steps { background: var(--surface-2); }

/* --- Fail-closed trust band: the core differentiator gets its own section,
   not buried as a third hero stat. Calm, not alarmist — a confident
   statement of design, framed the same way the hero's trust row is. --- */
.lp-failclosed { padding: clamp(28px, 4vw, 44px) 0; }
.lp-fc-inner { display: flex; align-items: center; gap: 22px;
  background: var(--accent-wash); border: 1px solid color-mix(in srgb, var(--accent) 20%, var(--line));
  border-radius: 20px; padding: clamp(22px, 3vw, 34px) clamp(24px, 4vw, 40px); }
.lp-fc-icon { display: inline-flex; width: 52px; height: 52px; border-radius: 14px; flex: none;
  align-items: center; justify-content: center; background: var(--accent); color: var(--accent-contrast); }
.lp-fc-icon svg { width: 26px; height: 26px; }
.lp-fc-inner h2 { font-family: var(--serif); font-weight: 600; letter-spacing: -.015em;
  font-size: clamp(21px, 2.4vw, 27px); color: var(--ink); margin: 4px 0 8px; }
.lp-fc-inner .lp-kicker { margin-bottom: 0; }
.lp-fc-inner p { font-size: 15px; line-height: 1.55; color: var(--ink-2); margin: 0; max-width: 54em; }
@media (max-width: 640px) { .lp-fc-inner { flex-direction: column; align-items: flex-start; gap: 14px; } }

.lp-feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.lp-persona-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px; max-width: 900px; margin: 0 auto; }
.lp-step-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; list-style: none; margin: 0; padding: 0; counter-reset: step; }
@media (max-width: 1000px) { .lp-step-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 820px) { .lp-feature-grid, .lp-step-grid { grid-template-columns: 1fr; } .lp-persona-grid { grid-template-columns: 1fr; } }

.lp-card, .lp-persona, .lp-step { background: var(--surface); border: 1px solid var(--line);
  border-radius: 18px; padding: 26px 24px; box-shadow: var(--shadow-sm);
  transition: transform .25s cubic-bezier(.2,.7,.2,1), box-shadow .25s, border-color .25s; }
.lp-card:hover, .lp-persona:hover, .lp-step:hover { transform: translateY(-4px);
  box-shadow: var(--shadow-md); border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); }
.lp-ico { display: inline-flex; width: 42px; height: 42px; border-radius: 12px; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent); margin-bottom: 16px; }
.lp-ico svg { width: 21px; height: 21px; }
.lp-card h3, .lp-persona h3, .lp-step h3 { font-size: 18px; font-weight: 650; color: var(--ink); margin: 0 0 8px; }
.lp-card p, .lp-persona p, .lp-step p { font-size: 14.5px; line-height: 1.55; color: var(--ink-2); margin: 0; }
.lp-persona .lp-textlink { display: inline-block; margin-top: 14px; }
.lp-step { position: relative; }

/* --- FAQ accordion: plain <details>/<summary> for real semantics and
   free keyboard/screen-reader behavior, styled onto the existing .lp-card
   shell so it matches the rest of the marketing site. --- */
.lp-faq { display: flex; flex-direction: column; gap: 14px; max-width: 760px; margin: 0 auto; }
.lp-faq-item { padding: 0; overflow: hidden; }
.lp-faq-item summary {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  cursor: pointer; list-style: none; padding: 20px 24px;
  font-size: 16px; font-weight: 650; color: var(--ink);
}
.lp-faq-item summary::-webkit-details-marker { display: none; }
.lp-faq-item summary::after {
  content: "+"; flex: none; width: 28px; height: 28px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; font-weight: 600; line-height: 1;
}
.lp-faq-item[open] summary::after { content: "−"; }
.lp-faq-item p { padding: 0 24px 22px; }
.lp-faq-item:hover { transform: none; }
.lp-step-num { display: inline-grid; place-items: center; width: 34px; height: 34px; border-radius: 50%;
  font-family: var(--serif); font-weight: 600; font-size: 16px; color: var(--accent-contrast);
  background: var(--accent); margin-bottom: 16px; }

/* --- "Coming soon" step: visually distinct, muted + dashed --- */
.lp-step--soon { border-style: dashed; border-color: var(--line-strong);
  background: color-mix(in srgb, var(--surface-2) 60%, var(--surface)); }
.lp-step--soon .lp-step-num { background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  color: var(--muted); box-shadow: inset 0 0 0 1px var(--line-strong); }
.lp-step--soon h3, .lp-step--soon p { color: var(--ink-2); }
.lp-step--soon:hover { border-color: color-mix(in srgb, var(--accent) 30%, var(--line-strong)); }
.lp-step-badge { position: absolute; top: 16px; right: 16px; display: inline-block;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 4px 9px; border-radius: 999px; color: var(--accent);
  background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent); }

/* --- CTA band --- */
.lp-cta { padding: clamp(20px, 4vw, 40px) 0 clamp(48px, 7vw, 90px); }
.lp-cta-inner { position: relative; overflow: hidden; text-align: center; border-radius: 26px;
  padding: clamp(40px, 6vw, 72px) 28px; color: #fff;
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 60%, #0f2f78 100%);
  box-shadow: var(--shadow-lg); }
.lp-cta-inner::before { content: ""; position: absolute; inset: -40% -10% auto auto; width: 60%; height: 140%;
  background: radial-gradient(closest-side, rgba(255,255,255,.18), transparent 70%); pointer-events: none; }
.lp-cta-inner h2 { font-family: var(--serif); font-weight: 600; letter-spacing: -.02em;
  font-size: clamp(26px, 3.6vw, 42px); margin: 0; position: relative; }
.lp-cta-inner p { margin: 14px auto 0; font-size: 17px; opacity: .92; max-width: 32em; position: relative; }
.lp-btn-invert { background: #fff; color: var(--accent); border-color: #fff; }
.lp-btn-invert:hover { background: #f0f4fc; }
.lp-textlink-invert { color: #fff; }

/* --- Footer --- */
.lp-foot { border-top: 1px solid var(--line); padding: 26px 0; }
.lp-foot .wrap { display: flex; align-items: center; gap: 14px; }
.lp-foot .spacer { flex: 1; }
.lp-foot-note { font-size: 13px; color: var(--muted); }
.lp-foot-links { display: flex; gap: 14px; font-size: 13px; }
.lp-foot-links a { color: var(--muted); text-decoration: none; }
.lp-foot-links a:hover { color: var(--ink-2); }

@media (prefers-reduced-motion: reduce) {
  .lp .reveal { opacity: 1 !important; transform: none !important; transition: none; }
  .us-map .state { transition: fill .15s ease; }
  .us-map .state:hover { transform: none; }
}

/* ============================================================================
   PRICING & BILLING
   ========================================================================== */
.pr-head { text-align: center; max-width: 640px; margin: clamp(24px,5vw,56px) auto clamp(20px,3vw,36px); padding: 0 20px; }
.pr-head h1 { font-family: var(--serif); font-weight: 600; letter-spacing: -.02em;
  font-size: clamp(30px, 4.5vw, 46px); line-height: 1.08; color: var(--ink); margin: 12px 0 0; }
.pr-head p { color: var(--ink-2); font-size: 16px; margin: 12px 0 0; }
.pr-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; align-items: stretch;
  padding-bottom: clamp(40px,6vw,80px); }
.pr-grid .pr-card { flex: 1 1 300px; max-width: 360px; }
.pr-card { position: relative; background: var(--surface); border: 1px solid var(--line);
  border-radius: 18px; padding: 28px 26px; box-shadow: var(--shadow-sm); display: flex; flex-direction: column;
  transition: box-shadow .15s, transform .15s; }
.pr-card:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
.pr-card--feature { border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  box-shadow: var(--shadow-md); }
.pr-card--feature:hover { box-shadow: var(--shadow-lg); }
.pr-badge { position: absolute; top: -11px; left: 26px; background: var(--accent); color: var(--accent-contrast);
  font-size: 11.5px; font-weight: 650; letter-spacing: .03em; padding: 4px 11px; border-radius: 999px; }
.pr-name { font-size: 15px; font-weight: 650; color: var(--ink-2); margin: 0; text-transform: uppercase; letter-spacing: .05em; }
/* z-index: 0 (not just position: relative) is load-bearing: it's what makes
   this element its own stacking context, so the glow's z-index: -1 only has
   to duck below the price text within this small box — not below every
   ancestor up to .pr-card's own background, which is where an unscoped
   negative z-index ends up and renders invisibly behind the card. */
.pr-price { position: relative; z-index: 0; font-family: var(--serif); font-weight: 600; font-size: 40px; color: var(--ink); margin: 10px 0 0; line-height: 1; }
/* Recommended plan only: a quiet glow behind the number, not the whole card —
   reinforces "this is the one to pick" without the card itself changing. */
.pr-card--feature .pr-price::before { content: "";
  position: absolute; inset: -8px -12px -18px; z-index: -1;
  background: radial-gradient(65% 75% at 32% 58%, color-mix(in srgb, var(--accent) 20%, transparent), transparent 72%);
  filter: blur(9px); pointer-events: none; }
.pr-price span { font-family: var(--sans); font-size: 15px; font-weight: 550; color: var(--muted); }
.pr-price .pr-was {
  font-family: var(--sans); font-size: 20px; font-weight: 500; color: var(--muted);
  text-decoration: line-through; text-decoration-thickness: 2px; margin-right: 9px;
}
.pr-blurb { color: var(--ink-2); font-size: 14px; margin: 10px 0 0; }
.pr-features { list-style: none; margin: 18px 0 22px; padding: 0; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.pr-features li { position: relative; padding-left: 27px; font-size: 14px; color: var(--ink-2); line-height: 1.4; }
/* Badge + glyph as two layers rather than one flat icon — echoes the
   ring-good treatment used for the hero's status checks, so the pricing
   page and the product mockup read as the same visual language. The glyph
   is a CSS mask (not a background-image) specifically so its color comes
   from var(--good-text): a data-URI's own stroke color is a literal hex
   baked in, and can't repaint for dark mode the way a real token can. */
.pr-features li::before { content: ""; position: absolute; left: 0; top: 2px; width: 17px; height: 17px;
  border-radius: 50%; background: var(--good-tint);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--good) 45%, transparent); }
.pr-features li::after { content: ""; position: absolute; left: 3.5px; top: 5.5px; width: 10px; height: 10px;
  background: var(--good-text);
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5' stroke='%23000' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask-size: 11px; mask-repeat: no-repeat; mask-position: center;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5' stroke='%23000' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  -webkit-mask-size: 11px; -webkit-mask-repeat: no-repeat; -webkit-mask-position: center; }
.pr-cta { width: 100%; }
.pr-current { display: inline-flex; align-items: center; justify-content: center; width: 100%;
  padding: 9px 18px; border-radius: 9px; font-weight: 600; font-size: 14px;
  background: var(--accent-soft); color: var(--accent); }

/* Billing page */
.bill-current { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: 20px 22px;
  box-shadow: var(--shadow-sm); margin: 0 auto 24px; max-width: 720px; }
.bill-plan-name { font-family: var(--serif); font-size: 24px; font-weight: 600; color: var(--ink); margin-top: 3px; }
.bill-usage { font-size: 13.5px; color: var(--ink-2); margin-top: 3px; }
.bill-usage-bar {
  width: 100%; max-width: 260px; height: 6px; border-radius: 999px;
  background: var(--surface-2); overflow: hidden; margin-top: 8px;
}
.bill-usage-bar-fill { display: block; height: 100%; border-radius: 999px; transition: width .25s ease; }
.bill-usage-bar-fill--ok { background: var(--accent); }
.bill-usage-bar-fill--warn { background: var(--warn); }
.bill-usage-bar-fill--crit { background: var(--crit); }
.bill-usage-note { font-size: 12.5px; color: var(--warn-text); margin: 6px 0 0; }
.bill-usage-note--crit { color: var(--crit-text); }
.bill-grid { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; }
.bill-grid .bill-card { flex: 1 1 260px; max-width: 340px; }
.bill-card { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: 22px 20px;
  box-shadow: var(--shadow-sm); display: flex; flex-direction: column; }
.bill-card--current { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.bill-card .pr-price { font-size: 30px; }
.bill-card form { margin: 0; }
.bill-card .btn { width: 100%; }

/* Beta agreement */
.agree-box {
  max-height: 200px; overflow-y: auto; margin: 4px 0 4px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px;
  padding: 14px 16px; font-size: 12.5px; line-height: 1.5; color: var(--ink-2);
  transition: border-color .18s ease, box-shadow .18s ease;
}
/* Brief flash when someone tries to agree before scrolling to the end. */
.agree-box--nudge {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.agree-box h3 { font-size: 14px; margin: 0 0 4px; color: var(--ink); }
.agree-box h4 { font-size: 12.5px; margin: 14px 0 4px; color: var(--ink); }
.agree-box p, .agree-box ul { margin: 0 0 8px; }
.agree-box ul { padding-left: 18px; }
.legal-eyebrow { font-size: 10.5px; letter-spacing: .12em; font-weight: 700; color: var(--accent); margin: 0 0 2px; }
.agree-check { display: flex; align-items: flex-start; gap: 9px; font-size: 13px; color: var(--ink-2);
  cursor: pointer; margin: 8px 0 4px; }
.agree-check input { margin-top: 2px; flex: none; }
.agree-check a { color: var(--accent); }
/* .form-card label {display:grid} (see above) outranks .agree-check on
   specificity when a checkbox row like this sits inside a .form-card
   (the invite-permissions checklist does) — without this, the checkbox,
   label text, and "?" tooltip each land in their own grid row instead of
   sitting inline. */
.form-card .agree-check { display: flex; align-items: flex-start; }

/* --- Tooltips -----------------------------------------------------------
   Two shapes sharing one bubble: a standalone "?" icon (.info-tip) for a
   label that needs extra explanation with no visible text of its own, and
   a bare data-tip attribute on an existing element (e.g. a standing pill)
   whose own text is already the label. Deliberately not the native `title`
   attribute — that's slow to appear, unstyleable, and invisible to anyone
   navigating by keyboard until a long delay, if at all.

   Bubble colors are the ink/page pair specifically, not surface/line: those
   two tokens are opposite-contrast by definition in both themes, so the
   bubble reads as high-contrast "inverted" text in light AND dark mode
   without a separate dark-mode override to maintain. */
[data-tip] { position: relative; }
[data-tip]::before {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 8px); left: 50%;
  transform: translateX(-50%) translateY(3px);
  background: var(--ink); color: var(--page);
  font-size: 12px; font-weight: 500; line-height: 1.4; font-family: var(--sans);
  text-transform: none; letter-spacing: normal; white-space: normal;
  width: max-content; max-width: 230px; padding: 7px 10px; border-radius: 8px;
  box-shadow: var(--shadow-md);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .12s ease, transform .12s ease;
  z-index: 40;
}
[data-tip]::after {
  content: ""; position: absolute; bottom: calc(100% + 3px); left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--ink);
  opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .12s ease;
}
[data-tip]:hover::before, [data-tip]:hover::after,
[data-tip]:focus-visible::before, [data-tip]:focus-visible::after {
  opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  [data-tip]::before, [data-tip]::after { transition: none; }
}
.info-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%; flex: none;
  background: var(--surface-2, var(--line)); color: var(--muted);
  font-size: 10px; font-weight: 700; line-height: 1; font-style: normal;
  cursor: help; vertical-align: -2px;
}
/* Wraps a label's text + its .info-tip together as one grid item — a form
   label is `display: grid`, which otherwise splits the trailing icon onto
   its own row instead of sitting right after the text. */
.lbl-row { display: inline-flex; align-items: center; gap: 5px; }

/* Branding form's live preview -- a small mock of what the owner-portal
   topbar looks like with the in-progress (unsaved) logo/color/email, so a
   firm doesn't have to save-and-check-as-a-client to see the effect. */
.branding-preview {
  max-width: 560px; border: 1px solid var(--line-strong); border-radius: 12px;
  overflow: hidden; margin-bottom: 24px; background: var(--page);
}
.branding-preview-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; border-bottom: 1px solid var(--line-strong);
}
.branding-preview-logo { width: 22px; height: 22px; color: var(--accent); flex: none; display: flex; }
.branding-preview-logo svg { width: 100%; height: 100%; }
.branding-preview-logo img { width: 100%; height: 100%; object-fit: contain; }
.branding-preview-name { font-weight: 650; font-size: 14px; }
.branding-preview-btn {
  font-size: 12px; font-weight: 600; padding: 6px 11px; border-radius: 7px;
  background: var(--accent); color: #fff;
}
.branding-preview-note { padding: 10px 16px; font-size: 12.5px; color: var(--ink-2); }

/* Multi-select entity picker on owner create/edit forms */
.form-card select[multiple] { padding: 4px; }
.form-card select[multiple] option { padding: 6px 8px; border-radius: 6px; }

/* Checkbox-based entity picker (owner create/edit forms) -- a scrollable
   list instead of ctrl/cmd-click on a <select multiple>, which wasn't
   discoverable enough for picking more than one entity. */
.entity-picker {
  max-height: 260px; overflow-y: auto;
  border: 1px solid var(--line-strong); border-radius: 9px;
  padding: 4px; display: flex; flex-direction: column; gap: 2px;
}
.entity-picker .agree-check { margin: 0; padding: 7px 8px; border-radius: 7px; }
.entity-picker .agree-check:hover { background: var(--surface-2, var(--line)); }

/* Standalone legal page */
.legal-page { max-width: 760px; padding: clamp(24px,4vw,48px) 28px; }
.legal h3 { font-family: var(--serif); font-size: 26px; font-weight: 600; color: var(--ink); margin: 0 0 6px; }
.legal h4 { font-size: 16px; margin: 24px 0 6px; color: var(--ink); }
.legal p, .legal li { color: var(--ink-2); line-height: 1.6; font-size: 14.5px; }
.legal ul { padding-left: 20px; }
.legal-page .legal-eyebrow { font-size: 12px; }
.legal-updated { color: var(--muted); font-size: 13px; margin: 0 0 18px; }

/* State coverage page */
.cov-stats { display: flex; justify-content: center; gap: 26px; margin-top: 22px; flex-wrap: wrap; }
.cov-stat { display: flex; flex-direction: column; gap: 2px; }
.cov-stat strong { font-family: var(--serif); font-size: 26px; font-weight: 600; color: var(--ink); line-height: 1; }
.cov-stat span { font-size: 12.5px; color: var(--muted); }
.cov-wrap { padding-bottom: clamp(40px,6vw,80px); max-width: 900px; }

.cov-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.cov-dot--auto { background: var(--accent); }
.cov-dot--manual { background: var(--line-strong); }

/* --- Map centrepiece --- */
.cov-map-panel { display: flex; flex-direction: column; align-items: center; }
.cov-map { position: relative; width: 100%; max-width: 720px; margin: 0 auto;
  filter: drop-shadow(0 20px 36px color-mix(in srgb, var(--accent) 12%, transparent)); }
/* Colour each state by its coverage status. Scoped to .cov-map so it overrides
   the landing page's global .us-map .state fill without touching it. */
.cov-map .us-map .state { fill: var(--line-strong); stroke: var(--surface); stroke-width: 1;
  transform-box: fill-box; transform-origin: center;
  transition: fill .14s ease, transform .16s ease-out; cursor: pointer; }
/* Since every state is "automated" in production now, using the full
   .lp-state (== --accent) fill here would wash the whole map into one
   uniformly bright mass with no hierarchy left to read -- toned down a step
   so "automated" still clearly outranks "manual" without glaring. */
.cov-map .us-map .state[data-cov="automated"] { fill: color-mix(in srgb, var(--accent) 55%, var(--surface)); }
.cov-map .us-map .state[data-cov="manual"]    { fill: var(--line-strong); }
/* Hover: brighten fill + a small scale from the centre. No translate — that
   moves the shape out from under the cursor and causes hover flicker. */
.cov-map .us-map .state:hover { transform: scale(1.06);
  filter: brightness(1.12) saturate(1.05); }
.cov-tip { z-index: 6; }
.cov-tip-cadence { font-size: 11.5px; color: var(--muted); font-weight: 500; }
.cov-tip-cadence[hidden] { display: none; }

.cov-legend { display: flex; justify-content: center; gap: 20px; flex-wrap: wrap;
  margin: 18px auto 0; font-size: 12.5px; color: var(--ink-2); }
.cov-legend span { display: inline-flex; align-items: center; gap: 7px; }

/* --- Search + chip grid --- */
.cov-browse { margin-top: 30px; }
.cov-search { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.cov-search-input { flex: 1 1 240px; max-width: 340px; padding: 10px 14px; font-size: 14.5px;
  border: 1px solid var(--line-strong); border-radius: 10px; background: var(--surface); color: var(--ink); }
.cov-search-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.cov-search-count { font-size: 12.5px; color: var(--muted); }
.cov-grid { display: flex; flex-wrap: wrap; gap: 10px; }
.cov-chip { display: inline-flex; align-items: center; gap: 8px; padding: 9px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow-sm); }
.cov-chip[hidden] { display: none; }
.cov-chip-dot { width: 9px; height: 9px; }
.cov-chip-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.cov-chip-code { font-size: 12px; color: var(--muted); }
.cov-chip-cadence { font-size: 12px; color: var(--ink-2);
  padding-left: 8px; border-left: 1px solid var(--line); }
.cov-chip-link { font-size: 12px; font-weight: 550; color: var(--accent); text-decoration: none;
  padding-left: 8px; border-left: 1px solid var(--line); }

.cov-chip-link--muted { color: var(--muted); font-weight: 500; }
.cov-noresult { margin-top: 16px; color: var(--muted); font-size: 14px; }

/* --- Admin collapsible (platform admins only) --- */
.cov-admin { margin-top: 34px; }
.cov-admin-body { margin-top: 14px; padding: 18px; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 14px; }
.cov-admin-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.cov-edit { display: flex; align-items: center; gap: 10px; margin: 0; flex-wrap: wrap;
  padding: 8px 12px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; }
.cov-edit-name { flex: 1 1 180px; min-width: 140px; }
.cov-mini { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--ink-2); white-space: nowrap; }
.cov-num { width: 44px; padding: 5px 6px; border: 1px solid var(--line-strong); border-radius: 7px;
  background: var(--surface); color: var(--ink); font-size: 13px; }
.cov-foot-note { margin-top: 24px; }

@media (max-width: 560px) {
  .cov-legend { gap: 12px; }
  .cov-edit { gap: 8px; }
}

/* --- Recent activity ---------------------------------------------------
   A quiet ledger under the table: what changed, not what was checked. Sits
   below the fold on purpose — the table is the work, this is the context. */
/* Floating onboarding checklist (dashboard only) — sits over whatever
   content is beneath its bottom-right corner rather than pushing layout
   around, so it can't shove the real table content off-balance. Minimize
   collapses it to just the header bar; both that and dismiss persist
   per-browser via localStorage (same lightweight pattern as the theme
   toggle in theme.js) since there's no per-user server-side state for it. */
.setup-guide {
  position: fixed; right: 24px; bottom: 24px; z-index: 30;
  width: 320px; max-width: calc(100vw - 32px);
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow-md); overflow: hidden;
}
.setup-guide.minimized { width: 196px; }
.setup-head {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  padding: 12px 8px 12px 16px; border-bottom: 1px solid var(--line);
}
.setup-guide.minimized .setup-head { border-bottom: none; }
.setup-head h3 { margin: 0; font-size: 14px; font-weight: 650; color: var(--ink); }
.setup-head-actions { display: flex; align-items: center; gap: 2px; flex: none; }
.setup-head .icon-btn { width: 26px; height: 26px; border: none; background: transparent; color: var(--muted); }
.setup-head .icon-btn:hover { color: var(--ink); background: var(--surface-2); border-color: transparent; }
.setup-head .icon-btn svg { width: 14px; height: 14px; }
.setup-guide:not(.minimized) .expand,
.setup-guide.minimized .collapse,
.setup-guide.minimized .setup-body { display: none; }
.setup-body { padding: 14px 16px 16px; }
.setup-progress { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.setup-ring {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--line) 0);
}
.setup-progress-text { font-size: 12.5px; color: var(--ink-2); }
.setup-progress-text strong { color: var(--ink); }
.setup-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.setup-item a {
  display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--ink);
  font-size: 13px; font-weight: 550; padding: 7px 6px; border-radius: 8px;
}
.setup-item a:hover { background: var(--surface-2); }
.setup-item.done a { color: var(--muted); text-decoration: line-through; }
.setup-check {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 20px; height: 20px; border-radius: 50%; font-size: 11px; font-weight: 700;
  border: 1.5px solid var(--line-strong); color: var(--muted);
}
.setup-item.done .setup-check { background: var(--good); border-color: var(--good); color: #fff; }
@media (max-width: 640px) {
  .setup-guide { right: 12px; bottom: 12px; left: 12px; width: auto; }
  .setup-guide.minimized { left: auto; width: 196px; }
}

.activity { margin-top: 26px; }
.activity-head {
  font-size: 11px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 10px;
}
/* Dashboard's "Recent entities" preview -- reuses .activity-head's own
   uppercase-label typography for the title (h2 override below), with a
   "View all" link on the same row instead of its own section. */
.recent-head { display: flex; align-items: center; justify-content: space-between; margin: 0 0 10px; }
.recent-head .activity-head { margin: 0; }
.recent-head .link-btn { font-size: 12.5px; }
.activity-list { list-style: none; margin: 0; padding: 0; }
.activity-item {
  display: flex; align-items: baseline; gap: 10px;
  padding: 9px 2px; border-bottom: 1px solid var(--line);
}
.activity-item:last-child { border-bottom: none; }
/* A quick stagger on load — honest about what it is: this isn't simulating a
   live push (nothing here is pushed; it's a normal page render), just a
   smoother arrival for a list that's otherwise a flat dump of rows. Fast and
   small on purpose, since the dashboard is opened many times a day. */
@media (prefers-reduced-motion: no-preference) {
  .activity-item { animation: activity-in .22s ease-out backwards; }
  .activity-item:nth-child(1) { animation-delay: 0ms; }
  .activity-item:nth-child(2) { animation-delay: 30ms; }
  .activity-item:nth-child(3) { animation-delay: 60ms; }
  .activity-item:nth-child(4) { animation-delay: 90ms; }
  .activity-item:nth-child(5) { animation-delay: 120ms; }
  .activity-item:nth-child(6) { animation-delay: 150ms; }
  .activity-item:nth-child(7) { animation-delay: 180ms; }
  .activity-item:nth-child(8) { animation-delay: 210ms; }
}
@keyframes activity-in {
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: translateY(0); }
}
.activity-dot {
  flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: var(--neutral-dot); transform: translateY(-1px);
}
.tone-crit { background: var(--crit); }
.tone-serious { background: var(--serious); }
.tone-warn { background: var(--warn); }
.tone-ok { background: var(--good); }
.tone-muted { background: var(--muted); opacity: .5; }
.activity-text {
  flex: 1; min-width: 0; color: var(--ink); text-decoration: none;
  font-size: 13.5px; line-height: 1.45;
}

.activity-name { font-weight: 620; }
.activity-state {
  font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 0 5px 0 6px;
}
.activity-what { color: var(--ink-2); }
.activity-when {
  flex: none; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums;
}
.activity-none { font-size: 13.5px; color: var(--muted); margin: 0; }
@media (max-width: 720px) {
  /* The timestamp drops to its own line rather than squeezing the sentence. */
  .activity-item { flex-wrap: wrap; }
  .activity-when { width: 100%; padding-left: 17px; }
}

/* --- Printable compliance snapshot -------------------------------------
   A document, not an app page. Sized and coloured for paper first; the
   on-screen view is the same document with a toolbar above it. */
.snapshot-page { max-width: 760px; margin: 0 auto; padding: 24px 20px 60px; }
.snapshot-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 18px;
}
.snapshot {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 36px 40px 30px; box-shadow: var(--shadow-sm);
}
.snap-head {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 24px;
  padding-bottom: 18px; border-bottom: 2px solid var(--ink); margin-bottom: 22px;
}
.snap-kicker {
  margin: 0 0 4px; font-size: 10.5px; font-weight: 650; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
}
.snap-head h1 { margin: 0; font-size: 25px; letter-spacing: -.02em; }
.snap-sub { margin: 5px 0 0; font-size: 13px; color: var(--ink-2); }
.snap-brand { text-align: right; }
.snap-firm { margin: 0; font-weight: 650; font-size: 13.5px; }
.snap-gen { margin: 3px 0 0; font-size: 11.5px; color: var(--muted); }

.snap-verdict {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px;
  padding: 14px 16px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--neutral-tint); margin-bottom: 14px;
}
.snap-verdict-label {
  font-size: 10.5px; font-weight: 650; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.snap-verdict-text { font-size: 19px; letter-spacing: -.01em; }
.snap-verdict-when { font-size: 12.5px; color: var(--ink-2); }
.snap-verdict--current { background: var(--good-tint); border-color: var(--good); }
.snap-verdict--current .snap-verdict-text { color: var(--good-text); }
.snap-verdict--due_soon { background: var(--warn-tint); border-color: var(--warn); }
.snap-verdict--due_soon .snap-verdict-text { color: var(--warn-text); }
.snap-verdict--delinquent, .snap-verdict--dissolved {
  background: var(--crit-tint); border-color: var(--crit);
}
.snap-verdict--delinquent .snap-verdict-text,
.snap-verdict--dissolved .snap-verdict-text { color: var(--crit-text); }
.snap-verdict--error { background: var(--serious-tint); border-color: var(--serious); }
.snap-verdict--error .snap-verdict-text { color: var(--serious-text); }

/* Caveats carry the fail-closed promise onto the printed page, where nobody
   can see the app telling them the check didn't complete. */
.snap-caveat {
  margin: 0 0 20px; padding: 10px 13px; font-size: 12.5px; line-height: 1.5;
  color: var(--ink-2); border-left: 3px solid var(--serious);
  background: var(--serious-tint); border-radius: 0 6px 6px 0;
}

.snap-block { margin-bottom: 22px; }
.snap-block h2 {
  margin: 0 0 8px; font-size: 11px; font-weight: 650; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.snap-table { width: 100%; border-collapse: collapse; }
.snap-table th, .snap-table td {
  text-align: left; padding: 7px 0; border-bottom: 1px solid var(--line);
  font-size: 13px; vertical-align: top;
}
.snap-table th {
  width: 190px; font-weight: 550; color: var(--muted); text-transform: none;
  letter-spacing: 0; white-space: normal;
}
.snap-table tr:last-child th, .snap-table tr:last-child td { border-bottom: none; }

.snap-foot {
  margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: 11.5px; line-height: 1.55; color: var(--muted);
}
.snap-foot p { margin: 0 0 7px; }
.snap-src { font-family: var(--mono); font-size: 10.5px; word-break: break-all; }

@media print {
  /* Print on white regardless of the viewer's theme, and drop everything
     that would print as a dead control. */
  :root, :root[data-theme="dark"] {
    --surface: #fff; --bg: #fff; --ink: #111; --ink-2: #333; --muted: #666;
    --line: #ccc;
  }
  .no-print, .page-icons, .lp-nav, .job-banner, .check-toast { display: none !important; }
  body { background: #fff; }
  .snapshot-page { max-width: none; padding: 0; }
  .snapshot { border: none; border-radius: 0; box-shadow: none; padding: 0; }
  .snap-block, .snap-verdict, .snap-caveat { break-inside: avoid; }
  .snap-foot { break-inside: avoid; }
  a { color: inherit; text-decoration: none; }
  @page { margin: 16mm; }
}

/* Honour the OS "reduce motion" setting everywhere, not just on the two
   components that opted in by hand. Transitions are cosmetic here — nothing
   in the UI depends on an animation completing — so they can all be dropped
   without changing what anything does. Kept last so it wins. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
