/* ============================================================
 * nav-global-fix-2026-05-27.css — GLOBAL canonical nav + footer
 * (head-of-FE fix). nav-inject.js injects the mega-nav whose styles
 * live in sovereign-primitives.css/styles.css, which the transformed
 * pages don't load (only sovereign-core-v2.compiled.css) → the nav
 * rendered as a 746px unstyled static stack on every page.
 * This self-contained GLASS nav restores a 72px sticky bar everywhere.
 * Injected by nav-inject.js so it loads on all pages. Teal accent.
 * ============================================================ */
:root { --ca-nav-h: 72px; }

/* fixed glass bar */
nav[aria-label="Main navigation"], nav.nav-frosted, .sv-nav {
  position: fixed !important; inset: 0 0 auto 0; z-index: var(--z-toast);
  height: var(--ca-nav-h); box-sizing: border-box;
  display: flex !important; flex-direction: row !important; align-items: center;
  padding: 0 clamp(16px, 4vw, 48px);
  background: rgba(4, 14, 26, 0.72);
  -webkit-backdrop-filter: saturate(160%) blur(16px); backdrop-filter: saturate(160%) blur(16px);
  border-bottom: 1px solid rgba(12, 201, 168, 0.16);
}
/* inner wrapper → row, space-between, capped width */
nav[aria-label="Main navigation"] > .wrap,
nav[aria-label="Main navigation"] > .sv-container,
nav[aria-label="Main navigation"] > div,
nav.nav-frosted > div {
  display: flex !important; flex-direction: row !important; align-items: center; justify-content: space-between;
  gap: var(--space-6); width: 100%; max-width: 1280px; margin: 0 auto; height: var(--ca-nav-h);
}
/* links row */
nav .nav-links, nav .nav-links.sv-cluster {
  display: flex !important; flex-direction: row !important; align-items: center; gap: var(--space-5); flex-wrap: nowrap; margin: 0;
}
nav .nav-links a, nav .nav-dropdown-trigger {
  color: rgba(232, 240, 250, 0.72); font-size: var(--text-sm); font-weight: 600; white-space: nowrap;
  text-decoration: none; line-height: 1; display: inline-flex; align-items: center; gap: var(--space-1); cursor: pointer;
}
nav .nav-links a:hover, nav .nav-dropdown-trigger:hover { color: var(--white); }
/* dropdowns must NOT inflate the bar — absolute, hidden until hover/focus */
nav .nav-dropdown { position: relative; }
nav .nav-mega {
  position: absolute; top: calc(100% + 10px); left: 50%; transform: translateX(-50%);
  display: none; min-width: 640px; padding: 24px;
  background: rgba(8, 18, 30, 0.98); -webkit-backdrop-filter: blur(24px); backdrop-filter: blur(24px);
  border: 1px solid rgba(12, 201, 168, 0.24); border-radius: 20px; box-shadow: 0 40px 100px -20px rgba(0, 0, 0, 0.9);
  z-index: var(--z-toast) !important;
}
/* transparent hover-bridge over the gap so moving the cursor from the trigger to the
   menu does NOT lose :hover (was the "very hard to click" bug). */
nav .nav-mega::before { content: ''; position: absolute; top: -30px; left: -100px; right: -100px; height: 40px; background: transparent; }
nav .nav-dropdown, nav .nav-item.has-dropdown, nav li:has(> .nav-mega) { position: relative; }
nav .nav-dropdown:hover > .nav-mega, nav .nav-dropdown:focus-within > .nav-mega,
nav .nav-item.has-dropdown:hover > .nav-mega, nav li:hover > .nav-mega, nav .nav-mega:hover {
  display: grid !important; grid-auto-flow: column; gap: var(--space-5);
}
nav .nav-mega-col { display: flex; flex-direction: column; gap: var(--space-1); min-width: 240px; }
nav .nav-mega-label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.12em; color: rgba(232, 240, 250, 0.5); padding: 4px 8px; }

/* ── LM-160: SITEWIDE TINY-TEXT FLOOR (owner 2026-05-30) ──
   Page-content labels were rendering at 9–10px (below the readable floor).
   Premium sites use 11–12px for uppercase tracking labels, never 9–10px.
   nav-global-fix loads LAST so this overrides the purged Tailwind utilities. */
.ca-eyebrow,
.ca-marquee-item,
.badge-cookie,
.legal-aside__label,
.ca-card-tags, .ca-card-tags span,
.ca-product-capsule, .ca-capsule,
[class*="text-[9px]"],
[class*="text-[10px]"] {
  font-size: var(--text-xs) !important;
}
/* owner 2026-05-30: the 4 homepage product cards' statute capsules sat right against
   the description text (margin-top:auto collapses to 0 in their block container).
   Add clear breathing room above the capsule row + comfortable spacing between chips. */
.ca-card-tags { margin-top: var(--space-4) !important; gap: var(--space-2) 10px !important; padding-top: var(--space-0); }
.ca-card-tags span {
  padding: 5px 12px !important; line-height: 1.4 !important;
  /* owner 2026-05-30: the statute capsule numbers (SI 2002/1674, 44+22 CE+, PPN 014/21…)
     were dim grey-on-dark (low contrast / "not visible"). Brighten the text + give the
     chip a touch more definition so the figures read clearly. */
  color: rgba(232, 240, 250, 0.82) !important;
  background: rgba(255, 255, 255, 0.07) !important;
  border-color: rgba(255, 255, 255, 0.16) !important;
}
/* breadcrumbs / TOC labels / table headers read better at 12px */
:is(.prose, .blog-stripe-prose, .article-body, .legal-doc, .legal-shell) th,
.ca-breadcrumb, .ca-breadcrumb *,
.ca-toc-label, .toc-label, [class*="text-[11px]"] {
  font-size: var(--text-xs) !important;
}

/* ── LM-161: tap targets (owner 2026-05-30) — icon-only controls >=44px
   (WCAG 2.5.8 / premium). Text links get a modest tap-area lift without
   ballooning the footer columns. ── */
.foot-social a, .footer-social a,
.ca-share a, .ca-share button,
[class*="share"] a[aria-label], [class*="share"] button[aria-label] {
  min-width: 44px; min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
}
.ca-footer .footer-links a { padding-block: var(--space-1); }
nav .nav-mega-item { display: flex; gap: var(--space-2); align-items: flex-start; padding: 8px; border-radius: 10px; color: rgba(232, 240, 250, 0.86); text-decoration: none; }
nav .nav-mega-item:hover { background: var(--teal-08); }
nav .nav-mega-item strong { color: var(--white); font-weight: 700; }
nav .nav-mega-desc { display: block; font-size: var(--text-xs); color: rgba(232, 240, 250, 0.65); margin-top: var(--space-0); }
nav .nav-mega-icon { flex-shrink: 0; margin-top: var(--space-0); }
/* logo + CTA */
nav .logo, nav .sv-logo, nav .nav-logo, nav .nav-cta-group { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; }
/* offset page content below the fixed bar (nav-inject nav was previously static) */
body { padding-top: var(--ca-nav-h); }
html { scroll-padding-top: calc(var(--ca-nav-h) + 12px); }
/* UX-012 (owner 2026-05-30): smooth anchor scrolling (FAQ + in-page jumps), reduced-motion-safe */
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

/* ── SCROLL PROGRESS BAR (owner 2026-05-30): restore + make global ──
   The reading-progress bar lost its height (rendered 0px) and only existed on the
   homepage. nav-inject now injects #scroll-progress on every long page; this styles
   it. Width is set 0→100% by the scroll handler. Sits as a thin line at the top edge. */
/* Reading-progress bar must sit ABOVE the fixed nav. The nav uses
   var(--z-toast) (1200); the bar previously also used --z-toast, so at equal
   z-index the nav (later in the DOM) painted over the 3px bar and it vanished
   behind the header — the 2026-06-02 z-index-ladder refactor introduced this
   collision. Promote the bar one rung above the nav (and the cookie rung 1250)
   so the indicator is always visible at the very top edge. */
:root { --z-progress: 1260; }
#scroll-progress, .scroll-progress {
  /* GPU-only progress bar: full-width element scaled on the X axis via transform
     (JS sets scaleX), so the per-scroll update composites on the GPU instead of
     animating `width` (layout/repaint every frame). */
  position: fixed; top: 0; left: 0; height: 3px; width: 100%;
  transform: scaleX(0); transform-origin: left center;
  background: linear-gradient(90deg, var(--teal, var(--teal)), var(--teal-d));
  z-index: var(--z-progress); pointer-events: none; will-change: transform;
  box-shadow: 0 0 8px rgba(12, 201, 168, 0.5);
}
@media (prefers-reduced-motion: no-preference) { #scroll-progress { transition: transform 0.08s linear; } }
#scroll-progress[hidden], body[data-progress-suppress] #scroll-progress { display: none; }

/* eyebrow capsule dot (owner 2026-05-30): the dot sat on the line-box centre, which is
   visually LOW vs uppercase tracking text (caps centre higher). Nudge it up 1px to
   optically centre with the text. Sitewide (all eyebrow capsules). */
.ca-eyebrow-dot { position: relative; top: -3px; flex: 0 0 auto; align-self: center; }

/* Sector marquee (home "Sectors served" band) — owner 2026-05-30 "still so slow".
   ROOT CAUSE: the list box was clamped to the viewport width (~1280px) while its content
   (2 identical copies of 12 sectors) spans ~7231px. translateX(-50%) is relative to the
   element's own box, so it only travelled ~640px then snapped back = a slow, broken crawl
   that never looped seamlessly. width:max-content makes the box equal the true content
   width, so -50% scrolls exactly one full copy (~3615px) = seamless continuous loop.
   ~3615px / 40s ≈ 90px/s = brisk and readable. flex:0 0 auto stops items from shrinking.
   nav-global-fix loads last so this wins over ca-primitives/finishing-pass. */
.ca-marquee-list { width: max-content !important; animation-duration: 40s !important; }
.ca-marquee-item { flex: 0 0 auto !important; }

/* eyebrow ROTATOR FOUC (owner 2026-05-30): the hero eyebrow has 4 rotating fact spans,
   all visible by default → on every refresh ALL of them flashed (stacked) before
   eyebrow-rotator.js collapsed them to one ("all the text shows for a fraction of a
   second"). Hide items 2..n in CSS (before JS); item 1 stays visible as the failsafe.
   The JS then takes over the rotation unchanged. */
[data-eyebrow-rotator] { position: relative; }
/* ROOT FIX (owner 2026-05-30): the dot was misaligned DIFFERENTLY per rotating text
   because item0 was a relative line (16px) but items 1-3 were absolute inset:0 = the
   28px PADDED container with top-aligned text, so each fact sat at a different height.
   The .ca-eyebrow-vp viewport is sized by item0's line; items 1-3 (absolute inset:0)
   now fill THAT line, so all 4 facts share one baseline and the dot aligns to every one. */
.ca-eyebrow-vp { position: relative; display: inline-flex; align-items: center; }
.ca-eyebrow-vp [data-eyebrow-item] ~ [data-eyebrow-item] {
  position: absolute !important; inset: 0 !important; display: flex; align-items: center;
  opacity: 0; pointer-events: none;
}

/* ── CAROUSEL caption "Sample Data" box (owner 2026-05-30): was a tall (201px) dark
   glass box where the caption wrapped. Make it a sleek WHITE bar — wider (longer) so
   the caption fits on one line → low height. ── */
[class*="max-w-xl"]:has(.pcar__caption) { max-width: 820px !important; }
.ca-glass-premium:has(.pcar__caption) {
  background: rgba(255, 255, 255, 0.96) !important;
  border-color: rgba(0, 0, 0, 0.08) !important;
  padding: 7px 16px !important;
  backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
}
.pcar__caption { color: var(--surface-1) !important; -webkit-text-fill-color: var(--surface-1) !important; white-space: nowrap !important; overflow: hidden; text-overflow: ellipsis; }
.ca-glass-premium:has(.pcar__caption) [class*="text-white/30"]:not(#_) { color: var(--bg) !important; -webkit-text-fill-color: var(--bg) !important; border-color: rgba(0, 0, 0, 0.18) !important; }
.ca-glass-premium:has(.pcar__caption) [class*="bg-white/10"] { background: rgba(0, 0, 0, 0.12) !important; }
/* dots: the 44px hit area (.pcar__tab rule below) is TRANSPARENT; the visible dot is
   the ::before. On the white context bar the inactive dot is dark, active is teal. */
.ca-glass-premium:has(.pcar__caption) .pcar__tab { background: transparent !important; }
.ca-glass-premium:has(.pcar__caption) .pcar__tab::before { background: rgba(0, 0, 0, 0.28) !important; }
.ca-glass-premium:has(.pcar__caption) .pcar__tab[aria-selected="true"]::before, .ca-glass-premium:has(.pcar__caption) .pcar__tab.is-active::before { background: var(--teal, var(--teal)) !important; width: 20px !important; }

/* ── FORM INPUT VISIBILITY (owner 2026-05-30, bugs #7/#8/#9) ──
   On contact / partners / about / regulatory-updates forms the inputs used
   !bg-white/5 (+ white text) for a translucent dark field. Those arbitrary opacity
   utilities were PURGED, so the field fell back to SOLID WHITE bg with WHITE text →
   invisible while typing. Restore the intended translucent-dark field + ensure the
   typed text + placeholder are visible. (These forms sit on dark sections.) */
.form-input,
input[class*="bg-white/5"], input[class*="bg-white/10"],
textarea[class*="bg-white/5"], textarea[class*="bg-white/10"],
select[class*="bg-white/5"], select[class*="bg-white/10"] {
  background-color: var(--white-06) !important;
  color: var(--white) !important; -webkit-text-fill-color: var(--white) !important;
  border-color: rgba(255, 255, 255, 0.14) !important;
}
.form-input::placeholder,
input[class*="bg-white/5"]::placeholder, input[class*="bg-white/10"]::placeholder,
textarea[class*="bg-white/5"]::placeholder, textarea[class*="bg-white/10"]::placeholder {
  color: rgba(255, 255, 255, 0.42) !important; -webkit-text-fill-color: rgba(255, 255, 255, 0.42) !important;
}
/* BROWSER AUTOFILL (owner 2026-05-30): when Chrome/Edge autofills a dark-form field it
   paints a light autofill background but keeps the white text → invisible while typed in.
   Force a dark autofill background (box-shadow inset hack) + white text on the dark-form
   inputs. Scoped so the white-bg VSME/checker fields (dark text) are NOT affected. */
.form-input:-webkit-autofill, .form-input:-webkit-autofill:hover, .form-input:-webkit-autofill:focus, .form-input:-webkit-autofill:active,
input[class*="bg-white/5"]:-webkit-autofill, input[class*="bg-white/5"]:-webkit-autofill:hover, input[class*="bg-white/5"]:-webkit-autofill:focus,
input[class*="bg-white/10"]:-webkit-autofill, input[class*="bg-white/10"]:-webkit-autofill:hover, input[class*="bg-white/10"]:-webkit-autofill:focus,
textarea[class*="bg-white/5"]:-webkit-autofill, textarea[class*="bg-white/10"]:-webkit-autofill {
  -webkit-text-fill-color: var(--white) !important;
  -webkit-box-shadow: 0 0 0 1000px var(--ca-c-0d2240) inset !important;
  box-shadow: 0 0 0 1000px var(--ca-c-0d2240) inset !important;
  caret-color: var(--white) !important;
  transition: background-color 600000s 0s, color 600000s 0s;
}

/* bug #4: blog "Search insights" input — the !pl-14 (left padding for the search
   icon) was purged, so the placeholder/text overlapped the icon. Restore padding. */
.blog-search-input { padding-left: 3.25rem !important; }

/* ── FREE-TOOLS "The Process / Three steps" cards (owner 2026-05-30) ──
   The .tool-step cards have a DARK slate background but sit inside a ca-section-light
   (white) section, which forces color:var(--bg) on every descendant → the heading + body
   rendered dark-on-dark (unreadable). Force LIGHT text inside the dark cards (text-fill
   trap). The .tool-step-num sits on a teal circle so it stays dark. Sitewide (all 6 tools). */
/* :not(#_) adds id-level specificity so these beat `section.ca-section-light *`
   (0,1,1, !important) which otherwise forces dark text on these dark cards. */
.tool-step-heading:not(#_) { color: var(--white) !important; -webkit-text-fill-color: var(--white) !important; }
.tool-step-body:not(#_) { color: rgba(232, 240, 250, 0.82) !important; -webkit-text-fill-color: rgba(232, 240, 250, 0.82) !important; }

/* free-tools "Back to all free tools" capsule (owner 2026-05-30): it intended teal text
   via !text-[var(--accent)] / !bg-[var(--accent)]/10 / !border-[var(--accent)]/20 — all PURGED, so the
   text was invisible. Restore the teal pill explicitly (id-level specificity to win). */
a.ca-product-capsule[class*="0CC9A8"]:not(#_), a.ca-capsule[class*="0CC9A8"]:not(#_) {
  color: var(--teal) !important; -webkit-text-fill-color: var(--teal) !important;
  background: rgba(12, 201, 168, 0.10) !important;
  border-color: rgba(12, 201, 168, 0.28) !important;
}

/* free-tools calculator submit button (owner 2026-05-30): it has flex-1, so on desktop
   it stretched ~full form width (872px) next to a small Reset — looks unbalanced/very
   long. Cap to content width on desktop (stays full-width stacked on mobile). All 6 tools. */
@media (min-width: 768px) {
  form button[type="submit"].sv-btn[class*="flex-1"] {
    flex: 0 1 auto !important; min-width: 220px;
  }
}

/* ── COOKIE BANNER "Manage preferences" detail panel (owner 2026-05-30) ──
   The detail-panel classes were UNDEFINED in CSS, so after clicking Manage the
   toggles rendered as raw checkboxes, the sr-only labels showed as visible text,
   and each category name ran straight into its description ("NecessarySession
   management…"). Style it like an enterprise consent manager: clean rows, real
   switch toggles, readable name/description, prominent Save. */
#ca-cookie .cookie-detail { display: flex; flex-wrap: wrap; gap: var(--space-4) 28px; align-items: flex-start; }
#ca-cookie .cookie-toggle-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  flex: 1 1 240px; min-width: 220px;
}
#ca-cookie .cookie-cat-name { display: block; font-weight: 700; font-size: var(--text-sm); color: var(--white); }
#ca-cookie .cookie-cat-desc { display: block; font-size: var(--text-xs); line-height: 1.45; color: rgba(232,240,250,0.62); margin-top: var(--space-1); }
/* real switch toggle (was a raw checkbox) */
#ca-cookie .cookie-toggle { position: relative; display: inline-flex; flex: 0 0 auto; width: 46px; height: 26px; cursor: pointer; }
#ca-cookie .cookie-toggle .cookie-chk { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
#ca-cookie .cookie-toggle .cookie-slider { position: absolute; inset: 0; background: rgba(255,255,255,0.22); border-radius: 999px; transition: background 0.2s ease; }
#ca-cookie .cookie-toggle .cookie-slider::before { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background: var(--white); border-radius: 50%; transition: transform 0.2s ease; }
#ca-cookie .cookie-toggle .cookie-chk:checked + .cookie-slider { background: var(--teal, var(--teal)); }
#ca-cookie .cookie-toggle .cookie-chk:checked + .cookie-slider::before { transform: translateX(20px); }
#ca-cookie .cookie-toggle .cookie-chk:focus-visible + .cookie-slider { outline: 2px solid transparent; outline-offset: 2px; box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 42%, transparent); }
/* the locked "Necessary = On" pill */
#ca-cookie .cookie-toggle-locked { width: auto; height: auto; padding: 4px 10px; background: var(--teal-15); border-radius: 999px; }
#ca-cookie .cookie-toggle-locked .toggle-on { font-size: var(--text-xs); font-weight: 700; color: var(--teal, var(--teal)); }
/* hide the sr-only toggle label that was rendering as visible text */
#ca-cookie .cookie-pref-toggle-sr { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
/* keep the Save / Accept-all actions clearly grouped */
#ca-cookie .cookie-detail-actions { display: flex; gap: var(--space-2); flex: 0 0 auto; align-items: center; }
@media (max-width: 767px) {
  #ca-cookie .cookie-detail { flex-direction: column; }
  #ca-cookie .cookie-toggle-row { width: 100%; }
  #ca-cookie .cookie-detail-actions { width: 100%; }
  #ca-cookie .cookie-detail-actions button { flex: 1 1 auto; }
}

/* owner 2026-05-30: resources /#guides "View all articles" button was stretching to
   374px TALL — it's a flex sibling of a tall heading block and `md:items-end` was
   purged, so the parent defaulted to align-items:stretch. align-self sizes it to its
   own content (bottom-aligned on desktop, left + auto-width on mobile). */
#guides a.sv-btn { align-self: flex-end; }
@media (max-width: 767px) { #guides a.sv-btn { align-self: flex-start; width: auto; } }

/* owner 2026-05-30: homepage VSME waitlist form — the !h-10/!px/!text-xs Tailwind
   overrides were PURGED, so the input + button rendered 66px tall (input text cramped
   to the edge, "Join waitlist" a near-circular black blob with 2-line wrapped text).
   Make it a tidy compact inline form: matched 44px height + radius, button sized to
   content on one line. */
#waitlist-form { align-items: center !important; gap: var(--space-2) !important; }
#waitlist-form .ca-input {
  height: 44px !important; padding: 0 16px !important; font-size: var(--text-sm) !important;
  border-radius: 10px !important; flex: 1 1 auto !important; min-width: 0 !important;
}
#waitlist-form button.sv-btn {
  height: 44px !important; min-height: 44px !important; padding: 0 20px !important;
  font-size: var(--text-sm) !important; border-radius: 10px !important; white-space: nowrap !important;
  flex: 0 0 auto !important; width: auto !important;
}

/* owner 2026-05-30: homepage free-tool demo widget — !h-16/!px-8/!px-10/!w-96 were
   PURGED, so the input collapsed to 24px tall and the rotator CTA button ("Calculate
   recovery →" / "Run PPN scorer →" / "Run readiness check →") rendered 102px tall on
   mobile. Force a clean matched 56px pair; both full-width stacked on mobile. */
.demo-widget-input { height: 56px !important; padding: 0 22px !important; font-size: var(--text-md) !important; }
button.ca-rotator {
  height: 56px !important; min-height: 56px !important; padding: 0 28px !important;
  display: inline-flex !important; align-items: center !important; justify-content: center !important;
}
/* the demo widget form shrank to content (~188px) inside its 350px card — fill it */
.demo-widget-row { width: 100% !important; }
@media (max-width: 767px) {
  .demo-widget-row { align-items: stretch !important; }
  .demo-widget-input, button.ca-rotator { width: 100% !important; max-width: 100% !important; }
}

/* mobile: collapse the link row (avoid the tall stack); rely on the hamburger if present */
@media (max-width: 1024px) {
  nav .nav-links, nav .nav-links.sv-cluster { display: none !important; }
  /* nav must fit the viewport; the hamburger was rendering off-screen (right≈455 on a
     390px screen) → no mobile menu + 11px horizontal overflow. Contain + reveal it. */
  header.sv-nav, nav.sv-nav, nav[aria-label="Main navigation"] { max-width: 100vw !important; }
  header.sv-nav > .wrap, header.sv-nav > div, nav.sv-nav > .wrap, nav.sv-nav > div,
  nav[aria-label="Main navigation"] > .wrap, nav[aria-label="Main navigation"] > div {
    max-width: 100% !important; width: 100% !important; padding-inline: var(--space-4) !important; box-sizing: border-box !important;
  }
  nav .ham, nav .nav-burger, button.ham { position: static !important; right: auto !important; transform: none !important; display: inline-flex !important; margin-left: var(--space-2); }
  nav .nav-actions, nav .nav-cta-group { flex-shrink: 1; min-width: 0; gap: var(--space-2) !important; }
}
/* kill phantom horizontal scroll site-wide (11px mobile overflow) without breaking fixed nav */
html, body { overflow-x: clip; max-width: 100%; }

/* DESKTOP: the nav-inject MOBILE menu (#mob-menu) was rendering display:block at all
   widths — dumping every product + free-tool name as plain text under the bar (owner-
   reported "so much text at top"). Hide it on desktop; it belongs behind the hamburger. */
@media (min-width: 1025px) {
  #mob-menu, .mob-menu, .nav-mobile, .mobile-menu, .mobile-nav { display: none !important; }
}
/* MOBILE: #mob-menu is the hamburger DRAWER — it must be hidden until opened.
   nav-inject injects it and the .ham toggle adds the `.open` class; but there was
   no rule hiding the closed state, so on mobile it rendered display:block
   (permanently expanded — the full nav list dumped under the bar on load). Hide it
   unless `.open`. */
/* G2 (2026-06-01 audit) — Z-INDEX GHOSTING: the drawer (#mob-menu) + its inner
   .mob-menu-nav were only hidden by display:none <=1024. ABOVE 1024 there was no
   hide rule, so on desktop the closed drawer stayed display:block / visible /
   pointer-events:auto — an invisible layer that can intercept header clicks
   ("dead zones"). FIX: the drawer is hidden EVERYWHERE by default and is only
   shown when BOTH .open AND <=1024 (desktop never opens it). When not .open it is
   pointer-events:none + aria-hidden semantics so it can never trap a click. */
#mob-menu { display: none !important; }
#mob-menu:not(.open), #mob-menu:not(.open) .mob-menu-nav { pointer-events: none !important; }
@media (max-width: 1024px) {
  #mob-menu.open { display: block !important; pointer-events: auto !important; }
  #mob-menu.open .mob-menu-nav { pointer-events: auto !important; }
  /* Hamburger tap target was 36x18px — below WCAG 2.5.5 (44x44). Pad it out
     without moving the glyph. */
  .ham { min-width: 44px !important; min-height: 44px !important; display: inline-flex !important; align-items: center !important; justify-content: center !important; }
}
/* the announce bar rendered as an unstyled left-aligned dump — make it a slim, centred,
   intentional strip (keeps the conversion message, removes the clutter look). */
#announce-bar, .announce-bar {
  display: flex !important; align-items: center; justify-content: center; gap: var(--space-2);
  text-align: center; font-size: var(--text-sm); line-height: 1; padding: 8px 16px;
  /* solid dark bg + near-white text = WCAG AA (was faint-teal/light = 1.84:1) */
  background: var(--ca-c-0a1c30) !important; color: var(--cloud) !important;
  border-bottom: 1px solid rgba(12, 201, 168, 0.18);
}
#announce-bar a, .announce-bar a { color: var(--ca-c-2ee6c4) !important; font-weight: 700; text-decoration: none; }
#announce-bar *, .announce-bar * { color: var(--cloud); }
#announce-bar .wrap, .announce-bar .wrap { max-width: 1280px; margin: 0 auto; display: flex; align-items: center; justify-content: center; gap: var(--space-2); }

/* logo lockup: white wordmark + teal tagline (was dark-on-dark) */
nav .logo, nav .sv-logo { color: var(--white); }
nav .logo-wordmark { color: var(--white) !important; font-weight: 800; font-size: var(--text-lg); letter-spacing: -0.02em; line-height: 1.05; }
nav .logo-wordmark span { color: var(--teal, var(--teal)); }
nav .logo-tag { color: var(--teal, var(--teal)) !important; font-size: 10px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
nav .logo-text, nav .logo > div:last-child { display: flex; flex-direction: column; line-height: 1.1; }
/* right-side actions: Sign in (light link) + Start free trial (teal pill) */
nav .nav-login, nav a[href*="login"], nav a[href*="signin"] { color: rgba(232, 240, 250, 0.78); font-weight: 600; font-size: var(--text-sm); text-decoration: none; white-space: nowrap; }
nav .nav-login:hover, nav a[href*="login"]:hover { color: var(--white); }
nav .nav-cta, nav .sv-btn, nav .sv-btn--primary, nav a[href*="signup"], nav a[href*="trial"], nav button {
  background: linear-gradient(180deg, var(--teal, var(--teal)), var(--teal-d)); color: var(--bg-tint) !important;
  padding: 9px 18px; border-radius: 999px; font-weight: 700; font-size: var(--text-sm); white-space: nowrap; border: none; cursor: pointer;
  box-shadow: 0 6px 18px -6px rgba(12, 201, 168, 0.6);
}
nav .nav-cta:hover, nav .sv-btn:hover, nav a[href*="signup"]:hover, nav button:hover { transform: translateY(-1px); }

/* LOGO MARK — the brand-mark SVG collapsed to 0 width (reset svg{height:auto}).
   Give it an explicit size so the logo is visible in nav + footer. */
nav .logo, nav a[href="/"], .sv-logo { display: flex; align-items: center; gap: var(--space-2); }
nav .logo-mark, nav .logo-box { display: inline-flex; width: 30px; height: 30px; flex-shrink: 0; }
nav .logo-mark svg, nav .logo svg, .sv-logo svg, .footer-col-brand .logo-mark svg, .footer-col-brand svg.logo, .ca-footer .logo-mark svg { width: 30px !important; height: 30px !important; display: block; }

/* ── GLOBAL FOOTER — nav-inject footer was unstyled (1376px stack). Restore a
   proper dark footer: brand column + link columns + legal bottom row. ── */
.ca-footer { background: var(--bg); border-top: 1px solid var(--teal-12); padding: clamp(48px, 7vw, 80px) var(--ca-pad) 32px; color: rgba(232, 240, 250, 0.82); }
.ca-footer .footer-grid { display: grid !important; grid-template-columns: 1.6fr repeat(4, 1fr) !important; gap: clamp(24px, 3vw, 48px); max-width: var(--ca-max); margin: 0 auto; align-items: start; }
.ca-footer .footer-col-brand { max-width: 340px; }
.ca-footer .footer-col-title { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: rgba(232, 240, 250, 0.5); margin-bottom: var(--space-4); }
.ca-footer .footer-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.ca-footer .footer-links a, .ca-footer a { color: rgba(232, 240, 250, 0.62); font-size: var(--text-sm); text-decoration: none; transition: color 0.15s; }
.ca-footer .footer-links a:hover, .ca-footer a:hover { color: var(--white); }
/* LM-148 (2026-05-29 — Claude, WCAG AA): bumped 0.45→0.62 opacity. At 0.45 these
   resolved to ~#6b747f on var(--surface-background) = 4.09:1 (fail for small text); 0.62 ≈ 5.5:1. */
.ca-footer .footer-tagline, .ca-footer .footer-credibility { color: rgba(232, 240, 250, 0.62); font-size: var(--text-sm); line-height: 1.6; margin-top: var(--space-3); }
/* LM-148 (2026-05-29 — Claude, WCAG AA): index kicker pills (10px uppercase,
   white border, rounded-full) had no text-color class → inherited var(--ca-c-3f4954) on
   var(--surface-background) = 2.11:1 (fail). The white border means these are ALWAYS on dark bg,
   so a light text colour is safe. Force readable light text. */
@layer base {
  [class*="text-[10px]"][class*="border-white/10"][class*="rounded-full"],
  [class*="text-[11px]"][class*="border-white/10"][class*="rounded-full"],
  [class*="text-[11px]"][class*="font-mono"][class*="text-white/40"] {
    color: rgba(232, 240, 250, 0.82) !important;
  }
}
.ca-footer .footer-status { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-xs); color: rgba(232, 240, 250, 0.62); margin-top: var(--space-3); }
.ca-footer .footer-status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--teal, var(--teal)); box-shadow: 0 0 8px var(--teal, var(--teal)); }
.ca-footer .footer-trust-row { display: flex; flex-wrap: wrap; gap: var(--space-3) 34px !important; margin-top: var(--space-4); }

/* ── FOOTER TRANSFORM (less dense, more breathing room, consistent everywhere) ── */
/* the AES-256 / TLS / ... credibility strip: space it out + give it its own band,
   separated from the columns below, with lighter weight. */
/* owner 2026-05-30: the divider + bottom margin live on the .footer-credibility
   WRAPPER (not the <ul>), so the asterisk footnote sits WITH the badges above the
   line — it was rendering below the divider, orphaned over the column grid. */
.ca-footer .footer-credibility {
  padding: 0 0 28px !important; margin-bottom: var(--space-8) !important; border-bottom: 1px solid var(--white-06);
}
.ca-footer .footer-trust-row, .ca-footer .footer-credibility-row {
  display: flex !important; flex-wrap: wrap; align-items: center; justify-content: center !important; gap: var(--space-3) 36px !important;
}
.ca-footer .footer-credibility-row {
  padding: 0 0 28px; margin-bottom: var(--space-8); border-bottom: 1px solid var(--white-06);
}
/* owner 2026-05-30: trust strip + its asterisk footnote centred sitewide (was left-aligned),
   note tucked tight under the badges. */
.ca-footer .footer-trust-note { text-align: center !important; margin: 10px auto 0 !important; }
.ca-footer .footer-trust-row > * , .ca-footer .footer-credibility-row > * {
  font-size: var(--text-xs) !important; color: rgba(232,240,250,0.85) !important; white-space: nowrap; letter-spacing: 0.01em;
}
/* more air in the link grid + lighter hierarchy */
.ca-footer .footer-grid { gap: clamp(28px, 3.5vw, 64px) !important; }
.ca-footer .footer-col-title { font-size: var(--text-xs) !important; letter-spacing: 0.14em !important; color: rgba(232,240,250,0.65) !important; margin-bottom: var(--space-4) !important; }
.ca-footer .footer-links { gap: var(--space-3) !important; }
.ca-footer .footer-links a, .ca-footer a { font-size: var(--text-sm) !important; color: rgba(232,240,250,0.85) !important; }
.ca-footer { padding-top: clamp(56px, 8vw, 96px) !important; }
.ca-footer .footer-bottom { margin-top: 52px !important; padding-top: var(--space-7) !important; }
.ca-footer .footer-bottom { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3); max-width: var(--ca-max); margin: 40px auto 0; padding-top: var(--space-6); border-top: 1px solid rgba(255, 255, 255, 0.07); }
.ca-footer .footer-copyright, .ca-footer .footer-legal-entity { color: rgba(232, 240, 250, 0.82) !important; font-size: var(--text-sm); }
/* a11y (axe link-in-text-block): this Companies House link sits inside the
   footer credibility sentence, so it needs a non-colour distinction — a
   persistent underline — not just the tinted colour. */
.ca-footer .footer-companies-house-link { color: rgba(232, 240, 250, 0.55); text-decoration: underline; text-underline-offset: 2px; }
.ca-footer .footer-bottom-link, .ca-footer .foot-social a { color: rgba(232, 240, 250, 0.78) !important; }
/* SOCIAL ICONS — were dark/black (invisible) + cramped on the dark footer, and
   differed between legacy & v2 pages. Force a single consistent, visible treatment
   everywhere: light icon that lifts to teal on hover, in a spaced pill. */
.ca-footer .foot-social { display: flex !important; gap: var(--space-2) !important; align-items: center; flex-wrap: nowrap !important; margin-top: var(--space-5); }
.ca-footer .foot-social a {
  display: inline-flex !important; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 9px; color: rgba(232,240,250,0.6) !important;
  background: var(--white-04); border: 1px solid var(--white-06);
  transition: color .15s, background .15s, border-color .15s;
}
.ca-footer .foot-social a:hover { color: var(--teal,var(--teal)) !important; background: var(--teal-12); border-color: rgba(12,201,168,0.3); }
.ca-footer .foot-social a svg, .ca-footer .foot-social svg { width: 17px !important; height: 17px !important; fill: currentColor !important; }
.ca-footer .foot-social a svg path, .ca-footer .foot-social svg path, .ca-footer .foot-social a svg * { fill: currentColor !important; }
.ca-footer .foot-social img { width: 17px !important; height: 17px !important; filter: brightness(0) invert(1); opacity: .6; }
.ca-footer .foot-social a:hover img { opacity: 1; }
/* footer brand lockup — was rendering wordmark + tagline INLINE and overlapping.
   Stack them (mark | wordmark-over-tagline) exactly like the nav lockup. */
.ca-footer .footer-col-brand .logo, .ca-footer .logo, .ca-footer .sv-logo {
  display: inline-flex !important; flex-direction: row !important; align-items: center; gap: var(--space-3); text-decoration: none;
}
.ca-footer .logo-text, .ca-footer .logo > div:last-child {
  display: flex !important; flex-direction: column !important; align-items: flex-start; line-height: 1.12; gap: var(--space-1);
}
.ca-footer .logo-mark, .ca-footer .logo-box { width: 34px; height: 34px; flex-shrink: 0; }
.ca-footer .logo-mark svg { width: 34px !important; height: 34px !important; display: block; }
.ca-footer .logo-wordmark { color: var(--white) !important; font-weight: 800; font-size: var(--text-lg); letter-spacing: -0.02em; line-height: 1; }
.ca-footer .logo-tag {
  color: var(--teal, var(--teal)) !important; font-size: 9px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; line-height: 1; white-space: nowrap; display: block;
}
.ca-footer .logo-tag .ca-brand-globe, .ca-footer .logo-tag .logo-tag-sep { margin: 0 3px; font-size: 8px; }
/* LM-156 (2026-05-30 — Claude): the base .footer-grid rule (line ~141) uses
   `grid-template-columns: 1.6fr repeat(4,1fr) !important` — its !important defeated
   these responsive overrides (which lacked !important), so the footer stayed 5-track
   on mobile and the 4th "Company" column overflowed ~11px past 390px. Add !important
   so the collapse actually applies. */
@media (max-width: 880px) { .ca-footer .footer-grid { grid-template-columns: 1fr 1fr !important; } .ca-footer .footer-col-brand { grid-column: 1 / -1 !important; } }
@media (max-width: 520px) { .ca-footer .footer-grid { grid-template-columns: 1fr !important; } .ca-footer .footer-bottom { flex-direction: column; align-items: flex-start; } }

/* ── OWNER-ORDERED: remove the disliked animated mesh / aurora / grain / glow.
   The `.atmos` overlay system + grain + hero-glow create the busy "mesh + motion"
   background the owner dislikes. Hide them globally for a clean, restrained surface.
   (Gemini retains full liberty to add a tasteful premium treatment later.) ── */
/* SAFE: only the v2 mesh OVERLAY child divs + grain/glow that the owner disliked
   on the v2 pages. These are dedicated overlay <div>s, never structural/content
   elements. (LESSON: never use [class*="…"] substring selectors here — they matched
   `pmb-aurora` / `pmb-orb-cluster` on the legacy <main> and hid all page content.) */
.atmos__aurora, .atmos__grid, .atmos__beam, .atmos__vignette,
.ca-grain, .ca-hero-glow {
  display: none !important;
}

/* COOKIE BANNER consistency — the Manage button has a long + short label span for
   responsive use; on some pages both rendered ("Manage preferencesManage"). Authoritative:
   long label on desktop, short on mobile, everywhere. */
.cookie-btn-short { display: none !important; }
.btn-cookie-outline .cookie-btn-long { display: inline !important; }
@media (max-width: 640px) {
  .cookie-btn-long { display: none !important; }
  .cookie-btn-short { display: inline !important; }
}
/* cookie banner buttons must be readable on any page (were 1:1 on some legacy pages) */
.cookie-banner .btn-cookie-outline, #ca-cookie .btn-cookie-outline { 
  color: var(--white) !important; 
  border: 1px solid rgba(255,255,255,0.4) !important; 
  background-color: var(--surface-2) !important; /* Opaque dark blue for scanner compatibility */
}
.cookie-banner .btn-cookie-outline:hover, #ca-cookie .btn-cookie-outline:hover { background: rgba(255,255,255,0.1) !important; }
#ca-cookie, .cookie-banner { background: var(--bg) !important; color: var(--white) !important; }
.cookie-banner .btn-cookie-primary, #ca-cookie .btn-cookie-primary { 
  color: var(--bg-tint) !important; 
  background: var(--teal, var(--teal)) !important; 
  border: none !important; 
}


/* reusable glass utility */
.ca-glass {
  background: rgba(4, 14, 26, 0.6); -webkit-backdrop-filter: saturate(160%) blur(16px); backdrop-filter: saturate(160%) blur(16px);
  border: 1px solid rgba(12, 201, 168, 0.14);
}

/* ============================================================
   HERO VISIBILITY FAILSAFE (2026-05-27 — Claude, Head of FE)
   premium-transformation-2026-05-27.css sets the hero title spans/chars and
   .ca-hero-desc to `opacity:0` "managed by GSAP". When the GSAP orchestrator
   does not run (or errors), the hero renders BLANK (confirmed: all 44 title
   spans + the description at opacity 0 on product pages). Content must never
   depend on JS to be visible. This CSS reveal guarantees the hero always ENDS
   visible; GSAP's inline styles still take over when it runs (inline beats
   stylesheet). nav-inject loads this file after premium-transformation, so it
   wins the cascade. Honours reduced-motion. */
@keyframes caHeroRevealFailsafe { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.ca-hero-title span,
.ca-hero-title-premium span,
.ca-hero-title .char,
.ca-hero-desc,
.ca-hero-desc-premium,
.ca-hero-btns,
.ca-hero-eyebrow-premium,
.ca-hero-meta-premium,
.ca-showcase-frame {
  animation: caHeroRevealFailsafe 0.7s var(--ease-canonical) 0.12s both;
}
@media (prefers-reduced-motion: reduce) {
  .ca-hero-title span,
  .ca-hero-title-premium span,
  .ca-hero-title .char,
  .ca-hero-desc,
  .ca-hero-desc-premium,
  .ca-hero-btns,
  .ca-hero-eyebrow-premium,
  .ca-hero-meta-premium,
  .ca-showcase-frame { animation: none !important; opacity: 1 !important; transform: none !important; }
}

/* ============================================================
   COOKIE BUTTON LABEL DEDUP — bulletproof (2026-05-27 — Claude).
   The Manage button has a long ("Manage preferences") + short ("Manage")
   label span; both rendered on mobile ("Manage preferencesManage"). The prior
   class-only rules were being overridden. Raise specificity with the #ca-cookie
   / .cookie-banner ancestor so the swap deterministically wins: long-only on
   desktop, short-only at <=640px. ============================================================ */
#ca-cookie .cookie-btn-short, .cookie-banner .cookie-btn-short { display: none !important; }
#ca-cookie .cookie-btn-long,  .cookie-banner .cookie-btn-long  { display: inline !important; }
@media (max-width: 640px) {
  #ca-cookie .cookie-btn-long,  .cookie-banner .cookie-btn-long  { display: none !important; }
  #ca-cookie .cookie-btn-short, .cookie-banner .cookie-btn-short { display: inline !important; }
}

/* ============================================================
   HERO TITLE SPREAD FIX (2026-05-28 — Claude).
   premium-transformation.css set the hero phrase spans to display:inline-block,
   so "Win contracts." / "Protect your business." / "Get paid faster." flowed
   INLINE across the viewport with a whitespace gap between every span — the
   "weird spread-out text" + right-edge overflow on desktop. Restore one phrase
   per line (block) and keep each phrase on a single line (nowrap). ============ */
.ca-hero-title-premium > span, .ca-hero-title > span {
  display: block !important;          /* each PHRASE on its own line (stacked) */
}
.ca-hero-title-premium .char, .ca-hero-title .char {
  display: inline-block !important;    /* keep transform-able for the entrance anim */
  margin: 0 !important;                /* KILL the per-char margin-right: var(--space-2) that
                                          spread every letter ("W i n  c o n t r a c t s") */
}
/* LM-154 (2026-05-30 — Claude): the kinetic char-splitter does NOT fully word-group on
   non-homepage heroes, so blog/glossary/product H1s broke words mid-word ("W/hat",
   "Sustainabili/ty", "Ef/ficiency"). Render INNER-PAGE hero chars as normal inline text
   so lines break ONLY at spaces (never mid-word). Homepage (.ca-hero-title-premium)
   keeps its inline-block per-char entrance animation. Specificity (0,3,0) > the (0,2,0)
   rule above so this wins. */
.ca-hero-title:not(.ca-hero-title-premium) .char {
  display: inline !important;
  white-space: normal !important;
}
/* LM-154 FOLLOW-UP (2026-05-30 — Claude, _fullmatrix). premium-transformation's
   `.ca-hero-title span span { display:inline-block; white-space:nowrap }` (added for
   .word spans, LM-126) ALSO traps CONTENT subtitle spans (e.g. blog `.text-[var(--accent)]`)
   on a single 1713px line → clipped page overflow at desktop on long blog/inner H1s.
   Scope nowrap to real word/char wrappers; let intermediate content spans wrap between
   words on inner-page (non-premium) heroes. Specificity (0,4,2) + loads-last wins. */
.ca-hero-title:not(.ca-hero-title-premium) span span:not(.word):not(.char) {
  display: inline !important;
  white-space: normal !important;
}
/* LM-130 REVERTED 2026-05-29 — owner did not want Claude editing the homepage hero;
   word-split JS + .word CSS reverted. Hero design is GEMINI's lane (see LM-133). */

/* LM-133 RESOLVED 2026-05-29 — Gemini shipped the new centered hero (CSS radial
   gradient, no WebGL canvas); the interim `.ca-mesh-canvas{display:none}` hide is
   no longer needed (canvas removed from index.html) and has been deleted. */

/* ============================================================
   UNIVERSAL BUTTON VISIBILITY (LM-134, 2026-05-29 — Claude). Owner: ghost buttons
   invisible on free-tools (black-on-black, no white boundary) + FAQ "Book a call"
   text invisible. Fix UNIVERSALLY, not per page. RCA:
   (1) the v2 Tailwind build PURGED the `bg-white/10` + `bg-white/5` utilities
       (confirmed absent from sovereign-core-v2.compiled.css), so EVERY
       `sv-btn !bg-white/10` ghost CTA renders with NO background and no visible
       boundary on dark sections — it reads as plain text, not a button.
   (2) an UNLAYERED global `a{color:teal}` beats the LAYERED `.text-black`/`text-[var(--bg)]`
       utilities (CSS cascade-layer reversal), so solid white CTAs (e.g. FAQ
       `bg-white text-black`) render TEAL on white ≈ invisible.
   Attribute selectors ([class*="bg-white/10"]) match the literal class token even
   though the utility CSS itself was purged. ============================================ */
/* (1) Ghost / translucent CTAs -> restore translucent fill + a clearly visible light border */
.sv-btn[class*="bg-white/10"],
.sv-btn[class*="bg-white/5"],
.sv-btn.sv-btn-ghost[class*="text-white"],
.sv-btn.sv-btn-ghost:not([class*="text-["]):not([class*="var(--bg)"]) {
  background-color: var(--white-08) !important;
  border: 1px solid rgba(255, 255, 255, 0.30) !important;
  color: var(--white) !important;
  -webkit-text-fill-color: var(--white) !important;
}
/* (2) Solid WHITE CTAs -> always dark, readable text (defeat the unlayered teal anchor colour) */
.sv-btn[class*="bg-white"]:not([class*="bg-white/"]),
a.bg-white, button.bg-white,
.sv-btn-primary[class*="bg-white"]:not([class*="bg-white/"]) {
  color: var(--bg) !important;
  -webkit-text-fill-color: var(--bg) !important;
}

/* ============================================================
   MOBILE NAV BAR + HAMBURGER (2026-05-28 — Claude).
   At <=900px the bar crammed logo + tagline + Sign in + Start-free-trial, and
   the .ham button (3 empty 0x0 transparent spans = an empty round circle)
   overlapped the CTA. Both actions live in the #mob-menu drawer. Declutter the
   bar to logo + hamburger, and render the hamburger as 3 visible bars. ======== */
.ham { flex-direction: column !important; gap: 0 !important; padding: 0 !important; border-radius: 10px !important; }
.ham > span {
  display: block !important; width: 22px !important; height: 2px !important;
  background: var(--cloud) !important; border-radius: 2px !important; margin: 2.5px 0 !important;
  transition: none !important;
}
@media (max-width: 900px) {
  .sv-nav-row .nav-login, .sv-nav-row .nav-cta,
  .sv-nav-row .btn-ghost-v2, .sv-nav-row .btn-primary-v2,
  #ca-nav .nav-login, #ca-nav .nav-cta { display: none !important; }
  /* owner 2026-05-31: keep the "Sustainability Intelligence" tagline VISIBLE on mobile
     (was display:none <900px so the brand lockup looked bare). html body specificity
     beats premium-transformation.css which also hid it. Small + stacked under wordmark. */
  html body .sv-nav-row .logo-tag, html body #ca-nav .logo-tag {
    display: block !important; font-size: 9px !important; line-height: 1.05 !important;
    letter-spacing: 0.04em !important; white-space: nowrap;
  }
}

/* ============================================================
   OPERATIONAL STANDARDS ("trust") — 6 items rendered as aligned, equal-height
   CARDS instead of loose text-with-a-line (2026-05-28 — Claude, owner request).
   On the white #trust section. ============================================ */
.ca-trust-matrix {
  display: grid !important;
  grid-template-columns: 1fr !important;
  gap: 1.5rem !important;
}
@media (min-width: 640px)  { .ca-trust-matrix { grid-template-columns: repeat(2, 1fr) !important; } }
@media (min-width: 1024px) { .ca-trust-matrix { grid-template-columns: repeat(3, 1fr) !important; } }
.ca-trust-item {
  background: var(--white) !important;
  border: 1px solid rgba(4, 14, 26, 0.08) !important;
  border-radius: 1.25rem !important;
  padding: 2rem !important;
  box-shadow: 0 4px 24px -12px rgba(4, 14, 26, 0.12) !important;
  display: flex !important; flex-direction: column !important; gap: 0.75rem !important;
}
.ca-trust-item .ca-trust-line {
  width: 36px; height: 3px; border-radius: 2px;
  background: var(--teal) !important; margin-bottom: 0.5rem;
}

/* ============================================================
   BLOG / ARTICLE PROSE TYPOGRAPHY (2026-05-28 — Claude).
   The v2 Tailwind build PURGED the `prose` plugin, so all 20 blog posts (which
   use class="prose prose-slate ...") rendered as a wall of tiny, unstyled text
   with no header hierarchy or spacing. This restores real article typography on
   the white blog body. Sizes match the explicit-class blogs so all 20 are
   consistent. ============================================================ */
:is(.prose, .blog-stripe-prose, .article-body) { color: var(--line-deep); }
:is(.prose, .blog-stripe-prose, .article-body) > :first-child { margin-top: 0; }
:is(.prose, .blog-stripe-prose, .article-body) h2 { font-size: clamp(1.9rem, 1.2rem + 1.4vw, 2.5rem); font-weight: 900; color: var(--bg); line-height: 1.15; letter-spacing: -0.02em; margin: 3rem 0 1.25rem; }
:is(.prose, .blog-stripe-prose, .article-body) h3 { font-size: 1.6rem; font-weight: 800; color: var(--bg); line-height: 1.25; margin: 2.5rem 0 1rem; }
:is(.prose, .blog-stripe-prose, .article-body) h4 { font-size: 1.2rem; font-weight: 800; color: var(--bg); margin: 2rem 0 0.6rem; }
:is(.prose, .blog-stripe-prose, .article-body) p  { font-size: 1.18rem; line-height: 1.75; margin: 0 0 1.3rem; color: var(--line-deep); }
:is(.prose, .blog-stripe-prose, .article-body) ul { list-style: disc; padding-left: 1.5rem; margin: 0 0 1.5rem; }
:is(.prose, .blog-stripe-prose, .article-body) ol { list-style: decimal; padding-left: 1.5rem; margin: 0 0 1.5rem; }
:is(.prose, .blog-stripe-prose, .article-body) li { font-size: 1.18rem; line-height: 1.7; margin: 0 0 0.6rem; color: var(--line-deep); }
:is(.prose, .blog-stripe-prose, .article-body) li::marker { color: var(--teal); }
:is(.prose, .blog-stripe-prose, .article-body) a { color: var(--teal-edge); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
:is(.prose, .blog-stripe-prose, .article-body) a:hover { color: var(--teal); }
:is(.prose, .blog-stripe-prose, .article-body) strong { color: var(--bg); font-weight: 700; }
:is(.prose, .blog-stripe-prose, .article-body) blockquote { border-left: 3px solid var(--teal); padding-left: 1.25rem; margin: 1.75rem 0; font-style: italic; color: var(--bg); }
:is(.prose, .blog-stripe-prose, .article-body) img { border-radius: 0.75rem; margin: 1.75rem 0; max-width: 100%; height: auto; }
/* LM-131 (2026-05-29 — owner: "security page has issues"): the security.html deep-dive
   uses `prose prose-slate prose-invert` on a DARK section, but Tailwind's prose-invert
   (light text for dark bg) was PURGED, so the .prose fallback above paints body text
   var(--line-deep) (dark navy) on a near-black bg ≈ 1.3:1 contrast = invisible. Restore the
   prose-invert intent: light body text + light headings on dark prose. Scoped to
   .prose-invert so light-bg blogs (no prose-invert) are unaffected. */
:is(.prose, .blog-stripe-prose, .article-body).prose-invert,
:is(.prose, .blog-stripe-prose, .article-body).prose-invert p,
:is(.prose, .blog-stripe-prose, .article-body).prose-invert li,
:is(.prose, .blog-stripe-prose, .article-body).prose-invert blockquote { color: var(--cloud); }
:is(.prose, .blog-stripe-prose, .article-body).prose-invert h2,
:is(.prose, .blog-stripe-prose, .article-body).prose-invert h3,
:is(.prose, .blog-stripe-prose, .article-body).prose-invert h4,
:is(.prose, .blog-stripe-prose, .article-body).prose-invert strong { color: var(--white); }
:is(.prose, .blog-stripe-prose, .article-body).prose-invert a { color: var(--teal); }
/* LM-129 (2026-05-29 — owner: "Company details card text visibility issues"): the
   about.html "Company details" card (#timeline right column) is markup-intended as a
   DARK card (`ca-card !bg-[var(--surface-background)] ... text-white`) but (1) the arbitrary `!bg-[var(--surface-background)]`
   utility was PURGED from the v2 build so it rendered light-grey, and (2) its parent
   `ca-section-light` forces `-webkit-text-fill-color:var(--bg)` on descendants, clobbering
   the intended white text → invisible text in an empty-looking box. Restore the dark card
   + white text (text-fill MUST be set too, it overrides `color`). */
#timeline .ca-card {
  background: var(--bg) !important;
  border-color: var(--white-08) !important;
}
#timeline .ca-card,
#timeline .ca-card h1, #timeline .ca-card h2, #timeline .ca-card h3,
#timeline .ca-card span, #timeline .ca-card p, #timeline .ca-card div,
#timeline .ca-card .ca-eyebrow {
  color: var(--white) !important;
  -webkit-text-fill-color: var(--white) !important;
}
#timeline .ca-card .ca-eyebrow {
  background: var(--line-deep) !important;
  border-color: rgba(255,255,255,0.20) !important;
}
#timeline .ca-card a[href^="mailto"] {
  color: var(--teal) !important;
  -webkit-text-fill-color: var(--teal) !important;
}
:is(.prose, .blog-stripe-prose, .article-body) hr { border: 0; border-top: 1px solid rgba(0,0,0,0.1); margin: 2.5rem 0; }
/* ============================================================
   PURGED ARBITRARY-UTILITY FIX — INVISIBLE CTA (2026-05-30 — Claude, owner-reported
   "Start free trial button invisible"). ROOT CAUSE: the v2 Tailwind build PURGED the
   arbitrary utilities `bg-[var(--teal)]` and `bg-[var(--lime)]` (0 occurrences in
   sovereign-core-v2.compiled.css). So CTAs like the homepage bottom
   `a.sv-btn.!bg-[var(--teal)].!text-[var(--surface-background)]` got NO background (transparent) → the
   near-black `var(--surface-background)` text rendered on the dark section background ≈ SAME COLOUR =
   completely invisible. Same purge class as LM-153. Used on index/404/resources/roadmap.
   FIX: re-declare the purged utilities here (nav-global-fix loads LAST). Dark text on a
   painted teal/lime fill is now visible. Same class of bug for any future `bg-[var(--x)]`.
   ============================================================ */
.\!bg-\[var\(--teal\)\] { background-color: var(--teal, var(--teal)) !important; }
.\!bg-\[var\(--lime\)\] { background-color: var(--lime, var(--lime)) !important; }
.bg-\[var\(--teal\)\]   { background-color: var(--teal, var(--teal)); }
.bg-\[var\(--lime\)\]   { background-color: var(--lime, var(--lime)); }
/* ALSO PURGED (confirmed 0 in compiled.css): arbitrary-HEX + standard teal bg utilities.
   `bg-[var(--accent)]` alone is used on 45 pages → its absence left teal CTAs unfilled (invisible
   dark-text-on-dark). Restore the full set. The `!`-prefixed (important) variants mirror
   the markup. Dark text on these light fills (teal/lime/purple) is visible; any `text-white`
   on teal/lime is a SEPARATE low-contrast issue queued for Gemini (use dark text). */
.bg-\[\var(--accent)\], .\!bg-\[\var(--accent)\] { background-color: var(--teal) !important; }
.bg-\[\var(--mark)\], .\!bg-\[\var(--mark)\] { background-color: var(--mark) !important; }
.bg-\[\var(--lime)\], .\!bg-\[\var(--lime)\] { background-color: var(--lime) !important; }
.bg-\[\var(--surface-background)\], .\!bg-\[\var(--surface-background)\] { background-color: var(--bg) !important; }
.bg-teal-500, .\!bg-teal-500 { background-color: var(--ca-c-14b8a6) !important; }
.bg-teal-400, .\!bg-teal-400 { background-color: var(--ca-c-2dd4bf) !important; }
/* TEXT colour utilities are ALSO purged (text-[var(--surface-background)]/[var(--accent)]/[var(--lime)]/[var(--mark)] all
   0 in compiled.css). Dark-text-on-teal CTAs (e.g. "Start free trial" bg-[var(--accent)]
   text-[var(--surface-background)]) fell back to INHERITED light text → light-on-teal ≈1.74:1. Restore them
   so dark text paints dark (≈9:1 on teal) and brand text accents render their real colour. */
.text-\[\var(--surface-background)\], .\!text-\[\var(--surface-background)\] { color: var(--bg) !important; -webkit-text-fill-color: var(--bg) !important; }
.text-\[\var(--accent)\], .\!text-\[\var(--accent)\] { color: var(--teal) !important; -webkit-text-fill-color: var(--teal) !important; }
.text-\[\var(--lime)\], .\!text-\[\var(--lime)\] { color: var(--lime) !important; -webkit-text-fill-color: var(--lime) !important; }
.text-\[\var(--mark)\], .\!text-\[\var(--mark)\] { color: var(--mark) !important; -webkit-text-fill-color: var(--mark) !important; }
/* UNIVERSAL (2026-06-01): after the brand-hex -> theme-utility migration the classes
   above became text-ca-bg / text-ca-teal / ... . Tailwind's text-ca-* sets `color` but
   NOT `-webkit-text-fill-color`, so a stray teal fill rule could paint a label
   teal-on-teal (invisible, e.g. the CERTIFIED-section "Start 14-day free trial"). Make
   every brand TEXT utility own BOTH properties so dark text on teal/lime stays visible.
   Uses the @theme --color-ca-* (defined in the compiled CSS on EVERY page) + hex fallback
   so it never depends on the legacy token layer. */
.text-ca-bg, .\!text-ca-bg { color: var(--color-ca-bg, var(--surface-background)) !important; -webkit-text-fill-color: var(--color-ca-bg, var(--surface-background)) !important; }
.text-ca-bg-deep, .\!text-ca-bg-deep { color: var(--color-ca-bg-deep, var(--bg-deep)) !important; -webkit-text-fill-color: var(--color-ca-bg-deep, var(--bg-deep)) !important; }
.text-ca-teal, .\!text-ca-teal { color: var(--color-ca-teal, var(--accent)) !important; -webkit-text-fill-color: var(--color-ca-teal, var(--accent)) !important; }
.text-ca-teal-d, .\!text-ca-teal-d { color: var(--color-ca-teal-d, var(--teal-d)) !important; -webkit-text-fill-color: var(--color-ca-teal-d, var(--teal-d)) !important; }
.text-ca-mark, .\!text-ca-mark { color: var(--color-ca-mark, var(--mark)) !important; -webkit-text-fill-color: var(--color-ca-mark, var(--mark)) !important; }
.text-ca-lime, .\!text-ca-lime { color: var(--color-ca-lime, var(--lime)) !important; -webkit-text-fill-color: var(--color-ca-lime, var(--lime)) !important; }
.text-ca-cloud, .\!text-ca-cloud { color: var(--color-ca-cloud, var(--text-primary)) !important; -webkit-text-fill-color: var(--color-ca-cloud, var(--text-primary)) !important; }
.text-ca-steel, .\!text-ca-steel { color: var(--color-ca-steel, var(--text-secondary)) !important; -webkit-text-fill-color: var(--color-ca-steel, var(--text-secondary)) !important; }
/* CTA-ON-TEAL/LIME CONTRAST (2026-05-30 — Claude, _ghostscan). White/light/teal text on a
   teal or lime FILL is a genuine low-contrast failure (≈1.2–2.1:1). Force DARK legible text
   on every teal/lime-filled link/button, setting BOTH `color` AND `-webkit-text-fill-color`
   (the latter overrides color and is what the LM-102 dark-card rule weaponised). Specificity
   `a[href][class*=…]` = (0,2,1) beats LM-102's (0,2,0) descendant rule so dark CTAs inside
   dark cards win. Purple (var(--mark)) keeps white (white-on-purple ≈4:1 = OK). */
a[href][class*="bg-[var(--accent)]"], a[href][class*="bg-[var(--accent)]"],
a[href][class*="bg-[var(--lime)]"], a[href][class*="bg-[var(--lime)]"],
a[href][class*="bg-[var(--teal)]"], a[href][class*="bg-[var(--lime)]"],
a[href][class*="bg-teal-5"], a[href][class*="bg-teal-4"],
button[type][class*="bg-[var(--accent)]"], button[type][class*="bg-[var(--lime)]"],
button[type][class*="bg-teal-5"] {
  color: var(--bg) !important;
  -webkit-text-fill-color: var(--bg) !important;
}

/* 2026-05-30 (Claude, _fullmatrix): this rule's specificity (0,1,1) beat the
   `.reg-table`/`.cost-table { display:block; overflow-x:auto }` (0,1,0) intent in
   blog-article.css, reverting wide content tables to display:table → page-level
   horizontal overflow (clipped) at 320/390 on regulatory-updates + retrofit-cost.
   Restore the responsive-scroll pattern here so EVERY prose/article table scrolls
   inside its own block instead of overflowing the page. */
:is(.prose, .blog-stripe-prose, .article-body) table { width: 100%; max-width: 100%; border-collapse: collapse; margin: 1.75rem 0; font-size: 0.98rem; display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
:is(.prose, .blog-stripe-prose, .article-body) th, :is(.prose, .blog-stripe-prose, .article-body) td { border: 1px solid rgba(0,0,0,0.1); padding: 0.7rem 1rem; text-align: left; vertical-align: top; }
:is(.prose, .blog-stripe-prose, .article-body) th { background: rgba(0,0,0,0.04); font-weight: 800; color: var(--bg); }

/* ============================================================
   SKIP-LINK + SR-ONLY (2026-05-28 — Claude, LM-029).
   The v2 Tailwind build PURGED `.sr-only`, so the skip-link rendered VISIBLE
   at top-left on EVERY page. Define both globally; the skip-link becomes a
   premium teal focus pill only when keyboard-focused.
   ============================================================ */
.sr-only:not(:focus):not(:focus-within) {
  position: absolute !important;
  width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
}
.skip-link {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}
.skip-link:focus, .skip-link:focus-visible {
  position: fixed !important;
  top: 16px !important; left: 16px !important;
  width: auto !important; height: auto !important;
  clip: auto !important; clip-path: none !important;
  padding: 12px 18px !important; margin: 0 !important;
  background: var(--bg) !important; color: var(--teal) !important;
  border: 1.5px solid var(--teal) !important; border-radius: 12px !important;
  font-weight: 700; font-size: var(--text-sm); letter-spacing: 0.01em;
  z-index: var(--z-toast) !important; outline: none !important;
  box-shadow: 0 8px 32px -8px rgba(12,201,168,0.5);
}

/* ============================================================
   HAMBURGER DESKTOP HIDE (2026-05-28 — Claude, LM-030).
   The .ham icon was rendering at 1440 desktop because nothing explicitly
   hid it. Per design system §1.6 hamburger ≤1024 only.
   ============================================================ */
@media (min-width: 1025px) {
  .ham, .nav-burger, button.ham,
  nav .ham, nav button.ham,
  #ca-nav .ham, .sv-nav .ham { display: none !important; }
}

/* ============================================================
   FOOTER TRUST-BADGE ICON↔TEXT ALIGNMENT (2026-05-28 — Claude, LM-010).
   The 7 trust badges (AES-256 · TLS 1.3 · GDPR · UK&EU · ISO 27001* · ICO
   registered · Companies House 17076461) had icons floating above their
   baseline. Force inline-flex + center + uniform icon size for crisp
   alignment across all 7 chips.
   ============================================================ */
.ca-footer .footer-trust-row > *,
.ca-footer .footer-credibility-row > *,
.ca-footer .trust-item, .ca-footer .credibility-item {
  display: inline-flex !important;
  align-items: center !important;
  gap: var(--space-2) !important;
  line-height: 1 !important;
}
.ca-footer .footer-trust-row svg,
.ca-footer .footer-credibility-row svg,
.ca-footer .trust-item svg, .ca-footer .credibility-item svg {
  width: 14px !important; height: 14px !important;
  flex-shrink: 0 !important;
  color: rgba(12,201,168,0.85) !important;
  vertical-align: middle !important;
  margin: 0 !important;
  display: inline-block !important;
}
.ca-footer .footer-trust-row svg path,
.ca-footer .footer-credibility-row svg path { stroke: currentColor !important; }
.ca-footer .footer-trust-row > * > span,
.ca-footer .footer-credibility-row > * > span,
.ca-footer .trust-item > span { display: inline-block !important; vertical-align: middle !important; line-height: 1 !important; }

/* ============================================================
   STRIPE-STYLE MOBILE NAV DRAWER (2026-05-31 — Claude, owner "do similar to
   Stripe"). Replaces the old in-flow flat stack. The drawer is now a FIXED
   full-viewport overlay anchored below the nav, with collapsible accordion
   sections for Products + Free Tools so the initial menu is short and scannable.
   ROOT-CAUSE of the "menu forces me to top + click twice" bug: the old menu was
   position:static, so opening it while scrolled rendered it off-screen at the top
   of the document and the focus-trap scrolled the page up to it. Fixed positioning
   + JS preventScroll eliminates both.
   ============================================================ */
@media (max-width: 1024px) {
  #mob-menu {
    position: fixed !important;
    top: var(--ca-nav-h, 72px) !important;
    left: 0 !important; right: 0 !important; bottom: 0 !important;
    z-index: var(--z-modal) !important;
    flex-direction: column;
    background: rgba(4,14,26,0.98) !important;
    -webkit-backdrop-filter: blur(20px) !important; backdrop-filter: blur(20px) !important;
    padding: 14px 22px calc(24px + env(safe-area-inset-bottom, 0px)) !important;
    overflow-y: auto !important;
    overscroll-behavior: contain;
    border-top: 1px solid rgba(12,201,168,0.18) !important;
  }
  #mob-menu.open { display: flex !important; }
  #mob-menu, #mob-menu * { box-sizing: border-box; }

  .mob-menu-nav { display: flex; flex-direction: column; width: 100%; }

  /* Top-level rows: flat links + accordion triggers share one look */
  #mob-menu .mob-toplink,
  #mob-menu .mob-acc-trigger {
    display: flex !important; align-items: center !important; justify-content: space-between;
    width: 100% !important; padding: 15px 4px !important; margin: 0 !important;
    color: rgba(232,240,250,0.92) !important;
    font-size: var(--text-md) !important; font-weight: 600 !important; font-family: inherit;
    text-decoration: none !important; background: none !important; border: none !important;
    border-bottom: 1px solid rgba(255,255,255,0.07) !important;
    line-height: 1.3 !important; min-height: 52px; cursor: pointer; text-align: left;
    border-radius: 0 !important; box-shadow: none !important; /* kill stray button pill/glow */
  }
  #mob-menu .mob-acc-chevron { transition: transform .25s ease; flex: 0 0 auto; opacity: .65; }
  #mob-menu .mob-acc.open > .mob-acc-trigger .mob-acc-chevron { transform: rotate(180deg); }
  #mob-menu .mob-acc.open > .mob-acc-trigger { color: var(--teal) !important; }

  /* GPU-friendly grid-rows accordion: .mob-acc has two children (trigger + panel),
     so we animate the parent grid-template-rows auto 0fr -> auto 1fr instead of a
     max-height ceiling. Panel stays in DOM; overflow-hidden clips it while collapsed. */
  #mob-menu .mob-acc { display: grid; grid-template-rows: auto 0fr; transition: grid-template-rows .3s ease; }
  #mob-menu .mob-acc.open { grid-template-rows: auto 1fr; }
  #mob-menu .mob-acc-panel { overflow: hidden; min-height: 0; }
  #mob-menu .mob-sublink {
    display: flex !important; align-items: center !important;
    width: 100% !important; padding: 12px 4px 12px 18px !important;
    color: rgba(232,240,250,0.72) !important;
    font-size: var(--text-md) !important; font-weight: 500 !important;
    text-decoration: none !important;
    border-bottom: 1px solid var(--white-05) !important;
    line-height: 1.3 !important; min-height: 46px;
  }
  #mob-menu .mob-toplink:hover, #mob-menu .mob-toplink:active,
  #mob-menu .mob-sublink:hover, #mob-menu .mob-sublink:active,
  #mob-menu .mob-acc-trigger:hover { color: var(--teal) !important; }

  /* CTA block, separated at the bottom */
  #mob-menu .mob-menu-ctas {
    display: flex; flex-direction: column; gap: var(--space-2);
    padding-top: var(--space-5); margin-top: var(--space-3);
    border-top: 1px solid rgba(255,255,255,0.1);
  }
  /* CTAs must be centred flex rows (owner 2026-05-31 regression: text was
     left-aligned/clipped because .btn is not a flexbox, so justify-content was
     inert). Force flex + centre both axes + text-align. */
  #mob-menu .mob-menu-ctas .btn {
    display: flex !important; align-items: center !important; justify-content: center !important;
    text-align: center !important; width: 100% !important; min-height: 50px;
    padding: 14px 20px !important; gap: 0 !important;
  }
  #mob-menu .mob-menu-ctas a[href*="signup"], #mob-menu .mob-menu-ctas .btn-primary-v2 {
    background: linear-gradient(180deg, var(--teal), var(--teal-d)) !important;
    color: var(--bg-tint) !important; border-radius: 999px !important;
    font-weight: 700 !important; border: none !important;
  }

  /* Close button as its own top-right row (not absolute) so it never overlaps
     the first accordion trigger's chevron. */
  .mob-menu-close {
    align-self: flex-end; margin: -2px -8px 2px 0;
    background: none; border: none; color: rgba(232,240,250,0.7);
    width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; cursor: pointer;
  }
  .mob-menu-close:hover { color: var(--teal); }

  @media (prefers-reduced-motion: reduce) {
    #mob-menu .mob-acc-panel, #mob-menu .mob-acc-chevron { transition: none !important; }
  }
}

/* ============================================================
   BATCH-A 2026-05-29 — Claude architectural CSS sweep (one commit, 9 LMs):
   LM-047 .sv-btn-premium family CSS (was missing, hero CTAs as plain text)
   LM-049 .ca-hero-title responsive clamp (was hardcoded 72px, clipped at 901px)
   LM-050 .ca-hero p / desc max-width (was overflowing mid-word)
   LM-051 py-60 sitewide responsive padding (was 240px every section = void bands)
   LM-054 partners hero overflow (covered by LM-049)
   LM-066 .ca-hero-btns flex collapsed to 24px (resolves with LM-047)
   LM-068/078 split-headline responsive collapse to single-column at <1440px
   LM-072 crowesg H1 clipped (covered by LM-049)
   LM-076 responsive padding scale py-20 md:py-40 lg:py-60 (covered by LM-051)
   .sr-only global strengthening (extends LM-029)
   ============================================================ */

/* ── LM-047 + LM-066 + LM-075: CTA button system, single source of truth ── */
.sv-btn-premium, .sv-btn-primary-premium, .sv-btn-ghost-premium,
.sv-btn, .sv-btn-primary, .sv-btn-secondary, .sv-btn-ghost,
.sv-btn-primary-v2, .sv-btn-ghost-v2 {
  display: inline-flex !important;
  align-items: center !important; justify-content: center !important;
  gap: var(--space-2) !important;
  padding: 14px 28px !important;
  min-height: 48px !important; height: auto !important;
  font-weight: 700 !important; font-size: var(--text-md) !important;
  line-height: 1.2 !important; letter-spacing: 0.005em !important;
  border-radius: 999px !important;
  border: 1.5px solid transparent !important;
  text-decoration: none !important; white-space: nowrap;
  cursor: pointer !important;
  transition: transform 0.18s ease-out, box-shadow 0.2s ease-out, background 0.2s ease-out, border-color 0.2s ease-out;
  -webkit-font-smoothing: antialiased;
}
.sv-btn-premium:hover, .sv-btn-primary-premium:hover, .sv-btn-ghost-premium:hover,
.sv-btn:hover, .sv-btn-primary:hover, .sv-btn-ghost:hover { transform: translateY(-1px); }
.sv-btn-premium:active, .sv-btn-primary-premium:active, .sv-btn-ghost-premium:active,
.sv-btn:active, .sv-btn-primary:active, .sv-btn-ghost:active { transform: scale(0.97); }
.sv-btn-premium:focus-visible, .sv-btn-primary-premium:focus-visible, .sv-btn-ghost-premium:focus-visible,
.sv-btn:focus-visible, .sv-btn-primary:focus-visible, .sv-btn-ghost:focus-visible {
  /* keep the button's resting drop-shadow, add the soft focus ring on top */
  outline: 2px solid transparent !important; outline-offset: 2px !important;
  box-shadow: 0 6px 22px -8px rgba(12,201,168,0.55), 0 0 0 3px color-mix(in srgb, var(--teal) 45%, transparent) !important;
}
.sv-btn-premium, .sv-btn-primary-premium, .sv-btn-primary, .sv-btn-primary-v2 {
  background: linear-gradient(180deg, var(--teal), var(--teal-d)) !important;
  color: var(--bg-tint) !important;
  box-shadow: 0 6px 22px -8px rgba(12,201,168,0.55);
}
.sv-btn-premium:hover, .sv-btn-primary-premium:hover, .sv-btn-primary:hover {
  box-shadow: 0 12px 28px -8px rgba(12,201,168,0.7);
  background: linear-gradient(180deg, var(--ca-c-14d6b5), var(--teal)) !important;
}
.sv-btn-ghost-premium, .sv-btn-ghost {
  background: transparent !important;
  color: var(--cloud) !important;
  border-color: rgba(232,240,250,0.28) !important;
}
.sv-btn-ghost-premium:hover, .sv-btn-ghost:hover {
  background: var(--white-04) !important;
  border-color: rgba(12,201,168,0.5) !important;
  color: var(--white) !important;
}
.sv-btn-secondary {
  background: var(--bg) !important; color: var(--white) !important;
  border-color: rgba(255,255,255,0.1) !important;
}
.ca-hero-btns, .ca-hero-cta-row, .cta-row, .faq-hero-cta {
  display: flex !important; flex-wrap: wrap;
  align-items: center; gap: var(--space-3) !important;
  margin-top: var(--space-8); min-height: 48px;
}

/* ── LM-049 + LM-054 + LM-072: hero H1 responsive font-size
   LM-108 (2026-05-29): REMOVED overflow-wrap:break-word + ADDED text-wrap:balance.
   Was splitting single words mid-character on cyber-essentials-readiness
   ("Essentia/ls") because the JS staggered-entrance module splits H1 into
   per-char inline-block spans — browser then treats every char boundary as
   a wrap opportunity. `text-wrap: balance` tells the browser to balance line
   wrapping at word boundaries when possible (modern Chrome/Safari/Edge).
   Also `word-break: keep-all` discourages mid-word splits.
   Gemini: long-term fix is to make the JS module word-aware. ── */
.ca-hero-title, .ca-hero-title-premium, .sec-hero h1, h1.page-title {
  font-size: clamp(1.85rem, 1.1rem + 4.2vw, 4rem) !important;
  line-height: 1.05 !important; letter-spacing: -0.025em !important;
  max-width: 100% !important;
  text-wrap: balance !important;
  word-break: keep-all !important;
}
/* BUG-001 (2026-05-29 — owner, CONFIRMED visually): premium-transformation sets
   font-weight:850 on hero titles, but Plus Jakarta Sans's variable axis maxes at 800.
   850 triggers synthetic/extrapolated weight that thickens the lowercase 'y'/'g' so the
   descender merges and "your"/"penalty" read as "vour"/"penaltv". Cap at 800 (valid
   axis max) sitewide so descenders render correctly. */
.ca-hero-title, .ca-hero-title-premium, .sec-hero h1, h1.page-title,
.ca-hero-title span, .ca-hero-title-premium span { font-weight: 800 !important; }
/* LM-143 (2026-05-29 — owner: "why is each page's heading size/style so different? fix all"):
   CANONICAL SITEWIDE HERO H1 SCALE — single source of truth. Supersedes BUG-056.
   ROOT-CAUSE of the divergence: premium-transformation.css defines
   `.f8-product .ca-hero-title { font-size:var(--h1-size-product) !important }` at
   specificity (0,2,0), which BEATS every (0,1,0) nav-global-fix rule — so f8-product
   pages (product pages + about) rendered a DIFFERENT size+weight+line-height than the
   rest. To force identical headings on EVERY page right now, this canonical block
   MATCHES the (0,2,0) specificity by enumerating the f8-product/f8-page/data-hero-scale
   variants alongside the base selectors. (Gemini's LM-143 cleanup then deletes the
   competing size rules in premium-transformation/compiled/resources so this is the only
   authority — see the loop file.) */
.ca-hero-title, .ca-hero-title-premium, .sec-hero h1, h1.page-title, #hero h1, .ca-hero h1,
.f8-product .ca-hero-title, .f8-page .ca-hero-title,
.f8-product .ca-hero-title-premium, .f8-page .ca-hero-title-premium,
[data-hero-scale] .ca-hero-title, [data-hero-scale] .ca-hero-title-premium {
  font-size: clamp(2.6rem, 1.4rem + 3.2vw, 4rem) !important;
  font-weight: 800 !important;
  line-height: 1.08 !important;
  letter-spacing: -0.03em !important;   /* optical kerning: 64px hero tracking (was -0.02em loose) */
}
#hero h1 span, .ca-hero h1 span { font-weight: 800 !important; }
@media (min-width: 1280px) {
  /* LM-143: pin EVERY desktop hero H1 to exactly 4rem (64px) so all pages are
     pixel-identical at desktop, regardless of body class. Includes the high-specificity
     f8-product/f8-page variants so product pages + about match the rest. */
  .ca-hero-title, .ca-hero-title-premium, #hero h1, .ca-hero h1,
  .f8-product .ca-hero-title, .f8-page .ca-hero-title,
  .f8-product .ca-hero-title-premium, .f8-page .ca-hero-title-premium,
  [data-hero-scale] .ca-hero-title, [data-hero-scale] .ca-hero-title-premium {
    font-size: 4rem !important;
    line-height: 1.08 !important;
  }
}

/* ── LM-050: hero <p> max-width responsive ── */
.ca-hero p, .ca-hero-desc, .ca-hero-desc-premium, .ca-hero-sub, .sec-hero-sub, .hero-sub {
  max-width: min(60ch, 100%) !important;
  margin-inline: auto;
  word-wrap: break-word; overflow-wrap: break-word;
  font-size: clamp(0.95rem, 0.85rem + 0.3vw, 1.18rem) !important;
  line-height: 1.6 !important;
}
.ca-hero, .sec-hero, .hero, .ca-main-transformation > section {
  max-width: 100vw !important; overflow-x: clip;
}

/* ── LM-105 + LM-108 (Claude 2026-05-29): mobile (≤768px) tighten hero typography.
   Original LM-105 used overflow-wrap:anywhere + hyphens:auto — too aggressive,
   split words mid-character. LM-108 fix: keep wrap at word boundaries only,
   no hyphenation. Hyphenated compounds like "public-sector" still break at
   the hyphen naturally. */
@media (max-width: 768px) {
  /* LM-143: canonical mobile hero H1 — same scale on every page incl. f8-product/f8-page.
     MUST include #hero h1 / .ca-hero h1 (ID specificity 1,0,1) — without them the
     non-media base rule won mobile on pages that wrap the h1 in #hero/.ca-hero,
     leaving them at 41.6px while others were 31.25px. */
  .ca-hero-title, .ca-hero-title-premium, .sec-hero h1, h1.page-title,
  #hero h1, .ca-hero h1,
  .f8-product .ca-hero-title, .f8-page .ca-hero-title,
  .f8-product .ca-hero-title-premium, .f8-page .ca-hero-title-premium,
  [data-hero-scale] .ca-hero-title, [data-hero-scale] .ca-hero-title-premium {
    font-size: clamp(1.9rem, 1.1rem + 3.5vw, 2.6rem) !important;
    line-height: 1.1 !important;
    overflow-wrap: break-word !important;
    max-width: 100% !important;
    padding-inline: var(--space-4) !important;
    text-align: center;
  }
  .ca-hero-eyebrow-premium, .ca-eyebrow, .sec-eyebrow, [class*="hero-eyebrow"], .section-label {
    font-size: clamp(0.625rem, 0.55rem + 0.3vw, 0.75rem) !important;
    letter-spacing: 0.06em !important;
    max-width: 100% !important;
    overflow-wrap: break-word !important;
    text-align: center;
    padding-inline: var(--space-4);
  }
  .ca-hero p, .ca-hero-desc, .ca-hero-desc-premium, .ca-hero-sub, .sec-hero-sub, .hero-sub {
    font-size: clamp(0.85rem, 0.78rem + 0.3vw, 1rem) !important;
    line-height: 1.55 !important;
    padding-inline: var(--space-4) !important;
  }
}

/* ── LM-143 (2026-05-29 — owner: "each page's heading size/style is so different, fix all"):
   SECTION HEADINGS (h2) were utility-soup — text-4xl through text-9xl + text-huge, all
   font-black, random leading-[0.8] — so every section title rendered a different size,
   several LARGER than the 64px hero H1 (e.g. about's "What we stand for." ≈ 96-128px).
   This caps every large display section h2 to the canonical h2 scale (max 2.75rem/44px),
   weight 800, line-height 1.15 — so section titles are uniform site-wide AND sit below
   the hero in the type hierarchy. Unlayered !important beats Tailwind's layered
   text-Nxl/font-black utilities (cascade-layer reversal). Scoped to <main> to leave
   nav/footer alone. GEMINI did the markup unification (commit d4869a9) → `.ca-section-title`,
   but did NOT define its font-size, so those h2s collapsed to 16px. This rule is now the
   CANONICAL definition for `.ca-section-title` (44px) AND keeps capping any not-yet-migrated
   text-Nxl utility headings. nav-global-fix loads last so it governs site-wide. */
main h2[class*="text-6xl"], main h2[class*="text-7xl"],
main h2[class*="text-8xl"], main h2[class*="text-9xl"],
main h2[class*="text-huge"], main h2[class*="text-5xl"],
.ca-section-title, h2.ca-section-title, main .ca-section-title {
  font-size: clamp(1.9rem, 1.2rem + 2vw, 2.75rem) !important;
  font-weight: 800 !important;
  line-height: 1.15 !important;
  letter-spacing: -0.03em !important;
}

/* ── LM-154 (2026-05-29): CASCADE-LAYER reinforcement of the canonical heading scale.
   Blog hero H1s carry Tailwind `!text-7xl` / `!leading-[0.8]` which live in
   `@layer utilities` with !important. For !important declarations, a LAYERED rule
   beats an UNLAYERED one (layer reversal), so the unlayered canonical rules above
   LOSE to those utilities (blog H1 rendered 72px/0.8 instead of 64px/1.08). The
   compiled CSS declares `@layer theme, base, components, utilities;` → for important,
   `base` beats `utilities`. Re-declaring the canonical scale inside `@layer base`
   makes it win over the size/leading utilities on EVERY page (incl. blogs). */
@layer base {
  .ca-hero-title, .ca-hero-title-premium, .sec-hero h1, h1.page-title, #hero h1, .ca-hero h1 {
    font-size: clamp(2.6rem, 1.4rem + 3.2vw, 4rem) !important;
    font-weight: 800 !important;
    line-height: 1.08 !important;
    letter-spacing: -0.03em !important;
  }
  @media (min-width: 1280px) {
    .ca-hero-title, .ca-hero-title-premium, #hero h1, .ca-hero h1 { font-size: 4rem !important; line-height: 1.08 !important; }
  }
  @media (max-width: 768px) {
    .ca-hero-title, .ca-hero-title-premium, .sec-hero h1, h1.page-title { font-size: clamp(1.9rem, 1.1rem + 3.5vw, 2.6rem) !important; line-height: 1.1 !important; }
  }
  main h2[class*="text-5xl"], main h2[class*="text-6xl"], main h2[class*="text-7xl"],
  main h2[class*="text-8xl"], main h2[class*="text-9xl"], main h2[class*="text-huge"],
  .ca-section-title {
    font-size: clamp(1.9rem, 1.2rem + 2vw, 2.75rem) !important;
    font-weight: 800 !important;
    line-height: 1.15 !important;
    letter-spacing: -0.03em !important;
  }
}

/* ── LM-102 (2026-05-29 — owner: glossary "Penalty calculation" card low contrast).
   Same root cause as LM-129/131/142: the v2 Tailwind build PURGED arbitrary
   `bg-[var(--surface-background)]`, so cards authored as dark (`class="… bg-[var(--surface-background)] text-white …"`)
   fell back to a near-transparent bg; and inside a .prose / ca-section-light context
   the forced dark `-webkit-text-fill-color` overrode `text-white` → dark-navy text on
   a near-white card = ~1.3:1. UNIVERSAL fix: any element intending BOTH a dark bg AND
   white text gets its dark bg restored + light text-fill re-asserted on its descendants
   (text-fill, not just color — the trap). Teal accents kept teal. Tight selector
   (`bg-[var(--surface-background)]` + `.text-white`) so it only hits genuine dark cards. */
[class*="bg-[var(--surface-background)]"].text-white, [class*="bg-[var(--surface-background)]"].text-white {
  background-color: var(--bg) !important;
}
[class*="bg-[var(--surface-background)]"].text-white,
[class*="bg-[var(--surface-background)]"].text-white :where(h1,h2,h3,h4,h5,p,li,strong,div,span,a,td),
[class*="bg-[var(--surface-background)]"].text-white,
[class*="bg-[var(--surface-background)]"].text-white :where(h1,h2,h3,h4,h5,p,li,strong,div,span,a,td) {
  color: var(--cloud) !important;
  -webkit-text-fill-color: var(--cloud) !important;
}
[class*="bg-[var(--surface-background)]"].text-white [class*="text-[var(--accent)]"],
[class*="bg-[var(--surface-background)]"].text-white [class*="text-[var(--accent)]"] {
  color: var(--teal) !important;
  -webkit-text-fill-color: var(--teal) !important;
}

/* ── LM-101 (2026-05-30 — Claude): cookie-preferences.html toggle switches were
   INVISIBLE — the markup is a WAI-ARIA switch (`<button class="toggle-switch"
   aria-checked role="switch"><span class="toggle-knob">`) but the CSS sizing it was
   undefined, so it rendered 0×0. Define the pill + knob + checked state. Scoped to
   `button.toggle-switch` so it does NOT touch pricing.html's `label.toggle-switch`. */
button.toggle-switch {
  position: relative; display: inline-flex; align-items: center; flex: 0 0 auto;
  width: 52px; min-width: 52px; height: 30px; padding: 0; cursor: pointer;
  border-radius: 999px; border: 1px solid rgba(4, 14, 26, 0.22);
  background: rgba(4, 14, 26, 0.16); /* off-state: visible grey on the WHITE cookie section */
  transition: background 0.25s ease, border-color 0.25s ease;
  -webkit-appearance: none; appearance: none;
}
button.toggle-switch .toggle-knob {
  position: absolute; top: 50%; left: 4px; transform: translateY(-50%);
  width: 22px; height: 22px; border-radius: 50%; background: var(--white);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); transition: transform 0.25s ease;
}
button.toggle-switch[aria-checked="true"] {
  background: var(--teal, var(--teal)); border-color: var(--teal, var(--teal));
}
button.toggle-switch[aria-checked="true"] .toggle-knob { transform: translateY(-50%) translateX(22px); }
button.toggle-switch[disabled] { opacity: 0.5; cursor: not-allowed; }
button.toggle-switch:focus-visible { outline: 2px solid transparent; outline-offset: 3px; box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 42%, transparent); }

/* ── LM-051 + LM-076 + LM-037 + REC-002: responsive section padding sitewide
   LM-114 (2026-05-29): mobile (≤768px) further compress to ~24-56px per side
   so home mobile drops from 26873px (69 screens) to ~16-18k (~40 screens). ── */
section.py-60, section.py-40, section.py-32, section.py-24, section.py-20,
.ca-section-dark.py-60, .ca-section.py-60,
[class*="py-60"], [class*="py-40"], [class*="py-32"] {
  padding-block: clamp(48px, 6vh, 96px) !important;
}
section.ca-hero, .sec-hero, .ca-hero, [data-hero-scale] {
  padding-block: clamp(72px, 10vh, 144px) !important;
}
@media (max-width: 768px) {
  section.py-60, section.py-40, section.py-32, section.py-24, section.py-20,
  .ca-section-dark.py-60, .ca-section.py-60,
  [class*="py-60"], [class*="py-40"], [class*="py-32"] {
    padding-block: clamp(24px, 4vh, 56px) !important;
  }
  section.ca-hero, .sec-hero, .ca-hero, [data-hero-scale] {
    padding-block: clamp(40px, 6vh, 80px) !important;
  }
  /* Dashboard mockup images: cap height on mobile */
  section img[src*="dashboard"], section img[src*="mockup"], section img[src*="product"],
  section .ca-card img:not([src*="logo"]):not([src*="icon"]) {
    max-height: 320px;
    object-fit: contain;
    object-position: center;
  }
  /* Card grids tighten the gap between cards on mobile */
  section [class*="gap-8"], section [class*="gap-12"], section [class*="gap-16"] {
    gap: clamp(12px, 3vw, 20px) !important;
  }
  /* Headings tightened margin-bottom on mobile */
  section h1, section h2, section h3 { margin-bottom: 0.625rem !important; }
  /* Body text tightened line-height on mobile */
  section p { line-height: 1.5; margin-bottom: 0.875rem; }
}
@media (min-width: 1280px) {
  section.py-60, section.py-40, .ca-section-dark.py-60 {
    padding-block: clamp(72px, 8vh, 128px) !important;
  }
  section.ca-hero, .sec-hero, .ca-hero { padding-block: clamp(96px, 12vh, 176px) !important; }
}

/* ── LM-068 + LM-078 + REC-004: split-headline two-column collapse to single column <1440px ──
   First fix only targeted > span (direct children). But the legacy H1 markup nests an inner
   span inside an outer wrapper span (e.g. about.html: <h1><span>Intelligence <br/><span class="text-[var(--teal)]">by engineers.</span></span></h1>).
   The inner gradient/colour span keeps display:inline-block from premium-transformation.css → horizontal gap remains.
   Fix: target ALL descendant spans + force normal whitespace so the <br>/wrap renders. */
@media (max-width: 1439px) {
  .ca-hero-title span, .ca-hero-title-premium span,
  .sec-hero h1 span, h1.page-title span {
    display: block !important;
    margin: 0 !important;
    white-space: normal !important;
    /* prevent the inline-block + nowrap + 0.1em margin combo from creating gap */
  }
}

/* ── .sr-only global strengthening (extends LM-029) ── */
.sr-only, [class~="sr-only"] {
  position: absolute !important;
  width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0,0,0,0) !important; clip-path: inset(50%) !important;
  white-space: nowrap !important; border: 0 !important;
}

/* ============================================================
   BATCH-B 2026-05-29 — Claude LM-041 contrast safety net
   Owner direct: "I saw many places text is written in white color and background
   is also white so text is not visible." Axe scan: 0/65 pages pass contrast (895
   nodes). Many are false positives but the user-visible ones are real.
   Strategy: targeted overrides for the common offender patterns. NOT a blanket *
   selector (which would break gradient/decorative text). ============== */

/* ============================================================
   STRIPE-STYLE CARD BOUNDARY (owner 2026-05-31)
   Problem: cards on the dark theme use a near-invisible surface
   (computed bg rgba(255,255,255,0.02)) + a faint --border2 hairline, so the
   card edge only appeared on hover (when the border turns teal). Owner asked
   for a persistent Stripe-style boundary. Fix: every card gets a crisp 1px
   edge + a soft layered depth shadow AT REST. Excludes .ca-card-premium (the
   highlighted plan card already owns a teal border) and product-shot mock cards.
   ============================================================ */
/* EXCLUDE [data-premium-stroke]: those cards (homepage CrowCash/Cyber/Mark/Core)
   own an animated rotating conic-gradient border that REQUIRES border:1.5px solid
   transparent. Adding an opaque grey border here clashed = "weird lines" (owner
   2026-05-31). They keep their premium animated stroke; we only add a depth shadow. */
.ca-card:not(.ca-card-premium):not(.ca-showcase-frame):not([data-premium-stroke]) {
  border: 1px solid rgba(255, 255, 255, 0.12) !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28), 0 14px 36px -14px rgba(0, 0, 0, 0.55) !important;
}
.ca-card:not(.ca-card-premium):not(.ca-showcase-frame):not([data-premium-stroke]):hover {
  border-color: var(--teal, var(--teal)) !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28), 0 22px 50px -14px rgba(12, 201, 168, 0.28) !important;
}
/* premium-stroke cards: keep their animated border, just add subtle depth. */
.ca-card[data-premium-stroke]:not(.ca-card-premium) {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28), 0 14px 36px -14px rgba(0, 0, 0, 0.55) !important;
}
/* On genuinely light/white-background sections, use a dark hairline + light
   shadow instead (a light border would vanish on white). */
section[class*="bg-white"]:not([class*="bg-white/"]) .ca-card:not(.ca-card-premium):not([data-premium-stroke]) {
  border-color: rgba(0, 0, 0, 0.10) !important;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 14px 32px -14px rgba(0, 0, 0, 0.14) !important;
}

/* ============ a11y CONTRAST (WCAG AA) — full axe scan 2026-05-31 (Claude) ============
   All real misses are text on LIGHT backgrounds. (The high-count dark-on-dark
   nodes axe reported on privacy/security hero titles were FALSE POSITIVES — the
   titles use gradient/clipped fills axe can't read; pixel-verified white.)
   These are colour-only bumps → zero layout impact. */
/* Legal-page muted TOC headings + company-info rows + table captions:
   rgba .5–.55 (3.4–4.3:1) -> .7 (>=4.5:1). */
.pv-toc-h, .sec-toc-h, .tm-toc-h,
.pv-coy-row span, .sec-coy-row span,
.tm-article caption, .tm-article .lc-table-wrap caption { color: rgba(4, 14, 26, 0.7) !important; }
/* Security/privacy chip labels: rgba .5 (3.44:1) -> .72. */
.sec-chip span, .pv-chip span { color: rgba(4, 14, 26, 0.72) !important; }
/* Teal-on-LIGHT (eyebrows/links/headings/stats): the per-page light-teal vars
   (var(--ca-c-0a9c82) privacy, var(--teal-d) terms) only reach ~2.4–3.1:1. Redefine the var on
   the LIGHT scopes only (dark heroes keep the bright --teal). var(--teal-pressed) = ~4.6–5:1. */
.tm-article, .tm-band--light, .tm-toc, .tm-contact { --teal-d: var(--teal-pressed) !important; }
.pv-band--light, .pv-panel, .pv-subcard, .pv-contact, .pv-toc, .pv-coy-row { --pv-teal-d: var(--teal-pressed) !important; }
/* terms bright-teal stat numbers/CTAs on light (var(--accent), 1.83:1) -> dark teal. */
.tm-article .lc-stat__num, .tm-article .lc-stat__num *, .tm-article .lc-stat__cta,
.tm-article .lc-stat__cta span { color: var(--teal-pressed) !important; -webkit-text-fill-color: var(--teal-pressed) !important; }
/* White-on-teal primary CTAs (2.11:1) -> dark obsidian text per brand rule. */
.lc-cta--primary, .lc-cta--primary span { color: var(--bg) !important; -webkit-text-fill-color: var(--bg) !important; }
/* Contact breadcrumb "/" separator on dark (2.5:1) -> lighter. */
[class*="before:content"]::before { color: rgba(255, 255, 255, 0.6) !important; }
/* Glossary cards on white: teal category label (2.11:1) + muted desc (3.58:1). */
.glossary-card .text-\[\var(--accent)\] { color: var(--ca-c-0a7257) !important; -webkit-text-fill-color: var(--ca-c-0a7257) !important; }
.glossary-card .text-\[\#1E3A58\]\/60 { color: rgba(30, 58, 88, 0.86) !important; }
/* Blog kicker label opacity-50 -> raise for legibility. */
.article-body .opacity-50, .blog-stripe-prose .opacity-50, article .opacity-50 { opacity: 0.78 !important; }
/* link-in-text-block: links inside paragraphs need a non-colour cue (underline). */
.is-roadmap-note a, .article-body p a[href*="unsplash"], p a[href*="unsplash"] { text-decoration: underline !important; }

/* Pattern 1: white-card on white-bg section — force dark text on contents */
section.bg-white :is(.ca-card.\!bg-white, .ca-card[class*="!bg-white"]:not([class*="bg-white/"])),
section[class*="bg-white"]:not([class*="bg-white/"]) .ca-card:not([class*="bg-[#"]):not([class*="!bg-[#"]) {
  color: var(--bg) !important;
}
section.bg-white .ca-card.\!bg-white :is(h1, h2, h3, h4, h5, h6, p, span:not([class*="text-"])):not(:has(svg)),
section[class*="bg-white"] .ca-card :is(h1, h2, h3, h4, h5, h6):not([class*="text-"]) {
  color: var(--bg) !important;
}
section.bg-white .ca-card.\!bg-white p:not([class*="text-"]),
section[class*="bg-white"] .ca-card p:not([class*="text-"]) {
  color: rgba(4, 14, 26, 0.66) !important;
}
/* Pattern 2: anywhere bg-white is applied to a section, body text inherits dark */
section.bg-white, section[class*="bg-white"]:not([class*="bg-white/"]) {
  color: var(--bg);
}
section.bg-white :is(h1, h2, h3, h4):not([class*="text-"]),
section[class*="bg-white"]:not([class*="bg-white/"]) :is(h1, h2, h3, h4):not([class*="text-"]) {
  color: var(--bg);
}
section.bg-white :is(p, li, dd, dt):not([class*="text-"]),
section[class*="bg-white"]:not([class*="bg-white/"]) :is(p, li, dd, dt):not([class*="text-"]) {
  color: var(--line-deep);
}

/* Pattern 3: security cred cards (LM-041 specific) — readable on dark surface */
.sec-cred-card, .sec-cred-card * {
  color: var(--cloud) !important;
}
.sec-cred-card .sec-cred-desc, .sec-cred-card p {
  color: rgba(232, 240, 250, 0.78) !important;
}
.sec-cred-title { color: var(--white) !important; font-weight: 700 !important; }

/* Pattern 4: tool/methodology step-number panels (the "01" "02" 1.08:1 issue) */
.step-num, .sec-step-num, [class*="-step-num"], [data-step], .ca-step,
.sec-aes-key, .sec-aes-val, .sec-eyebrow-inline, .sec-eyebrow {
  color: rgba(232, 240, 250, 0.86) !important;
}

/* Pattern 5: gradient text fallback — if text-transparent + bg-clip:text fails to
   render the gradient, the text would be INVISIBLE. Provide a sane fallback color. */
[class*="text-transparent"][class*="bg-clip-text"]:not([style*="background"]) {
  color: var(--teal);
}

/* Pattern 6: ca-card on light/white sections — descriptions readable */
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) h1,
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) h2,
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) h3,
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) h4 { color: var(--bg) !important; font-weight: 800 !important; }
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) p,
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) [class*="text-black"],
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) span:not([class*="text-"]) {
  color: rgba(4, 14, 26, 0.7) !important;
}
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) [class*="text-4xl"],
.ca-card[class*="!bg-white"]:not([class*="bg-white/"]) [class*="text-3xl"] {
  color: var(--bg) !important;
}

/* Pattern 7: footer link contrast bump (was 0.62 → 0.74 for WCAG AA) */
.ca-footer .footer-links a, .ca-footer a:not(.foot-social a):not(.footer-bottom-link) {
  color: rgba(232, 240, 250, 0.74) !important;
}
.ca-footer .footer-links a:hover { color: var(--white) !important; }

/* Pattern 8: blog/index article card category labels (was 1:1) */
.article-card [class*="text-[10px]"][class*="uppercase"],
.article-card .ca-eyebrow, .article-card .article-eyebrow {
  color: var(--teal) !important;
  font-weight: 700 !important;
}

/* ============================================================
   BATCH-C 2026-05-29 — Claude LM-031 section reveal motion
   Per PREMIUM MOTION DIRECTIVE: every page must feel alive with subtle motion.
   IntersectionObserver-driven fade-up + translateY on every section as it scrolls
   into view. Respect prefers-reduced-motion. JS adds `.js-sv-reveal` to <html>
   when active, so CSS only hides sections AFTER JS confirms it'll reveal them
   (no FOUC for no-JS users).
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  html.js-sv-reveal .sv-reveal {
    opacity: 0;
    transform: translateY(20px);
    transition:
      opacity 0.6s var(--ease-canonical),
      transform 0.6s var(--ease-canonical);
    will-change: opacity, transform;
  }
  html.js-sv-reveal .sv-reveal.sv-revealed {
    opacity: 1;
    transform: translateY(0);
    will-change: auto;
  }
}
/* Card hover lift sitewide (extends BATCH-A button lift to cards) */
@media (prefers-reduced-motion: no-preference) {
  .ca-card, .sv-card, [class*="ca-card"], .article-card, .ca-trust-item {
    transition: transform 0.2s ease-out, box-shadow 0.25s ease-out, border-color 0.2s ease-out;
  }
  .ca-card:hover, .sv-card:hover, .article-card:hover, .ca-trust-item:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 36px -16px rgba(12, 201, 168, 0.18);
  }
}

/* ============================================================
   BATCH-D 2026-05-29 — Claude polish pass
   - LM-080 canonical breadcrumb component
   - LM-040 products hub 4-card grid centring
   - LM-079 footer social hover tooltip via title-attr (CSS-only enhancement)
   - LM-019 invisible-text spot fixes (cookie banner 1.08:1)
   ============================================================ */

/* LM-080 canonical breadcrumb component */
.ca-breadcrumb, nav[aria-label="Breadcrumb"], .breadcrumb,
.f10-breadcrumbs ol, [role="navigation"][aria-label="Breadcrumb"] {
  display: flex !important;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1);
  font-size: var(--text-xs) !important;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(232, 240, 250, 0.55) !important;
  margin-bottom: var(--space-6);
  list-style: none !important;
  /* zero only VERTICAL padding (thin bar). Inline padding kept so a breadcrumb
     that is also .ca-container keeps the page gutter (was padding:0 -> the
     contact.html breadcrumb slammed the left edge while content below was inset). */
  padding-block: 0 !important;
}
.ca-breadcrumb li, nav[aria-label="Breadcrumb"] li,
.f10-breadcrumbs li, [role="navigation"][aria-label="Breadcrumb"] li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.ca-breadcrumb li + li::before,
nav[aria-label="Breadcrumb"] li + li::before,
.f10-breadcrumbs li + li::before {
  content: "›";
  margin-right: var(--space-1);
  opacity: 0.5;
}
.ca-breadcrumb a, nav[aria-label="Breadcrumb"] a, .f10-breadcrumbs a {
  color: rgba(232, 240, 250, 0.7) !important;
  text-decoration: none !important;
  transition: color 0.15s;
}
.ca-breadcrumb a:hover, nav[aria-label="Breadcrumb"] a:hover { color: var(--teal) !important; }
.ca-breadcrumb [aria-current="page"], .f10-breadcrumbs [aria-current="page"] {
  color: var(--white) !important;
}

/* LM-040 products hub card grid auto-centred 4-up at >=1024px */
.products-hub-grid, .ca-products-grid,
section [class*="grid-cols-2"][class*="grid-cols-4"] {
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important;
  gap: 1.5rem !important;
  max-width: 1120px;
  margin-inline: auto;
}

/* LM-019 cookie banner contrast bump on the "We use cookies..." sub-text (was 1.08:1 reported) */
.cookie-banner p, #ca-cookie p, .cookie-banner .cookie-msg {
  color: rgba(255, 255, 255, 0.88) !important;
}
.cookie-banner a, #ca-cookie a { color: var(--teal) !important; }
.cookie-banner a:hover { color: var(--ca-c-14d6b5) !important; text-decoration: underline; }

/* LM-139 (2026-05-29 — owner: "Cookie preferences has responsiveness issue"): the
   compiled cookie layout has NO mobile rule — `.cookie-inner` is a fixed flex row
   and `.cookie-actions` (3 buttons) is `flex-shrink:0`, so on narrow screens the
   buttons overflow the viewport and "Accept all" is clipped off the right edge.
   Stack the banner vertically on mobile and let the action buttons share the full
   width (wrap if needed) so all three are fully visible + tappable (44px). */
@media (max-width: 640px) {
  #ca-cookie .cookie-inner, .cookie-banner .cookie-inner {
    flex-direction: column !important;
    align-items: stretch !important;
    gap: var(--space-3) !important;
    padding: 0 16px !important;
  }
  #ca-cookie .cookie-actions, .cookie-banner .cookie-actions {
    width: 100% !important;
    flex-wrap: wrap !important;
    gap: var(--space-2) !important;
  }
  #ca-cookie .cookie-actions > button, .cookie-banner .cookie-actions > button {
    flex: 1 1 auto !important;
    min-width: 0 !important;
    justify-content: center !important;
  }
}

/* LM-142 (2026-05-29 — owner: "text visibility issue on /terms"): the legal-page
   dark components — `.lc-cta--primary` (bg var(--surface-background)) and `.lc-stat` (dark var(--surface-background)
   card) — sit INSIDE the white `!bg-white` legal section. `section.!bg-white *`
   forces `-webkit-text-fill-color:var(--bg)` on EVERY descendant, which clobbers the
   white/light text on these dark components → dark-on-dark = invisible ("Request
   DPA", "Monthly uptime target…", "View status page"). text-fill OVERRIDES color,
   so we must re-assert text-fill (not just color) on these dark components. */
.lc-cta--primary, .lc-cta--primary span, .lc-cta--primary svg {
  color: var(--white) !important; -webkit-text-fill-color: var(--white) !important;
}
.lc-cta--primary:hover, .lc-cta--primary:hover span, .lc-cta--primary:hover svg {
  color: var(--bg) !important; -webkit-text-fill-color: var(--bg) !important;
}
.lc-stat, .lc-stat__body, .lc-stat__body p {
  color: rgba(232,240,250,0.85) !important; -webkit-text-fill-color: rgba(232,240,250,0.85) !important;
}
.lc-stat__num { color: var(--teal) !important; -webkit-text-fill-color: var(--teal) !important; }
.lc-stat__cta, .lc-stat__cta span, .lc-stat__cta svg {
  color: var(--teal) !important; -webkit-text-fill-color: var(--teal) !important;
}

/* a11y CONTRAST round-2 (full axe 2026-05-31 night) — 3 real residuals:
   1) Primary CTAs in .lc-cta-row have a TEAL bg (brand primary) but LM-142 forced
      WHITE text-fill (assuming a dark bg) → white-on-teal 2.11:1. Dark obsidian text
      on teal is the brand-correct + AA-passing choice. Higher specificity (0,3,0)
      than LM-142 (0,2,0) + later source order, scoped to cta-rows so LM-142's
      genuine dark-bg CTAs are untouched. */
.lc-cta-row .lc-cta--primary, .lc-cta-row .lc-cta--primary span, .lc-cta-row .lc-cta--primary svg {
  color: var(--bg) !important; -webkit-text-fill-color: var(--bg) !important;
}
/* 2) breadcrumb current item + its "/" separator: var(--ca-c-4d4e59) on dark (2.5:1) -> lighter. */
li[class*="before:content"], li[class*="before:content"]::before { color: rgba(255,255,255,0.72) !important; }
/* 3) blog kicker label uses text-white/20 (var(--ca-c-363e48) on dark, 1.79:1) -> lift to ~0.55. */
article .text-white\/20, .article-body .text-white\/20, .blog-stripe-prose .text-white\/20 {
  color: rgba(255,255,255,0.55) !important; -webkit-text-fill-color: rgba(255,255,255,0.55) !important;
}

/* LM-019 pricing 10px + contact 9px footnote contrast bump */
.text-\[10px\]:not(.text-\[\var(--accent)\]):not([class*="text-white"]):not([class*="text-teal"]),
.text-\[9px\]:not(.text-\[\var(--accent)\]):not([class*="text-white"]):not([class*="text-teal"]) {
  color: rgba(232, 240, 250, 0.65) !important;
}

/* LM-079 footer social hover ripple */
.ca-footer .foot-social a {
  position: relative;
  overflow: hidden;
}
.ca-footer .foot-social a::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(circle, rgba(12, 201, 168, 0.18) 0%, transparent 70%);
  opacity: 0; transition: opacity 0.25s ease-out;
}
.ca-footer .foot-social a:hover::after { opacity: 1; }

/* ============================================================
   LM-106 (Claude 2026-05-29 10:25) — owner-spotted: free-tools + partners
   heroes are LEFT-ALIGNED but per spec §1.1 default content alignment is
   CENTRED. Tools/* and partners.html hero markup has explicit Tailwind
   `!text-left` + `!items-start` + `!justify-start` overrides.
   Quick CSS override forces center on hero content; .legal-doc (terms/privacy/
   cookies long-form legal prose) keeps its own left alignment.
   Gemini should also clean up the markup classes (queued as LM-106).
   ============================================================ */
/* LM-106 FIX: Tailwind's `.\!text-left { ... !important }` lives inside
   `@layer utilities`. For !important declarations, layer order is REVERSED,
   so layered !important BEATS unlayered !important. We must declare inside
   an EARLIER layer than utilities to win. The compiled CSS declares
   `@layer theme, base, components, utilities;` so we use @layer base.
   The same trick is used for .ca-hero-content, .ca-hero-btns, etc. */
@layer base {
  section.ca-hero .ca-hero-content,
  section.ca-hero .ca-hero-content.text-left,
  section.ca-hero .ca-hero-content.\!items-start {
    align-items: center !important;
    text-align: center !important;
  }
  section.ca-hero .ca-hero-title,
  section.ca-hero .ca-hero-title.\!text-left,
  section.ca-hero .ca-hero-sub,
  section.ca-hero .ca-hero-sub.\!text-left,
  section.ca-hero .ca-hero-desc,
  section.ca-hero p {
    text-align: center !important;
    margin-inline: auto !important;
  }
  section.ca-hero .ca-hero-btns,
  section.ca-hero .ca-hero-btns.\!justify-start,
  section.ca-hero .cta-row {
    justify-content: center !important;
    align-items: center !important;
  }
  /* Trust pillar rows under hero — centred too */
  section.ca-hero [class*="grid-cols-3"], section.ca-hero .ca-hero-pillars {
    margin-inline: auto !important;
    max-width: 960px;
  }
}

/* ============================================================
   LM-107 (Claude 2026-05-29 10:36) — owner-spotted home cards.
   "For your role" + "Who it's for" sections have <img> overlays inside
   `.ca-card .absolute.inset-0.opacity-5` (or opacity-10). The src URLs
   reference 6 missing sector .webp files (LM-048 — 404). The broken-image
   icons are visible at 5-10% opacity making text hard to read.
   Fix: hide the broken background-image overlays entirely. Cards keep
   their solid colour background + content. Until LM-048 sources real photos,
   this is the right interim behaviour. Also for /sectors/ src paths
   matching the known-broken filenames, set display:none on the img.
   ============================================================ */
.ca-card.relative.overflow-hidden > .absolute.inset-0[class*="opacity-"],
.ca-card .absolute.inset-0[class*="opacity-5"],
.ca-card .absolute.inset-0[class*="opacity-10"] {
  display: none !important;
}
img[src*="/Assets/photos/sectors/sector-professional-services"],
img[src*="/Assets/photos/sectors/sector-retail-hospitality"],
img[src*="/Assets/photos/sectors/sector-public-sector-civic"],
img[src*="/Assets/photos/sectors/sector-manufacturing-industrial"],
img[src*="/Assets/photos/sectors/sector-real-estate-commercial"],
img[src*="/Assets/photos/sectors/sector-construction-civil"] {
  display: none !important;
}

/* ============================================================
   BATCH-E 2026-05-29 — Claude PREMIUM SURFACE EFFECTS
   Owner-requested: glass-morphism (existing), Apple-style specular highlight
   on cards, animated gleam sweep across buttons, chromatic/liquid-metal
   gradients, animated rainbow gradient borders. All respect prefers-reduced-
   motion.
   ============================================================ */

/* CSS @property for animatable angle (used by rainbow border + chromatic shift) */
@property --premium-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}
@property --premium-pos {
  syntax: '<percentage>';
  initial-value: 0%;
  inherits: false;
}

/* ── 1. APPLE-STYLE SPECULAR HIGHLIGHT (cards) ──
   Subtle reflective sheen that rotates with cursor position. Tracks hover
   via radial-gradient anchored at --x / --y CSS variables (set by JS would be
   nicer but pure-CSS uses pseudo + transform fallback). */
@media (prefers-reduced-motion: no-preference) {
  .ca-card, .sv-card, .article-card, .ca-trust-item {
    position: relative;
    isolation: isolate;
  }
  .ca-card::before, .sv-card::before, .article-card::before, .ca-trust-item::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    background: linear-gradient(
      135deg,
      rgba(255, 255, 255, 0) 30%,
      var(--white-06) 47%,
      var(--teal-12) 50%,
      var(--white-06) 53%,
      rgba(255, 255, 255, 0) 70%
    );
    opacity: 0;
    transform: translateX(-100%);
    transition: opacity 0.3s, transform 0.9s var(--ease-canonical);
    z-index: var(--z-base);
    mix-blend-mode: screen;
  }
  .ca-card:hover::before, .sv-card:hover::before,
  .article-card:hover::before, .ca-trust-item:hover::before {
    opacity: 1;
    transform: translateX(100%);
  }
  /* keep card content above the sheen overlay */
  .ca-card > *, .sv-card > *, .article-card > *, .ca-trust-item > * {
    position: relative;
    z-index: var(--z-content);
  }
}

/* ── 2. ANIMATED GLEAM SWEEP across buttons (CTA shine) ──
   Diagonal light streak sweeps across primary CTAs on hover. */
@media (prefers-reduced-motion: no-preference) {
  .sv-btn-premium, .sv-btn-primary-premium, .sv-btn-primary, .sv-btn,
  .sv-btn--primary, button.sv-btn-primary {
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }
  .sv-btn-premium::after, .sv-btn-primary-premium::after,
  .sv-btn-primary::after, .sv-btn::after, .sv-btn--primary::after {
    content: '';
    position: absolute;
    top: -50%; bottom: -50%;
    left: -120%;
    width: 60%;
    background: linear-gradient(
      105deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, 0.42) 50%,
      rgba(255, 255, 255, 0) 100%
    );
    transform: translateX(0) skewX(-22deg);
    pointer-events: none;
    /* GPU-only: animate transform (translateX) instead of `left` so the gleam
       sweep composites on the GPU and never triggers layout/repaint. */
    transition: transform 0.85s var(--ease-canonical);
    z-index: var(--z-base);
  }
  .sv-btn-premium:hover::after, .sv-btn-primary-premium:hover::after,
  .sv-btn-primary:hover::after, .sv-btn:hover::after, .sv-btn--primary:hover::after {
    transform: translateX(250%) skewX(-22deg);
  }
  /* button content above the gleam */
  .sv-btn-premium > *, .sv-btn-primary-premium > *,
  .sv-btn-primary > *, .sv-btn > *, .sv-btn--primary > * {
    position: relative; z-index: var(--z-content);
  }
  /* Ambient pulse on the gleam for the highest-priority CTA */
  .sv-btn-premium.sv-btn-pulse,
  [data-cta-pulse] {
    animation: caCtaPulse 3.5s ease-in-out infinite;
  }
  @keyframes caCtaPulse {
    0%, 100% { box-shadow: 0 6px 22px -8px rgba(12,201,168,0.55); }
    50% { box-shadow: 0 12px 32px -8px rgba(12,201,168,0.85), 0 0 0 4px var(--teal-08); }
  }
}

/* ── 3. CHROMATIC / LIQUID-METAL GRADIENT (premium accents) ──
   Slow-rotating conic gradient on opt-in elements. Apply via class
   `.ca-chromatic` or as a background for premium hero accents. */
@media (prefers-reduced-motion: no-preference) {
  .ca-chromatic {
    background:
      conic-gradient(
        from var(--premium-angle, 0deg) at 50% 50%,
        rgba(12, 201, 168, 0.85) 0deg,
        rgba(167, 139, 250, 0.7) 90deg,
        rgba(56, 189, 248, 0.7) 180deg,
        rgba(12, 201, 168, 0.85) 270deg,
        rgba(12, 201, 168, 0.85) 360deg
      );
    animation: caChromaticSpin 12s linear infinite;
  }
  @keyframes caChromaticSpin {
    from { --premium-angle: 0deg; }
    to   { --premium-angle: 360deg; }
  }
  /* Liquid-metal text effect — for hero accent words: <span class="ca-liquid-text">word</span> */
  .ca-liquid-text {
    background: linear-gradient(
      135deg,
      var(--accent) 0%,
      var(--ca-c-14d6b5) 25%,
      var(--white) 45%,
      var(--ca-c-14d6b5) 65%,
      var(--accent) 100%
    );
    background-size: 250% 250%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    animation: caLiquidShimmer 6s ease-in-out infinite;
  }
  @keyframes caLiquidShimmer {
    0%, 100% { background-position: 0% 50%; }
    50%      { background-position: 100% 50%; }
  }
}

/* ── 4. ANIMATED RAINBOW GRADIENT BORDER (premium cards) ──
   Subtle rotating chromatic stroke on opt-in cards via `.ca-card-premium`
   or on `[data-premium-stroke]`. Uses conic-gradient + mask trick. */
@media (prefers-reduced-motion: no-preference) {
  .ca-card-premium, .ca-card.is-featured, [data-premium-stroke],
  .pricing-panel .ca-card.scale-105 {
    position: relative;
    background-clip: padding-box;
    border: 1.5px solid transparent;
  }
  .ca-card-premium::before, .ca-card.is-featured::before,
  [data-premium-stroke]::before, .pricing-panel .ca-card.scale-105::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1.5px;
    background: conic-gradient(
      from var(--premium-angle, 0deg),
      rgba(12, 201, 168, 0.9) 0%,
      rgba(167, 139, 250, 0.6) 25%,
      rgba(56, 189, 248, 0.6) 50%,
      rgba(244, 114, 182, 0.5) 75%,
      rgba(12, 201, 168, 0.9) 100%
    );
    -webkit-mask:
      linear-gradient(var(--bg) 0 0) content-box,
      linear-gradient(var(--bg) 0 0);
    -webkit-mask-composite: xor;
            mask:
      linear-gradient(var(--bg) 0 0) content-box,
      linear-gradient(var(--bg) 0 0);
            mask-composite: exclude;
    animation: caPremiumStroke 8s linear infinite;
    pointer-events: none;
    z-index: var(--z-base);
  }
  @keyframes caPremiumStroke {
    from { --premium-angle: 0deg; }
    to   { --premium-angle: 360deg; }
  }
  /* card content above the stroke */
  .ca-card-premium > *, .ca-card.is-featured > *,
  [data-premium-stroke] > *, .pricing-panel .ca-card.scale-105 > * {
    position: relative; z-index: var(--z-content);
  }
}

/* ── DISABLE the rotating rainbow conic-gradient border (owner 2026-05-31) ──
   The [data-premium-stroke] ::before (teal->purple->cyan->pink conic + 8s rotate)
   read as gimmicky "weird lines + animation", NOT ultra-premium (owner reported
   the homepage CrowCash/Cyber/Mark/Core cards twice). Kill the ::before and give
   these cards the clean Stripe border + teal-on-hover + depth shadow instead.
   Declared AFTER the stroke definition so it wins on source order. */
[data-premium-stroke]::before { display: none !important; content: none !important; }
[data-premium-stroke]:not(.ca-card-premium) {
  border: 1px solid rgba(255, 255, 255, 0.12) !important;
  background-clip: border-box !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28), 0 14px 36px -14px rgba(0, 0, 0, 0.55) !important;
  transition: border-color .3s ease, box-shadow .3s ease, transform .3s ease !important;
}
[data-premium-stroke]:not(.ca-card-premium):hover {
  border-color: var(--teal, var(--teal)) !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28), 0 22px 50px -14px rgba(12, 201, 168, 0.28) !important;
}

/* ── 5. ENHANCED GLASS-MORPHISM (sitewide) ──
   Existing nav already uses backdrop-filter blur. Add a richer `.ca-glass-premium`
   variant for select surfaces: 24px blur + subtle teal border + inner highlight. */
.ca-glass-premium, .pricing-panel .ca-card.scale-105:not([data-no-glass]),
.ca-card.ca-glass {
  background:
    linear-gradient(180deg, var(--white-04), rgba(255,255,255,0.01)),
    rgba(8, 18, 30, 0.55) !important;
  -webkit-backdrop-filter: saturate(170%) blur(24px) !important;
          backdrop-filter: saturate(170%) blur(24px) !important;
  border: 1px solid rgba(12, 201, 168, 0.18) !important;
  box-shadow:
    inset 0 1px 0 var(--white-08),
    0 24px 60px -24px rgba(0, 0, 0, 0.6);
}

/* Reduced motion — keep static premium surface, drop animation */
@media (prefers-reduced-motion: reduce) {
  .ca-chromatic, .ca-liquid-text,
  .ca-card-premium::before, .ca-card.is-featured::before,
  .sv-btn-premium::after, .sv-btn-primary::after, .sv-btn::after,
  .ca-card::before, .sv-card::before, .article-card::before {
    animation: none !important;
    transition: none !important;
  }
}

/* ============================================================
   LM-109 (Claude 2026-05-29) — COMPREHENSIVE CONTRAST SAFETY NET
   Owner re-flagged: "many text are invisible across website because text
   and background colors are same — white bg white text, black bg black text".
   Existing BATCH-B handled common patterns but Tailwind's `@layer utilities`
   !important wins over unlayered. Same trick as LM-106: declare inside
   @layer base so we BEAT layered utilities for !important.

   Strategy: scope by SECTION background colour. Any element with bg-white
   forces dark descendants. Any element with bg-[var(--surface-background)] / bg-black / dark
   bg forces light descendants. Excluding specific gradient/button slots and
   honest opt-out via .ca-text-keep / .text-balance.
   ============================================================ */
@layer base {
  /* ── WHITE / LIGHT BACKGROUNDS → force DARK text ── */
  section.bg-white,
  section[class*="bg-white"]:not([class*="bg-white/"]),
  div.bg-white:not(.cookie-banner):not(#ca-cookie),
  div[class*="bg-white"]:not([class*="bg-white/"]):not(.cookie-banner):not(#ca-cookie),
  [class*="!bg-white"]:not([class*="!bg-white/"]):not(.sv-btn-primary):not(.sv-btn):not(.btn-cookie-primary) {
    color: var(--bg) !important;
  }
  /* Headings, paragraphs, lists inside white-bg sections — explicit dark */
  section.bg-white :is(h1, h2, h3, h4, h5, h6),
  section[class*="bg-white"]:not([class*="bg-white/"]) :is(h1, h2, h3, h4, h5, h6),
  [class*="!bg-white"]:not([class*="!bg-white/"]) :is(h1, h2, h3, h4, h5, h6) {
    color: var(--bg) !important;
  }
  section.bg-white :is(p, li, dt, dd, span:not([class*="text-"]):not([class*="!text-"])),
  section[class*="bg-white"]:not([class*="bg-white/"]) :is(p, li, dt, dd) {
    color: var(--line-deep) !important;
  }
  /* Light section backgrounds (bg-slate-100, bg-gray-100, etc.) — dark text */
  section[class*="bg-slate-100"], section[class*="bg-gray-100"],
  section[class*="bg-stone-100"], section[class*="bg-zinc-100"] {
    color: var(--bg) !important;
  }

  /* ── DARK BACKGROUNDS → force LIGHT text ── */
  section.bg-\[\var(--surface-background)\], section[class*="bg-[var(--surface-background)]"],
  section.bg-\[\#000212\], section[class*="bg-[#000212]"],
  section.bg-black, section[class*="bg-black"]:not([class*="bg-black/"]),
  section.ca-section-dark, .ca-section-dark,
  body.bg-\[\#000212\] > section:not([class*="bg-white"]):not(.bg-white) {
    /* base color set: ensure inheritable light */
  }
  section.ca-section-dark :is(h1, h2, h3, h4, h5, h6):not([class*="text-["]):not([class*="!text-["]),
  section.bg-black :is(h1, h2, h3, h4, h5, h6):not([class*="text-["]):not([class*="!text-["]),
  [class*="bg-[var(--surface-background)]"] :is(h1, h2, h3, h4, h5, h6):not([class*="text-["]):not([class*="!text-["]) {
    color: var(--white) !important;
  }
  section.ca-section-dark :is(p, li, dt, dd):not([class*="text-["]):not([class*="!text-["]),
  section.bg-black :is(p, li, dt, dd):not([class*="text-["]):not([class*="!text-["]),
  [class*="bg-[var(--surface-background)]"] :is(p, li, dt, dd):not([class*="text-["]):not([class*="!text-["]) {
    color: rgba(232, 240, 250, 0.82) !important;
  }

  /* ── CARDS — context-aware contrast ── */
  /* White card on any section: dark text */
  .ca-card.\!bg-white, .ca-card[class*="!bg-white"]:not([class*="!bg-white/"]),
  .ca-card.bg-white {
    color: var(--bg) !important;
  }
  .ca-card.\!bg-white :is(h1, h2, h3, h4),
  .ca-card[class*="!bg-white"]:not([class*="!bg-white/"]) :is(h1, h2, h3, h4),
  .ca-card.bg-white :is(h1, h2, h3, h4) {
    color: var(--bg) !important;
  }
  .ca-card.\!bg-white :is(p, li, span:not([class*="text-["])),
  .ca-card[class*="!bg-white"]:not([class*="!bg-white/"]) :is(p, li, span:not([class*="text-["])),
  .ca-card.bg-white :is(p, li, span:not([class*="text-["])) {
    color: var(--line-deep) !important;
  }
  /* Dark card on any section: light text */
  .ca-card.\!bg-\[\var(--surface-background)\], .ca-card[class*="!bg-[var(--surface-background)]"],
  .ca-card.bg-black, .ca-card.\!bg-black {
    color: rgba(232, 240, 250, 0.92) !important;
  }
  .ca-card.\!bg-\[\var(--surface-background)\] :is(h1, h2, h3, h4),
  .ca-card[class*="!bg-[var(--surface-background)]"] :is(h1, h2, h3, h4),
  .ca-card.bg-black :is(h1, h2, h3, h4),
  .ca-card.\!bg-black :is(h1, h2, h3, h4) {
    color: var(--white) !important;
  }
  .ca-card.\!bg-\[\var(--surface-background)\] :is(p, li),
  .ca-card[class*="!bg-[var(--surface-background)]"] :is(p, li),
  .ca-card.bg-black :is(p, li),
  .ca-card.\!bg-black :is(p, li) {
    color: rgba(232, 240, 250, 0.78) !important;
  }

  /* ── TAILWIND TEXT-COLOUR UTILITIES THAT FREQUENTLY GO INVISIBLE ── */
  /* text-white on white-bg section is invisible — force dark */
  section.bg-white .text-white, section.bg-white .\!text-white,
  section[class*="bg-white"]:not([class*="bg-white/"]) .text-white,
  section[class*="bg-white"]:not([class*="bg-white/"]) .\!text-white,
  .ca-card.\!bg-white .text-white, .ca-card[class*="!bg-white"]:not([class*="!bg-white/"]) .text-white {
    color: var(--bg) !important;
  }
  /* text-black on dark-bg section is invisible — force light */
  section.bg-\[\var(--surface-background)\] .text-black, section.bg-\[\var(--surface-background)\] .\!text-black,
  section.ca-section-dark .text-black, section.ca-section-dark .\!text-black,
  section.bg-black .text-black, section.bg-black .\!text-black,
  .ca-card[class*="!bg-[var(--surface-background)]"] .text-black,
  .ca-card.\!bg-\[\var(--surface-background)\] .text-black, .ca-card.bg-black .text-black {
    color: var(--white) !important;
  }
  /* text-[var(--surface-background)] on a dark section is the same — force light */
  section.ca-section-dark [class*="text-[var(--surface-background)]"]:not([class*="bg-white"]),
  section.bg-\[\var(--surface-background)\] [class*="text-[var(--surface-background)]"]:not([class*="bg-white"]),
  section.bg-black [class*="text-[var(--surface-background)]"]:not([class*="bg-white"]) {
    color: rgba(232, 240, 250, 0.92) !important;
  }
  /* text-[var(--white)] / text-white on a light section — same — force dark */
  section.bg-white [class*="text-[var(--white)]"]:not(.cookie-banner *):not(#ca-cookie *),
  section[class*="bg-white"]:not([class*="bg-white/"]) [class*="text-[var(--white)]"]:not(.cookie-banner *):not(#ca-cookie *) {
    color: var(--bg) !important;
  }

  /* ── EYEBROW / SMALL-CAPS labels — always readable in their context ── */
  section.bg-white .ca-eyebrow, section.bg-white [class*="text-eyebrow"],
  section[class*="bg-white"] .ca-eyebrow {
    color: var(--teal-edge) !important; /* dark teal — readable on white */
  }
  section.ca-section-dark .ca-eyebrow,
  section.bg-\[\var(--surface-background)\] .ca-eyebrow,
  section.bg-black .ca-eyebrow {
    color: var(--teal) !important; /* bright teal — readable on dark */
  }

  /* ── LINKS — always readable in their context ──
     LM-111: exclude ALL button variants ([class*="sv-btn"]) so buttons keep
     their explicit dark-on-teal text (per spec §1.1 CTA = teal bg + dark fg). */
  section.bg-white a:not([class*="sv-btn"]):not([class*="sv-btn"]):not([class*="text-["]),
  section[class*="bg-white"]:not([class*="bg-white/"]) a:not([class*="sv-btn"]):not([class*="sv-btn"]):not([class*="text-["]) {
    color: var(--teal-edge) !important; /* dark teal link on white */
  }
  section.ca-section-dark a:not([class*="sv-btn"]):not([class*="sv-btn"]):not([class*="text-["]),
  section.bg-\[\var(--surface-background)\] a:not([class*="sv-btn"]):not([class*="sv-btn"]):not([class*="text-["]) {
    color: var(--teal) !important;
  }
  /* ── LM-111 BUTTON CONTRAST GUARANTEES (in @layer base so it always wins) ──
     Per spec §1.1: CTA button = teal bg + dark (var(--bg)) text. Ghost = transparent
     bg + light text. NEVER white/teal text on teal bg (1.45:1 fail).
     Verified WCAG AA pairs:
       var(--surface-background) on var(--accent) = 14.5:1 ✓ AAA
       var(--text-primary) on var(--surface-background) = 17.6:1 ✓ AAA
       var(--accent) on var(--surface-background) = 10.3:1 ✓ AAA
       var(--teal-edge) on var(--white) = 6.4:1 ✓ AA
     Failing pairs DO NOT use:
       var(--white) on var(--accent) = 1.45:1 ✗
       var(--accent) on var(--white) = 2.3:1 ✗ (body), 3.3:1 (large) — only AA-large OK
       var(--accent) on var(--accent) = 1:1 ✗ ← what was happening
   */
  .sv-btn-premium, .sv-btn-primary-premium, .sv-btn-primary, .sv-btn-primary-v2,
  a.sv-btn-premium, a.sv-btn-primary-premium, a.sv-btn-primary,
  button.sv-btn-premium, button.sv-btn-primary-premium, button.sv-btn-primary {
    color: var(--bg-tint) !important; /* DARK text on teal CTA — 14.5:1 contrast */
  }
  .sv-btn-ghost, .sv-btn-ghost-premium,
  a.sv-btn-ghost, a.sv-btn-ghost-premium {
    color: var(--cloud) !important; /* light text on transparent/dark ghost — 17.6:1 */
  }
  .sv-btn-secondary, a.sv-btn-secondary {
    color: var(--white) !important; /* white text on dark obsidian secondary */
  }
  /* LM-111 BUTTON OPT-OUT — match LM-109's specificity (0,3,1) so we WIN the
     cascade and beat the generic dark-text-on-dark-section flip. */
  section.ca-section-dark [class*="sv-btn"][class*="!text-[var(--surface-background)]"],
  section.ca-section-dark [class*="sv-btn"][class*="text-[var(--surface-background)]"],
  section[class*="bg-["] [class*="sv-btn"][class*="!text-[var(--surface-background)]"],
  section[class*="bg-["] [class*="sv-btn"][class*="text-[var(--surface-background)]"],
  section.bg-black [class*="sv-btn"][class*="!text-[var(--surface-background)]"],
  section.bg-black [class*="sv-btn"][class*="text-[var(--surface-background)]"] {
    color: var(--bg) !important;
  }
  /* Same trick for text-white / text-[var(--white)] on light-bg buttons (rare). */
  section.bg-white [class*="sv-btn"][class*="!text-[var(--white)]"],
  section.bg-white [class*="sv-btn"][class*="text-[var(--white)]"],
  section.bg-white [class*="sv-btn"][class*="!text-white"]:not([class*="!bg-white"]) {
    color: var(--white) !important;
  }
  /* Catch-all unlayered-equivalent in this layer */
  [class*="sv-btn"][class*="!text-[var(--surface-background)]"]:not([class*="!bg-white"]),
  [class*="sv-btn"][class*="text-[var(--surface-background)]"]:not([class*="!bg-white"]) {
    color: var(--bg) !important;
  }

  /* LM-112 (owner-spotted): premium-transformation.css line 200 sets
     -webkit-text-fill-color:var(--bg) on every descendant of section.!bg-white
     → overrode !text-white on buttons → dark on dark = INVISIBLE.
     Reset -webkit-text-fill-color to match the button's explicit text utility. */
  [class*="sv-btn"][class*="!text-white"],
  [class*="sv-btn"][class*="text-white"]:not([class*="!bg-white"]) {
    color: var(--white) !important;
    -webkit-text-fill-color: var(--white) !important;
  }
  [class*="sv-btn"][class*="!text-[var(--surface-background)]"],
  [class*="sv-btn"][class*="text-[var(--surface-background)]"] {
    color: var(--bg) !important;
    -webkit-text-fill-color: var(--bg) !important;
  }
  .sv-btn-premium, .sv-btn-primary-premium, .sv-btn-primary, .sv-btn-primary-v2,
  a.sv-btn-premium, a.sv-btn-primary-premium, a.sv-btn-primary {
    -webkit-text-fill-color: var(--bg-tint) !important;
  }
  .sv-btn-ghost, .sv-btn-ghost-premium,
  a.sv-btn-ghost, a.sv-btn-ghost-premium {
    -webkit-text-fill-color: var(--cloud) !important;
  }
  /* For dark-bg buttons (.sv-btn !bg-[var(--surface-background)]) inside !bg-white sections —
     premium-transformation forces dark fill on every descendant. Override. */
  section.\!bg-white [class*="sv-btn"][class*="!bg-\[\var(--surface-background)\]"],
  section.bg-white [class*="sv-btn"][class*="!bg-\[\var(--surface-background)\]"],
  section.\!bg-white [class*="sv-btn"][class*="!bg-black"],
  section.bg-white [class*="sv-btn"][class*="!bg-black"] {
    color: var(--white) !important;
    -webkit-text-fill-color: var(--white) !important;
  }

  /* LM-113 (owner-spotted): pricing .ptabs renders as inline-flex per
     premium-transformation line 163. Tailwind 'flex justify-center' on the
     markup is overridden by inline-flex, so the switcher pill sits LEFT
     instead of centred. Fix: margin-inline:auto + display block on wrap. */
  .ptab-wrap, .ptab-wrap > .ptabs, .ptabs {
    margin-inline: auto !important;
  }
  .ptab-wrap {
    display: block !important;
    text-align: center !important;
    width: 100% !important;
  }
  /* Ensure the parent flex container itself centres. (owner 2026-05-30: stack the
     tab capsule and the Monthly/Annual toggle in a CENTRED COLUMN — they were a flex
     ROW, so the capsule sat left-of-centre with the toggle floating far right.
     The markup gives the toggle mt-8, i.e. it's meant to be BELOW, centred.) */
  div:has(> .ptabs), div:has(> .ptab-wrap) {
    display: flex !important;
    flex-direction: column !important;
    align-items: center !important;
    justify-content: center !important;
    width: 100% !important;
  }

  /* ── OPT-OUT: honest content marked .ca-text-keep wins ── */
  .ca-text-keep, .ca-text-keep * {
    color: revert !important;
  }

  /* ── LM-117 (Claude 2026-05-29 owner-spotted): oversized product page CTAs.
     crowcash 'Start free trial' + crowesg 'Join the waitlist' use px-20 py-10
     text-3xl (80px horizontal padding, 40px vertical, 30px font) = absurdly
     large. Owner: 'too big — make slightly smaller'. Cap padding+font on
     section-bottom CTAs that aren't already in the canonical button family. */
  section a[class*="px-20"][class*="py-10"]:not(.sv-btn-premium):not(.sv-btn-primary-premium):not(.sv-btn-ghost-premium),
  section a[class*="px-16"][class*="py-8"]:not(.sv-btn-premium):not(.sv-btn-primary-premium):not(.sv-btn-ghost-premium),
  section a[class*="!px-20"][class*="!py-10"] {
    padding: 16px 36px !important;
    font-size: 1.125rem !important; /* ~18px from 30px */
    line-height: 1.2 !important;
    min-height: 56px !important;
    font-weight: 700 !important;
    letter-spacing: 0.005em !important;
    box-shadow: 0 6px 22px -8px rgba(12,201,168,0.45) !important;
  }
  @media (min-width: 1280px) {
    section a[class*="px-20"][class*="py-10"]:not(.sv-btn-premium):not(.sv-btn-primary-premium):not(.sv-btn-ghost-premium) {
      padding: 18px 42px !important;
      font-size: 1.25rem !important;
    }
  }

  /* ── G8 · PREMIUM GLASS SHEEN ──
     Dynamic specular highlight that follows the mouse across glass surfaces.
     Consumes --mouse-x and --mouse-y from sovereign-transformation-v2.js. */
  .ca-glass-sheen {
    position: relative;
    overflow: hidden;
  }
  .ca-glass-sheen::after {
    content: "";
    position: absolute;
    inset: 0;
    background: radial-gradient(
      circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
      var(--white-08) 0%,
      transparent 60%
    );
    pointer-events: none;
    z-index: var(--z-content);
    opacity: 0;
    transition: opacity 0.3s ease;
  }
  .ca-glass-sheen:hover::after {
    opacity: 1;
  }

  /* ── LM-117 contrast: oversized CTAs sometimes also use non-standard bg
     colours (lime var(--lime), etc.). Force readable dark text on lime, white on dark. */
  a[class*="bg-[var(--lime)]"], a[class*="!bg-[var(--lime)]"] {
    background: var(--lime) !important;
    color: var(--bg) !important;
    -webkit-text-fill-color: var(--bg) !important;
  }
  a[class*="bg-[var(--mark)]"], a[class*="!bg-[var(--mark)]"] {
    background: var(--mark) !important;
    color: var(--bg) !important;
    -webkit-text-fill-color: var(--bg) !important;
  }
  /* Big CTAs with bg-[var(--surface-background)] (dark obsidian) + text-white: ensure visible */
  a[class*="bg-[var(--surface-background)]"][class*="text-white"] {
    color: var(--white) !important;
    -webkit-text-fill-color: var(--white) !important;
  }

  /* ── LM-115 (owner-spotted): Low-opacity white text is invisible ── */
  /* 'By subscribing you agree...' on contact uses text-white/10 = 10% opacity = invisible.
     Bump all low-opacity utility text on dark sections to readable 60-72%. */
  section.ca-section-dark .text-white\/10, section.ca-section-dark [class*="text-white/10"],
  section.bg-\[\var(--surface-background)\] .text-white\/10, section.bg-\[\var(--surface-background)\] [class*="text-white/10"],
  section.bg-black .text-white\/10, section.bg-black [class*="text-white/10"] {
    color: rgba(255, 255, 255, 0.62) !important;
    -webkit-text-fill-color: rgba(255, 255, 255, 0.62) !important;
  }
  section.ca-section-dark .text-white\/20, section.ca-section-dark [class*="text-white/20"] {
    color: rgba(255, 255, 255, 0.68) !important;
    -webkit-text-fill-color: rgba(255, 255, 255, 0.68) !important;
  }
  /* Anywhere text-white/30 lives, bump to /60 for readability */
  section.ca-section-dark .text-white\/30, section.ca-section-dark [class*="text-white/30"] {
    color: rgba(255, 255, 255, 0.72) !important;
    -webkit-text-fill-color: rgba(255, 255, 255, 0.72) !important;
  }

  /* ── LM-115 form labels / inputs / selects: context-aware ── */
  /* Form labels on white-section parents must be dark.  */
  section.bg-white .form-label, section.bg-white label.form-label,
  section[class*="bg-white"]:not([class*="bg-white/"]) .form-label,
  .ca-card.\!bg-white .form-label,
  [class*="!bg-white"]:not([class*="!bg-white/"]) .form-label {
    color: var(--bg) !important;
    -webkit-text-fill-color: var(--bg) !important;
  }
  /* Form inputs/selects on white sections — dark text */
  section.bg-white .form-input, section.bg-white input.form-input,
  section.bg-white select.form-input, section.bg-white textarea.form-input,
  section[class*="bg-white"]:not([class*="bg-white/"]) .form-input,
  section[class*="bg-white"]:not([class*="bg-white/"]) input,
  section[class*="bg-white"]:not([class*="bg-white/"]) select,
  section[class*="bg-white"]:not([class*="bg-white/"]) textarea {
    color: var(--bg) !important;
    -webkit-text-fill-color: var(--bg) !important;
    background-color: var(--white) !important;
    border-color: rgba(4, 14, 26, 0.16) !important;
  }
  section.bg-white .form-input::placeholder,
  section[class*="bg-white"]:not([class*="bg-white/"]) input::placeholder,
  section[class*="bg-white"]:not([class*="bg-white/"]) textarea::placeholder {
    color: rgba(4, 14, 26, 0.5) !important;
    -webkit-text-fill-color: rgba(4, 14, 26, 0.5) !important;
  }
  /* Form inputs/selects on dark sections — light text */
  section.ca-section-dark .form-input, section.ca-section-dark input,
  section.ca-section-dark select, section.ca-section-dark textarea,
  section.bg-\[\var(--surface-background)\] .form-input, section.bg-\[\var(--surface-background)\] input,
  section.bg-\[\var(--surface-background)\] select, section.bg-\[\var(--surface-background)\] textarea {
    color: var(--cloud) !important;
    -webkit-text-fill-color: var(--cloud) !important;
    background-color: var(--white-04) !important;
    border-color: rgba(255, 255, 255, 0.1) !important;
  }
  section.ca-section-dark .form-input::placeholder,
  section.ca-section-dark input::placeholder,
  section.ca-section-dark textarea::placeholder {
    color: rgba(232, 240, 250, 0.5) !important;
    -webkit-text-fill-color: rgba(232, 240, 250, 0.5) !important;
  }
  /* SELECT options — browsers render in OS UI; force readable colours. */
  select option { color: var(--bg) !important; background-color: var(--white) !important; }
  /* Form labels on dark sections — light */
  section.ca-section-dark .form-label, section.bg-\[\var(--surface-background)\] .form-label,
  section.bg-black .form-label {
    color: var(--cloud) !important;
    -webkit-text-fill-color: var(--cloud) !important;
  }

  /* ── LM-115 generic invisible-text safety: low-opacity descendants ── */
  /* If a section has dark bg AND a descendant has opacity < 0.4, bump to 0.6 */
  /* (CSS can't conditionally test computed opacity; instead target common Tailwind
     utility classes that yield low opacity on text.) */
  section.ca-section-dark .opacity-10, section.ca-section-dark .opacity-20,
  section.ca-section-dark [class*="opacity-10"], section.ca-section-dark [class*="opacity-20"] {
    opacity: 0.7 !important;
  }
  section.bg-white .opacity-10:not([class*="bg-"]):not([class*="border-"]),
  section.bg-white .opacity-20:not([class*="bg-"]):not([class*="border-"]) {
    opacity: 0.55 !important;
  }
}

/* ============================================================
   LM-110 (Claude 2026-05-29) — owner-spotted home "Who it's for" cards
   "text and icon of these cards are not top aligned properly so looking odd".
   Root cause: home cards use `flex flex-col justify-between` on outer
   .ca-card.ca-glass. The .ca-glow decorative element sits IN-FLOW at top so
   justify-between pushes the content wrapper to the BOTTOM of the card.
   Fix: take .ca-glow out of flow (absolute positioning) AND force
   justify-content:flex-start on .ca-card.ca-glass so the icon+h3+p block
   anchors at the top regardless of card height.
   ============================================================ */
.ca-card.ca-glass {
  justify-content: flex-start !important;
}
.ca-card.ca-glass > .ca-glow {
  position: absolute !important;
  inset: 0 !important;
  pointer-events: none !important;
  z-index: var(--z-base) !important;
}
/* Ensure cards in #who-its-for grid have equal-height stretched layout
   with content top-aligned and icon+h3+p tight spacing */
section#who-its-for .grid > .ca-card,
section#who-its-for .ca-card.ca-glass {
  justify-content: flex-start !important;
  align-items: stretch !important;
}
section#who-its-for .ca-card .relative.z-10 {
  display: flex;
  flex-direction: column;
  gap: 0;
}
/* Icon gets consistent margin to heading; heading to paragraph */
section#who-its-for .ca-card .w-12.h-12 {
  margin-bottom: 1.5rem !important; /* was mb-10 = 2.5rem — tighten */
}
section#who-its-for .ca-card h3,
section#who-its-for .ca-card h4 {
  margin-bottom: 0.875rem !important;
}

/* Polish: focus-visible rings on every interactive element (a11y).
   Premium soft ring: a token-tinted box-shadow that follows the element's own
   border-radius (no harsh square outline on rounded buttons/cards). The
   transparent outline is the forced-colors / Windows-high-contrast fallback
   (box-shadow is dropped there; the outline becomes a system colour). */
a:focus-visible, button:focus-visible, [tabindex="0"]:focus-visible, [role="button"]:focus-visible {
  outline: 2px solid transparent !important;
  outline-offset: 2px !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 42%, transparent) !important;
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid transparent !important;
  outline-offset: 1px !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 38%, transparent) !important;
}

/* ── LM-157 (2026-05-30 — Claude, owner-spotted): pricing product switcher looked
   "very odd" — the tabs rendered as oversized (84px-tall), border-radius:999px
   overlapping circles because the sliding-indicator script isn't loaded and the
   fallback .ptab sizing is broken. Render a clean segmented PILL control instead:
   one rounded track, inactive = subtle/transparent, active (.on / aria-selected) =
   teal-filled with dark text. No overlap, sensible height. nav-global-fix loads last
   so this governs. */
.ptabs {
  display: inline-flex !important;
  align-items: center !important; /* stop tabs stretching to the track's cross height */
  flex-wrap: nowrap !important;
  gap: var(--space-1) !important;
  padding: 6px !important;
  height: auto !important;
  background: var(--white-04) !important;
  border: 1px solid var(--white-08) !important;
  border-radius: 999px !important;
  max-width: 100%;
  overflow-x: auto;
}
.ptabs .ptab {
  position: relative;
  z-index: var(--z-content);
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  align-self: center !important;
  flex: 0 0 auto !important;
  box-sizing: border-box !important;
  height: 40px !important;
  min-height: 40px !important;
  max-height: 40px !important;
  width: auto !important;
  padding: 0 18px !important;
  margin: 0 !important;
  border: 0 !important;
  border-radius: 999px !important;
  background: transparent !important;
  color: rgba(255, 255, 255, 0.7) !important;
  -webkit-text-fill-color: rgba(255, 255, 255, 0.7) !important;
  font-size: var(--text-sm) !important;
  font-weight: 700 !important;
  line-height: 1 !important;
  white-space: nowrap !important;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}
.ptabs .ptab.on,
.ptabs .ptab[aria-selected="true"] {
  background: var(--teal, var(--teal)) !important;
  color: var(--bg) !important;
  -webkit-text-fill-color: var(--bg) !important;
}
.ptabs .ptab:hover:not(.on):not([aria-selected="true"]) {
  color: var(--white) !important;
  -webkit-text-fill-color: var(--white) !important;
  background: var(--white-06) !important;
}
@media (max-width: 480px) {
  .ptabs .ptab { padding: 8px 12px !important; font-size: var(--text-sm) !important; }
}

/* ── LM-158 (2026-05-30 — Claude, owner-spotted): contact.html + partners.html form
   fields rendered with NO visible border (markup used `.form-input !border-white/10`
   which sets border-COLOR but not border-WIDTH → border:0), so fields were invisible/
   cramped (24px tall, no box). Define .form-input as a proper field: visible 1px border,
   48px min height (touch target), padding, rounded, teal focus. The markup's
   !border-white/10 / !bg-white/5 still set colour; this supplies width + sizing. */
.form-input {
  display: block;
  width: 100% !important;
  min-height: 48px !important;
  padding: 12px 16px !important;
  border-width: 1px !important;
  border-style: solid !important;
  border-color: rgba(255, 255, 255, 0.12);
  border-radius: 10px !important;
  background: var(--white-05);
  color: var(--cloud) !important;
  -webkit-text-fill-color: var(--cloud) !important;
  font-size: var(--text-md) !important;
  line-height: 1.4 !important;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.form-input::placeholder { color: rgba(232, 240, 250, 0.4) !important; -webkit-text-fill-color: rgba(232, 240, 250, 0.4) !important; }
.form-input:focus, .form-input:focus-visible {
  outline: none !important;
  border-color: var(--teal) !important;
  box-shadow: 0 0 0 3px rgba(12, 201, 168, 0.18) !important;
}
textarea.form-input { min-height: 120px !important; padding-top: var(--space-3) !important; }
select.form-input { cursor: pointer; }

/* ============================================================
   CHROME AUDIT 2026-05-30 — sitewide a11y + polish (Claude)
   A11Y-004 focus ring · PERF-001 reduced-motion · RESP-002 marquee
   fade · A11Y-003 carousel 44px tap targets.
   ============================================================ */

/* A11Y-004 (WCAG 2.4.7): universal visible focus indicator. The site
   suppressed default outlines globally; only buttons/skip-link/toggle had a
   custom :focus-visible. Keyboard users got no focus ring on links, nav items,
   form fields or carousel dots. This guarantees a 2px teal ring (3:1 contrast
   on both light and dark surfaces) on every interactive element. Uses
   :focus-visible so mouse clicks don't show the ring. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible,
[role="tab"]:focus-visible,
[role="menuitem"]:focus-visible {
  outline: 2px solid transparent !important;
  outline-offset: 2px !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 42%, transparent) !important;
}

/* PERF-001 (WCAG 2.3.3): global reduced-motion guard. Existing rules only
   neutralised the hero animation. This snaps ALL animations/transitions
   (incl. scroll reveals + number counters) to their final state for users who
   set prefers-reduced-motion. Counter modules read their data-target so the
   final value shows immediately rather than mid-tween. */
@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;
  }
}

/* RESP-002: sectors marquee edge fade. The ticker text appeared/disappeared
   abruptly at the viewport edges. A linear-gradient mask fades both edges to
   transparent for the premium "infinite scroll" look. */
.ca-marquee-band {
  -webkit-mask-image: linear-gradient(to right, transparent 0%, var(--bg) 7%, var(--bg) 93%, transparent 100%);
          mask-image: linear-gradient(to right, transparent 0%, var(--bg) 7%, var(--bg) 93%, transparent 100%);
}

/* A11Y-003 (WCAG 2.5.5): carousel dot buttons rendered a 28px ring — below the
   44x44 minimum target size. Pad the clickable area to 44px while the visual
   ring stays 28px (centred). */
.pcar__tab {
  min-width: 44px !important;
  min-height: 44px !important;
  width: 44px !important;
  height: 44px !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 0 !important;
  background: transparent !important;
  border: none !important;
}
/* FIX (owner 2026-05-31, issue #2): the 44px tap-target was filling the WHOLE dot
   (the button's own background), so the carousel pagination rendered as giant 44px
   blobs and squeezed the caption to ~32px ("capsules look big, text misaligned").
   Keep the 44px HIT AREA, show a small dot via ::before. */
.pcar__tab::before {
  content: ""; display: block;
  width: 7px; height: 7px; border-radius: 9999px;
  background: rgba(255, 255, 255, 0.35);
  transition: width .3s ease, background .3s ease;
}
.pcar__tab[aria-selected="true"]::before, .pcar__tab.is-active::before {
  width: 20px; background: var(--teal, var(--teal));
}
/* #3 (owner 2026-05-31): the rotating Free-Tools CTA rendered ALL THREE labels
   stacked ("Calculate recovery" / "Run PPN scorer" / "Run readiness check") because
   the rotator hide rule wasn't taking effect inside the <button>. Force only the
   active label visible so the CTA reads as one clean button, and give the button a
   stable min-width so it doesn't jump as labels rotate. */
button.ca-rotator { position: relative; min-width: 230px; }
button.ca-rotator .ca-rotator__item {
  position: absolute !important; inset: 0; opacity: 0 !important; pointer-events: none !important;
  display: inline-flex !important; align-items: center !important; justify-content: center !important;
  white-space: nowrap;
}
button.ca-rotator .ca-rotator__item--first,
button.ca-rotator .ca-rotator__item[aria-current="true"] {
  position: relative !important; inset: auto !important; opacity: 1 !important; pointer-events: auto !important;
}

/* SAME BUG, the Free-Tools HEADLINE + DESCRIPTION rotators (owner 2026-05-31, reported
   repeatedly): on BOTH desktop and mobile all three headlines ("Calculate statutory
   interest." / "Score your Social Value response." / "Pre-screen Cyber Essentials
   readiness.") AND all three descriptions rendered STACKED as one static wall of text,
   because ca-primitives.css's .ca-rotator__item hide rule was being overridden here
   (computed position:static; opacity:1). The JS cycles aria-current fine — we just have
   to make the cascade hide the non-active items. Force only the active line visible so
   the section reads as ONE headline + ONE description that rotate in place. */
h2.ca-rotator, p.ca-rotator { position: relative !important; }
h2.ca-rotator .ca-rotator__item,
p.ca-rotator .ca-rotator__item {
  position: absolute !important; inset: 0 !important; left: 0 !important; right: 0 !important;
  opacity: 0 !important; visibility: hidden !important; pointer-events: none !important;
  display: block !important;
}
/* .ca-section-title paints its text with a gradient via background-clip:text +
   transparent fill. That only works while the text is INLINE inside the h2; once the
   rotator items become positioned blocks (above) they fall out of the h2's clip flow
   and inherit the transparent fill with no gradient of their own -> invisible glyphs.
   Give each rotator line a solid fill so the active headline is legible. */
h2.ca-rotator .ca-rotator__item {
  -webkit-text-fill-color: currentColor !important;
  background: none !important;
}
h2.ca-rotator .ca-rotator__item--first,
h2.ca-rotator .ca-rotator__item[aria-current="true"],
p.ca-rotator .ca-rotator__item--first,
p.ca-rotator .ca-rotator__item[aria-current="true"] {
  position: relative !important; inset: auto !important;
  opacity: 1 !important; visibility: visible !important; pointer-events: auto !important;
}

/* #free-tools card mobile type scale. */
@media (max-width: 767px) {
  #free-tools h2.ca-rotator { font-size: clamp(22px, 6.4vw, 30px) !important; line-height: 1.15 !important; }
  #free-tools .ca-section-desc { font-size: var(--text-md) !important; line-height: 1.55 !important; margin-bottom: var(--space-8) !important; }
}
/* #free-tools card mobile padding: Tailwind's `!p-20` (5rem/80px) lives in @layer
   utilities, so an UNLAYERED !important loses to it. For !important declarations the
   layer order is INVERTED — EARLIER layers win — so placing this in @layer base
   (declared before utilities) beats the utility unconditionally, no specificity race. */
@layer base {
  @media (max-width: 767px) {
    #free-tools .ca-card { padding: 36px 20px !important; }
  }
}

/* MOBILE declutter of the carousel context bar (issue #2): even with small visual
   dots, 5x44px hit areas + the decorative "Sample Data" / "Live Platform" badge left
   no room for the caption on a ~298px bar. On phones, hide the decorative badge + its
   divider and tighten the bar so the caption reads clearly; dots keep a 30px hit area
   (>=24px WCAG 2.5.8 AA) at 44px height. */
@media (max-width: 640px) {
  .ca-glass-premium:has(.pcar__caption) .shrink-0 > span,
  .ca-glass-premium:has(.pcar__caption) .shrink-0 > [class*="w-px"],
  [class*="bg-white/9"]:has(.pcar__caption) .shrink-0 > span,
  [class*="bg-white/9"]:has(.pcar__caption) .shrink-0 > [class*="w-px"] { display: none !important; }
  .ca-glass-premium:has(.pcar__caption),
  [class*="bg-white/9"]:has(.pcar__caption) { gap: var(--space-2) !important; padding: 6px 12px !important; }
  .pcar__tab { min-width: 26px !important; width: 26px !important; }
  /* tighten the dot row's own gap so the caption gets more room */
  .ca-glass-premium:has(.pcar__caption) .shrink-0 [class*="gap-1"],
  [class*="bg-white/9"]:has(.pcar__caption) .shrink-0 [class*="gap-1"] { gap: var(--space-0) !important; }
}

/* RESP-005 (Chrome audit 2026-05-30 — Claude): homepage API code preview could
   overflow its container on narrow viewports (long URL / Bearer token strings).
   Allow horizontal scroll within the block and let long tokens wrap, so the code
   never forces the whole page to scroll sideways on mobile. */
.ca-code-block { overflow-x: auto !important; max-width: 100% !important; }
.ca-code-block > div { overflow-wrap: anywhere; word-break: break-word; }

/* Chrome audit 2026-05-30 (Claude) — solid CTA pill anchors must use dark text.
   A global anchor colour tinted these teal, so /faq's "Book a call" rendered as
   teal text on a teal-500 background (invisible), and white-bg CTAs washed out.
   Per CLAUDE.md a teal-background CTA uses obsidian (var(--bg)) text. Scoped to
   Tailwind solid-fill utility anchors so it never touches ghost/nav buttons. */
a.bg-teal-500, a.bg-teal-400, a.bg-teal-600, a.bg-white,
a.bg-teal-500 *, a.bg-teal-400 *, a.bg-teal-600 *, a.bg-white * {
  color: var(--bg-tint) !important;
  -webkit-text-fill-color: var(--bg-tint) !important;
}

/* #5 CTA BUTTON SIZING (owner 2026-05-31): marketing CTA buttons stretched full-bleed
   (~350px, "so long") inside flex-column containers on mobile, but were small (~163px)
   on desktop, and some long labels wrapped to 2 lines. Give them a consistent, premium,
   centred size on mobile: content-width with a comfortable min so stacked buttons align,
   never edge-to-edge, single line. Excludes form submit buttons (they match their input)
   and the mobile-menu CTAs (which are intentionally full-width). */
@media (max-width: 767px) {
  .ca-hero-btns > .sv-btn,
  [class*="flex-col"] > .sv-btn:not([type="submit"]) {
    align-self: center !important;
    width: auto !important;
    min-width: 220px;
    max-width: 100%;
    white-space: nowrap;
  }
}

/* NUMBERED STEP/PROCESS CARDS (owner 2026-05-31): the big 01/02/03/04 watermark
   numbers were text-white/5 (~5% opacity = invisible) on charcoal cards, and
   text-[var(--surface-background)]/10 on light cards. Brighten so they read as a crisp design element
   ("shiny white"), while staying a tasteful watermark (not overpowering the heading).
   Targeted by the white/5 (or dark/10) + font-black token pair these numbers share. */
[class~="text-white/5"][class~="font-black"] {
  color: rgba(255, 255, 255, 0.40) !important;
  -webkit-text-fill-color: rgba(255, 255, 255, 0.40) !important;
}
[class~="text-[var(--surface-background)]/10"][class~="font-black"] {
  color: rgba(4, 14, 26, 0.38) !important;
  -webkit-text-fill-color: rgba(4, 14, 26, 0.38) !important;
}

/* CLOUDFLARE TURNSTILE (owner 2026-05-31): the widget is a fixed ~300px iframe. On
   the partners form (card !p-12 = 48px padding) the inner width dropped to ~204px on
   mobile, so the Turnstile overflowed the form ("going out to form"). Tighten the
   form-card padding on phones so the 300px widget fits, and make the widget container
   never overflow (scroll as a last resort). */
/* HOME PRODUCT CAROUSEL mobile rebalance (owner 2026-05-31): on phones the browser-
   chrome bar + white context capsule looked oversized while the actual screenshot
   looked small. Tighten the frame/chrome and widen the card so the screenshot
   dominates. In @layer base to beat layered utility padding. */
@layer base {
  @media (max-width: 640px) {
    .ca-showcase-frame { padding: 4px !important; border-radius: 22px !important; }
    .ca-browser-chrome { padding: 7px 11px !important; }
    .ca-browser-chrome > .flex > div { width: 9px !important; height: 9px !important; } /* traffic lights */
    /* let the showcase use the full hero width (less dark gutter) so the screenshot is larger */
    .ca-hero-visual, .ca-hero-visual-col { max-width: none !important; padding-left: 0 !important; padding-right: 0 !important; }
    /* context capsule: trimmer so it doesn't dominate the screenshot */
    .ca-glass-premium:has(.pcar__caption) { padding: 6px 12px !important; }
  }
}

.cf-turnstile { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* IN @layer base: the card !p-12 (48px) is Tailwind @layer utilities !important; an
   UNLAYERED override loses to it (for !important, layered beats unlayered). Placing
   this in @layer base lets it beat the utilities-layer padding. */
@layer base {
  @media (max-width: 1023px) {
    /* form section grid rendered ~302px (not full width) and the 48px card padding
       left ~204px inner — too narrow for the 300px Turnstile. Full-width column +
       lighter padding so the widget fits. */
    #partner-form-section .grid, #contact-form-section .grid {
      grid-template-columns: 1fr !important; gap: 2.5rem !important;
    }
    #partner-form-section .ca-card, #contact-form-section .ca-card { padding: 1.5rem !important; }
  }
}

/* HOME "What we cover" STAT NUMBERS (owner 2026-05-31): all are text-5xl, but the
   longer values (Base+8%, 1,000+, 44+22) wrapped/overflowed the 2-col mobile grid
   while short ones (10%) fit on one line, so the numbers looked different sizes.
   Clamp to a responsive size that keeps every stat on ONE line at the same scale on
   mobile; desktop max (3rem) matches the original text-5xl. Covers EVERY stat in
   #stats — incl. the static "2028" (no data-counter, so the old counter-only scope
   missed it and it stayed 48px while siblings shrank to ~27px on mobile). */
.text-5xl[data-counter-to],
.text-5xl:has([data-counter-to]),
#stats .grid > div > .text-5xl {
  font-size: clamp(1.6rem, 7vw, 3rem) !important;
  line-height: 1.05 !important;
  white-space: nowrap !important;
}

/* LIME CONTRAST (owner 2026-05-31): the CrowESG neon-lime (var(--lime)) is very light,
   so white text on it is invisible (e.g. pricing "Waitlist Open" badge). Any element
   with a lime background must use obsidian text. Scoped to lime-fill utilities. */
[class~="bg-[var(--lime)]"], [class~="bg-[var(--lime)]"] *,
[class~="!bg-[var(--lime)]"], [class~="!bg-[var(--lime)]"] * {
  color: var(--bg) !important;
  -webkit-text-fill-color: var(--bg) !important;
}
/* the "Waitlist Open" eyebrow specifically: .ca-eyebrow sets a near-white color +
   -webkit-text-fill-color with !important, which beat the earlier fix. This dark
   override loads after .ca-eyebrow so it wins the tie. */
.ca-eyebrow[class~="!bg-[var(--lime)]"], .ca-eyebrow[class~="bg-[var(--lime)]"] {
  color: var(--bg) !important;
  -webkit-text-fill-color: var(--bg) !important;
}

/* HERO CAROUSEL CAPTION — MOBILE (owner 2026-05-31): the full-width bright-white
   caption bar (desktop choice) dominated the shrunk dashboard on mobile + looked
   weird. On mobile make it a COMPACT DARK-GLASS pill (auto width, hugs the text)
   with light text → subtle + premium. Overrides the white-bar rule (~line 166). */
@media (max-width: 767px) {
  #hero .ca-glass-premium:has(.pcar__caption) {
    /* near-opaque dark so it reads dark even where backdrop-filter is unsupported */
    background: rgba(8, 20, 36, 0.94) !important;
    border-color: rgba(255, 255, 255, 0.14) !important;
    backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important;
    width: auto !important; max-width: calc(100% - 1.5rem) !important;
    padding: 6px 14px !important; bottom: 0.6rem !important; gap: 0.6rem !important; border-radius: 12px !important;
  }
  #hero .ca-glass-premium .pcar__caption { color: rgba(255,255,255,0.92) !important; -webkit-text-fill-color: rgba(255,255,255,0.92) !important; font-size: 10.5px !important; line-height: 1.3 !important; }
  /* "Sample Data" pill + divider take too much room on mobile — drop them, keep dots. */
  #hero .ca-glass-premium > div > span:first-child,
  #hero .ca-glass-premium > div > .w-px { display: none !important; }
  #hero .ca-glass-premium .pcar__tab { width: 6px !important; height: 6px !important; }
  #hero .ca-glass-premium:has(.pcar__caption) .pcar__tab::before { background: rgba(255,255,255,0.35) !important; }
}

/* PRODUCT / OTHER CAROUSELS = EXACTLY like the HERO carousel (owner 2026-05-31).
   The product carousels were rebuilt in HTML to use the hero's exact structure
   (.ca-hero-visual.max-w-5xl wrapper, mac chrome, 16:10 viewport, glass overlay caption
   bar with dots INSIDE the viewport, slab base + shadow). Two safety nets remain:
   1) force 16:10 even if any stray markup says 16:9;
   2) on mobile the product carousels sit inside .ca-container (20px side padding) while
      the hero is full-bleed — break them out so every carousel is the SAME width as the
      hero. .ca-container left/right padding is 20px at <=767px. */
[data-pcar] .ca-viewport { aspect-ratio: 16 / 10 !important; }
[data-pcar].ca-container { max-width: 64rem !important; margin-left: auto !important; margin-right: auto !important; } /* legacy: any not-yet-converted carousel */
@media (max-width: 767px) {
  /* True full-bleed regardless of ancestor padding (product hero sections have 0 side
     padding + 20px container; the homepage #interface section has 24px + 20px). The
     `calc(50% - 50vw)` margin pulls each edge to the viewport edge no matter how nested,
     so every .ca-container carousel matches the full-bleed HERO width. body/sections use
     overflow-x:clip so there is no horizontal scroll. */
  .ca-container > [data-pcar].ca-hero-visual {
    width: 100vw !important; max-width: 100vw !important;
    margin-left: calc(50% - 50vw) !important; margin-right: calc(50% - 50vw) !important;
  }
}

/* PRODUCT-PAGE CAROUSEL — MOBILE (owner 2026-05-31): the .pcar__tab pagination
   was hijacked by the global (pointer:coarse) button rule into a large teal PILL
   (looked odd), and .pcar__caption was near-invisible (faint steel on dark). Force
   the indicator back to a small dot and make the caption legible. */
@media (max-width: 767px) {
  /* Include [aria-selected=true]: the ACTIVE tab BUTTON itself was 12x24 teal +
     radius 4px (a vertical teal pill) via a more-specific rule. Reset it so the
     indicator is only the small scaled teal ::before dot. */
  .pcar__tab, .pcar__tab[aria-selected="true"] {
    width: 24px !important; height: 24px !important; min-width: 0 !important; min-height: 0 !important;
    background: none !important; background-color: transparent !important; border: 0 !important; border-radius: 0 !important; padding: 0 !important;
    box-shadow: none !important;
  }
  .pcar__tab::before { width: 7px !important; height: 7px !important; border-radius: 50% !important; }
  .pcar__tab[aria-selected="true"]::before { width: 7px !important; transform: scale(1.25) !important; background: var(--teal, var(--teal)) !important; }
  /* The SVG progress ring stretches into an odd teal "pill" because the coarse-pointer
     rule widens the tab button. Hide it on mobile; the scaled teal dot is the indicator. */
  .pcar__ring { display: none !important; }
  .pcar__caption { color: rgba(255, 255, 255, 0.85) !important; font-size: 0.8rem !important; padding: 0 12px !important; }
  /* ZOOM/CROP the dashboard screenshots on mobile so the metrics/title are legible
     (owner 2026-05-31). TIGHTLY scoped to the dashboard SHOWCASE only
     ([data-pcar] .ca-showcase-frame .ca-viewport) — this cannot touch the other
     .pcar__viewport carousels that the earlier broad rule broke. */
  [data-pcar] .ca-showcase-frame .ca-viewport { overflow: hidden !important; }
  [data-pcar] .ca-showcase-frame .ca-viewport .pcar__slide img {
    transform: scale(1.3) !important; transform-origin: top center !important;
  }
  /* The #interface "See it in action" single showcase uses .ca-carousel-frame /
     .ca-slide (NOT the [data-pcar] hero carousel), so the rule above skipped it and
     its dashboard rendered ~half-size/tiny on mobile. Apply the SAME zoom so the
     product screenshot matches the hero carousel size on every product page. */
  /* .ca-carousel-frame is the product-showcase frame and appears ONLY on the 5
     product pages (one each), so this is safe un-scoped — covers core/cash/esg
     whose showcase section isn't wrapped in #interface. */
  .ca-carousel-frame .ca-viewport { overflow: hidden !important; }
  .ca-carousel-frame .ca-viewport .ca-slide img {
    transform: scale(1.3) !important; transform-origin: top center !important;
  }
}

/* FOOTER ACCORDION — MOBILE (owner 2026-05-31, Apple/AWS-style). Each footer
   column heading is a tap-to-expand button; links collapse by default on mobile.
   Desktop is untouched (columns always open). The brand column never collapses. */
@media (max-width: 767px) {
  .ca-footer .footer-col:not(.footer-col-brand) { border-bottom: 1px solid var(--white-08); }
  .ca-footer .footer-col:not(.footer-col-brand) .footer-col-title {
    display: flex; align-items: center; justify-content: space-between;
    cursor: pointer; margin: 0; padding: 16px 2px; -webkit-user-select: none; user-select: none;
    min-height: 44px;
  }
  .ca-footer .footer-col:not(.footer-col-brand) .footer-col-title::after {
    content: ''; flex: none; width: 9px; height: 9px; margin-right: var(--space-1);
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(45deg); transition: transform .3s ease; opacity: 0.55;
  }
  .ca-footer .footer-col.is-open .footer-col-title::after { transform: rotate(-135deg); }
  /* GPU-friendly grid-rows accordion (no max-height layout tween): .footer-col
     has exactly two children (title + .footer-links), so animating the parent's
     grid-template-rows from `auto 0fr` to `auto 1fr` collapses/expands the links
     row smoothly without a hardcoded max-height ceiling. */
  .ca-footer .footer-col:not(.footer-col-brand) {
    display: grid; grid-template-rows: auto 0fr; transition: grid-template-rows .35s ease;
  }
  .ca-footer .footer-col.is-open:not(.footer-col-brand) { grid-template-rows: auto 1fr; }
  .ca-footer .footer-col:not(.footer-col-brand) .footer-links {
    overflow: hidden; min-height: 0; opacity: 0; transition: opacity .25s ease;
  }
  .ca-footer .footer-col.is-open .footer-links { opacity: 1; padding: 6px 0 16px; }
  .ca-footer .footer-col:not(.footer-col-brand) .footer-col-title:focus-visible { outline: 2px solid transparent; outline-offset: 2px; box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 42%, transparent); }
}

/* ============================================================
   MOBILE RESPONSIVENESS ROOT FIX (Chrome audit 2026-05-30 — Claude)
   Owner: every page clipped content on mobile. Root cause: .ca-container is a
   flex item inside flex-column .ca-hero/.ca-section (align-items:center). Its
   default min-width:auto let it grow to its CONTENT min-content width (e.g.
   457px) and overflow the 390px viewport — body overflow-x:clip hid the
   scrollbar but the right edge of text/badges was cut off. Forcing width:100%
   + min-width:0 makes it fill (never exceed) its parent on every viewport.
   ============================================================ */
/* ============================================================
   GEOMETRIC SPINE — 2026-06-01 (Stripe/Apple-grade audit findings G1/G3/G4).
   Root cause of "geometric drift": three different content columns —
   hero 56rem centred (content left 272@1440 / 512@1920), sections 90rem +80px
   (left 80 / 320), footer 1280 +48px (left 48). No shared spine = "zigzag".
   FIX: ONE canonical container primitive. Hero inner, every .ca-container and
   the footer grid share an identical max-width + fluid padding, so the content
   column is the SAME width and centres on the same axis at every viewport.
   Owner decision 2026-06-01: "Center everything (Apple)" — centred column model.
   Capping at 80rem also fixes the widescreen "lost content" (G4): content no
   longer keeps spreading on >1440 screens; margins grow symmetrically instead.
   Long-form prose (legal/blog/glossary) keeps its own narrower measure inside
   this column — only the OUTER column is unified here.
   ============================================================ */
:root {
  --ca-max: 80rem;                      /* 1280px canonical content column */
  --ca-pad: clamp(20px, 5vw, 64px);     /* fluid gutter: 20px@<=400 → 64px@>=1280 */
  --section-spacing: clamp(64px, 10vh, 128px);
}
.ca-container {
  max-width: var(--ca-max) !important;
  margin-inline: auto !important;
  padding-inline: var(--ca-pad) !important;
  width: 100% !important;
  min-width: 0 !important;
}
@media (max-width: 767px) {
  /* defensive: any flex row of pills/badges must wrap, never force width */
  .ca-hero-content ul, .ca-hero-meta, .ca-hero-btns { flex-wrap: wrap !important; }
}

/* ============================================================
   INVISIBLE-CTA ROOT FIX — 2026-06-01. A broad section/link rule sets
   -webkit-text-fill-color:var(--white) on <a> in dark sections; on a link-button with a
   WHITE or TEAL fill that paints the label white-on-white / white-on-teal =
   invisible (confirmed on faq.html "Book a 15-minute call": computed fill var(--white)
   on bg var(--white)). Brand rule: light/teal button fill ALWAYS takes dark obsidian
   text. Force BOTH color and -webkit-text-fill-color dark on any link-button
   with a solid white or teal fill, or that explicitly asked for text-black.
   Excludes translucent bg-white/NN fields (those are dark glass + white text). */
a[class*="bg-white"]:not([class*="bg-white/"]),
a[class*="bg-teal"],
a.text-black,
a[class*="bg-white"]:not([class*="bg-white/"]) *,
a[class*="bg-teal"] * {
  color: var(--bg) !important;
  -webkit-text-fill-color: var(--bg) !important;
}

/* a11y (2026-06-01, axe serious — the ONLY remaining WCAG2.1AA violation site-wide):
   glossary landing card descriptions used text-ca-line/60 = ca-line(var(--line-deep)) @60%
   over a white card = rgb(120,137,155) = 3.59:1 on 14px text → FAILS AA 4.5:1.
   (A prior session mis-logged this as a "10.83 anomaly"; measured here at 3.59.)
   Fix: solid ca-line token (~9:1) — readable dark-navy secondary, token-based. */
.glossary-card [class*="text-ca-line/60"] {
  color: var(--color-ca-line, var(--line-deep)) !important;
  -webkit-text-fill-color: var(--color-ca-line, var(--line-deep)) !important;
}

/* ============================================================
   ULTRA-PREMIUM MICRO-DETAILS — 2026-06-02 (luxury-interface polish, all
   token-based per Sovereign mandate).
   ============================================================ */
/* 1. OPTICAL KERNING — larger type needs exponentially tighter tracking. Fluid
   scale, !important to beat ad-hoc Tailwind tracking-* utilities. */
.cz-hero-title { letter-spacing: -0.04em !important; }                          /* ~96px homepage hero — harmonised toward the -0.03em hero scale (was -0.05em; Gemini "disjointed" tracking) */
h1.ca-hero-title, .ca-hero-title.is-split, .sec-hero h1, h1.page-title,
h1, .sv-h1 { letter-spacing: -0.03em !important; }                              /* ~64px hero/page h1 */
h2.ca-section-title, h2, .ca-section-title, .sv-h2 { letter-spacing: -0.025em !important; }
h3, .sv-h3 { letter-spacing: -0.03em !important; }

/* 2. SPECULAR CAP — 1px top-edge highlight so cards/buttons read as physical
   glossy objects. Pseudo follows the radius; never intercepts clicks. Excludes
   cards that already own a ::before (premium conic stroke) + glossary cards. */
.sv-card, .ca-card:not([data-premium-stroke]):not(.glossary-card) { position: relative; }
.sv-card::before,
.ca-card:not([data-premium-stroke]):not(.glossary-card)::before {
  content: ""; position: absolute; inset: 0;
  border-top: 1px solid var(--white-15);
  border-radius: inherit; pointer-events: none; z-index: 1;
}

/* 3. SATURATED BACKDROP BLUR — vibrant cinematic glass, not muddy. */
#ca-nav, #ca-nav.sv-nav, .pricing-sticky, .ca-hero-visual, .ca-newsletter,
#mob-menu, .ca-dropdown, .ca-modal, .ca-glass, [class*="backdrop-blur"] {
  backdrop-filter: blur(24px) saturate(180%) !important;
  -webkit-backdrop-filter: blur(24px) saturate(180%) !important;
}

/* 4. KINETIC OVERSHOOT — spring bounce on interactive transforms (alive feel).
   transform uses --ease-spring; colour stays quick/non-bouncy. */
.sv-btn, .sv-btn, .cz-btn, .sv-btn--primary, .sv-btn--secondary, .sv-btn--ghost {
  transition: transform .4s var(--ease-spring),
              box-shadow .4s var(--ease-canonical),
              background-color .25s ease, color .25s ease, border-color .25s ease !important;
}

/* ============================================================
   OPTICAL TYPOGRAPHY — 2026-06-02 (top-1% line balancing; Sovereign Charter R5
   lists text-wrap:balance as a default). Fixes the zigzag/triangle/ragged
   defects on centred text:
   R1 balance headings -> equal line lengths, stable rhythm (no widow zigzag).
   R2 pretty paragraphs -> no single-word widows/orphans.
   R3 golden measure -> character-based (55ch hero/section intros, 45ch card
      bodies) instead of jittery px -> clean rectangle, not a triangle.
   R4 unified spine -> centred card title + body share one measure + axis.
   ============================================================ */
h1, h2, h3, h4,
.cz-hero-title, [class*="hero-title"], .ca-section-title,
.sv-h1, .sv-h2, .sv-h3 {
  text-wrap: balance;
}
.cz-hero-desc, .ca-hero-desc, .ca-section-desc,
.sv-card__body, .sv-lead, p.cz-hero-desc,
.ca-card p, .glossary-card p, section p {
  text-wrap: pretty;
}
#hero p.cz-hero-desc, .cz-hero-desc, .ca-hero-desc, .ca-section-desc, .sv-lead {
  max-width: 55ch !important;
  margin-inline: auto !important;
}
.ca-card p, .sv-card__body { max-width: 45ch; }
/* CARD BUTTON ALIGNMENT (2026-06-02 forensic): Apple-centring centred card
   title/desc, but card CTAs/arrows kept align-self:flex-end (bottom-RIGHT) ->
   centred text + corner arrow = "off-centre, odd". Centre card-level buttons /
   icon-arrows onto the card's centre axis. Excludes form/table cards. */
.ca-card:not(:has(form)):not(:has(table)) > :is(.ca-card-icon-btn, .sv-btn),
.ca-card-content > :is(.ca-card-icon-btn, .sv-btn),
.ca-card-content > .ca-card-icon-btn {
  align-self: center !important;   /* cross-axis centre in a flex-column card; doesn't spread button ROWS */
}
/* CTA BUTTON ROWS (2026-06-02 forensic #2): a flex row/col holding .sv-btn CTAs
   with NO explicit justify defaults to flex-start (LEFT) — clashes with centred
   card/CTA text (e.g. tool "Need the full picture?" dark card: centred heading +
   left buttons). Centre button groups that don't already set their own justify.
   Respects rows that intentionally declare justify-between/start/end. */
[class*="flex"]:has(> a.sv-btn):not([class*="justify"]):not(form),
[class*="flex"]:has(> button.sv-btn):not([class*="justify"]):not(form),
[class*="flex"]:has(> a.sv-btn):not([class*="justify"]):not(form) {
  justify-content: center !important;
  align-items: center;
}
.ca-card.text-center :is(h2, h3, h4, p), .ca-card[class*="text-center"] :is(h2, h3, h4, p),
section .ca-card:is(.text-center, [class*="items-center"]) :is(h2, h3, h4, p) {
  max-width: 45ch;
  margin-inline: auto;
}
/* CARD BASELINE (2026-06-02 forensic #3 — "floating button"): in equal-height
   grid rows, block cards let the trailing CTA float mid-card (measured gapBottom
   0-83px across pricing tiers) so CTAs in a row don't share a baseline. Flip ONLY
   cards whose LAST child is a CTA / CTA-row to flex-column (leaves cards with
   internal grids or non-CTA tails untouched), then push that trailing CTA to the
   bottom via margin-top:auto -> all CTAs in a grid row land on ONE baseline.
   Excludes form/table/glossary cards. Cross-axis centring already handled above. */
/* Directive 1 (2026-06-02): MATHEMATICAL baselines. Any non-form/table/glossary
   card that contains a CTA becomes flex-column, and its LAST in-flow child (the
   CTA or the block wrapping it; absolute overlays excluded) is pinned to the
   bottom via margin-top:auto — so every CTA block in a grid row lands on ONE
   baseline regardless of body text length. Form/widget panels keep natural flow. */
.ca-card:not(:has(form)):not(:has(table)):not(.glossary-card):has(:is(a.sv-btn, button.sv-btn, .ca-card-icon-btn)),
.sv-card:not(:has(form)):not(:has(table)):has(:is(a.sv-btn, button.sv-btn, .ca-card-icon-btn)) {
  display: flex !important;
  flex-direction: column !important;
}
.ca-card:not(:has(form)):not(:has(table)):not(.glossary-card):has(:is(a.sv-btn, button.sv-btn, .ca-card-icon-btn)) > *:last-child:not([class*="absolute"]),
.sv-card:not(:has(form)):not(:has(table)):has(:is(a.sv-btn, button.sv-btn, .ca-card-icon-btn)) > *:last-child:not([class*="absolute"]) {
  margin-top: auto !important;
}

/* ============================================================
   PRICING STICKY BAR — condense-on-scroll (2026-06-01, owner UX). The product
   switcher + monthly/annual toggle stack to ~185px when stuck (nav 72 + 185 =
   ~28-37% of viewport = "restricts half the view"). When stuck (.condensed,
   toggled by a scroll listener), collapse the two stacked rows into ONE slim
   row (tabs + toggle side-by-side) ~56px tall — both controls stay reachable,
   ~125px of viewport reclaimed. Smooth eased transition. ============================================================ */
/* GPU hygiene: padding is layout-triggering and cannot be hardware-accelerated.
   The condense is a one-shot scroll-threshold toggle (not a per-frame animation),
   so we drop the transition rather than jank a padding tween. */
.pricing-sticky.condensed { padding-top: var(--space-2) !important; padding-bottom: var(--space-2) !important; }
/* block + inline-flex children (NOT container flex — a stubborn flex-direction:
   column kept winning) so tabs + toggle flow side-by-side on one row. */
.pricing-sticky.condensed > .ca-container {
  display: block !important;
  text-align: center !important;
  white-space: nowrap;
}
.pricing-sticky.condensed .ptabs {
  display: inline-flex !important;
  vertical-align: middle !important;
  margin: 0 !important;
  width: auto !important;
}
.pricing-sticky.condensed .billing-toggle-container {
  display: inline-flex !important;
  align-items: center !important;
  vertical-align: middle !important;
  margin: 0 0 0 clamp(16px, 3vw, 40px) !important;
}
/* slightly tighten the controls in condensed mode so the row stays ~56px */
.pricing-sticky.condensed .ptab { padding-top: var(--space-1) !important; padding-bottom: var(--space-1) !important; }
@media (max-width: 640px) {
  /* on phones, allow wrap so tabs + toggle stack if the row is too tight */
  .pricing-sticky.condensed > .ca-container { gap: var(--space-2) !important; flex-wrap: wrap !important; }
  .pricing-sticky.condensed .ptabs { flex-wrap: nowrap !important; overflow-x: auto; }
}

/* ============================================================
   TYPOGRAPHY UNIFICATION — 2026-06-01 (Gemini P0 "font schism"). Verified: body
   + all h2 + all p already compute Inter site-wide; only the sub-page <h1> held
   out as Plus Jakarta Sans (the homepage hero is already Inter). Inter is the
   de-facto canonical, so force ALL headings to it — one typographic family
   across all 22 pages, no "font jump" on navigation. (Body stays Inter too.)
   ============================================================ */
h1, h2, h3, h4, h5, h6,
.cz-hero-title, [class*="hero-title"], .ca-section-title, [class*="section-title"] {
  font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif !important;
}

/* ============================================================
   PREMIUM INTERACTIONS — 2026-06-01 (Gemini P1). Replace the default
   `transition: all` on buttons/cards with specific, eased curves
   (var(--ease-canonical) — the "ease-out-expo" feel premium sites use) and
   add card micro-interactions: subtle lift + depth shadow + teal border-glow on
   hover. Tokenised glow (color-mix on --teal) so it stays themeable.
   ============================================================ */
.sv-btn, .sv-btn {
  transition: transform .4s var(--ease-spring),
              box-shadow .45s var(--ease-canonical),
              background-color .3s ease, color .3s ease, border-color .3s ease !important;
}
.ca-card:not(:has(form)):not(:has(table)):not(:has(input)) {
  transition: transform .5s var(--ease-canonical),
              box-shadow .5s var(--ease-canonical),
              border-color .5s var(--ease-canonical) !important;
}
.ca-card:not(:has(form)):not(:has(table)):not(:has(input)):not([data-premium-stroke]):hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 50px -16px rgba(0, 0, 0, 0.45);
  border-color: color-mix(in srgb, var(--teal) 38%, transparent) !important;
}
@media (prefers-reduced-motion: reduce) {
  .ca-card:hover { transform: none; }
}

/* ============================================================
   TAP TARGETS >=44px — 2026-06-01 (WCAG 2.5.5). Icon-only links/buttons (footer
   socials, share icons, close ×, etc.) measured 6-24px on mobile — too small to
   tap reliably. Give them a 44px min hit area via inline-flex centring WITHOUT
   enlarging the icon glyph. Scoped to touch widths; excludes nav dropdown
   chevrons (inline within a larger link) and elements already sized. */
@media (max-width: 1024px) {
  a.ca-touch-target, button.ca-touch-target,
  .ca-footer .foot-social a, .ca-footer .footer-bottom-link,
  a:has(> svg:only-child):not(.nav-dropdown-trigger *):not(.cz-btn):not(.sv-btn),
  button:has(> svg:only-child):not(.nav-dropdown-trigger *) {
    min-width: 44px !important;
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
  }
  /* text-bearing CTAs/links that measured short on mobile: nav trial/sign-in
     buttons + cookie-banner links — give a 44px tap height. */
  header nav a[href*="signup"], header nav a[href*="login"], header nav .nav-cta,
  .cookie-banner a, #ca-cookie a, [class*="cookie"] a {
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center !important;
  }
}

/* ============================================================
   ZIGZAG FIX — 2026-06-01 (owner: centralised "Apple" alignment site-wide).
   Audit found 27 pages with mixed heading alignment — most section titles
   centred but stray ones left-aligned (.ca-section-title, large text-5xl/6xl
   product titles, .tool-step-* process steps) = visible zigzag. Centre ALL
   section-level headings + eyebrows + process steps so every section shares one
   centred spine. Scoped AWAY from long-form prose and cards, where left is
   correct: legal docs (.legal-doc/.prose), blog articles (article), and card
   internals (.ca-card/.glossary-card/[data-pcar]) keep their own alignment.
   text-4xl+ is section-title territory (cards use text-xl/2xl/3xl), so centring
   those headings is safe. ============================================================ */
.ca-section-title,
.tool-step-heading, .tool-step-eyebrow, .tool-step-body,
section h2[class*="text-xl"], section h2[class*="text-2xl"], section h2[class*="text-3xl"],
section h2[class*="text-4xl"], section h2[class*="text-5xl"],
section h2[class*="text-6xl"], section h2[class*="text-7xl"],
section h2[class*="text-8xl"] {
  text-align: center !important;
}
/* APPLE-CENTRED SECTION HEADER (2026-06-01 v2): centring the h2 alone left the
   eyebrow ABOVE and the intro paragraph BELOW still left-aligned = still zigzag.
   Centre the whole HEADER WRAPPER (the block that directly holds the section
   title) so its eyebrow + title + subhead + intro paragraph all centre as one
   unit. :has targets only wrappers whose direct child is a section title (cards
   use h3, so card grids are unaffected). */
section :is(div, header, hgroup):has(> .ca-section-title),
section :is(div, header, hgroup):has(> h2[class*="text-2xl"]),
section :is(div, header, hgroup):has(> h2[class*="text-3xl"]),
section :is(div, header, hgroup):has(> h2[class*="text-4xl"]),
section :is(div, header, hgroup):has(> h2[class*="text-5xl"]),
section :is(div, header, hgroup):has(> h2[class*="text-6xl"]),
section :is(div, header, hgroup):has(> h2[class*="text-7xl"]),
section :is(div, header, hgroup):has(> h2[class*="text-8xl"]) {
  text-align: center !important;
}
/* constrained intro/subhead paragraphs: text-align centres the TEXT but a
   max-w box stays left-anchored — auto-centre the box too. Scoped to header
   wrappers + the canonical section-desc class; never inside cards/articles. */
.ca-section-desc,
section :is(div, header, hgroup):has(> h2[class*="text-4xl"]) > :is(p, span, .ca-eyebrow),
section :is(div, header, hgroup):has(> h2[class*="text-5xl"]) > :is(p, span, .ca-eyebrow),
section :is(div, header, hgroup):has(> h2[class*="text-6xl"]) > :is(p, span, .ca-eyebrow),
section :is(div, header, hgroup):has(> h2[class*="text-7xl"]) > :is(p, span, .ca-eyebrow),
section :is(div, header, hgroup):has(> h2[class*="text-8xl"]) > :is(p, span, .ca-eyebrow),
section :is(div, header, hgroup):has(> .ca-section-title) > :is(p, span, .ca-eyebrow) {
  margin-inline: auto !important;
}
/* eyebrow badges: a section eyebrow is always a header label — centre it as a
   block sized to its content, regardless of its wrapper's alignment. (Excludes
   eyebrows inside cards/steps where local alignment is intentional.) */
section .ca-eyebrow:not(.ca-card *):not(.tool-step *):not([data-pcar] *) {
  display: block !important;
  width: -moz-fit-content !important; width: fit-content !important;
  margin-inline: auto !important;
}
/* "title + side-link" header rows (e.g. Related products | All products ->):
   a flex md:justify-between row keeps the title left. When the row holds a
   section title, centre it so it matches the Apple-centred spine. */
section div[class*="justify-between"]:has(> h2[class*="text-3xl"]),
section div[class*="justify-between"]:has(> h2[class*="text-4xl"]),
section div[class*="justify-between"]:has(> h2[class*="text-5xl"]),
section div[class*="justify-between"]:has(> h2[class*="text-6xl"]) {
  justify-content: center !important;
  text-align: center !important;
}
/* keep long-form + article headings at their natural alignment */
.legal-doc h2, .prose h2, article h2 {
  text-align: left !important;
}
/* CTA banners + feature cards centre their content (Apple) so a left-aligned
   card never sits among centred sections (e.g. the "Automate your credit
   control?" banner). EXCEPT cards that hold a form, table, inputs, or a long
   list — those stay left for function/readability — and glossary/blog cards. */
section .ca-card:not(.glossary-card):not(:has(form)):not(:has(table)):not(:has(input)):not(:has(textarea)):not(:has(li + li + li + li)) {
  text-align: center !important;
}
section .ca-card:has(form), section .ca-card:has(table),
section .ca-card:has(input), section .ca-card:has(textarea),
section .ca-card:has(li + li + li + li), .glossary-card {
  text-align: left !important;
}

/* ============================================================
   COMPREHENSIVE APPLE-CENTRED DEFAULT (2026-06-01 v4) — the authoritative rule.
   Piecemeal per-class centring left too many stray left elements (intro lines,
   sub-headings, banners). Instead: centre ALL text content inside marketing
   <section>s by default, then re-LEFT only what must stay left for function or
   readability. Legal/policy pages (body.f8-legal) opt out entirely (prose left).
   ============================================================ */
body:not(.f8-legal) main section :is(h1,h2,h3,h4,h5,h6,p,span,a,li,div,dt,dd,blockquote,figcaption,.ca-eyebrow,[class*="eyebrow"]) {
  text-align: center !important;
}
/* RE-LEFT (function / readability): forms + fields, data tables, code, long-form
   prose (blog/legal/article), carousel captions, and any card that holds a form,
   table, or input. These keep their natural left alignment. */
body:not(.f8-legal) main :is(form, form *, table, table *, thead, tbody, tr, th, td,
  input, textarea, select, label, code, pre, kbd,
  .ca-code-block, .ca-code-block *, [class*="code-block"], [class*="code-block"] *, [class*="font-mono"],
  .prose, .prose *, article, article *, .legal-doc, .legal-doc *,
  .blog-stripe-prose, .blog-stripe-prose *, .article-body, .article-body *,
  [data-pcar] .pcar__caption, [data-pcar] .pcar__caption *,
  .ca-table, .ca-table *),
body:not(.f8-legal) main section .ca-card:has(form) :is(h1,h2,h3,h4,h5,h6,p,span,a,li,label,div),
body:not(.f8-legal) main section .ca-card:has(table) :is(h1,h2,h3,h4,h5,h6,p,span,a,li,div),
body:not(.f8-legal) main section .ca-card:has(input) :is(h1,h2,h3,h4,h5,h6,p,span,a,li,label,div) {
  text-align: left !important;
}
/* RE-LEFT GRID FEATURE-CARDS (2026-06-02 — root cause of the "zigzag"): the
   comprehensive centred default above also centred MULTI-LINE card body copy
   (measured 5-10 lines) inside feature grids, producing ragged left+right edges
   — AND overrode authors' own `text-left` (e.g. the #sectors grid literally
   carries class="... text-left"). The genuine Stripe/Apple pattern is a CENTRED
   section header (eyebrow + h2 + short lead) above a row of LEFT-aligned card
   blocks. Re-left every .ca-card / .sv-card that is a direct grid item (icon,
   heading, body, list all left). Standalone CTA banner cards are NOT direct grid
   items, so they keep the centred default (e.g. the tool "Need the full picture?"
   card stays centred). */
body:not(.f8-legal) main [class*="grid"] > :is(.ca-card, .sv-card),
body:not(.f8-legal) main [class*="grid"] > :is(.ca-card, .sv-card) :is(h2,h3,h4,h5,h6,p,span,a,li,div,dt,dd,blockquote,figcaption),
body:not(.f8-legal) main [class*="grid"][class*="text-left"] :is(h1,h2,h3,h4,h5,h6,p,span,a,li,div,dt,dd) {
  text-align: left !important;
}
/* In a left-aligned grid card, the trailing CTA / icon-arrow should sit at the
   left edge (not floated to centre) so it aligns under the left-aligned copy. */
body:not(.f8-legal) main [class*="grid"] > :is(.ca-card, .sv-card) > :is(.ca-card-icon-btn, .sv-btn, .sv-btn),
body:not(.f8-legal) main [class*="grid"] > :is(.ca-card, .sv-card) .ca-card-content > :is(.ca-card-icon-btn, .sv-btn, .sv-btn) {
  align-self: flex-start !important;
}
/* RE-LEFT EXPLICIT OPT-IN (2026-06-03): honour an author's explicit `text-left`
   on any list/container. The comprehensive centred default above also centred the
   Core "capabilities" <ul> — invisible until a bullet wrapped to 2 lines, which
   then showed a ragged first line (extra gap after the ✓) + a centred second
   line ("MEES assessment"). Specificity (0,3,4) + !important beats the centred
   default (0,2,3). Any element the author marks text-left (and its text
   descendants) stays left, the way the utility class is meant to behave. */
body:not(.f8-legal) main section .text-left,
body:not(.f8-legal) main section .text-left :is(h1,h2,h3,h4,h5,h6,p,span,a,li,div,dt,dd,blockquote,figcaption) {
  text-align: left !important;
}
/* LEGAL/POLICY PAGES stay left + consistent (Apple keeps legal left). The
   marketing-centering above must never touch them. Covers all 5 policy pages
   via the f8-legal body class. */
body.f8-legal section h2, body.f8-legal .ca-section-title,
body.f8-legal section h2[class*="text-xl"], body.f8-legal section h2[class*="text-2xl"],
body.f8-legal section h2[class*="text-3xl"], body.f8-legal section h2[class*="text-4xl"] {
  text-align: left !important;
}
/* but the legal page HERO (h1 + its lead) may stay centred — that's the only
   centred element on a legal page and matches the rest of the site's heroes. */
body.f8-legal .ca-hero h1, body.f8-legal .ca-hero h2 { text-align: center !important; }
/* centre the process-step columns as a whole (icon + heading + body) so a
   "how it works" row reads as a centred trio, not left-aligned blocks */
.tool-howitworks .tool-step, .tool-step { text-align: center !important; }

/* ============================================================
   BUTTON SCALE — 2026-06-01 (owner-approved). Premium sites use ONE fixed,
   role-based size scale; same action = same size. Audit found the same primary
   CTA at 34/38/50/60/62px, ~15 distinct size combos, and a glitched radius
   (3.35e7px). Canonicalise the dominant .sv-btn system to a 2-tier scale.
   nav-global-fix loads after the v2 compiled utilities, so .sv-btn (0,1,0) beats
   the Tailwind !py-6/!px-12 overrides (equal specificity, later wins).
   - md (default): ~48px tall, 14px label, pill.
   - lg (hero + final-CTA + the oversized text-3xl one-offs): ~56px, 16px label.
   ============================================================ */
.sv-btn {
  padding-block: var(--space-4) !important;
  padding-inline: var(--space-8) !important;
  font-size: var(--text-sm) !important;
  line-height: 1 !important;
  border-radius: 999px !important;
  min-height: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: var(--space-2);
}
.ca-hero .sv-btn,
section.ca-cta-final .sv-btn,
.sv-btn[class*="text-lg"],
.sv-btn[class*="text-xl"],
.sv-btn[class*="text-2xl"],
.sv-btn[class*="text-3xl"],
.sv-btn[class*="!px-12"] {
  padding-block: var(--space-5) !important;
  padding-inline: var(--space-10) !important;
  font-size: var(--text-md) !important;
}
/* Raw-Tailwind pill CTAs not using .sv-btn (faq Book-a-call/Browse, newsletter
   Subscribe, etc.) — normalise to the md pill so they don't render at 55/58/64px.
   Scoped to anchors/buttons that are pill + have a solid fill class. */
a[class*="rounded-full"][class*="py-4"]:not(.sv-btn):not([class*="bg-white/"]),
a[class*="rounded-full"][class*="py-5"]:not(.sv-btn):not([class*="bg-white/"]),
button[class*="rounded-full"][class*="py-4"]:not(.sv-btn),
button[class*="rounded-full"][class*="py-5"]:not(.sv-btn) {
  padding-block: var(--space-4) !important; font-size: var(--text-sm) !important; line-height: 1 !important;
  display: inline-flex !important; align-items: center !important; justify-content: center !important;
}
/* legacy .btn.primary (11 uses) + raw oversized Tailwind CTAs (px-20 py-10
   text-3xl) → fold into the same pill md/lg so nothing renders off-scale. */
a.btn.primary, button.btn.primary, .btn.primary {
  padding: 16px 32px !important; font-size: var(--text-sm) !important; line-height: 1 !important;
  border-radius: 999px !important; display: inline-flex !important;
  align-items: center !important; justify-content: center !important;
}
a[class*="px-20"][class*="py-10"], a[class*="px-20"][class*="py-10"][data-cta-pulse] {
  padding: 20px 44px !important; font-size: var(--text-lg) !important; border-radius: 999px !important;
  display: inline-flex !important; align-items: center !important; justify-content: center !important;
}

/* Mobile: hero product-showcase carousel column is a flex item with
   min-width:auto, so it grew to its content min-content (~422px) and overflowed
   390px. Clamp the visual column + showcase frame to the viewport. */
@media (max-width: 767px) {
  .ca-hero-visual-col, .ca-hero-visual, .ca-showcase-frame,
  .ca-browser-chrome, .ca-viewport, .pcar__slide {
    min-width: 0 !important;
    max-width: 100% !important;
  }
}

/* cookies.html legal TOC: .legal-shell--wide kept a 2-col grid (~580px track)
   below tablet, overflowing mobile. Force single column under 1024px. */
@media (max-width: 1023px) {
  .legal-shell, .legal-shell--wide { grid-template-columns: 1fr !important; }
}

/* Mobile pricing switcher: the 5-product segmented control was nowrap +
   overflow-x:auto, so it clipped/half-scrolled on 390px (owner-reported). Wrap
   the tabs to two centred rows so all five products are visible at a glance. */
@media (max-width: 767px) {
  .ptabs {
    flex-wrap: wrap !important;
    overflow-x: visible !important;
    justify-content: center !important;
    border-radius: 20px !important;
  }
  .ptabs .ptab { flex: 0 1 auto; }
}

/* cookies.html (proper root-cause fix, supersedes the 1fr attempt above):
   the legal-shell grid track blew out to ~580px because `1fr` = minmax(auto,1fr)
   and the grid item (.legal-doc, min-width:auto) contains a 578px data table,
   so the track grew to the table's min-content. Fix: minmax(0,1fr) + min-width:0
   lets the track shrink to the container; the table gets its own scroll area. */
@media (max-width: 1023px) {
  .legal-shell, .legal-shell--wide { grid-template-columns: minmax(0, 1fr) !important; }
  .legal-shell > *, .legal-doc { min-width: 0 !important; }
  .cookies-table-wrapper { overflow-x: auto !important; max-width: 100% !important; -webkit-overflow-scrolling: touch; }
}

/* Pricing switcher mobile (PROPER fix, supersedes the flex-wrap-only attempt):
   .ptabs is display:inline-flex (desktop segmented pill) so on mobile it
   shrink-wrapped to ~118px and stacked the 5 tabs vertically, with the billing
   toggle flowing inline beside it. Make it a full-width block flex on mobile so
   the 5 short tabs lay out on one centred row, and force the toggle onto its own
   centred row below. */
@media (max-width: 767px) {
  .ptabs {
    display: flex !important;
    width: 100% !important;
    flex-wrap: wrap !important;
    justify-content: center !important;
  }
  .billing-toggle-container {
    display: flex !important;
    width: 100% !important;
    justify-content: center !important;
    margin-top: var(--space-4) !important;
  }
}

/* Pricing switcher mobile — TRUE root cause: the `div:has(> .ptabs)` rule above
   forces the switcher's .ca-container to display:flex ROW. That container holds
   BOTH .ptabs and .billing-toggle-container, so on mobile they became side-by-side
   flex items and .ptabs got squeezed to ~118px (tabs stacked vertically). Stack
   them as a column on mobile so .ptabs takes the full row (tabs horizontal) and
   the toggle sits below. */
@media (max-width: 767px) {
  div:has(> .ptabs) { flex-direction: column !important; align-items: center !important; }
}

/* Homepage "Solve/Prove/Profit" methodology section (#how): the left column is
   `sticky top-40 h-fit` for desktop 2-col sticky-storytelling. It lacked an lg:
   prefix, so it stayed sticky on mobile (1-col) and the pinned cards overlapped
   the content scrolling beneath ("Profit." over "Report everywhere."). Disable
   sticky below desktop so the cards scroll normally. (Legal pages already use
   lg:sticky and are unaffected.) */
@media (max-width: 1023px) {
  .sticky.top-40 { position: static !important; }
}

/* Homepage stats ("What we cover"): values are text-5xl (~48px); on the 2-col
   mobile grid the widest ("Base+8%") clipped its "%". Scope a clamp to the
   counter values only (not all text-5xl) so they fit the mobile column. */
@media (max-width: 767px) {
  div:has(> [data-counter-to]) { font-size: clamp(1.7rem, 8vw, 2.5rem) !important; line-height: 1.05 !important; }
}

/* ============================================================
   MOBILE VERTICAL RHYTHM (Chrome audit 2026-05-30 — Claude)
   Sections use desktop-scale vertical padding (py-60=240px, py-40=160px,
   py-32=128px) with no responsive step-down, so mobile showed huge empty
   bands between sections (owner + agents). Trim to a premium mobile rhythm.
   Responsive-prefixed classes (lg:py-60 etc.) are separate selectors and are
   untouched. ============================================================ */
@media (max-width: 767px) {
  .py-60 { padding-top: 4.5rem !important; padding-bottom: 4.5rem !important; }
  .py-40 { padding-top: 3.5rem !important; padding-bottom: 3.5rem !important; }
  .py-32 { padding-top: 3rem !important; padding-bottom: 3rem !important; }
  .py-24 { padding-top: 2.5rem !important; padding-bottom: 2.5rem !important; }
  /* announce bar wrapped mid-phrase on mobile; put the message on its own
     centred line with the CTA + dismiss below, and drop the leading dot. */
  #announce-bar .wrap, .announce-bar .wrap { flex-wrap: wrap !important; gap: var(--space-1) 10px !important; padding: 8px 12px !important; }
  #announce-bar .ab-text, .announce-bar .ab-text { flex-basis: 100% !important; text-align: center !important; font-size: var(--text-xs) !important; line-height: 1.3 !important; }
  #announce-bar .ab-dot, .announce-bar .ab-dot { display: none !important; }
}

/* Mobile heroes: .ca-hero forces min-height:100vh + padding-bottom:10rem, so on
   mobile the vertically-centred content left big dead bands above/below. Drop the
   forced full height and heavy padding on mobile so the hero sits tight under the
   nav. (Desktop full-height heroes unchanged.) */
@media (max-width: 767px) {
  .ca-hero { min-height: auto !important; padding-top: 4.5rem !important; padding-bottom: 3.5rem !important; }
}

/* Homepage hero carousel caption has a fixed h-6 (24px) height (to avoid
   layout shift between slides). On mobile the caption wraps to 3 lines and
   overflowed its fixed box, bleeding onto the "Illustrative · sample data"
   watermark below. Let it grow on mobile so the watermark sits clear. */
@media (max-width: 767px) {
  .pcar__caption { height: auto !important; min-height: 1.5rem; margin-bottom: var(--space-2) !important; }
}

/* Back-to-top FAB on mobile: it sits bottom-left (chatbot owns bottom-right) and
   on small screens floated over content (table rows, form labels, FAQ) — agents
   flagged it across pages. On mobile the chatbot already provides a FAB and
   scrolling is trivial, so hide the back-to-top under 768px to declutter and
   stop the content overlap. (Desktop keeps it.) */
@media (max-width: 767px) {
  #back-to-top { display: none !important; }
}

/* ============================================================
   FINAL CTA TEXT-CONTRAST OVERRIDE (2026-05-30 — Claude, _ghostscan probe-confirmed).
   `.!text-white` on teal/lime/purple-filled `.sv-btn` CTAs ("Get started") was winning
   the cascade over attribute-selector fixes → white-on-teal ≈2.1:1 (AA fail). Target the
   EXACT class combination (0,3,0 specificity) + set -webkit-text-fill-color, appended last
   so it wins decisively. Dark text on teal/lime/light-purple = legible (≈5–9:1).
   ============================================================ */
.sv-btn.\!bg-\[\var(--accent)\].\!text-white, .sv-btn.bg-\[\var(--accent)\].text-white,
.sv-btn.\!bg-\[\var(--lime)\].\!text-white, .sv-btn.bg-\[\var(--lime)\].text-white,
.sv-btn.\!bg-\[\var(--mark)\].\!text-white, .sv-btn.bg-\[\var(--mark)\].text-white,
.sv-btn.\!bg-\[var\(--teal\)\].\!text-white, .sv-btn.\!bg-\[var\(--lime\)\].\!text-white,
.sv-btn.bg-teal-500.text-white, .sv-btn.\!bg-teal-500.\!text-white {
  color: var(--bg) !important;
  -webkit-text-fill-color: var(--bg) !important;
}

/* ════════════════════════════════════════════════════════════════════
   PRINCIPAL-AUDIT POLISH (2026-06-02) — the final 1% (Stripe/Apple grade).
   Four "stealth" upgrades, all token-driven + reduced-motion-safe.
   ════════════════════════════════════════════════════════════════════ */

/* ── 1. RHYTHMIC ASYMMETRY (the "breathing" gap) ──
   Symmetric section padding reads template-y. Premium sites anchor a section
   by giving it MORE space above the heading than below the content (~1.7:1),
   so each section reads as a distinct "visual chapter". Driven by clamp tokens
   (no hardcoded px). Applied to the same marketing-section selectors that
   already carry symmetric padding above; heroes keep their own rhythm. */
:root {
  --sec-pt: 160px;   /* Directive 4: strict 2:1 rhythmic scale (160 top / 80 bottom) */
  --sec-pb: 80px;
}
/* Target the real section set (direct children of <main>, same set sv-reveal
   uses) so the rhythm actually engages regardless of the per-section padding
   class. Skip heroes (own rhythm), the marquee band (full-bleed), and announce.
   SUM (pt+pb ~= 264px) is kept close to the prior symmetric 240px so total page
   height barely moves — only the INTRA-section balance shifts (heading sits
   lower, content ends tighter = the "anchored chapter" effect). */
body:not(.f8-legal) main > section:not(.ca-hero):not(.sec-hero):not(.hero):not([data-hero-scale]):not(.ca-marquee-band):not(#announce-bar):not(.sticky) {
  padding-top: var(--sec-pt) !important;
  padding-bottom: var(--sec-pb) !important;
}
/* Sticky control bars (blog search/filter, etc.) are compact toolbars, NOT content
   sections — the 160/80 rhythm made the blog sticky search bar 266px tall, so when
   stuck it blurred/covered ~half the viewport. Excluded above; keep their own
   compact py-* padding. */
@media (max-width: 768px) {
  :root { --sec-pt: 88px; --sec-pb: 44px; }  /* same strict 2:1 ratio, phone-scaled */
}

/* ── 2. KINETIC SEQUENCING (staggered grid entrances) ──
   sv-reveal.js fades whole sections; premium grids should have their cards
   ASSEMBLE with a short stagger. Pure CSS keyed off the .sv-reveal/.sv-revealed
   classes sv-reveal.js already toggles + the html.js-sv-reveal flag it sets only
   when motion is allowed (it returns early under prefers-reduced-motion, so the
   hidden state below never engages for those users — content stays visible).
   20px Y-slide + the canonical cubic-bezier(0.16,1,0.3,1) reveal. */
/* SAFE staggered entrance (2026-06-02 — Directive 5 rebuilt): use a one-shot
   @keyframes on .sv-revealed with animation-delay per card. CRITICAL: there is NO
   persistent opacity:0 base — cards default VISIBLE, so if reveal timing ever lags
   or JS is absent, NOTHING is stuck hidden (the previous transition+opacity:0
   approach risked invisible cards; it was also dead because premium-transformation's
   `transition:all!important` reset the delay). animation `both` holds the from-state
   only during the brief delay window after the card is revealed in-view. Uses
   animation-delay (what the audit scans for). */
@keyframes svCardIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  /* Animation assigned via LONGHAND (never the `animation:` shorthand) so it can
     NOT reset animation-delay to 0. Only animation-NAME is gated on .sv-revealed
     (entrance plays on scroll-in); the per-card DELAY is set UNCONDITIONALLY below
     so it is present + inspectable in devtools even before reveal (static audits
     read it without scrolling). 70ms step = Apple-waterfall cascade. */
  html.js-sv-reveal section.sv-revealed [class*="grid"] > :is(.ca-card, .sv-card, [class*="card"]) {
    animation-name: svCardIn;
    animation-duration: .6s;
    animation-timing-function: var(--ease-out);
    animation-fill-mode: both;
  }
  html.js-sv-reveal section [class*="grid"] > :nth-child(1) { animation-delay: 0ms; }
  html.js-sv-reveal section [class*="grid"] > :nth-child(2) { animation-delay: 70ms; }
  html.js-sv-reveal section [class*="grid"] > :nth-child(3) { animation-delay: 140ms; }
  html.js-sv-reveal section [class*="grid"] > :nth-child(4) { animation-delay: 210ms; }
  html.js-sv-reveal section [class*="grid"] > :nth-child(5) { animation-delay: 280ms; }
  html.js-sv-reveal section [class*="grid"] > :nth-child(6) { animation-delay: 350ms; }
  html.js-sv-reveal section [class*="grid"] > :nth-child(7) { animation-delay: 420ms; }
  html.js-sv-reveal section [class*="grid"] > :nth-child(n+8) { animation-delay: 480ms; }
}

/* ── 3. LASER-CUT TYPOGRAPHY (high-DPI crispness) ──
   On dark backgrounds, Inter light-on-dark can look thick/blurry on Win/Linux.
   optimizeLegibility enables kerning + ligatures; the optical-size axis (opsz)
   tunes Inter's letterforms for large viewports (no-op if the loaded face lacks
   the axis — safe). Paired with the antialiasing already on body. */
body {
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
  font-variation-settings: "opsz" 32;
}

/* ── 4. (OKLCH wide-gamut accent is promoted in crowagent-brand-tokens.css
   via @supports — keeps the hex canonical + only engages on P3 engines.) ── */

/* ============================================================
   AUDIT-FIX 2026-06-02 PM (forensic audit close-out)
   ============================================================ */

/* (1) GEOMETRIC SPINE — footer credibility row.
   .footer-grid + .footer-bottom already centre to the 80px spine via
   max-width:--ca-max + margin:auto, but .footer-credibility had no width
   cap so it (and its divider) spanned the full --ca-pad box (64px edge).
   Constrain it to the same spine so the whole footer aligns at 80px@1440.
   (We do NOT strip .ca-footer's padding: the grid relies on it for the
   mobile side-gutter; capping this row is the regression-free equivalent.) */
.ca-footer .footer-credibility { max-width: var(--ca-max); margin-inline: auto; }

/* (2) Z-INDEX LADDER — resolve nav (var(--z-toast)=1200) vs cookie collision.
   The ladder already reserves --z-cookie:1250 ("above modals and toast").
   Promote the cookie banner to it so it sits one rung above the fixed nav.
   Selector matches the existing #ca-cookie.cookie-banner specificity (1,1,0)
   in sovereign-core (which pins var(--z-toast)); this file loads later -> wins. */
#ca-cookie.cookie-banner, .cookie-banner { z-index: var(--z-cookie) !important; }

/* (3) SOVEREIGN TOKENS — working `ca-teal-d` utilities (= --teal-d = #0AA88C).
   The Tailwind arbitrary `[#0AA88C]` classes were dropped from the compiled
   build (rendered transparent/white = dead). These hand-authored utilities
   restore the exact brand shade AND retire the hardcoded-hex class names.
   color-mix reproduces Tailwind's /opacity output. */
.text-ca-teal-d        { color: var(--teal-d) !important; }
.text-ca-teal-d\/70    { color: color-mix(in srgb, var(--teal-d) 70%, transparent) !important; }
.bg-ca-teal-d          { background-color: var(--teal-d) !important; }
.bg-ca-teal-d\/5       { background-color: color-mix(in srgb, var(--teal-d) 5%,  transparent) !important; }
.bg-ca-teal-d\/10      { background-color: color-mix(in srgb, var(--teal-d) 10%, transparent) !important; }
.bg-ca-teal-d\/20      { background-color: color-mix(in srgb, var(--teal-d) 20%, transparent) !important; }
.border-ca-teal-d\/20  { border-color: color-mix(in srgb, var(--teal-d) 20%, transparent) !important; }

/* ============================================================
   AUDIT-FIX 2026-06-02 PM (batch 1 — secondary-page hex eradication)
   ============================================================ */
/* Lime opacity variants (= --lime = #C2FF57) — Tailwind arbitrary [#C2FF57]/NN
   were not compiled; hand-author so bg-ca-lime/10|20 + border-ca-lime/30 work. */
.bg-ca-lime\/10     { background-color: color-mix(in srgb, var(--lime) 10%, transparent) !important; }
.bg-ca-lime\/20     { background-color: color-mix(in srgb, var(--lime) 20%, transparent) !important; }
.border-ca-lime\/30 { border-color: color-mix(in srgb, var(--lime) 30%, transparent) !important; }

/* macOS browser-chrome window dots (decorative, NON-brand). Canonical hex lives
   in brand-tokens as --dot-close/minimize/maximize; these utilities let the HTML
   drop the inline [#FF5F57]/[#FEBC2E]/[#28C840] hex while keeping the exact look. */
.bg-dot-close    { background-color: var(--dot-close) !important; }
.bg-dot-minimize { background-color: var(--dot-minimize) !important; }
.bg-dot-maximize { background-color: var(--dot-maximize) !important; }

/* ============================================================
   AUDIT-FIX 2026-06-02 PM — `!`-important variants of the ca-teal-d/lime/mark
   utilities. The hex->utility swap turned `!bg-[#hex]` into `!bg-ca-teal-d`
   etc.; without these explicit rules the bg/border/text is dropped — e.g. the
   homepage "Ready when you are" final-CTA 'Start free trial' button lost its
   teal fill and rendered dark-on-dark (invisible). Values match the non-! ones.
   ============================================================ */
.\!bg-ca-teal-d         { background-color: var(--teal-d) !important; }
.\!bg-ca-teal-d\/10     { background-color: color-mix(in srgb, var(--teal-d) 10%, transparent) !important; }
.\!text-ca-teal-d       { color: var(--teal-d) !important; -webkit-text-fill-color: var(--teal-d) !important; }
.\!border-ca-teal-d\/20 { border-color: color-mix(in srgb, var(--teal-d) 20%, transparent) !important; }
.\!bg-ca-lime           { background-color: var(--lime) !important; }
.\!bg-ca-lime\/20       { background-color: color-mix(in srgb, var(--lime) 20%, transparent) !important; }
.\!border-ca-lime\/20   { border-color: color-mix(in srgb, var(--lime) 20%, transparent) !important; }
.\!bg-ca-mark           { background-color: var(--mark) !important; }
.\!bg-ca-mark\/20       { background-color: color-mix(in srgb, var(--mark) 20%, transparent) !important; }
.\!border-ca-mark       { border-color: var(--mark) !important; }
.\!border-ca-mark\/20   { border-color: color-mix(in srgb, var(--mark) 20%, transparent) !important; }

/* ============================================================
   AUDIT-FIX 2026-06-02 PM (batch 4 — typographic rag).
   text-wrap:pretty on body copy inside cards eliminates widows/orphans; balance
   on card headings evens multi-line ragged edges. Applied at the component level
   so dynamically-built cards inherit it even when their Tailwind classes don't
   carry the global h1/h2/h3 balance rule. ============================================================ */
.ca-card p, .ca-card li, .ca-method-item p, .pricing-panel p, .pcar__caption { text-wrap: pretty; }
.ca-card h2, .ca-card h3, .ca-card h4, .ca-method-item h3 { text-wrap: balance; }

/* ============================================================
   AUDIT-FIX 2026-06-02 PM (batch 1 round-2 — remaining hex on
   roadmap/resources/index/products/methodology). Tokens already exist in
   brand-tokens; these utilities let the HTML drop the inline [#hex] classes.
   High-specificity (#main-content / body scope) + -webkit-text-fill so the
   accent colour beats the universal section text rules. ============================================================ */
.text-ca-gold, body .text-ca-gold       { color: var(--gold) !important; -webkit-text-fill-color: var(--gold) !important; }
.bg-ca-gold, body .bg-ca-gold           { background-color: var(--gold) !important; }
.border-ca-gold, body .border-ca-gold   { border-color: var(--gold) !important; }
.text-ca-teal-aa, body .text-ca-teal-aa { color: var(--teal-aa) !important; -webkit-text-fill-color: var(--teal-aa) !important; }
.text-code-yellow, body .text-code-yellow { color: var(--code-yellow) !important; -webkit-text-fill-color: var(--code-yellow) !important; }
.text-code-pink, body .text-code-pink     { color: var(--code-pink) !important; -webkit-text-fill-color: var(--code-pink) !important; }
.text-code-purple, body .text-code-purple { color: var(--code-purple) !important; -webkit-text-fill-color: var(--code-purple) !important; }
.text-code-green, body .text-code-green   { color: var(--code-green) !important; -webkit-text-fill-color: var(--code-green) !important; }

/* batch1 round-2: remaining blog hexes -> tokens. --slate-50 is the near-white
   (#f8fafc) card surface; teal/bg-deep utilities already exist. */
:root { --slate-50: #f8fafc; }
.bg-ca-slate-50, body .bg-ca-slate-50 { background-color: var(--slate-50) !important; }

/* Blog search input had NO base rule (rendered ~24px tall, unstyled). Give it a
   proper pill height/shape; left padding (!pl-14) already clears the search icon. */
.blog-search-input {
  width: 100%; height: 52px; border-radius: 9999px;
  padding-right: 1.25rem; font-size: 0.95rem; color: var(--white);
  border: 1px solid rgba(255,255,255,0.10); outline: none;
}
.blog-search-input::placeholder { color: rgba(255,255,255,0.35); }
