/* ===== prisma-tokens.css ===== */
/* prisma-tokens.css — canonical design tokens for the prisma product surface.
   Source of truth for typography, colour, spacing, radius and shadow across
   all 17 pages.

   Authority: this file supersedes any per-page :root block. Pages still
   carrying inline tokens are migrating off them — until they do, their
   inline rules override these (later rule wins), so this file remains
   non-breaking when extended.

   Loaded BEFORE prisma-base.css so component primitives can reference these.
   See audits/16-ui-ux-design-audit.md Section 7 for the full rationale.

   2026-05-11: Repainted to the Geist + Instrument Serif visual language
   (see preview/redesign). Token NAMES are unchanged — only their VALUES.
   The legacy aliases (--ink, --paper, --rule, etc.) still resolve. */

:root {
  /* ── 1. Type families ──────────────────────────────────────── */
  /* Brand pairing: Geist (neo-grotesque) for UI + body, Geist Mono for
     tabular/data and code, Instrument Serif (italic) for editorial display
     accents inside hero h1's and card titles. All three load from Google
     Fonts via the @import in prisma-base.css. */
  --font-ui:      'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-display: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-mono:    'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-serif:   'Instrument Serif', Georgia, 'Times New Roman', serif;
  --font-body:    var(--font-ui); /* alias used by some auth pages */

  /* ── 2. Type scale (size + line-height + weight) ───────────── */
  --text-micro-size:    9.5px;  --text-micro-lh:    10px;  --text-micro-weight:    600;
  --text-label-size:    11px;   --text-label-lh:    13px;  --text-label-weight:    600;
  --text-body-size:     13px;   --text-body-lh:     1.5;   --text-body-weight:     400;
  --text-strong-size:   13px;   --text-strong-lh:   1.4;   --text-strong-weight:   600;
  --text-title-size:    15px;   --text-title-lh:    1.3;   --text-title-weight:    600;
  --text-display-size:  22px;   --text-display-lh:  1.1;   --text-display-weight:  500;
  --text-hero-size:     30px;   --text-hero-lh:     1.05;  --text-hero-weight:     500;
  --tracking-tight:     -0.025em;
  --tracking-loose:     0.06em;

  /* ── 3. Spacing scale (use everywhere) ─────────────────────── */
  --pad-3xs: 2px 6px;     /* micro pills (sentiment, tag-ai) */
  --pad-2xs: 4px 8px;     /* badges, meta chips */
  --pad-xs:  6px 10px;    /* filter chips, secondary mini-buttons */
  --pad-sm:  8px 12px;    /* form inputs, card buttons, table cells */
  --pad-md:  10px 16px;   /* primary buttons, mode pills, dropdowns */
  --pad-lg:  14px 20px;   /* modal headers/footers */
  --pad-xl:  20px 24px;   /* card containers */

  --gap-1:  4px;
  --gap-2:  6px;
  --gap-3:  8px;
  --gap-4:  10px;
  --gap-5:  12px;
  --gap-6:  14px;
  --gap-8:  18px;
  --gap-10: 20px;
  --gap-14: 28px;

  /* ── 3.1 Button height scale ───────────────────────────────────
     The 2026-05-19 design audit measured 4 distinct primary-CTA heights
     (32 / 34 / 44 / 45 px) across login/signup/pricing/billing/topbar
     with no shared token. These three buckets are the canonical scale
     future button rules should map into. Existing buttons (.btn-primary,
     .pc-btn, .pp-btn--primary, .pp-cta, .card-btn, .mode-pill, .btn-icon)
     are intentionally NOT retrofitted here - the integrator (or follow-up
     commit) migrates them one cluster at a time. Tokens land first so the
     migration is a class-by-class find-and-replace, not a design debate.

     Mapping guide (read these BEFORE adding a new button class):
       --btn-h-sm  32px - dense data-table chips, filter pills, inline
                          icon buttons sitting next to a larger primary.
                          NEVER use as a stand-alone primary CTA on mobile -
                          fails WCAG 2.5.5 (44x44 minimum touch target).
                          Matches .pc-btn--sm and .btn-ghost (topbar chips).
       --btn-h-md  36px - secondary actions, table-row inline edits,
                          desktop toolbar buttons. Matches .mode-pill
                          and several .pc-btn dropdown triggers.
       --btn-h-lg  44px - primary CTAs (Sign up, Subscribe, Start free),
                          form submit buttons, mobile primary actions.
                          WCAG 2.5.5 (AAA) touch-target floor. Matches
                          base .pc-btn min-height and .pp-btn--primary. */
  --btn-h-sm: 32px;
  --btn-h-md: 36px;
  --btn-h-lg: 44px;

  /* ── 4. Border-radius scale ────────────────────────────────── */
  --radius-xs:   3px;   /* focus-visible outline */
  --radius-sm:   6px;   /* small chips, app-nav items */
  --radius-md:   10px;  /* form inputs, card buttons */
  --radius-lg:   14px;  /* primary buttons, cards, modals */
  --radius-xl:   20px;  /* large hero containers, loading card */
  --radius-pill: 999px; /* badges, true pill chips */
  /* legacy alias — ~30 rule sites still use --radius without suffix */
  --radius:      10px;

  /* ── 5. Surfaces (dark, default) ───────────────────────────── */
  /* Adopted from preview/redesign: deeper near-black bg with two slightly
     lighter elevations. Borders are cool-neutral, not warm. */
  --bg:            #0A0B0D;
  --bg-elev:       #101216;
  --surface:       #141619;
  --surface-2:     #181B20;
  --surface-3:     #1F2329;
  --surface-hover: rgba(255,255,255,.04);
  --border:        #1F2329;
  --border-2:      #2A2F37;
  /* alias from redesign — same value as --border-2 */
  --border-strong: var(--border-2);

  /* ── 6. Text colours (4 levels) ────────────────────────────── */
  --text:    #E8EAED;     /* primary */
  --text-2:  #B5BAC3;     /* body-secondary: card meta, table cells */
  --text-3:  #8A8F99;     /* captions: chip count, plan-name uppercase */
  --text-4:  #8A8F99;     /* placeholder dashes, sparkline scale (≥AA — 4.71:1 vs --bg) */
  /* legacy aliases — keep for migration period, delete after sweep */
  --text-muted: var(--text-2);
  --text-faint: var(--text-4);
  /* aliases from redesign */
  --muted:    var(--text-3);
  --muted-2:  #4A4F58;

  /* ── 7. Brand accent ───────────────────────────────────────── */
  /* Teal — same hue across light & dark; the redesign's "live data" tone. */
  --accent:      #3DDBC2;
  --accent-2:    #2DC4AC;
  --accent-3:    #5EE9D2;             /* hover state, slightly lighter */
  --accent-ink:  #06241F;             /* readable on top of --accent */
  --accent-soft: rgba(61,219,194,.12);
  --accent-glow: rgba(61,219,194,.35);

  /* ── 8. Semantic state ─────────────────────────────────────── */
  /* Aligned to the redesign palette: amber/rose/blue/violet replace the
     yellow/red/blue from the legacy product. */
  --pass: #5ED39A;  --pass-bg: rgba(94,211,154,.10);
  --warn: #E8B45C;  --warn-bg: rgba(232,180,92,.12);
  --fail: #E16A78;  --fail-bg: rgba(225,106,120,.12);
  --info: #6FA8F0;  --info-bg: rgba(111,168,240,.10);
  /* --pin is the user-pinned-domain affordance — distinct from --warn so a
     change to warning hues can't accidentally re-skin pinned cards. Amber-
     leaning (matches what unai shipped) but a touch warmer to read as a
     deliberate UI signal, not a system warning. */
  --pin:      #F0A23C;
  --pin-soft: rgba(240,162,60,.40);
  /* aliases used by some legacy pages */
  --err: var(--fail);
  --ok:  var(--pass);

  /* Extended semantic palette (additive — used by metric cards, dots,
     priority pills, gradient text emphasis). */
  --amber:  #E8B45C;
  --rose:   #E16A78;
  --blue:   #6FA8F0;
  --violet: #B58BE8;

  /* ── 9. LLM brand palette (token, not hex) ─────────────────── */
  --llm-chatgpt:    #10A37F;
  --llm-claude:     #D97757;
  --llm-perplexity: #20B8CD;
  --llm-gemini:     #4285F4;
  --llm-grok:       #1D9BF0;
  --llm-bing:       #008373;
  --llm-google-aio: #EA4335;

  /* ── 10. Elevation ─────────────────────────────────────────── */
  --shadow-sm: 0 1px 3px rgba(0,0,0,.20);
  --shadow-md: 0 8px 24px -8px rgba(0,0,0,.50);
  --shadow-lg: 0 0 0 1px var(--border), 0 24px 48px -24px rgba(0,0,0,.75);

  /* ── 11. App shell ─────────────────────────────────────────── */
  --sidebar-w:   248px;
  --topbar-h:    52px;
  --content-max: 1320px;
  --content-pad: 40px;

  /* ── 12. Z-index scale ─────────────────────────────────────── */
  /* Canonical layering scale. The codebase grew 24 distinct z-index
     literals organically (0,1,2,5,10,30,35,40,50,70,80,90,99,100,140,150,
     200,201,300,500,999,1100,9000,9998,9999,10000,99999) — these tokens
     are the documented scale future code should opt into. EXISTING usages
     are intentionally not migrated; this is purely additive documentation
     so new code has a canonical reference.

     Layer semantics (lowest → highest):
       base       → in-flow content, default stacking context
       sticky     → sticky table headers, in-page sticky bars
       overlay    → page-level overlays and drawer scrims
       dropdown   → menus, autocomplete, select popups
       modal      → modal dialogs (sits above page overlays)
       popover    → tooltips and popovers attached to modal/dropdown
       toast      → transient notifications (always on top of UI)
       impersonation-banner → top-of-app admin-impersonation strip
                              (sits above everything including toasts) */
  --z-base:                 1;
  --z-sticky:               100;
  --z-overlay:              200;
  --z-dropdown:             300;
  --z-modal:                500;
  --z-popover:              1100;
  --z-toast:                9999;
  --z-impersonation-banner: 99999;
}

/* ── 13. Breakpoint scale (documentation only) ───────────────────
   The product currently uses 14+ distinct max-width breakpoints across
   the 17 pages: 360 / 380 / 460 / 480 / 520 / 560 / 580 / 600 / 640 /
   700 / 720 / 760 / 768 / 880 / 900 / 1024 / 1100. That set grew
   per-page rather than from a shared scale, so values cluster but
   don't always align.

   The documented canonical scale below collapses that set to seven
   buckets. Future @media rules should snap to one of these widths
   so cross-page responsive behaviour stays predictable. Existing
   rules are intentionally not migrated — this comment block is the
   reference, not a rewrite.

     --bp-xs:   360px   — phones narrow (iPhone SE-class)
     --bp-sm:   480px   — phones default
     --bp-md:   640px   — phones wide / small tablets portrait
     --bp-lg:   768px   — tablets portrait
     --bp-xl:   900px   — tablets landscape / small laptops
     --bp-2xl:  1024px  — laptops
     --bp-3xl:  1280px  — desktops (matches --content-max - padding)

   Usage convention:
     @media (max-width: 768px) { ... }   — mobile-down
     @media (min-width: 1024px) { ... }  — desktop-up
   CSS custom properties cannot be referenced inside @media queries,
   so this is intentionally a comment-only scale. Pick the literal
   from the list above. */

/* Light theme — used by the admin pages and anywhere a customer flips to
   light mode. Same token names, swapped values. AA-cleared on near-white. */
[data-theme="light"] {
  --bg:            #F7F8FA;
  --bg-elev:       #FFFFFF;
  --surface:       #FFFFFF;
  --surface-2:     #F1F3F6;
  --surface-3:     #E6EAEF;
  --surface-hover: rgba(0,0,0,.03);
  --border:        #E2E5EA;
  --border-2:      #C9CDD4;
  --border-strong: var(--border-2);

  --text:    #15171B;
  --text-2:  #3F4450;     /* ≥4.5:1 on white */
  --text-3:  #6A6F7B;
  --text-4:  #8A8F99;     /* AA-borderline; reserve for non-content */
  --muted:   var(--text-3);
  --muted-2: #B0B4BC;

  --accent:      #0F8A77;
  --accent-2:    #0B6E5F;
  --accent-3:    #16A18C;
  --accent-ink:  #FFFFFF;
  --accent-soft: rgba(15,138,119,.08);
  --accent-glow: rgba(15,138,119,.18);

  --pass: #2E8E5C;  --pass-bg: rgba(46,142,92,.08);
  --warn: #B07A28;  --warn-bg: rgba(176,122,40,.10);
  --fail: #B0455A;  --fail-bg: rgba(176,69,90,.08);
  --info: #3A6CB6;  --info-bg: rgba(58,108,182,.08);
  /* --pin: pinned-domain affordance, dark theme. See light-theme block. */
  --pin:      #C77F1F;
  --pin-soft: rgba(199,127,31,.40);

  --amber:  #B07A28;
  --rose:   #B0455A;
  --blue:   #3A6CB6;
  --violet: #6A4FB6;

  --shadow-sm: 0 1px 2px rgba(0,0,0,.06);
  --shadow-md: 0 6px 16px -4px rgba(0,0,0,.10);
  --shadow-lg: 0 0 0 1px var(--border), 0 24px 48px -24px rgba(0,0,0,.16);
}

/* Light theme — admin "financial terminal" variant.
   Set on <html data-theme="light" data-variant="terminal"> when admin pages
   want the warm-cream Bloomberg aesthetic specifically. */
[data-theme="light"][data-variant="terminal"] {
  --bg:        #faf7f0;
  --bg-elev:   #fff;
  --surface:   #fff;
  --surface-2: #f6f2e7;
  --surface-3: #efeadb;
  --border:    #e6e1d2;
  --border-2:  #cfc8b6;
  --border-strong: var(--border-2);
  --text:      #121212;
  --text-2:    #3d3a35;
  --text-3:    #6e6a60;
  --text-4:    #8a857d;
  --accent:    #0a3a2f;
  --accent-2:  #07251e;
  --accent-3:  #126a55;
  --accent-ink:#faf7f0;
  --accent-soft: rgba(10,58,47,.08);
  --accent-glow:rgba(10,58,47,.18);
  --pass:#1e6b3c; --warn:#8a5a00; --fail:#9a1b1b; --info:#0c4e8a;
  --font-ui:    'IBM Plex Sans', -apple-system, system-ui, sans-serif;
  --font-mono:  'IBM Plex Mono', ui-monospace, monospace;
}

/* ── Legacy admin alias namespace ────────────────────────────────
   admin-dashboard.html historically used --ink / --paper / --rule
   etc. Aliasing them onto the canonical tokens keeps the ~80 rule
   sites working without a rewrite. */
:root {
  --ink:          var(--text);
  --ink-soft:     var(--text-muted);
  --ink-faint:    var(--text-faint);
  --ink-faintest: var(--text-faint);
  --ink-muted:    var(--text-muted);
  --paper:        var(--bg);
  --surface-alt:  var(--surface-2);
  --rule:         var(--border);
  --rule-strong:  var(--border-2);
  --accent-line:  var(--border-2);
  --ok:           var(--pass);
  --err:          var(--fail);
}

/* ── Type-scale utility classes — drop-in replacements for the 19
   distinct font-size literals across the 3 pages. ──────────────── */
.t-micro   { font: var(--text-micro-weight) var(--text-micro-size)/var(--text-micro-lh) var(--font-mono); letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-3); }
.t-label   { font: var(--text-label-weight) var(--text-label-size)/var(--text-label-lh) var(--font-mono); letter-spacing: 0.6px; text-transform: uppercase; color: var(--text-3); }
.t-body    { font: var(--text-body-weight) var(--text-body-size)/var(--text-body-lh) var(--font-ui); color: var(--text); }
.t-body-2  { font: var(--text-body-weight) var(--text-body-size)/var(--text-body-lh) var(--font-ui); color: var(--text-2); }
.t-strong  { font: var(--text-strong-weight) var(--text-strong-size)/var(--text-strong-lh) var(--font-ui); color: var(--text); }
.t-title   { font: var(--text-title-weight) var(--text-title-size)/var(--text-title-lh) var(--font-display); color: var(--text); letter-spacing: var(--tracking-tight); }
.t-display { font: var(--text-display-weight) var(--text-display-size)/var(--text-display-lh) var(--font-display); color: var(--text); letter-spacing: var(--tracking-tight); }
.t-hero    { font: var(--text-hero-weight) var(--text-hero-size)/var(--text-hero-lh) var(--font-display); color: var(--text); letter-spacing: var(--tracking-tight); }

/* Editorial italic accent — used inside hero h1's. Pages that already
   wrap a word in <em> inside an h1/h2 get this serif style for free
   when this class is also applied; the legacy code that sets
   font-style:italic on the surrounding heading still works. */
.t-serif, .serif {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.02em;
}

/* ===== prisma-base.css ===== */
/* prisma-base.css — shared accessibility & motion primitives.
   Loaded by every HTML page. Keep this file small and free of page-specific
   styling. The point is a single shared a11y baseline so the existing
   per-page design systems can drift visually without losing keyboard,
   screen-reader, and reduced-motion guarantees.

   2026-05-11: Repainted to Geist + Instrument Serif. Font import below
   replaces the legacy Migra/General Sans/JetBrains Mono trio. */

/* 0. Type stack — fonts.
   Geist (UI), Geist Mono (data/code), Instrument Serif (italic display).

   P3-O LANDED (2026-05-15) · Self-hosting via /fonts/*.woff2. The previous
   @import url('https://fonts.googleapis.com/...') was replaced with the
   local prisma-fonts.css, which declares 8 @font-face blocks for latin +
   latin-ext subsets of all three families. Net wins: one fewer 3rd-party
   hop on every page load (gstatic.com gone), no Referer/IP leak to Google,
   and CSP can drop fonts.googleapis.com/fonts.gstatic.com from
   style-src/font-src — see middleware.js. Geist and Geist Mono ship as
   variable fonts so a single ~30 KB file covers weights 400-900.

   P1-A LANDED (2026-05-19) · prisma-fonts.css is now concatenated into
   BUNDLE_PARTS in server.js, so the previous @import here is redundant
   and would force a wasted round-trip during CSS parse. Removed. */

/* 0.1 Page-wide visual baseline — applied to every <html>/<body> via
   element selectors so the look is inherited even by pages that don't
   set --bg explicitly. The radial-gradient bg comes from the redesign
   landing page; it adds depth without screaming "AI tool". */
html, body {
  background: var(--bg, #0A0B0D);
  color: var(--text, #E8EAED);
  font-family: var(--font-ui, 'Geist', system-ui, -apple-system, sans-serif);
  font-feature-settings: 'ss01', 'cv11';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.005em;
}
body {
  min-height: 100vh;
  min-height: 100dvh;
  background:
    radial-gradient(1200px 600px at 20% -10%, rgba(61, 219, 194, 0.05), transparent 60%),
    radial-gradient(900px 500px at 90% 0%, rgba(111, 168, 240, 0.03), transparent 60%),
    var(--bg, #0A0B0D);
  background-attachment: fixed;
}
[data-theme="light"] body {
  background:
    radial-gradient(1200px 600px at 20% -10%, rgba(15, 138, 119, 0.05), transparent 60%),
    radial-gradient(900px 500px at 90% 0%, rgba(58, 108, 182, 0.04), transparent 60%),
    var(--bg, #F7F8FA);
}

/* 0.2 Custom scrollbar — matches the dark surface */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-2, #2A2F37);
  border-radius: 10px;
  border: 2px solid var(--bg, #0A0B0D);
}
::-webkit-scrollbar-thumb:hover { background: #3A3F47; }
[data-theme="light"] ::-webkit-scrollbar-thumb { background: var(--border-2, #C9CDD4); border-color: var(--bg, #F7F8FA); }
[data-theme="light"] ::-webkit-scrollbar-thumb:hover { background: #B0B4BC; }

/* 0.3 Editorial-italic helper — wrap single words in <em class="serif">
   inside hero h1/h2 to get the Instrument Serif italic accent. The bare
   <em> tag still gets a subtle italic via a default user-agent style;
   pages that want the explicit serif emphasis must add the class. */
.serif, .mono { font-feature-settings: normal; }
.mono { font-family: var(--font-mono, 'Geist Mono', monospace); font-feature-settings: 'tnum'; }
.serif {
  font-family: var(--font-serif, 'Instrument Serif', Georgia, serif);
  font-style: italic;
  letter-spacing: -0.02em;
  font-weight: 400;
}

/* 0.4 Brand mark — additive class for the conic-gradient logo square.
   Production HTML rarely uses this class today; defining it here makes
   it available to any page that wants to drop in <span class="brand-mark"></span>
   alongside the wordmark. Harmless if unused. */
.brand-mark {
  display: inline-block;
  width: 22px; height: 22px;
  vertical-align: middle;
  background: conic-gradient(from 210deg, #3DDBC2, #6FA8F0, #B58BE8, #3DDBC2);
  border-radius: 6px;
  position: relative;
  box-shadow: 0 0 18px rgba(61, 219, 194, 0.40);
  flex-shrink: 0;
}
.brand-mark::after {
  content: '';
  position: absolute; inset: 4px;
  background: var(--bg, #0A0B0D);
  border-radius: 3px;
}
[data-theme="light"] .brand-mark::after { background: var(--bg, #F7F8FA); }

/* 1. Keyboard focus ring — restored across all interactive controls.
   Uses --accent if defined by the page; falls back to a high-contrast
   teal that reads acceptably on both dark and light surfaces. */
:where(a, button, [role="button"], [role="tab"], [role="menuitem"],
       input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent, #3DDBC2);
  outline-offset: 2px;
  border-radius: 3px;
}

/* 2. Skip-to-main-content link.
   Visually hidden until focused, then jumps to top-left.
   Add as the first <body> child:
     <a class="skip-link" href="#main">Skip to main content</a> */
/* RE-1 (2026-05-19 audit): keep the link completely outside the
   render path until focused. `top:-40px` alone left the element in
   document layout space; some flash-of-render frameworks would surface
   it briefly. `clip-path: inset(50%)` collapses the box to zero. */
.skip-link {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 9999;
  padding: 10px 14px;
  background: var(--accent, #3DDBC2);
  color: var(--accent-ink, #06241F);
  font: 600 14px/1 var(--font-ui, system-ui), sans-serif;
  text-decoration: none;
  border-radius: 6px;
  transition: clip-path .15s;
  box-shadow: 0 8px 24px -8px rgba(61, 219, 194, .50);
  clip-path: inset(50%);
}
.skip-link:focus,
.skip-link:focus-visible {
  clip-path: inset(0);
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* 3. Visually-hidden helper for labels that should reach screen readers
   but stay off-screen visually. Standard "sr-only" pattern.
   X-05 (2026-05-19 audit): `display: inline-block !important` so
   inner <table>s can't reserve their intrinsic width on a 320px
   viewport (display:table tables forced 320–500 px width via
   sparkline companion tables, triggering horizontal scroll). */
.sr-only {
  position: absolute !important;
  display: inline-block !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 4. Reduced-motion — kill animations/transitions for users who ask.
   Honours WCAG 2.3.3. Pages can still opt back in by overriding. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* 5. Toast notification primitive.
   Render programmatically; default position bottom-right.
   Usage:
     <div class="prisma-toast-host" id="prisma-toasts"></div>
     // call window.prismaToast('Saved', { kind: 'ok' }) — see prisma-base.js */
.prisma-toast-host {
  position: fixed;
  bottom: 16px;
  right: 16px;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
  max-width: min(420px, calc(100vw - 32px));
}
.prisma-toast {
  pointer-events: auto;
  padding: 12px 14px 12px 16px;
  border-radius: var(--radius-md, 10px);
  font: 500 13px/1.5 var(--font-ui, system-ui), sans-serif;
  background: var(--surface, #141619);
  color: var(--text, #E8EAED);
  border: 1px solid var(--border, #1F2329);
  box-shadow: 0 8px 20px -10px rgba(0,0,0,.45);
  display: flex;
  align-items: flex-start;
  gap: 10px;
  animation: prisma-toast-in .2s ease-out;
}
/* Full-box semantic border identifies the kind without flooding the toast
   with tinted backgrounds. */
.prisma-toast[data-kind="ok"]   { border-color: var(--pass, #5ED39A); }
.prisma-toast[data-kind="warn"] { border-color: var(--warn, #E8B45C); }
.prisma-toast[data-kind="err"]  { border-color: var(--fail, #E16A78); }
.prisma-toast[data-kind="info"] { border-color: var(--info, #6FA8F0); }
.prisma-toast button.dismiss {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-muted, #B5BAC3);
  cursor: pointer;
  padding: 0 4px;
  font-size: 16px;
  line-height: 1;
}
@keyframes prisma-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* 6. Disabled-button visual when using aria-disabled (which keeps focus). */
:where(button, [role="button"])[aria-disabled="true"] {
  opacity: .55;
  cursor: not-allowed;
}

/* 7. Skeleton loaders — shimmer placeholders for in-flight data.
   Usage:
     <span class="prisma-skel prisma-skel-text" style="width:60px"></span>
     <div class="prisma-skel prisma-skel-card" style="height:160px"></div>
   Or programmatically via window.prismaSkeleton(targetEl, { count, kind }).
   Honours prefers-reduced-motion by swapping the shimmer for a static tint. */
.prisma-skel {
  position: relative;
  display: inline-block;
  overflow: hidden;
  background: var(--surface-2, #1A1D22);
  border-radius: var(--radius-sm, 6px);
  color: transparent !important;
  user-select: none;
  vertical-align: middle;
  isolation: isolate;
}
.prisma-skel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, .045) 50%,
    transparent 100%
  );
  animation: prisma-skel-shimmer 1.35s ease-in-out infinite;
  transform: translateX(-100%);
  will-change: transform;
}
[data-theme="light"] .prisma-skel {
  background: var(--surface-2, #ECEEF1);
}
[data-theme="light"] .prisma-skel::after {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(0, 0, 0, .035) 50%,
    transparent 100%
  );
}
.prisma-skel-text {
  height: 1em;
  width: 4em;
  border-radius: 3px;
}
.prisma-skel-line {
  display: block;
  height: 12px;
  width: 100%;
  margin: 6px 0;
  border-radius: 3px;
}
.prisma-skel-line + .prisma-skel-line { width: 78%; }
.prisma-skel-line + .prisma-skel-line + .prisma-skel-line { width: 55%; }
.prisma-skel-circle {
  border-radius: 50%;
  width: 32px;
  height: 32px;
}
.prisma-skel-card {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 90px;
  border-radius: var(--radius-md, 10px);
  border: 1px solid var(--border, #1F2329);
  background: var(--surface, #141619);
}
.prisma-skel-card::after {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, .035) 50%,
    transparent 100%
  );
}
[data-theme="light"] .prisma-skel-card {
  background: var(--surface, #FFFFFF);
  border-color: var(--border, #E2E5EA);
}
.prisma-skel-stat {
  display: inline-block;
  width: 64px;
  height: 28px;
  border-radius: 6px;
  vertical-align: -6px;
}
@keyframes prisma-skel-shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
  .prisma-skel::after { animation: none; opacity: .12; transform: none; }
}

/* 8. Rich tooltip — replacement for the browser's native title="…" delay
   and unstyled look. Activated by JS for any element with [data-tooltip]
   or programmatically via window.prismaTooltipShow(el, content).
   Positioning is computed by the helper to keep the bubble inside the
   viewport on small screens; CSS just supplies the visual shell. */
.prisma-tip {
  position: fixed;
  z-index: 10001;
  max-width: 280px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--surface, #1A1D22);
  border: 1px solid var(--border, #2A2F37);
  color: var(--text, #E8EAED);
  font: 500 12px/1.45 var(--font-ui, system-ui), sans-serif;
  letter-spacing: -.005em;
  box-shadow: 0 10px 28px -12px rgba(0, 0, 0, .55),
              0 2px 6px -2px rgba(0, 0, 0, .35);
  pointer-events: none;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity .12s ease-out, transform .12s ease-out;
}
.prisma-tip[data-open="1"] { opacity: 1; transform: translateY(0); }
.prisma-tip[data-kind="info"]    { border-color: var(--info, #6FA8F0); }
.prisma-tip[data-kind="warn"]    { border-color: var(--warn, #E8B45C); }
.prisma-tip[data-kind="success"] { border-color: var(--pass, #5ED39A); }
.prisma-tip strong { color: var(--text, #E8EAED); font-weight: 600; }
.prisma-tip kbd {
  display: inline-block;
  padding: 1px 5px;
  margin: 0 1px;
  background: var(--surface-2, #2A2F37);
  border: 1px solid var(--border, #3A3F47);
  border-radius: 3px;
  font: 500 10.5px/1.3 var(--font-mono, ui-monospace, monospace);
  color: var(--text-muted, #B5BAC3);
  vertical-align: 1px;
}
[data-theme="light"] .prisma-tip {
  background: #FFFFFF;
  border-color: var(--border, #E2E5EA);
  box-shadow: 0 8px 24px -10px rgba(15, 20, 30, .18);
}
[data-tooltip] {
  cursor: help;
  -webkit-text-decoration: underline dotted var(--border-2, #2A2F37);
  text-decoration: underline dotted var(--border-2, #2A2F37);
  text-underline-offset: 3px;
}
[data-tooltip][data-tooltip-plain="1"] {
  text-decoration: none;
  cursor: inherit;
}
@media (prefers-reduced-motion: reduce) {
  .prisma-tip { transition: opacity .01ms; }
}

/* 9. Inline progress bar — drop-in indeterminate spinner alternative.
   Usage:
     <div class="prisma-progress" role="progressbar" aria-label="Loading…"></div>
     .prisma-progress--determinate with style="--p:42" for known percentages */
.prisma-progress {
  position: relative;
  width: 100%;
  height: 3px;
  background: var(--surface-2, #1A1D22);
  border-radius: 2px;
  overflow: hidden;
}
.prisma-progress::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 40%;
  background: linear-gradient(90deg, transparent, var(--accent, #3DDBC2), transparent);
  animation: prisma-progress-slide 1.15s ease-in-out infinite;
}
.prisma-progress--determinate::after {
  width: calc(var(--p, 0) * 1%);
  background: var(--accent, #3DDBC2);
  animation: none;
  transition: width .25s ease-out;
}
@keyframes prisma-progress-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}
@media (prefers-reduced-motion: reduce) {
  .prisma-progress::after { animation: none; width: 100%; opacity: .5; }
}

/* 10. Optimistic UI states.
   Apply to any element being mutated locally before the server confirms.
   - [data-opt="pending"] dims the element slightly and adds a top progress bar.
   - [data-opt="failed"]  briefly flashes a fail outline then auto-clears.
   - [data-opt="success"] briefly pulses the accent border.
   The JS helper window.prismaOptimistic() toggles these attributes. */
[data-opt="pending"] {
  position: relative;
  opacity: .82;
  transition: opacity .15s ease-out;
}
[data-opt="pending"]::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent, #3DDBC2), transparent);
  animation: prisma-progress-slide 1.1s ease-in-out infinite;
  pointer-events: none;
}
[data-opt="failed"] {
  animation: prisma-opt-shake .35s ease-in-out 1, prisma-opt-flash-fail 1.6s ease-out 1;
}
[data-opt="success"] {
  animation: prisma-opt-flash-ok 1.2s ease-out 1;
}
@keyframes prisma-opt-shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-3px); }
  75%      { transform: translateX(3px); }
}
@keyframes prisma-opt-flash-fail {
  0%   { box-shadow: 0 0 0 2px var(--fail, #E16A78) inset; }
  100% { box-shadow: 0 0 0 0 transparent inset; }
}
@keyframes prisma-opt-flash-ok {
  0%   { box-shadow: 0 0 0 2px var(--pass, #5ED39A) inset; }
  100% { box-shadow: 0 0 0 0 transparent inset; }
}
@media (prefers-reduced-motion: reduce) {
  [data-opt="failed"], [data-opt="success"] { animation: none; }
  [data-opt="pending"]::before { animation: none; opacity: .5; }
}

/* 11. Cached/stale data marker — tiny dot the SWR helper can attach to
   any element to hint that the value was served from cache while a
   revalidation is in-flight. Subtle by design; ignored visually if the
   page doesn't add the class. */
.prisma-stale-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--info, #6FA8F0);
  margin-left: 6px;
  vertical-align: middle;
  animation: prisma-stale-pulse 1.6s ease-in-out infinite;
}
@keyframes prisma-stale-pulse {
  0%, 100% { opacity: .35; }
  50%      { opacity: .9;  }
}
@media (prefers-reduced-motion: reduce) {
  .prisma-stale-dot { animation: none; opacity: .55; }
}

@media print {
  :root {
    color-scheme: light !important;
  }
  body {
    background: #fff !important;
    color: #000 !important;
  }
  .sidebar, .pp-sidebar, .topbar, .pp-topbar, .pc-topbar, header[role="banner"],
  nav[role="navigation"], .pp-drawer, .pin-bar, .pp-bottom-nav, .bulk-bar-sticky,
  button, .pc-btn:not(.print-keep), .ph-btn, [data-no-print] {
    display: none !important;
  }
  main, .page, .pc-page, [role="main"] {
    margin: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    background: #fff !important;
    color: #000 !important;
  }
  a, a:visited {
    color: #000 !important;
    text-decoration: underline;
  }
  .domain-card, .pc-card, .pc-panel, .ph-tile {
    page-break-inside: avoid;
    background: #fff !important;
    border: 1px solid #ccc !important;
    color: #000 !important;
  }
  @page { margin: 1cm; }
}

/* ===== prisma-components.css ===== */
/* prisma-components.css — shared UI primitives.
   Layered on top of prisma-tokens.css + prisma-base.css. Everything here is
   namespaced under `.pc-` so it can coexist with the per-page legacy classes
   without specificity wars. As pages migrate, replace their bespoke
   .btn/.card/.chip with these primitives.

   Convention: classes start with `pc-` (prisma component). Variants chain.
   Examples:
     <button class="pc-btn pc-btn--primary">Suscribirme</button>
     <button class="pc-btn pc-btn--secondary">Cancelar</button>
     <button class="pc-btn pc-btn--danger pc-btn--sm">Eliminar</button>

   Empty state, skeleton, badge, chip, card, table — all here. Don't bake in
   page-specific spacing — let the consumer decide.

   2026-05-11: Repainted to the Geist + Instrument Serif visual language.
   Primary button is teal-fill with optional glow on hover. Cards have the
   redesign's 12-14px radius. Topbar is translucent + backdrop-blur. */

/* X-02 (2026-05-20 audit) — color-mix(in oklab, ...) is Baseline 2023 but
   absent from Safari < 16.2 and iOS Safari < 16.2. When the function is
   unsupported the WHOLE declaration is dropped and the affected element
   inherits whatever sits above it (often unstyled). Provide token-level
   fallbacks for the most prominent decorative uses (scrollbar tinting,
   hover accent fades) so older webkits still show readable, on-brand
   chrome. rgba() can't reproduce oklab perceptual mixing, but a slightly
   cooler tint is better than no tint at all. */
@supports not (color: color-mix(in oklab, red, blue)) {
  :root {
    --accent-soft:   rgba(124, 209, 209, .22);
    --accent-faint:  rgba(124, 209, 209, .12);
    --accent-strong: rgba(124, 209, 209, .38);
    --border-strong: rgba(255, 255, 255, .14);
    --border-faint:  rgba(255, 255, 255, .06);
  }
  [data-theme="light"] {
    --accent-soft:   rgba( 70, 165, 165, .22);
    --accent-faint:  rgba( 70, 165, 165, .10);
    --accent-strong: rgba( 70, 165, 165, .38);
    --border-strong: rgba( 14,  22,  28, .14);
    --border-faint:  rgba( 14,  22,  28, .06);
  }
  .tabs-side,
  .analysis-shell .tabs-bar.tabs-side,
  .tabs-bar.tabs-side {
    scrollbar-color: rgba(124, 209, 209, .22) transparent;
  }
}

/* ─── Button ─────────────────────────────────────────────────── */
/* F17 (2026-05-16): touch-target floor of 44×44px is the WCAG 2.5.5 (AAA)
   and Apple HIG / Material guidance recommendation. We enforce min-height
   and min-width on the base .pc-btn; `.pc-btn--sm` opts out below with an
   explicit override since chip-sized controls in dense data tables need
   to be 32px and almost always sit next to ≥44px primary actions. */
.pc-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 18px;
  min-height: 44px;
  min-width: 44px;
  font: 500 13px/1 var(--font-ui);
  letter-spacing: .015em;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
  text-decoration: none;
  user-select: none;
  background: transparent;
  color: var(--text);
  transition: background-color .15s, border-color .15s, color .15s, box-shadow .15s, transform .08s;
}
.pc-btn:hover { border-color: var(--border-2); background: var(--surface-2); }
.pc-btn:active { transform: translateY(1px); }
.pc-btn[aria-disabled="true"], .pc-btn:disabled {
  opacity: .55; cursor: not-allowed; transform: none;
}
/* Primary — teal fill, dark accent-ink text, subtle glow on hover.
   Matches the redesign's `.btn-primary`. */
.pc-btn--primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
  font-weight: 600;
}
.pc-btn--primary:hover {
  background: var(--accent-3, #5EE9D2);
  border-color: var(--accent-3, #5EE9D2);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.pc-btn--secondary {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text);
}
.pc-btn--secondary:hover {
  background: var(--surface-3);
  border-color: var(--border-2);
}
.pc-btn--ghost {
  background: transparent;
  color: var(--text-muted);
  border-color: transparent;
}
.pc-btn--ghost:hover { color: var(--text); background: var(--surface-2); }
.pc-btn--danger {
  background: var(--fail-bg);
  border-color: var(--fail);
  color: var(--fail);
}
.pc-btn--danger:hover { background: var(--fail); color: #fff; }
/* Explicit opt-out from the 44×44 touch-target floor. Use only where the
   button sits inside dense data tables / chips next to a larger primary
   CTA — never as a stand-alone primary action on mobile. */
.pc-btn--sm {
  padding: 6px 12px;
  min-height: 32px;
  min-width: 32px;
  font-size: 12px;
  border-radius: var(--radius-sm);
}
.pc-btn--lg {
  padding: 14px 24px;
  font-size: 14px;
  border-radius: var(--radius-md);
}

/* Legacy alias — production HTML still ships `.btn-primary` plain. Style
   it the same way `.pc-btn--primary` is styled so pages that haven't been
   migrated still get the redesign treatment. */
.btn-primary {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 22px;
  background: var(--accent);
  color: var(--accent-ink);
  font: 600 13px/1 var(--font-ui);
  letter-spacing: .02em;
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  text-decoration: none;
  cursor: pointer;
  text-transform: uppercase;
  transition: background-color .15s, border-color .15s, box-shadow .15s, transform .08s;
}
.btn-primary:hover {
  background: var(--accent-3, #5EE9D2);
  border-color: var(--accent-3, #5EE9D2);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.btn-primary:active { transform: translateY(1px); }
.btn-primary[aria-disabled="true"], .btn-primary:disabled { opacity: .55; cursor: not-allowed; transform: none; }

/* Legacy alias — `.btn-ghost` mirrors the redesign's hollow button. */
.btn-ghost {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 13px;
  font: 500 12.5px/1 var(--font-ui);
  color: var(--text-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s, border-color .15s, color .15s;
}
.btn-ghost:hover { color: var(--text); border-color: var(--border-2); background: var(--surface-2); }

/* ─── Card ───────────────────────────────────────────────────── */
.pc-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: border-color .15s;
}
.pc-card:hover { border-color: var(--border-2); }
.pc-card--elev { box-shadow: var(--shadow-lg); }
.pc-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.pc-card__title {
  font: 500 15px/1.3 var(--font-display);
  color: var(--text);
  letter-spacing: -0.012em;
  margin: 0;
}
.pc-card__sub {
  font: 400 12px/1.4 var(--font-ui);
  color: var(--text-muted);
}

/* ─── Badge / Chip ───────────────────────────────────────────── */
.pc-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  font: 600 10.5px/1.4 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  border-radius: 99px;
  background: var(--surface-2);
  color: var(--text-muted);
  border: 1px solid var(--border);
}
.pc-badge--ok   { color: var(--pass); border-color: rgba(94,211,154,.35); background: var(--pass-bg); }
.pc-badge--warn { color: var(--warn); border-color: rgba(232,180,92,.35); background: var(--warn-bg); }
.pc-badge--fail { color: var(--fail); border-color: rgba(225,106,120,.35); background: var(--fail-bg); }
.pc-badge--info { color: var(--info); border-color: rgba(111,168,234,.35); background: var(--info-bg); }
.pc-badge--accent { color: var(--accent); border-color: rgba(61,219,194,.30); background: var(--accent-soft); }

.pc-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font: 500 12px/1 var(--font-ui);
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color .15s, color .15s, border-color .15s;
}
.pc-chip:hover { color: var(--text); border-color: var(--border-2); }
.pc-chip[aria-pressed="true"], .pc-chip.is-active {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}

/* ─── Table baseline ─────────────────────────────────────────── */
.pc-table {
  width: 100%;
  border-collapse: collapse;
  font: 400 13px/1.5 var(--font-ui);
}
.pc-table caption {
  text-align: left;
  font: 600 11px/1.3 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 6px 0 12px;
}
.pc-table thead th {
  text-align: left;
  font: 600 11px/1.3 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  position: sticky;
  top: 0;
}
.pc-table tbody td,
.pc-table tbody th {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  color: var(--text);
}
.pc-table tbody tr:hover { background: var(--surface-2); }
.pc-table tbody th[scope="row"] {
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}
.pc-table--zebra tbody tr:nth-child(even) { background: var(--surface-2); }
.pc-table--compact th, .pc-table--compact td { padding: 6px 8px; }

/* ─── Empty state ────────────────────────────────────────────── */
.pc-empty {
  text-align: center;
  padding: 48px 24px;
  border: 1px dashed var(--border-2);
  border-radius: var(--radius-lg);
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  background: var(--surface);
}
.pc-empty__icon {
  width: 48px;
  height: 48px;
  color: var(--text-3);
  margin-bottom: 4px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.pc-empty__icon svg { width: 100%; height: 100%; }
.pc-empty__title {
  font: 500 16px/1.3 var(--font-display);
  letter-spacing: -0.012em;
  color: var(--text);
  margin: 0;
}
.pc-empty__hint {
  font: 400 12.5px/1.5 var(--font-ui);
  max-width: 36ch;
}
.pc-empty__desc {
  font: 400 13px/1.5 var(--font-ui);
  color: var(--text-3);
  max-width: 320px;
  margin: 0;
}
.pc-empty__cta { margin-top: 6px; }

/* ─── Skeleton (loading shimmer) ─────────────────────────────── */
.pc-skel {
  background: linear-gradient(
    90deg,
    var(--surface-2) 0%,
    var(--surface-3) 50%,
    var(--surface-2) 100%
  );
  background-size: 200% 100%;
  border-radius: var(--radius-sm);
  animation: pc-shimmer 1.4s linear infinite;
}
.pc-skel--text { height: 1em; margin: 4px 0; }
.pc-skel--block { height: 80px; }
@keyframes pc-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ─── Form input ─────────────────────────────────────────────── */
.pc-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.pc-field__label {
  font: 600 11px/1.3 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.pc-field__input,
.pc-field input,
.pc-field select,
.pc-field textarea {
  padding: 11px 13px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: 400 13.5px/1.4 var(--font-ui);
  color: var(--text);
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.pc-field input::placeholder,
.pc-field textarea::placeholder,
.pc-field__input::placeholder { color: var(--text-4); }
.pc-field input:focus,
.pc-field select:focus,
.pc-field textarea:focus,
.pc-field__input:focus {
  border-color: var(--accent);
  outline: none;
  background: var(--surface-3);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.pc-field__hint {
  font: 400 11.5px/1.4 var(--font-ui);
  color: var(--text-faint);
}
.pc-field--error .pc-field__input,
.pc-field--error input { border-color: var(--fail); }
.pc-field--error .pc-field__hint { color: var(--fail); }

/* ─── Section heading ────────────────────────────────────────── */
.pc-section-title {
  font: 500 18px/1.2 var(--font-display);
  color: var(--text);
  letter-spacing: -0.014em;
  margin: 24px 0 14px;
}

/* ─── Stack / Inline (tiny layout helpers) ───────────────────── */
.pc-stack { display: flex; flex-direction: column; gap: 10px; }
.pc-stack--lg { gap: 18px; }
.pc-inline { display: flex; align-items: center; gap: 8px; }
.pc-inline--end { justify-content: flex-end; }

/* ───────────────────────────────────────────────────────────────
   Redesign primitives — added 2026-04-26 alongside the dropped
   Fraunces / gradient sweep. Pure additive: any page can opt in
   without editing existing rules.
   ─────────────────────────────────────────────────────────────── */

/* KPI cell — replaces the empty stat-card pattern. Mono label,
   tabular numerals, optional delta line. Compose a row with .pc-kpi-row. */
.pc-kpi-row {
  display: grid;
  gap: 10px;
}
.pc-kpi-row.pc-kpi-row--3 { grid-template-columns: repeat(3, 1fr); }
.pc-kpi-row.pc-kpi-row--4 { grid-template-columns: repeat(4, 1fr); }
.pc-kpi-row.pc-kpi-row--5 { grid-template-columns: repeat(5, 1fr); }
.pc-kpi-row.pc-kpi-row--6 { grid-template-columns: repeat(6, 1fr); }
@media (max-width: 1100px) {
  .pc-kpi-row.pc-kpi-row--5,
  .pc-kpi-row.pc-kpi-row--6 { grid-template-columns: repeat(3, 1fr); }
  .pc-kpi-row.pc-kpi-row--4 { grid-template-columns: repeat(2, 1fr); }
}
.pc-kpi {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: border-color .15s;
}
.pc-kpi:hover { border-color: var(--border-2); }
.pc-kpi-label {
  font: 500 11px/1 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-3, var(--text-muted));
}
.pc-kpi-val {
  font: 500 28px/1 var(--font-ui);
  letter-spacing: -.022em;
  color: var(--text);
  font-variant-numeric: tabular-nums slashed-zero;
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.pc-kpi-val small {
  font: 500 13px/1 var(--font-mono);
  color: var(--text-3, var(--text-muted));
  letter-spacing: 0;
}
.pc-kpi-meta {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font: 500 12px/1.4 var(--font-mono);
  color: var(--text-3, var(--text-muted));
  font-variant-numeric: tabular-nums;
  flex-wrap: wrap;
}

/* Delta — colored numeric change. Use with .pc-kpi-meta or inline. */
.pc-delta { font-weight: 500; font-variant-numeric: tabular-nums; }
.pc-delta--pos { color: var(--pass); }
.pc-delta--neg { color: var(--fail); }
.pc-delta--flat { color: var(--text-3, var(--text-muted)); }

/* Mono brackets — terminal-style status chip. Replaces colored pills. */
.pc-bkt {
  display: inline-flex;
  align-items: center;
  font: 600 10.5px/1 var(--font-mono);
  letter-spacing: .06em;
  color: var(--text-2, var(--text-muted));
  text-transform: uppercase;
  white-space: nowrap;
}
.pc-bkt::before { content:'['; color: var(--text-4, var(--text-faint)); margin-right: 2px; }
.pc-bkt::after  { content:']'; color: var(--text-4, var(--text-faint)); margin-left: 2px; }
.pc-bkt--ok   { color: var(--pass); }
.pc-bkt--warn { color: var(--warn); }
.pc-bkt--neg  { color: var(--fail); }
.pc-bkt--ink  { color: var(--text); }

/* Score — typographic, semantic color carries severity. No dot ring. */
.pc-score {
  display: inline-flex;
  align-items: baseline;
  font: 500 22px/1 var(--font-ui);
  letter-spacing: -.018em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.pc-score--warn { color: var(--warn); }
.pc-score--bad  { color: var(--fail); }
.pc-score small {
  font: 500 11px/1 var(--font-mono);
  color: var(--text-4, var(--text-faint));
  margin-left: 3px;
}

/* Sparkline — inline tiny chart, fixed height for table cells. */
.pc-spark { display: inline-block; vertical-align: middle; }
.pc-spark-line { fill: none; stroke: var(--accent); stroke-width: 1.4; }
.pc-spark-line--warn { stroke: var(--warn); }
.pc-spark-line--neg  { stroke: var(--fail); }

/* LLM coverage strip — 8 squares, one per engine. */
.pc-llm-strip { display: inline-flex; gap: 3px; align-items: center; }
.pc-llm-cell {
  width: 16px; height: 16px;
  border-radius: 3px;
  background: var(--surface-3);
  border: 1px solid var(--border-2);
  display: grid; place-items: center;
  font: 700 8.5px/1 var(--font-mono);
  color: var(--text-4, var(--text-faint));
}
.pc-llm-cell--cited {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.pc-llm-cell--partial {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}

/* Chart helpers — pure SVG, no library. Pages embed inline <svg>
   and use these classes for stroke/fill consistency. */
.pc-chart-svg { display: block; width: 100%; height: auto; overflow: visible; }
.pc-chart-grid line { stroke: var(--border); stroke-width: 1; }
.pc-chart-grid line.pc-chart-zero { stroke: var(--border-2); }
.pc-chart-axis { font: 500 10.5px var(--font-mono); fill: var(--text-4, var(--text-faint)); font-variant-numeric: tabular-nums; }
.pc-chart-line { fill: none; stroke: var(--accent); stroke-width: 1.6; }
.pc-chart-line--alt { stroke: var(--info); }
.pc-chart-line--ghost { stroke: var(--text-2, var(--text-muted)); stroke-dasharray: 3 3; }
.pc-chart-area { fill: var(--accent-soft); }
.pc-chart-bar { fill: var(--accent); }
.pc-chart-bar--bg   { fill: var(--surface-3); }
.pc-chart-bar--warn { fill: var(--warn); }
.pc-chart-bar--neg  { fill: var(--fail); }

/* Histogram — flex row of bars for distribution display. */
.pc-histo { display: flex; align-items: flex-end; gap: 2px; height: 64px; }
.pc-histo-bar {
  flex: 1;
  background: var(--surface-3);
  border-radius: 1px 1px 0 0;
}
.pc-histo-bar--fill { background: var(--accent); }
.pc-histo-bar--warn { background: var(--warn); }
.pc-histo-bar--neg  { background: var(--fail); }

/* Donut — host wrapper for SVG donut + legend grid. */
.pc-donut-wrap { display: flex; align-items: center; gap: 16px; }
.pc-donut-track { stroke: var(--surface-3); fill: none; stroke-width: 14; }
.pc-donut-arc   { fill: none; stroke-width: 14; }
.pc-legend { display: flex; flex-direction: column; gap: 6px; font: 500 12px/1.4 var(--font-mono); color: var(--text-2, var(--text-muted)); font-variant-numeric: tabular-nums; }
.pc-legend-row { display: flex; align-items: center; gap: 8px; }
.pc-legend-dot { width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0; }
.pc-legend-num { margin-left: auto; color: var(--text-3, var(--text-muted)); }

/* Data table — denser than .pc-table, tabular numerals, no zebra. */
.pc-dt {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  table-layout: fixed;
}
.pc-dt thead th {
  text-align: left;
  font: 600 11px/1.2 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-3, var(--text-muted));
  padding: 10px 12px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.pc-dt thead th.pc-right, .pc-dt tbody td.pc-right { text-align: right; }
.pc-dt thead th.pc-center, .pc-dt tbody td.pc-center { text-align: center; }
.pc-dt tbody td {
  padding: 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  color: var(--text);
  font-variant-numeric: tabular-nums slashed-zero;
}
.pc-dt tbody tr:last-child td { border-bottom: 0; }
.pc-dt tbody tr:hover { background: var(--surface-2); }

/* ─── Modal / Dialog overlay ────────────────────────────────── */
/* Shared backdrop + box system. Replaces per-page .prisma-dlg,
   .modal-overlay, and .ai-modal-box definitions.

   Usage:
     <dialog class="pc-modal pc-modal--top">   <!-- top-aligned (drawer) -->
     <dialog class="pc-modal pc-modal--center"> <!-- vertically centered  -->
       <div class="pc-modal-box">
         <div class="pc-modal-hdr">…</div>
         <div class="pc-modal-body">…</div>
         <div class="pc-modal-ftr">…</div>
       </div>
     </dialog>                                                  */

dialog.pc-modal {
  padding: 0; border: none; background: transparent; color: inherit;
  width: 100%; height: 100%; max-width: none; max-height: none;
  margin: 0; inset: 0; overflow: visible;
}
dialog.pc-modal::backdrop {
  background: rgba(10, 11, 13, 0.72);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
dialog.pc-modal[open] {
  display: flex; justify-content: center;
  padding: 20px; box-sizing: border-box; overflow-y: auto; z-index: 200;
}
/* Top-aligned: content appears near top of screen (sheet/drawer style). */
dialog.pc-modal.pc-modal--top[open]    { align-items: flex-start; }
/* Centered: content floats in the middle of the viewport. */
dialog.pc-modal.pc-modal--center[open] { align-items: center; }
/* Padding overrides for top-aligned dialogs. */
dialog.pc-modal.pdg-top-40[open] { padding-top: 40px; }
dialog.pc-modal.pdg-top-50[open] { padding-top: 50px; }
dialog.pc-modal.pdg-top-60[open] { padding-top: 60px; }
@media (max-width: 600px) {
  dialog.pc-modal.pc-modal--center[open] { align-items: flex-end; padding: 0; }
}

/* Inner content box — the visible card inside the backdrop. */
.pc-modal-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  width: 100%; max-width: 560px;
  box-shadow: var(--shadow-lg);
  animation: pc-modal-in .22s cubic-bezier(.4,0,.2,1);
}
@keyframes pc-modal-in {
  from { opacity: 0; transform: translateY(-12px); }
  to   { opacity: 1; transform: none; }
}
/* Header / body / footer structural helpers. */
.pc-modal-hdr {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
}
/* Accent square mark — pure-CSS decorative element; appears before the
   title in some modal headers. The redesign uses this little glyph as
   a visual anchor on top of cards & dialogs. */
.pc-modal-hdr::before {
  content: '';
  width: 12px; height: 12px;
  border-radius: 3px;
  background: linear-gradient(135deg, var(--accent), var(--blue, #6FA8F0));
  box-shadow: 0 0 12px var(--accent-glow);
  flex-shrink: 0;
}
.pc-modal-title {
  font: 500 16px/1.3 var(--font-ui);
  letter-spacing: -0.015em;
  flex: 1;
  color: var(--text);
}
.pc-modal-close {
  width: 30px; height: 30px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-muted); display: grid; place-items: center;
  font-size: 15px; cursor: pointer; font-family: inherit;
  transition: color .12s, border-color .12s, background .12s;
}
.pc-modal-close:hover { color: var(--text); border-color: var(--border-2); background: var(--surface-3); }
.pc-modal-body { padding: 20px; min-height: 80px; }
.pc-modal-ftr {
  padding: 14px 20px; border-top: 1px solid var(--border);
  display: flex; gap: 8px; justify-content: flex-end;
}

/* ─── Shell v2: Horizontal Topbar + Subnav ──────────────────────
   F2 — 2026-05-10. Replaces sidebar-grid layout across all app
   pages. Activated by prismaRenderShell() adding .has-pc-topbar
   to <body>. The !important overrides win over per-page inline
   <style> blocks that still carry the old grid definitions.

   2026-05-11 repaint: translucent topbar with backdrop-blur (matches
   the redesign's `.topbar`). Brand wordmark uses Instrument Serif
   italic at 17px. Sub-nav stays sticky below the fixed topbar. */

/* Body offset for the fixed topbar */
body.has-pc-topbar { padding-top: 52px; }
/* Account for the fixed topbar in the shell min-height so the page only
   scrolls when content actually overflows the viewport. Without this the
   shell's `min-height: 100vh` PLUS the body's 52px top padding always
   added up to 100vh + 52px → constant 52px of phantom scroll on Analyze. */
body.has-pc-topbar .app-shell { min-height: calc(100vh - 52px); min-height: calc(100dvh - 52px); }

/* WHY F — reserve vertical space for the topbar shell BEFORE prismaRenderShell()
   runs so the body content doesn't jump 52px on mount. Without this the topbar
   markup is injected post-paint and every element below drops, registering a
   CLS of 0.48 in the audit. The 104px floor on ≤720px accounts for the
   wrapped two-row variant. */
#prisma-topbar-mount { min-height: 52px; display: block; }
@media (max-width: 720px) {
  #prisma-topbar-mount { min-height: 104px; }
}

/* Override grid layout in pages with inline sidebar CSS */
body.has-pc-topbar .app-shell      { display: block !important; }
body.has-pc-topbar .app-sidebar    { display: none  !important; }
body.has-pc-topbar .app-sidebar-scrim { display: none !important; }
body.has-pc-topbar .app-main       { display: block !important; grid-column: auto !important; grid-row: auto !important; }
body.has-pc-topbar .app-topbar     { display: none  !important; } /* old sticky topbar inside app-main */

/* Center .app-content horizontally when the parent is the topbar-shell
   block layout. The page-local rules use `align-self: center`, which is a
   no-op now that .app-main flipped from flex to block. margin-inline:auto
   wins regardless of parent display, and keeps the existing max-width
   constraint (1320px) intact. Fixes "content drifts to the left at
   fullscreen" reported 2026-05-12. */
body.has-pc-topbar .app-content { margin-inline: auto !important; }

/* Primary topbar — fixed, full-width, 52px, translucent w/ backdrop-blur */
.pc-topbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 52px;
  background: rgba(10, 11, 13, 0.75);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 16px;
  z-index: 100;
  gap: 0;
}
[data-theme="light"] .pc-topbar {
  background: rgba(247, 248, 250, 0.80);
}

.pc-topbar__brand {
  font-family: var(--font-serif, 'Instrument Serif'), Georgia, serif;
  font-size: 22px;
  font-weight: 400;
  letter-spacing: -0.025em;
  color: var(--accent);
  font-style: italic;
  text-decoration: none;
  padding: 0 10px 0 0;
  flex-shrink: 0;
  white-space: nowrap;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
/* Decorative conic-gradient brand mark — the redesign uses a small
   square with a rotating teal-blue-violet gradient. Pure CSS, no
   asset required. */
.pc-topbar__brand-mark {
  width: 18px;
  height: 18px;
  border-radius: 5px;
  background: conic-gradient(from 210deg,
    var(--accent),
    var(--info, #6FA8F0),
    #B58BE8,
    var(--accent));
  position: relative;
  box-shadow: 0 0 14px var(--accent-glow);
  flex-shrink: 0;
}
.pc-topbar__brand-mark::after {
  content: '';
  position: absolute;
  inset: 3px;
  background: var(--bg);
  border-radius: 2px;
}
.pc-topbar__sep {
  width: 1px; height: 18px;
  background: var(--border);
  flex-shrink: 0;
  margin: 0 10px 0 2px;
}

/* Domain selector */
.pc-topbar__domain { position: relative; flex-shrink: 0; }
.pc-topbar__domain-btn {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  color: var(--text);
  font: 500 12.5px/1 var(--font-ui);
  cursor: pointer;
  max-width: 176px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: border-color .12s;
}
.pc-topbar__domain-btn:hover { border-color: var(--border-2); }
.pc-topbar__domain-btn .pc-caret { opacity: .5; margin-left: 1px; flex-shrink: 0; }
.pc-topbar__domain-drop {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 220px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: 200;
}
.pc-topbar__domain-drop.is-open { display: block; }
.pc-topbar__domain-search {
  display: block; width: 100%;
  padding: 9px 12px;
  border: none; border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  font: 13px/1 var(--font-ui);
  outline: none;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
.pc-topbar__domain-list { max-height: 240px; overflow-y: auto; padding: 4px; }
.pc-topbar__domain-opt {
  display: block;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-size: 12.5px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: none; border: none; width: 100%; text-align: left;
  font-family: var(--font-ui);
}
.pc-topbar__domain-opt:hover,
.pc-topbar__domain-opt.is-active { background: var(--surface-2); color: var(--text); }
.pc-topbar__domain-opt.is-active { font-weight: 600; }
.pc-topbar__domain-empty { padding: 12px; color: var(--text-3); font-size: 12px; text-align: center; }

/* Section nav — 6 primary sections */
.pc-topbar__nav {
  display: flex;
  align-items: center;
  height: 100%;
  margin: 0 8px;
  gap: 0;
  overflow-x: auto;
  scrollbar-width: none;
  flex: 1;
}
.pc-topbar__nav::-webkit-scrollbar { display: none; }
.pc-topbar__sec {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
  height: 100%;
  font: 500 13px/1 var(--font-ui);
  letter-spacing: -0.005em;
  color: var(--text-3);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  transition: color .15s, border-color .15s;
  flex-shrink: 0;
}
.pc-topbar__sec:hover { color: var(--text-2); }
.pc-topbar__sec.is-active { color: var(--text); border-bottom-color: var(--accent); }
.pc-topbar__sec svg { opacity: .65; }
.pc-topbar__sec.is-active svg { opacity: 1; }

/* Right actions cluster */
.pc-topbar__right {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
  padding-left: 8px;
  flex-shrink: 0;
}

/* Notification button + badge */
.pc-notif { position: relative; }
.pc-notif__badge {
  position: absolute;
  top: 3px; right: 2px;
  min-width: 14px; height: 14px;
  border-radius: 7px;
  background: var(--fail);
  color: #fff;
  font: 700 8px/14px var(--font-mono);
  text-align: center;
  padding: 0 2px;
  display: none;
  border: 1.5px solid var(--surface);
}

/* Secondary subnav — sticky at top:52px, below fixed topbar */
.pc-subnav {
  position: sticky;
  top: 52px;
  height: 40px;
  background: rgba(10, 11, 13, 0.85);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 24px;
  gap: 0;
  z-index: 90;
  overflow-x: auto;
  scrollbar-width: none;
}
[data-theme="light"] .pc-subnav { background: rgba(247, 248, 250, 0.85); }
.pc-subnav::-webkit-scrollbar { display: none; }
.pc-subnav:empty { border-bottom: none; height: 0; }

.pc-subnav__tab {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 12px;
  font: 500 12.5px/1 var(--font-ui);
  letter-spacing: -0.005em;
  color: var(--text-3);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  transition: color .15s, border-color .15s;
  cursor: pointer;
  background: none;
  border-top: none; border-left: none; border-right: none;
  flex-shrink: 0;
  font-family: var(--font-ui);
}
.pc-subnav__tab:hover { color: var(--text-2); }
.pc-subnav__tab.is-active { color: var(--text); border-bottom-color: var(--accent); }

/* Mobile hamburger — shown only on narrow screens, hidden by default */
.pc-topbar__hamburger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  border: 1px solid var(--border-2);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  flex-shrink: 0;
  margin-left: 6px;
  /* Slightly elevated so it reads as a tappable control, not a decorative icon */
  box-shadow: 0 1px 3px rgba(0,0,0,.18);
}
.pc-topbar__hamburger:hover { background: var(--surface-3); }
.pc-topbar__hamburger:active { background: var(--surface-3); transform: scale(.94); }

/* Mobile section drawer */
.pc-topbar__drawer {
  display: none;
  position: fixed;
  top: 52px; left: 0; bottom: 0;
  width: 216px;
  background: var(--surface);
  border-right: 1px solid var(--border);
  z-index: 150;
  flex-direction: column;
  padding: 8px 0;
  overflow-y: auto;
  box-shadow: var(--shadow-md);
}
.pc-topbar__drawer.is-open { display: flex; }
.pc-topbar__drawer-sec {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  font: 500 13px/1 var(--font-ui);
  color: var(--text-2);
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: color .12s, border-color .12s;
}
.pc-topbar__drawer-sec:hover { color: var(--text); background: var(--surface-2); }
.pc-topbar__drawer-sec.is-active { color: var(--text); border-left-color: var(--accent); background: var(--surface-2); }
.pc-topbar__drawer-scrim {
  display: none;
  position: fixed;
  inset: 0; top: 52px;
  background: rgba(0,0,0,.5);
  z-index: 140;
}
.pc-topbar__drawer.is-open + .pc-topbar__drawer-scrim { display: block; }

/* Responsive */
@media (max-width: 768px) {
  .pc-topbar__nav    { display: none; }
  .pc-topbar__hamburger { display: flex; }
  .pc-topbar__domain-btn { max-width: 120px; }
  .pc-subnav { padding: 0 12px; }
  .pc-subnav__tab { padding: 0 8px; font-size: 11.5px; }
}
@media (max-width: 480px) {
  .pc-topbar { padding: 0 10px; }
  .pc-topbar__brand { font-size: 19px; }
}
/* Mobile (≤640px) — bottom nav handles navigation; hide hamburger, drawer, account menu */
@media (max-width: 640px) {
  .pc-topbar__hamburger { display: none !important; }
  .pc-topbar__drawer,
  .pc-topbar__drawer-scrim { display: none !important; }
  #acctMenu { display: none !important; }
  /* Right cluster: remove separator border (no nav items to its left), tighten gap */
  .pc-topbar__right {
    border-left: none !important;
    margin-left: auto !important;
    gap: 6px;
    padding-left: 0;
  }
  /* Always show the Límites chip on mobile so user can reach the limits panel */
  #quotaChip { display: inline-flex !important; align-items: center; }
}

/* ─── F5.5 Mobile fixes ──────────────────────────────────────── */
/* Touch targets: ensure min 44px for all interactive elements on mobile */
@media (max-width: 768px) {
  .lang-btn, .lang-btn-dash,
  .pc-subnav__tab,
  .pc-topbar__sec,
  .input-mode-btn,
  .tab-btn {
    min-height: 44px;
  }
}

/* Grid overflow on narrow viewports: min(200px,100%) prevents scrollbar */
.grid-auto-200 {
  grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr));
}

/* Dashboard bulk bar offset: account for both topbar + subnav when shell active */
body.has-pc-topbar .bulk-bar-sticky {
  top: calc(var(--topbar-h, 52px) + 40px);
}

/* ─── Hero + pricing landing — additive skins for legacy classes ───
   These classes already exist on pricing.html and other landing pages.
   Styling them here lets the redesign aesthetic land without HTML edits.

   `.hero` is the wrapper, `.eyebrow` is the dot+tag pill above the
   headline, `.h1` is the large display, and `.search-wrap` + `.btn-primary`
   form the input cluster. The redesign uses Instrument Serif italic on the
   <em> inside the H1 for editorial emphasis. */

.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 6px 14px 6px 8px;
  border: 1px solid var(--border-2);
  border-radius: 999px;
  font: 500 12px/1 var(--font-ui);
  color: var(--text-2);
  background: var(--surface);
  margin-bottom: 32px;
}
.eyebrow .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 8px var(--accent-glow);
  animation: pc-pulse 2s infinite;
}
.eyebrow-tag {
  background: var(--accent-soft); color: var(--accent);
  padding: 2px 8px; border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
}
@keyframes pc-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

/* Mode pills — used in pricing/analyzer landing and chip toggles. The
   redesign treats them as a rounded inline-flex group inside `.mode-pills`
   wrapping <button class="on geo|seo|both">…</button>. */
.mode-pills {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px;
}
.mode-pills button {
  padding: 7px 16px;
  font: 500 12.5px/1 var(--font-ui);
  color: var(--text-2);
  border-radius: 999px;
  transition: background .18s, color .18s, box-shadow .18s;
  display: flex; align-items: center; gap: 6px;
  background: none; border: none; cursor: pointer;
  font-family: var(--font-ui);
}
.mode-pills button.on.geo {
  background: var(--accent); color: var(--accent-ink);
}
.mode-pills button.on.seo {
  background: var(--surface-2); color: var(--text);
  box-shadow: inset 0 0 0 1px var(--border-2);
}
.mode-pills button.on.both {
  background: linear-gradient(90deg, #2C3138, var(--accent) 60%);
  color: var(--accent-ink);
  box-shadow: 0 0 18px var(--accent-soft);
}

/* Search-input cluster — pill-shaped container that lights up on focus.
   The legacy markup is `<div class="search-wrap"><input/><button/></div>`
   on pricing.html and analyzer.html, so we style the parent. */
.search-wrap {
  display: flex;
  max-width: 680px;
  margin: 0 auto;
  background: var(--surface);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-lg);
  padding: 6px;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.search-wrap:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.search-wrap .search-icon {
  display: grid; place-items: center;
  padding: 0 14px;
  color: var(--text-3);
}
.search-wrap input,
.search-wrap input[type="text"],
.search-wrap input[type="search"],
.search-wrap input[type="url"] {
  flex: 1;
  background: transparent;
  border: none; outline: none;
  font: 400 15px/1.4 var(--font-ui);
  color: var(--text);
  padding: 12px 8px;
}
.search-wrap input::placeholder { color: var(--text-4); }

/* ─── Recent strip (analyzer hero footer) ───────────────────────
   The "Análisis recientes" preview row that sits below the hero
   feature checkmarks. Four cards in a row on desktop, single column
   on mobile. The legacy markup uses .recent-strip / .recent-row /
   .recent-card so we style those classes directly. */
.recent-strip {
  max-width: 1080px;
  margin: 30px auto 64px;
  padding: 0 32px;
}
.recent-strip h3 {
  font: 500 11.5px/1 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3, var(--text-muted));
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.recent-strip h3::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}
.recent-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
@media (max-width: 900px) {
  .recent-row { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .recent-row { grid-template-columns: 1fr; }
  .recent-strip { padding: 0 16px; }
}
.recent-card {
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  transition: border-color .15s, transform .15s;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  color: inherit;
}
.recent-card:hover {
  border-color: var(--border-2);
  transform: translateY(-1px);
}
.recent-card .top {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 500;
  margin-bottom: 10px;
  color: var(--text);
}
.recent-card .fav {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  display: grid;
  place-items: center;
  font: 700 10px/1 var(--font-ui);
  color: #fff;
  flex-shrink: 0;
  background: linear-gradient(135deg, var(--info, #6FA8F0), #B58BE8);
  text-transform: uppercase;
}
.recent-card .scores {
  display: flex;
  gap: 6px;
}
.recent-card .pill {
  font: 500 10.5px/1 var(--font-mono);
  padding: 3px 7px;
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--text-2);
  display: flex;
  align-items: center;
  gap: 4px;
  font-variant-numeric: tabular-nums;
}
.recent-card .pill .label {
  color: var(--text-3, var(--text-muted));
}

/* ─── Hero foot + check icon helper ──────────────────────────────
   Small rows of green-check + label sit under the analyzer hero.
   Already styled inline on analyzer.html via .hero-foot, but the
   redesign uses a more generous gap and slightly muted text. We
   only widen the gap and harmonise the icon color. */
.hero-foot {
  margin-top: 50px;
  display: flex;
  justify-content: center;
  gap: 28px;
  flex-wrap: wrap;
  font: 400 12px/1 var(--font-ui);
  color: var(--text-3, var(--text-muted));
}
.hero-foot .item {
  display: flex;
  align-items: center;
  gap: 8px;
}
.hero-foot .item .check {
  color: var(--accent);
  display: inline-flex;
  align-items: center;
}

/* ─── Loading overlay (analyzer pre-results) ─────────────────────
   The full-screen blocker shown while analysis runs. Concentric
   pulse-ring + glowing core, large title, mode line, step list with
   checkmarks. Targets the existing #loading + .loading-card markup
   on analyzer.html — does not change any IDs. */
.loading-overlay {
  /* Style is applied by the existing #loading rule on analyzer.html.
     This block only adds the redesign's softer card look + roomier
     spacing without overriding the activation logic.               */
}
.loading-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  text-align: center;
}
.loading-pulse .ring,
.loading-pulse .lp-ring {
  position: absolute; inset: 0;
  border: 1.5px solid var(--accent);
  border-radius: 50%;
  animation: pc-loading-ring 1.5s ease-out infinite;
}
.loading-pulse .core,
.loading-pulse .lp-core {
  position: absolute; inset: 18px;
  background: var(--accent);
  border-radius: 50%;
  box-shadow: 0 0 20px var(--accent-glow);
  animation: pc-loading-core 1.5s ease-in-out infinite;
}
@keyframes pc-loading-core {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(.85); opacity: .7; }
}
@keyframes pc-loading-ring {
  0%   { transform: scale(.5); opacity: 1; }
  100% { transform: scale(1.4); opacity: 0; }
}

/* ─── Analysis-shell — 2-column post-analysis layout ─────────────
   Wraps the sticky results-bar, sidebar (.tabs-side) and main
   content. Used ONLY when results are visible (#results.active) so
   the hero/landing remains a single-column, centered layout.

   Desktop ≥1024px: 290px sidebar + 1fr content.
   ≤1024px: collapses to a stacked layout where .tabs-side becomes
   a horizontal scroll strip — preserves the legacy .tabs-bar
   visual on small screens. */
.analysis-shell {
  /* Block layout (was grid). The 290px sidebar lane is reserved on the
     .analysis-content via `margin-left:290px` below, because the sidebar
     itself is `position:fixed` so it can anchor to the viewport top —
     not the analysis-shell's natural-flow top. */
  display: block;
  position: relative;
  /* Full-bleed: escape .app-content's 1320px max-width so the sidebar
     reaches the viewport's LEFT edge (matches preview/redesign intent).
     Without this the .analysis-shell sat centered inside the 1320px
     content max, which on 1600px+ viewports made the sidebar appear to
     float mid-page. Reported 2026-05-12. */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  max-width: none;
  min-height: calc(100vh - 52px);
  min-height: calc(100dvh - 52px);
}
/* When the tabsBar still has its initial [hidden] attribute (no analysis
   has been run yet), drop the reserved 290px lane on .analysis-content
   so the empty hero-like state fills the whole shell. */
.analysis-shell:has(> .tabs-bar[hidden]) > .analysis-content,
.analysis-shell:has(> .tabs-side[hidden]) > .analysis-content {
  margin-left: 0;
}
.analysis-shell > .tabs-side {
  /* Desktop side-rail (≥1024px). Fixed-to-viewport so the rail anchors to
     the topbar regardless of what (score-pill-strip, results-bar) sits
     above it in DOM order. z-index 40 paints OVER the full-width sticky
     rails (35/34/32) so the sidebar stays visible while the rails just
     pad their content past x=290. */
  position: fixed;
  top: var(--topbar-h, 52px);
  left: 0;
  width: 290px;
  height: calc(100vh - var(--topbar-h, 52px));
  height: calc(100dvh - var(--topbar-h, 52px));
  background: var(--bg);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  padding: 16px 14px 80px;
  margin: 0;
  z-index: 40;
  overflow-y: auto;
  overflow-x: hidden;
  /* Trap the sidebar's own scroll INSIDE the sidebar so it doesn't accidentally
     scroll the page when reaching its top/bottom. */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in oklab, var(--accent) 22%, transparent) transparent;
}
.analysis-shell > .tabs-side::-webkit-scrollbar { width: 6px; }
.analysis-shell > .tabs-side::-webkit-scrollbar-track { background: transparent; }
.analysis-shell > .tabs-side::-webkit-scrollbar-thumb {
  background: color-mix(in oklab, var(--accent) 20%, transparent);
  border-radius: 3px;
}
.analysis-shell > .tabs-side::-webkit-scrollbar-thumb:hover {
  background: color-mix(in oklab, var(--accent) 38%, transparent);
}
/* Desktop content lane — clear the 290 px fixed sidebar with margin-left. */
.analysis-shell > .analysis-content {
  min-width: 0;
  margin-left: 290px;
  padding: 28px 32px 80px;
}

/* Below the breakpoint the sidebar collapses into a horizontal scroll bar
   styled like the previous .tabs-bar, so mobile users keep the familiar
   horizontal nav. (The reported bug at desktop is fixed by the desktop
   block above — this block stays scoped to phones/tablets only.) */
@media (max-width: 1024px) {
  .analysis-shell {
    display: block;
  }
  .analysis-shell > .tabs-side,
  .analysis-shell > .tabs-bar.tabs-side {
    display: flex;
    flex-direction: row;
    border-right: none;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 0;
    position: sticky !important;
    /* Sit directly under the score-pill strip (top:52 + 64 strip height). */
    top: calc(var(--topbar-h, 52px) + 64px) !important;
    left: auto !important;
    width: auto !important;
    height: auto !important;
    z-index: 29;
    background: var(--bg);
    align-items: stretch;
    margin-bottom: 18px;
    gap: 1px;
  }
  .analysis-shell > .tabs-side::-webkit-scrollbar,
  .analysis-shell > .tabs-bar.tabs-side::-webkit-scrollbar { display: none; }
  .analysis-shell > .analysis-content {
    /* WHY — desktop rule reserves 290px for the fixed sidebar lane.
       Below 1024px the sidebar becomes a horizontal strip (position:sticky,
       full-width), so the reserved lane must be cleared or content is
       pushed off-screen on phones. Root-cause of the "100px column" bug. */
    margin-left: 0 !important;
    padding: 18px 16px 80px;
  }
  /* On mobile the vertical groups become an inline strip. Headings,
     badges and the active accent rail get demoted/hidden to fit. */
  .analysis-shell > .tabs-side .tabs-group,
  .analysis-shell > .tabs-bar.tabs-side .tabs-group {
    display: contents;
  }
  .analysis-shell > .tabs-side .tabs-group-head,
  .analysis-shell > .tabs-bar.tabs-side .tabs-group-head {
    display: none;
  }
  .analysis-shell > .tabs-side .tab-row,
  .analysis-shell > .tabs-bar.tabs-side .tab-row,
  .analysis-shell > .tabs-bar.tabs-side .tab-btn {
    flex-shrink: 0;
    border-radius: 0;
    padding: 10px 14px;
    border-bottom: 2px solid transparent;
    background: none;
    box-shadow: none;
  }
  .analysis-shell > .tabs-side .tab-row::before,
  .analysis-shell > .tabs-bar.tabs-side .tab-row::before { display: none; }
  .analysis-shell > .tabs-side .tab-row.active,
  .analysis-shell > .tabs-bar.tabs-side .tab-row.active,
  .analysis-shell > .tabs-bar.tabs-side .tab-btn.active {
    background: none;
    box-shadow: none;
    border-bottom-color: var(--accent);
    color: var(--text);
  }
  .analysis-shell > .tabs-side .tab-row .glyph,
  .analysis-shell > .tabs-bar.tabs-side .tab-row .glyph {
    width: 14px; height: 14px;
    border: none; background: transparent;
    color: currentColor;
    padding: 0;
  }
  .analysis-shell > .tabs-side .tab-row > svg.ico:first-child,
  .analysis-shell > .tabs-bar.tabs-side .tab-row > svg.ico:first-child {
    width: 14px; height: 14px;
    border: none; background: transparent;
    color: currentColor;
    padding: 0;
  }
  .analysis-shell > .tabs-side .tab-row .glyph .ico,
  .analysis-shell > .tabs-side .tab-row .glyph svg,
  .analysis-shell > .tabs-bar.tabs-side .tab-row .glyph .ico,
  .analysis-shell > .tabs-bar.tabs-side .tab-row .glyph svg { width: 14px; height: 14px; }
  .analysis-shell > .tabs-side .tab-row .new,
  .analysis-shell > .tabs-bar.tabs-side .tab-row .new {
    margin-left: 0;
  }
  /* Group separators (·) and headline-as-text labels — keep the legacy
     visuals on mobile since we re-expose .tab-group-label / .tab-group-sep
     from the existing inline CSS. */
  .analysis-shell > .tabs-bar.tabs-side .tab-group-label,
  .analysis-shell > .tabs-bar.tabs-side .tab-group-sep {
    display: inline-flex; align-items: flex-end;
    padding-bottom: 12px;
  }
}
/* Very small viewports — drop the inline group labels entirely for room. */
@media (max-width: 900px) {
  .analysis-shell > .tabs-bar.tabs-side .tab-group-label,
  .analysis-shell > .tabs-bar.tabs-side .tab-group-sep { display: none; }
}

/* ─── Results bar — sticky horizontal strip above analysis-shell ──
   The redesign places domain pill + mode chip + snapshot meta + ghost
   action buttons on a single row above the 2-column shell. Already
   exists on analyzer.html via .results-bar; we only refine spacing
   and sticky behavior so it sits cleanly above the sidebar. */
#results.active .results-bar,
.results-bar {
  background: var(--bg-elev, var(--surface));
  border-bottom: 1px solid var(--border);
  /* 2026-05-20: scrolls with content (was sticky). The sidebar provides
     persistent navigation; the URL pill row only needs to render in its
     natural position. */
  position: static;
  z-index: 35;
  flex-wrap: wrap;
}

/* ─── Sidebar (.tabs-side) — vertical tab navigation ─────────────
   Replaces the horizontal .tabs-bar inside the analysis-shell on
   desktop. Each .tab-row keeps its existing data-tab / aria-controls
   / id attributes so the existing JS handlers (showTab,
   prismaTabs, etc.) keep working untouched. The headline / demoted
   modifiers come from the existing .tab-btn.is-headline /
   .tab-btn.is-demoted classes — we expose them on .tab-row too via
   chained class names. */
/* Base sidebar (desktop ≥1025px). Each variant below mobile breakpoint
   collapses into the horizontal strip. */
.tabs-side,
.analysis-shell .tabs-bar.tabs-side,
.tabs-bar.tabs-side {
  padding: 16px 14px 80px;
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  margin: 0;
  border-bottom: none;
  border-right: 1px solid var(--border);
  scroll-behavior: smooth;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in oklab, var(--accent) 22%, transparent) transparent;
}
/* Hide the legacy inline separator dots and group labels in vertical
   mode — the new .tabs-group-head replaces them. */
.tabs-side .tab-group-sep,
.analysis-shell .tabs-bar.tabs-side .tab-group-sep,
.tabs-bar.tabs-side .tab-group-sep { display: none; }
.tabs-side .tab-group-label,
.analysis-shell .tabs-bar.tabs-side .tab-group-label,
.tabs-bar.tabs-side .tab-group-label { display: none; }
.tabs-side::-webkit-scrollbar,
.tabs-bar.tabs-side::-webkit-scrollbar { width: 6px; background: transparent; }
.tabs-side::-webkit-scrollbar-track,
.tabs-bar.tabs-side::-webkit-scrollbar-track { background: transparent; }
.tabs-side::-webkit-scrollbar-thumb,
.tabs-bar.tabs-side::-webkit-scrollbar-thumb {
  background: color-mix(in oklab, var(--accent) 22%, transparent);
  border-radius: 3px;
}
.tabs-side::-webkit-scrollbar-thumb:hover,
.tabs-bar.tabs-side::-webkit-scrollbar-thumb:hover {
  background: color-mix(in oklab, var(--accent) 40%, transparent);
}
.tabs-group {
  margin-bottom: 18px;
}
.tabs-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font: 500 10.5px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 6px 10px 6px 12px;
  /* Make the group header act as an accordion toggle when it carries
     [data-collapsible="true"] (added by JS on init). */
  background: none;
  border: 0;
  border-radius: 6px;
  width: 100%;
  text-align: left;
  font-family: var(--font-mono);
}
.tabs-group-head[data-collapsible="true"] {
  cursor: pointer;
  transition: background .12s, color .12s;
}
.tabs-group-head[data-collapsible="true"]:hover { background: var(--surface); color: var(--text-2, var(--text)); }
.tabs-group-head[data-collapsible="true"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tabs-group-head[data-collapsible="true"]::after {
  content: '';
  width: 8px; height: 8px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform .15s;
  margin-left: 8px;
  opacity: .7;
}
.tabs-group[data-collapsed="true"] .tabs-group-head[data-collapsible="true"]::after {
  transform: rotate(-45deg) translate(1px, 1px);
}
.tabs-group[data-collapsed="true"] .tab-btn,
.tabs-group[data-collapsed="true"] .tab-row { display: none; }
.tabs-group[data-collapsed="true"] .tab-group-label,
.tabs-group[data-collapsed="true"] .tab-group-sep { display: none; }
.tabs-group-head .badge {
  margin-left: auto;
  font: 500 10px/1 var(--font-mono);
  padding: 1px 6px;
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  text-transform: none;
  letter-spacing: 0;
  border: 1px solid var(--border-2);
}
.tabs-group.headline .tabs-group-head { color: var(--accent); }
.tabs-group.demoted .tabs-group-head { color: var(--text-muted); opacity: .85; }

.tabs-side .tab-row,
.tabs-bar.tabs-side .tab-row,
.tabs-bar.tabs-side .tab-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  font: 500 13px/1.2 var(--font-ui);
  color: var(--text-2, var(--text-muted));
  border-radius: 8px;
  transition: background .15s, color .15s, box-shadow .15s;
  position: relative;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
  font-family: inherit;
  margin-bottom: 0;
  border-bottom: none;
}
.tabs-side .tab-row .glyph,
.tabs-bar.tabs-side .tab-row .glyph,
.tabs-bar.tabs-side .tab-btn .glyph,
.tabs-side .tab-row > svg.ico:first-child,
.tabs-side .tab-row > svg:first-child,
.tabs-bar.tabs-side .tab-row > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn > svg.ico:first-child {
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border-radius: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-3, var(--text-muted));
  flex-shrink: 0;
  transition: background .15s, color .15s, border-color .15s;
  padding: 3px;
  box-sizing: border-box;
}
.tab-row .glyph .ico,
.tab-row .glyph svg {
  width: 12px;
  height: 12px;
  display: block;
}
.tab-row > svg.ico:first-child {
  /* Inline SVGs that aren't wrapped in <span class="glyph"> still
     get the bordered chip look — using the SVG itself as the box. */
  padding: 3px;
}
/* When the SVG is the only icon (no .glyph wrapper) we shrink its
   inner stroke so it still reads at 12px inside an 18px chip. */
.tab-row > svg.ico:first-child > * {
  transform-origin: center;
}
/* Some tab-rows lead with a non-SVG <span class="tag-ai"> instead of an
   icon. Treat that span as a glyph too so the layout is consistent. */
.tabs-side .tab-row > .tag-ai:first-child,
.tabs-side .tab-row > .vs-text:first-child,
.tabs-bar.tabs-side .tab-row > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-row > .vs-text:first-child,
.tabs-bar.tabs-side .tab-btn > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-btn > .vs-text:first-child {
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border-radius: 4px;
  background: var(--accent-soft);
  border: 1px solid rgba(61, 219, 194, 0.3);
  color: var(--accent);
  font: 700 8.5px/1 var(--font-mono);
  letter-spacing: 0;
  text-transform: uppercase;
  flex-shrink: 0;
  padding: 0;
}
.tabs-side .tab-row:hover,
.tabs-bar.tabs-side .tab-row:hover,
.tabs-bar.tabs-side .tab-btn:hover { background: var(--surface); color: var(--text); }
.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-btn.active {
  background: var(--surface-2);
  color: var(--text);
  box-shadow: inset 3px 0 0 var(--accent);
  font-weight: 600;
  border-bottom-color: transparent;
}
.tabs-side .tab-row.active::before,
.tabs-bar.tabs-side .tab-row.active::before,
.tabs-bar.tabs-side .tab-btn.active::before { display: none; }
.tabs-side .tab-row.headline,
.tabs-side .tab-row.is-headline,
.tabs-bar.tabs-side .tab-row.headline,
.tabs-bar.tabs-side .tab-row.is-headline,
.tabs-bar.tabs-side .tab-btn.is-headline { color: var(--text); }
.tabs-side .tab-row.headline .glyph,
.tabs-side .tab-row.is-headline .glyph,
.tabs-bar.tabs-side .tab-row.is-headline .glyph,
.tabs-bar.tabs-side .tab-btn.is-headline .glyph,
.tabs-side .tab-row.headline > svg.ico:first-child,
.tabs-side .tab-row.is-headline > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row.is-headline > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.is-headline > svg.ico:first-child {
  background: var(--accent-soft);
  border-color: rgba(61, 219, 194, 0.3);
  color: var(--accent);
}
.tabs-side .tab-row.headline.active .glyph,
.tabs-side .tab-row.is-headline.active .glyph,
.tabs-bar.tabs-side .tab-row.is-headline.active .glyph,
.tabs-bar.tabs-side .tab-btn.is-headline.active .glyph,
.tabs-side .tab-row.headline.active > svg.ico:first-child,
.tabs-side .tab-row.is-headline.active > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row.is-headline.active > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.is-headline.active > svg.ico:first-child {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: 0 0 14px var(--accent-glow);
}
.tabs-side .tab-row.demoted,
.tabs-side .tab-row.is-demoted,
.tabs-bar.tabs-side .tab-row.demoted,
.tabs-bar.tabs-side .tab-row.is-demoted,
.tabs-bar.tabs-side .tab-btn.is-demoted { color: var(--text-3, var(--text-muted)); }
.tabs-side .tab-row.demoted .glyph,
.tabs-side .tab-row.is-demoted .glyph,
.tabs-bar.tabs-side .tab-row.is-demoted .glyph,
.tabs-bar.tabs-side .tab-btn.is-demoted .glyph,
.tabs-side .tab-row.demoted > svg.ico:first-child,
.tabs-side .tab-row.is-demoted > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row.is-demoted > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.is-demoted > svg.ico:first-child {
  background: transparent;
  border-color: var(--border);
}
.tabs-side .tab-row .new,
.tabs-bar.tabs-side .tab-row .new,
.tabs-bar.tabs-side .tab-btn .new {
  font: 500 9px/1 var(--font-mono);
  padding: 2px 5px;
  border-radius: 3px;
  background: var(--accent);
  color: var(--accent-ink);
  letter-spacing: 0.05em;
  margin-left: auto;
  text-transform: uppercase;
}
.tabs-side .tab-row.locked,
.tabs-side .tab-row.is-locked,
.tabs-bar.tabs-side .tab-row.locked,
.tabs-bar.tabs-side .tab-row.is-locked,
.tabs-bar.tabs-side .tab-btn.is-locked {
  color: var(--text-4, var(--text-faint));
  cursor: not-allowed;
  opacity: .55;
}
.tabs-side .tab-row.locked .glyph,
.tabs-side .tab-row.is-locked .glyph,
.tabs-bar.tabs-side .tab-row.is-locked .glyph,
.tabs-bar.tabs-side .tab-btn.is-locked .glyph { opacity: .5; }
.tabs-side .tab-row .lock,
.tabs-bar.tabs-side .tab-row .lock {
  margin-left: auto;
  opacity: .6;
  display: inline-flex;
  align-items: center;
}
/* Override the legacy .tab-btn.is-locked::after tooltip since we render
   inside a vertical sidebar — the absolute-positioned tooltip would
   bleed off-screen. We re-expose it via simple CSS title fallback. */
.tabs-side .tab-btn.is-locked::after,
.tabs-bar.tabs-side .tab-btn.is-locked::after { display: none; }

/* ─── Score-hero — large dial + breakdown grid ───────────────────
   The redesign wraps the score-ring with a 360px column and the
   sub-scores grid in the second column inside a single rounded card.
   We keep the existing #scoreNumber / #ringFill / .score-meta IDs
   but enlarge the ring to 280×280 and apply the accent-glow stroke
   filter so it looks like the redesign's `.score-dial`. */
.score-hero {
  display: grid;
  grid-template-columns: 360px minmax(0, 1fr);
  gap: 28px;
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  margin: 18px 0 28px;
  position: relative;
  overflow: hidden;
}
.score-hero::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(circle at 0% 0%, var(--accent-soft), transparent 50%);
  pointer-events: none;
}
.score-hero > * { position: relative; z-index: 1; }
@media (max-width: 1100px) {
  .score-hero {
    grid-template-columns: 1fr;
    padding: 22px;
  }
}

/* ─── Score-dial (analyzer score-section refit) ──────────────────
   Live markup keeps using .score-section as the wrapper. Inside it,
   the existing .score-ring-wrap (with #ringFill / #scoreNumber) gets
   resized + restyled so it visually matches the redesign's .score-dial
   without any HTML changes. We then center the .score-meta column
   below it on narrow screens and to the right on the wide layout. */
.score-section.score-section--hero {
  /* Activated by adding .score-section--hero to the existing
     .score-section element so this rule never disrupts pages that
     don't opt in. */
  display: grid;
  grid-template-columns: 360px minmax(0, 1fr);
  align-items: center;
  gap: 28px;
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  margin: 18px 0 28px;
  text-align: left;
  position: relative;
  overflow: hidden;
}
.score-section.score-section--hero::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(circle at 0% 0%, var(--accent-soft), transparent 50%);
  pointer-events: none;
}
.score-section.score-section--hero > * { position: relative; z-index: 1; }
.score-section.score-section--hero .score-ring-wrap {
  width: 280px;
  height: 280px;
  margin: 0 auto;
  display: grid;
  place-items: center;
  position: relative;
}
.score-section.score-section--hero .score-ring-wrap svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}
.score-section.score-section--hero .ring-bg {
  stroke: var(--border-2);
  fill: none;
  stroke-width: 7;
}
.score-section.score-section--hero .ring-fill {
  stroke: var(--accent);
  filter: drop-shadow(0 0 8px var(--accent-glow));
  fill: none;
  stroke-width: 7;
}
.score-section.score-section--hero .score-label {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
}
.score-section.score-section--hero .score-number {
  font: 500 88px/1 var(--font-display, var(--font-ui));
  letter-spacing: -0.04em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.score-section.score-section--hero .score-text {
  font: 500 11px/1 var(--font-mono);
  color: var(--text-3, var(--text-muted));
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-top: 6px;
}
.score-section.score-section--hero .score-meta {
  max-width: none;
  margin: 0;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.score-section.score-section--hero .score-meta h2 {
  font: 500 26px/1.15 var(--font-display, var(--font-ui));
  letter-spacing: -0.02em;
  margin: 0;
}
.score-section.score-section--hero .score-meta > p {
  font-size: 13px;
  color: var(--text-2, var(--text-muted));
  margin: 0;
  max-width: 60ch;
}
.score-section.score-section--hero .sub-scores {
  justify-content: flex-start;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.score-section.score-section--hero .action-btns {
  justify-content: flex-start;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 6px;
}
@media (max-width: 1100px) {
  .score-section.score-section--hero {
    grid-template-columns: 1fr;
    text-align: center;
    padding: 22px;
  }
  .score-section.score-section--hero .score-meta { text-align: center; align-items: center; }
  .score-section.score-section--hero .sub-scores,
  .score-section.score-section--hero .action-btns { justify-content: center; }
}
@media (max-width: 640px) {
  .score-section.score-section--hero .score-ring-wrap {
    width: 200px; height: 200px;
  }
  .score-section.score-section--hero .score-number { font-size: 64px; }
}

/* ─── Billing page (port of preview/redesign/styles-billing.css) ───────
   Restyles the existing billing.html markup. Class names are scoped
   under `.bill-` so they don't clash with the legacy `.card` / `.plan`
   selectors that other pages still use.
   2026-05-12: Initial port. */
.bill-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 28px;
  margin-bottom: 18px;
  transition: border-color 0.15s;
}
.bill-card:hover { border-color: var(--border-2); }
.bill-card > h2 {
  font: 500 17px/1.3 var(--font-display);
  letter-spacing: -0.005em;
  margin: 0 0 4px;
  color: var(--text);
}
.bill-card > .sub,
.bill-card > p.muted {
  color: var(--text-3);
  font-size: 13px;
  margin: 0 0 22px;
}

/* Page hero — italic <em class="serif"> accent on the title. */
.page-hero h1 .serif,
.bill-head h1 .serif,
.bill-head h1 em {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  color: var(--accent);
  letter-spacing: -0.02em;
}

/* Key/value list — terminal-style label column on the left. */
.bill-kv-list {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--border);
}
.bill-kv-row {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 24px;
  padding: 14px 0;
  align-items: center;
  border-bottom: 1px solid var(--border);
}
.bill-kv-key {
  font: 600 10.5px/1.2 var(--font-mono);
  color: var(--text-3);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.bill-kv-val {
  font-size: 14px;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  word-break: break-word;
}
.bill-kv-val code {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-4);
  overflow-wrap: anywhere;
}

/* Status pill — colored dot + uppercase mono label. Variants per
   subscription state. Dot is offset from the label baseline by
   `align-items:center` and explicitly sized so it reads as a deliberate
   indicator rather than a typographic glyph. */
.bill-status-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 11px 4px 9px;
  border-radius: var(--radius-pill);
  font: 600 10.5px/1.2 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid transparent;
}
.bill-status-pill .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 6px currentColor;
  flex-shrink: 0;
}
.bill-status-pill.is-active   { background: var(--pass-bg); color: var(--pass); border-color: rgba(94,211,154,.25); }
.bill-status-pill.is-trialing { background: var(--info-bg); color: var(--info); border-color: rgba(111,168,234,.25); }
.bill-status-pill.is-past_due,
.bill-status-pill.is-canceled { background: var(--fail-bg); color: var(--fail); border-color: rgba(225,106,120,.25); }
.bill-status-pill.is-free     { background: var(--surface-2); color: var(--text-3); border-color: var(--border); }

/* Plan name + price line under the status pill. */
.bill-plan-headline {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  margin: 18px 0 22px;
}
.bill-plan-headline .name {
  font: 400 26px/1.1 var(--font-serif);
  font-style: italic;
  letter-spacing: -0.01em;
  color: var(--text);
}
.bill-plan-headline .price {
  font: 500 13px/1 var(--font-mono);
  color: var(--text-2);
  letter-spacing: 0.02em;
}

/* Tech-details disclosure — fold-out for Stripe customer ID etc. */
.bill-tech-details { font-size: 13px; }
.bill-tech-details summary {
  cursor: pointer;
  color: var(--text-3);
  font: 500 12.5px/1 var(--font-ui);
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  user-select: none;
  padding: 4px 8px 4px 6px;
  margin-left: -6px;
  border-radius: var(--radius-sm);
  transition: color 0.15s, background-color 0.15s;
}
.bill-tech-details summary:hover { color: var(--text); background: var(--surface-2); }
.bill-tech-details summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.bill-tech-details summary::-webkit-details-marker { display: none; }
.bill-tech-details summary::before {
  content: '\25B8';
  font-size: 10px;
  transition: transform 0.15s;
}
.bill-tech-details[open] summary::before { transform: rotate(90deg); }
.bill-tech-details .tech-body {
  margin-top: 10px;
  padding: 10px 14px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: 400 12px/1.7 var(--font-mono);
  color: var(--text-3);
  word-break: break-all;
}

/* Card actions row — divides the card body from its trailing buttons. */
.bill-card-actions {
  margin-top: 22px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* Alert banner — neutral surface card with a single colored accent rule
   along the top edge. Used for past-due / payment errors and any inline
   "something needs attention" callouts. Same primitive across the app so
   the eye learns the shape once. */
.alert-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--fail);
  border-radius: var(--radius-md);
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.alert-banner .alert-icon {
  width: 22px;
  height: 22px;
  color: var(--fail);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.alert-banner .alert-text {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  color: var(--text-2);
  line-height: 1.5;
}
.alert-banner .alert-text b { font-weight: 600; color: var(--text); }

/* ─── Reusable inline callout ───────────────────────────────────────────
 * One primitive for every non-toast "this row of UI needs to say something
 * about the request that just ran" surface. Neutral card, single colored
 * accent rule along the top. Used by analyzer error boxes, gating notices,
 * the offline-server notice, and any future inline callout.
 *
 *   <div class="pc-callout pc-callout--warn">…</div>
 *   <div class="pc-callout pc-callout--err">…</div>
 *   <div class="pc-callout pc-callout--info">…</div>
 *   <div class="pc-callout pc-callout--ok">…</div>
 *
 * Headline and body are not enforced — keep the copy short. A leading
 * <b>label</b> auto-colors to var(--text) so authors don't need inline color.
 */
.pc-callout {
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md, 10px);
  font: 500 13px/1.5 var(--font-ui, system-ui), sans-serif;
  color: var(--text-2);
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.pc-callout--ok   { border-color: var(--pass); }
.pc-callout--warn { border-color: var(--warn); }
.pc-callout--err  { border-color: var(--fail); }
.pc-callout--info { border-color: var(--info); }
.pc-callout b     { color: var(--text); font-weight: 600; }
.pc-callout .pc-callout__body { flex: 1; min-width: 0; }
/* Compact variant — fits inline above charts / inside form rows. */
.pc-callout--sm   { padding: 10px 14px; font-size: 12.5px; }

/* Usage rows — horizontal "label · meta · numbers" row above a thin bar.
   The leading capital letter is a tiny mono badge keyed off the bucket
   name (A / G / C / S). */
.bill-usage-row {
  padding: 16px 0;
  border-bottom: 1px solid var(--border);
}
.bill-usage-row:last-child { border-bottom: none; }
.bill-usage-row:first-child { padding-top: 0; }
.bill-usage-row .top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 8px;
}
.bill-usage-row .lab {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  font: 500 13.5px/1.4 var(--font-ui);
  color: var(--text);
}
.bill-usage-row .lab .key-letter {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--text-3);
  font: 600 10.5px/1 var(--font-mono);
  letter-spacing: 0;
  align-self: center;
  flex-shrink: 0;
}
.bill-usage-row .lab .meta {
  font: 400 11.5px/1.4 var(--font-ui);
  color: var(--text-3);
}
.bill-usage-row .nums {
  font: 500 12.5px/1 var(--font-mono);
  color: var(--text-2);
  white-space: nowrap;
}
.bill-usage-row .nums .used { color: var(--text); font-weight: 600; }
.bill-usage-row .nums.is-warn .used { color: var(--warn); }
.bill-usage-row .nums.is-full .used { color: var(--fail); }

/* Progress bar — pure CSS, color shifts with state. */
.bill-bar {
  height: 6px;
  border-radius: 3px;
  background: var(--surface-2);
  overflow: hidden;
}
.bill-bar > .fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--accent);
  transition: width 0.4s ease;
}
.bill-bar > .fill.is-warn { background: var(--warn); }
.bill-bar > .fill.is-full {
  background: var(--fail);
  animation: bill-pulse-full 1.6s ease-in-out infinite;
}
@keyframes bill-pulse-full {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.7; }
}

/* Inline nudge under usage list when one+ buckets crosses warn/full.
   Matches .alert-banner: neutral surface, single colored accent rule along
   the top edge. The kind modifier only changes the accent color. */
.bill-usage-nudge {
  margin-top: 18px;
  padding: 14px 16px;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 2px solid var(--border);
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.bill-usage-nudge.is-warn   { border-color: var(--warn); }
.bill-usage-nudge.is-danger { border-color: var(--fail); }
.bill-usage-nudge .text {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  color: var(--text-2);
  line-height: 1.5;
}
.bill-usage-nudge .text b { color: var(--text); font-weight: 600; }
.bill-usage-foot {
  margin-top: 16px;
  font: 400 11.5px/1 var(--font-mono);
  color: var(--muted-2);
  text-align: right;
}

/* Plan grid — 4 cards side-by-side, current plan glows teal. */
.bill-plans-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 14px;
}
.bill-plan-card {
  padding: 22px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  position: relative;
}
.bill-plan-card.is-current {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 30px rgba(61, 219, 194, 0.12);
}
.bill-plan-card .badge {
  font: 600 10px/1 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 14px;
}
.bill-plan-card.is-current .badge { color: var(--accent); }
.bill-plan-card .name {
  font: 400 26px/1.1 var(--font-serif);
  font-style: italic;
  letter-spacing: -0.01em;
  margin-bottom: 4px;
  color: var(--text);
}
.bill-plan-card .price {
  font: 500 14px/1.3 var(--font-mono);
  color: var(--text-2);
  margin-bottom: 18px;
  min-height: 18px;
}
.bill-plan-card .pitch {
  font-size: 12.5px;
  color: var(--text-3);
  line-height: 1.45;
  margin-bottom: 16px;
  min-height: 36px;
}
.bill-plan-card .limits { font-size: 12.5px; margin-bottom: 22px; }
.bill-plan-card .limits .lim {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px dashed var(--border);
}
.bill-plan-card .limits .lim:last-child { border-bottom: none; }
.bill-plan-card .limits .lim .l {
  color: var(--text-3);
  font: 500 11px/1.2 var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.bill-plan-card .limits .lim .v {
  color: var(--text);
  font: 500 12px/1.2 var(--font-mono);
  text-align: right;
}
.bill-plan-card .limits .lim .v.is-custom {
  color: var(--accent);
  font-style: italic;
  font-family: var(--font-ui);
  text-transform: none;
  letter-spacing: 0;
}
.bill-plan-card .plan-cta {
  margin-top: auto;
  width: 100%;
  padding: 11px;
  border-radius: var(--radius-md);
  font: 500 13px/1 var(--font-ui);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
}
.bill-plan-card .plan-cta.is-primary {
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  border-color: var(--accent);
}
.bill-plan-card .plan-cta.is-primary:hover {
  background: var(--accent-3);
  border-color: var(--accent-3);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.bill-plan-card .plan-cta.is-outline {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border-2);
}
.bill-plan-card .plan-cta.is-outline:hover {
  background: var(--surface-2);
  border-color: var(--text-3);
}
.bill-plan-card .plan-cta.is-disabled {
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid rgba(61, 219, 194, 0.30);
  cursor: not-allowed;
  opacity: 1;
}
.bill-plan-card .plan-foot {
  margin-top: 10px;
  font: 400 10.5px/1.3 var(--font-ui);
  color: var(--muted-2);
  text-align: center;
}

/* Page footer — small print, links muted. */
.bill-footer {
  text-align: center;
  font: 400 11.5px/1.5 var(--font-ui);
  color: var(--muted-2);
  margin-top: 40px;
}
.bill-footer a { color: var(--text-3); }
.bill-footer a:hover { color: var(--text-2); }
.bill-footer .sep { margin: 0 8px; color: var(--muted-2); }

/* Mobile collapse — single column for plans, smaller card padding. */
@media (max-width: 700px) {
  .bill-card { padding: 22px 18px; }
  .bill-kv-row {
    grid-template-columns: 1fr;
    gap: 4px;
    padding: 12px 0;
  }
  .bill-plans-grid { grid-template-columns: 1fr; }
  .bill-plan-headline { gap: 10px; }
  .bill-plan-headline .name { font-size: 22px; }
}

/* ─── Dashboard page (port of preview/redesign/dashboard.jsx) ──────────
   Restyles dashboard.html. The legacy `.dash-hero-compact` variant
   stays intact — this overrides the default `.dash-hero` mode plus the
   project-card visual. Class names stay the same as the redesign so
   server-side or future componentization is a 1:1 rename.
   2026-05-12: Initial port. */

/* Hero — italic-serif <em> accent on the H1, 4-stat grid below subtitle.
   Top 8px nudges the title down so combined with .app-content's 28px top
   padding the H1 sits at ~36px from the topbar — matches the redesign
   reference (`.dash { padding: 36px ... }`). Bottom margin owns the gap
   to the toolbar (32px, matches redesign `.dash-hero { margin-bottom: 32px }`). */
.dash-hero {
  padding: 8px 0 0;
  margin-bottom: 32px;
  border-bottom: none;
  display: block;
}
.dash-hero h1,
.dash-hero .dash-hero-title {
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 0 0 8px;
  color: var(--text);
  text-align: left;
}
.dash-hero h1 em,
.dash-hero .dash-hero-title em {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--accent);
}
.dash-hero p,
.dash-hero .dash-hero-sub {
  color: var(--text-2);
  font-size: 14.5px;
  line-height: 1.5;
  margin: 0 0 12px;
  max-width: 720px;
}
.dash-hero .dash-hero-counters {
  font: 400 12.5px/1.5 var(--font-mono);
  color: var(--muted);
  margin: 0 0 24px;
  letter-spacing: 0;
}

/* 4-stat grid — replaces the legacy flex row. The compact variant below
   keeps the old single-row layout for any page that opts in. */
.dash-hero .dash-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin: 0;
  width: auto;
}
.dash-hero .dash-stat {
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
  min-width: 0;
}
.dash-hero .dash-stat .dash-stat-l {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 500;
  margin: 0 0 8px;
}
.dash-hero .dash-stat .dash-stat-n {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 500;
  letter-spacing: -0.025em;
  line-height: 1;
  display: flex;
  align-items: baseline;
  gap: 8px;
  color: var(--text);
}
/* Inline trend pill (set by updateStats() into stat-avg). */
.dash-hero .dash-stat .dash-stat-trend {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 3px 7px;
  border-radius: 5px;
  margin: 0;
}
.dash-hero .dash-stat .dash-stat-trend.is-down {
  color: var(--rose);
  background: var(--fail-bg);
}
.dash-hero .dash-stat .dash-stat-trend.is-flat {
  color: var(--text-3);
  background: var(--surface-2);
}
.dash-hero .dash-stat .dash-stat-sub {
  font-size: 12px;
  color: var(--muted);
  margin-top: 6px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}
/* Make the .dash-stat-actionable button look identical to the static
   .dash-stat container — it already sits inside the same grid cell. */
.dash-hero .dash-stat.dash-stat-actionable {
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--surface);
  font-family: inherit;
  text-align: left;
  padding: 20px;
}
.dash-hero .dash-stat.dash-stat-actionable:hover {
  border-color: var(--border-2);
  background: var(--surface-2);
}
.dash-hero .dash-stat.dash-stat-actionable:hover .dash-stat-n { color: var(--accent); }
.dash-hero .dash-stat.dash-stat-actionable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Toolbar — replaces the legacy .toolbar inside the dashboard wrapper.
   Top margin is 0 because .dash-hero owns the 32px gap below stats. */
.dash-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 18px;
  flex-wrap: wrap;
}
.dash-toolbar .search-mini {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  flex: 1;
  max-width: 340px;
  min-width: 200px;
  color: var(--muted);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.dash-toolbar .search-mini:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.dash-toolbar .search-mini svg {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--muted);
}
.dash-toolbar .search-mini input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  padding: 9px 0;
  font-size: 13px;
  color: var(--text);
  font-family: inherit;
  min-width: 0;
}
.dash-toolbar .search-mini input::placeholder { color: var(--muted); }

/* View toggle (cards / table) — pill group with two icon buttons.
   Lives in two places in dashboard.html: inside .dash-toolbar (rare) and
   inside .filter-chips (production placement). Both selectors get the
   same redesign treatment so the toggle never reverts to the legacy
   inline `.dash-view-btn` styling when the parent changes. */
.dash-toolbar .dash-view-toggle,
.filter-chips .dash-view-toggle {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 3px;
  gap: 0;
  margin-left: 0;
}
.dash-toolbar .dash-view-toggle .dash-view-btn,
.filter-chips .dash-view-toggle .dash-view-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  background: transparent;
  border: none;
  color: var(--muted);
  border-radius: 7px;
  font-size: 11.5px;
  font-weight: 500;
  font-family: inherit;
  line-height: 1;
  cursor: pointer;
  transition: color 0.12s, background 0.12s, box-shadow 0.12s;
  letter-spacing: 0;
  text-transform: none;
}
.dash-toolbar .dash-view-toggle .dash-view-btn:hover,
.filter-chips .dash-view-toggle .dash-view-btn:hover {
  color: var(--text);
  background: transparent;
  border-color: transparent;
}
.dash-toolbar .dash-view-toggle .dash-view-btn.active,
.filter-chips .dash-view-toggle .dash-view-btn.active {
  background: var(--bg-elev);
  color: var(--text);
  border: none;
  box-shadow: inset 0 0 0 1px var(--border-2);
}
.dash-toolbar .dash-view-toggle .dash-view-btn svg,
.filter-chips .dash-view-toggle .dash-view-btn svg {
  width: 11px;
  height: 11px;
}

/* Sort select — restyled native <select> as a pill matching the redesign. */
.dash-toolbar .sort-select,
.dash-toolbar select.toolbar-select {
  appearance: none;
  -webkit-appearance: none;
  padding: 8px 32px 8px 12px;
  background: var(--surface)
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%236E747F' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 6l4 4 4-4'/></svg>")
    no-repeat right 10px center;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13px;
  color: var(--text-2);
  cursor: pointer;
  font-family: inherit;
  line-height: 1.2;
  transition: border-color 0.12s, color 0.12s;
}
.dash-toolbar select.toolbar-select:hover { border-color: var(--border-2); color: var(--text); }
.dash-toolbar select.toolbar-select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Toolbar spacer pushes refresh + Add to the right. */
.dash-toolbar .dash-toolbar-spacer { flex: 1; min-width: 0; }

/* Buttons inside the toolbar inherit the .pc-btn classes already loaded
   on the legacy markup; this just makes sure the heights line up with
   the new search-mini and pill controls. */
.dash-toolbar .pc-btn {
  height: 36px;
  padding: 0 14px;
}
.dash-toolbar .pc-btn--primary {
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* Filter chips row — sits between toolbar and grid. Compact look. */
.filter-chips .dash-view-toggle { margin-left: auto; }

/* ─── Projects grid + project card ────────────────────────────────── */
.projects-grid,
.domains-grid.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 14px;
  margin-bottom: 40px;
  justify-content: start;
}
.project-card,
.domain-card.project-card {
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
  overflow: visible;
}
.project-card:hover,
.domain-card.project-card:hover {
  border-color: var(--border-2);
  background: var(--surface-2);
  box-shadow: 0 1px 2px rgba(0,0,0,.20);
}
.project-card:focus-within,
.domain-card.project-card:focus-within {
  border-color: var(--accent);
}
.project-card.monitored::after {
  content: '';
  position: absolute;
  top: 16px;
  right: 16px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
  pointer-events: none;
}

/* Top row: fav letter + domain name + kebab. */
.project-card .ph-top {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
}
.project-card .ph-top .pc-select {
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
  flex: 0 0 auto;
}
.project-card .ph-top .fav {
  width: 28px;
  height: 28px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 12px;
  color: white;
  background: var(--surface-2);
  flex: 0 0 auto;
  overflow: hidden;
}
.project-card .ph-top .fav img {
  width: 18px;
  height: 18px;
  object-fit: contain;
}
.project-card .ph-top .pc-name-btn {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  padding: 0;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  color: var(--text);
}
.project-card .ph-top .name {
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.005em;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 0.15s;
}
.project-card .ph-top .pc-name-btn:hover .name { color: var(--accent); }
.project-card .ph-top .pc-url {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.project-card .ph-top .kebab {
  margin-left: auto;
  flex: 0 0 auto;
  position: relative;
}

/* Score row — 4 mini chips per card. */
.project-card .scores {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin: 0;
}
.score-pill {
  padding: 8px 9px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.score-pill .lab {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--muted);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  font-weight: 500;
}
.score-pill .val {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1;
}
/* Score-pill values stay neutral; semantic context comes from the .lab. */
.score-pill .val { color: var(--text); }

/* Sparkline row — bordered top + bottom strip with trend pill. */
.project-card .spark-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  margin: 0;
}
.project-card .spark-row .spark-wrap {
  flex: 1;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: none;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.project-card .spark-row .sparkline {
  height: 28px;
}
.project-card .spark-row .sparkline svg { height: 28px; }
/* Hide the verbose 7d/30d/90d range chips inside the card — they
   make the card noisy. The detailed history view lives in the
   per-domain history modal already. The .spark-meta we DO want
   (the inline "47 snaps · hace 2h · +4 30d" strip) lives as a
   direct child of .project-card .spark-row so it's not matched by
   `.spark-wrap .spark-meta`. */
.project-card .spark-row .spark-wrap .spark-head,
.project-card .spark-row .spark-wrap .spark-meta { display: none; }

/* Inline meta on the right side of the sparkline row.
   Direct child of .spark-row, not inside .spark-wrap. */
.project-card > .spark-row > .spark-meta,
.project-card .spark-row > .spark-meta {
  font: 500 11px/1.4 var(--font-mono);
  color: var(--muted);
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: right;
  flex: 0 0 auto;
  min-width: 0;
}
.project-card .spark-row > .spark-meta .pc-trend {
  color: var(--accent);
  font-weight: 500;
}
.project-card .spark-row > .spark-meta .pc-trend.is-down { color: var(--rose); }
.project-card .spark-row > .spark-meta .pc-trend.is-flat { color: var(--text-3); }
.project-card .spark-row .spark-empty {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--muted);
  text-align: left;
  padding: 4px 0;
}

/* Card-meta strip (snaps · last · trend) — small mono row. Replaces the
   legacy .card-meta that lived in the grid. */
.project-card .pc-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin: 0;
}
.project-card .pc-meta .pc-trend { color: var(--accent); }
.project-card .pc-meta .pc-trend.is-down { color: var(--rose); }
.project-card .pc-meta .pc-trend.is-flat { color: var(--text-3); }

/* Action-row — three mini buttons that fill the bottom strip.
   Selector intentionally scoped under .project-card .pcb-actions so it
   beats the legacy .card-btn rule still living in dashboard.html's inline
   <style> (which has flat specificity 0,1,0). The standalone `.btn-mini`
   alias is kept for any future call site outside the dashboard. */
.project-card .pcb-actions {
  display: flex;
  gap: 6px;
  margin: 0;
  flex-wrap: wrap;
}
.project-card .pcb-actions .btn-mini,
.btn-mini {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  font-style: normal;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
  text-align: center;
}
.project-card .pcb-actions .btn-mini:hover,
.btn-mini:hover {
  border-color: var(--border-2);
  color: var(--text);
  background: var(--bg-elev);
}
.project-card .pcb-actions .btn-mini.primary,
.btn-mini.primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
  font-weight: 600;
}
.project-card .pcb-actions .btn-mini.primary:hover,
.btn-mini.primary:hover {
  background: var(--accent-3);
  color: var(--accent-ink);
  border-color: var(--accent-3);
}
.project-card .pcb-actions .btn-mini.kebab,
.btn-mini.kebab {
  flex: 0 0 36px;
  width: 36px;
  padding: 0;
}

/* Kebab menu — pop-over inside the card top row. */
.project-card .kebab-wrap { position: relative; }
.project-card .kebab-wrap .icon-btn {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.12s, background 0.12s, border-color 0.12s;
}
.project-card .kebab-wrap .icon-btn:hover {
  color: var(--text);
  background: var(--surface-2);
  border-color: var(--border);
}
.project-card .kebab-wrap .icon-btn svg {
  width: 14px;
  height: 14px;
}
.project-card .menu,
.dash-kebab-menu {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 6px;
  min-width: 220px;
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  padding: 6px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
  z-index: 30;
  display: flex;
  flex-direction: column;
}
.project-card .menu button,
.dash-kebab-menu .card-kebab-item,
.dash-kebab-menu button {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  font-size: 13px;
  font-family: inherit;
  color: var(--text-2);
  border-radius: 7px;
  text-align: left;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.project-card .menu button:hover,
.dash-kebab-menu .card-kebab-item:hover,
.dash-kebab-menu button:hover {
  background: var(--bg-elev);
  color: var(--text);
}
.project-card .menu button.danger,
.dash-kebab-menu .card-kebab-item-danger {
  color: var(--rose);
}
.project-card .menu button.danger:hover,
.dash-kebab-menu .card-kebab-item-danger:hover {
  background: var(--fail-bg);
  color: var(--rose);
}
.project-card .menu hr,
.dash-kebab-menu .card-kebab-sep {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 4px 0;
}

/* Inline expanded URLs panel inside the card — tone down. */
.project-card .card-urls {
  margin: 0;
  padding: 10px 12px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 11.5px;
}

/* ─── Responsive ─────────────────────────────────────────────────── */
@media (max-width: 1100px) {
  .dash-hero .dash-stats { grid-template-columns: repeat(2, 1fr); }
  .dash-hero h1,
  .dash-hero .dash-hero-title { font-size: 28px; }
}
@media (max-width: 720px) {
  .dash-hero { padding: 4px 0 22px; margin-bottom: 16px; }
  .dash-hero h1,
  .dash-hero .dash-hero-title { font-size: 24px; }
  .dash-hero .dash-stat { padding: 14px; }
  .dash-hero .dash-stat .dash-stat-n { font-size: 26px; }
  .dash-toolbar { gap: 8px; }
  .dash-toolbar .search-mini { max-width: none; flex-basis: 100%; order: -1; }
}

/* ─── Compact-mode override ────────────────────────────────────────
   When the .dash-hero also carries .dash-hero-compact, fall back to the
   single-row layout already defined locally in dashboard.html. The
   compact rules win because the local <style> block loads after this
   stylesheet — kept for documentation purposes. */
.dash-hero.dash-hero-compact { padding: 18px 0 14px; margin-bottom: 18px; }
.dash-hero.dash-hero-compact .dash-stats {
  display: flex;
  gap: 18px;
  margin-left: auto;
  width: auto;
}
.dash-hero.dash-hero-compact .dash-stat {
  padding: 0;
  background: transparent;
  border: none;
  min-width: 0;
}

/* ─── Dash stat sub-line (per-card description under the value).
   Ported 2026-05-12 to bring the hero stat cards to 1:1 with the
   redesign preview (preview/redesign/dashboard.jsx). */
.dash-hero .dash-stat .dash-stat-sub {
  font: 400 12px/1.4 var(--font-ui);
  color: var(--muted);
  margin-top: 6px;
  letter-spacing: 0;
  text-transform: none;
}

/* ─── API Status modal (port of preview/redesign/api-status.jsx) ──────
   Class-scoped under `.prisma-api-modal *` so the older inline-styled
   block in prisma-app.js is fully replaced. Names match the redesign
   so any future React port is a 1:1 rename. */
.prisma-api-modal.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  display: grid; place-items: center;
  z-index: 9999;
  padding: 24px;
  animation: prisma-modal-fadein 0.16s cubic-bezier(.16,.84,.44,1);
}
.prisma-api-modal.is-closing {
  animation: prisma-modal-fadeout 0.14s cubic-bezier(.4,0,1,1) forwards;
}
@keyframes prisma-modal-fadein {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes prisma-modal-fadeout {
  from { opacity: 1; }
  to   { opacity: 0; }
}
.prisma-api-modal .modal {
  width: 560px; max-width: 100%; max-height: 90vh;
  background: var(--surface);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: flex; flex-direction: column;
  animation: prisma-modal-slideup 0.18s cubic-bezier(.16,.84,.44,1);
  box-shadow: 0 24px 60px rgba(0,0,0,0.5);
}
.prisma-api-modal.is-closing .modal {
  animation: prisma-modal-slidedown 0.14s cubic-bezier(.4,0,1,1) forwards;
}
@keyframes prisma-modal-slideup {
  from { transform: translateY(8px) scale(.97); opacity: 0; }
  to   { transform: translateY(0)   scale(1);   opacity: 1; }
}
@keyframes prisma-modal-slidedown {
  from { transform: translateY(0)   scale(1);   opacity: 1; }
  to   { transform: translateY(4px) scale(.98); opacity: 0; }
}
.prisma-api-modal .modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 22px;
  border-bottom: 1px solid var(--border);
}
.prisma-api-modal .modal-head h3 {
  margin: 0; font: 500 17px/1.3 var(--font-display);
  letter-spacing: -0.005em; color: var(--text);
}
.prisma-api-modal .modal-head .close {
  width: 30px; height: 30px; display: grid; place-items: center;
  border-radius: var(--radius-sm); color: var(--muted);
  background: transparent; border: 1px solid transparent; cursor: pointer;
  font-family: inherit;
  transition: background-color .15s, color .15s, border-color .15s;
}
.prisma-api-modal .modal-head .close:hover {
  background: var(--surface-2); color: var(--text);
  border-color: var(--border-2);
}
.prisma-api-modal .modal-head .close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.prisma-api-modal .modal-body {
  overflow-y: auto;
  padding: 20px 22px 24px;
}
.prisma-api-modal .chips {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 6px 10px; margin-bottom: 24px;
}
.prisma-api-modal .chips .chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font: 500 11px/1 var(--font-mono);
  color: var(--text-2);
}
.prisma-api-modal .chips .chip.online {
  border-color: rgba(94, 211, 154, 0.30);
  color: var(--pass);
}
.prisma-api-modal .chips .chip .dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 6px currentColor;
}
.prisma-api-modal .chips .sep-text {
  color: var(--muted); font-size: 11.5px;
  font-family: var(--font-mono);
}
.prisma-api-modal .chips .sep-text .strong {
  color: var(--text); font-weight: 500;
}
.prisma-api-modal .modal-section { margin-bottom: 20px; }
.prisma-api-modal .modal-section .label {
  font: 600 10.5px/1 var(--font-mono);
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.prisma-api-modal .integrations {
  display: flex; flex-wrap: wrap; gap: 6px;
}
.prisma-api-modal .integ {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px;
  border-radius: var(--radius-pill);
  font: 500 11.5px/1 var(--font-ui);
  background: var(--bg-elev);
  border: 1px solid var(--border);
}
.prisma-api-modal .integ.ok {
  color: var(--pass);
  border-color: rgba(94, 211, 154, 0.30);
}
.prisma-api-modal .integ.fail {
  color: var(--fail);
  border-color: rgba(225, 106, 120, 0.30);
}
.prisma-api-modal .integ .glyph { font-weight: 700; }
.prisma-api-modal .code-block {
  padding: 12px 14px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: 400 12.5px/1 var(--font-mono);
  color: var(--accent);
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  word-break: break-all;
}
.prisma-api-modal .code-block .copy {
  color: var(--muted); font-size: 11px;
  display: inline-flex; align-items: center; gap: 4px;
  background: transparent; border: 1px solid transparent; cursor: pointer;
  font-family: var(--font-mono);
  flex: 0 0 auto;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  transition: color .15s, background-color .15s, border-color .15s;
}
.prisma-api-modal .code-block .copy:hover {
  color: var(--text); background: var(--surface-2); border-color: var(--border-2);
}
.prisma-api-modal .code-block .copy:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.prisma-api-modal .endpoints {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  max-height: 220px; overflow-y: auto;
}
.prisma-api-modal .endpoint-row {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 14px; padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 12px; align-items: center;
  transition: background-color .12s;
}
.prisma-api-modal .endpoint-row:last-child { border-bottom: none; }
.prisma-api-modal .endpoint-row:hover { background: var(--bg-elev); }
.prisma-api-modal .endpoint-row .path {
  font: 500 11.5px/1 var(--font-mono);
  color: var(--accent);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.prisma-api-modal .endpoint-row .desc {
  color: var(--muted); font-size: 11.5px;
}

/* =====================================================================
   ▼  UI/UX REFINEMENT SWEEP — 2026-05-15  (CSS-only, no markup edits)
   Three audits consolidated:
     • cross-page-refinement.md   (lowest specificity, runs first)
     • sidebar-refinement.md      (.tabs-side rail only)
     • main-content-refinement.md (analyzer right-of-sidebar only)
   Uses existing tokens only. Source-order wins where it competes;
   !important is used only against inline style="..." attributes that
   are rendered by JS at runtime (dashboard exec-panel, NEW pills,
   #btnNicheDiscover) or against per-page inline <style> blocks.
   ===================================================================== */

/* ── 1. CROSS-PAGE ──────────────────────────────────────────────── */

/* WHY 1.1 — kill the saturated inline tints on dashboard exec tiles.
   The status colour stays on the small label below; the tile itself
   reads as a calm financial-terminal card, not an alarm dashboard. */
#exec-panel > div > div[style*="background:rgba"],
#exec-panel > div > div[style*="background:var(--surface-2)"] {
  background: var(--surface) !important;
  border: 1px solid var(--border) !important;
  box-shadow: none !important;
}
/* Neutralise the big score number (was painted in --fail / --warn / --pass
   inline). The status label + sub-label below carry the colour. */
#exec-panel > div > div > div[style*="font-size:28px"] {
  color: var(--text) !important;
}
/* The small status label gets a subtle mono-caps treatment — same
   colour family as inline but shrunk so it reads as metadata. */
#exec-panel > div > div > div[style*="font-size:11px"][style*="font-weight:600"][style*="margin-top:2px"] {
  font: 600 10px/1 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.85;
}

/* WHY 1.2 — calm the auth focus halo. 4px teal-soft ring + surface-3
   bg swap read as a heavy AI-dashboard glow. 2px ring, no bg swap. */
:where(.pc-field input, .pc-field select, .pc-field textarea, .pc-field__input):focus,
:where(.field input, .card input[type="email"], .card input[type="password"], .card input[type="text"]):focus {
  background: var(--surface-2) !important;
  box-shadow: 0 0 0 2px var(--accent-soft) !important;
  border-color: var(--accent) !important;
}

/* WHY 1.3 — neutralise the gradient on legacy auth submit buttons so
   they match .btn-primary (flat teal, no glow, no gradient). */
.card > form button[type="submit"],
.card button[type="submit"],
form#form button[type="submit"] {
  background: var(--accent) !important;
  background-image: none !important;
  color: var(--accent-ink) !important;
  filter: none !important;
  border: 1px solid var(--accent) !important;
  border-radius: var(--radius-md) !important;
  box-shadow: none !important;
  font-weight: 600 !important;
  transition: background-color .15s, box-shadow .15s, transform .08s !important;
}
.card > form button[type="submit"]:hover,
.card button[type="submit"]:hover,
form#form button[type="submit"]:hover {
  background: var(--accent-3) !important;
  border-color: var(--accent-3) !important;
  box-shadow: 0 0 0 2px var(--accent-soft) !important;
  filter: none !important;
}

/* WHY 1.4 — unify card primitives on one radius + one hover step. */
:where(.pc-card, .bill-card, .domain-card, .portfolio-health, .ph-tile, .pc-callout) {
  border-radius: var(--radius-lg);
}
:where(.pc-card, .bill-card, .domain-card, .portfolio-health):hover {
  border-color: var(--border-2);
  box-shadow: var(--shadow-md);
}

/* WHY 1.5 — calmer "active" state for filter/view-toggle chips. Solid
   teal is reserved for primary CTAs; toggles get teal-on-soft. */
.fchip.active,
.dash-view-btn.active {
  background: var(--accent-soft) !important;
  color: var(--accent) !important;
  border-color: rgba(61,219,194,.30) !important;
}
.fchip.active .fchip-count {
  background: rgba(61,219,194,.18) !important;
  color: var(--accent) !important;
}

/* WHY 1.6 — canonical .hero h1 so analyzer + pricing + future landings
   share one rule. Inline blocks in analyzer.html / pricing.html become
   dead code (safe to delete later — out of scope for this CSS pass). */
.hero {
  text-align: center;
  padding: 64px 24px 32px;
}
.hero h1 {
  font: 500 clamp(34px, 5.4vw, 56px)/1.05 var(--font-display);
  letter-spacing: -0.022em;
  color: var(--text);
  margin: 0 0 14px;
  max-width: 18ch;
  margin-inline: auto;
}
.hero h1 em,
.hero h1 span,
.hero h1 .serif {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--text);   /* editorial accent stays neutral, not teal */
}
.hero p,
.hero .sub,
.hero-sub {
  color: var(--text-2);
  font-size: 14.5px;
  line-height: 1.55;
  max-width: 56ch;
  margin: 0 auto 22px;
}

/* WHY 1.7 — prevent doubled hairlines when topbar + subnav stack. */
.pc-topbar:has(+ .pc-subnav) { border-bottom: none; }

/* WHY 1.8 — auth-page wordmark consistency: signup.html .brand /
   .card-brand match the Instrument Serif italic of .pc-topbar__brand. */
.brand,
.card-brand {
  font-family: var(--font-serif) !important;
  font-style: italic !important;
  font-weight: 400 !important;
  font-size: 22px !important;
  letter-spacing: -0.025em !important;
  color: var(--text) !important;
}

/* WHY 1.9 — auth pages: keep the background gradient from doubling
   when the page uses a centred .card[role="main"] grid layout. */
body:has(> .card[role="main"]) { background-attachment: scroll; }


/* ── 2. ANALYZER SIDEBAR (.tabs-side) ────────────────────────────── */

/* WHY 2.1 — group labels read as one family; teal stays for active item. */
.tabs-side .tabs-group.headline .tabs-group-head,
.tabs-bar.tabs-side .tabs-group.headline .tabs-group-head { color: var(--text-3); }

/* WHY 2.2 — consistent group-head density and tone. */
.tabs-side .tabs-group-head,
.tabs-bar.tabs-side .tabs-group-head { padding: 2px 10px 6px; color: var(--text-3); opacity: 1; }
.tabs-bar.tabs-side .tabs-group:first-child .tabs-group-head { padding-top: 0; }
.tabs-side .tabs-group.demoted .tabs-group-head,
.tabs-bar.tabs-side .tabs-group.demoted .tabs-group-head { opacity: 1; color: var(--text-3); }

/* WHY 2.3 — badges step back; group label leads. */
.tabs-side .tabs-group-head .badge,
.tabs-bar.tabs-side .tabs-group-head .badge {
  color: var(--text-3);
  border-color: var(--border);
  background: var(--surface);
}

/* WHY 2.4 — tighter group rhythm inside the 290px rail. */
.tabs-side .tabs-group,
.tabs-bar.tabs-side .tabs-group { margin-bottom: 12px; }
.tabs-side,
/* Small padding-top for a visible breathing room under the topbar without
   the ~70px dead zone we had originally. Bottom padding stays generous so
   the last item isn't flush against the viewport bottom when the rail
   scrolls. */
.tabs-bar.tabs-side { gap: 2px; padding: 16px 12px 80px; }

/* WHY 2.5 — consistent hit-target regardless of icon presence (≥32px). */
.tabs-side .tab-row,
.tabs-bar.tabs-side .tab-row,
.tabs-bar.tabs-side .tab-btn {
  min-height: 32px;
  padding: 7px 10px;
  gap: 10px;
  border-radius: 6px;
  font-weight: 500;
}

/* WHY 2.6 — unify icon chip: same 20px square, same surface, same border. */
.tabs-side .tab-row .glyph,
.tabs-bar.tabs-side .tab-row .glyph,
.tabs-bar.tabs-side .tab-btn .glyph,
.tabs-side .tab-row > svg.ico:first-child,
.tabs-side .tab-row > svg:first-child,
.tabs-bar.tabs-side .tab-row > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn > svg.ico:first-child,
.tabs-side .tab-row > .tag-ai:first-child,
.tabs-side .tab-row > .vs-text:first-child,
.tabs-bar.tabs-side .tab-row > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-row > .vs-text:first-child,
.tabs-bar.tabs-side .tab-btn > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-btn > .vs-text:first-child {
  width: 20px;
  height: 20px;
  border-radius: 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-3);
  flex-shrink: 0;
  padding: 0;
}

/* WHY 2.7 — hide the dot-only icons (width=6) so the chip is not "a chip
   with a tiny dot"; the chip itself stays as a consistent leading marker. */
.tabs-side .tab-row > svg.ico[width="6"]:first-child > *,
.tabs-bar.tabs-side .tab-row > svg.ico[width="6"]:first-child > *,
.tabs-bar.tabs-side .tab-btn > svg.ico[width="6"]:first-child > * { display: none; }

/* WHY 2.8 — draw the stroked SVGs at a readable size inside the chip. */
.tab-row .glyph .ico,
.tab-row .glyph svg,
.tabs-side .tab-row > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn > svg.ico:first-child { padding: 3px; box-sizing: border-box; }

/* WHY 2.9 — .tag-ai / .vs-text inside the rail read as quiet markers,
   not saturated chips that repeat the brand colour 5 times in a group. */
.tabs-side .tab-row > .tag-ai:first-child,
.tabs-side .tab-row > .vs-text:first-child,
.tabs-bar.tabs-side .tab-row > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-row > .vs-text:first-child,
.tabs-bar.tabs-side .tab-btn > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-btn > .vs-text:first-child {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text-2);
  font: 600 8px/1 var(--font-mono);
  letter-spacing: 0.04em;
}

/* WHY 2.10 — drop the font-weight jump on .is-headline so the rail
   reads as one voice; accent reserved for the active item. */
.tabs-side .tab-row.is-headline,
.tabs-side .tab-row.headline,
.tabs-bar.tabs-side .tab-row.is-headline,
.tabs-bar.tabs-side .tab-btn.is-headline { color: var(--text-2); font-weight: 500; }
.tabs-side .tab-row.is-headline.lead,
.tabs-bar.tabs-side .tab-row.is-headline.lead { font-weight: 500; }
.tabs-side .tab-row.is-headline .glyph,
.tabs-side .tab-row.headline .glyph,
.tabs-bar.tabs-side .tab-row.is-headline .glyph,
.tabs-bar.tabs-side .tab-btn.is-headline .glyph,
.tabs-side .tab-row.is-headline > svg.ico:first-child,
.tabs-side .tab-row.headline > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row.is-headline > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.is-headline > svg.ico:first-child {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text-3);
  box-shadow: none;
}

/* WHY 2.11 — stronger but restrained active state. */
.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-btn.active {
  background: var(--surface-2);
  color: var(--text);
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--accent);
}
.tabs-side .tab-row.active .glyph,
.tabs-side .tab-row.active > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row.active .glyph,
.tabs-bar.tabs-side .tab-row.active > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.active > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.active .glyph,
.tabs-side .tab-row.active > .tag-ai:first-child,
.tabs-side .tab-row.active > .vs-text:first-child,
.tabs-bar.tabs-side .tab-row.active > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-row.active > .vs-text:first-child {
  background: var(--accent-soft);
  border-color: rgba(61, 219, 194, 0.25);
  color: var(--accent);
}

/* WHY 2.12 — restrained hover that doesn't ape the active surface. */
.tabs-side .tab-row:hover,
.tabs-bar.tabs-side .tab-row:hover,
.tabs-bar.tabs-side .tab-btn:hover {
  background: var(--surface-hover);
  color: var(--text);
  transition: background 120ms ease, color 120ms ease;
}

/* WHY 2.13 — focus ring uses the canonical accent token + offset. */
.tabs-side .tab-row:focus-visible,
.tabs-bar.tabs-side .tab-row:focus-visible,
.tabs-bar.tabs-side .tab-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* WHY 2.14 — NEW pill cooled so it doesn't fight the active rail. */
.tabs-side .tab-row .new,
.tabs-bar.tabs-side .tab-row .new,
.tabs-bar.tabs-side .tab-btn .new {
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid rgba(61, 219, 194, 0.25);
  font: 600 8.5px/1 var(--font-mono);
  letter-spacing: 0.06em;
  padding: 2px 6px;
  border-radius: 999px;
}

/* WHY 2.15 — demoted items get a calmer chip that matches the rest. */
.tabs-side .tab-row.is-demoted .glyph,
.tabs-side .tab-row.is-demoted > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row.is-demoted .glyph,
.tabs-bar.tabs-side .tab-row.is-demoted > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.is-demoted .glyph,
.tabs-bar.tabs-side .tab-btn.is-demoted > svg.ico:first-child {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text-3);
}
.tabs-side .tab-row.is-demoted,
.tabs-bar.tabs-side .tab-row.is-demoted,
.tabs-bar.tabs-side .tab-btn.is-demoted { color: var(--text-2); }


/* ── 3. ANALYZER MAIN CONTENT (right of sidebar) ─────────────────── */

/* WHY 3.1 — drop the teal-tinted .pos-intro cards. Two stacked
   teal cards + teal CTAs = brand-colour repeated 6x in one viewport. */
.pos-intro {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 22px 24px;
  margin-bottom: 20px;
  transition: border-color .15s;
}
.pos-intro:hover { border-color: var(--border-2); }

/* WHY 3.2 — calm the leading icon chip (40 → 32px, surface-2 fill).
   2026-05-19: add display:grid + place-items:center so the inner SVG
   centers inside the chip (matched .gen-intro-icon behaviour). */
.pos-intro-icon {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  color: var(--accent);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

/* WHY 3.3 — typography now carries the section hierarchy. */
.pos-intro-text h3 {
  font: 500 17px/1.25 var(--font-display);
  letter-spacing: -0.015em;
  color: var(--text);
  margin: 0 0 4px;
}
.pos-intro-text p {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-2);
  margin: 0;
  max-width: 64ch;
}

/* WHY 3.4 — Niche Discovery NEW pill aligned to the canonical NEW chip. */
.pos-intro-text h3 > span[data-i18n="niche.new"] {
  background: var(--accent-soft) !important;
  color: var(--accent) !important;
  border: 1px solid rgba(61,219,194,.25);
  font: 600 9.5px/1 var(--font-mono) !important;
  letter-spacing: 0.08em;
  padding: 3px 7px !important;
  border-radius: var(--radius-pill) !important;
  text-transform: uppercase;
  margin-left: 8px;
  vertical-align: middle;
}

/* WHY 3.5 — Niche Discovery CTA forced back to the teal primary voice. */
#btnNicheDiscover {
  background: var(--accent) !important;
  color: var(--accent-ink) !important;
  border: 1px solid var(--accent);
}
#btnNicheDiscover:hover {
  background: var(--accent-3) !important;
  border-color: var(--accent-3) !important;
}

/* WHY 3.6 — results-bar: clear left→right info hierarchy with hairline
   dividers between info groups; drop the mode-chip teal-glow label. */
.results-bar { padding: 10px 24px; gap: 12px; }
.results-bar-domain { gap: 8px; padding-right: 12px; border-right: 1px solid var(--border); }
.results-bar .mode-chip {
  background: transparent;
  border: 1px solid var(--border);
  padding: 4px 10px 4px 6px;
  gap: 6px;
}
.results-bar .mode-chip-label {
  background: var(--surface-2);
  color: var(--text-2);
  border: 1px solid var(--border);
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.08em;
  padding: 3px 7px;
}
.results-bar-meta { padding-left: 12px; border-left: 1px solid var(--border); }
.results-bar-actions { gap: 6px; }

/* WHY 3.7 — results-bar favicon is a neutral domain marker, not a status. */
.results-bar-fav {
  background: var(--surface-2);
  color: var(--text-3);
  border: 1px solid var(--border);
  width: 24px;
  height: 24px;
  border-radius: 6px;
}

/* WHY 3.8 — score-pill empty state reads as "pending", not "broken". */
.score-pill .score-pill-n:empty { color: var(--text-4); }
.score-pill-strip .score-pill {
  background: transparent;
  border: 1px solid var(--border);
}
.score-pill-strip .score-pill:hover { background: var(--surface-2); border-color: var(--border-2); }

/* WHY 3.9 — score-section--hero: drop the corner radial-gradient in
   the empty/initial state so the eye doesn't read it as "live data". */
.score-section.score-section--hero::before { display: none; }
.score-section.score-section--hero {
  border: 1px solid var(--border);
  box-shadow: none;
  background: var(--surface);
}
.score-section.score-section--hero:hover { border-color: var(--border-2); }

/* WHY 3.10 — Priority Table heading promoted to display scale with
   hairline beneath so it reads as a major section break. */
.analysis-content > section > .section-title {
  font: 500 18px/1.25 var(--font-display);
  letter-spacing: -0.015em;
  color: var(--text);
  margin: 0 0 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.analysis-content > section > .section-title svg {
  color: var(--text-3);
  width: 14px;
  height: 14px;
}

/* WHY 3.11 — priority-table chrome: hairline only, neutral surface. */
.priority-table-wrap {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.priority-table thead th {
  background: var(--surface);
  color: var(--text-3);
  font: 600 10px/1.2 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  padding: 10px 14px;
}
.priority-table tbody tr:nth-child(even) td { background: transparent; }
.priority-table tbody tr:hover td { background: var(--surface-2); }
.priority-table td { border-top: 1px solid var(--border); padding: 12px 14px; }

/* WHY 3.12 — consistent vertical rhythm (24-28px) between blocks. */
.analysis-content > section,
.analysis-content > .pos-intro,
.analysis-content > .severity-rollup,
.analysis-content > .score-evolution-card,
.analysis-content > .pc-card { margin-bottom: 24px; }
.analysis-content > .divider {
  margin: 28px 0;
  border: 0;
  border-top: 1px solid var(--border);
  height: 0;
}

/* WHY 3.13 — residual "live-data" tells replaced with a single 2px
   top-accent hairline (matches the .alert-banner / .pc-callout pattern). */
.gsw.is-active {
  background: var(--surface);
  border-color: var(--accent);
  box-shadow: none;
}
.gbp-table tbody tr.highlight {
  background: var(--surface-2);
  box-shadow: none;
}
.pos-progress-bar { background: var(--accent); }


/* =====================================================================
   ▼  UI/UX REFINEMENT SWEEP — ROUND 2 (2026-05-15)
   Two more audits consolidated:
     • deep-tabs-refinement.md   (residual deep-tab + modal patterns)
     • responsive-refinement.md  (1024px tablet + 768px floor)
   Continues the section numbering of round 1 (which ended at section 3).
   ===================================================================== */

/* ── 4. DEEP TABS + MODALS ───────────────────────────────────────── */

/* WHY 4.1 — AI Search sub-tab nav needs a container hairline so the
   2px active underline reads as a contained nav strip, not a floating
   stroke. Matches .pc-topbar__sec rhythm + spacing. */
.ais-subtab-nav,
[role="tablist"]:has(> .ais-subtab) {
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
  padding: 0 0 0 2px;
  gap: 4px;
}
.ais-subtab {
  padding: 10px 12px;
  font: 500 12.5px/1 var(--font-ui);
  letter-spacing: -0.005em;
  color: var(--text-3);
  border-bottom-width: 2px;
}
.ais-subtab:hover { color: var(--text-2); }
.ais-subtab.active,
.ais-subtab[aria-selected="true"] {
  color: var(--text);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

/* WHY 4.2 — calm the empty-state containers so "Aún no has ejecutado
   este análisis…" reads as a deliberate empty state, not a faint
   placeholder. Same rhythm across .ais-stub / .empty-stub / .hist-empty. */
.ais-stub,
.empty-stub,
.mw-empty,
.hist-empty {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 32px 24px;
  text-align: center;
  color: var(--text-2);
  font-size: 13px;
  line-height: 1.55;
  max-width: 560px;
  margin: 0 auto;
}
.ais-stub strong { font: 500 17px/1.3 var(--font-display); letter-spacing: -0.015em; color: var(--text); }
.ais-stub p     { color: var(--text-2); font-size: 13px; line-height: 1.55; margin: 4px 0 0; }
.ais-stub em    { font-style: normal; color: var(--text-3); }

/* WHY 4.3 — kill the teal-glow on .ai-panel-intro, .hist-diff and the
   two inline B14/promo CTAs at analyzer.html:9341 + :13845. Same
   neutralisation the round-1 .pos-intro patch used. */
.ai-panel-intro,
.hist-diff {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px 24px;
}
.ai-panel-intro h3,
.hist-diff .hist-diff-title { font: 500 16px/1.3 var(--font-display); letter-spacing: -0.015em; color: var(--text); }
.ai-panel-intro p { color: var(--text-2); font-size: 13px; line-height: 1.5; }
div[style*="background:var(--accent-glow);border:1px solid var(--accent)"] {
  background: var(--surface) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius-lg) !important;
}

/* WHY 4.4 — modal icon chips: tokenise --accent + --accent-ink instead
   of hard-coded #fff. Downgrade size + use the canonical accent-ink. */
.ai-modal-ico,
.ai-full-ico,
.gen-intro-icon {
  background: var(--accent);
  color: var(--accent-ink);
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
}

/* WHY 4.5 — drop the ::before square + glow on .pc-modal-hdr — every
   modal header had a glowing 12px square fighting the title text. */
.pc-modal-hdr::before { display: none; }

/* WHY 4.6 — .gen-card-head: drop the bottom hairline when the card has
   no result so the empty card doesn't read as two stacked panels. */
.gen-card .gen-card-head { border-bottom-color: transparent; }
.gen-card:has(.gen-card-result.active) .gen-card-head { border-bottom-color: var(--border); }

/* WHY 4.7 — .ask-ai-btn switched to outline-ghost so it doesn't paint a
   column of teal pills next to every priority-table row. */
.ask-ai-btn {
  background: transparent;
  color: var(--text-2);
  border: 1px solid var(--border);
  font: 600 11px/1 var(--font-mono);
  letter-spacing: 0.04em;
  padding: 5px 9px;
  border-radius: 6px;
  text-transform: uppercase;
  transition: color .12s, border-color .12s, background .12s;
}
.ask-ai-btn:hover {
  background: var(--accent-soft);
  border-color: rgba(61,219,194,.30);
  color: var(--accent);
}

/* WHY 4.8 — action-plan: real secondary voice for inline-overridden
   "Importar/Refrescar tracker" pseudo-secondary buttons. */
button.pc-btn--primary[style*="background:var(--surface-2)"],
button.pc-btn--primary[style*="background: var(--surface-2)"] {
  background: transparent !important;
  color: var(--text-2) !important;
  border: 1px solid var(--border) !important;
  font-weight: 500 !important;
}
button.pc-btn--primary[style*="background:var(--surface-2)"]:hover,
button.pc-btn--primary[style*="background: var(--surface-2)"]:hover {
  background: var(--surface-2) !important;
  color: var(--text) !important;
  border-color: var(--border-2) !important;
}

/* WHY 4.9 — audit-summary KPI tiles (.severity-rollup .sr-cell): fix
   the inverted hover (--surface-2 → --surface darkens cell in dark mode),
   neutralise the empty state so 4 zero-tiles don't paint as chromatic. */
.severity-rollup .sr-cell {
  background: var(--surface);
  border: 1px solid var(--border);
}
.severity-rollup .sr-cell:hover {
  background: var(--surface-2);
  border-color: var(--border-2);
}
.severity-rollup .sr-cell .sr-cell-n { color: var(--text); }
.severity-rollup .sr-cell:has(.sr-cell-n:empty) .sr-cell-n,
.severity-rollup .sr-cell .sr-cell-n:where(:empty) { color: var(--text-3); }

/* WHY 4.10 — .hist-table chrome aligned to round-1 .priority-table so
   the two tables read as one primitive across tabs. */
.hist-table-wrap {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.hist-table thead th,
.hist-table th {
  background: var(--surface);
  color: var(--text-3);
  font: 600 10px/1.2 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  padding: 10px 14px;
}
.hist-table td { border-top: 1px solid var(--border); padding: 12px 14px; }
.hist-table tr:hover td { background: var(--surface-2); }

/* WHY 4.11 — .mp-section headings promoted to the canonical section
   title scale (matches round-1 .analysis-content > section >
   .section-title at 18/500 with hairline beneath). */
.mp-section { padding: 20px 22px; }
.mp-section h3 {
  font: 500 16px/1.3 var(--font-display);
  letter-spacing: -0.015em;
  color: var(--text);
  margin: 0 0 6px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.mp-section h3 svg.ico { color: var(--text-3); width: 14px; height: 14px; }
.mp-section p { font-size: 13px; color: var(--text-2); line-height: 1.5; margin: 0 0 14px; }

/* 2026-05-20: WHY 4.12 reverted — the strip is now a transparent
   pass-through that hosts 5 floating glass pills. No band, no border,
   no background. The pills carry their own glass treatment. */
.score-pill-strip {
  background: transparent;
  border: none;
}

/* WHY 4.13 — .gsw.is-active leftover gradient still painted a horizontal
   accent fade after round 1. Final neutralisation of the background-image. */
.gsw.is-active {
  background-image: none !important;
}
.gsw.is-active .gsw-icon {
  background: var(--surface-2);
  border-color: var(--border-2);
  color: var(--accent);
}

/* WHY 4.14 — .mode-chip-label outside .results-bar (modals, etc.) keeps
   the canonical mono pill voice. */
.mode-chip-label {
  background: var(--surface-2);
  color: var(--text-2);
  border: 1px solid var(--border);
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.08em;
  padding: 3px 7px;
}


/* ── 5. RESPONSIVE — 1024px tablet refinements ───────────────────── */

@media (max-width: 1024px) {
  /* WHY 5.1 — SWEEP 2.11 inset left-rail is desktop-only. At 1024px the
     sidebar flips to a horizontal strip; revert active marker to the
     bottom-border underline the existing tablet block defines. */
  .analysis-shell > .tabs-side .tab-row.active,
  .analysis-shell > .tabs-bar.tabs-side .tab-row.active,
  .analysis-shell > .tabs-bar.tabs-side .tab-btn.active {
    box-shadow: none;
    background: none;
    border-bottom: 2px solid var(--accent);
    color: var(--text);
  }
  .analysis-shell > .tabs-side .tab-row.active .glyph,
  .analysis-shell > .tabs-side .tab-row.active > svg.ico:first-child,
  .analysis-shell > .tabs-bar.tabs-side .tab-row.active .glyph,
  .analysis-shell > .tabs-bar.tabs-side .tab-btn.active .glyph {
    background: transparent;
    border: none;
    color: var(--accent);
  }

  /* WHY 5.2 — pricing 4-card row → clean 2×2 wrap. */
  #plans.grid,
  .plans-grid,
  .pricing-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
  }

  /* WHY 5.3 — exec-panel 5-tile row → 3+2 wrap so numbers don't break
     to two lines and the PAGESPEED label stops truncating. */
  #exec-panel > div {
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    gap: 10px !important;
  }
  #exec-panel > div > div {
    padding: 12px 14px !important;
  }

  /* WHY 5.4 — hero clamp ceiling lowered so tablet doesn't render
     near-desktop scale and crowd the sub-headline. */
  .hero h1 {
    font-size: clamp(30px, 4.6vw, 42px);
  }
  .hero { padding: 48px 24px 28px; }
  .hero p,
  .hero .sub,
  .hero-sub { font-size: 14px; max-width: 52ch; }

  /* WHY 5.5 — cap auth card width so CTAs don't become banner-wide. */
  body:has(> .card[role="main"]) > .card[role="main"] {
    max-width: 480px;
    margin-inline: auto;
  }

  /* WHY 5.6 — topbar density: tighten section padding + add a gutter
     before the right cluster so icons don't touch the last nav item. */
  .pc-topbar__sec { padding: 0 9px; }
  .pc-topbar__right {
    margin-left: 4px;
    padding-left: 8px;
    border-left: 1px solid var(--border);
  }

  /* WHY 5.7 — dashboard KPI grid: 4 across at 1024px is too tight;
     drop to 2×2 so trend pill + sub-label get room. */
  .dash-hero .dash-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
  }
  .dash-hero .dash-stat { padding: 18px; }
  .dash-hero .dash-stat .dash-stat-n { font-size: 30px; }

  /* WHY 5.8 — analyzer content padding tightens with viewport so the
     priority-table and result cards don't feel pinned to a thin column. */
  .analysis-shell > .analysis-content { padding: 22px 20px 80px; }
  .results-bar { padding: 8px 20px; gap: 10px; }
  .pos-intro { padding: 18px 20px; }
}


/* ── 6. RESPONSIVE — 768px narrow-tablet / phablet floor ─────────── */

@media (max-width: 768px) {
  /* WHY 6.1 — pricing + exec-panel + dashboard KPI all collapse to single
     column; no justification for two narrow tiles below this width. */
  #plans.grid,
  .plans-grid,
  .pricing-grid,
  .dash-hero .dash-stats {
    grid-template-columns: 1fr;
  }
  #exec-panel > div {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }

  /* WHY 6.2 — hero floor for phones: readable but doesn't dominate. */
  .hero h1 { font-size: clamp(26px, 6.5vw, 34px); }
  .hero { padding: 36px 20px 24px; }

  /* WHY 6.3 — topbar nav becomes icon-only on phones (existing markup
     already has SVG icons next to the label spans). */
  .pc-topbar__sec { padding: 0 8px; font-size: 0; gap: 0; }
  .pc-topbar__sec svg { opacity: 1; width: 16px; height: 16px; }
  .pc-topbar__sec.is-active svg { color: var(--accent); }

  /* WHY 6.4 — auth card flush to the viewport with a small inset. */
  body:has(> .card[role="main"]) > .card[role="main"] {
    max-width: none;
    margin: 16px;
  }
}


/* ── 7. ADMIN / TERMINAL VARIANT ─────────────────────────────────────
   Refinements that fire only under [data-variant="terminal"] (admin
   surfaces) — never bleed into the dark product surface. Tokens come
   from the [data-theme="light"][data-variant="terminal"] block in
   prisma-tokens.css (cream paper, deep-pine accent, IBM Plex pair). */

/* WHY 7.1 — gate-screen + modal danger buttons: drop solid-red on
   cream paper; outline-danger reads as restraint, tints on hover. */
[data-variant="terminal"] :where(
  .gate button[style*="var(--err)"],
  button.refresh[style*="background:var(--err)"],
  button.refresh[style*="background: var(--err)"]
) {
  background: transparent !important;
  color: var(--fail) !important;
  border: 1px solid var(--fail) !important;
  box-shadow: none !important;
}
[data-variant="terminal"] :where(
  .gate button[style*="var(--err)"],
  button.refresh[style*="background:var(--err)"],
  button.refresh[style*="background: var(--err)"]
):hover {
  background: rgba(154,27,27,.06) !important;
  color: var(--fail) !important;
}

/* WHY 7.2 — reinstate --shadow-sm on JS-painted exec tiles after
   SWEEP §1.1 stripped all box-shadow. Cream paper needs the lift. */
[data-variant="terminal"] #exec-panel > div > div[style*="background:rgba"] {
  box-shadow: var(--shadow-sm) !important;
}

/* WHY 7.3 — modal "+" icon chips: cream-tone fill, accent text. The
   deep-pine block was too heavy next to a serif modal title. */
[data-variant="terminal"] :where(
  div[style*="background:var(--accent)"][style*="border-radius:8px"],
  div[style*="background: var(--accent)"][style*="border-radius:8px"]
) {
  background: var(--surface-2) !important;
  color: var(--accent) !important;
  border: 1px solid var(--border) !important;
}

/* WHY 7.4 — admin-usage avatars: dark near-black circles read as
   stencils on cream. Soft-accent fill + accent text matches restraint. */
[data-variant="terminal"] .avatar,
[data-variant="terminal"] .avatar-lg {
  background: var(--accent-soft);
  color: var(--accent);
}

/* WHY 7.5 — admin-usage role-badge + event-icon tints: dark-surface
   rgba palette remapped to cream-variant pass/warn/fail/info pastels. */
[data-variant="terminal"] .role-admin     { background:#fdf0f0; color:#8a1e1e; }
[data-variant="terminal"] .role-agency    { background:#eef3f9; color:#174a7c; }
[data-variant="terminal"] .role-developer { background:#fcf3dc; color:#7a5800; }
[data-variant="terminal"] .role-client    { background:#eef7f4; color:#146049; }
[data-variant="terminal"] .ev-api    { background:#eef3f9; color:#174a7c; }
[data-variant="terminal"] .ev-click  { background: var(--accent-soft); color: var(--accent); }
[data-variant="terminal"] .ev-input  { background:#fcf3dc; color:#7a5800; }
[data-variant="terminal"] .ev-change { background:#eef7f4; color:#146049; }

/* WHY 7.6 — admin-feature-audit references --pass-bg/--warn-bg/
   --fail-bg/--info-bg which don't exist; terminal-only aliases so
   the status chips actually paint a backdrop. */
[data-variant="terminal"] .status.pass    { background:#eef7f4; }
[data-variant="terminal"] .status.warning { background:#fcf3dc; }
[data-variant="terminal"] .status.fail,
[data-variant="terminal"] .status.error,
[data-variant="terminal"] .status.timeout { background:#fdf0f0; }
[data-variant="terminal"] .status.pending,
[data-variant="terminal"] .status.running { background:#eef3f9; color:#174a7c; }

/* WHY 7.7 — header .pill ("super-owner"): demote from solid-accent
   block to accent-soft so the wordmark .mark leads. */
[data-variant="terminal"] header .pill {
  background: var(--accent-soft);
  color: var(--accent);
}

/* WHY 7.8 — sys-strip warn/err chips: cream-toned solids at low
   alpha instead of dark-surface rgba glass. */
[data-variant="terminal"] .sys-chip.is-warn {
  background:#fcf3dc; color:#7a5800; border-color:#ead7a4;
}
[data-variant="terminal"] .sys-chip.is-err {
  background:#fdf0f0; color:#8a1e1e; border-color:#f2d4d4;
}
[data-variant="terminal"] .user-flag.is-err   { background:#fdf0f0; color:#8a1e1e; border-color:#f2d4d4; }
[data-variant="terminal"] .user-flag.is-warn  { background:#fcf3dc; color:#7a5800; border-color:#ead7a4; }
[data-variant="terminal"] .user-flag.is-info  { background: var(--accent-soft); color: var(--accent); border-color: var(--border-2); }

/* WHY 7.9 — filter-chip .on on terminal: accent-soft + accent ink
   (mirrors SWEEP §1.5 for .fchip.active on dark surface). */
[data-variant="terminal"] .filter-chip.on,
[data-variant="terminal"] .filter-chip:hover {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--border-2);
}

/* WHY 7.10 — usage sparkline series captions: tone down the four
   inline hex colours that read as highlighter on cream paper. The
   SVG strokes themselves are out of CSS reach (JS-rendered). */
[data-variant="terminal"] #usage-chart > div > div > div[style*="color:#60a5fa"],
[data-variant="terminal"] #usage-chart > div > div > div[style*="color:#22d3ee"],
[data-variant="terminal"] #usage-chart > div > div > div[style*="color:#fbbf24"],
[data-variant="terminal"] #usage-chart > div > div > div[style*="color:#a78bfa"] {
  color: var(--text-3) !important;
}

/* WHY 7.11 — admin-feature-audit .summary-cards align with SWEEP
   §1.1 exec-tile pattern: neutral surface + 2px coloured top hairline
   indicates kind. :has() keeps non-status tiles neutral. */
[data-variant="terminal"] .summary-cards .card:has(.value.pass) { border-color: var(--pass); }
[data-variant="terminal"] .summary-cards .card:has(.value.warn) { border-color: var(--warn); }
[data-variant="terminal"] .summary-cards .card:has(.value.fail) { border-color: var(--fail); }

/* WHY 7.12 — terminal focus ring uses the SWEEP §1.2 hairline +
   box-shadow ring pattern instead of the inline outline rules. */
[data-variant="terminal"] :where(
  select, input[type="date"], input[type="text"], input[type="email"]
):focus {
  outline: none !important;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 2px var(--accent-soft) !important;
}


/* ── 8. RESPONSIVE — 480px phone-portrait floor ──────────────────── */

@media (max-width: 480px) {
  /* WHY 8.1 — at ≤480px the 5-pill row collides (text overlaps and the
     last pill clips). Drop the analyzer's 1-row scroller for a 2-column
     grid so every pill keeps full width + readable typography. The Δ 7D
     pill (last) spans both columns so the change-over-time signal stays
     visually distinct from the absolute scores above. */
  .score-pill-strip {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    padding: 10px 12px;
    overflow-x: visible;
  }
  .score-pill-strip::-webkit-scrollbar { display: none; }
  .score-pill-strip .score-pill {
    flex: unset;
    min-width: 0;
    min-height: 64px;
  }
  .score-pill-strip .score-pill:last-child { grid-column: 1 / -1; }

  /* WHY 8.2 — results-bar: drop the §3.6 vertical hairlines that read
     as trailing strokes when groups wrap. Stack as left-aligned rows
     with no dividers; row-order carries the hierarchy. */
  .results-bar { padding: 10px 14px; gap: 8px; }
  .results-bar-domain {
    padding-right: 0;
    border-right: none;
    width: 100%;
  }
  .results-bar-meta {
    padding-left: 0;
    border-left: none;
    width: 100%;
  }
  .results-bar-actions { width: 100%; }

  /* WHY 8.3 — modal inner padding floor (20 → 14) so title + close
     glyph don't collide on 360–480 viewports. */
  .pc-modal-hdr { padding: 14px 16px; gap: 8px; }
  .pc-modal-body { padding: 16px; }
  .pc-modal-ftr { padding: 14px 16px; gap: 8px; }

  /* WHY 8.4 — priority / hist tables overflow viewport even after the
     analyzer @640 column-hide. Make the wrap horizontally scrollable so
     cells keep their padding instead of getting crushed. */
  .priority-table-wrap,
  .hist-table-wrap { overflow-x: auto; }
  .priority-table,
  .hist-table { min-width: 480px; }

  /* WHY 8.5 — .tabs-side horizontal strip (the §5.1 1024px flip) has
     13+ items in analyzer; wrap → 4 visual rows. 1-row scroll-strip
     matches the standard analyzer tab rail pattern. */
  .analysis-shell > .tabs-side,
  .analysis-shell > .tabs-bar.tabs-side {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding: 8px 12px;
    scrollbar-width: none;
  }
  .analysis-shell > .tabs-side::-webkit-scrollbar,
  .analysis-shell > .tabs-bar.tabs-side::-webkit-scrollbar { display: none; }
  .analysis-shell > .tabs-side .tab-row,
  .analysis-shell > .tabs-bar.tabs-side .tab-btn { flex-shrink: 0; }

  /* WHY 8.6 — severity-rollup 4-cell row squeezes to <80px each. Drop
     to 2×2 below 480; numbers and labels keep their hierarchy. */
  .severity-rollup,
  .severity-rollup > div:first-child {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: 8px;
  }

  /* WHY 8.7 — url-form stacks vertically (current inline rule fires
     only at 380px; 393–480 still get the cramped row). */
  .url-form {
    flex-direction: column;
    padding: 8px;
    gap: 8px;
  }
  .url-form .analyze-btn,
  .url-form button[type="submit"] {
    width: 100%;
    justify-content: center;
  }
  .analysis-mode-pills,
  .mode-pills {
    align-self: center;
    flex-wrap: wrap;
    justify-content: center;
  }

  /* WHY 8.8 — pc-subnav strip wraps to 2 rows; force 1-row scroll. */
  .pc-subnav {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .pc-subnav::-webkit-scrollbar { display: none; }
  .pc-subnav__tab { flex-shrink: 0; }

  /* WHY 8.9 — analysis-content padding floor; SWEEP §5.8 lands 22/20,
     phone-portrait wants 16/14 so cards don't pin to a thin column. */
  .analysis-shell > .analysis-content { padding: 16px 14px 80px; }
  .pos-intro { padding: 14px 16px; }

  /* WHY 8.10 — analyzer hero clamp floor; at 480 the 6.5vw clamp from
     SWEEP §6.2 yields ~31px — still desktop-heavy against a 480 column. */
  .hero h1 { font-size: clamp(22px, 7vw, 28px); }
  .hero { padding: 28px 16px 20px; }
  .hero p, .hero .sub, .hero-sub {
    font-size: 13.5px;
    max-width: none;
  }

  /* WHY 8.11 — score-evolution: sec-row title + "ÚLTIMOS 90 DÍAS" hint
     wrap awkwardly at 390px. Shrink hint to 10.5px + nowrap so it stays
     on the same baseline row as the title. */
  .score-evolution-card .sec-hint {
    font-size: 10.5px;
    white-space: nowrap;
  }

  /* WHY 8.12 — section-overview card grid: minmax(240px,1fr) at 480px
     viewport always collapses to 1 column — explicit single column avoids
     the browser reflow guess and guarantees full-bleed cards. */
  .prs-section-overview__grid {
    grid-template-columns: 1fr;
  }

  /* WHY 8.13 — tabs-side strip touch targets: 10px 14px vertical padding
     at ≤480 yields ≈34px row — below the 44px WCAG 2.5.5 AA floor for
     interactive touch controls. Bump vertical to 12px. */
  .analysis-shell > .tabs-bar.tabs-side .tab-btn,
  .analysis-shell > .tabs-side .tab-row {
    padding-top: 12px;
    padding-bottom: 12px;
    min-height: 44px;
  }

  /* WHY 8.14 — results-bar action row on phones: flex-wrap so all 3 ghost
     buttons stay accessible without truncation; remove justify end so they
     left-align with the domain pill above. */
  .results-bar-actions {
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 6px;
  }
}


/* ── 9. RESPONSIVE — 360px crunch (small-phone portrait) ─────────── */

@media (max-width: 360px) {
  /* WHY 9.1 — score-ring 200 → 180px so the 64px number doesn't crowd
     the column; matches the SWEEP §6.2 hero scale-down logic. */
  .score-section.score-section--hero .score-ring-wrap {
    width: 180px;
    height: 180px;
  }
  .score-section.score-section--hero .score-number { font-size: 56px; }

  /* WHY 9.2 — modal padding floor on 320px iPhone SE. */
  .pc-modal-hdr,
  .pc-modal-ftr { padding: 12px 14px; }
  .pc-modal-body { padding: 14px; }

  /* WHY 9.3 — auth card flush; SWEEP §6.4 margin:16px wastes 10% of
     viewport. 8px inset keeps the form readable. */
  body:has(> .card[role="main"]) > .card[role="main"] { margin: 8px; }
}


/* ── 9b. RESPONSIVE — 768px phone-landscape / phablet analysis shell ─
   These rules target the analysis shell specifically at ≤768px where the
   fixed sidebar + margin-left pattern is no longer appropriate. They
   complement §5 (1024px) by adding analysis-specific overrides that were
   missing from the original §6 (768px) sweep. */

@media (max-width: 768px) {
  /* WHY 9b.1 — full-bleed shell on phones: the §1 100vw stretch + negative
     margins exist to let the fixed sidebar reach the viewport left edge on
     wide desktops. On phones there's no sidebar, just extra horizontal
     scroll potential. Reset to normal flow. */
  .analysis-shell {
    width: 100%;
    margin-left: 0;
    margin-right: 0;
  }

  /* WHY 9b.2 — score section hero on phone: the large ring + score number
     combo takes 60% of viewport height on 390px portrait. Scale down the
     card padding so content starts earlier. */
  .score-section.score-section--hero {
    padding: 20px 16px;
  }

  /* WHY 9b.3 — prs-section-overview cards: at tablet widths minmax(240px,1fr)
     yields 2 columns, which is fine. At ≤768px (phones in landscape) we still
     want 2-col if there's room — auto-fill handles this. No override needed
     here; §8.12 (480px) drops to 1-col. */

  /* WHY 9b.4 — score-evolution card sec-row: on 600–768 the sec-hint can
     still wrap if the title is long. Cap to row layout with some flex floor. */
  .score-evolution-card .sec-row {
    flex-wrap: nowrap;
    gap: 6px;
  }
  .score-evolution-card .sec-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* WHY 9b.5 — pos-intro card: desktop padding 24px/20px is heavy on
     phones; match the §8.9 analysis-content floor. */
  .pos-intro { padding: 14px 16px; }

  /* WHY 9b.6 — section-rail pills: on narrow phones the rail can overflow
     horizontally. Enable 1-row scroll. */
  .prs-section-rail {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 10px 14px;
  }
  .prs-section-rail::-webkit-scrollbar { display: none; }
  .prs-section-rail__pill { flex-shrink: 0; }
}


/* ── 10. AUTH SECONDARY (reset / verify / setup-2fa / invite) ─────── */

/* WHY 10.1 — calm the .card shadow on all auth pages. setup-2fa carried
   the same 50px+teal-inner-ring tell login.html had before it was
   surgically fixed; this external rule covers any remaining offender. */
body:has(> .card[role="main"]) > .card[role="main"] {
  box-shadow: var(--shadow-md) !important;
}

/* WHY 10.2 — auth toasts: saturated rgba(34,197,94,.1) / (240,68,68,.1)
   backdrops replaced by neutral surface + 2px coloured top hairline,
   matching the app's pattern (§1.1 exec tiles, §7.11 admin summary). */
.card .toast,
.card .err,
.card .ok,
.card .info {
  background: var(--surface) !important;
  border: 1px solid var(--border) !important;
  border-top-width: 2px !important;
  color: var(--text-2) !important;
}
.card .toast.ok,
.card .ok          { border-top-color: var(--ok) !important; color: var(--ok) !important; }
.card .toast.err,
.card .err         { border-top-color: var(--err) !important; color: var(--err) !important; }
.card .info        { border-top-color: var(--border-2, var(--border)) !important; }

/* WHY 10.3 — verify-email .steps-bar .s.done + invite .chip both
   hand-rolled rgba(45,212,191,.x) literals. Use --accent-soft so the
   cream and light themes inherit the right tone via their own tokens. */
.steps-bar .s.done {
  background: var(--accent-soft) !important;
  color: var(--accent) !important;
  border-color: var(--accent) !important;
}
.card .chip {
  background: var(--accent-soft) !important;
  color: var(--accent) !important;
}

/* WHY 10.4 — invite .lang-toggle.active hardcoded color:#fff breaks
   contrast on cream/light themes. Other auth pages already use the
   --accent-ink token + fallback. */
.lang-toggle button.active {
  color: var(--accent-ink) !important;
}

/* WHY 10.5 — setup-2fa OTP input: 10px letter-spacing pushes the 6th
   digit flush against the right border. 8px centres the group inside
   the 14px padding box; mobile drop to 6px already exists. Add the
   §1.2 2px focus halo so the OTP doesn't get different focus chrome. */
.field.otp input {
  letter-spacing: 8px !important;
  padding-right: 8px !important;
  text-indent: 4px;
}
.field.otp input:focus {
  background: var(--surface-2) !important;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 2px var(--accent-soft) !important;
}

/* WHY 10.6 — invite readonly email input: legacy opacity:.6 is overridden
   by JS-injected style="opacity:1". Surface-3 tint communicates "value
   is determined by the invite, not editable" without making text unreadable. */
.card input[readonly] {
  background: var(--surface-3, var(--surface-2)) !important;
  color: var(--text-2) !important;
  cursor: not-allowed;
}

/* WHY 10.7 — setup-2fa recovery .codes code: parity with .secret-box
   so triple-click selects a single code for copying. */
.codes code { user-select: all; }


/* ── 11. ACCESSIBILITY (WCAG 2.1 AA) ─────────────────────────────────
   Restores focus-visible rings the inline <style> wiped, swaps every
   #fff-on-accent pair for the canonical --accent-ink (1.73:1 → 9.46:1),
   tightens non-text contrast of accent-soft chip borders. */

/* WHY 11.1 [P0] — every #fff-on-accent pair becomes --accent-ink so the
   contrast jumps from 1.73:1 (fail) to 9.46:1 (pass). Hits class rules
   in the analyzer's legacy inline <style> AND the ~10 inline-styled
   CTAs in the page body that ship style="color:#fff;background:var(--accent)".
   2026-05-15 extension: 7 more selectors landed since the original sweep
   (analyzer .analyze-btn, .mode-pill.active, .pr-table th, .mbb-btn.primary;
   dashboard .card-btn.primary, .range-chip.active, .mobile-back a) — all
   ship the same #fff-on-accent pair in their inline <style> blocks
   (1.6:1 fail). Listing them here promotes the canonical accent-ink fix. */
:where(
  .logo-mark,
  .gen-intro-icon, .gen-btn-primary, .gen-spinner,
  .ai-modal-ico, .ai-full-ico,
  .tools-cat-btn.active,
  .sm-filter-btn.active,
  .mon-save-btn,
  .orgkw-days-toggle button.active,
  .ob-num, .ob-start,
  .analyze-btn,
  .mode-pill.active,
  .card-btn.primary,
  .range-chip.active,
  .mbb-btn.primary,
  .mobile-back a,
  .pr-table th
) {
  color: var(--accent-ink) !important;
}
[style*="background:var(--accent)"][style*="color:#fff"],
[style*="background: var(--accent)"][style*="color:#fff"],
[style*="background:var(--accent)"][style*="color: #fff"],
[style*="background: var(--accent)"][style*="color: #fff"] {
  color: var(--accent-ink) !important;
}

/* WHY 11.2 [P0] — neutralise the global `button{outline:none}` in
   analyzer.html:48 that wiped the canonical focus-visible ring across
   every button on the page. Restore via cascade. */
button:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--accent) !important;
  outline-offset: 2px !important;
  border-radius: 3px;
}
button:focus:not(:focus-visible) { outline: none; }

/* WHY 11.3 [P1] — inline style="outline:none" on ~30 inputs gets a
   real :focus-visible ring back. Inline style suppresses outline at
   rest; :focus-visible repaints it for keyboard users. */
input[style*="outline:none"]:focus-visible,
input[style*="outline: none"]:focus-visible,
textarea[style*="outline:none"]:focus-visible,
textarea[style*="outline: none"]:focus-visible,
select[style*="outline:none"]:focus-visible,
select[style*="outline: none"]:focus-visible {
  outline: 2px solid var(--accent) !important;
  outline-offset: 1px !important;
}

/* WHY 11.4 [P0] — SWEEP §7.12 stripped outline on terminal inputs;
   re-instate for :focus-visible (keyboard) so forced-colors / high-
   contrast modes still get a visible indicator. */
[data-variant="terminal"] :where(
  select, input[type="date"], input[type="text"], input[type="email"],
  input[type="password"], input[type="number"], input[type="search"]
):focus-visible {
  outline: 2px solid var(--accent) !important;
  outline-offset: 2px !important;
}

/* WHY 11.5 [P1] — accent-soft chip borders failed 1.4.11 non-text
   contrast (1.76:1). Bump the active-state border to --accent (11:1
   against surface) so the ring stands off. */
.fchip.active,
.dash-view-btn.active,
.tabs-side .tab-row.active > .tag-ai:first-child,
.tabs-side .tab-row.active > .vs-text:first-child,
.tabs-bar.tabs-side .tab-row.active > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-row.active > .vs-text:first-child,
.tabs-bar.tabs-side .tab-btn.active > .tag-ai:first-child,
.tabs-bar.tabs-side .tab-btn.active > .vs-text:first-child,
.tabs-side .tab-row.active .glyph,
.tabs-side .tab-row.active > svg.ico:first-child,
.tabs-bar.tabs-side .tab-row.active > svg.ico:first-child,
.tabs-bar.tabs-side .tab-btn.active > svg.ico:first-child {
  border-color: var(--accent) !important;
}
.tabs-side .tab-row .new,
.tabs-bar.tabs-side .tab-btn .new,
.ask-ai-btn:hover {
  border-color: var(--accent) !important;
}

/* WHY 11.6 [P1] — topbar icon-only at ≤480px (SWEEP §6.3) needs a
   ≥44px hit target per the iOS/Material 44px guideline. */
@media (max-width: 480px) {
  .pc-topbar__sec {
    min-width: 44px;
    justify-content: center;
  }
}


/* ════════════════════════════════════════════════════════════════════
   ── 12. LIQUID GLASS — INTERACTIVE CONTROLS ────────────────────────
   Apple-style "polished glass capsule" treatment for buttons, inputs,
   chips and pills. Pairs with §12 (cards/glass-cards.md) but stays
   distinct: cards are "frosted panes", controls are "polished crystal".

   The recipe is the same in spirit (translucent fill + 1px inner top
   sheen + subtle outer ring), but scaled down: controls are touched
   constantly, so blur is light, transitions are short (≤120ms), and
   focus rings stay opaque + high-contrast (a11y > aesthetics).
   ════════════════════════════════════════════════════════════════════ */

/* WHY 12.0 — control-scoped alias tokens. Distinct from §12-cards so
   they can tune independently (controls are smaller, need less blur,
   need a stronger top-edge sheen because the eye reads them at button
   scale where 1px of light matters more than on a 600px card). */
:root {
  --ctl-glass-tint:    rgba(24, 27, 32, 0.62);     /* ghost/secondary fill */
  --ctl-glass-tint-2:  rgba(31, 35, 41, 0.74);     /* hover step */
  --ctl-glass-stroke:  rgba(255, 255, 255, 0.07);  /* outer hairline */
  --ctl-glass-sheen:   rgba(255, 255, 255, 0.10);  /* inner top-edge highlight (1px) */
  --ctl-glass-sheen-2: rgba(255, 255, 255, 0.16);  /* primary CTA inner highlight (brighter) */
  --ctl-glass-blur:    blur(12px) saturate(135%);
  --ctl-glass-press:   inset 0 1px 2px rgba(0, 0, 0, 0.25);  /* tactile pressed feel */
}

/* WHY 12.1 — solid teal CTAs (.btn-primary, .pc-btn--primary, the auth
   submit override, #btnNicheDiscover, .analyze-btn). Solidity is kept —
   the teal fill stays — but a 1px inner top-edge sheen makes it read as
   a polished pill, not a flat rect. This is the SINGLE detail that
   separates "casino bonus button" from "Apple Pay button": one hairline
   of light at the top, no gradients, no glow halos, no rainbow shadows. */
:where(
  .btn-primary,
  .pc-btn--primary,
  #btnNicheDiscover,
  .analyze-btn,
  .url-form button[type="submit"],
  .card > form button[type="submit"],
  .card button[type="submit"],
  form#form button[type="submit"]
) {
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen-2),
    0 1px 1px rgba(0, 0, 0, 0.15);
}

/* WHY 12.2 — solid CTA hover. Existing rules add the 4px accent-soft
   halo on hover; we keep that but reinforce the inner sheen so the
   button reads "lit from above" when the pointer lands. NO scale, NO
   glow — the existing translateY/scale on :active does the tactile work. */
:where(
  .btn-primary,
  .pc-btn--primary,
  #btnNicheDiscover,
  .analyze-btn,
  .url-form button[type="submit"],
  .card > form button[type="submit"],
  .card button[type="submit"],
  form#form button[type="submit"]
):hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 0 0 4px var(--accent-soft),
    0 2px 6px -2px rgba(0, 0, 0, 0.25);
}

/* WHY 12.3 — solid CTA :active becomes "pressed glass": the inner sheen
   inverts to an inner shadow (light is now coming from below the press)
   plus the existing translateY(1px) holds. Sells the tactile metaphor. */
:where(
  .btn-primary,
  .pc-btn--primary,
  #btnNicheDiscover,
  .analyze-btn,
  .url-form button[type="submit"]
):active {
  box-shadow:
    var(--ctl-glass-press),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* WHY 12.4 — ghost/secondary buttons get the translucent glass surface.
   This is where Liquid Glass actually shines: a 62%-opacity surface
   reads the body radial-gradient through itself, so the button picks
   up subtle teal/blue tints from the page bg instead of looking like a
   grey rectangle. Border becomes a hairline + the inner top sheen sells
   the "glass capsule" silhouette. */
:where(.pc-btn--ghost, .pc-btn--secondary, .btn-ghost, .btn-secondary, .ask-ai-btn) {
  background: var(--ctl-glass-tint);
  -webkit-backdrop-filter: var(--ctl-glass-blur);
  backdrop-filter: var(--ctl-glass-blur);
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen),
    0 0 0 1px var(--ctl-glass-stroke);
}
:where(.pc-btn--ghost, .pc-btn--secondary, .btn-ghost, .btn-secondary, .ask-ai-btn):hover {
  background: var(--ctl-glass-tint-2);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    0 0 0 1px rgba(255, 255, 255, 0.10);
}
:where(.pc-btn--ghost, .pc-btn--secondary, .btn-ghost, .btn-secondary, .ask-ai-btn):active {
  box-shadow:
    var(--ctl-glass-press),
    0 0 0 1px var(--ctl-glass-stroke);
}

/* WHY 12.5 — utility icon buttons (theme toggle, settings, refresh).
   Inline-styled in analyzer.html at 34×34 with --surface-2 fill. We
   upgrade them to the same glass primitive so the topbar cluster reads
   as one material family. Hit-target stays at 34px on desktop but the
   §11.6 ≤480px rule already enforces 44px floor. */
:where(.theme-btn, .settings-btn, .refresh) {
  background: var(--ctl-glass-tint) !important;
  -webkit-backdrop-filter: var(--ctl-glass-blur);
  backdrop-filter: var(--ctl-glass-blur);
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen),
    0 0 0 1px var(--ctl-glass-stroke);
  transition: background-color .12s, box-shadow .12s, color .12s;
}
:where(.theme-btn, .settings-btn, .refresh):hover {
  background: var(--ctl-glass-tint-2) !important;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    0 0 0 1px rgba(255, 255, 255, 0.10);
}

/* WHY 12.6 — text-only buttons (.btn-text, .pc-btn--text) get the
   minimum-viable glass: no surface at rest, but on hover a faint
   translucent pad appears underneath. Restraint matters here — these
   are inline "Learn more"-style links, not CTAs. */
:where(.btn-text, .pc-btn--text):hover {
  background: rgba(255, 255, 255, 0.04);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border-radius: var(--radius-sm);
}

/* WHY 12.7 — toggle/filter chips (.fchip, .dash-view-btn at rest).
   Same glass primitive at chip scale. The .active state is owned by
   §1.5 + §11.5 (accent-soft fill + accent border) and is left untouched
   — active state needs to read as "this filter is ON", not "this filter
   is also glass". */
:where(.fchip, .dash-view-btn):not(.active) {
  background: var(--ctl-glass-tint);
  -webkit-backdrop-filter: var(--ctl-glass-blur);
  backdrop-filter: var(--ctl-glass-blur);
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen),
    0 0 0 1px var(--ctl-glass-stroke);
}
:where(.fchip, .dash-view-btn):not(.active):hover {
  background: var(--ctl-glass-tint-2);
}

/* WHY 12.8 — input fields (.pc-field input/select/textarea, .field input,
   .url-input host). Glass on inputs is the trickiest call: too much
   blur and text gets unreadable. We use a low-opacity tint that mostly
   reads as surface but lets the body gradient bleed through 1-2%, plus
   the canonical inner top sheen. Focus ring (§1.2) wins on focus —
   accent border + 2px accent-soft halo — and we DON'T blur focus state. */
:where(
  .pc-field input, .pc-field select, .pc-field textarea, .pc-field__input,
  .field input, .field select, .field textarea,
  .card input[type="email"], .card input[type="password"], .card input[type="text"],
  .dash-toolbar .search-mini, .search-wrap
) {
  background: var(--ctl-glass-tint);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
  backdrop-filter: blur(8px) saturate(120%);
  box-shadow: inset 0 1px 0 var(--ctl-glass-sheen);
}

/* WHY 12.9 — .url-form analyzer bar is the hero input. It deserves a
   slightly stronger glass treatment because it's the single CTA on the
   blank-state page — the user looks at NOTHING else. Stroke + sheen
   make it feel like a polished crystal capsule waiting to be tapped. */
.url-form {
  background: var(--ctl-glass-tint) !important;
  -webkit-backdrop-filter: var(--ctl-glass-blur);
  backdrop-filter: var(--ctl-glass-blur);
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen),
    0 0 0 1px var(--ctl-glass-stroke),
    0 6px 20px -10px rgba(0, 0, 0, 0.35);
}
/* Glow on focus removed — keep base glass styling; border-color comes from analyzer.html. */

/* WHY 12.10 — native <select> styling on the toolbar sort dropdown.
   appearance:none already in §dash-toolbar; we just add the glass fill
   so it matches its sibling input. */
:where(.dash-toolbar .sort-select, .dash-toolbar select.toolbar-select) {
  background-color: var(--ctl-glass-tint);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
  backdrop-filter: blur(8px) saturate(120%);
  box-shadow: inset 0 1px 0 var(--ctl-glass-sheen);
}

/* WHY 12.11 — chips/pills/badges (.pc-chip, .pc-badge, .mode-chip,
   .chip non-active, .ai-status). Scaled-down glass primitive. NOT
   applied to colored semantic badges (--ok/--warn/--fail/--info
   variants of .pc-badge) — those carry meaning through saturated tint
   and shouldn't dilute. .ai-status.online has a colored fill too, only
   the neutral "offline/loading" state picks up glass. */
:where(.pc-chip:not([aria-pressed="true"]):not(.is-active),
       .pc-badge:not(.pc-badge--ok):not(.pc-badge--warn):not(.pc-badge--fail):not(.pc-badge--info):not(.pc-badge--accent),
       .mode-chip,
       .ai-status:not(.online):not(.offline)) {
  background: var(--ctl-glass-tint);
  -webkit-backdrop-filter: blur(8px) saturate(130%);
  backdrop-filter: blur(8px) saturate(130%);
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen),
    0 0 0 1px var(--ctl-glass-stroke);
}

/* WHY 12.12 — .mode-pills group + .mode-pill / .input-mode-btn buttons.
   The group container becomes a glass tray; the individual non-active
   pills are transparent inside it (so they don't double-glass). The
   .active pill keeps its solid accent fill from inline rules + picks
   up the §12.1 inner sheen via the cascade. */
.mode-pills {
  background: var(--ctl-glass-tint) !important;
  -webkit-backdrop-filter: var(--ctl-glass-blur);
  backdrop-filter: var(--ctl-glass-blur);
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen),
    0 0 0 1px var(--ctl-glass-stroke);
}
:where(.mode-pill.active, .input-mode-btn.active, .mode-pills button.on.geo) {
  box-shadow: inset 0 1px 0 var(--ctl-glass-sheen-2);
}

/* WHY 12.13 — .score-pill (analyzer hero metric chips). These already
   went transparent in §3.8; we lift them off the page with the same
   inner-sheen treatment so they read as "data crystals" not "label
   stickers". Border is owned by §3.8; we touch only box-shadow. */
.score-pill-strip .score-pill {
  box-shadow:
    inset 0 1px 0 var(--ctl-glass-sheen),
    0 0 0 1px var(--ctl-glass-stroke);
}
.score-pill-strip .score-pill:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    0 0 0 1px rgba(255, 255, 255, 0.10);
}

/* WHY 12.14 — hit-target floor for every glass control. Existing
   §F5.5 + §11.6 enforce 44px on phones for nav/topbar/lang controls;
   we extend the rule to the chips and toggle buttons that the brief
   calls out, because Liquid Glass typically nudges devs to make
   controls SMALLER (the visual lightness invites shrinkage). The
   44×44 minimum protects fingertip accuracy on touch. */
@media (max-width: 768px) {
  :where(.fchip, .dash-view-btn, .mode-pill, .mode-chip,
         .theme-btn, .settings-btn, .refresh,
         .ai-status, .pc-chip) {
    min-height: 44px;
    min-width: 44px;
  }
}

/* WHY 12.15 — focus rings stay OPAQUE + UNBLURRED. Every selector here
   inherits the canonical :focus-visible from prisma-base.css §1 (2px
   solid accent + 2px offset). We make sure no glass rule overrides it:
   explicit override that the focus ring is a flat outline, not a glass
   halo. Required by WCAG 2.4.7 and forced-colors mode. */
:where(
  .btn-primary, .pc-btn, .pc-btn--primary, .pc-btn--ghost, .pc-btn--secondary,
  .btn-ghost, .btn-secondary, .btn-text, .pc-btn--text,
  .analyze-btn, .url-form, .url-input,
  .fchip, .dash-view-btn, .mode-pill, .input-mode-btn,
  .theme-btn, .settings-btn, .refresh, .ask-ai-btn,
  .pc-chip, .pc-badge, .mode-chip,
  .pc-field input, .pc-field select, .field input
):focus-visible {
  outline: 2px solid var(--accent) !important;
  outline-offset: 2px !important;
  -webkit-backdrop-filter: var(--ctl-glass-blur);
  backdrop-filter: var(--ctl-glass-blur);
}

/* WHY 12.16 — LIGHT THEME variant. Cream paper does not want frosted
   glass; it wants ink on paper. We swap the dark-on-translucent tint
   for a near-white tint + warmer stroke. Sheen uses a deeper black
   shadow at the top (reverse of dark: light shines DOWN onto a white
   surface, so the highlight is a SHADOW not a glow). */
[data-theme="light"] {
  --ctl-glass-tint:    rgba(255, 255, 255, 0.62);
  --ctl-glass-tint-2:  rgba(255, 255, 255, 0.80);
  --ctl-glass-stroke:  rgba(15, 17, 21, 0.08);
  --ctl-glass-sheen:   rgba(255, 255, 255, 0.85);
  --ctl-glass-sheen-2: rgba(255, 255, 255, 0.95);
  --ctl-glass-press:   inset 0 1px 2px rgba(15, 17, 21, 0.10);
}

/* WHY 12.17 — TERMINAL variant (admin cream-paper Bloomberg aesthetic).
   Drops backdrop-filter entirely — the warm-cream surface is opaque by
   design and frosting it reads as plastic, not paper. Inputs/buttons
   keep their solid fills + get a 1px inner sheen ONLY (the polished-
   button cue), no translucency, no blur. */
[data-variant="terminal"] :where(
  .pc-btn, .pc-btn--primary, .pc-btn--ghost, .pc-btn--secondary,
  .btn-primary, .btn-ghost, .btn-secondary,
  .fchip, .dash-view-btn, .mode-pill, .input-mode-btn,
  .theme-btn, .settings-btn, .refresh,
  .pc-chip, .pc-badge, .mode-chip, .url-form, .ai-status,
  .pc-field input, .field input, .dash-toolbar .search-mini, .search-wrap
) {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  background-color: var(--surface);
}
[data-variant="terminal"] :where(
  .btn-primary, .pc-btn--primary, #btnNicheDiscover, .analyze-btn
) {
  background-color: var(--accent);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 1px 1px rgba(0, 0, 0, 0.10);
}
[data-variant="terminal"] :where(.pc-btn--ghost, .btn-ghost, .pc-btn--secondary, .btn-secondary) {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    0 0 0 1px var(--border);
}

/* WHY 12.18 — REDUCED-TRANSPARENCY fallback. macOS / iOS / Windows
   users who turn on the system "Reduce transparency" pref get every
   glass surface back to opaque + the inner sheen demoted to a 1px
   solid border-top hairline (so the polished-button cue survives in
   a flatter form). Hardware-mandatory; not a nice-to-have. */
@media (prefers-reduced-transparency: reduce) {
  :where(
    .btn-primary, .pc-btn--primary, .pc-btn--ghost, .pc-btn--secondary,
    .btn-ghost, .btn-secondary, .btn-text, .pc-btn--text,
    .analyze-btn, .url-form, .fchip, .dash-view-btn,
    .mode-pill, .mode-pills, .input-mode-btn,
    .theme-btn, .settings-btn, .refresh, .ask-ai-btn,
    .pc-chip, .pc-badge, .mode-chip, .ai-status,
    .pc-field input, .pc-field select, .pc-field textarea,
    .field input, .url-input, .score-pill-strip .score-pill,
    .dash-toolbar .search-mini, .search-wrap,
    .dash-toolbar .sort-select, .dash-toolbar select.toolbar-select
  ) {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  :where(.pc-btn--ghost, .pc-btn--secondary, .btn-ghost, .btn-secondary,
         .fchip:not(.active), .dash-view-btn:not(.active),
         .mode-pills, .url-form, .pc-chip:not([aria-pressed="true"]):not(.is-active),
         .pc-field input, .pc-field select, .field input,
         .dash-toolbar .search-mini, .search-wrap, .ai-status:not(.online):not(.offline),
         .theme-btn, .settings-btn, .refresh) {
    background-color: var(--surface) !important;
  }
  :where(.btn-primary, .pc-btn--primary, .pc-btn--ghost, .pc-btn--secondary,
         .btn-ghost, .btn-secondary, .fchip, .dash-view-btn,
         .mode-pills, .url-form, .pc-chip, .pc-badge, .mode-chip,
         .theme-btn, .settings-btn, .refresh, .ai-status,
         .score-pill-strip .score-pill) {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 0 0 1px var(--border) !important;
  }
  [data-theme="light"] :where(.btn-primary, .pc-btn--primary, .pc-btn--ghost,
         .pc-btn--secondary, .btn-ghost, .btn-secondary, .fchip,
         .dash-view-btn, .mode-pills, .url-form, .pc-chip, .pc-badge,
         .mode-chip, .theme-btn, .settings-btn, .refresh, .ai-status,
         .score-pill-strip .score-pill) {
    box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.03), 0 0 0 1px var(--border) !important;
  }
}


/* ════════════════════════════════════════════════════════════════════
   ── 13. LIQUID GLASS — CARDS & SURFACES ────────────────────────────
   Frosted-pane treatment for floating UI primitives. Reads the body
   radial-gradient bg through the surface. Tokens prefixed --glass-card-*
   to keep §13/§14/§15 namespaces independent.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 13.0 — card-scoped tokens. */
:root {
  --glass-card-tint:    rgba(20, 22, 25, 0.74);
  --glass-card-tint-2:  rgba(24, 27, 32, 0.78);
  --glass-card-stroke:  rgba(255, 255, 255, 0.055);
  --glass-card-sheen:   rgba(255, 255, 255, 0.06);
  --glass-card-shadow:  0 0 0 1px var(--glass-card-stroke),
                        inset 0 1px 0 var(--glass-card-sheen),
                        0 8px 28px -12px rgba(0, 0, 0, 0.55);
  --glass-card-shadow-hover:
                        0 0 0 1px rgba(255, 255, 255, 0.08),
                        inset 0 1px 0 rgba(255, 255, 255, 0.09),
                        0 14px 38px -14px rgba(0, 0, 0, 0.65);
  --glass-card-blur:    blur(20px) saturate(140%);
}

/* WHY 13.1 — primary card primitives. One shared pane recipe. */
:where(.pc-card, .sec-card, .card, .bill-card, .domain-card,
       .gen-card, .pos-intro, .mp-section, .ai-panel-intro, .hist-diff) {
  background: var(--glass-card-tint);
  -webkit-backdrop-filter: var(--glass-card-blur);
          backdrop-filter: var(--glass-card-blur);
  border: 1px solid transparent;
  box-shadow: var(--glass-card-shadow);
}

/* WHY 13.2 — card hover lifts the sheen; no glow. */
:where(.pc-card, .bill-card, .domain-card, .pos-intro, .gen-card):hover {
  border-color: transparent !important;
  box-shadow: var(--glass-card-shadow-hover);
}

/* WHY 13.3 — dashboard KPI tiles. */
.dash-hero .dash-stat {
  background: var(--glass-card-tint);
  -webkit-backdrop-filter: var(--glass-card-blur);
          backdrop-filter: var(--glass-card-blur);
  border-color: transparent;
  box-shadow: var(--glass-card-shadow);
}
.dash-hero .dash-stat.dash-stat-actionable:hover {
  border-color: transparent !important;
  box-shadow: var(--glass-card-shadow-hover);
}

/* WHY 13.4 — score-section--hero, the analyzer's hero pane. */
.score-section.score-section--hero {
  background: var(--glass-card-tint-2);
  -webkit-backdrop-filter: var(--glass-card-blur);
          backdrop-filter: var(--glass-card-blur);
  border-color: transparent;
  box-shadow: var(--glass-card-shadow);
}

/* WHY 13.5 — executive-summary tiles layer glass on top of §1.1's neutral. */
#exec-panel > div > div[style*="background:rgba"],
#exec-panel > div > div[style*="background:var(--surface-2)"] {
  background: var(--glass-card-tint-2) !important;
  -webkit-backdrop-filter: var(--glass-card-blur);
          backdrop-filter: var(--glass-card-blur);
  border-color: transparent !important;
  box-shadow: var(--glass-card-shadow) !important;
}

/* WHY 13.6 — severity rollup cells; slimmer drop so 4-cell row doesn't double-rule. */
.severity-rollup .sr-cell {
  background: var(--glass-card-tint);
  -webkit-backdrop-filter: var(--glass-card-blur);
          backdrop-filter: var(--glass-card-blur);
  border-color: transparent;
  box-shadow: inset 0 1px 0 var(--glass-card-sheen),
              0 0 0 1px var(--glass-card-stroke),
              0 4px 14px -8px rgba(0, 0, 0, 0.45);
}
.severity-rollup .sr-cell:hover {
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.09),
              0 0 0 1px rgba(255,255,255,0.08),
              0 8px 18px -8px rgba(0, 0, 0, 0.55);
}

/* WHY 13.7 — table wrappers (priority + history). Wrapper is the pane;
   rows stay opaque-on-glass via transparent default bg. */
.priority-table-wrap,
.hist-table-wrap {
  background: var(--glass-card-tint);
  -webkit-backdrop-filter: var(--glass-card-blur);
          backdrop-filter: var(--glass-card-blur);
  border-color: transparent;
  box-shadow: var(--glass-card-shadow);
}

/* WHY 13.8 — light theme: translucent white instead of dark tint;
   lower blur (over light bg the high blur reads as glow). */
[data-theme="light"] :where(.pc-card, .sec-card, .card, .bill-card,
                            .domain-card, .gen-card, .pos-intro,
                            .mp-section, .ai-panel-intro, .hist-diff,
                            .priority-table-wrap, .hist-table-wrap,
                            .score-section.score-section--hero),
[data-theme="light"] .dash-hero .dash-stat,
[data-theme="light"] .severity-rollup .sr-cell,
[data-theme="light"] #exec-panel > div > div[style*="background:rgba"],
[data-theme="light"] #exec-panel > div > div[style*="background:var(--surface-2)"] {
  background: rgba(255, 255, 255, 0.76);
  -webkit-backdrop-filter: blur(14px) saturate(135%);
          backdrop-filter: blur(14px) saturate(135%);
  border-color: var(--border);
  box-shadow: 0 0 0 1px rgba(15, 17, 22, 0.04),
              inset 0 1px 0 rgba(255, 255, 255, 0.6),
              0 8px 22px -14px rgba(15, 17, 22, 0.14);
}

/* WHY 13.9 — terminal variant opts OUT of glass entirely. Cream
   Bloomberg paper wants ink on paper, not frost. */
[data-variant="terminal"] :where(.pc-card, .sec-card, .card, .bill-card,
                                 .domain-card, .gen-card, .pos-intro,
                                 .mp-section, .ai-panel-intro, .hist-diff,
                                 .priority-table-wrap, .hist-table-wrap,
                                 .score-section.score-section--hero),
[data-variant="terminal"] .dash-hero .dash-stat,
[data-variant="terminal"] .severity-rollup .sr-cell,
[data-variant="terminal"] #exec-panel > div > div[style*="background:rgba"] {
  background: var(--surface);
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}

/* WHY 13.10 — reduced-transparency fallback. */
@media (prefers-reduced-transparency: reduce) {
  :where(.pc-card, .sec-card, .card, .bill-card, .domain-card,
         .gen-card, .pos-intro, .mp-section, .ai-panel-intro, .hist-diff,
         .priority-table-wrap, .hist-table-wrap,
         .score-section.score-section--hero),
  .dash-hero .dash-stat,
  .severity-rollup .sr-cell,
  #exec-panel > div > div[style*="background:rgba"],
  #exec-panel > div > div[style*="background:var(--surface-2)"] {
    background: var(--surface) !important;
    -webkit-backdrop-filter: none !important;
            backdrop-filter: none !important;
    border: 1px solid var(--border) !important;
    box-shadow: var(--shadow-sm) !important;
  }
  :where(.pc-card, .bill-card, .domain-card, .pos-intro, .gen-card):hover,
  .dash-hero .dash-stat.dash-stat-actionable:hover {
    border-color: var(--border-2) !important;
    box-shadow: var(--shadow-md) !important;
  }
}


/* ════════════════════════════════════════════════════════════════════
   ── 14. LIQUID GLASS — NAV CHROME ──────────────────────────────────
   Sticky floating bars (topbar / subnav / results-bar / score-pill /
   tabs-side / app-sidebar) get glass over the radial-gradient bg.
   Tokens prefixed --glass-nav-* to avoid §13/§15 conflicts.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 14.0 — nav-scoped tokens. */
:root {
  --glass-nav-tint:     rgba(10, 11, 13, 0.72);
  --glass-nav-saturate: 180%;
  --glass-nav-edge:     rgba(255, 255, 255, 0.06);
  --glass-nav-ring:     rgba(0, 0, 0, 0.30);
}
[data-theme="light"] {
  --glass-nav-tint:     rgba(255, 255, 255, 0.72);
  --glass-nav-saturate: 160%;
  --glass-nav-edge:     rgba(255, 255, 255, 0.70);
  --glass-nav-ring:     rgba(15, 23, 35, 0.08);
}
[data-theme="light"][data-variant="terminal"] {
  --glass-nav-tint:     rgba(250, 247, 240, 0.82);
  --glass-nav-saturate: 140%;
  --glass-nav-edge:     rgba(255, 251, 241, 0.55);
  --glass-nav-ring:     rgba(60, 50, 30, 0.10);
}

/* WHY 14.1 — .pc-topbar load-bearing app-shell bar. */
.pc-topbar {
  background: var(--glass-nav-tint);
  -webkit-backdrop-filter: blur(24px) saturate(var(--glass-nav-saturate));
          backdrop-filter: blur(24px) saturate(var(--glass-nav-saturate));
  box-shadow: inset 0 1px 0 var(--glass-nav-edge),
              0 1px 0 var(--glass-nav-ring);
}
[data-theme="light"] .pc-topbar { background: var(--glass-nav-tint); }

/* WHY 14.2 — .pc-subnav sits at top:52px; lighter blur to avoid milky stack. */
.pc-subnav {
  background: var(--glass-nav-tint);
  -webkit-backdrop-filter: blur(18px) saturate(var(--glass-nav-saturate));
          backdrop-filter: blur(18px) saturate(var(--glass-nav-saturate));
  box-shadow: inset 0 1px 0 var(--glass-nav-edge),
              0 1px 0 var(--glass-nav-ring);
}
[data-theme="light"] .pc-subnav { background: var(--glass-nav-tint); }

/* WHY 14.3 — .results-bar sticky strip above the 2-column analyzer shell. */
#results.active .results-bar,
.results-bar {
  background: var(--glass-nav-tint);
  -webkit-backdrop-filter: blur(24px) saturate(var(--glass-nav-saturate));
          backdrop-filter: blur(24px) saturate(var(--glass-nav-saturate));
  box-shadow: inset 0 1px 0 var(--glass-nav-edge),
              0 1px 0 var(--glass-nav-ring);
}

/* 2026-05-20 — WHY 14.4 retired: the wrapper-level glass-nav-tint +
   blur made a visible band around the score-pill strip. User wanted
   the 5 pills floating naked over the page. Strip is now a pure
   pass-through; each .score-pill carries its own glass. */
.score-pill-strip {
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
}

/* WHY 14.5 — .tabs-side as a vertical glass pane; only at desktop. */
@media (min-width: 1025px) {
  .tabs-side,
  .analysis-shell > .tabs-side,
  .analysis-shell .tabs-bar.tabs-side,
  .tabs-bar.tabs-side {
    background: var(--glass-nav-tint);
    -webkit-backdrop-filter: blur(20px) saturate(var(--glass-nav-saturate));
            backdrop-filter: blur(20px) saturate(var(--glass-nav-saturate));
    box-shadow: inset 1px 0 0 var(--glass-nav-edge),
                1px 0 0 var(--glass-nav-ring);
  }
}

/* WHY 14.6 — .site-header (marketing / auth) — upgrade existing 10px blur. */
.site-header {
  background: var(--glass-nav-tint) !important;
  -webkit-backdrop-filter: blur(22px) saturate(var(--glass-nav-saturate));
          backdrop-filter: blur(22px) saturate(var(--glass-nav-saturate));
  box-shadow: inset 0 1px 0 var(--glass-nav-edge),
              0 1px 0 var(--glass-nav-ring);
}

/* WHY 14.7 — .app-sidebar (shell sidebar) gets glass signature but
   shallower blur — it rarely floats over scrolling content. */
body:not(.has-pc-topbar) .app-sidebar {
  background: var(--glass-nav-tint);
  -webkit-backdrop-filter: blur(16px) saturate(var(--glass-nav-saturate));
          backdrop-filter: blur(16px) saturate(var(--glass-nav-saturate));
  box-shadow: inset 1px 0 0 var(--glass-nav-edge),
              1px 0 0 var(--glass-nav-ring);
}

/* WHY 14.8 — .tab-row.active needs only an extra inner top highlight
   so the active row reads as a raised pane within the glassy rail. */
.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-btn.active {
  box-shadow: inset 0 0 0 1px var(--border-2),
              inset 0 1px 0 var(--glass-nav-edge);
}

/* WHY 14.9 — reduced-transparency: revert to opaque bg-elev. */
@media (prefers-reduced-transparency: reduce) {
  .pc-topbar, .pc-subnav, #results.active .results-bar, .results-bar,
  .score-pill-strip, .site-header,
  .tabs-side, .analysis-shell > .tabs-side, .tabs-bar.tabs-side,
  body:not(.has-pc-topbar) .app-sidebar {
    background: var(--bg-elev) !important;
    -webkit-backdrop-filter: none !important;
            backdrop-filter: none !important;
  }
  [data-theme="light"] .pc-topbar,
  [data-theme="light"] .pc-subnav { background: var(--bg-elev) !important; }
}

/* WHY 14.10 — @supports fallback for browsers without backdrop-filter. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pc-topbar, .pc-subnav, #results.active .results-bar, .results-bar,
  .score-pill-strip, .site-header,
  .tabs-side, .analysis-shell > .tabs-side, .tabs-bar.tabs-side,
  body:not(.has-pc-topbar) .app-sidebar { background: var(--bg-elev); }
}


/* ════════════════════════════════════════════════════════════════════
   ── 15. LIQUID GLASS — MODALS & OVERLAYS ───────────────────────────
   Apple Vibrancy on floating dialogs/drawers/toasts. Deeper blur than
   cards (modals float above more). Tokens prefixed --glass-modal-*.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 15.0 — modal-scoped tokens. */
:root {
  --glass-modal-blur:       28px;
  --glass-modal-blur-pop:   18px;
  --glass-modal-blur-scrim: 14px;
  --glass-modal-saturate:   180%;
  --glass-modal-tint:       70%;       /* surface mix ratio for color-mix */
  --glass-modal-tint-pop:   82%;
  --glass-modal-highlight:  rgba(255,255,255,.08);
  --glass-modal-edge:       rgba(255,255,255,.05);
  --glass-modal-scrim-tint: rgba(8,9,11,.55);
  --glass-modal-shadow:     0 32px 64px -16px rgba(0,0,0,.65),
                            0 8px 24px -8px rgba(0,0,0,.45),
                            0 0 0 1px rgba(255,255,255,.04);
}

/* WHY 15.1 — scrim: blur + darken page beneath native <dialog>. */
dialog.pc-modal::backdrop,
dialog#ai-modal::backdrop,
dialog.pr-drawer::backdrop,
dialog.onboarding-overlay::backdrop,
.prisma-api-modal.modal-backdrop {
  background: var(--glass-modal-scrim-tint);
  -webkit-backdrop-filter: blur(var(--glass-modal-blur-scrim)) saturate(140%);
          backdrop-filter: blur(var(--glass-modal-blur-scrim)) saturate(140%);
}
.onboarding-overlay {
  background: var(--glass-modal-scrim-tint);
  -webkit-backdrop-filter: blur(var(--glass-modal-blur-scrim)) saturate(140%);
          backdrop-filter: blur(var(--glass-modal-blur-scrim)) saturate(140%);
}
.prisma-api-modal.modal-backdrop {
  background: var(--glass-modal-scrim-tint);
}

/* WHY 15.2 — modal surface: deep glass on the floating pane. */
.pc-modal-box,
.prisma-api-modal .modal,
.onboarding-box,
.ai-modal-box,
.audit-detail-panel,
.ask-ai-modal,
.ai-full-modal {
  background: color-mix(in oklab, var(--surface) var(--glass-modal-tint), transparent);
  -webkit-backdrop-filter: blur(var(--glass-modal-blur)) saturate(var(--glass-modal-saturate));
          backdrop-filter: blur(var(--glass-modal-blur)) saturate(var(--glass-modal-saturate));
  border: 1px solid var(--glass-modal-edge);
  box-shadow: var(--glass-modal-shadow), inset 0 1px 0 var(--glass-modal-highlight);
  isolation: isolate;
}

/* WHY 15.3 — drawer (.pr-drawer): full-height glass, left edge floats. */
.pr-drawer-panel {
  background: color-mix(in oklab, var(--surface) var(--glass-modal-tint), transparent);
  -webkit-backdrop-filter: blur(var(--glass-modal-blur)) saturate(var(--glass-modal-saturate));
          backdrop-filter: blur(var(--glass-modal-blur)) saturate(var(--glass-modal-saturate));
  border-left: 1px solid var(--glass-modal-edge);
  box-shadow: -24px 0 64px -16px rgba(0,0,0,.55),
              inset 1px 0 0 var(--glass-modal-highlight);
  isolation: isolate;
}
.pr-drawer-hdr {
  background: color-mix(in oklab, var(--surface) 60%, transparent);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
}

/* WHY 15.4 — toasts + popovers: lighter glass tier. */
.prisma-toast,
.dash-toolbar-kebab-menu,
.card-kebab-menu,
.dash-kebab-menu,
.project-card .menu {
  background: color-mix(in oklab, var(--surface) var(--glass-modal-tint-pop), transparent);
  -webkit-backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(160%);
          backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(160%);
  border: 1px solid var(--glass-modal-edge);
  box-shadow: 0 16px 40px -12px rgba(0,0,0,.50),
              inset 0 1px 0 var(--glass-modal-highlight);
  isolation: isolate;
}

/* WHY 15.5 — modal hdr/ftr: soften dividers so they don't paint hard
   horizontal stripes over the blur. */
.pc-modal-hdr,
.pc-modal-ftr,
.prisma-api-modal .modal-head {
  border-color: var(--glass-modal-edge);
  background: transparent;
}

/* WHY 15.6 — light theme calibration. */
[data-theme="light"] {
  --glass-modal-tint:       78%;
  --glass-modal-tint-pop:   88%;
  --glass-modal-saturate:   140%;
  --glass-modal-highlight:  rgba(255,255,255,.55);
  --glass-modal-edge:       rgba(0,0,0,.06);
  --glass-modal-scrim-tint: rgba(20,22,28,.32);
  --glass-modal-shadow:     0 24px 48px -16px rgba(15,17,22,.18),
                            0 8px 16px -8px rgba(15,17,22,.10),
                            0 0 0 1px rgba(15,17,22,.04);
}

/* WHY 15.7 — terminal (cream Bloomberg) calibration. */
[data-theme="light"][data-variant="terminal"] {
  --glass-modal-tint:       82%;
  --glass-modal-saturate:   125%;
  --glass-modal-highlight:  rgba(255,251,238,.65);
  --glass-modal-edge:       rgba(58,46,28,.10);
  --glass-modal-scrim-tint: rgba(60,46,28,.30);
  --glass-modal-shadow:     0 24px 48px -16px rgba(60,46,28,.20),
                            0 8px 16px -8px rgba(60,46,28,.12),
                            0 0 0 1px rgba(60,46,28,.05);
}

/* WHY 15.8 — reduced-transparency fallback. */
@media (prefers-reduced-transparency: reduce) {
  .pc-modal-box, .prisma-api-modal .modal, .onboarding-box,
  .ai-modal-box, .audit-detail-panel, .ask-ai-modal, .ai-full-modal,
  .pr-drawer-panel, .prisma-toast, .dash-toolbar-kebab-menu,
  .card-kebab-menu, .dash-kebab-menu, .project-card .menu {
    background: var(--surface);
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
    border-color: var(--border);
  }
  dialog.pc-modal::backdrop, dialog#ai-modal::backdrop,
  dialog.pr-drawer::backdrop, dialog.onboarding-overlay::backdrop,
  .onboarding-overlay, .prisma-api-modal.modal-backdrop {
    background: rgba(0,0,0,.72);
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
  .pr-drawer-hdr {
    background: var(--surface);
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
}

/* WHY 15.9 — @supports fallback for browsers without backdrop-filter. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pc-modal-box, .prisma-api-modal .modal, .onboarding-box,
  .ai-modal-box, .audit-detail-panel, .ask-ai-modal, .ai-full-modal,
  .pr-drawer-panel, .prisma-toast, .dash-toolbar-kebab-menu,
  .card-kebab-menu, .dash-kebab-menu, .project-card .menu {
    background: var(--surface);
    border-color: var(--border);
  }
}


/* ════════════════════════════════════════════════════════════════════
   ── 16. MOTION & MICRO-INTERACTIONS ────────────────────────────────
   Motion = feedback, not decoration. Every animation maps to a state
   change the user just caused (open / focus / press / hover / data).
   CSS-only. prefers-reduced-motion honoured (prisma-base.css §4 global
   kill + §16.10 explicit transform-fallback below).
   Easing tokens:
     enter:  cubic-bezier(.22, 1, .36, 1)
     stage:  cubic-bezier(.4, 0, .2, 1)
   ════════════════════════════════════════════════════════════════════ */

/* WHY 16.1 — modal enter: soft scale-up + fade (Apple-style "materialise
   in place" instead of the existing translateY drop). 220ms ease-out. */
.pc-modal-box,
.onboarding-box,
.ai-modal-box,
.ask-ai-modal,
.ai-full-modal {
  animation: prisma-modal-rise .22s cubic-bezier(.22, 1, .36, 1);
  transform-origin: 50% 40%;
  will-change: transform, opacity;
}
@keyframes prisma-modal-rise {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1); }
}

/* WHY 16.2 — drawer slide-in from right edge, 240ms ease-out. */
.pr-drawer-panel {
  animation: prisma-drawer-in .24s cubic-bezier(.22, 1, .36, 1);
  will-change: transform, opacity;
}
@keyframes prisma-drawer-in {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* WHY 16.3 — sidebar active-rail grow-in. ::after pseudo so scaleY 0→1
   can animate; origin centre so the rail expands from the middle outward. */
.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-row.active,
.tabs-bar.tabs-side .tab-btn.active { position: relative; }
.tabs-side .tab-row.active::after,
.tabs-bar.tabs-side .tab-row.active::after,
.tabs-bar.tabs-side .tab-btn.active::after {
  content: '';
  position: absolute;
  left: 0; top: 6px; bottom: 6px;
  width: 2px;
  background: var(--accent);
  border-radius: 1px;
  transform: scaleY(0);
  transform-origin: 50% 50%;
  animation: prisma-rail-in .18s cubic-bezier(.22, 1, .36, 1) forwards;
}
@keyframes prisma-rail-in {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

/* WHY 16.4 — primary button press scale; tactile "give" only on solid CTAs. */
.pc-btn--primary:active,
.card > form button[type="submit"]:active,
.card button[type="submit"]:active,
form#form button[type="submit"]:active {
  transform: translateY(1px) scale(.985);
}

/* WHY 16.5 — card hover lift: 1px translateY, barely perceptible. */
:where(.pc-card, .sec-card, .bill-card, .domain-card,
       .portfolio-health, .ph-tile, .pc-callout, .pos-intro) {
  transition: border-color .15s, box-shadow .15s, transform .15s cubic-bezier(.22, 1, .36, 1);
}
:where(.pc-card, .sec-card, .bill-card, .domain-card,
       .portfolio-health, .ph-tile, .pc-callout, .pos-intro):hover {
  transform: translateY(-1px);
}

/* WHY 16.6 — focus ring snap-in: outline-offset 4→2px over 120ms. */
:where(a, button, [role="button"], [role="tab"], [role="menuitem"],
       input, select, textarea, summary, [tabindex]) {
  transition: outline-offset .12s cubic-bezier(.22, 1, .36, 1);
}
:where(a, button, [role="button"], [role="tab"], [role="menuitem"],
       input, select, textarea, summary, [tabindex]):focus-visible {
  outline-offset: 2px;
}
:where(a, button, [role="button"], [role="tab"], [role="menuitem"],
       input, select, textarea, summary, [tabindex]):not(:focus-visible) {
  outline-offset: 4px;
}

/* WHY 16.7 — score-pill data-arrival; forward-compatible (no JS today). */
.score-pill.has-value .val,
.score-pill.has-value .score-pill-n {
  animation: prisma-score-in .22s cubic-bezier(.22, 1, .36, 1);
  transform-origin: 50% 100%;
}
@keyframes prisma-score-in {
  from { opacity: 0; transform: scale(.85); }
  to   { opacity: 1; transform: scale(1); }
}

/* WHY 16.8 — glass-modal sheen on :focus-within. Single 600ms diagonal
   pass, ~8% white at peak. Reserved for modals; cards stay sheen-free. */
.pc-modal-box { position: relative; overflow: hidden; }
.pc-modal-box::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg,
    transparent 30%,
    rgba(255,255,255,0.06) 50%,
    transparent 70%);
  transform: translateX(-100%);
  pointer-events: none;
  opacity: 0;
  z-index: 0;
}
.pc-modal-box:focus-within::before {
  animation: glass-sheen .6s cubic-bezier(.4, 0, .2, 1) forwards;
}
.pc-modal-box > * { position: relative; z-index: 1; }
@keyframes glass-sheen {
  0%   { transform: translateX(-100%); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translateX(100%); opacity: 0; }
}

/* WHY 16.9 — toast slide-in refinement; same transform, smoother stop. */
.prisma-toast {
  animation: prisma-toast-in .2s cubic-bezier(.22, 1, .36, 1);
}

/* WHY 16.10 — reduced-motion explicit transform-fallback (the global
   prisma-base.css §4 only catches transition/animation durations). */
@media (prefers-reduced-motion: reduce) {
  .pc-modal-box, .onboarding-box, .ai-modal-box, .ask-ai-modal,
  .ai-full-modal, .pr-drawer-panel, .prisma-toast {
    animation: none !important;
  }
  .tabs-side .tab-row.active::after,
  .tabs-bar.tabs-side .tab-row.active::after,
  .tabs-bar.tabs-side .tab-btn.active::after {
    animation: none !important;
    transform: scaleY(1) !important;
  }
  .pc-btn--primary:active,
  .card > form button[type="submit"]:active,
  .card button[type="submit"]:active,
  form#form button[type="submit"]:active {
    transform: translateY(1px) !important;
  }
  :where(.pc-card, .sec-card, .bill-card, .domain-card,
         .portfolio-health, .ph-tile, .pc-callout, .pos-intro):hover {
    transform: none !important;
  }
  :where(a, button, [role="button"], [role="tab"], [role="menuitem"],
         input, select, textarea, summary, [tabindex]):not(:focus-visible) {
    outline-offset: 2px !important;
  }
  .score-pill.has-value .val,
  .score-pill.has-value .score-pill-n {
    animation: none !important;
  }
  .pc-modal-box::before { display: none !important; }
}


/* ════════════════════════════════════════════════════════════════════
   ── 17. ICONOGRAPHY ────────────────────────────────────────────────
   Analyzer ships ~200 inline <svg class="ico"> with drift in stroke-
   width (1.5-3) and size (10-18). CSS `stroke-width` overrides the
   SVG attribute on inline SVGs, so we snap everything to one weight
   and a 4-step scale without touching markup.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 17.1 — single stroke weight (matches sidebar nav, the most-
   visible cluster). */
svg.ico { stroke-width: 1.6; }

/* WHY 17.2 — size scale xs(12) / sm(14) / md(16) / lg(20) / xl(24).
   Snaps orphaned 10/11/13 sizes; keeps intentional 6px dots (§2.7). */
svg.ico              { width: 14px; height: 14px; }
svg.ico[width="10"],
svg.ico[width="11"],
svg.ico[width="13"]  { width: 12px; height: 12px; }
svg.ico[width="12"]  { width: 12px; height: 12px; }
svg.ico[width="6"]   { width: 6px;  height: 6px;  }
svg.ico[width="16"]  { width: 16px; height: 16px; }
svg.ico[width="18"],
svg.ico[width="20"]  { width: 20px; height: 20px; }
svg.ico[width="22"],
svg.ico[width="24"]  { width: 24px; height: 24px; }

/* WHY 17.3 — emphasis icons inside loud surfaces keep stroke 2. */
.badge svg.ico,
.tag-ai svg.ico,
.kpi-trend svg.ico,
.btn-primary svg.ico,
.pill-new svg.ico,
.toast-error svg.ico,
.toast-warn svg.ico  { stroke-width: 2; }

/* WHY 17.4 — currentColor inheritance for parent-tinted icons. */
.pc-topbar svg.ico,
.pc-modal-hdr svg.ico,
.prisma-api-modal .modal-head svg.ico,
.audit-detail-panel svg.ico,
.pr-drawer-hdr svg.ico,
.kf-cell svg.ico,
.tab-content svg.ico { color: inherit; }

/* WHY 17.5 — flex alignment: never squeeze the leading glyph; baseline-align. */
svg.ico {
  flex-shrink: 0;
  vertical-align: -0.125em;
}

/* WHY 17.6 — modal/dialog header icons at sm (14px) to match topbar. */
.pc-modal-hdr > svg.ico,
.prisma-api-modal .modal-head > svg.ico,
.audit-detail-panel > .hdr > svg.ico,
.pr-drawer-hdr > svg.ico  { width: 14px; height: 14px; stroke-width: 1.6; }

/* WHY 17.7 — JS-rendered check / spinner glyphs (analyzer.html:4768,
   5904, 9156 ship stroke-width="3"/"2.5"). Property wins over attribute. */
.step-icon svg,
.kf-cell svg              { stroke-width: 1.6; }

/* WHY 17.8 — smooth tint transition on sidebar icons (matches the row). */
.tabs-side .tab-row svg.ico,
.tabs-bar.tabs-side .tab-row svg.ico,
.tabs-bar.tabs-side .tab-btn svg.ico {
  transition: color 120ms ease;
}

/* WHY 17.9 — light theme bumps stroke so the line stays optically
   equal to dark mode against near-white. */
[data-theme="light"] svg.ico              { stroke-width: 1.75; }
[data-theme="light"] .badge svg.ico,
[data-theme="light"] .tag-ai svg.ico,
[data-theme="light"] .btn-primary svg.ico { stroke-width: 2; }

/* WHY 17.10 — terminal (cream) shaves stroke for a tighter editorial
   register; emphasis stays at 1.9 against the warm paper. */
[data-theme="light"][data-variant="terminal"] svg.ico { stroke-width: 1.5; }
[data-theme="light"][data-variant="terminal"] .badge svg.ico,
[data-theme="light"][data-variant="terminal"] .tag-ai svg.ico,
[data-theme="light"][data-variant="terminal"] .btn-primary svg.ico { stroke-width: 1.9; }

/* WHY 17.11 — reduced-motion respects the new color-transition. */
@media (prefers-reduced-motion: reduce) {
  .tabs-side .tab-row svg.ico,
  .tabs-bar.tabs-side .tab-row svg.ico,
  .tabs-bar.tabs-side .tab-btn svg.ico { transition: none; }
}


/* ════════════════════════════════════════════════════════════════════
   ── 19. TYPE SYSTEM CONSOLIDATION ──────────────────────────────────
   Re-map drifting font-size / weight / letter-spacing / line-height
   onto the 8-step token scale + .t-* utility classes. No new sizes.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 19.1 — body floor: analyzer + dashboard inline blocks set 14/1.55;
   token spec is 13/1.5. */
body.has-pc-topbar,
body:where([data-page="analyzer"], [data-page="dashboard"]),
.analysis-content,
.app-content {
  font-size: var(--text-body-size);
  line-height: var(--text-body-lh);
}

/* WHY 19.2 — KPI numeric display: one display scale (22/500) for card
   metrics, hero scale (30/500) for the dashboard 4-up + analyzer ring. */
:where(
  .dash-stat-n, .score-mini-n, .sub-score-val, .sr-cell-n,
  .ph-tile .ph-score, .gauge-num, .sec-score-num
) {
  font: var(--text-display-weight) var(--text-display-size)/var(--text-display-lh) var(--font-display);
  letter-spacing: var(--tracking-tight);
  font-feature-settings: 'tnum' 1, 'ss01' 1;
  color: var(--text);
}
.dash-hero .dash-stats .dash-stat-n,
.score-number {
  font: var(--text-hero-weight) var(--text-hero-size)/var(--text-hero-lh) var(--font-display);
  letter-spacing: var(--tracking-tight);
  font-feature-settings: 'tnum' 1, 'ss01' 1;
}
.score-section .score-number {
  font-weight: 400;
  letter-spacing: -0.025em;
}

/* WHY 19.3 — KPI mono caption: 7 letter-spacings × 4 sizes × 3 weights
   collapse to .t-label (11/0.6px) or .t-micro (9.5/0.5px). */
:where(
  .dash-stat-l, .score-mini-l, .sub-score-label, .sr-cell-l,
  .psi-metric-label, .orgkw-metric-label, .sm-stat-lbl, .bp-label,
  .pr-section-title, .pr-crux-metric, .plan-name, .lg-title
) {
  font: var(--text-label-weight) var(--text-label-size)/var(--text-label-lh) var(--font-mono);
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-3);
}
:where(
  .app-nav-label, .app-brand-sub, .gauge-lab,
  .sub-bar .sb-lab, .sub-bar .sb-w,
  .rank-table thead th, .ggc-pill-select label, .ggc-gp-tag,
  .ggc-gp-nums .nl, .ggc-solv-bar .sb-lab, .ggc-diff-head .dh-tag,
  .tool-cat-pill, .tab-group-label, .range-chip,
  .spark-legend-inline, .spark-meta, .spark-caption-dates
) {
  font: var(--text-micro-weight) var(--text-micro-size)/var(--text-micro-lh) var(--font-mono);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-3);
}

/* WHY 19.4 — table headers: unify mono-caps idiom (was 5 sizes × 6 trackings). */
:where(
  .dash-table thead th, .pos-table thead th, .sm-table thead th,
  .kf-table thead th, .orgkw-table thead th,
  .priority-table thead th, .hist-table thead th, .compare thead th
) {
  font: 600 10px/1.2 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* WHY 19.5 — section titles (cross-cut). Three competing rules; pin
   any unscoped .section-title to the title scale; SWEEP §3.10 keeps
   the analyzer-scoped variant. */
.section-title:not(.hero .section-title):not(.analysis-content > section > .section-title) {
  font: var(--text-title-weight) var(--text-title-size)/var(--text-title-lh) var(--font-display);
  letter-spacing: var(--tracking-tight);
  color: var(--text);
}
:where(
  .card-domain, .check-title, .snippet-title, .gen-card-title,
  .sec-card-name, .gen-intro h3, .sec-info h3, .ais-stub strong
) {
  font: var(--text-strong-weight) var(--text-strong-size)/var(--text-strong-lh) var(--font-ui);
  letter-spacing: -0.005em;
  color: var(--text);
}

/* WHY 19.6 — editorial serif accent for naked <em> in dashboard hero
   (and any .page-hero h1) — SWEEP §1.6 covered .hero h1 em only. */
.dash-hero-title-compact em,
.dash-hero-title em,
.page-hero h1 em {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--text);
}

/* WHY 19.7 — weight 700 → 600 downgrade. Geist 700 reads heavier than
   the rest of the UI grid; reserved for hero. Most product chrome was
   using 700 incorrectly. */
:where(
  .logo, .ai-status, .geo-yes, .geo-no, .check-pill,
  .geo-score, .pt-badge, .pos-pill, .pos-type,
  .ph-tile .ph-score, .pos-table th, .priority-table th,
  .dash-table th, .sm-table th, .hist-table th,
  .empty-title, .field-label, .sec-server-chip,
  .sec-card-weight, .sec-url-tag, .copy-btn
) {
  font-weight: 600;
}

/* WHY 19.8 — line-height normalisation (1.55 → 1.5). */
:where(.muted, .card p.muted, .sub, .row, .ph-hint, .sec-hint, .sr-hint) {
  line-height: var(--text-body-lh);
}

/* WHY 19.9 — brand wordmark to italic Instrument Serif (matches
   SWEEP §1.8 .brand / .card-brand rule). */
.app-brand,
.app-brand-compact {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.025em;
}
.app-brand em { font-family: inherit; font-style: italic; }


/* ════════════════════════════════════════════════════════════════════
   ── 18. DATA VISUALIZATION ─────────────────────────────────────────
   ApexCharts + inline SVG charts onto the token palette. Series colors,
   gridlines, tooltips, axes, sparklines, progress bars, score donuts.
   JS-rendered hex (analyzer.html:3260, dashboard.html:2782/2787,
   admin-dashboard.html:2108) flagged for a follow-up code edit.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 18.0 — series-palette tokens. 7-stop qualitative scale built
   from existing semantic tokens; muted variants at 55% for sparklines. */
:root {
  --series-1: var(--accent);
  --series-2: var(--violet);
  --series-3: var(--blue);
  --series-4: var(--amber);
  --series-5: var(--pass);
  --series-6: var(--rose);
  --series-7: var(--text-3);
  --series-1-mute: color-mix(in oklab, var(--series-1) 55%, transparent);
  --series-2-mute: color-mix(in oklab, var(--series-2) 55%, transparent);
  --series-3-mute: color-mix(in oklab, var(--series-3) 55%, transparent);
  --series-4-mute: color-mix(in oklab, var(--series-4) 55%, transparent);
  --series-5-mute: color-mix(in oklab, var(--series-5) 55%, transparent);
  --series-6-mute: color-mix(in oklab, var(--series-6) 55%, transparent);
  --viz-grid:     var(--border);
  --viz-grid-2:   var(--border-2);
  --viz-axis-ink: var(--text-3);
  --viz-tip-bg:   var(--surface);
  --viz-tip-bd:   var(--border-2);
}

/* WHY 18.1 — ApexCharts tooltip on tokenised pane (was white/black). */
.apexcharts-tooltip.apexcharts-theme-dark,
.apexcharts-tooltip.apexcharts-theme-light,
.apexcharts-tooltip {
  background: var(--viz-tip-bg) !important;
  border: 1px solid var(--viz-tip-bd) !important;
  color: var(--text) !important;
  box-shadow: 0 8px 24px -8px rgba(0,0,0,.45) !important;
  border-radius: var(--radius-md) !important;
  font: 500 12px/1.4 var(--font-mono) !important;
}
.apexcharts-tooltip-title {
  background: var(--surface-2) !important;
  border-bottom: 1px solid var(--border) !important;
  color: var(--text-2) !important;
  font: 600 11px/1.3 var(--font-mono) !important;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.apexcharts-tooltip-series-group {
  background: transparent !important;
  padding: 4px 10px !important;
}
.apexcharts-tooltip-text-y-label,
.apexcharts-tooltip-text-y-value,
.apexcharts-tooltip-text-goals-label,
.apexcharts-tooltip-text-goals-value,
.apexcharts-tooltip-text-z-label,
.apexcharts-tooltip-text-z-value {
  color: var(--text) !important;
}
.apexcharts-tooltip-marker {
  border: 1px solid var(--border-2) !important;
}
.apexcharts-xaxistooltip,
.apexcharts-yaxistooltip {
  background: var(--surface) !important;
  border: 1px solid var(--border-2) !important;
  color: var(--text) !important;
  border-radius: var(--radius-sm) !important;
  font: 500 11px/1.3 var(--font-mono) !important;
}
.apexcharts-xaxistooltip-bottom::before { border-bottom-color: var(--border-2) !important; }
.apexcharts-xaxistooltip-bottom::after  { border-bottom-color: var(--surface) !important; }
.apexcharts-xaxistooltip-top::before    { border-top-color: var(--border-2) !important; }
.apexcharts-xaxistooltip-top::after     { border-top-color: var(--surface) !important; }

/* WHY 18.2 — axis labels demoted to --text-3 + tabular-nums. */
.apexcharts-xaxis-label,
.apexcharts-yaxis-label,
.apexcharts-yaxis-title text,
.apexcharts-xaxis-title text {
  fill: var(--viz-axis-ink) !important;
  font-family: var(--font-mono) !important;
  font-size: 11px !important;
  font-variant-numeric: tabular-nums;
}
.apexcharts-legend-text {
  color: var(--text-2) !important;
  font: 500 12px/1.4 var(--font-ui) !important;
}
.apexcharts-text title { font: 500 11px var(--font-mono); }

/* WHY 18.3 — gridlines to --border dashed; zero-line to --border-2 solid. */
.apexcharts-grid line,
.apexcharts-gridline {
  stroke: var(--viz-grid) !important;
  stroke-dasharray: 3 3;
  opacity: .85;
}
.apexcharts-grid-borders line {
  stroke: var(--viz-grid-2) !important;
  stroke-dasharray: 0;
}
.apexcharts-xaxis line,
.apexcharts-yaxis line {
  stroke: var(--viz-grid) !important;
}
.apexcharts-zero-line {
  stroke: var(--viz-grid-2) !important;
  stroke-dasharray: 0;
}

/* WHY 18.4 — data labels demoted to --text-2 mono + tabular-nums. */
.apexcharts-datalabel,
.apexcharts-datalabel-label,
.apexcharts-datalabel-value {
  fill: var(--text-2) !important;
  font-family: var(--font-mono) !important;
  font-variant-numeric: tabular-nums;
}
.apexcharts-pie-label {
  fill: var(--text) !important;
  font-family: var(--font-mono) !important;
}

/* WHY 18.5 — score-tier histogram bars at 80% alpha (color-mix). */
.pc-histo-bar--fill { background: color-mix(in oklab, var(--pass) 80%, transparent); }
.pc-histo-bar--warn { background: color-mix(in oklab, var(--warn) 80%, transparent); }
.pc-histo-bar--neg  { background: color-mix(in oklab, var(--fail) 80%, transparent); }
.pc-histo-bar:hover { filter: brightness(1.12); }

/* WHY 18.6 — sparkline subtlety: muted series for density signal. */
.pc-spark-line { stroke: var(--series-1-mute); stroke-width: 1.3; }
.pc-spark-line--warn { stroke: var(--warn); }
.pc-spark-line--neg  { stroke: var(--fail); }
.pc-spark { opacity: .92; }
.pc-spark:hover { opacity: 1; }

/* WHY 18.7 — beat the analyzer.html:332 inline .pos-progress-bar
   gradient via selector specificity (no !important needed). */
.pos-progress-wrap .pos-progress-bar,
.pos-progress-wrap > .pos-progress-bar {
  background: var(--accent);
  background-image: none;
}

/* WHY 18.8 — score donut tokens (lock against SVG attribute drift). */
.ring-bg,
.gauge-arc-bg,
circle.ring-bg {
  stroke: var(--surface-3);
}
.ring-fill {
  stroke: var(--accent);
}

/* WHY 18.9 — Apex legend marker pin: 10×2px hairline. */
.apexcharts-marker { stroke: transparent !important; }
.apexcharts-legend-marker {
  border: 0 !important;
  width: 10px !important;
  height: 2px !important;
  border-radius: 1px !important;
  margin-right: 6px !important;
  transform: translateY(-1px);
}

/* WHY 18.10 — light theme tooltip + gridline overrides. */
[data-theme="light"] .apexcharts-tooltip,
[data-theme="light"] .apexcharts-tooltip.apexcharts-theme-light,
[data-theme="light"] .apexcharts-tooltip.apexcharts-theme-dark {
  background: var(--bg-elev) !important;
  border-color: var(--border-2) !important;
  box-shadow: 0 8px 24px -8px rgba(15,17,22,.18) !important;
  color: var(--text) !important;
}
[data-theme="light"] .apexcharts-tooltip-title {
  background: var(--surface-2) !important;
  color: var(--text-2) !important;
}
[data-theme="light"] .apexcharts-grid line,
[data-theme="light"] .apexcharts-gridline {
  stroke: var(--border) !important;
  opacity: .9;
}

/* WHY 18.11 — terminal variant: sparkline 70% (vs 55%) + tooltip on
   --bg-elev; histogram bars 88% alpha. */
[data-theme="light"][data-variant="terminal"] {
  --series-1-mute: color-mix(in oklab, var(--accent) 70%, transparent);
  --series-2-mute: color-mix(in oklab, var(--violet) 70%, transparent);
  --series-3-mute: color-mix(in oklab, var(--blue) 70%, transparent);
  --series-4-mute: color-mix(in oklab, var(--amber) 70%, transparent);
}
[data-theme="light"][data-variant="terminal"] .apexcharts-tooltip {
  background: var(--bg-elev) !important;
  border-color: var(--border-2) !important;
  color: var(--text) !important;
  font-family: var(--font-mono) !important;
  border-radius: var(--radius-sm) !important;
}
[data-theme="light"][data-variant="terminal"] .apexcharts-xaxis-label,
[data-theme="light"][data-variant="terminal"] .apexcharts-yaxis-label,
[data-theme="light"][data-variant="terminal"] .apexcharts-legend-text {
  fill: var(--text-3) !important;
  color: var(--text-3) !important;
}
[data-theme="light"][data-variant="terminal"] .pc-histo-bar--fill { background: color-mix(in oklab, var(--pass) 88%, transparent); }
[data-theme="light"][data-variant="terminal"] .pc-histo-bar--warn { background: color-mix(in oklab, var(--warn) 88%, transparent); }
[data-theme="light"][data-variant="terminal"] .pc-histo-bar--neg  { background: color-mix(in oklab, var(--fail) 88%, transparent); }

/* WHY 18.12 — reduced-motion + forced-colors safety. */
@media (prefers-reduced-motion: reduce) {
  .apexcharts-grid line,
  .apexcharts-legend-marker,
  .apexcharts-tooltip { transition: none !important; }
}
@media (forced-colors: active) {
  .apexcharts-tooltip,
  .apexcharts-xaxistooltip,
  .apexcharts-yaxistooltip {
    background: Canvas !important;
    color: CanvasText !important;
    border-color: CanvasText !important;
  }
  .apexcharts-grid line { stroke: GrayText !important; }
  .pc-histo-bar--fill,
  .pc-histo-bar--warn,
  .pc-histo-bar--neg { forced-color-adjust: none; }
}


/* ════════════════════════════════════════════════════════════════════
   ── 20. STATUS BANNERS & ALERTS ────────────────────────────────────
   Convergence pass on .alert-banner / .pc-callout / .bill-usage-nudge /
   .server-banner / #offline-notice / .prisma-toast / .card .toast /
   empty-states. Unified grid (icon | body | action), inset top
   highlight, semantic top hairline + matching gradient wash.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 20.0 — status-scoped tokens (12% mix is loud enough to register,
   quiet enough not to compete with cards). */
:root {
  --status-tint:        12%;
  --status-tint-strong: 18%;
  --status-edge-warn:   color-mix(in oklab, var(--warn) var(--status-tint), transparent);
  --status-edge-err:    color-mix(in oklab, var(--fail) var(--status-tint), transparent);
  --status-edge-ok:     color-mix(in oklab, var(--pass) var(--status-tint), transparent);
  --status-edge-info:   color-mix(in oklab, var(--info) var(--status-tint), transparent);
  --status-highlight:   rgba(255,255,255,.04);
  --status-radius:      var(--radius-md);
  --status-blur:        blur(16px) saturate(150%);
}

/* WHY 20.1 — unified shell with auto 1fr auto grid for icon|body|action. */
.alert-banner,
.pc-callout,
.bill-usage-nudge,
.server-banner,
#offline-notice,
.card .toast {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 2px solid var(--border);
  border-radius: var(--status-radius);
  box-shadow: inset 0 1px 0 var(--status-highlight);
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  font: 500 13px/1.5 var(--font-ui);
  color: var(--text-2);
  text-align: left;
}
.alert-banner > svg, .pc-callout > svg,
.bill-usage-nudge > svg, #offline-notice > svg,
.card .toast > svg {
  flex-shrink: 0;
}
.alert-banner :where(b, strong),
.pc-callout :where(b, strong),
.bill-usage-nudge :where(b, strong),
#offline-notice :where(b, strong),
.card .toast :where(b, strong) { color: var(--text); font-weight: 600; }

/* WHY 20.2 — semantic full-box border identifies the kind without flooding
   the surface with tinted backgrounds. */
.pc-callout--ok,
.bill-usage-nudge.is-ok,
.card .toast.ok    { border-color: var(--pass); }
.pc-callout--warn,
.bill-usage-nudge.is-warn,
.server-banner,
#offline-notice,
.card .toast.warn  { border-color: var(--warn); }
.alert-banner,
.pc-callout--err,
.bill-usage-nudge.is-danger,
.server-banner.error,
.card .toast.err   { border-color: var(--fail); }
.pc-callout--info,
.card .toast.info  { border-color: var(--info); }

/* WHY 20.3 — sticky/full-bleed banners get §14 nav-glass treatment. */
#offline-notice.show,
.server-banner:not([style*="display:none"]),
#serverBanner {
  background-color: color-mix(in oklab, var(--surface) 80%, transparent);
  -webkit-backdrop-filter: var(--status-blur);
          backdrop-filter: var(--status-blur);
  box-shadow: inset 0 1px 0 var(--status-highlight),
              0 4px 12px -6px rgba(0,0,0,.35);
}

/* WHY 20.4 — neutralise the inline-styled <code> in dash.offlineNotice
   (rgba(245,158,11,.2) saturated chip → tokenised mono inline). */
#offline-notice code,
.alert-banner code,
.pc-callout code {
  background: var(--surface-2) !important;
  color: var(--text) !important;
  font: 500 12px/1.4 var(--font-mono);
  padding: 1px 6px !important;
  border-radius: 4px !important;
  border: 1px solid var(--border) !important;
}

/* WHY 20.5 — leading-icon tint matches the accent for each variant. */
.pc-callout--ok    > svg.ico, .card .toast.ok   > svg.ico { color: var(--pass); }
.pc-callout--warn  > svg.ico, .card .toast.warn > svg.ico,
.server-banner     > svg.ico, #offline-notice   > svg.ico { color: var(--warn); }
.pc-callout--err   > svg.ico, .alert-banner     > svg.ico,
.card .toast.err   > svg.ico, .server-banner.error > svg.ico { color: var(--fail); }
.pc-callout--info  > svg.ico, .card .toast.info > svg.ico { color: var(--info); }

/* WHY 20.6 — trailing action: any <button>/<a>:last-child becomes a
   compact ghost (so retry/learn-more/dismiss read as one shape). */
.alert-banner > :where(button, a):last-child,
.pc-callout   > :where(button, a):last-child,
.bill-usage-nudge > :where(button, a):last-child,
#offline-notice > :where(button, a):last-child {
  font: 500 12px/1 var(--font-ui);
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-2);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s ease, border-color .15s ease;
}
.alert-banner > :where(button, a):last-child:hover,
.pc-callout   > :where(button, a):last-child:hover,
.bill-usage-nudge > :where(button, a):last-child:hover,
#offline-notice > :where(button, a):last-child:hover {
  background: var(--surface-3); border-color: var(--text-3);
}

/* WHY 20.7 — .prisma-toast icon tint + .dismiss polish.
   Semantic identification now lives on the full-box border (prisma-base.css). */
.prisma-toast[data-kind="ok"]   > svg.ico { color: var(--pass); }
.prisma-toast[data-kind="warn"] > svg.ico { color: var(--warn); }
.prisma-toast[data-kind="err"]  > svg.ico { color: var(--fail); }
.prisma-toast[data-kind="info"] > svg.ico { color: var(--info); }
.prisma-toast button.dismiss {
  align-self: start;
  margin-left: auto;
  border-radius: var(--radius-xs);
  transition: color .15s ease, background .15s ease;
}
.prisma-toast button.dismiss:hover {
  color: var(--text);
  background: var(--surface-hover);
}

/* WHY 20.8 — empty-states gain inset highlight + accent-soft wash. */
.ais-stub,
.empty-stub,
.mw-empty,
.hist-empty {
  box-shadow: inset 0 1px 0 var(--status-highlight);
  background-image:
    linear-gradient(to bottom,
      color-mix(in oklab, var(--accent) 5%, transparent) 0,
      transparent 64px);
}
.ais-stub > svg.ico:first-child,
.empty-stub > svg.ico:first-child {
  display: block;
  margin: 0 auto 14px;
  width: 28px; height: 28px;
  color: var(--text-3);
  stroke-width: 1.4;
}

/* WHY 20.9 — page-level error / session-required: full-box --fail border. */
:where(.ais-stub, .empty-stub).is-error,
:where(.ais-stub, .empty-stub)[data-state="error"],
.page-error, .page-404, .page-500 {
  border-color: var(--fail);
}

/* WHY 20.10 — override the dashboard.html:867 + analyzer.html:1727
   mono-font override so the §20.1 grid wins. */
:where(#offline-banner, #serverBanner, .server-banner, #offline-notice) {
  font-family: var(--font-ui);
  font-size: 13px;
  letter-spacing: normal;
  border-radius: var(--status-radius);
  border-width: 1px;
}

/* WHY 20.11 — light theme: warmer wash, inverted highlight. */
[data-theme="light"] {
  --status-tint:        14%;
  --status-tint-strong: 22%;
  --status-highlight:   rgba(255,255,255,.55);
}

/* WHY 20.12 — terminal cream: deepest wash, squarer radius, lighter icon. */
[data-theme="light"][data-variant="terminal"] {
  --status-tint:        16%;
  --status-tint-strong: 24%;
  --status-highlight:   rgba(255,251,238,.65);
  --status-radius:      var(--radius-sm);
}
[data-theme="light"][data-variant="terminal"] :where(
  .alert-banner, .pc-callout, .bill-usage-nudge,
  .server-banner, #offline-notice, .card .toast,
  .prisma-toast) > svg.ico { stroke-width: 1.5; }

/* WHY 20.13 — reduced-transparency + reduced-motion safety. */
@media (prefers-reduced-transparency: reduce) {
  #offline-notice.show,
  .server-banner,
  #serverBanner {
    background-color: var(--surface);
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .alert-banner > :where(button, a),
  .pc-callout   > :where(button, a),
  #offline-notice > :where(button, a) { transition: none; }
}

/* WHY 20.14 — forced-colors: replace gradient wash with hard borders. */
@media (forced-colors: active) {
  .alert-banner, .pc-callout, .bill-usage-nudge,
  .server-banner, #offline-notice, .card .toast, .prisma-toast {
    background-image: none;
    border: 2px solid CanvasText;
    forced-color-adjust: none;
  }
}


/* ════════════════════════════════════════════════════════════════════
   ── 22. DROPDOWNS, TOOLTIPS, POPOVERS ──────────────────────────────
   Floating UI §15 didn't cover. Extends --glass-modal-tint-pop /
   blur-pop to the URL switcher, glossary popover, hover tooltip and
   chart tooltip; harmonises native <select> chevrons.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 22.1 — profile-dropdown trigger: click target + hover + focus. */
.profile-dropdown-trigger {
  border-radius: var(--radius-md);
  transition: background .12s, color .12s;
}
.profile-dropdown-trigger:hover,
.profile-dropdown.open .profile-dropdown-trigger {
  background: color-mix(in oklab, var(--surface-2) 70%, transparent);
  color: var(--text);
}
.profile-dropdown-trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* WHY 22.2 — profile-dropdown-list rides §15 glass-pop tier. */
.profile-dropdown-list {
  background: color-mix(in oklab, var(--surface) var(--glass-modal-tint-pop), transparent);
  -webkit-backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(160%);
          backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(160%);
  border: 1px solid var(--glass-modal-edge);
  box-shadow: 0 16px 40px -12px rgba(0,0,0,.50),
              inset 0 1px 0 var(--glass-modal-highlight);
  isolation: isolate;
}

/* WHY 22.3 — hover / keyboard-active share one visual; aria-selected
   uses inset rail (row height stable). */
.profile-dropdown-item:hover,
.profile-dropdown-item[data-active="true"],
.profile-dropdown-item:focus-visible {
  background: color-mix(in oklab, var(--surface-2) 80%, transparent);
  outline: none;
}
.profile-dropdown-item.selected,
.profile-dropdown-item[aria-selected="true"] {
  box-shadow: inset 2px 0 0 var(--accent);
}

/* WHY 22.4 — group header for future role="group" wrappers. */
.profile-dropdown-list [role="group"] > [role="presentation"],
.profile-dropdown-list .dropdown-group-label {
  display: block;
  padding: 8px 14px 4px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* WHY 22.5 — disabled option: 55% opacity (prisma-base §6 parity). */
.profile-dropdown-item[aria-disabled="true"],
.profile-dropdown-item:disabled {
  opacity: .55;
  cursor: not-allowed;
  background: transparent !important;
}

/* WHY 22.6 — empty-state row aligned to glass pane voice. */
.profile-dropdown-empty {
  font-family: var(--font-ui);
  letter-spacing: -.01em;
}

/* WHY 22.7 — glossary popover [role="tooltip"] (injected with inline
   style.cssText at analyzer.html:3752). */
[role="tooltip"] {
  background: color-mix(in oklab, var(--surface) var(--glass-modal-tint-pop), transparent) !important;
  -webkit-backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(160%);
          backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(160%);
  border: 1px solid var(--glass-modal-edge) !important;
  box-shadow: 0 14px 36px -8px rgba(0,0,0,.45),
              inset 0 1px 0 var(--glass-modal-highlight) !important;
  font-size: 12.5px;
  line-height: 1.5;
  isolation: isolate;
}

/* WHY 22.8 — legacy .tooltip-box / .help-tip / .tip-pane (smaller blur). */
.tooltip-box,
.help-tip,
.tip-pane {
  background: color-mix(in oklab, var(--surface) var(--glass-modal-tint-pop), transparent);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
          backdrop-filter: blur(14px) saturate(150%);
  border: 1px solid var(--glass-modal-edge);
  box-shadow: 0 10px 28px -6px rgba(0,0,0,.40),
              inset 0 1px 0 var(--glass-modal-highlight);
  border-radius: 10px;
  font-size: 12px;
  isolation: isolate;
}

/* WHY 22.9 — tooltip downward pointer via pseudo-element. */
.tooltip-box::after,
[role="tooltip"][data-arrow]::after {
  content: '';
  position: absolute;
  bottom: -5px;
  left: 50%;
  width: 8px;
  height: 8px;
  background: inherit;
  border-right: 1px solid var(--glass-modal-edge);
  border-bottom: 1px solid var(--glass-modal-edge);
  transform: translateX(-50%) rotate(45deg);
  -webkit-backdrop-filter: inherit;
          backdrop-filter: inherit;
}

/* WHY 22.10 — chart-tooltip (analyzer.html:2112) was pure-black. */
.chart-tooltip {
  background: color-mix(in oklab, var(--surface) var(--glass-modal-tint-pop), transparent);
  -webkit-backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(150%);
          backdrop-filter: blur(var(--glass-modal-blur-pop)) saturate(150%);
  border: 1px solid var(--glass-modal-edge);
  color: var(--text);
  box-shadow: 0 12px 28px -10px rgba(0,0,0,.50),
              inset 0 1px 0 var(--glass-modal-highlight);
  isolation: isolate;
}
.chart-tooltip .tt-month { color: var(--text-muted); }
.chart-tooltip .tt-row .val { color: var(--text); }

/* WHY 22.11 — native <select> outside .dash-toolbar gets the chevron. */
select:not(.toolbar-select):not(.sort-select):not([multiple]):not([size]) {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%236E747F' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 6l4 4 4-4'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
}

/* WHY 22.12 — color-scheme tells OS which native popup to draw. */
select { color-scheme: dark; }
[data-theme="light"] select { color-scheme: light; }

/* WHY 22.13 — light theme chevron stroke survives on cream paper. */
[data-theme="light"] select:not(.toolbar-select):not(.sort-select):not([multiple]):not([size]) {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%23596275' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 6l4 4 4-4'/></svg>");
}

/* WHY 22.14 — terminal variant: warmer chevron tone matches text muted. */
[data-theme="light"][data-variant="terminal"] select:not(.toolbar-select):not(.sort-select):not([multiple]):not([size]) {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%237a6a48' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 6l4 4 4-4'/></svg>");
}

/* WHY 22.15 — reduced-transparency: opaque fallback (mirrors §15.8). */
@media (prefers-reduced-transparency: reduce) {
  .profile-dropdown-list,
  [role="tooltip"],
  .tooltip-box, .help-tip, .tip-pane,
  .chart-tooltip {
    background: var(--surface) !important;
    -webkit-backdrop-filter: none !important;
            backdrop-filter: none !important;
    border-color: var(--border) !important;
  }
}

/* WHY 22.16 — @supports not (backdrop-filter) fallback. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .profile-dropdown-list,
  [role="tooltip"],
  .tooltip-box, .help-tip, .tip-pane,
  .chart-tooltip {
    background: var(--surface);
    border-color: var(--border);
  }
}

/* WHY 22.17 — reduced-motion: kill chevron rotation + hover transitions. */
@media (prefers-reduced-motion: reduce) {
  .profile-dropdown-trigger,
  .profile-dropdown-trigger svg,
  .profile-dropdown-item { transition: none !important; }
  .profile-dropdown.open .profile-dropdown-trigger svg { transform: rotate(180deg) !important; }
}


/* ════════════════════════════════════════════════════════════════════
   ── 21. FORM VALIDATION & STATES ───────────────────────────────────
   Canonical chrome for invalid / valid / disabled / readonly / required
   across auth, analyzer settings, agency invite, admin. CSS-only.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 21.1 — aria-invalid="true" (set by prismaShowFieldError) gets
   painted. Sighted users see what screen-readers already hear. */
input[aria-invalid="true"],
textarea[aria-invalid="true"],
select[aria-invalid="true"],
.field--error input, .field--error select, .field--error textarea,
.input--error {
  border-color: var(--fail) !important;
  background: color-mix(in oklab, var(--fail) 6%, var(--surface-2)) !important;
}
input[aria-invalid="true"]:focus,
textarea[aria-invalid="true"]:focus,
select[aria-invalid="true"]:focus,
.field--error input:focus, .field--error select:focus, .field--error textarea:focus,
.input--error:focus {
  border-color: var(--fail) !important;
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--fail) 22%, transparent) !important;
}

/* WHY 21.2 — kill the native :invalid pink halo on auth inputs so only
   our aria-invalid logic paints red. :placeholder-shown gate prevents
   mid-typing red flashes. */
.card input:invalid:not(:placeholder-shown):not(:focus),
.pc-field input:invalid:not(:placeholder-shown):not(:focus),
.field input:invalid:not(:placeholder-shown):not(:focus) {
  border-color: var(--border);
  box-shadow: none;
}

/* WHY 21.3 — :valid stays neutral; only opt-in .field--ok paints green
   (so a correctly-typed email doesn't prematurely declare success). */
.field--ok input, .field--ok select, .field--ok textarea,
input.input--ok, .pc-field--ok input {
  border-color: var(--pass) !important;
}
.field--ok input:focus, .field--ok select:focus, .field--ok textarea:focus {
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--pass) 22%, transparent) !important;
}

/* WHY 21.4 — canonical disabled opacity .55 (matches .btn-primary).
   signup.html .6 / analyzer .45 / admin .5 all converge here. */
:where(
  button, [role="button"], input, select, textarea
):disabled,
:where(
  button, [role="button"], input, select, textarea
)[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}
input[readonly], textarea[readonly] {
  opacity: 1;
  cursor: not-allowed;
  background: var(--surface-3, var(--surface-2));
  color: var(--text-2);
}

/* WHY 21.5 — required asterisk.
   F12 (2026-05-16): the :has() pseudo-class is broken in Safari ≤15.4 and
   Firefox ≤120, so we ship an explicit `.field-required` class on the label
   (or legacy `<span class="req-asterisk">*</span>` inline) and style it here. */
.req-asterisk {
  color: var(--danger, #dc2626);
  font-weight: 600;
  margin-left: 2px;
}
.field-required::after {
  content: " *";
  color: var(--danger, #dc2626);
  font-weight: 600;
}

/* WHY 21.5b — password visibility toggle (F31). Positions an eye-icon
   button inside the right edge of a password input without disturbing the
   field's existing border/padding. */
.password-wrap {
  position: relative;
  display: block;
}
.password-wrap > input {
  width: 100%;
  padding-right: 44px;
}
.password-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  min-width: 36px;
  min-height: 36px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: var(--text-2, var(--text-muted));
  cursor: pointer;
  transition: background .14s ease, color .14s ease;
}
.password-toggle:hover { color: var(--text); background: color-mix(in oklab, var(--text) 6%, transparent); }
.password-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
@media (max-width: 768px) {
  .password-toggle { min-width: 44px; min-height: 44px; }
}

/* WHY 21.6 — field hint + error: canonical typography. */
.field-hint, .pc-field__hint, .input-hint, .form-hint {
  font: 400 11.5px/1.45 var(--font-ui);
  color: var(--text-3);
  margin-top: 5px;
}
.field-error, .pc-field__error, .input-error, .form-error {
  font: 500 11.5px/1.45 var(--font-ui);
  color: var(--fail);
  margin-top: 5px;
  display: flex;
  align-items: flex-start;
  gap: 5px;
}
.field-error::before, .pc-field__error::before {
  content: "!";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--fail);
  color: var(--bg);
  font: 700 9px/1 var(--font-mono);
  flex-shrink: 0;
  margin-top: 2px;
}

/* WHY 21.7 — submit "loading" state. aria-busy="true" (set by
   prismaLockSubmit) shows a spinner so the user knows it's working,
   not just disabled. */
button[aria-busy="true"], [role="button"][aria-busy="true"] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
button[aria-busy="true"]::after, [role="button"][aria-busy="true"]::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 16px; height: 16px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  color: var(--accent-ink);
  animation: pc-spin 0.7s linear infinite;
}
.pc-btn--ghost[aria-busy="true"]::after,
.pc-btn--secondary[aria-busy="true"]::after,
.btn-ghost[aria-busy="true"]::after,
.btn-secondary[aria-busy="true"]::after {
  color: var(--accent);
}
@keyframes pc-spin { to { transform: rotate(360deg); } }

/* WHY 21.8 — checkbox + radio: teal accent-color (one-liner skins the
   native control across signup TOS / login remember-me / admin filters). */
input[type="checkbox"], input[type="radio"] {
  accent-color: var(--accent);
  width: 16px;
  height: 16px;
  cursor: pointer;
}
input[type="checkbox"]:disabled, input[type="radio"]:disabled {
  cursor: not-allowed;
}
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* WHY 21.9 — textarea baseline: vertical resize only, min-height 80px. */
textarea {
  resize: vertical;
  min-height: 80px;
  line-height: 1.5;
}

/* WHY 21.10 — password-strength meter track to --surface-3 so the empty
   track recedes (was rendering as a hard divider via inline JS background). */
input[type="password"] + span + div[style*="height:3px"],
span:has(> input[type="password"]) + div[style*="height:3px"] {
  background: var(--surface-3) !important;
  border-radius: 2px;
}

/* WHY 21.11 — OTP invalid state pairs §10.5 with red halo + shake. */
.field.otp input[aria-invalid="true"] {
  border-color: var(--fail) !important;
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--fail) 22%, transparent) !important;
  animation: pc-shake 0.32s ease-in-out;
}
@keyframes pc-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}

/* WHY 21.12 — light theme: stronger fail tint on near-white. */
[data-theme="light"] input[aria-invalid="true"],
[data-theme="light"] textarea[aria-invalid="true"],
[data-theme="light"] select[aria-invalid="true"] {
  background: color-mix(in oklab, var(--fail) 10%, var(--surface-2)) !important;
}
[data-theme="light"] .field-error::before,
[data-theme="light"] .pc-field__error::before {
  color: #fff;
}

/* WHY 21.13 — terminal cream: less saturated blend, square error glyph. */
[data-theme="light"][data-variant="terminal"] input[aria-invalid="true"],
[data-theme="light"][data-variant="terminal"] textarea[aria-invalid="true"] {
  background: var(--surface-2) !important;
  border-color: var(--fail) !important;
}
[data-theme="light"][data-variant="terminal"] .field-error::before,
[data-theme="light"][data-variant="terminal"] .pc-field__error::before {
  border-radius: 2px;
}

/* WHY 21.14 — reduced-motion: static busy spinner + no OTP shake. */
@media (prefers-reduced-motion: reduce) {
  button[aria-busy="true"]::after,
  [role="button"][aria-busy="true"]::after {
    animation: none;
    border-top-color: currentColor;
    opacity: 0.5;
  }
  .field.otp input[aria-invalid="true"] {
    animation: none;
  }
}

/* ── 22. PUBLIC PAGES — pricing / login / signup polish ─────────────
   Cross-page primitives added 2026-05-16 to lift pricing.html, login.html
   and signup.html to a Linear/Vercel/Stripe-grade feel. These pages are
   the first paid surface a prospect sees; the system above is generally
   product-shell. This section is a curated "marketing-shell" set that
   covers: ambient page background, scrollytelling-grade hero, pricing-
   card polish, comparison-table densification, FAQ rhythm, auth-card
   refinement, customer-logo strip, footnote rhythm.

   Naming convention: every selector starts with `.pp-` (public page)
   so collisions with the product shell remain impossible. The 3 pages
   opt in by class — none of these rules are body-wide. */

/* 22.1 — Ambient page background. A single, very low-amplitude radial
   gradient anchored top-centre on dark, top-left on light. Replaces the
   flat near-black void from the previous build. No motion (avoid
   AI-glow tells); pure colour-temperature shift. */
body.pp-page {
  background:
    radial-gradient(1200px 600px at 50% -200px, rgba(61,219,194,0.06), transparent 70%),
    radial-gradient(900px 500px at 100% 100%, rgba(181,139,232,0.04), transparent 70%),
    var(--bg);
  background-attachment: fixed;
}
[data-theme="light"] body.pp-page {
  background:
    radial-gradient(1200px 600px at 50% -200px, rgba(15,138,119,0.05), transparent 70%),
    radial-gradient(900px 500px at 100% 100%, rgba(15,138,119,0.03), transparent 70%),
    var(--bg);
}

/* 22.2 — Public topbar. The pricing & signup pages share the same
   "marketing topbar" — wordmark + nav + lang toggle, with a hairline
   bottom border that fades on scroll (no JS — uses backdrop blur for
   a subtle separation regardless of scroll position). */
.pp-topbar {
  position: sticky; top: 0; z-index: var(--z-sticky, 100);
  display: flex; align-items: center; gap: 18px;
  padding: 14px clamp(16px, 4vw, 36px);
  background: color-mix(in oklab, var(--bg) 78%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--border);
}
.pp-topbar__brand {
  font-family: var(--font-serif, 'Instrument Serif', Georgia, serif);
  font-style: italic; font-weight: 400;
  font-size: 24px; letter-spacing: -0.025em;
  color: var(--text);
  text-decoration: none;
  display: inline-flex; align-items: center; gap: 10px;
  transition: opacity .15s;
}
.pp-topbar__brand:hover { opacity: 0.82; text-decoration: none; }
.pp-topbar__spacer { flex: 1; }
.pp-topbar__nav { display: flex; align-items: center; gap: 6px; }
.pp-topbar__nav a {
  color: var(--text-2);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  padding: 7px 11px;
  border-radius: 7px;
  transition: color .15s, background .15s;
}
.pp-topbar__nav a:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.pp-topbar__nav a.cta {
  color: var(--accent-ink);
  background: var(--accent);
  font-weight: 600;
}
.pp-topbar__nav a.cta:hover { background: var(--accent-3); color: var(--accent-ink); }
@media (max-width: 560px) {
  .pp-topbar { gap: 10px; padding: 12px 14px; flex-wrap: wrap; }
  .pp-topbar__nav { gap: 2px; flex-wrap: wrap; }
  .pp-topbar__nav a { padding: 6px 9px; font-size: 13px; }
}

/* 22.3 — Lang toggle (consistent across all public pages). Sits inside
   .pp-topbar but can be used standalone (login.html does this). */
.pp-lang {
  display: inline-flex; gap: 2px;
  padding: 3px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 99px;
}
.pp-lang button {
  appearance: none;
  background: transparent; border: 0;
  color: var(--text-3);
  font: 600 10.5px/1 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.06em;
  padding: 5px 9px;
  border-radius: 99px;
  cursor: pointer;
  transition: color .12s, background .12s;
}
.pp-lang button:hover { color: var(--text); }
.pp-lang button.active,
.pp-lang button[aria-pressed="true"] {
  background: var(--accent);
  color: var(--accent-ink);
}

/* 22.4 — Pricing hero. Re-uses .hero canonical from §1.6 but lifts the
   subtitle width + adds an editorial accent-row of mini-stats. The italic
   emphasis on the h1 is already inherited from §1.6. */
.pp-hero {
  text-align: center;
  padding: clamp(36px, 6vw, 72px) 24px clamp(20px, 3vw, 36px);
  max-width: 920px; margin: 0 auto;
}
.pp-hero__eyebrow {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px 5px 9px;
  font: 600 10.5px/1 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.08em;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid color-mix(in oklab, var(--accent) 28%, transparent);
  border-radius: 99px;
  margin-bottom: 18px;
  text-transform: uppercase;
}
.pp-hero__eyebrow::before {
  content: '';
  width: 6px; height: 6px;
  background: var(--accent);
  border-radius: 50%;
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent) 25%, transparent);
}
.pp-hero h1 {
  font: 500 clamp(38px, 5.8vw, 60px)/1.04 var(--font-display, var(--font-ui));
  letter-spacing: -0.025em;
  margin: 0 0 14px;
  color: var(--text);
}
.pp-hero h1 em,
.pp-hero h1 .serif,
.pp-hero h1 span {
  font-family: var(--font-serif, 'Instrument Serif', Georgia, serif);
  font-style: italic;
  font-weight: 400;
  color: var(--text);
}
.pp-hero__sub {
  color: var(--text-2);
  font-size: 16px;
  line-height: 1.55;
  max-width: 60ch;
  margin: 0 auto;
}

/* 22.5 — Trust row. Replaces the rendered SVG-in-pill chips with a single
   inline strip that wraps cleanly on mobile. Each item is its own pill;
   reads as metadata, not as buttons. */
.pp-trust-row {
  display: flex; flex-wrap: wrap;
  justify-content: center; gap: 8px;
  margin: 22px auto 0;
  max-width: 760px;
}
.pp-trust-pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px;
  font-size: 12.5px;
  color: var(--text-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 99px;
  line-height: 1;
  white-space: nowrap;
}
.pp-trust-pill svg {
  width: 13px; height: 13px;
  color: var(--accent);
  flex-shrink: 0;
}
@media (max-width: 480px) {
  .pp-trust-pill { font-size: 11.5px; padding: 5px 10px; }
}

/* 22.6 — Billing-cycle pill. Replaces the local .cycle-toggle in
   pricing.html with a shared, more polished variant. Includes the
   "save 20%" badge inline. */
.pp-cycle {
  display: inline-flex; gap: 2px;
  margin: 24px auto 0;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 99px;
  box-shadow: var(--shadow-sm);
}
.pp-cycle button {
  appearance: none; background: transparent; border: 0;
  color: var(--text-2);
  font: 600 12px/1 var(--font-ui, system-ui), sans-serif;
  letter-spacing: 0.02em;
  /* MB-08: vertical padding 8 → 12 so the pill lands at ~40px tall,
     clearing the WCAG 2.5.5 adequate-spacing floor (≥8px gap to siblings,
     which the surrounding layout already provides). */
  padding: 12px 18px;
  border-radius: 99px;
  cursor: pointer;
  transition: color .15s, background .15s;
  display: inline-flex; align-items: center; gap: 6px;
}
.pp-cycle button:hover { color: var(--text); }
.pp-cycle button[aria-pressed="true"] {
  background: var(--text);
  color: var(--bg);
}
.pp-cycle .pp-cycle__save {
  font: 700 9.5px/1 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.06em;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 3px 6px;
  border-radius: 4px;
}
.pp-cycle button[aria-pressed="true"] .pp-cycle__save {
  color: var(--accent-ink);
  background: var(--accent);
}

/* 22.7 — Pricing card grid + card. Replaces the local .grid + .plan rules
   in pricing.html. Cards now have a richer structure: tier-tag at top,
   distinct featured-card lift, considered bullet list with custom marker. */
.pp-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  max-width: 1200px; margin: 0 auto;
}
@media (max-width: 1080px) {
  .pp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .pp-grid { grid-template-columns: 1fr; gap: 10px; }
}

.pp-card {
  position: relative;
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 22px 20px 20px;
  transition: border-color .18s, transform .18s, box-shadow .18s;
}
.pp-card:hover {
  border-color: var(--border-2);
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}
.pp-card--featured {
  background:
    linear-gradient(180deg, color-mix(in oklab, var(--accent) 6%, var(--surface)) 0%, var(--surface) 60%),
    var(--surface);
  border-color: color-mix(in oklab, var(--accent) 50%, var(--border));
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--accent) 35%, transparent),
    0 14px 40px -20px color-mix(in oklab, var(--accent) 40%, transparent);
}
.pp-card--featured:hover {
  border-color: var(--accent);
  box-shadow:
    0 0 0 1px var(--accent),
    0 18px 48px -20px color-mix(in oklab, var(--accent) 50%, transparent);
}
.pp-card__pill {
  position: absolute; top: -10px; left: 18px;
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--accent);
  color: var(--accent-ink);
  font: 700 10px/1 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 9px;
  border-radius: 99px;
  box-shadow: 0 4px 14px -4px color-mix(in oklab, var(--accent) 60%, transparent);
}
.pp-card__pill::before {
  content: '';
  width: 5px; height: 5px;
  background: var(--accent-ink);
  border-radius: 50%;
  opacity: 0.6;
}
.pp-card__tier {
  font: 600 10.5px/1 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 8px;
}
.pp-card__label {
  font: 500 22px/1.15 var(--font-display, var(--font-ui));
  letter-spacing: -0.018em;
  color: var(--text);
  margin: 0 0 2px;
}
.pp-card__tagline {
  font-size: 13px;
  color: var(--text-2);
  line-height: 1.45;
  min-height: 38px;
  margin-bottom: 14px;
}
.pp-card__price {
  display: flex; align-items: baseline; gap: 6px;
  font-family: var(--font-display, var(--font-ui));
  font-weight: 500;
  letter-spacing: -0.02em;
  margin: 4px 0 2px;
}
.pp-card__price-main {
  font-size: 34px;
  color: var(--text);
  line-height: 1;
}
.pp-card__price-cycle {
  font-size: 13px;
  color: var(--text-3);
  font-family: var(--font-ui);
  font-weight: 400;
  letter-spacing: 0;
}
.pp-card__price-hint {
  font-size: 12px;
  color: var(--text-3);
  margin: 4px 0 16px;
  min-height: 16px;
  line-height: 1.4;
}
.pp-card__bullets {
  display: flex; flex-direction: column;
  gap: 8px;
  margin: 0 0 18px;
  padding: 0;
  list-style: none;
  flex: 1;
}
.pp-card__bullets li {
  display: flex; align-items: flex-start; gap: 9px;
  font-size: 13px;
  color: var(--text-2);
  line-height: 1.5;
}
.pp-card__bullets li::before {
  content: '';
  flex-shrink: 0;
  margin-top: 4px;
  width: 14px; height: 14px;
  background: var(--accent-soft);
  border-radius: 50%;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'><path d='M3.2 7.3l2.6 2.4 5-5.4' fill='none' stroke='%233DDBC2' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size: 14px 14px;
  background-repeat: no-repeat;
}
.pp-card__bullets li strong {
  color: var(--text);
  font-weight: 600;
}
.pp-card__cta {
  display: block; width: 100%;
  text-align: center;
  padding: 11px 16px;
  border-radius: 10px;
  font: 600 13.5px/1.2 var(--font-ui, system-ui), sans-serif;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s, border-color .15s, color .15s, box-shadow .15s;
}
.pp-card__cta--primary {
  background: var(--accent);
  color: var(--accent-ink);
  border: 1px solid var(--accent);
}
.pp-card__cta--primary:hover {
  background: var(--accent-3);
  border-color: var(--accent-3);
  text-decoration: none;
  color: var(--accent-ink);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.pp-card__cta--secondary {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
}
.pp-card__cta--secondary:hover {
  border-color: var(--accent);
  color: var(--accent);
  text-decoration: none;
  background: var(--surface-2);
}
.pp-card__cta--ghost {
  background: transparent;
  color: var(--text-2);
  border: 1px solid var(--border);
}
.pp-card__cta--ghost:hover {
  color: var(--text);
  border-color: var(--border-2);
  background: var(--surface);
  text-decoration: none;
}
.pp-card__footnote {
  font-size: 11.5px;
  color: var(--text-4);
  margin-top: 10px;
  text-align: center;
  line-height: 1.5;
}

/* 22.8 — Customer-logo strip. Stub: shows 4 placeholder agency badges so
   pricing/signup reads as "in use by N agencies". Real logos can drop in
   later; right now this is a confidence-anchor band, not a vanity wall. */
.pp-logo-strip {
  margin: 56px auto 32px;
  max-width: 920px;
  padding: 0 24px;
  text-align: center;
}
.pp-logo-strip__label {
  font: 500 11.5px/1.4 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 16px;
}
.pp-logo-strip__row {
  display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center;
  gap: 32px 40px;
  opacity: 0.78;
  transition: opacity .18s;
}
.pp-logo-strip__row:hover { opacity: 1; }
.pp-logo-strip__logo {
  display: inline-flex; align-items: center; gap: 8px;
  font: 500 16px/1 var(--font-ui, system-ui), sans-serif;
  letter-spacing: -0.01em;
  color: var(--text-2);
  filter: grayscale(1);
}
.pp-logo-strip__logo::before {
  content: '';
  width: 16px; height: 16px;
  background: currentColor;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  opacity: 0.8;
}
.pp-logo-strip__logo[data-shape="dot"]::before {
  border-radius: 50%; background: var(--text-2); -webkit-mask: none; mask: none;
}
.pp-logo-strip__logo[data-shape="square"]::before {
  border-radius: 3px; background: var(--text-2); -webkit-mask: none; mask: none;
}
.pp-logo-strip__logo[data-shape="tri"]::before {
  background: var(--text-2); -webkit-mask: none; mask: none;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.pp-logo-strip__logo[data-shape="hex"]::before {
  background: var(--text-2); -webkit-mask: none; mask: none;
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}
@media (max-width: 560px) {
  .pp-logo-strip__row { gap: 20px 28px; }
  .pp-logo-strip__logo { font-size: 14px; }
}

/* 22.9 — Comparison table polish. Scoped to .pp-compare (do not let it
   leak into product tables — those use .pc-table). Pinned first column,
   row-group headers, ✓ in accent and — in muted. */
.pp-compare-wrap {
  margin: 16px auto 0;
  max-width: 1200px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
}
.pp-compare {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.pp-compare th,
.pp-compare td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.pp-compare thead th {
  background: var(--surface-2);
  color: var(--text);
  font: 600 11px/1.2 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  position: sticky; top: 0;
}
.pp-compare thead th:first-child { text-align: left; }
.pp-compare thead th.is-featured {
  background: color-mix(in oklab, var(--accent) 12%, var(--surface-2));
  color: var(--accent);
}
.pp-compare tbody th[scope="row"] {
  font-weight: 500;
  color: var(--text);
  width: 32%;
  font-family: var(--font-ui);
  text-transform: none;
  letter-spacing: 0;
}
.pp-compare tbody td {
  text-align: center;
  color: var(--text-2);
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 12.5px;
}
.pp-compare tbody td.is-featured {
  background: color-mix(in oklab, var(--accent) 5%, transparent);
}
.pp-compare tr:last-child th,
.pp-compare tr:last-child td { border-bottom: none; }
.pp-compare tr:hover td,
.pp-compare tr:hover th[scope="row"] {
  background: color-mix(in oklab, var(--surface-2) 50%, transparent);
}
.pp-compare tr:hover td.is-featured {
  background: color-mix(in oklab, var(--accent) 9%, var(--surface-2));
}
.pp-compare .check {
  color: var(--accent);
  font-weight: 600;
  font-size: 14px;
}
.pp-compare .dash {
  color: var(--text-4);
  opacity: 0.5;
}
.pp-compare .row-group {
  background: var(--bg);
}
.pp-compare .row-group td {
  font: 600 10.5px/1.4 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  text-align: left;
  padding: 14px 16px 8px;
  background: var(--bg);
}
@media (max-width: 720px) {
  .pp-compare-wrap { border-radius: 12px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .pp-compare { min-width: 640px; font-size: 12.5px; }
  .pp-compare th, .pp-compare td { padding: 10px 12px; }
  .pp-compare tbody th[scope="row"] { width: auto; }
}

/* 22.10 — FAQ. Replaces the local .faq in pricing.html. Calmer hover,
   chevron rotates with a tiny ease, no all-caps shouting. */
.pp-faq {
  max-width: 880px; margin: 16px auto 0;
  display: flex; flex-direction: column; gap: 8px;
}
.pp-faq details {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  transition: border-color .15s, background .15s;
}
.pp-faq details:hover { border-color: var(--border-2); }
.pp-faq details[open] {
  border-color: var(--border-2);
  background: color-mix(in oklab, var(--surface-2) 30%, var(--surface));
}
.pp-faq summary {
  list-style: none;
  cursor: pointer;
  padding: 16px 50px 16px 18px;
  font: 500 14.5px/1.4 var(--font-ui, system-ui), sans-serif;
  color: var(--text);
  position: relative;
  letter-spacing: -0.005em;
}
.pp-faq summary::-webkit-details-marker { display: none; }
.pp-faq summary::after {
  content: '';
  position: absolute;
  right: 18px; top: 50%;
  width: 22px; height: 22px;
  margin-top: -11px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background:
    linear-gradient(currentColor, currentColor) center / 9px 1.2px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.2px 9px no-repeat;
  color: var(--text-2);
  transition: transform .2s, border-color .15s, color .15s;
}
.pp-faq details:hover summary::after { color: var(--text); border-color: var(--border-2); }
.pp-faq details[open] summary::after {
  transform: rotate(45deg);
  border-color: var(--accent);
  color: var(--accent);
}
.pp-faq details > div,
.pp-faq details > p {
  padding: 0 18px 18px;
  color: var(--text-2);
  font-size: 13.5px;
  line-height: 1.65;
}
.pp-faq details > p a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in oklab, var(--accent) 40%, transparent);
}
.pp-faq details > p a:hover { text-decoration-color: var(--accent); }

/* 22.11 — Marketing section header. Eyebrow caption + display heading.
   Used between pricing grid → comparison → FAQ to reset the reader's eye. */
.pp-section {
  margin: clamp(48px, 7vw, 80px) auto 0;
  max-width: 1200px;
  padding: 0 24px;
}
.pp-section__head {
  text-align: center;
  margin-bottom: 22px;
}
.pp-section__eyebrow {
  font: 600 10.5px/1 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 10px;
}
.pp-section h2 {
  font: 500 clamp(26px, 3.4vw, 34px)/1.1 var(--font-display, var(--font-ui));
  letter-spacing: -0.022em;
  color: var(--text);
  margin: 0 0 8px;
}
.pp-section h2 em,
.pp-section h2 span {
  font-family: var(--font-serif, 'Instrument Serif', Georgia, serif);
  font-style: italic;
  font-weight: 400;
  color: var(--text);
}
.pp-section__sub {
  color: var(--text-2);
  font-size: 14.5px;
  max-width: 56ch;
  margin: 0 auto;
  line-height: 1.55;
}

/* 22.12 — "Explainer" disclosure used for the GEO definition box.
   Calmer than the inline geo-explainer from before; reads as inline help. */
.pp-explainer {
  max-width: 760px;
  margin: 32px auto 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
  padding: 18px 22px;
}
.pp-explainer summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 10px;
  font: 500 14.5px/1.3 var(--font-ui, system-ui), sans-serif;
  color: var(--text);
  letter-spacing: -0.005em;
}
.pp-explainer summary::-webkit-details-marker { display: none; }
.pp-explainer summary::before {
  content: '';
  width: 22px; height: 22px;
  border: 1px solid var(--border);
  border-radius: 50%;
  flex-shrink: 0;
  background:
    linear-gradient(currentColor, currentColor) center / 9px 1.2px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.2px 9px no-repeat;
  color: var(--text-2);
  transition: transform .18s;
}
.pp-explainer[open] summary::before {
  transform: rotate(45deg);
  border-color: var(--accent);
  color: var(--accent);
}
.pp-explainer__body {
  margin-top: 12px;
  color: var(--text-2);
  font-size: 13.5px;
  line-height: 1.65;
}
.pp-explainer__body strong {
  color: var(--text);
  font-weight: 600;
}

/* 22.13 — AUTH-CARD shell (login + signup). The current pages have wildly
   different paddings/widths; this gives both one canonical shell with
   side-by-side hero + form layout on desktop ≥960px, single-column on
   mobile. The "hero" side carries trust copy + testimonial. */
.pp-auth {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 5vw, 72px);
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(28px, 5vw, 64px) clamp(20px, 4vw, 36px);
  align-items: center;
}
@media (max-width: 960px) {
  .pp-auth {
    grid-template-columns: 1fr;
    gap: 28px;
    padding: 24px 16px 32px;
    max-width: 520px;
  }
}

.pp-auth__hero {
  display: flex; flex-direction: column;
  gap: 22px;
  padding-right: 8px;
}
@media (max-width: 960px) { .pp-auth__hero { padding-right: 0; text-align: center; align-items: center; } }

.pp-auth__hero h1 {
  font: 500 clamp(30px, 4.2vw, 44px)/1.08 var(--font-display, var(--font-ui));
  letter-spacing: -0.025em;
  color: var(--text);
  margin: 0;
  max-width: 20ch;
}
.pp-auth__hero h1 em,
.pp-auth__hero h1 span {
  font-family: var(--font-serif, 'Instrument Serif', Georgia, serif);
  font-style: italic; font-weight: 400;
  color: var(--text);
}
.pp-auth__hero p {
  color: var(--text-2);
  font-size: 15px;
  line-height: 1.6;
  max-width: 44ch;
  margin: 0;
}

.pp-auth__signals {
  display: grid; gap: 14px;
  margin-top: 4px;
}
.pp-auth__signal {
  display: flex; align-items: flex-start; gap: 12px;
  font-size: 13.5px;
  color: var(--text-2);
  line-height: 1.55;
}
.pp-auth__signal-icon {
  flex-shrink: 0;
  width: 28px; height: 28px;
  display: inline-grid; place-items: center;
  background: var(--accent-soft);
  border-radius: 8px;
  color: var(--accent);
}
.pp-auth__signal-icon svg { width: 14px; height: 14px; }
.pp-auth__signal strong {
  display: block;
  color: var(--text);
  font-weight: 600;
  margin-bottom: 1px;
}

.pp-auth__quote {
  margin-top: 12px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  position: relative;
}
.pp-auth__quote::before {
  content: '“';
  position: absolute; top: -14px; left: 12px;
  font: 400 56px/1 var(--font-serif, 'Instrument Serif', Georgia, serif);
  font-style: italic;
  color: var(--accent);
  opacity: 0.5;
  pointer-events: none;
}
.pp-auth__quote p {
  font: 400 14px/1.55 var(--font-ui, system-ui), sans-serif;
  color: var(--text);
  margin: 0 0 10px;
  letter-spacing: -0.005em;
}
.pp-auth__quote footer {
  display: flex; align-items: center; gap: 10px;
  font-size: 12.5px;
  color: var(--text-3);
}
.pp-auth__quote-avatar {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--violet));
  color: var(--accent-ink);
  font: 600 11px/1 var(--font-mono);
  display: inline-grid; place-items: center;
  flex-shrink: 0;
}
.pp-auth__quote footer strong {
  color: var(--text-2);
  font-weight: 600;
}

.pp-auth__card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: clamp(24px, 3vw, 32px) clamp(20px, 3vw, 30px);
  box-shadow: var(--shadow-md);
  position: relative;
}
.pp-auth__card-head {
  margin-bottom: 18px;
}
.pp-auth__card-head h2 {
  font: 500 22px/1.2 var(--font-display, var(--font-ui));
  letter-spacing: -0.018em;
  margin: 0 0 4px;
  color: var(--text);
}
.pp-auth__card-head p {
  margin: 0;
  font-size: 13.5px;
  color: var(--text-2);
  line-height: 1.5;
}

.pp-auth__steps {
  display: flex; gap: 4px;
  margin: 0 0 18px;
}
.pp-auth__step {
  flex: 1;
  display: flex; flex-direction: column; gap: 4px;
}
.pp-auth__step-bar {
  height: 3px;
  background: var(--border);
  border-radius: 99px;
  transition: background .25s;
}
.pp-auth__step-label {
  font: 600 9.5px/1.2 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-4);
  transition: color .25s;
}
.pp-auth__step.is-active .pp-auth__step-bar { background: var(--accent); }
.pp-auth__step.is-active .pp-auth__step-label { color: var(--accent); }
.pp-auth__step.is-done .pp-auth__step-bar { background: color-mix(in oklab, var(--accent) 60%, transparent); }
.pp-auth__step.is-done .pp-auth__step-label { color: var(--text-3); }

.pp-auth__field {
  display: block;
  margin-bottom: 14px;
}
.pp-auth__field-label {
  display: flex; align-items: center; justify-content: space-between;
  font: 600 10.5px/1 var(--font-mono, ui-monospace, monospace);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 6px;
}
.pp-auth__field-label a {
  font: 500 11.5px/1 var(--font-ui, system-ui), sans-serif;
  letter-spacing: 0;
  color: var(--text-2);
  text-transform: none;
  text-decoration: none;
  border-bottom: 1px dotted var(--border-2);
  padding-bottom: 1px;
  transition: color .12s, border-color .12s;
}
.pp-auth__field-label a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.pp-auth__field input {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 13px;
  color: var(--text);
  font: 400 14px/1.4 var(--font-ui, system-ui), sans-serif;
  outline: none;
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.pp-auth__field input::placeholder { color: var(--text-4); }
.pp-auth__field input:hover { border-color: var(--border-2); }
.pp-auth__field input:focus,
.pp-auth__field input:focus-visible {
  border-color: var(--accent);
  background: var(--surface-2);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.pp-auth__field input[aria-invalid="true"] {
  border-color: var(--fail);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--fail) 18%, transparent);
}

.pp-auth__cta {
  width: 100%;
  margin-top: 8px;
  padding: 13px 16px;
  background: var(--accent);
  color: var(--accent-ink);
  border: 1px solid var(--accent);
  border-radius: 10px;
  font: 600 14px/1.2 var(--font-ui, system-ui), sans-serif;
  letter-spacing: -0.005em;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: background .15s, box-shadow .15s, transform .08s;
}
.pp-auth__cta:hover {
  background: var(--accent-3);
  border-color: var(--accent-3);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.pp-auth__cta:active { transform: translateY(1px); }
.pp-auth__cta:disabled,
.pp-auth__cta[aria-disabled="true"] {
  opacity: 0.55; cursor: not-allowed; box-shadow: none; transform: none;
}
.pp-auth__cta svg { width: 14px; height: 14px; }

.pp-auth__divider {
  display: flex; align-items: center;
  gap: 12px;
  margin: 18px 0;
  font: 500 10.5px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-4);
}
.pp-auth__divider::before,
.pp-auth__divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

.pp-auth__alt {
  display: flex; align-items: center; justify-content: center;
  font-size: 13px;
  color: var(--text-2);
  gap: 6px;
}
.pp-auth__alt a {
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid color-mix(in oklab, var(--accent) 60%, transparent);
  padding-bottom: 1px;
  transition: color .12s, border-color .12s;
}
.pp-auth__alt a:hover { color: var(--accent); border-bottom-color: var(--accent); }

.pp-auth__tos {
  display: flex; align-items: flex-start; gap: 9px;
  margin: 14px 0 4px;
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.5;
}
.pp-auth__tos input[type="checkbox"] {
  flex-shrink: 0;
  margin-top: 2px;
  width: 16px; height: 16px;
  appearance: none;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
  position: relative;
  transition: background .12s, border-color .12s;
}
.pp-auth__tos input[type="checkbox"]:hover { border-color: var(--border-2); }
.pp-auth__tos input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.pp-auth__tos input[type="checkbox"]:checked::after {
  content: '';
  position: absolute; inset: 2px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M2.5 6.3l2.3 2.2 4.5-4.8' fill='none' stroke='%2306241F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 10px 10px;
}
.pp-auth__tos input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.pp-auth__tos label { margin: 0; font-family: var(--font-ui); text-transform: none; letter-spacing: 0; color: var(--text-2); font-weight: 400; }
.pp-auth__tos a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: color-mix(in oklab, var(--accent) 50%, transparent);
  text-decoration-thickness: 1px;
}
.pp-auth__tos a:hover { text-decoration-color: var(--accent); }

/* 22.13b — Legal-doc H3 type rhythm.
   2026-05-19 audit (P1-33): terms.html, terms-en.html, privacy.html and
   cookies.html ship inline `.legal-main h3 { font-size: 14px }` rules in
   their <head> <style> blocks. 14px collapses H3 onto body copy (15px /
   line-height 1.7), so readers can't visually scan the document outline
   under WCAG 1.3.1 information & relationships.

   This rule lives in prisma-components.css so it's part of the bundle and
   wins via specificity (html .legal-main h3 = 0,2,1) over the inline rule
   on those four pages (.legal-main h3 = 0,1,1). When the integrator drops
   the inline overrides, this token-aligned rule keeps the cascade clean.

   Scale: body 15px -> h3 17px (1.13 step) -> h2 21px -> h1 30-42px clamp. */
html .legal-main h3 {
  font-family: var(--font-display, var(--font-ui));
  font-size: 17px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--text);
  margin: 26px 0 10px;
  scroll-margin-top: 80px;
}

/* 22.14 — Footnote / legal row used in pricing + auth pages. */
.pp-footnote {
  padding: 32px 24px;
  text-align: center;
  font-size: 12px;
  color: var(--text-4);
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: clamp(48px, 6vw, 80px);
}
.pp-footnote a {
  color: var(--text-3);
  text-decoration: none;
  transition: color .12s;
}
.pp-footnote a:hover { color: var(--accent); }
.pp-footnote__sep { color: var(--text-4); opacity: 0.5; }

/* 22.15 — Toasts inside auth-card. Compact, slot-in below CTA. */
.pp-auth__feedback {
  margin-top: 14px;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 12.5px;
  line-height: 1.5;
}
.pp-auth__feedback[data-kind="ok"] {
  background: var(--pass-bg);
  border: 1px solid color-mix(in oklab, var(--pass) 30%, transparent);
  color: var(--pass);
}
.pp-auth__feedback[data-kind="err"] {
  background: var(--fail-bg);
  border: 1px solid color-mix(in oklab, var(--fail) 30%, transparent);
  color: var(--fail);
}
.pp-auth__feedback[data-kind="info"] {
  background: var(--info-bg);
  border: 1px solid color-mix(in oklab, var(--info) 26%, transparent);
  color: var(--text-2);
}
.pp-auth__feedback.hidden { display: none; }

/* 22.16 — "value bar" used on signup to anchor the free-plan included
   items. Tiny strip of checkmarks above the form. */
.pp-auth__includes {
  display: flex; flex-wrap: wrap; gap: 10px 14px;
  padding: 12px 14px;
  background: var(--accent-soft);
  border: 1px solid color-mix(in oklab, var(--accent) 22%, transparent);
  border-radius: 10px;
  margin-bottom: 18px;
}
.pp-auth__includes-item {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px;
  color: var(--text);
  font-weight: 500;
  line-height: 1.3;
}
.pp-auth__includes-item::before {
  content: '';
  width: 14px; height: 14px;
  flex-shrink: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'><path d='M3 7.3l2.5 2.4 5-5.4' fill='none' stroke='%233DDBC2' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-size: 14px;
}

/* 22.17 — Brand-mark + wordmark cluster for topbar/auth-card head. */
.pp-brand-cluster {
  display: inline-flex; align-items: center; gap: 10px;
  text-decoration: none;
  color: var(--text);
}
.pp-brand-cluster .brand-mark {
  /* override base size for marketing-shell — slightly chunkier */
  width: 24px; height: 24px;
  box-shadow: 0 0 22px rgba(61,219,194,.32);
}
.pp-brand-cluster .pp-brand-word {
  font-family: var(--font-serif, 'Instrument Serif', Georgia, serif);
  font-style: italic; font-weight: 400;
  font-size: 24px; letter-spacing: -0.025em;
  color: var(--text);
  line-height: 1;
}

/* 22.18 — Reduced motion: kill the card hover lift + featured-card shimmer. */
@media (prefers-reduced-motion: reduce) {
  .pp-card:hover { transform: none; }
  .pp-card,
  .pp-faq details,
  .pp-auth__cta,
  .pp-cycle button,
  .pp-lang button { transition: none; }
}

/* 22.19 — Light theme tuning. The accent-soft + accent-glow are already
   redefined by the [data-theme="light"] block in prisma-tokens.css; this
   just nudges a few sub-tokens that look too bright on white. */
[data-theme="light"] .pp-card--featured {
  background:
    linear-gradient(180deg, color-mix(in oklab, var(--accent) 4%, var(--surface)) 0%, var(--surface) 70%),
    var(--surface);
}
[data-theme="light"] .pp-cycle button[aria-pressed="true"] {
  background: var(--text);
  color: var(--bg);
}
[data-theme="light"] .pp-topbar {
  background: color-mix(in oklab, var(--bg) 82%, transparent);
}

/* ─────────────────────────────────────────────────────────────────────
   F33 (2026-05-17): mobile responsiveness — merged from
   design-review/overrides.css so customers actually get the layout
   work. The sandbox file used !important heavily to fight other
   design-review demo styles; the migration here strips most of that
   because these are now the canonical mobile rules — they're not
   fighting anyone. Where !important is kept, it's because the base
   rule above is also !important and we need to win at equal specificity.

   Selectors are intentionally curated: design-review demo elements
   (.dr-badge etc) are NOT migrated — they only exist in the sandbox.
   Real customer surfaces (.domain-card, .gauge-card, .ph-tile,
   .url-form, .pc-modal, .pp-auth__card, .pp-card, .fchip,
   .bulk-bar-sticky, .rank-table, …) are.
   ────────────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  /* App shell — tighter padding */
  .app-content { padding: 14px 14px 60px; }
  .app-topbar  { padding: 0 14px; gap: 10px; }

  /* Dashboard: single-column grid */
  .domains-grid { grid-template-columns: 1fr; gap: 8px; }

  /* Domain card: compact but breathable */
  .domain-card { padding: 14px 14px 11px; gap: 10px; border-radius: 12px; }
  .card-domain { font-size: 12.5px; }
  .card-url    { font-size: 10.5px; }

  /* Score gauge: tighter */
  .gauge-card { padding: 10px 12px; gap: 12px; border-radius: 10px; }
  .gauge-wrap { width: 76px; height: 58px; flex-shrink: 0; }
  .gauge-num  { font-size: 17px; letter-spacing: -.05em; }
  .gauge-lab  { font-size: 7.5px; letter-spacing: .1em; }

  /* Sub-bar — drop the weight column, tighten layout */
  .sub-bar         { grid-template-columns: 24px 1fr 26px; gap: 4px; }
  .sub-bar .sb-w   { display: none; }
  .sub-bar .sb-lab { font-size: 8.5px; }
  .sub-bar .sb-val { font-size: 11px; }

  /* Sparkline row */
  .spark-row  { gap: 8px; }
  .spark-meta { flex-wrap: wrap; gap: 3px 8px; font-size: 10px; }

  /* Card actions — analyze fills the row */
  .card-actions { gap: 5px; }
  .card-btn.btn-mini,
  .card-btn.card-btn { min-height: 38px; font-size: 11.5px; }

  /* Portfolio-health grid: 2 columns */
  .ph-grid { grid-template-columns: 1fr 1fr; gap: 8px; }
  .ph-tile { padding: 11px 12px; gap: 5px; border-radius: 10px; }
  .ph-tile .ph-domain { font-size: 11.5px; }
  .ph-tile .ph-score  { font-size: 20px; letter-spacing: -.03em; }
  .ph-tile .ph-delta  { font-size: 10px; }

  /* Bulk-action bar: fixed bottom strip */
  .bulk-bar-sticky {
    position: fixed; top: auto; bottom: 0; left: 0; right: 0;
    z-index: var(--z-sticky, 200);
    border-radius: 14px 14px 0 0;
    border-left: none; border-right: none; border-bottom: none;
    padding: 12px 16px; flex-wrap: wrap; gap: 8px;
    box-shadow: 0 -4px 24px rgba(0,0,0,.25);
  }

  /* Filter chips: wrapping row */
  .fchip {
    font-size: 10px; padding: 5px 9px; min-height: 30px;
    display: inline-flex; align-items: center;
  }

  /* Analyzer topbar */
  .site-header { padding-left: 14px; padding-right: 14px; }

  /* Analyzer URL form */
  .url-form  { max-width: 100%; border-radius: 10px; }
  .url-input { font-size: 14px; }

  /* Analysis-mode pills */
  .analysis-mode-wrap {
    flex-wrap: wrap; justify-content: center; gap: 6px; margin-top: 14px;
  }
  .mode-pill { padding: 6px 12px; font-size: 12px; min-height: 34px; }

  /* Analyzer score section */
  .score-section { padding: 22px 12px 16px; gap: 14px; }

  /* Wide tables: allow horizontal scroll */
  .rank-table-wrap,
  .table-scroll,
  [class*="-table-wrap"] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .rank-table { min-width: 460px; }

  /* Auth pages: hero off, card centered */
  .pp-auth       { padding: 0; gap: 0; }
  .pp-auth__hero { display: none; }
  .pp-auth__card {
    width: 100%; max-width: 440px;
    padding: clamp(22px, 5vw, 30px) clamp(18px, 5vw, 26px);
    margin: 0 auto;
  }

  /* Marketing topbar: hide nav links */
  .pp-topbar__nav { display: none; }
  .pp-topbar      { padding: 12px clamp(16px, 4vw, 24px); }

  /* Pricing grid: single column */
  #plans.pp-grid,
  .pp-grid {
    grid-template-columns: 1fr; gap: 10px;
    max-width: 460px; margin-left: auto; margin-right: auto;
  }
  .pp-card               { padding: 20px 18px; }
  .pp-card__price-main   { font-size: 28px; }
  .pp-hero h1            { font-size: clamp(22px, 6vw, 32px); max-width: 100%; }
  .pp-hero               { padding-top: clamp(32px, 6vw, 52px); padding-left: 16px; padding-right: 16px; }

  /* Modals: bottom-sheet on mobile */
  .pc-modal-overlay { align-items: flex-end; }
  .pc-modal {
    border-radius: 16px 16px 0 0;
    max-width: 100%; width: 100%; max-height: 92dvh;
    overflow-y: auto;
    padding-bottom: env(safe-area-inset-bottom, 12px);
  }

  /* CTA buttons: 44px WCAG 2.5.5 floor (F17 baseline already 44 on .pc-btn).
     MB-06 bumped from 42 → 44 so the pricing card primary CTA clears the
     full touch-target spec without relying on adequate-spacing exemption. */
  .pp-card__cta,
  .pp-auth__cta,
  .analyze-btn,
  .pc-btn--primary,
  .pc-btn--secondary { min-height: 44px; }

  /* WCAG 2.5.5 — 44×44 touch-target floor on mobile (F17 + F38).
     Sweeps billing pills, dashboard card actions, analyzer chips, agency
     header actions and any other small interactive controls. */
  .pc-btn,
  .btn,
  .ph-btn,
  button.dr-btn,
  .pc-icon-btn,
  .domain-card .card-action,
  .domain-card .pin-btn,
  .domain-card a[href],
  .domain-card button,
  .bar-actions button,
  a.badge,
  button.badge {
    min-height: 44px;
    min-width: 44px;
  }
  .card-btn.btn-mini,
  .card-btn.card-btn { min-height: 44px; }
  .mode-pill { min-height: 44px; }
  .fchip { min-height: 44px; padding-top: 8px; padding-bottom: 8px; }
}

@media (max-width: 480px) {
  .app-content   { padding: 10px 12px 60px; }
  .domains-grid  { gap: 7px; }
  .domain-card   { padding: 12px 12px 10px; gap: 9px; border-radius: 10px; }

  .gauge-card { padding: 9px 10px; gap: 10px; }
  .gauge-wrap { width: 70px; height: 54px; }
  .gauge-num  { font-size: 15px; }

  /* URL form: stack vertically */
  .url-form    { flex-direction: column; padding: 10px; gap: 7px; }
  /* M-01 fix: explicit 16px so iOS Safari doesn't auto-zoom. The §17.16b
     block below also forces it via !important; this is the in-place value. */
  .url-input   { padding: 10px 12px; font-size: 16px; }
  .analyze-btn { width: 100%; justify-content: center; padding: 11px 16px; border-radius: 9px; }

  .pp-auth__card { padding: 20px 16px; border-radius: 12px; }
  .pp-card       { padding: 18px 16px; }
  .score-section { padding: 18px 8px 14px; }

  .ph-tile             { padding: 10px; border-radius: 8px; }
  .ph-tile .ph-score   { font-size: 18px; }
  .ph-tile .ph-domain  { font-size: 10.5px; }
}

[data-loading="true"] .stat-card,
[data-loading="true"] .skeleton-row {
  position: relative;
  overflow: hidden;
  background: var(--surface-2, rgba(255,255,255,.05));
  border-radius: var(--radius-md, 12px);
  min-height: 64px;
}
[data-loading="true"] .stat-card::after,
[data-loading="true"] .skeleton-row::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.06), transparent);
  animation: shimmer 1.4s infinite;
}
@keyframes shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
  [data-loading="true"] .stat-card::after,
  [data-loading="true"] .skeleton-row::after { animation: none; }
}

.table-scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

@media (max-width: 768px) {
  .pp-agency-header,
  .agency-header {
    flex-wrap: wrap;
    row-gap: 8px;
  }
}

/* ════════════════════════════════════════════════════════════════════
   ── 13. ANALYZER SECTION-FIRST NAVIGATION (R1, 2026-05-17) ─────────
   Two-tier IA on top of the existing flat .tab-btn list. The Overview
   pill (Positioning + Action plan) sits left of a hairline divider;
   six section pills (Visibilidad / Competidores / Contenido / Técnico
   / Local / Monitor) sit to the right. JS sets data-active-section on
   the section rail and on the sidebar — CSS handles the filter via
   attribute selectors so the existing .tab-btn click handlers, locale
   switches and panel mounts stay untouched.
   ════════════════════════════════════════════════════════════════════ */

.prs-section-rail {
  /* 2026-05-20: scrolls with content (was sticky). User asked for all
     three top rails — URL pill / score pills / Overview…Monitor — to
     scroll away naturally with the page rather than stick. The sidebar
     (vertical) carries persistent section navigation on desktop. */
  position: static;
  z-index: 32;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  margin: 12px 0 14px;
  background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.025));
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 14px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
}
.prs-section-rail::-webkit-scrollbar { display: none; }
.prs-section-rail[hidden] { display: none; }
.prs-section-rail-fade { display: none; }

.prs-section-group {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.prs-section-group--main {
  flex: 1 1 auto;
  flex-wrap: nowrap;
}

.prs-section-divider {
  width: 1px;
  height: 22px;
  background: linear-gradient(180deg, transparent, rgba(255,255,255,.14) 30%, rgba(255,255,255,.14) 70%, transparent);
  flex-shrink: 0;
}

.prs-section-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  min-height: 36px;
  font: 500 13px/1 var(--font-ui);
  letter-spacing: 0.005em;
  color: var(--text-2);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 10px;
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s ease, color .15s ease, border-color .15s ease, transform .12s ease;
  scroll-snap-align: start;
  flex-shrink: 0;
}
.prs-section-pill .ico { color: currentColor; flex-shrink: 0; }
.prs-section-pill:hover {
  color: var(--text);
  background: rgba(255,255,255,.04);
  border-color: rgba(255,255,255,.06);
}
.prs-section-pill:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.prs-section-pill.is-active,
.prs-section-pill[aria-pressed="true"] {
  color: var(--accent);
  background: var(--accent-glow);
  border-color: rgba(61, 219, 194, 0.32);
  font-weight: 600;
}
.prs-section-pill.is-active .ico,
.prs-section-pill[aria-pressed="true"] .ico { color: var(--accent); }

.prs-section-pill--overview {
  background: rgba(255,255,255,.025);
  border-color: rgba(255,255,255,.08);
}
.prs-section-pill--overview.is-active,
.prs-section-pill--overview[aria-pressed="true"] {
  background: var(--accent-glow);
  border-color: rgba(61, 219, 194, 0.32);
  color: var(--accent);
}

.prs-section-crumb {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 4px 16px;
  font: 500 12px/1 var(--font-ui);
  letter-spacing: 0.005em;
  color: var(--text-3);
  margin: -4px 0 0;
}
.prs-section-crumb[hidden] { display: none; }
.prs-section-crumb__section {
  color: var(--accent);
  font-weight: 600;
}
.prs-section-crumb__sep {
  color: var(--text-faint, var(--text-3));
  opacity: .55;
  font-weight: 400;
  transform: translateY(-1px);
}
.prs-section-crumb__tab { color: var(--text-2); }

/* Section-filter mechanism: handled in JS via inline style.display
   on each .tab-btn (see analyzer.html applySectionFilter). The JS
   approach correctly handles tabs that live in multiple sections
   (e.g. 'advanced' belongs to competidores+tecnico+monitor) which a
   pure-CSS [data-section~="X"] selector would also support, but the
   JS path lets us also tag empty groups via data-empty. */

.tabs-bar.tabs-side .tabs-group[data-empty="true"] { display: none !important; }
.tabs-bar.tabs-side .tabs-group[data-empty="true"] .tabs-group-head { display: none !important; }

@media (max-width: 1024px) {
  .prs-section-rail {
    border-radius: 12px;
    margin: 6px 0 10px;
    padding: 8px 10px;
  }
  .prs-section-pill {
    padding: 10px 14px;
    font-size: 12.5px;
  }
  .analysis-shell > .tabs-bar.tabs-side {
    scroll-snap-type: x mandatory;
    padding: 6px 10px !important;
    gap: 4px;
  }
  .analysis-shell > .tabs-bar.tabs-side .tab-btn {
    scroll-snap-align: start;
  }
}

@media (max-width: 768px) {
  .prs-section-pill { min-height: 44px; padding: 10px 16px; }
  .analysis-shell > .tabs-bar.tabs-side .tab-btn,
  .analysis-shell > .tabs-bar.tabs-side .tab-row {
    min-height: 44px;
    padding-block: 12px;
  }
  .prs-section-crumb { font-size: 11.5px; }
}

.prs-section-overview {
  margin: 0 0 24px;
  padding: 0;
  border: 0;
  background: transparent;
}
.prs-section-overview[hidden] { display: none; }
.prs-section-overview__head {
  margin: 0 0 12px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.prs-section-overview__title {
  font: 600 16px/1.2 var(--font-ui);
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 0;
}
.prs-section-overview__hint {
  font: 400 12px/1.5 var(--font-ui);
  color: var(--text-3, var(--text-2));
  margin: 0;
}

/* ── Grid: single-column list at all sizes, 2-col at ≥640px ── */
.prs-section-overview__grid {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
}
@media (min-width: 640px) {
  .prs-section-overview__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

/* ── Stagger animation on mount ── */
@keyframes prs-card-in {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}
.prs-section-overview__card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 12px 12px 16px;
  min-height: 56px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: background .12s ease;
  animation: prs-card-in 220ms ease-out both;
}
/* 2-col grid: right column items lose right border, bottom row items lose bottom border */
@media (min-width: 640px) {
  .prs-section-overview__card:nth-child(even)  { border-left: 1px solid var(--border); }
  .prs-section-overview__card:nth-last-child(-n+2):nth-child(odd),
  .prs-section-overview__card:last-child        { border-bottom: none; }
}
/* Single-col: only last item loses bottom border */
@media (max-width: 639px) {
  .prs-section-overview__card:last-child { border-bottom: none; }
}
/* Stagger delays */
.prs-section-overview__card:nth-child(1)  { animation-delay:   0ms; }
.prs-section-overview__card:nth-child(2)  { animation-delay:  30ms; }
.prs-section-overview__card:nth-child(3)  { animation-delay:  55ms; }
.prs-section-overview__card:nth-child(4)  { animation-delay:  80ms; }
.prs-section-overview__card:nth-child(5)  { animation-delay: 100ms; }
.prs-section-overview__card:nth-child(6)  { animation-delay: 120ms; }
.prs-section-overview__card:nth-child(7)  { animation-delay: 138ms; }
.prs-section-overview__card:nth-child(8)  { animation-delay: 155ms; }
.prs-section-overview__card:nth-child(9)  { animation-delay: 170ms; }
.prs-section-overview__card:nth-child(10) { animation-delay: 184ms; }
.prs-section-overview__card:nth-child(11) { animation-delay: 197ms; }
.prs-section-overview__card:nth-child(12) { animation-delay: 210ms; }

.prs-section-overview__card:hover {
  background: var(--surface-2);
}
.prs-section-overview__card:active {
  background: var(--surface-2);
  transform: scale(0.99);
}
.prs-section-overview__card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.prs-section-overview__card-icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: 8px;
  background: var(--accent-soft);
  border: 1px solid rgba(61, 219, 194, 0.18);
  color: var(--accent);
  transition: background .15s ease, border-color .15s ease;
}
.prs-section-overview__card:hover .prs-section-overview__card-icon {
  background: rgba(61, 219, 194, 0.14);
  border-color: rgba(61, 219, 194, 0.32);
}
.prs-section-overview__card-icon svg { width: 15px; height: 15px; }

.prs-section-overview__card-body {
  min-width: 0;
  flex: 1;
}
.prs-section-overview__card-name {
  font: 600 13px/1.25 var(--font-ui);
  color: var(--text);
  margin: 0 0 2px;
  letter-spacing: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prs-section-overview__card-desc {
  font: 400 11.5px/1.4 var(--font-ui);
  color: var(--text-3, var(--text-2));
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Chevron arrow */
.prs-section-overview__card-arrow {
  flex-shrink: 0;
  color: var(--text-faint);
  transition: transform .18s cubic-bezier(0.16,1,0.3,1), color .15s ease;
}
.prs-section-overview__card:hover .prs-section-overview__card-arrow {
  transform: translateX(3px);
  color: var(--text-muted);
}

.prs-section-overview__card .new {
  font: 600 8.5px/1 var(--font-mono);
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid rgba(61, 219, 194, 0.25);
  padding: 2px 6px;
  border-radius: 999px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  flex-shrink: 0;
}

@media (prefers-reduced-motion: reduce) {
  .prs-section-overview__card { animation: none; }
  .prs-section-overview__card-arrow { transition: none; }
}

/* ANL-3 fix: NEW badge spacing. The legacy badge had no left margin,
   so "AI Search" + "NEW" rendered as "AI SearchNEW". Add an explicit
   gap; preserve the auto-margin in the sidebar list. */
.tab-btn .new,
.tab-row .new {
  margin-left: 6px;
}
.tabs-side .tab-row .new,
.tabs-bar.tabs-side .tab-row .new,
.tabs-bar.tabs-side .tab-btn .new {
  margin-left: auto;
}

/* Vertical desktop layout (≥1025px): .tabs-side is fixed-left at
   290px and .analysis-content gets margin-left:290px + padding:28px 32px.
   Mirror that offset on the rail so it sits flush with the content
   column rather than overlaying the sidebar. */
@media (min-width: 1025px) {
  .analysis-shell > .prs-section-rail {
    margin-left: 322px;   /* 290 sidebar + 32 left padding */
    margin-right: 32px;
  }
  .analysis-shell > .prs-section-crumb {
    margin-left: 322px;
    padding-left: 0;
  }
}
@media (max-width: 1024px) {
  .analysis-shell > .prs-section-rail,
  .analysis-shell > .prs-section-crumb { margin-left: 0; margin-right: 0; }
}

/* ════════════════════════════════════════════════════════════════════
   ── 25. PAGE-LEVEL POLISH (R2 SPRINT 2026-05-17) ───────────────────
   Visual polish + responsive correctness for the five flagship pages
   (dashboard / billing / agency / admin / pricing). Lives at the
   bottom of the bundle on purpose — these rules need to win against
   page-local inline <style> blocks that ship with the legacy HTML.
   ════════════════════════════════════════════════════════════════════ */

/* WHY 17.1 — Dashboard hero stat numerals lift to 30px tabular Geist so
   the 4-tile row reads as a single scannable strip; existing eyebrow
   label sits more confidently above. Counters the per-page 38px set in
   dashboard.html which made the row dominate the viewport on laptops. */
.dash-hero .dash-stats .dash-stat .dash-stat-n {
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums slashed-zero;
}
.dash-hero .dash-stats .dash-stat .dash-stat-l {
  font: 600 10.5px/1.2 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* WHY 17.2 — Portfolio-health tile with no data: the bare "0" reads as
   broken. Dim the score + surface a tiny eyebrow caption so the tile
   reads as deliberately empty. JS adds .ph-tile--empty when value is 0. */
.ph-tile.ph-tile--empty .ph-score,
.ph-tile.ph-grey .ph-score {
  color: var(--text-4);
  opacity: .55;
}
.ph-tile .ph-empty-caption {
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-4);
  margin-top: 2px;
}

/* WHY 17.3 — Domain card top-of-card status hairline. The card grid is
   34+ cards tall — without a peripheral cue the user can't tell which
   need attention. Red for score <50, amber for 50-69, transparent
   otherwise. Driven by JS toggling .domain-card--attention / --warn. */
.domain-card { position: relative; }
.domain-card.domain-card--attention::before,
.domain-card.domain-card--warn::before,
.domain-card[data-status="attention"]::before,
.domain-card[data-status="warn"]::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  border-top-left-radius: inherit;
  border-top-right-radius: inherit;
  z-index: 1;
  opacity: 1;
}
.domain-card.domain-card--attention::before,
.domain-card[data-status="attention"]::before { background: var(--fail); }
.domain-card.domain-card--warn::before,
.domain-card[data-status="warn"]::before { background: var(--warn); }

/* WHY 17.4 — Inline score+delta badge at the top-right of a domain card.
   Replaces the implicit "scan-the-card-to-find-the-number" workflow with
   a single fixed location. The JS that owns .domain-card may opt in by
   rendering a .card-score-badge element instead of the legacy score row. */
.domain-card .card-score-badge {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  margin-left: auto;
}
.domain-card .card-score-badge .n {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
  line-height: 1;
}
.domain-card .card-score-badge .delta {
  font-size: 10.5px;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-3);
  letter-spacing: 0.02em;
}
.domain-card .card-score-badge .delta.is-up   { background: color-mix(in oklab, var(--pass) 16%, transparent); color: var(--pass); }
.domain-card .card-score-badge .delta.is-down { background: color-mix(in oklab, var(--fail) 16%, transparent); color: var(--fail); }

/* WHY 17.5 — Card-actions: primary "Analizar" fills the bottom of the
   card at 44px so the touch target is locked AAA. Secondary actions
   collapse to a kebab next to it. JS that renders the card can opt in
   by adding .card-actions--stacked; the legacy 3-button row keeps its
   current behaviour. */
.card-actions.card-actions--stacked {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: stretch;
}
.card-actions.card-actions--stacked .card-btn.primary {
  width: 100%;
  min-height: 44px;
  padding: 11px 16px;
  font-weight: 600;
  letter-spacing: -0.005em;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.card-actions.card-actions--stacked .card-kebab > summary {
  min-width: 44px;
  min-height: 44px;
}

/* WHY 17.6 — Billing zebra striping on the quotas table + sticky first
   column on mobile so the metric name stays visible while values scroll.
   Scoped to #usage-state's rows so the bill-trust + plan-grid tables
   stay neutral. */
#usage-state .bill-usage-row:nth-child(even) {
  background: rgba(255,255,255,.02);
}
[data-theme="light"] #usage-state .bill-usage-row:nth-child(even) {
  background: rgba(0,0,0,.02);
}
@media (max-width: 640px) {
  #usage-state .bill-usage-row {
    position: relative;
  }
  #usage-state .bill-usage-row > :first-child {
    position: sticky;
    left: 0;
    background: inherit;
    z-index: 1;
  }
}

/* WHY 17.7 — Available plan cards: equalize heights and pin CTA at the
   bottom. Without this the price + features stack at different heights
   and the "Subscribe" buttons land on different baselines, which reads
   as carelessness next to a real SaaS pricing page. */
.bill-plans-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 14px;
  align-items: stretch;
}
.bill-plans-grid > .plan,
.bill-plans-grid > .bill-plan-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.bill-plans-grid > .plan > .plan-btn,
.bill-plans-grid > .bill-plan-card > .plan-btn,
.bill-plans-grid > .plan > .pc-btn,
.bill-plans-grid > .bill-plan-card > .pc-btn {
  margin-top: auto;
  min-height: 44px;
}

/* WHY 17.8 — Credit-pack preset buttons: 4-up on desktop, 2-up on phone
   so each button keeps a readable tap target (current rule at line 297
   already does the 2-up; this just guarantees the 4-up at ≥640px wins
   when the bundle is concatenated against the page-local override). */
@media (min-width: 641px) {
  .bill-credits-presets {
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
  }
}
@media (max-width: 640px) {
  .bill-credits-presets {
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
  }
}

/* WHY 17.9 — Auto-recharge "How it works" copy was duplicated in two
   places after a refactor. The fix lives in JS (one copy only) but if
   the page renders two .bill-autotopup-howit blocks before JS hydrates,
   hide every duplicate. */
.bill-autotopup-empty + .bill-autotopup-howit ~ .bill-autotopup-howit { display: none; }

/* WHY 17.10 — Agency header collapses to 2 lines at ≤768px. The 6-item
   row (brand · eyebrow · role-pill · org · refresh · logout) clipped
   "Salir" off-screen on 390px. Wrap order: brand+eyebrow on row 1,
   the rest below; identity pushes utility buttons to the right. */
@media (max-width: 768px) {
  header.topbar {
    flex-wrap: wrap;
    row-gap: 8px;
    padding: 12px 18px;
    align-items: center;
    column-gap: 10px;
  }
  header.topbar .spacer { display: none; }
  header.topbar .brand { font-size: 18px; }
  header.topbar .eyebrow {
    padding-left: 8px;
    margin-left: 0;
    font-size: 9.5px;
  }
  header.topbar .pill {
    padding: 2px 7px;
    font-size: 9px;
  }
  header.topbar #topbar-orgname {
    font-size: 11px;
    flex: 1 0 100%;
    padding-left: 0;
    order: 5;
  }
  header.topbar .ident {
    flex: 0 0 auto;
    order: 6;
    margin-left: auto;
    font-size: 11px;
  }
  header.topbar .pc-btn,
  header.topbar .refresh {
    order: 7;
    min-height: 36px;
    padding: 6px 10px;
    font-size: 11px;
  }
}
@media (max-width: 640px) {
  header.topbar { gap: 6px; padding: 10px 14px; column-gap: 6px; }
  header.topbar .pc-btn,
  header.topbar .refresh {
    padding: 6px 9px;
    font-size: 10.5px;
  }
  /* Agency + admin stat tiles drop to 2-col so the 4-tile row doesn't
     overflow at narrow widths. Admin uses .grid-stats; agency reuses it. */
  .grid-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}

/* WHY 17.11 — Admin top-of-page tab strip: horizontal scroll-snap on
   ≤768px so the 10-tab row stays as a single discoverable strip
   instead of wrapping to 2-3 lines. Matches the analyzer sub-tab
   pattern R1 is using. */
@media (max-width: 768px) {
  .tabs[role="tablist"] {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 16px;
  }
  .tabs[role="tablist"]::-webkit-scrollbar { display: none; }
  .tabs[role="tablist"] > .tab {
    flex: 0 0 auto;
    scroll-snap-align: start;
    min-height: 44px;
  }
}

/* WHY 17.12 — Admin sys-strip badge row: touch target floor + truncate
   long impersonation/ID strings so the row stays readable on phone. */
.sys-strip .sys-chip {
  min-height: 32px;
  display: inline-flex;
  align-items: center;
}
@media (max-width: 640px) {
  .sys-strip { padding: 8px 14px; gap: 6px; }
  .sys-strip .sys-chip { font-size: 10.5px; padding: 4px 8px; }
  /* Admin table email cell — truncate at <640 so the row doesn't drag
     the table beyond viewport. Bound to .col-email so unrelated columns
     stay full-width. */
  td.col-email,
  td .truncate-email {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    vertical-align: bottom;
  }
}

/* WHY 17.13 — Admin KPI tiles (.stat inside .grid-stats) had the
   §1.1-sweep box-shadow stripped. Restore --shadow-sm on dark + cream
   so the 4-tile row reads as a contained surface, not a flat strip. */
.grid-stats .stat,
#ov-stats .stat {
  box-shadow: var(--shadow-sm);
}

/* WHY 17.14 — Pricing comparison table needs a horizontal scroll
   wrapper at <1024px so wide rows don't bust the viewport. The
   .pp-compare-wrap defined in §22.9 stays the visual frame; here we
   add the actual scroll affordance plus a fade-shadow on the right
   edge so the user has a visual cue that the table scrolls.
   `background-attachment: local, scroll` makes the right-edge fade
   travel WITH the scrolled content (so it disappears at the end of
   the scroll) — see https://lea.verou.me/2012/04/background-attachment-local/ */
@media (max-width: 1024px) {
  .pp-compare-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* Two-layer background: first a transparent "scroll buddy" layer
     * (so the visible fade only appears when there IS content to
     * scroll), then a right-pinned gradient that signals overflow. */
    background:
      linear-gradient(to right, var(--surface), var(--surface)) left center / 12px 100% no-repeat,
      linear-gradient(to right, color-mix(in oklab, var(--bg) 90%, transparent), transparent 28px) right center / 28px 100% no-repeat;
    background-attachment: local, scroll;
  }
  .pp-compare { min-width: 720px; }
}

/* WHY 17.15 — Pricing primary CTA: ensure ≥44px height + solid teal
   background with --accent-ink (9.46:1 contrast). The §22 .pp-card__cta
   defaults are mostly correct; this just guarantees the touch-target
   floor on mobile and locks the contrast. */
.pp-card__cta {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.pp-card__cta--primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.pp-card__cta--primary:hover {
  background: var(--accent-2);
  color: var(--accent-ink);
}

/* WHY 17.16 — Touch target floor on every interactive primitive at
   ≤768px. Builds on §F5.5 / §11.6 / §12.14; adds the surfaces R1's tab
   redesign hasn't covered yet (badges with role="button", .card-action,
   .pc-name-btn). */
@media (max-width: 768px) {
  .badge[role="button"],
  .badge.is-interactive,
  .pc-name-btn,
  .card-action {
    min-height: 44px;
  }
  .pc-icon-btn {
    min-height: 44px;
    min-width: 44px;
  }
}

/* WHY 17.16b — iOS Safari auto-zooms the viewport when a focused input
   has computed font-size < 16px. The audit (MB-01) found ~9 mobile-
   breakpoint input selectors at 13.5-15px. Initial fix forced 16px
   globally below 640px, but more-specific class selectors (.pp-auth__field
   input, .mup-input, .url-input) defeat `input { … }` on specificity →
   2026-05-19 audit caught the regression. We now duplicate the override
   for each class that beat us, with !important so the bundle-order
   ambiguity from runtime concatenation can't bite us either. */
@media (max-width: 640px) {
  input,
  select,
  textarea {
    font-size: 16px;
  }
  /* M-01 fix: high-specificity selectors that defeated the generic rule. */
  .pp-auth__field input,
  .url-input,
  .mup-input {
    font-size: 16px !important;
  }
}

/* WHY 17.16c — Tap-target floor for the topbar icon buttons (M-04 / P1-10).
   `.btn-icon` had no declared width/height; 14×14 SVG + default padding
   resolved to 32×32, under the WCAG 2.5.5 floor. Scope to ≤640px so the
   denser desktop topbar (and other .btn-icon hosts) keeps its existing
   geometry. Inside the topbar these stay flush with the bell/account
   slots because the parent uses align-items:center. */
@media (max-width: 640px) {
  .btn-icon {
    min-width: 40px;
    min-height: 40px;
  }
  /* Header lang toggle (M-06 / P1-12): 21×32 on every page. The F5.5 block
     already sets min-height:44px but flexible width was never enforced —
     bump padding so the 10.5px label cluster is reachable. */
  .lang-btn,
  .lang-btn-dash {
    min-width: 40px;
    min-height: 40px;
    padding: 8px 12px;
  }
}

/* WHY 17.17 — Skeleton consistency: extend the shipped
   [data-loading="true"] pattern (§agency add6324) to dashboard hero
   stat cards, billing plan card and credits balance. The shimmer
   animation + neutral surface are already defined at §16 above; we
   just register the additional surfaces that should opt in. */
[data-loading="true"] .dash-stat,
[data-loading="true"] .bill-plan-card,
[data-loading="true"] #current-state,
[data-loading="true"] #credits-state .bill-credits-amount {
  position: relative;
  overflow: hidden;
  background: var(--surface-2, rgba(255,255,255,.04));
  border-radius: var(--radius-md, 12px);
  min-height: 56px;
  color: transparent;
}
[data-loading="true"] .dash-stat::after,
[data-loading="true"] .bill-plan-card::after,
[data-loading="true"] #current-state::after,
[data-loading="true"] #credits-state .bill-credits-amount::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.06), transparent);
  animation: shimmer 1.4s infinite;
}
@media (prefers-reduced-motion: reduce) {
  [data-loading="true"] .dash-stat::after,
  [data-loading="true"] .bill-plan-card::after,
  [data-loading="true"] #current-state::after,
  [data-loading="true"] #credits-state .bill-credits-amount::after { animation: none; }
}

/* WHY 17.18 — Mobile domain-grid pagination affordance. JS hides cards
   beyond the first 9 by adding .is-hidden, then a "Mostrar más" button
   reveals the rest. This rule just gives the hide state + the CTA
   below the grid a consistent look. */
.domains-grid .domain-card.is-hidden { display: none; }
.domains-grid + .domains-load-more {
  display: grid;
  place-items: center;
  margin: -24px auto 32px;
}
.domains-grid + .domains-load-more .pc-btn {
  min-height: 44px;
  padding: 10px 22px;
}

/* WHY 17.19 — Extras-section "Total: €X.XX" — keep the running total
   visually obvious. Pairs with the existing .bill-domains-cost block
   (already styled) but bumps the readability of the standalone total
   row some pages render outside the grid. */
.bill-domains-state .total,
.bill-domains-total {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════════════════
   LIQUID GLASS — iOS dark-mode systemMaterial overlay
   ───────────────────────────────────────────────────────────────────
   Applied via token swap so a single set of rules covers both themes:
     - Dark (:root default)   → translucent rgba + backdrop-filter blur
     - Light ([data-theme])   → falls back to solid surface tokens
   Keeps the existing class API untouched (.pc-card, .score-pill, etc).
   ═══════════════════════════════════════════════════════════════════ */
:root {
  --glass-surface:        rgba(255,255,255,.07);
  --glass-surface-strong: rgba(255,255,255,.13);
  --glass-edge:           rgba(255,255,255,.16);
  --glass-edge-strong:    rgba(255,255,255,.24);
  --glass-bar-bg:         rgba(14,20,22,.88);
  --glass-nav-bg:         rgba(22,28,30,.86);
  --glass-blur-card:      blur(40px) saturate(180%);
  --glass-blur-tile:      blur(24px) saturate(160%);
  --glass-blur-bar:       blur(36px) saturate(180%);
  --glass-blur-nav:       blur(60px) saturate(180%);
  --glass-edge-light:     rgba(255,255,255,.12);
  --glass-radius-card:    18px;
  --glass-shadow-card:
    inset 0 1px 0 rgba(255,255,255,.09),
    0 10px 28px -10px rgba(0,0,0,.6),
    0 1px 0 rgba(0,0,0,.3);
  --glass-shadow-nav:
    inset 0 0.5px 0 rgba(255,255,255,.16),
    0 12px 40px -8px rgba(0,0,0,.55);
}
[data-theme="light"] {
  /* Light mode opts out of glass — preserve solid surfaces. */
  --glass-surface:        var(--surface);
  --glass-surface-strong: var(--surface-2);
  --glass-edge:           var(--border);
  --glass-edge-strong:    var(--border-2);
  --glass-bar-bg:         var(--surface);
  --glass-nav-bg:         var(--surface);
  --glass-blur-card:      none;
  --glass-blur-tile:      none;
  --glass-blur-bar:       none;
  --glass-blur-nav:       none;
  --glass-edge-light:     transparent;
  --glass-shadow-card:    none;
  --glass-shadow-nav:     0 4px 24px rgba(0,0,0,.12), 0 1px 4px rgba(0,0,0,.08);
}

/* Primary card surfaces — translucent in dark, solid in light. */
.pc-card,
.bill-card,
.domain-card,
.portfolio-health,
.pc-callout {
  background: var(--glass-surface);
  border-color: var(--glass-edge);
  border-radius: var(--glass-radius-card);
  box-shadow: var(--glass-shadow-card);
  -webkit-backdrop-filter: var(--glass-blur-card);
  backdrop-filter: var(--glass-blur-card);
}

/* Smaller tiles — lighter blur, no top-edge shadow. */
.ph-tile {
  background: var(--glass-surface);
  border-color: var(--glass-edge);
  box-shadow: inset 0 0.5px 0 var(--glass-edge-light);
  -webkit-backdrop-filter: var(--glass-blur-tile);
  backdrop-filter: var(--glass-blur-tile);
}

/* Score-pill strip wrapper — fully transparent pass-through. No
   backdrop-filter on the wrapper itself (that painted a fuzzy blur
   band across the full width of the strip). Each .score-pill carries
   its own glass blur so only the bubbles render the frosted look. */
.score-pill-strip {
  background: transparent;
  border: none;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.score-pill-strip .score-pill {
  background: var(--glass-surface-strong);
  border-color: var(--glass-edge);
  border-radius: 999px;
  box-shadow: inset 0 0.5px 0 var(--glass-edge-light);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
}
.score-pill-strip .score-pill:hover {
  background: var(--glass-surface-strong);
  border-color: var(--glass-edge-strong);
}

/* Results bar — sticky frosted nav. */
.results-bar {
  background: var(--glass-bar-bg);
  border-color: var(--glass-edge);
  -webkit-backdrop-filter: var(--glass-blur-bar);
  backdrop-filter: var(--glass-blur-bar);
}

/* Bottom mobile nav — iOS Tab Bar material (dark-tinted heavy frost).
   [data-theme]-prefixed selectors beat inline `.an-mobile-nav { … }`
   declared inside @media blocks in analyzer.html. */
:root .an-mobile-nav,
[data-theme="dark"] .an-mobile-nav {
  background: var(--glass-nav-bg);
  border-color: rgba(255,255,255,.12);
  box-shadow: var(--glass-shadow-nav);
  -webkit-backdrop-filter: var(--glass-blur-nav);
  backdrop-filter: var(--glass-blur-nav);
}
:root .an-mobile-nav__item--primary,
[data-theme="dark"] .an-mobile-nav__item--primary {
  background: rgba(61,219,194,.22);
  border-color: rgba(61,219,194,.36);
  color: var(--accent);
  box-shadow: inset 0 0.5px 0 rgba(255,255,255,.14);
}
[data-theme="light"] .an-mobile-nav {
  background: var(--surface);
  border-color: var(--border);
  box-shadow: 0 4px 24px rgba(0,0,0,.12), 0 1px 4px rgba(0,0,0,.08);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* ════════════════════════════════════════════════════════════════════
   ── 27. MOBILE REDESIGNS — 8 SUB-SECTION IMPROVEMENTS (2026-05-20) ──
   All rules scoped to max-width:640px. Desktop layout untouched.
   ════════════════════════════════════════════════════════════════════ */

/* ── 1. Posicionamiento: table → query-card rows ────────────────── */
@media(max-width:640px){
  .pos-table{display:block}
  .pos-table thead{display:none}
  .pos-table tbody{display:block}
  .pos-table tbody tr{
    display:flex;flex-wrap:wrap;align-items:center;
    padding:14px;margin-bottom:8px;
    background:var(--glass)!important;
    border:1px solid var(--glass-edge)!important;
    border-radius:13px!important;
    backdrop-filter:blur(40px) saturate(180%);
    -webkit-backdrop-filter:blur(40px) saturate(180%);
    box-shadow:inset 0 0.5px 0 rgba(255,255,255,.06),0 1px 0 rgba(0,0,0,.25);
    gap:0;
  }
  .pos-table tbody tr td{padding:0;border:none}
  /* keyword — full width first row */
  .pos-table .pos-query{
    flex-basis:100%;order:1;
    font-size:14px;font-weight:700;letter-spacing:-.01em;color:var(--text);
    white-space:normal;max-width:100%;overflow:visible;text-overflow:unset;
    padding-bottom:10px;margin-bottom:8px;
    border-bottom:1px solid var(--border);
  }
  /* type chip — show as footer */
  .pos-table tbody tr td:nth-child(2){
    order:5;flex-basis:100%;display:block!important;
    padding-top:8px;margin-top:6px;
    border-top:1px solid var(--border);
  }
  /* priority badge — second row right */
  .pos-table tbody tr td:nth-child(3){order:2;margin-left:auto;flex-shrink:0;margin-bottom:6px}
  /* rank cells — third row, flex */
  .pos-table .pos-cell{
    order:3;font-size:11.5px;flex-shrink:0;
    display:flex;flex-direction:column;align-items:center;gap:2px;
    margin-right:10px;
  }
  /* GEO score (last pos-cell or td[id^=geoscore]) — big accent number right */
  .pos-table tbody tr td[id^=geoscore]{
    order:4;margin-left:auto;
    font-size:20px;font-weight:800;
    color:var(--accent);
    font-variant-numeric:tabular-nums;letter-spacing:-.04em;
  }
}

/* ── 2. Multi-IA: chip switcher ─────────────────────────────────── */
.mia-chips{display:none}
@media(max-width:640px){
  .mia-chips{
    display:flex;overflow-x:auto;gap:6px;padding-bottom:10px;margin-bottom:4px;
    scrollbar-width:none;-webkit-overflow-scrolling:touch;
  }
  .mia-chips::-webkit-scrollbar{display:none}
  .mia-chip{
    flex-shrink:0;padding:6px 14px;border-radius:20px;
    background:var(--surface-2);border:1px solid var(--border);
    color:var(--text-muted);font-size:12.5px;font-weight:600;cursor:pointer;
    white-space:nowrap;font-family:inherit;
    transition:background .15s,color .15s,border-color .15s;
  }
  .mia-chip--active{
    background:var(--accent-soft);border-color:rgba(61,219,194,.3);color:var(--accent);
  }
  .mia-panel{display:none}
  .mia-panel--active{display:block}
}
@media(min-width:641px){
  .mia-panel{display:block!important}
}

/* ── 3. Brand SERP: links-table → query card rows ───────────────── */
@media(max-width:640px){
  #serp-results .links-table{display:block;min-width:0!important}
  #serp-results .links-table thead{display:none}
  #serp-results .links-table tbody{display:block}
  #serp-results .links-table tr{
    display:block;padding:10px 12px;margin-bottom:6px;
    background:var(--surface-2);border:1px solid var(--border);border-radius:10px;
  }
  #serp-results .links-table td{display:block;padding:0;border:none}
  #serp-results .links-table td:first-child{
    font-size:13px;font-weight:600;color:var(--text);
    white-space:normal;margin-bottom:8px;
  }
  #serp-results .links-table td:not(:first-child){
    display:inline-flex;align-items:center;justify-content:center;
    width:34px;height:34px;border-radius:50%;
    background:var(--surface-3);border:1px solid var(--border);
    font-size:14px;margin-right:4px;vertical-align:middle;
  }
}

/* ── 4. Canibalización: dual-render (desktop table / mobile accordion) */
@media(min-width:641px){.cann-mobile{display:none}}
@media(max-width:640px){.cann-desktop{display:none}}

.cann-group{
  border:1px solid var(--border);border-radius:10px;margin-bottom:8px;
  overflow:hidden;background:var(--surface-2);
}
.cann-grp-hdr{
  width:100%;display:flex;align-items:center;gap:8px;
  padding:12px 14px;background:none;border:none;cursor:pointer;
  font-family:inherit;color:var(--text);text-align:left;
}
.cann-grp-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.cann-grp-label{flex:1;font-size:13.5px;font-weight:700}
.cann-grp-count{
  font-size:11px;font-weight:700;padding:2px 7px;border-radius:20px;
  background:var(--surface-3);color:var(--text-muted);
}
.cann-chevron{
  flex-shrink:0;color:var(--text-muted);
  transition:transform .2s cubic-bezier(0.16,1,0.3,1);
}
.cann-group--open .cann-chevron{transform:rotate(180deg)}
.cann-grp-body{
  display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .25s cubic-bezier(0.16,1,0.3,1);
}
.cann-group--open .cann-grp-body{grid-template-rows:1fr}
.cann-grp-inner{overflow:hidden}
.cann-item{padding:10px 14px;border-top:1px solid var(--border)}
.cann-keyword{font-size:13px;font-weight:700;color:var(--text);margin-bottom:3px}
.cann-primary{
  font-size:11.5px;color:var(--text-muted);margin-bottom:4px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;
}
.cann-cannibs{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
.cann-cannib{
  font-size:10.5px;padding:2px 8px;border-radius:20px;
  background:rgba(239,68,68,.1);color:var(--fail);border:1px solid rgba(239,68,68,.2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px;
}

/* ── 5. Share of Voice: compact cells for horizontal scroll ─────── */
@media(max-width:640px){
  #sov-table-wrap table{font-size:11.5px}
  #sov-table-wrap th,#sov-table-wrap td{padding:5px 6px;white-space:nowrap}
  #sov-table-wrap td:first-child{max-width:80px;overflow:hidden;text-overflow:ellipsis}
}

/* ── 6. Plan de Acción: tracker rows → stacked ──────────────────── */
@media(max-width:640px){
  .act-row{display:flex!important;flex-direction:column;gap:8px}
  .act-row select{align-self:flex-start}
  .act-row > div:last-child{flex-direction:row!important;align-items:center;gap:10px}
}

/* ── 7. Autoridad: 2-col grid → single column ───────────────────── */
@media(max-width:640px){
  .auth-grid{grid-template-columns:1fr!important}
}

/* ── 8. Competidores: GBP URL row → stacked ─────────────────────── */
@media(max-width:640px){
  #gbp-url-row{flex-direction:column}
  #gbp-url-row input{width:100%}
  #gbp-url-row button{align-self:stretch}
}

/* ════════════════════════════════════════════════════════════════════
   ── 28. MOBILE RESUMEN + PLAN DE ACCIÓN REDESIGN (2026-05-21) ───────
   Score hero compact horizontal, severity 2×2, actions card polish.
   ════════════════════════════════════════════════════════════════════ */

/* ── Score hero: centered design matching mobile-preview ────────── */
@media(max-width:640px){
  .score-section.score-section--hero{
    grid-template-columns:1fr!important;
    text-align:center!important;
    gap:14px;
    padding:20px 16px!important;
    margin:8px 0 12px;
    /* Glassmorphism — matches preview card */
    background:rgba(255,255,255,.06)!important;
    border-color:rgba(255,255,255,.10)!important;
    backdrop-filter:blur(40px) saturate(180%);
    -webkit-backdrop-filter:blur(40px) saturate(180%);
    box-shadow:inset 0 0.5px 0 rgba(255,255,255,.08),0 1px 0 rgba(0,0,0,.25);
  }
  .score-section.score-section--hero .score-ring-wrap{
    width:148px!important;
    height:148px!important;
    margin:0 auto!important;
    align-self:center;
  }
  .score-section.score-section--hero .score-number{font-size:40px!important}
  .score-section.score-section--hero .score-text{font-size:9px;margin-top:2px}
  .score-section.score-section--hero .score-meta{
    text-align:center!important;
    align-items:center!important;
    gap:7px;
  }
  .score-section.score-section--hero .score-meta h2{font-size:16px}
  .score-section.score-section--hero .score-meta>p{display:block!important;font-size:11.5px}
  .score-section.score-section--hero #fetchQualityBadge{display:none!important}
  .score-section.score-section--hero .sub-scores{
    justify-content:center!important;
    flex-wrap:nowrap!important;
    gap:6px;
  }
  .score-section.score-section--hero .sub-scores .sub-score{
    flex:1 1 0;min-width:0;padding:7px 8px!important;
  }
  .score-section.score-section--hero .sub-scores .score-mini{padding:5px 8px}
  .score-section.score-section--hero .sub-scores .score-mini-n{font-size:18px}
  .score-section.score-section--hero .sub-scores .score-mini-l{font-size:8.5px}
  /* action buttons: centered, scrollable if many */
  .score-section.score-section--hero .action-btns{
    justify-content:center!important;
    flex-wrap:nowrap;
    overflow-x:auto;
    scrollbar-width:none;
    gap:5px;
    padding-bottom:2px;
    margin-top:0;
  }
  .score-section.score-section--hero .action-btns::-webkit-scrollbar{display:none}
  .score-section.score-section--hero .action-btns .pc-btn{
    flex-shrink:0;
    font-size:11px;
    padding:5px 9px;
    gap:4px;
  }
}

/* ── Severity rollup: extend 2×2 grid to full 640px range ───────── */
@media(max-width:640px){
  .severity-rollup .sr-grid{
    grid-template-columns:repeat(2,minmax(0,1fr))!important;
    gap:8px;
  }
  .severity-rollup .sr-cell{padding:10px 12px}
  .severity-rollup .sr-cell-n{font-size:20px}
}

/* ── Plan de Acción: header action buttons → stacked on mobile ───── */
@media(max-width:640px){
  .act-header-actions{flex-direction:column!important;gap:6px!important}
  .act-header-actions .pc-btn{justify-content:center;width:100%}
}

/* ── Plan de Acción: priority action row → 2-col + score footer ─── */
@media(max-width:640px){
  .act-pact-row{
    grid-template-columns:30px 1fr!important;
    grid-template-rows:auto auto;
    gap:4px 10px!important;
    padding:12px 14px!important;
  }
  .act-pact-n{grid-column:1;grid-row:1;font-size:16px!important}
  .act-pact-row>div:nth-child(2){grid-column:2;grid-row:1}
  .act-pact-scores{
    grid-column:1/-1!important;
    grid-row:2!important;
    text-align:left!important;
    display:flex!important;
    gap:10px!important;
    flex-wrap:wrap;
    padding-top:8px;
    border-top:1px solid var(--border);
    margin-top:2px;
  }
}

/* ── Tracker status summary: wrap cleanly ───────────────────────── */
@media(max-width:640px){
  .act-status-row{flex-wrap:wrap!important;gap:5px!important}
  .act-status-row>span{font-size:11px!important}
}

/* ── Tracker custom action form: compact ────────────────────────── */
@media(max-width:640px){
  #tab-actions details>div[style*="grid-template-columns:1fr 1fr"]{
    grid-template-columns:1fr!important;
  }
  #tab-actions details>div>div[style*="display:flex"]{
    flex-wrap:wrap;gap:6px;
  }
}

/* ===== prisma-fonts.css ===== */
/* prisma-fonts.css — self-hosted @font-face declarations.

   P3-O (2026-05-15) landed: Geist + Geist Mono + Instrument Serif are now
   served from /fonts/*.woff2 instead of fonts.gstatic.com. Benefits:
     1. One less DNS + TLS handshake per page (faster TTI, esp. on cold
        mobile cellular where the gstatic.com hop is ~150-400ms).
     2. CSP can be tightened — fonts.googleapis.com drops out of style-src
        and fonts.gstatic.com drops out of font-src once HTML pages stop
        preconnecting/importing them. (Migration is incremental: pages that
        still <link> Google Fonts directly will continue to work; this
        file only governs the prisma-base.css trio.)
     3. Privacy — no more Referer + IP leak to Google for every page view.

   Source: fetched 2026-05-15 from
   https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700;800;900&family=Geist+Mono:wght@400;500;600;700&family=Instrument+Serif:ital,wght@0,400;1,400
   using a Chrome 120 User-Agent. Geist + Geist Mono ship as a single
   variable WOFF2 per subset (one file covers weights 400-900); Instrument
   Serif ships one regular + one italic file per subset. Only the `latin`
   and `latin-ext` subsets are vendored — sufficient for ES/EN/FR/DE/IT
   audiences. If we ever ship Cyrillic/Vietnamese, add those subsets here.

   Total payload (8 files): ~172 KB on disk, ~165 KB over the wire.
   The browser only downloads the subset(s) it actually needs based on
   unicode-range, so a typical Spanish page fetches just `latin.woff2`. */


/* ── Geist (UI font) — variable, weights 400-900 ─────────────────────── */

/* latin-ext: covers Á-Ž, Ŀ-ş, Ž-ž, € fallbacks, smcp marks for ES/PT/IT/RO */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('/fonts/Geist-Variable-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin: ASCII + Latin-1 supplement (ñ, á, ü…), curly quotes, € */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('/fonts/Geist-Variable-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}


/* ── Geist Mono (data/code) — variable, weights 400-700 ───────────────── */

@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/GeistMono-Variable-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/GeistMono-Variable-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}


/* ── Instrument Serif — display italic for editorial accents ──────────── */

@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/InstrumentSerif-Regular-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/InstrumentSerif-Regular-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}

@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/InstrumentSerif-Italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/InstrumentSerif-Italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}

