@charset "utf-8";
/* ═══════════════════════════════════════════════════════════════════════════
   RapidCents — rapidcents-gen2 theme stylesheet
   ═══════════════════════════════════════════════════════════════════════════

   One standalone file. No Tailwind, no build step, no @import of anything.
   Order: tokens → reset/base → layout → typography → components → chrome →
   utilities → print.

   ── FONTS: use a <link>, not an @import ───────────────────────────────────
   An `@import url(fonts.googleapis.com/...)` written here cannot start until
   this file has been fetched AND parsed, so the font CSS lands one full
   round-trip behind the page — and the font FILES land two behind. A <link>
   in <head> is found by the HTML preload scanner in the first packet and
   downloads in parallel with this stylesheet, which is why the @import is
   deliberately absent. The theme's PHP author must add, in <head>:

     <link rel="preconnect" href="https://fonts.googleapis.com">
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400..700&family=JetBrains+Mono:wght@400..700&family=Manrope:wght@600..800&display=swap">

   or, the WordPress way, in functions.php:

     wp_enqueue_style( 'rc-fonts', 'https://fonts.googleapis.com/css2?family=Inter:wght@400..700&family=JetBrains+Mono:wght@400..700&family=Manrope:wght@600..800&display=swap', array(), null );

   Three families, three files. Each request asks for a weight RANGE, not a
   list, so Google serves one variable font per family instead of six static
   faces. Every face below carries a real fallback stack, so a blocked or slow
   Google Fonts response degrades to a system face rather than to invisible
   text — `display=swap` covers the same failure from the other side.

   The ranges have to cover every weight the file below asks for, because a
   variable face CLAMPS to its declared axis rather than falling back to a
   heavier static one: served at `400..600`, every `font-weight: 700` in this
   stylesheet rendered at 600, and the mono axis at `400..500` clamped its 700
   to 500. The app loads the families with no `weight` restriction at all, so
   its 700s are 700 — which is the whole of the difference in heading and
   label ink between the two builds. `600..800` on Manrope is already right:
   the display face is never asked for less than 600 here.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
   1. TOKENS
   ═══════════════════════════════════════════════════════════════════════════
   Ported name-for-name from packages/design-system/tokens.css. The names are
   the shared vocabulary between this theme, the Next.js app and the imported
   content — renaming any of them breaks that contract, so values move and
   names never do.

   Dark is the site default (`data-theme="dark"` on <html>). Bare :root below
   still carries the LIGHT palette so a missing attribute does not invent a
   third look; [data-theme="dark"] is what first-time visitors actually hit.
   Light is a stored choice from the header toggle, never the OS preference.

   The OS preference is deliberately NOT consulted. This file used to carry a
   second, byte-identical dark block under `@media (prefers-color-scheme: dark)`
   guarded by `:not([data-theme="light"])`, which meant a visitor whose laptop
   was set to dark got a #010526 site where the live one is #f6f8fd — the
   largest single visual difference between the two builds, on every page.
   `app/[locale]/layout.tsx` stamps `data-theme="light"` on <html> and flips it
   only for a stored choice; the theme now does exactly the same, so those media
   blocks were unreachable as well as wrong and are gone. Four of them existed:
   the token block here, the logo swap, the theme-toggle icon swap and the film
   grain. Adding a fifth would silently reintroduce the bug.

   Brand tokens that are GRADIENT STOPS — primary/secondary/success/refund/
   danger fills, the blue surface stack, glows and highlights — do NOT flip
   between themes. They are the stops of a fill that is midnight in both
   themes and always carries white text; re-pointing them at light values
   produces washed-out mush on a white button. Components here follow the same
   rule the app learned the hard way: surfaces are bordered, not filled, and
   only text/line/band/shadow tokens are theme-dependent. */

:root {
  color-scheme: light;

  /* ── Type families (bound by the <link> above; fallbacks are load-bearing) ── */
  --font-display: "Manrope", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-sans: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", "SF Mono", Menlo, monospace;

  /* ── Midnight backgrounds (§3) ── */
  --rc-bg-midnight: #f6f8fd;
  --rc-bg-bottom: #eef2fa;
  --rc-bg-lower: #e6edf9;
  --rc-bg-top: #0128a7;
  --rc-bg-upper: #0038cd;
  --rc-bg-middle: #004de0;
  --rc-bg-glow: #0150ea;

  /* ── Text (§7) ── */
  --rc-text-primary: #0d1b3e;
  --rc-text-financial: #0a1733;
  --rc-text-secondary: #45557a;
  --rc-text-blue: #0b5fd0;
  --rc-text-disabled: #5a6885;
  --rc-icon-white: #f4f8ff;

  /* ── Blue surfaces (§4) — gradient stops, identical in both themes ── */
  --rc-surface-top: #0c2f9d;
  --rc-surface-middle: #061f82;
  --rc-surface-bottom: #011a77;
  --rc-border-blue: #176bff;
  --rc-border-cyan: #2ccbff;
  --rc-glow-blue: #087dff;
  --rc-glow-cyan: #00d9ff;
  --rc-edge-highlight: #dff9ff;

  /* ── Primary action (§5) ── */
  --rc-primary-top: #197dfb;
  --rc-primary-middle: #125ce6;
  --rc-primary-bottom: #063cd3;
  --rc-primary-border: #31e2ff;
  --rc-primary-highlight: #73f3ff;
  --rc-glow-primary: #00bfff;
  --rc-primary-pressed-top: #1267dc;
  --rc-primary-pressed-bottom: #042ea8;

  /* ── Secondary action (§6) ── */
  --rc-secondary-top: #071f78;
  --rc-secondary-middle: #041765;
  --rc-secondary-bottom: #03125a;
  --rc-secondary-border: #1748c9;
  --rc-secondary-glow: #145cff;

  /* ── Semantic: success (§11) ── */
  --rc-success-top: #0c8f4f;
  --rc-success-middle: #08c95b;
  --rc-success-bottom: #029a45;
  --rc-success-border: #0a7a44;
  --rc-success-glow: #00e86a;

  /* ── Semantic: refund (§11) ── */
  --rc-refund-top: #45143f;
  --rc-refund-middle: #2e0b36;
  --rc-refund-bottom: #170625;
  --rc-refund-border: #ff4d84;
  --rc-refund-glow: #ff286e;
  --rc-refund-bright: #ff234e;

  /* ── Semantic: destructive (§11) ── */
  --rc-danger-top: #f25310;
  --rc-danger-middle: #db3508;
  --rc-danger-bottom: #b72008;
  --rc-danger-border: #ff8a20;
  --rc-danger-glow: #ff4500;

  /* ── Category accents (§11) ── */
  --rc-purple-highlight: #6d28d9;
  --rc-purple: #7c3dff;
  --rc-purple-mid: #5e2bd6;
  --rc-purple-deep: #2a126f;
  --rc-teal-highlight: #0a6b7e;
  --rc-teal: #077f95;
  --rc-teal-mid: #0798ad;
  --rc-teal-deep: #034d68;
  --rc-warning: #b45f06;

  /* ── Legacy aliases (CMS / internal pages) ── */
  --rc-navy-950: #010526;
  --rc-navy-900: #010837;
  --rc-blue-700: #0038cd;
  --rc-blue-600: #0b5fd0;
  --rc-blue-500: #0150ea;
  --rc-cyan-400: #31e2ff;
  --rc-green-500: #18e86f;
  --rc-amber-500: #ffb44d;
  --rc-red-500: #ff4d84;

  /* Light surfaces (CMS pages fallback) */
  --surface-white: #ffffff;
  --surface-cloud: #f2f5fb;
  --surface-ice: #e8f1fd;
  --surface-blue-soft: #eef4fe;
  --border-light: #d9e2f2;
  --border-strong: #b6c5de;
  --text-primary: #0d1b3e;
  --text-secondary: #45557a;
  --text-muted: #5a6885;

  /* Dark surfaces — literal midnight values, never themed */
  --surface-obsidian: #010526;
  --surface-charcoal: #010837;
  --surface-graphite: #011362;
  --surface-dark-hover: #0c2f9d;
  --border-dark: rgba(44, 203, 255, 0.16);
  --text-dark-primary: #f7f9ff;
  --text-dark-secondary: #b8c7ed;

  /* Gradients */
  --gradient-hero-midnight:
    radial-gradient(
      circle at 50% 18%,
      rgba(1, 80, 234, 0.62) 0%,
      rgba(0, 56, 205, 0.3) 28%,
      rgba(1, 19, 98, 0.18) 55%,
      rgba(1, 8, 55, 0) 72%
    ),
    linear-gradient(180deg, #0128a7 0%, #0038cd 14%, #011362 48%, #010837 76%, #010526 100%);

  --gradient-page-midnight:
    radial-gradient(circle at 50% 0%, rgba(11, 95, 208, 0.06), transparent 45%),
    #f6f8fd;

  --gradient-hero-light:
    radial-gradient(
      circle at 78% 25%,
      rgba(0, 140, 255, 0.18) 0%,
      rgba(0, 91, 255, 0.08) 34%,
      rgba(255, 255, 255, 0) 68%
    ),
    #ffffff;

  --gradient-developer: var(--gradient-page-midnight);
  --gradient-cta: linear-gradient(135deg, #010526 0%, #011362 55%, #0038cd 100%);

  /* Spacing — 8px foundation (§22) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  /* Off the 8px foundation, like --space-3 above it. It is the app's `p-5`,
     which is what the two tile grids are padded with. */
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;
  --space-24: 96px;
  --space-30: 120px;
  --space-32: 128px;
  --space-36: 144px;

  /* Radius (§21) */
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-2xl: 20px;
  --radius-3xl: 24px;
  --radius-pill: 999px;
  --rc-radius-input: 16px;
  --rc-radius-button: 18px;
  --rc-radius-card: 24px;
  --rc-radius-panel: 30px;

  /* Elevation */
  --shadow-card:
    inset 0 1px 0 rgba(255, 255, 255, 0.8),
    0 16px 48px rgba(23, 51, 110, 0.1);
  --shadow-float:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 0 22px rgba(11, 95, 208, 0.1),
    0 22px 54px rgba(23, 51, 110, 0.14);
  --rc-shadow-dark: rgba(0, 5, 31, 0.65);
  --rc-shadow-inner: rgba(0, 11, 61, 0.45);

  /* Motion (§20) */
  --rc-motion-fast: 100ms;
  --rc-motion-standard: 220ms;
  --rc-motion-page: 360ms;
  --rc-ease-premium: cubic-bezier(0.22, 1, 0.36, 1);

  /* Layout */
  /* 1440, the app's own `rc-container` cap, and the same value --content-wide
     already carries. At 1280 every band of page content was inset 80px further
     than the header that sits above it, so the site's own left edge disagreed
     with itself on every viewport wider than 1440. A full token-by-token diff
     against the app's stylesheet found this to be the only value that differed. */
  --content-max: 1440px;
  --content-wide: 1440px;
  --content-editorial: 760px;
  --content-legal: 860px;
  --content-docs: 780px;

  /* ── V1.07 — unified bands ──
     Every public section sits on one of five surfaces. Sections pick a band;
     they never hand-roll a background colour. */
  --rc-band-base: #f6f8fd;
  --rc-band-deep: #eef2fa;
  --rc-band-raised: #ffffff;
  --rc-band-blue: #e8f1fd;
  --rc-band-panel: rgba(232, 241, 253, 0.75);
  --rc-band-charcoal: #0d1424;

  /* The two washes the app lays over a band. Tokens rather than literals
     because the purple one is the single component colour whose alpha differs
     between the palettes — `.rc-accent-purple` in the app's globals.css carries
     0.06 in light and 0.12 of a brighter purple in dark, and a component rule
     cannot read that from any existing token. */
  --rc-wash-ice: rgba(8, 125, 255, 0.16);
  --rc-wash-purple: rgba(109, 40, 217, 0.06);

  /* Hairlines — one border family, three strengths */
  --rc-line-soft: rgba(13, 42, 105, 0.08);
  --rc-line: rgba(13, 42, 105, 0.14);
  --rc-line-strong: rgba(11, 95, 208, 0.32);

  /* Tinted elevation — shadows carry the page hue, never pure black */
  --rc-shadow-sm: 0 2px 8px rgba(23, 51, 110, 0.08);
  --rc-shadow-md:
    inset 0 1px 0 rgba(255, 255, 255, 0.8),
    0 12px 34px rgba(23, 51, 110, 0.1);
  --rc-shadow-lg:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 28px 70px rgba(23, 51, 110, 0.14);

  /* Z-index scale — components reference these, never arbitrary values */
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 30;
  --z-nav: 50;
  --z-overlay: 70;
  --z-modal: 90;
  --z-grain: 100;

  /* Typography roles */
  --rc-tracking-display: -0.045em;
  --rc-tracking-heading: -0.028em;
  --rc-tracking-label: 0.14em;

  /* ── Theme-local additions ──
     The app gets these from Tailwind config and from .rc-nav-glass; a plain
     stylesheet has neither, so they are declared here under the same rc-
     vocabulary. --rc-header-h is referenced by scroll-padding and by the
     mega-menu height cap, so the sticky header can only ever be one number. */
  /* Reserved height for a demo stand-in. The section renderer overrides it
     per variant — pricing wants 4/3 — so it is a token, not a literal. */
  --rc-mock-ratio: 16 / 10;
  /* 80px, because the app's header is `h-[80px]` and the two are compared side
     by side. It is referenced by scroll-padding and by the mega-menu height
     cap, so the sticky header can only ever be one number. */
  --rc-header-h: 80px;
  --rc-header-bg: rgba(255, 255, 255, 0.82);
  /* The app's .rc-menu-panel glass, which it puts on the announcement ribbon
     and on every menu card. Only the ribbon can use it here — see the note on
     .rc-nav__panel — but it is the app's value and it is themed, so it is a
     token and not a literal in the one rule that reads it. */
  --rc-menu-panel-bg: rgba(255, 255, 255, 0.96);
  /* Tailwind's shadow-xl, which is what the app's menu cards carry rather than
     this theme's --rc-shadow-lg. */
  --rc-nav-panel-shadow:
    0 20px 25px -5px rgba(0, 0, 0, 0.1),
    0 8px 10px -6px rgba(0, 0, 0, 0.1);
  /* The account pill's fill: the app tints it with the ink colour at 4%, not
     with the blue band. */
  --rc-nav-account-bg: rgba(13, 42, 105, 0.04);
  /* The sign-up half of that pill: the app washes it with the brand blue at
     10%, and 18% under the pointer. */
  --rc-nav-signup-bg: rgba(11, 95, 208, 0.1);
  --rc-nav-signup-bg-hover: rgba(11, 95, 208, 0.18);
  /* Solutions: the category rail is a 4% wash of the brand blue and the pane
     beside it a 5% wash of the ink. Both were opaque bands here, which made
     the rail grey where the app's is cool and lost the well the cards sit in
     altogether. */
  --rc-nav-rail-bg: rgba(25, 125, 251, 0.04);
  --rc-nav-well-bg: rgba(13, 42, 105, 0.05);
}

/* Dark is the site default. The toggle writes `rc-theme` to localStorage and
   the boot script in <head> stamps a stored light choice back before first
   paint. There is deliberately no prefers-color-scheme twin: the OS is not
   an input. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --rc-bg-midnight: #010526;
  --rc-bg-bottom: #010837;
  --rc-bg-lower: #011362;

  --rc-text-primary: #f7f9ff;
  --rc-text-financial: #f8faff;
  --rc-text-secondary: #b8c7ed;
  --rc-text-blue: #78c8ff;
  --rc-text-disabled: #8093c9;

  --rc-purple-highlight: #a66bff;
  --rc-teal-highlight: #6fffff;
  --rc-teal: #11d9e8;
  --rc-warning: #ffb44d;
  --rc-success-top: #18e86f;
  --rc-success-border: #7cffb0;
  --rc-blue-600: #197dfb;

  --gradient-page-midnight:
    radial-gradient(circle at 50% 0%, rgba(1, 80, 234, 0.2), transparent 45%),
    #010526;

  --surface-white: #010b3a;
  --surface-cloud: #01072c;
  --surface-ice: #01144f;
  --surface-blue-soft: #01144f;
  --border-light: rgba(120, 200, 255, 0.16);
  --border-strong: rgba(44, 203, 255, 0.38);
  --text-primary: #f7f9ff;
  --text-secondary: #b8c7ed;
  --text-muted: #8093c9;

  --rc-band-base: #010526;
  --rc-band-deep: #01072c;
  --rc-band-raised: #010b3a;
  --rc-band-blue: #01144f;
  --rc-band-panel: rgba(8, 32, 116, 0.42);
  --rc-band-charcoal: #01102f;

  --rc-wash-ice: rgba(8, 125, 255, 0.16);
  --rc-wash-purple: rgba(124, 61, 255, 0.12);

  --rc-line-soft: rgba(120, 200, 255, 0.1);
  --rc-line: rgba(120, 200, 255, 0.16);
  --rc-line-strong: rgba(44, 203, 255, 0.38);

  --rc-shadow-sm: 0 2px 8px rgba(0, 6, 34, 0.45);
  --rc-shadow-md:
    inset 0 1px 0 rgba(223, 249, 255, 0.08),
    0 12px 34px rgba(0, 6, 34, 0.5);
  --rc-shadow-lg:
    inset 0 1px 0 rgba(223, 249, 255, 0.12),
    0 28px 70px rgba(0, 6, 34, 0.55);
  --shadow-card:
    inset 0 1px 0 rgba(223, 249, 255, 0.14),
    0 16px 48px rgba(0, 5, 31, 0.4);
  --shadow-float:
    inset 0 1px 0 rgba(223, 249, 255, 0.22),
    0 0 22px rgba(8, 125, 255, 0.3),
    0 22px 54px rgba(0, 5, 31, 0.5);

  --rc-header-bg: rgba(1, 5, 38, 0.72);
  --rc-menu-panel-bg: rgba(1, 5, 38, 0.92);
  --rc-nav-panel-shadow:
    0 20px 25px -5px rgba(0, 0, 0, 0.4),
    0 8px 10px -6px rgba(0, 0, 0, 0.4);
  --rc-nav-account-bg: rgba(1, 5, 38, 0.5);
  --rc-nav-signup-bg: rgba(0, 140, 255, 0.18);
  --rc-nav-signup-bg-hover: rgba(0, 140, 255, 0.28);
  --rc-nav-rail-bg: rgba(0, 140, 255, 0.06);
  --rc-nav-well-bg: rgba(1, 5, 38, 0.55);
}

/* ═══════════════════════════════════════════════════════════════════════════
   2. RESET AND BASE
   ═══════════════════════════════════════════════════════════════════════════ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Margins are opted into by components rather than inherited from the UA, so
   a section's rhythm is decided in one place instead of fought with. */
body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
blockquote,
dl,
dd,
ol,
ul {
  margin: 0;
}

html {
  /* `clip` rather than `hidden`: hidden would make <html> a scroll container
     and silently kill position:sticky on the header. */
  overflow-x: clip;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* An in-page anchor must not land under the sticky header. */
  scroll-padding-top: calc(var(--rc-header-h) + var(--space-4));
}

body {
  min-height: 100%;
  background: var(--rc-band-base);
  color: var(--rc-text-primary);
  font-family: var(--font-sans);
  font-size: 16px;
  /* 1.5, which is what Tailwind's preflight puts on the app's <html> and what
     every element in the app that does not name its own leading inherits.
     Anything set here reaches a surprising number of places — table cells, the
     path selector's descriptions, list items with no rule of their own — and
     at 1.6 each of them ran 1.6px taller per line than the app's. */
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
svg,
video,
canvas,
iframe,
embed,
object {
  display: block;
  max-width: 100%;
}

img,
video {
  height: auto;
}

/* The theme wraps images in <picture> to offer AVIF with a WebP fallback. The
   wrapper must not become a box of its own: where an image is a flex or grid
   item, a <picture> in between would take that role and the <img> would be laid
   out against the wrapper instead of the parent. `display: contents` removes it
   from the box tree, so every existing rule keeps applying to the <img>. */
picture {
  display: contents;
}

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

button {
  background: none;
  border: 0;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: var(--rc-tracking-heading);
  text-wrap: balance;
  color: var(--rc-text-primary);
}

p {
  text-wrap: pretty;
}

a {
  color: var(--rc-text-blue);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: color var(--rc-motion-fast) var(--rc-ease-premium);
}

a:hover {
  color: var(--rc-text-primary);
}

code,
kbd,
samp,
pre {
  font-family: var(--font-mono);
  font-size: 0.9375em;
}

hr {
  border: 0;
  border-top: 1px solid var(--rc-line);
  margin-block: var(--space-8);
}

::selection {
  background: var(--rc-line-strong);
  color: var(--rc-text-primary);
}

/* One focus ring for the whole theme. --rc-text-blue is the only accent that
   clears 3:1 against every band in BOTH palettes (5.55:1 light, 10.95:1 dark),
   which is why the ring reads the text token rather than a fixed cyan. The
   offset keeps the ring on the page background instead of on a filled button,
   where a blue-on-blue ring would vanish. Nothing in this file removes an
   outline without putting one of these back. */
:focus-visible {
  outline: 2px solid var(--rc-text-blue);
  outline-offset: 2px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   3. LAYOUT
   ═══════════════════════════════════════════════════════════════════════════ */

.rc-container {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: clamp(20px, 4vw, 48px);
}

/* Vertical rhythm, from the app's own SECTION constant in
   `components/sections/section-renderer.tsx`, which reads `py-14 lg:pt-16
   lg:pb-20` — 56px, stepping to 64/80 at lg.
   Flat pixels rather than a clamp, because the app steps once at lg and holds
   still either side of it; a clamp met the app only at its ceiling and ran
   32px tight at every width below 1280.

   The constant had been re-tightened in the app and this file was still
   quoting — and drawing — the old `py-20 … lg:pt-24 lg:pb-28`. That is 24px of
   invented air above and 32px below every section on the site: on the home
   page alone, across its eleven bands, about 700px of page height that the
   live site does not have. The quoted constant is part of the fix, not a note
   about it: the next person to change this needs to see what it is now. */
.rc-section {
  padding-block: 56px;
}

@media (min-width: 1024px) {
  .rc-section {
    padding-block: 64px 80px;
  }
}

/* The device showcase is the one band the section constant does not describe.
   `TerminalShowcase.tsx:75` carries its own `py-20 lg:py-28`, so it keeps the
   taller rhythm the rest of the page gave up — take it down to `.rc-section`'s
   and the terminal photograph loses 24px of air at every width and 48 at lg,
   which on the one section built around a full-height product shot is the
   difference between a showcase and a strip. Doubled selector for the same
   reason the variants above are doubled: the `lg` step on `.rc-section` must
   not be able to out-order it. */
.rc-section.rc-section--showcase {
  padding-block: 80px;
}

@media (min-width: 1024px) {
  .rc-section.rc-section--showcase {
    padding-block: 112px;
  }
}

/* Block rhythm variants, one per shape the app draws. Doubled selectors so the
   `lg` step on `.rc-section` above can never out-order them, whatever gets
   added to this file later. */
.rc-section.rc-section--tight {
  padding-block: clamp(24px, 3.5vw, 48px);
}

/* Trust strip — `py-10`. */
.rc-section.rc-section--strip {
  padding-block: 40px;
}

/* Stats and the trust badge row — `py-12`. */
.rc-section.rc-section--slim {
  padding-block: 48px;
}

/* Industry index — `py-20`, and the one full section the app does not step at
   lg. */
.rc-section.rc-section--even {
  padding-block: 80px;
}

/* Conversion CTA — `py-10 sm:py-14 lg:py-16`. The panel inside carries the
   band's real height; this is only the air around it. */
.rc-section.rc-section--cta {
  padding-block: 40px;
}

@media (min-width: 640px) {
  .rc-section.rc-section--cta {
    padding-block: 56px;
  }
}

@media (min-width: 1024px) {
  .rc-section.rc-section--cta {
    padding-block: 64px;
  }
}

/* The horizontal gutter the app puts on the section itself — `px-4 sm:px-6
   lg:px-8` — on top of the `padding-inline` `.rc-container` already carries.
   Two paddings rather than one is not a mistake to fold away: the container is
   capped at --content-max and the section is not, so past 1440 the outer
   padding stops mattering and the measure is the same on both sides, while
   below it the copy starts 16 to 32px further in. Folding them into a single
   value agrees at 1920 and is wrong at every laptop and phone width.

   The rule is right; it was the call sites that were wrong. Fourteen sections
   in `inc/sections.php` asked for it and exactly ONE of them has a `px-*` in
   the app — `deviceShowcase`, whose `TerminalShowcase.tsx:75` genuinely
   carries `px-4 sm:px-6 lg:px-8`. Every other section renders through
   `SECTION`, which has no horizontal padding at all and lets `.rc-container`
   alone set the measure. Doubling the gutter on those thirteen cost 32px of
   measure a side at lg and, worse, left adjacent bands disagreeing about where
   the page's left edge is — a band with the modifier started 32px further in
   than the band above it. So the modifier stays, for its one caller. */
.rc-section--gutter {
  padding-inline: 16px;
}

@media (min-width: 640px) {
  .rc-section--gutter {
    padding-inline: 24px;
  }
}

@media (min-width: 1024px) {
  .rc-section--gutter {
    padding-inline: 32px;
  }
}

/* Full-bleed tinted band — the app's `.rc-section-cloud`. The section element
   spans the viewport; the .rc-container inside it keeps the copy on the same
   measure as its neighbours, so an alternating stripe never shifts the text
   column.

   Flat, and with no border of its own. The theme used to lay a panel-coloured
   ellipse over this and hairline it top and bottom; the app draws neither, and
   the rules that do want an edge ask for one below. */
.rc-section--band {
  background: var(--rc-band-deep);
}

/* The pale band a demo sits on — the app's `.rc-section-ice`. Lighter than
   --band, because a demo already carries its own raised card and stacking two
   strong surfaces makes the card read as sunk into the page rather than lifted
   off it. */
.rc-section--ice {
  background:
    radial-gradient(ellipse 120% 90% at 50% 0%, var(--rc-wash-ice), transparent 62%),
    var(--rc-band-blue);
}

/* The developer band — the app's `.rc-accent-purple`. */
.rc-section--purple {
  background:
    radial-gradient(circle at 50% 0%, var(--rc-wash-purple), transparent 45%),
    var(--rc-bg-bottom);
}

/* Band edges. --rc-line, not --rc-line-soft: every `border-y` and `border-b`
   the app puts on a section reads the same hairline token its cards do. */
.rc-section--rule-y {
  border-block: 1px solid var(--rc-line);
}

.rc-section--rule-b {
  border-block-end: 1px solid var(--rc-line);
}

/* ── Below-the-fold rendering ──────────────────────────────────────────────
   Skip layout and paint for bands the reader has not reached yet.

   The home page ships 19 sections and roughly 2,600 elements, and the browser
   lays out and paints every one of them before it can answer the first click.
   That work is what presentation delay measures, and presentation delay is the
   largest of the three parts of INP. Deferring it costs nothing visible: the
   browser still renders each band before it scrolls into view.

   From the fourth section on, so the hero, the trust strip and the first
   content band are never deferred — those are on screen at load on every
   viewport this site supports, and deferring them would trade a real paint for
   nothing.

   `contain-intrinsic-size: auto 600px` is what keeps the scrollbar honest. The
   `auto` keyword tells the browser to remember each section's real height once
   it has rendered it, so the placeholder is only used the first time; 600px is
   the starting guess. Without this the page would report a wrong height and
   scroll position would jump as bands rendered.

   The exclusions are all sticky hosts. `content-visibility` implies paint
   containment, which clips descendants to the section box, and a sticky child
   that outlives its parent's box stops travelling when it hits the clip. The
   `:has()` guard in `@supports` matters as much as the rules: a browser that
   cannot evaluate the exclusion selectors would otherwise apply the deferral
   without them, so it opts out of the whole block instead. */
@supports (content-visibility: auto) and selector(:has(*)) {
  .rc-singular > .rc-section:nth-of-type(n + 4):not(.rc-product-hero):not(
      :has(.rc-faq-layout, .rc-app-directory__toolbar, .rc-app-directory__rail)
    ) {
    content-visibility: auto;
    contain-intrinsic-size: auto 600px;
  }
}

/* ── Demo band ─────────────────────────────────────────────────────────────
   Copy on one side, the working demo on the other. One column until there is
   room for two: a demo squeezed into half of a 900px viewport is unreadable,
   and the fields inside it stop being tappable long before that. */
.rc-demo-band__grid {
  display: grid;
  align-items: center;
  /* `gap-12`, and the same 48px either side of the breakpoint — the app never
     narrows it on a phone, where the two tracks are stacked and the gap is the
     only thing separating the copy from the demo. */
  gap: var(--space-12);
  grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
  .rc-demo-band__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Fee check promo — the same split, weighted 1.15 / 0.85 the way the app
   weights it, so the copy column stays the wider of the two. */
.rc-promo-grid {
  display: grid;
  align-items: center;
  gap: var(--space-12);
  grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
  .rc-promo-grid {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  }
}

/* Developer band — copy against the code panel, `gap-14` at every width. */
.rc-dev-grid {
  display: grid;
  align-items: center;
  gap: 56px;
  grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
  .rc-dev-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.rc-dev-grid > * {
  min-width: 0;
}

.rc-promo-grid > *,
.rc-demo-band__grid > * {
  min-width: 0;
}

.rc-demo-band__copy > :first-child {
  margin-top: 0;
}

/* dashboardDemo leads with the interface. The order is swapped in the layout
   and not in the markup, so a screen reader still reads the heading before the
   thing it introduces, and the tab order still runs copy then controls. */
@media (min-width: 1024px) {
  .rc-demo-band--flip .rc-demo-band__copy {
    order: 2;
  }

  .rc-demo-band--flip .rc-demo-band__demo {
    order: 1;
  }
}

/* `space-y-4` — the gap `SummaryText` puts between the paragraphs of a body
   that was authored with blank lines in it. */
.rc-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* The card grid.
   `list-style`, `padding` and `margin` are zeroed here, and that is not
   housekeeping: `inc/sections.php` puts this class on `<ul>` elements, so
   without the reset the browser drew its own disc in front of every card on
   the site and indented each track by 40px — which is both the dots the client
   photographed and the reason the demo's cards were narrower than the app's
   and its copy wrapped a line earlier. `.rc-list`, `.rc-steps` and
   `.rc-trust-strip` all already zero the same three; this rule was the one
   that did not.

   The list stays a list, and the reason is semantic rather than technical: a
   grid of cards that are each a link is a list of links, so killing the marker
   in CSS is the fix the markup does not have to pay for. It is not that the
   script forces the tag — `assets/js/theme.js` reads the industry filter's
   cards as `[data-rc-filter-item]`, a bare attribute selector that matches any
   element, so the `<li>` could become a `<div>` without touching that file.
   What the script does care about is the `hidden` attribute it sets on these
   cells; see the `:not([hidden])` on `.rc-grid > li` below. */
.rc-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* min-width:0 on the children is what actually prevents the 390px horizontal
   scroll: a grid/flex item defaults to min-content width, so one long token —
   a URL, an unbroken merchant name — would otherwise push the track wider
   than the viewport. */
.rc-grid > *,
.rc-stack > * {
  min-width: 0;
}

/* The app's grid cell is the card itself, so a short card stretches to its
   row's height. Here the cell is the `<li>` and the card is inside it, and a
   card that does not fill its cell leaves a short tile floating above the
   bottom of its row — which is what made the industry tiles a line shorter
   than the app's at two of the five widths. */
/* `:not([hidden])` for the same reason `.rc-industry-filter__controls` carries
   it: the industry filter hides a card by setting the `hidden` attribute on
   this exact `<li>`, once per keystroke across 120 of them. Chrome's UA rule
   for `[hidden]` is `!important` and survives a bare `display: flex` here, but
   an engine whose UA rule is not — the reason the sibling rule is written this
   way — would keep every filtered-out card on the page. */
.rc-grid > li:not([hidden]) {
  display: flex;
}

.rc-grid > li > .rc-card {
  flex: 1;
  min-width: 0;
}

/* Tighter gutter — the app's `gap-3` on the industry tiles, which are the one
   grid whose cards carry no call to action and can sit closer together. */
.rc-grid--tight {
  gap: var(--space-3);
}

/* Column counts, composed rather than derived. Each grid takes the app's own
   breakpoints, and there is only one pair of them: `section-renderer.tsx` writes
   `grid gap-4 sm:grid-cols-2 ${COL_CLASS[fitColumns(items.length, 4)]}` for
   both the product grid and the tile grid, so every one of them steps to two
   tracks at `sm` (640) and to its final count at `lg` (1024). The `md2`/`xl4`
   pair this file used to carry described a 768/1280 step that the app has
   nowhere: the product grid sat on one track from 640 to 767 where the app was
   already two-up, and stayed two-up from 1024 to 1279 where the app was four.

   The final count is NOT always four. `fitColumns(total, 4)` walks down from
   four to the first number that divides the item count, so six items are three
   across in two clean rows rather than four-plus-two with two dead cells. The
   PHP mirror of that lives in `inc/sections.php`; these are the tracks it
   selects between, which is why `--lg2` and `--lg3` exist at all. */
@media (min-width: 640px) {
  .rc-grid--sm2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .rc-grid--lg2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .rc-grid--lg3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .rc-grid--lg4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   4. TYPOGRAPHY
   ═══════════════════════════════════════════════════════════════════════════ */

/* Rationed by the design system: one per section at most. The wide tracking is
   what makes 11px uppercase readable — remove it and the label turns to mush. */
.rc-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  font-family: var(--font-sans);
  font-size: 11px;
  /* 700, the weight `.variant-n .rc-eyebrow` carries in the app's globals.css.
     At 11px in caps the step from 600 reads as ink rather than as size, and it
     is the lead-in line above the heading in the hero, the developer band, the
     fee check panel and both comparison column heads. */
  font-weight: 700;
  /* 1.5, not 1.4 — the app leaves this at the browser's `normal`, which for
     Inter at 11px is 16.5px, and the eyebrow is the shortest line in several
     sections so it decides their measured leading. */
  line-height: 1.5;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-text-blue);
}

/* ── The h1 scale, and the seven templates that do not use it ──────────────
   There is no single h1 size in the app. Eight templates each pick their own,
   because each has a different column to fill, and this file used to draw one
   size for all of them — the largest. The result was not "slightly big": the
   five `rc-section-heading` pages (company, developers, legal) rendered their
   headline at 64px against the app's 44 at 1920, and the 126 product pages at
   64 against 48.

   The bare class is `PageIntro`'s scale (`components/ui/page-intro.tsx:32`),
   which is what the page-title header in `functions.php` prints and what the
   largest family of pages — every index, industry, solution and commercial
   page — actually renders. Manrope and the heading tracking come from the
   app's own bare `h1, h2, h3, h4` rule in globals.css, which every one of
   these headings inherits; only `.rc-hero-heading` re-points the tracking at
   the display value, so the three modifiers below that map onto it say so.

   Each scale has TWO hooks, and the second one is not redundant.
   `wordpress/tests/render-harness.php:363` proves every rendered page has a
   heading by testing for the literal string `<h1 class="rc-h1">` — the closing
   quote included — so ANY second class on the element, first in the list or
   not, turns that assertion off across all 1,731 pages without failing it.
   Until the harness is relaxed to a pattern, a caller that cannot afford to
   lose the check marks the SCOPE instead: `rc-h1-scale--*` on the block that
   contains the heading, which leaves the h1's own attribute untouched. The
   `.rc-h1--*` modifiers are the direct form, for callers that carry a scale of
   their own anyway. Neither ever appears on the same heading as the other. */
.rc-h1 {
  font-family: var(--font-display);
  font-size: clamp(2rem, 4vw, 3.25rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: var(--rc-tracking-heading);
  text-wrap: balance;
  max-width: 22ch;
  color: var(--rc-text-primary);
}

/* The home hero — `section-renderer.tsx:145`, `rc-hero-heading mt-5
   max-w-[17ch] text-[clamp(2.5rem,4.6vw,4rem)]`.
   The hero's copy column is its own scope hook: it is the only place a hero h1
   can be, so a hero heading gets this scale whether or not its renderer names
   the modifier. `:not([class*="rc-h1--"])` is what stops that convenience from
   becoming a trap — a product hero drawn inside the same column asks for
   `--product`, and a bare descendant selector would outrank it. */
.rc-h1--hero,
.rc-hero-layout__copy .rc-h1:not([class*="rc-h1--"]) {
  font-size: clamp(2.5rem, 4.6vw, 4rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: var(--rc-tracking-display);
  max-width: 17ch;
}

/* The product hero — `product-hero.tsx:42`. The copy column is the wide side
   of a two-column grid, so the column is already the measure and a 22ch cap
   on top of it wrapped the headline onto seven lines. The scope hook is on
   the hero band itself: that band prints the h1, so a page-title header is
   not in the way. */
.rc-h1--product,
.rc-h1-scale--product .rc-h1 {
  font-size: clamp(2rem, 3.8vw, 3rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: var(--rc-tracking-display);
  max-width: none;
}

/* The careers board — `job-board.tsx:89`. */
.rc-h1--jobs,
.rc-h1-scale--jobs .rc-h1 {
  font-size: clamp(2.1rem, 4vw, 3.2rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: var(--rc-tracking-display);
  max-width: 18ch;
}

/* `rc-section-heading` promoted to the page heading — the app does this
   wherever a section carries the page's own title rather than repeating it
   under one: the darkFeature that opens a company or developer page
   (`section-renderer.tsx:533`), the legal document title
   (`legal-document-view.tsx:181`) and the not-found panel
   (`not-found-panel.tsx:50`). Same stops as `.rc-h2`, which is the same app
   class.

   Three templates, one scale, three MEASURES — and the measure is not a
   detail here. Only the promoted darkFeature carries `max-w-[20ch]`; the two
   overrides below are what the other two carry, and running all three at 20ch
   wrapped "Know Your Customer and Anti-Money-Laundering Policy" — 51
   characters, and 78 in French — onto four lines on a page the app sets in
   one or two. */
.rc-h1--section,
.rc-h1-scale--section .rc-h1,
.rc-h1-scale--legal .rc-h1,
.rc-h1-scale--notfound .rc-h1 {
  font-size: clamp(1.875rem, 3.6vw, 2.75rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: var(--rc-tracking-heading);
  max-width: 20ch;
}

/* The legal document title has no cap of its own. Its containing `<header>`
   is capped at `68ch` of the BODY font, which is a different measure again and
   belongs to the legal furniture work — this rule only stops the theme from
   imposing a cap the app never had. */
.rc-h1-scale--legal .rc-h1 {
  max-width: none;
}

/* The 404 apology is deliberately the narrowest of the three. */
.rc-h1-scale--notfound .rc-h1 {
  max-width: 18ch;
}

/* An individual job posting — `job-posting-view.tsx:97`. Not the board's
   scale: the board sells the company to a browser and the posting is already
   a decision, so it opens a stop smaller on a wider measure. */
.rc-h1--posting,
.rc-h1-scale--posting .rc-h1 {
  font-size: clamp(1.9rem, 3.6vw, 2.85rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: var(--rc-tracking-display);
  max-width: 22ch;
}

/* A resource article — `resource-article-view.tsx:143`. The only heading on
   the site that is neither the page-intro scale nor a hero one: it is a bare
   `h1`, so Manrope and the heading tracking come from globals.css, the weight
   is `font-bold` and not the 800 the hero classes carry, and `leading-tight`
   is looser than every other heading here because an article headline is
   read rather than scanned. No cap — the editorial column is the measure. */
.rc-h1--article,
.rc-h1-scale--article .rc-h1 {
  font-size: clamp(2rem, 4vw, 2.75rem);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: var(--rc-tracking-heading);
  max-width: none;
}

/* A comparison page — `comparison-page-view.tsx:115`. The largest of the
   non-hero headings, because the h1 IS the answer block's claim. */
.rc-h1--comparison,
.rc-h1-scale--comparison .rc-h1 {
  font-size: clamp(2.25rem, 4.4vw, 3.5rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: var(--rc-tracking-display);
  max-width: 20ch;
}

/* The app's `.rc-section-heading`, stop for stop. The two scales used to meet
   only at their shared 44px ceiling: 1.75rem against 1.875rem at the floor and
   3.4vw against 3.6vw between, which is 2px of difference on a phone and
   enough to move where ten headings wrapped. */
.rc-h2 {
  font-family: var(--font-display);
  font-size: clamp(1.875rem, 3.6vw, 2.75rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: var(--rc-tracking-heading);
  text-wrap: balance;
  color: var(--rc-text-primary);
}

/* Heading measure. The app constrains most section headings with `max-w-[22ch]`
   or `max-w-[20ch]`, and the theme constrained none of them — which is why a
   heading that sets on two lines in the app sets on one long line in WordPress.
   `ch` rather than a pixel width, so the measure follows the clamped font size
   up and down without a second breakpoint. */
.rc-h2--m20 {
  max-width: 20ch;
}

.rc-h2--m22 {
  max-width: 22ch;
}

/* The industry index heading is the one the app does not scale: a flat
   `text-3xl font-bold`, the same 30px at every width. */
.rc-h2--fixed {
  font-size: 1.875rem;
  line-height: 1.2;
}

.rc-h3 {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.9vw, 1.5rem);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: var(--rc-tracking-heading);
  text-wrap: balance;
  color: var(--rc-text-primary);
}

/* Section summary. `text-lg` in the app — a flat 18px over 28px, not a scale:
   the theme's clamp ran 17px on a phone and 20px on a desktop and met the app
   at neither end. */
.rc-lead {
  max-width: 62ch;
  margin-top: var(--space-4);
  font-size: 1.125rem;
  line-height: 1.75rem;
  color: var(--rc-text-secondary);
}

/* Two summaries take `leading-relaxed` on top of `text-lg` — the hero's and the
   product grid's — which is 29.25px rather than 28. */
.rc-lead--relaxed {
  line-height: 1.625;
}

.rc-lead--m54 {
  max-width: 54ch;
}

.rc-lead--m58 {
  max-width: 58ch;
}

/* ── Long-form body ────────────────────────────────────────────────────────
   68ch is the measure the article layouts already use; anything wider and the
   eye loses the line return on a 1440px display. */
.rc-prose {
  max-width: 68ch;
  font-size: 1.0625rem;
  line-height: 1.75;
  color: var(--rc-text-secondary);
  /* Imported content carries raw URLs and account identifiers that have no
     break opportunity of their own. */
  overflow-wrap: break-word;
}

.rc-prose > :first-child {
  margin-top: 0;
}

.rc-prose > :last-child {
  margin-bottom: 0;
}

.rc-prose p {
  margin-block: 0 var(--space-4);
}

.rc-prose h2 {
  margin-block: var(--space-10) var(--space-4);
  font-size: clamp(1.5rem, 2.4vw, 1.875rem);
  color: var(--rc-text-primary);
}

.rc-prose h3 {
  margin-block: var(--space-8) var(--space-3);
  font-size: 1.25rem;
  color: var(--rc-text-primary);
}

.rc-prose ul,
.rc-prose ol {
  margin-block: 0 var(--space-4);
  padding-inline-start: var(--space-6);
}

.rc-prose li {
  margin-block: var(--space-2);
}

.rc-prose li::marker {
  color: var(--rc-text-blue);
}

.rc-prose strong,
.rc-prose b {
  font-weight: 600;
  color: var(--rc-text-primary);
}

/* A quote is set at reading weight on the primary ink so it reads as an
   escalation, not as a second colour of body text. */
.rc-prose blockquote {
  margin-block: var(--space-6);
  padding-inline-start: var(--space-6);
  border-inline-start: 3px solid var(--rc-text-blue);
  font-size: 1.125rem;
  line-height: 1.65;
  color: var(--rc-text-primary);
}

.rc-prose a {
  color: var(--rc-text-blue);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

.rc-prose a:hover {
  color: var(--rc-text-primary);
}

.rc-prose code {
  padding: 2px 6px;
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-sm);
  background: var(--rc-band-panel);
  color: var(--rc-text-primary);
  font-size: 0.875em;
}

.rc-prose pre {
  margin-block: var(--space-6);
  padding: var(--space-4);
  overflow-x: auto;
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
  background: var(--rc-band-deep);
  color: var(--rc-text-primary);
  line-height: 1.6;
}

.rc-prose pre code {
  padding: 0;
  border: 0;
  background: none;
  font-size: 0.875rem;
}

.rc-prose img,
.rc-prose figure {
  margin-block: var(--space-6);
}

.rc-prose img {
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
}

.rc-prose figcaption {
  margin-top: var(--space-3);
  font-size: 0.875rem;
  color: var(--rc-text-disabled);
}

/* ═══════════════════════════════════════════════════════════════════════════
   5. COMPONENTS
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Card ──────────────────────────────────────────────────────────────────
   Bordered, never filled. The surface tokens are gradient stops tuned for
   midnight; painting a card with one and then flipping the theme gives a dark
   slab on a white page. A hairline that brightens on hover reads as the same
   component in both palettes and costs one animatable property. */
/* A block with margins between its children, not a flex column with a gap.
   They measure within a pixel of each other everywhere except the card's last
   line: the app's call to action is an inline-flex span sitting in an inline
   formatting context, so its line box takes the paragraph strut and comes out
   1px taller than the same span blockified as a flex item. */
.rc-card {
  display: block;
  padding: var(--space-6);
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
  background: none;
  transition:
    border-color var(--rc-motion-standard) var(--rc-ease-premium),
    transform var(--rc-motion-standard) var(--rc-ease-premium),
    box-shadow var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-card:hover,
.rc-card:focus-within {
  border-color: var(--rc-line-strong);
}

/* A whole card that is a link still needs the 44px floor and must not inherit
   the global link colour for its body copy. */
a.rc-card {
  min-height: 44px;
  color: inherit;
  text-decoration: none;
}

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

/* `text-lg font-semibold` in the app — 18px over 28px at 600, not 700 over
   1.3. The weight is the visible half of that: 700 on a card title beside a
   700 section heading flattens the difference between the two. */
.rc-card__title {
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.75rem;
  letter-spacing: var(--rc-tracking-heading);
  color: var(--rc-text-primary);
}

.rc-card__body {
  margin-top: var(--space-3);
  font-size: 0.875rem;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

.rc-card__body + .rc-card__body {
  margin-top: var(--space-4);
}

/* ── Card variants ─────────────────────────────────────────────────────────
   Three shapes, because the app draws three and the difference between them is
   deliberate: the product tiles are the page's primary choice and carry the
   full card radius and padding; the industry tiles are small and repeat eight
   or a hundred and twenty times, so they lose 4px of padding and half the
   radius; the industry index cards are filled rather than outlined because
   they sit on a tinted band and need to lift off it. */

/* Industry tiles — `p-5 rounded-[var(--radius-lg)]`, title at the body size. */
.rc-card--tile {
  padding: var(--space-5);
  border-radius: var(--radius-lg);
}

.rc-card--tile .rc-card__title {
  font-size: 1rem;
  line-height: 1.5;
}

.rc-card--tile .rc-card__body {
  margin-top: var(--space-2);
}

/* Industry index cards — the same tile, filled, at `rounded-[var(--radius-xl)]`
   and with the flat 20px leading `text-sm` gives on its own. */
.rc-card--filled {
  padding: var(--space-5);
  border-radius: var(--radius-xl);
  background: var(--rc-band-raised);
}

.rc-card--filled .rc-card__title {
  font-size: 1rem;
  line-height: 1.5;
}

.rc-card--filled .rc-card__body {
  margin-top: var(--space-2);
  line-height: 1.4286;
}

/* The card's call to action — `mt-5`. Not pinned to the bottom edge: the app
   leaves it directly under the copy, and a row of cards is the same height
   either way because the grid stretches them. */
.rc-card__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25rem;
  color: var(--rc-text-blue);
}

.rc-card__cta svg {
  width: 14px;
  height: 14px;
  transition: transform var(--rc-motion-standard) var(--rc-ease-premium);
}

a.rc-card:hover .rc-card__cta svg {
  transform: translateX(2px);
}

@media (prefers-reduced-motion: reduce) {
  .rc-card__cta svg {
    transition: none;
  }

  a.rc-card:hover .rc-card__cta svg {
    transform: none;
  }
}

/* ── Cursor spotlight ──────────────────────────────────────────────────────
   The wash that follows the pointer across an interactive card. `--mx`/`--my`
   are written inline by the app's component; nothing in this theme sets them
   yet, and the 50%/0% fallbacks are what makes that survivable — with no
   script the card gets a still glow from its top edge on hover rather than a
   gradient centred on `NaN`. `isolation: isolate` keeps the ::before behind
   the card's own content without a z-index on every child.

   Only the plain product-grid card carries this in the app. The `--tile` and
   `--filled` cards do not, and painting it on them would be a new difference
   rather than a fixed one. */
.rc-spotlight {
  position: relative;
  isolation: isolate;
}

.rc-spotlight::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-base);
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(
    240px circle at var(--mx, 50%) var(--my, 0%),
    var(--rc-spotlight-tint, rgba(11, 95, 208, 0.1)),
    transparent 68%
  );
  transition: opacity var(--rc-motion-standard) var(--rc-ease-premium);
}

/* Guarded, because on a touch device `:hover` sticks after a tap and the
   card would keep the glow until something else was tapped. */
@media (hover: hover) {
  .rc-spotlight:hover::before {
    opacity: 1;
  }
}

/* Cyan on midnight. The light tint is a 10% brand blue, which on a dark card
   is invisible. */
:root[data-theme="dark"] .rc-spotlight::before {
  --rc-spotlight-tint: rgba(49, 226, 255, 0.16);
}

/* margin-top:auto pins the meta row to the bottom edge so a row of cards with
   unequal copy still lines its metadata up. */
.rc-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-top: auto;
  padding-top: var(--space-3);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--rc-text-disabled);
}

/* ── Buttons ───────────────────────────────────────────────────────────────
   min-height AND min-width on the base class, so no variant can accidentally
   ship a target smaller than a fingertip. 48px and `12px 20px` are the app's
   own `Button` — comfortably over the 44px floor rather than sitting on it,
   which is why matching the app costs nothing here. */
.rc-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 48px;
  min-width: 44px;
  /* `14px 28px` over a 1.5 line box is what `.rc-button-primary` in the app's
     globals.css draws — 52.5px tall, not the 48 the `min-h-[48px]` utility on
     the markup suggests, because that utility loses to the unlayered rule. */
  padding: 14px 28px;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-button);
  background: none;
  color: var(--rc-text-primary);
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform var(--rc-motion-standard) var(--rc-ease-premium),
    border-color var(--rc-motion-standard) var(--rc-ease-premium),
    background-color var(--rc-motion-standard) var(--rc-ease-premium),
    box-shadow var(--rc-motion-standard) var(--rc-ease-premium);
}

/* The ring sits further out on a button than elsewhere: at offset 2 it would
   land on the primary fill, where blue-on-blue is invisible. */
.rc-btn:focus-visible {
  outline-offset: 3px;
}

.rc-btn[disabled],
.rc-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

/* The middle stop is pulled to 38% so the band behind a vertically-centred
   label is #125ce6 or darker — 5.7:1 against white. Left at 50% the label's
   cap-height rides the #197dfb stop, which is only 3.9:1. */
.rc-btn--primary {
  border-color: var(--rc-primary-border);
  background: linear-gradient(
    180deg,
    var(--rc-primary-top) 0%,
    var(--rc-primary-middle) 38%,
    var(--rc-primary-bottom) 100%
  );
  color: #ffffff;
  /* Design system rule 3: glow belongs to hover and press, not to rest. */
  box-shadow:
    inset 0 1px 0 rgba(115, 243, 255, 0.42),
    0 10px 26px rgba(0, 5, 31, 0.28);
}

.rc-btn--primary:hover {
  transform: translateY(-2px);
  border-color: var(--rc-primary-highlight);
  color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.48),
    0 0 26px rgba(0, 217, 255, 0.45),
    0 16px 36px rgba(0, 5, 31, 0.35);
}

.rc-btn--primary:active {
  transform: translateY(0) scale(0.98);
  background: linear-gradient(
    180deg,
    var(--rc-primary-pressed-top) 0%,
    #0b4fc5 50%,
    var(--rc-primary-pressed-bottom) 100%
  );
}

.rc-btn--ghost {
  border-color: var(--rc-line-strong);
  color: var(--rc-text-primary);
}

.rc-btn--ghost:hover {
  border-color: var(--rc-text-blue);
  background-color: var(--rc-band-panel);
  color: var(--rc-text-primary);
}

/* The filled navy action — the app's `.rc-button-secondary`, which `Button`
   maps both its `secondary` and its `dark` variants onto. It is the second
   button in every hero and every CTA panel, and the theme did not have it, so
   those calls to action were rendering as `--ghost`: an outline on the page
   ground where the app draws a filled navy pill. On a light band that is the
   difference between a button someone sees and a border someone does not.

   The `--rc-secondary-*` stops it needs have been in the token block since the
   port and had no rule reading them. They are gradient stops, so like the
   primary's they stay midnight in both themes and always carry white text —
   the label colour is written out rather than tokenised for that reason. */
.rc-btn--secondary {
  border-color: var(--rc-secondary-border);
  background: linear-gradient(
    180deg,
    var(--rc-secondary-top),
    var(--rc-secondary-middle),
    var(--rc-secondary-bottom)
  );
  color: #f7f9ff;
  box-shadow:
    inset 0 1px 0 rgba(98, 167, 255, 0.16),
    0 0 12px rgba(20, 92, 255, 0.18);
}

.rc-btn--secondary:hover {
  transform: translateY(-2px);
  border-color: var(--rc-border-cyan);
  color: #ffffff;
}

/* ── Bulleted list ─────────────────────────────────────────────────────────
   The dot is drawn rather than inherited from ::marker so its size and colour
   survive the theme flip and so the halo can separate it from a band. */
.rc-list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-list > li {
  position: relative;
  padding-inline-start: var(--space-6);
  line-height: 1.65;
  color: var(--rc-text-secondary);
}

.rc-list > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.55em;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rc-text-blue);
  box-shadow: 0 0 0 3px var(--rc-band-panel);
}

.rc-list strong {
  font-weight: 600;
  color: var(--rc-text-primary);
}

/* The developer band's bullets. The app marks each of these with a 16px arrow
   in the band's own purple rather than with a dot, so the mark is drawn in the
   markup — an icon, not a pseudo-element — and the dot this list normally
   paints is switched off. The arrow points at the sentence the way the band's
   own call to action points at the docs; a dot on a purple wash also loses the
   `--rc-band-panel` ring that separates it from an untinted band. */
.rc-list--arrow > li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding-inline-start: 0;
  /* The app gives these no leading of their own, so they take the page's 1.5
     rather than the 1.65 a dotted list uses for its longer lines. */
  line-height: 1.5;
}

.rc-list--arrow > li::before {
  content: none;
}

.rc-list__icon {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 4px;
  color: var(--rc-purple-highlight);
}

/* ── Trust strip ───────────────────────────────────────────────────────────
   Ticked assurances across the band, in the app's two shapes. Every column
   count lives on a variant class rather than on `.rc-trust-strip`, so the two
   never have to out-specify each other: both modifiers are single classes, and
   a shared base that set columns would make the cascade order load-bearing.

   Its own grid rather than `.rc-grid--4`. `.rc-grid` steps to two tracks at 768
   with a uniform 24px gap, both sized for cards — a card narrower than its own
   padding budget is unreadable, which is what that rule's comment says. These
   rows have no padding to run out of, so they take the app's breakpoints and
   the app's split gutters instead.

   No fixed-width box anywhere in here, which is the point. This section used to
   be built from `.rc-badge`, and a pill sized to its content is a promise that
   the content is short — one the 52 comparison pages do not keep. Text in a
   1fr track cannot be wider than its track, at any string length.

   The app puts `.rc-container` on the `<ul>` itself and the theme keeps it on
   a wrapping div, because that is the structure the section parity harness
   locates this band by. `measure.contentLeft` is identical either way. */
.rc-trust-strip {
  display: grid;
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-trust-strip > li {
  display: flex;
  /* A grid item is min-content wide by default, so one long token — a URL, an
     unhyphenated merchant name — would push its track past the viewport. Same
     guard `.rc-grid > *` carries, and the reason the phone width holds. */
  min-width: 0;
  color: var(--rc-text-secondary);
}

/* `flex: none` so the tick keeps its size against a three-line sentence; a flex
   item with an intrinsic width squashes before its text does.
   --rc-success-top is 3.9:1 on this band, under AA for text and fine for a
   mark: WCAG 1.4.11 asks 3:1 of a graphical object. The sentence beside it
   carries the meaning and is --rc-text-secondary, well clear. */
.rc-trust-strip__check {
  flex: none;
  color: var(--rc-success-top);
}

/* Chips — the app's `trustStrip` case. Short assurances, centred on the tick,
   `gap-x-8 gap-y-4` and `text-sm font-medium`, 1 / 2 / 4 columns. */
.rc-trust-strip--chips {
  gap: var(--space-4) var(--space-8);
}

.rc-trust-strip--chips > li {
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 500;
  /* 20px, not 1.5. `text-sm` is a pair — 0.875rem over 1.25rem — and taking the
     size from it while leaving the leading at the theme's default put the chip
     row a pixel taller than the app's. */
  line-height: 20px;
}

@media (min-width: 640px) {
  .rc-trust-strip--chips {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .rc-trust-strip--chips {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Takeaways — the comparison pages' sentences, matching the "Key takeaways"
   list in `ComparisonPageView`: `gap-x-12 gap-y-4`, two columns from `lg` and
   one below it, `flex gap-3 text-[15px] leading-relaxed`.

   Aligned to the top rather than centred, and the tick nudged down by the
   app's `mt-1`, so it sits on the first line of a four-line sentence instead of
   floating halfway down the paragraph. Four columns would be wrong here for the
   same reason: 195 characters in a quarter of the measure is a column of five
   words. */
.rc-trust-strip--takeaways {
  gap: var(--space-4) var(--space-12);
}

/* No `align-items` here on purpose: the app leaves it at `normal`, and the tick
   holds the top line by its own `margin-top` and an explicit 16px height that
   stretch cannot touch. Setting `flex-start` measured identically but is a
   second mechanism doing the first one's job. */
.rc-trust-strip--takeaways > li {
  gap: var(--space-3);
  font-size: 15px;
  font-weight: 400;
  line-height: 1.625;
}

.rc-trust-strip--takeaways .rc-trust-strip__check {
  margin-top: 4px;
}

@media (min-width: 1024px) {
  .rc-trust-strip--takeaways {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ── Numbered workflow ─────────────────────────────────────────────────────
   Four cards across, not one stacked column. The theme used to draw this as a
   single full-width track of 26px rows with a connector down the left; the app
   lays the same steps out two-up from `md` and four-up from `lg`, each a card
   with a numbered chip in it. On a 1280px page that is the difference between
   a 428px block and a 304px one, and between four bordered cards and four
   lines of text.

   Still a CSS counter rather than typed digits, so a reordered workflow
   renumbers itself and the <ol> semantics survive; `decimal-leading-zero`
   because the app pads the index to `01`. */
.rc-steps {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: rc-step;
}

/* 640, not 768. `workflow-diagram.tsx` writes `sm:grid-cols-2`, and Tailwind's
   `sm` is 640 — this file was reading it as `md` and holding one track through
   128px of the phablet range the app is already two-up in. */
@media (min-width: 640px) {
  .rc-steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* auto-fit, not a fixed four — the app's `lg:grid-cols-[repeat(auto-fit,
   minmax(190px,1fr))]`, and the component's own docblock says why: every
   product in product-seeds.ts defines five `howItWorks` steps, so four fixed
   tracks orphan step 05 on a row of its own with the connector hairline after
   step 04 pointing into empty space. 41 product pages × 3 locales.
   The track floor stays 190px so a six-step workflow wraps rather than
   squeezing six unreadable columns into 1024. */
@media (min-width: 1024px) {
  .rc-steps {
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  }
}

/* The tint is written out rather than tokenised: it is the app's own
   `bg-[rgba(120,200,255,0.04)]`, a single arbitrary value with no dark variant
   behind it, and no token in either palette carries a 4% cyan. */
.rc-steps > li {
  position: relative;
  min-width: 0;
  counter-increment: rc-step;
  padding: var(--space-6);
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
  background: rgba(120, 200, 255, 0.04);
}

.rc-steps__index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--rc-line-strong);
  border-radius: var(--radius-md);
  background: rgba(0, 140, 255, 0.12);
  color: var(--rc-text-blue);
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.25rem;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

.rc-steps__index::before {
  content: counter(rc-step, decimal-leading-zero);
}

.rc-steps__text {
  margin-top: var(--space-4);
  font-size: 0.875rem;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

/* The connector makes the row read as one sequence instead of four cards. It
   only exists where the cards are side by side — the markup drops it on the
   last step so the line does not dangle off the end of the row. */
.rc-steps__link {
  display: none;
}

@media (min-width: 1024px) {
  .rc-steps__link {
    display: block;
    position: absolute;
    inset-inline-end: 0;
    top: 50%;
    width: var(--space-4);
    height: 1px;
    transform: translateX(100%);
    background: var(--rc-line-strong);
  }
}

/* The block's own top margin lives on the wrapper, where the app puts it, so
   the <ol> itself carries none. */
.rc-steps-wrap {
  margin-top: var(--space-12);
}

.rc-steps-wrap > .rc-steps {
  margin-top: 0;
}

.rc-steps strong {
  display: block;
  margin-bottom: var(--space-1);
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: var(--rc-tracking-heading);
  color: var(--rc-text-primary);
}

/* ── FAQ ───────────────────────────────────────────────────────────────────
   Built on <details>/<summary>: open and close is the browser's job, so the
   list works with JavaScript off and the open state survives print.

   Two columns from `lg`, with the heading held beside the questions rather
   than stacked above them — the arrangement the app uses, and the reason its
   FAQ reads as one exchange instead of a heading followed by an unrelated
   list. Below `lg` it is one column and the difference does not exist, which
   is why this was invisible on a phone and obvious on the demo's monitor. */
.rc-faq-layout {
  display: grid;
  gap: var(--space-12);
  grid-template-columns: 1fr;
}

.rc-faq-layout > * {
  min-width: 0;
}

@media (min-width: 1024px) {
  .rc-faq-layout {
    grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.3fr);
    gap: 80px;
  }

  /* `top-28` clears the sticky header, which is 80px, with room to spare. */
  .rc-faq-layout > .rc-h2 {
    position: sticky;
    top: 112px;
    align-self: start;
  }
}

.rc-faq {
  border-block: 1px solid var(--rc-line);
}

.rc-faq__item {
  padding-block: var(--space-6);
}

.rc-faq__item + .rc-faq__item {
  border-top: 1px solid var(--rc-line);
}

.rc-faq__q {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.75rem;
  letter-spacing: var(--rc-tracking-heading);
  color: var(--rc-text-primary);
  cursor: pointer;
  list-style: none;
  transition: color var(--rc-motion-fast) var(--rc-ease-premium);
}

/* A one-line question is 28px tall, which is under the target floor. The
   summary keeps the app's drawn height and takes a transparent overlay that
   carries the touch — the same device `.rc-announce__cta` and the panel's
   replay button use, and the reason it is an overlay rather than a min-height
   is that growing the row would move every question below it. */
.rc-faq__q::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 100%;
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

.rc-faq__q::-webkit-details-marker {
  display: none;
}

.rc-faq__q:hover {
  color: var(--rc-text-blue);
}

/* The summary is full-bleed inside its row, so an outside ring would overlap
   the rows above and below. Pulling it inside keeps it fully visible. */
.rc-faq__q:focus-visible {
  outline-offset: -2px;
}

/* The app's open/close mark is a plus that turns into a cross, not a chevron.
   It is a character in the markup rather than a pseudo-element because the
   summary's own ::after is carrying the touch target. */
/* No line-height of its own: the mark takes the summary's 28px line box, which
   is what sets the row's height once `mt-1` is added to it. Collapsing it to 1
   made every closed question 4px shorter than the app's. */
.rc-faq__sign {
  flex: none;
  margin-top: 4px;
  color: var(--rc-text-blue);
  transition: transform var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-faq__item[open] .rc-faq__sign {
  transform: rotate(45deg);
}

.rc-faq__a {
  max-width: 68ch;
  margin-top: var(--space-4);
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

.rc-faq__a > * + * {
  margin-top: var(--space-3);
}

@media (prefers-reduced-motion: reduce) {
  .rc-faq__sign {
    transition: none;
  }
}

/* ── Tables ────────────────────────────────────────────────────────────────
   Every table is wrapped. The wrapper is the only element on the page allowed
   to scroll sideways; min-width on the table is what forces the scroll instead
   of letting six columns crush to 40px each at 390px. Give the wrapper
   tabindex="0" in the markup so it can also be scrolled from the keyboard. */
.rc-table-wrap {
  max-width: 100%;
  margin-block: var(--space-6);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
}

.rc-table {
  width: 100%;
  min-width: 480px;
  border-collapse: separate;
  border-spacing: 0;
  /* The app leaves the table at the body size and steps individual cells down
     with `text-sm`; setting 15px on the table put every row a couple of pixels
     short of the app's. */
  font-size: 1rem;
  text-align: start;
  /* Fee and rate columns only line up if the digits are the same width. */
  font-variant-numeric: tabular-nums;
}

.rc-table caption {
  padding: var(--space-3) var(--space-6);
  border-bottom: 1px solid var(--rc-line);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: start;
  color: var(--rc-text-secondary);
}

.rc-table th,
.rc-table td {
  padding: 14px 20px;
  border-bottom: 1px solid var(--rc-line-soft);
  vertical-align: top;
  text-align: start;
}

.rc-table th {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--rc-text-secondary);
}

.rc-table td {
  color: var(--rc-text-secondary);
}

/* The row-label column is the one people scan, so it gets full ink. */
.rc-table td:first-child {
  font-weight: 500;
  color: var(--rc-text-primary);
}

.rc-table tbody tr:last-child td {
  border-bottom: 0;
}

/* A row header is a label a person reads, not a column heading. The rule above
   sets every `th` in 11px uppercase, which is right at the top of a table and
   wrong down its left edge — it turned the comparison table's row labels into
   tiny capitals nobody could scan. Both tables that use `th scope="row"` are
   fixed by scoping the readable treatment to the body.

   This is a deliberate divergence and it is the app's own intent, not a
   preference: `pricing-table.tsx` writes `font-medium normal-case
   tracking-normal` on exactly these cells and the utilities never land,
   because `.variant-n .rc-table th` outranks them. The app ships four rate
   scenarios set in 11px capitals with 1.54px of tracking. Matching that would
   make the pricing table 13px shorter and unreadable. */
.rc-table tbody th[scope="row"] {
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  white-space: normal;
  color: var(--rc-text-primary);
}

/* Rates and fees only line up as a column if the digits are the same width and
   the face is the same one the rest of the site uses for figures. */
.rc-table__figure {
  font-family: var(--font-mono);
  font-size: 0.875rem;
  line-height: 1.25rem;
}

.rc-table th.rc-table__total {
  color: var(--rc-text-blue);
}

.rc-table td.rc-table__total {
  background: color-mix(in srgb, var(--rc-text-blue) 10%, transparent);
  font-weight: 600;
  color: var(--rc-text-primary);
}

/* ── Pricing table ─────────────────────────────────────────────────────────
   The table and its disclaimer are one card, because the disclaimer is what
   makes the numbers publishable — a footnote that can be scrolled away from
   its table is a footnote that has stopped doing its job. */
.rc-pricing-table {
  margin-block: var(--space-10) 0;
  overflow: hidden;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
  background: var(--rc-band-deep);
}

/* The wrapper keeps its horizontal scroll and gives up the border and radius
   it would otherwise draw inside this one. */
.rc-pricing-table .rc-table-wrap {
  margin-block: 0;
  border: 0;
  border-radius: 0;
}

/* 560px, the app's own `min-w-[560px]`. Four columns in the theme's 480px
   floor put the scenario labels on two lines each at 390 and made the block
   80px taller than the app's. */
.rc-pricing-table .rc-table {
  min-width: 560px;
}

.rc-pricing-table__note {
  margin: 0;
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--rc-line);
  font-size: 0.75rem;
  line-height: 1rem;
  color: var(--rc-text-disabled);
}

/* ── Comparison table ──────────────────────────────────────────────────────
   "Why merchants switch", drawn the way the app draws it: a raised panel with
   the RapidCents column lifted out of the other two, a Recommended chip over
   it, a tick before every claim it makes and a dash before every one the
   incumbent does not.

   The app builds this out of nested `<div>`s on a three-track grid, and this
   is the one place the theme keeps its own structure. A comparison matrix is
   the textbook case for `<th scope>`: without the row and column association a
   screen reader reads twenty cells with no idea which capability or which
   provider each belongs to, and the app's grid of divs carries none of it. The
   table is the accessible drawing of the same picture, so the picture moves
   and the markup does not — the exception the brief allows for keeping a
   structure the theme needs.

   The one thing that follows from the table and not from the app: below `md`
   the app swaps to a stack of one card per capability, and this scrolls in its
   `.rc-table-wrap` instead. Reflowing a table into cards means giving up the
   header association the table is here for. */
.rc-compare {
  margin-top: var(--space-10);
}

.rc-compare .rc-table-wrap {
  margin-block: 0;
  background: var(--rc-band-deep);
  box-shadow: var(--rc-shadow-lg);
}

.rc-compare .rc-table {
  font-variant-numeric: normal;
}

/* 1.05 / 1.15 / 1, the app's own track weights. Only while the table is a
   table: the phone layout below stacks the cells and a fixed track width there
   would hold the first one at a third of the card. */
@media (min-width: 768px) {
  .rc-compare .rc-table {
    table-layout: fixed;
  }

  .rc-compare .rc-table th:nth-child(1) {
    width: 32.8%;
  }

  .rc-compare .rc-table th:nth-child(2) {
    width: 35.9%;
  }

  .rc-compare .rc-table th:nth-child(3) {
    width: 31.3%;
  }
}

.rc-compare .rc-table th,
.rc-compare .rc-table td {
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--rc-line-soft);
  font-size: 0.875rem;
  letter-spacing: normal;
  text-transform: none;
  white-space: normal;
}

/* The app's header cells are plain divs at the page's own size, and the strut
   of that 16px line box is part of what makes the header row 97px tall — so
   the cell keeps the body size and the labels inside it step down, rather than
   the cell stepping down and taking the strut with it. */
.rc-compare .rc-table thead th {
  border-bottom: 1px solid var(--rc-line);
  font-size: 1rem;
  line-height: 1.5rem;
  vertical-align: bottom;
}

/* The eyebrow's own bottom margin is off in here: the app spaces the label
   below it with `mt-1.5` and nothing else. */
.rc-compare .rc-eyebrow {
  margin-bottom: 0;
}

.rc-compare .rc-table thead th:nth-child(3) {
  border-left: 1px solid var(--rc-line);
}

.rc-compare .rc-table tbody th[scope="row"] {
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.375;
  color: var(--rc-text-primary);
}

.rc-compare .rc-table tbody tr:last-child > * {
  border-bottom: 0;
}

/* The zebra is the app's `index % 2 === 1`, which is the second row and every
   other one after it. */
.rc-compare .rc-table tbody tr:nth-child(even) > :not(.rc-compare__pick) {
  background: rgba(120, 200, 255, 0.03);
}

/* The recommended column, lifted out of the panel by a tint and a brighter
   rule rather than by being taller. */
.rc-compare__pick {
  background: rgba(0, 140, 255, 0.09);
}

.rc-compare .rc-table tbody tr:nth-child(even) .rc-compare__pick {
  background: rgba(0, 140, 255, 0.13);
}

.rc-compare .rc-table thead .rc-compare__pick {
  position: relative;
  border-bottom-color: var(--rc-line-strong);
  background: rgba(0, 140, 255, 0.12);
}

.rc-compare .rc-table thead .rc-compare__pick::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--rc-border-cyan), transparent);
}

.rc-compare__label {
  display: block;
  margin-top: 6px;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25rem;
  color: var(--rc-text-primary);
}

.rc-compare__label--pick {
  margin-top: var(--space-2);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.5rem;
}

.rc-compare__label--legacy {
  color: var(--rc-text-secondary);
}

.rc-compare__badge {
  display: inline-flex;
  padding: 2px 10px;
  border-radius: var(--radius-sm);
  background: var(--rc-primary-middle);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.025em;
  text-transform: uppercase;
  color: #ffffff;
}

/* The two body columns lead with a mark: a tick on what RapidCents does, a
   dash on what the incumbent does not. Both are `flex` so a three-line claim
   keeps its mark on the first line. */
.rc-compare__cell {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  line-height: 1.625;
}

.rc-compare .rc-compare__pick .rc-compare__cell {
  font-weight: 500;
  color: var(--rc-text-primary);
}

.rc-compare .rc-compare__pick .rc-trust-strip__check {
  margin-top: 2px;
}

.rc-compare__legacy {
  border-left: 1px solid var(--rc-line-soft);
  color: var(--rc-text-disabled);
}

.rc-compare__legacy .rc-compare__cell::before {
  content: "";
  flex: none;
  width: 12px;
  height: 1px;
  margin-top: var(--space-2);
  background: var(--rc-text-disabled);
}

.rc-compare__note {
  margin: var(--space-4) 0 0;
  font-size: 0.75rem;
  line-height: 1rem;
  color: var(--rc-text-disabled);
}

/* Below `md` the app stops being a table and becomes one card per capability,
   and so does this — reflowed rather than rebuilt. The header row leaves the
   visual flow but stays in the document, so every cell keeps the `scope`
   association a screen reader reads it by; the labels the reader sees come
   from `data-label` on each cell. Three columns on a 390px screen is a table
   nobody can read either way, and scrolling one sideways is worse than
   stacking it. */
@media (max-width: 767px) {
  .rc-compare .rc-table-wrap {
    overflow: visible;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
  }

  .rc-compare .rc-table {
    display: block;
    min-width: 0;
    table-layout: auto;
  }

  .rc-compare .rc-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .rc-compare .rc-table tbody {
    display: block;
  }

  .rc-compare .rc-table tbody tr {
    display: block;
    overflow: hidden;
    border: 1px solid var(--rc-line);
    border-radius: var(--rc-radius-card);
    background: var(--rc-band-deep);
  }

  .rc-compare .rc-table tbody tr + tr {
    margin-top: var(--space-3);
  }

  .rc-compare .rc-table tbody tr > * {
    display: block;
    width: auto;
    padding: var(--space-4);
    border-bottom: 0;
  }

  .rc-compare .rc-table tbody th[scope="row"] {
    padding-block: var(--space-3);
    border-bottom: 1px solid var(--rc-line);
    font-weight: 700;
    line-height: 1.25rem;
  }

  .rc-compare .rc-table tbody tr:nth-child(even) > :not(.rc-compare__pick) {
    background: none;
  }

  .rc-compare .rc-table tbody .rc-compare__pick,
  .rc-compare .rc-table tbody tr:nth-child(even) .rc-compare__pick {
    border-bottom: 1px solid var(--rc-line-strong);
    background: rgba(0, 140, 255, 0.12);
  }

  .rc-compare .rc-table tbody .rc-compare__legacy {
    border-left: 0;
  }

  /* The column label each value belongs to, printed above it — and the mark
     that belongs with it moves up onto that line too, the way the app's card
     puts a tick beside "RapidCents" and a dash beside the incumbent. Leaving
     either mark in the value row would take 28px out of a 286px measure and
     wrap every claim onto a second line. */
  .rc-compare .rc-table tbody td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: var(--space-2);
    font-size: 10px;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.025em;
    text-transform: uppercase;
    color: var(--rc-text-disabled);
  }

  .rc-compare .rc-table tbody .rc-compare__pick {
    position: relative;
  }

  .rc-compare .rc-table tbody .rc-compare__pick::before {
    padding-inline-start: 22px;
    color: var(--rc-text-blue);
  }

  .rc-compare .rc-table tbody .rc-compare__pick .rc-trust-strip__check {
    position: absolute;
    inset-inline-start: var(--space-4);
    top: 17px;
    width: 14px;
    height: 14px;
  }

  /* The incumbent's dash, drawn as a background rule on the label rather than
     as a flex child of the value. */
  .rc-compare .rc-table tbody .rc-compare__legacy::before {
    padding-inline-start: 20px;
    background-image: linear-gradient(var(--rc-text-disabled), var(--rc-text-disabled));
    background-repeat: no-repeat;
    background-size: 12px 1px;
    background-position: 0 50%;
  }

  .rc-compare .rc-table tbody .rc-compare__legacy .rc-compare__cell::before {
    display: none;
  }
}

/* Off-canvas rather than display:none, so a screen reader still announces it.
   Wins over the visible `.rc-table caption` rule by naming both. */
.rc-sr-only,
.rc-table caption.rc-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Badge ─────────────────────────────────────────────────────────────────
   The label is always primary ink. Colouring 12px text with an accent token
   was the tempting version, but --rc-warning and --rc-success-top land at
   4.3:1 and 3.9:1 on the light bands — under AA for text that size. The
   variant, when there is one, belongs on the border and the tint. */
.rc-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px 12px;
  border: 1px solid var(--rc-line-strong);
  border-radius: var(--radius-pill);
  background: var(--rc-band-panel);
  color: var(--rc-text-primary);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  /* A badge wraps rather than running off the page. `white-space: nowrap` is
     right for the two or three words a badge normally holds, and it was wrong
     for the trust strip, which used to put whole sentences in one — a pill
     wide enough to scroll every comparison page sideways. The trust strip is
     ticked text now and no longer a caller here, so the two remaining
     callers — the industry filter tags and the card meta rows — are both short
     by construction. The cap stays anyway: it costs nothing on a chip that
     already fits, and it is the difference between a long tag wrapping and a
     long tag reopening that scrollbar. */
  max-width: 100%;
}

/* A badge that is actionable stops being a label and has to meet the target
   floor like any other control. */
a.rc-badge,
button.rc-badge {
  min-height: 44px;
  padding-inline: var(--space-4);
  text-decoration: none;
}

/* ── Mock ──────────────────────────────────────────────────────────────────
   Stands in for a React demo that has no PHP equivalent. The aspect-ratio and
   min-height reserve the space up front, so the page never reflows around it,
   and the blueprint grid says "placeholder" without pretending to be a
   screenshot of a product that would then be wrong. */
.rc-mock {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-3);
  /* width before ratio: with only a min-height and an aspect-ratio, the box
     solves for width — 260px tall at 16/10 is 416px wide, which overflowed a
     390px viewport by 46px on all 222 pages carrying a mock. Pinning the width
     makes the ratio decide height, and min-height only raises it. */
  width: 100%;
  max-width: 100%;
  aspect-ratio: var(--rc-mock-ratio, 16 / 10);
  min-height: 260px;
  padding: calc(38px + var(--space-6)) var(--space-6) var(--space-6);
  overflow: hidden;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-panel);
  background-color: var(--rc-band-panel);
  background-image:
    linear-gradient(var(--rc-line-soft) 1px, transparent 1px),
    linear-gradient(90deg, var(--rc-line-soft) 1px, transparent 1px);
  background-size: 32px 32px;
  background-position: center;
}

/* Title bar. Absolutely positioned, so it paints above in-flow content — the
   children below are lifted back over it rather than the bar being pushed
   into the flow, which would fight the reserved aspect-ratio. */
.rc-mock::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 38px;
  border-bottom: 1px solid var(--rc-line);
  background: var(--rc-band-deep);
}

.rc-mock::after {
  content: "";
  position: absolute;
  inset-inline-start: var(--space-4);
  top: 15px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rc-line-strong);
  box-shadow:
    16px 0 0 var(--rc-line-strong),
    32px 0 0 var(--rc-line-strong);
}

.rc-mock > * {
  position: relative;
  z-index: var(--z-raised);
}

.rc-mock h2,
.rc-mock h3,
.rc-mock .rc-card__title {
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--rc-text-primary);
}

.rc-mock p {
  max-width: 52ch;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--rc-text-secondary);
}

/* ── Breadcrumbs ───────────────────────────────────────────────────────────
   The links carry the 44px floor even though the trail is small type; the row
   ends up thumb-height on mobile, which is the point. */
.rc-breadcrumbs {
  font-size: 0.8125rem;
  color: var(--rc-text-disabled);
}

.rc-breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-breadcrumbs li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.rc-breadcrumbs li + li::before {
  content: "/";
  color: var(--rc-text-disabled);
}

/* min-width as well as min-height: a crumb reading "Home" is only 35px of
   text, and half a target is still a missed tap. */
.rc-breadcrumbs a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--rc-text-secondary);
  text-decoration: none;
}

.rc-breadcrumbs a:hover {
  color: var(--rc-text-blue);
  text-decoration: underline;
}

.rc-breadcrumbs [aria-current="page"] {
  color: var(--rc-text-primary);
}

/* ── Section spacing ───────────────────────────────────────────────────────
   Every block the app puts under a section heading opens with `mt-12`, and the
   two that follow a control row open with `mt-10`. Carried on the block rather
   than on the heading, because a section without a heading still wants the
   same air above its content. */
.rc-grid,
.rc-rows,
.rc-path-list,
.rc-steps {
  margin-top: var(--space-12);
}

/* The row of buttons that closes a section — `mt-9 flex flex-wrap gap-4`. */
.rc-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-top: 36px;
}

/* `mt-10`, for the two places the app opens the row a notch lower: the
   conversion panel and the industry grid's link to the index. */
.rc-actions--wide {
  margin-top: var(--space-10);
}

.rc-actions--center {
  justify-content: center;
}

/* A single button standing on its own at the end of a column — `mt-9` with no
   row around it, which is the shape the developer band has. */
.rc-btn--spaced {
  margin-top: 36px;
}

/* The trailing arrow. `inc/icons.php` writes a 20px box into the markup and
   the app draws this one glyph at 14, 15, 16 and 20px depending on what it
   sits in, so the size comes from the context rather than from the icon. */
.rc-arrow {
  flex: none;
}

.rc-btn svg {
  flex: none;
  width: 15px;
  height: 15px;
  transition: transform var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-btn:hover svg {
  transform: translateX(2px);
}

@media (prefers-reduced-motion: reduce) {
  .rc-btn svg {
    transition: none;
  }

  .rc-btn:hover svg {
    transform: none;
  }
}

/* A plain accent link with an arrow — the hero's developer link. 14px medium,
   not a button, and it keeps the target floor through a transparent overlay
   rather than by growing: it sits in a row beside two 44px buttons that are
   already setting the row's height, so growing it would change nothing a
   finger can reach and would push the text off the buttons' baseline. */
.rc-text-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.25rem;
  color: var(--rc-text-blue);
  text-decoration: none;
}

.rc-text-link::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

.rc-text-link svg {
  flex: none;
  width: 15px;
  height: 15px;
}

.rc-eyebrow--purple {
  color: var(--rc-purple-highlight);
}

/* The comparison table's third column labels its own side "Legacy" in the
   quiet ink, so the eyebrow above RapidCents is the only one reading as an
   accent. */
.rc-eyebrow--muted {
  color: var(--rc-text-disabled);
}

/* The code panel is the one section whose heading carries its own bottom
   margin — `mb-10` — because the panel below it has no top margin of its own. */
.rc-h2--mb10 {
  margin-bottom: var(--space-10);
}

/* The trust badge row's heading: 18px semibold and centred, not the 20–24px
   left-aligned h3 the theme was drawing. */
.rc-badges__title {
  margin-bottom: 28px;
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.75rem;
  letter-spacing: var(--rc-tracking-heading);
  text-align: center;
  color: var(--rc-text-primary);
}

/* ── Developer band ────────────────────────────────────────────────────────
   Copy against the API demo. `mt-4` under the eyebrow, matching the app, with
   the eyebrow giving up its own bottom margin so the two do not stack; the
   bullet list opens `mt-8` and the button `mt-9`, which `.rc-actions` already
   carries. */
.rc-dev-copy .rc-eyebrow {
  margin-bottom: 0;
}

.rc-dev-copy .rc-h2 {
  margin-top: var(--space-4);
}

.rc-dev-copy .rc-list {
  margin-top: var(--space-8);
}

.rc-dev-panel {
  min-width: 0;
}

/* ── Path selector ─────────────────────────────────────────────────────────
   A divided list, not a grid of cards. The app numbers each answer in tabular
   figures, sets the question at 20px and pushes an arrow to the right edge;
   the theme was drawing four bordered cards two-up, which is a different block
   entirely and the one a reader notices first after the bullets.

   The number is a counter rather than typed digits, so a reordered path list
   renumbers itself — the same reason `.rc-steps` uses one. */
.rc-path-list {
  margin-block: var(--space-12) 0;
  padding: 0;
  list-style: none;
  border-block: 1px solid var(--rc-line);
  counter-reset: rc-path;
}

.rc-path-list > li {
  counter-increment: rc-path;
}

.rc-path-list > li + li {
  border-top: 1px solid var(--rc-line);
}

.rc-path {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-block: 28px;
  color: inherit;
  text-decoration: none;
  transition: background-color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-path:hover {
  background-color: rgba(120, 200, 255, 0.03);
  color: inherit;
}

@media (min-width: 640px) {
  .rc-path {
    flex-direction: row;
    align-items: center;
    gap: var(--space-8);
  }
}

.rc-path__index {
  flex: none;
  width: 48px;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.25rem;
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-disabled);
}

.rc-path__index::before {
  content: counter(rc-path, decimal-leading-zero);
}

.rc-path__copy {
  min-width: 0;
  flex: 1;
}

/* Reading face, not the display one, and no tracking: this is a `<span>` in
   the app rather than a heading, so it never picks up the `h1..h4` rule that
   sets Manrope and -0.028em everywhere else. */
.rc-path__title {
  display: block;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.75rem;
  color: var(--rc-text-primary);
}

.rc-path__body {
  display: block;
  max-width: 60ch;
  margin-top: 6px;
  color: var(--rc-text-secondary);
}

.rc-path__arrow {
  flex: none;
  width: 20px;
  height: 20px;
  color: var(--rc-text-blue);
  transition: transform var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-path:hover .rc-path__arrow {
  transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
  .rc-path,
  .rc-path__arrow {
    transition: none;
  }

  .rc-path:hover .rc-path__arrow {
    transform: none;
  }
}

/* ── Divided rows ──────────────────────────────────────────────────────────
   Two columns of hairline-topped rows, with no box around anything — the
   feature list and the quote wall. The app sets a 64px column gutter and no
   row gutter at all: the hairline is what separates one row from the next, and
   a row gap would put a gap in the rule. */
.rc-rows {
  display: grid;
  grid-template-columns: 1fr;
  column-gap: var(--space-16);
  margin-block: var(--space-12) 0;
  padding: 0;
  list-style: none;
}

.rc-rows > * {
  min-width: 0;
}

@media (min-width: 768px) {
  .rc-rows {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.rc-row {
  padding-block: 28px;
  border-top: 1px solid var(--rc-line);
}

.rc-row__title {
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.75rem;
  letter-spacing: var(--rc-tracking-heading);
  color: var(--rc-text-primary);
}

.rc-row__body {
  max-width: 60ch;
  margin-top: var(--space-2);
  font-size: 0.9375rem;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

.rc-row__body + .rc-row__body {
  margin-top: var(--space-4);
}

/* Quotes take a taller row and a wider attribution block. */
.rc-row--quote {
  padding-block: var(--space-8);
}

.rc-quote {
  font-size: 0.9375rem;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

/* The lead quote is set larger and in primary ink, so a wall of testimonials
   has somewhere to start rather than reading as an undifferentiated block. */
.rc-row--quote:first-child .rc-quote {
  font-size: 1.25rem;
  color: var(--rc-text-primary);
}

.rc-quote__by {
  display: block;
  margin-top: var(--space-5);
  font-size: 0.875rem;
  line-height: 1.25rem;
}

.rc-quote__name {
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-quote__role {
  display: block;
  color: var(--rc-text-disabled);
}

/* ── Stats ─────────────────────────────────────────────────────────────────
   The figure is the one element in this band a reader is meant to look at, and
   the theme was setting it at 20 to 24px against the app's flat 36. Monospace
   and tabular, so a row of four figures lines its digits up.

   The cells are separated by a rule from `lg` rather than by a gap: the app
   gives each 32px of side padding, zeroes it on the first, and hairlines
   between them. */
.rc-stats {
  display: grid;
  grid-template-columns: 1fr;
  margin: 0;
}

.rc-stats > * {
  min-width: 0;
}

@media (min-width: 640px) {
  .rc-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .rc-stats {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .rc-stats:has(> :nth-child(3):last-child) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .rc-stats:has(> :nth-child(5)) {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

.rc-stats-band {
  position: relative;
  overflow: hidden;
  /* Midnight island in both palettes. The figures used to re-pin their text
     tokens to near-white and then sit on `.rc-section--band`, which reads
     `--rc-band-deep` from the page. In light mode that token is #eef2fa, so
     the RapidBridge proof row (and every other stats band) painted white
     type on a pale ground. Re-pin the surface with the text, the way
     `.rc-cinema` and `.rc-cta-panel` already do. */
  --rc-bg-midnight: #010526;
  --rc-band-deep: #01072c;
  --rc-text-primary: #f7f9ff;
  --rc-text-financial: #f8faff;
  --rc-text-secondary: #cdd9f6;
  --rc-text-disabled: #7085bc;
  --rc-line: rgba(120, 200, 255, 0.16);
  color: var(--rc-text-primary);
  color-scheme: dark;
  background: var(--rc-band-deep);
}

.rc-stats-band::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(57, 232, 255, 0.55),
    transparent
  );
}

.rc-stats__tile {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 2rem 0;
}

@media (min-width: 640px) {
  .rc-stats__tile {
    padding: 1.75rem 2rem;
  }

  .rc-stats__tile:nth-child(odd) {
    padding-left: 0;
  }

  .rc-stats__tile:nth-child(n + 3) {
    border-top: 1px solid var(--rc-line);
  }
}

@media (min-width: 1024px) {
  .rc-stats__tile {
    padding: 0.5rem 2.5rem;
  }

  .rc-stats__tile:first-child {
    padding-left: 0;
  }

  .rc-stats__tile:nth-child(n + 3) {
    border-top: 0;
  }

  .rc-stats__tile + .rc-stats__tile::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.5rem;
    bottom: 0.5rem;
    width: 1px;
    background: var(--rc-line);
  }
}

.rc-stats__index {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-disabled);
}

.rc-stats__value {
  margin: 0.75rem 0 0;
  font-family: var(--font-mono);
  font-size: clamp(2.1rem, 3.8vw, 3.15rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--rc-text-financial);
}

.rc-stats__value::after {
  content: "";
  display: block;
  width: 2.5rem;
  height: 1px;
  margin-top: 1rem;
  background: linear-gradient(90deg, rgba(17, 217, 232, 0.95), transparent);
}

.rc-stats__label {
  margin: 1rem 0 0;
  max-width: 18ch;
  font-size: 0.9375rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  line-height: 1.35;
  color: var(--rc-text-secondary);
}

.rc-contact {
  display: grid;
  gap: 2rem;
}

@media (min-width: 1024px) {
  .rc-contact {
    grid-template-columns: minmax(0, 1fr) 280px;
    align-items: start;
  }
}

.rc-contact__form-wrap,
.rc-contact__aside,
.rc-contact--sent {
  padding: 1.5rem;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card, 16px);
  background: var(--rc-band-deep);
}

@media (min-width: 640px) {
  .rc-contact__form-wrap {
    padding: 2rem;
  }
}

.rc-contact__eyebrow {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rc-text-blue);
}

.rc-contact__form-wrap h2,
.rc-contact--sent h2 {
  margin: 0.5rem 0 0;
}

.rc-contact__lead,
.rc-contact--sent p {
  margin: 0.5rem 0 0;
  max-width: 52ch;
  color: var(--rc-text-secondary);
}

.rc-contact__error {
  margin: 1rem 0 0;
  color: var(--rc-danger-border, #ff6b6b);
}

.rc-contact__grid {
  display: grid;
  gap: 0 1.25rem;
}

@media (min-width: 640px) {
  .rc-contact__grid {
    grid-template-columns: 1fr 1fr;
  }
}

.rc-contact__field {
  margin: 1.25rem 0 0;
}

.rc-contact__field label {
  display: block;
  margin-bottom: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--rc-text-primary);
}

.rc-contact .rc-input {
  width: 100%;
  min-height: 48px;
  padding: 0.75rem 1rem;
  border: 1px solid var(--rc-secondary-border, var(--rc-line));
  border-radius: var(--rc-radius-input, 16px);
  background: var(--rc-band-raised, transparent);
  color: var(--rc-text-primary);
}

.rc-contact textarea.rc-input {
  min-height: 8rem;
  resize: vertical;
}

.rc-contact__hp {
  position: absolute;
  left: -9999px;
  height: 0;
  width: 0;
  overflow: hidden;
}

.rc-contact__form {
  position: relative;
}

.rc-contact__form .rc-btn {
  margin-top: 1.5rem;
}

.rc-contact__aside {
  background: transparent;
}

.rc-contact__aside-title {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-contact__aside ul {
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}

.rc-contact__aside li + li {
  margin-top: 1rem;
}

.rc-contact__aside strong {
  display: block;
  color: var(--rc-text-primary);
}

.rc-contact__aside a {
  color: var(--rc-text-blue);
}

/* ── Conversion CTA ────────────────────────────────────────────────────────
   An inset midnight panel, not a pale band. This is the brightest moment on
   any page in the app and the theme was drawing it as another tinted stripe
   with navy type — a difference of a third of the colour cube on the heading,
   and the single most visible thing on the home page after the bullets.

   The panel is a midnight island in both palettes, so it re-pins the tokens its
   children read the way `.rc-promo-panel` does: everything inside is
   light-on-dark whichever way the page is themed. (The hero panel used to be
   the other example here. It no longer is — the hero story flips with the page
   rather than staying midnight, so it carries its own `--hs-*` palette
   instead.) */
.rc-cta-panel {
  --rc-text-primary: #f7f9ff;
  --rc-text-secondary: rgba(255, 255, 255, 0.88);
  --rc-text-blue: #78c8ff;
  --rc-line: rgba(120, 200, 255, 0.16);
  --rc-line-strong: rgba(44, 203, 255, 0.38);
  --rc-band-panel: rgba(8, 32, 116, 0.42);

  position: relative;
  overflow: hidden;
  padding: 56px var(--space-6);
  border: 1px solid rgba(49, 226, 255, 0.38);
  border-radius: var(--radius-3xl);
  /* The first two layers stand in for the pair of blurred discs the app floats
     over the panel — `h-72 w-72` at `-left-24 top-1/2` and `-right-20 -top-10`,
     both `blur-3xl`. A blurred disc and a radial stop are the same picture, and
     one of them does not need two more elements or an animation. */
  background:
    radial-gradient(circle 200px at 48px 50%, rgba(0, 140, 255, 0.32), transparent 70%),
    radial-gradient(circle 190px at calc(100% - 48px) 18px, rgba(49, 226, 255, 0.22), transparent 70%),
    radial-gradient(ellipse 95% 85% at 12% 48%, rgba(0, 140, 255, 0.48) 0%, transparent 58%),
    radial-gradient(ellipse 75% 65% at 92% 22%, rgba(49, 226, 255, 0.32) 0%, transparent 54%),
    radial-gradient(circle at 50% 115%, rgba(1, 80, 234, 0.58) 0%, transparent 44%),
    linear-gradient(152deg, #010526 0%, #011362 28%, #0038cd 58%, #0150ea 82%, #0128a7 100%);
  box-shadow:
    0 28px 90px rgba(0, 56, 205, 0.38),
    0 0 48px rgba(49, 226, 255, 0.12);
  color: var(--rc-text-primary);
  text-align: center;
}

@media (min-width: 640px) {
  .rc-cta-panel {
    padding: 64px var(--space-10);
  }
}

@media (min-width: 1024px) {
  .rc-cta-panel {
    padding: 80px var(--space-16);
  }
}

/* The blueprint grid, masked to fade out before it reaches the border. */
.rc-cta-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
  background-size: 44px 44px;
  -webkit-mask-image: radial-gradient(ellipse at center, #000000 15%, transparent 72%);
  mask-image: radial-gradient(ellipse at center, #000000 15%, transparent 72%);
}

/* A highlight along the top edge and a shadow along the bottom, so the panel
   reads as lit from above rather than as a flat rectangle of gradient. */
.rc-cta-panel::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(
      90deg,
      transparent,
      rgba(126, 232, 255, 0.75),
      transparent
    ) top / 100% 1px no-repeat,
    linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.07) 0%,
      transparent 32%,
      transparent 68%,
      rgba(0, 5, 31, 0.28) 100%
    );
}

.rc-cta-panel__inner {
  position: relative;
  z-index: var(--z-raised);
  max-width: 48rem;
  margin-inline: auto;
}

@media (min-width: 1024px) {
  .rc-cta-panel__inner {
    max-width: 56rem;
  }
}

/* The pill above the heading. Its own rule rather than `.rc-badge`, because a
   badge is a label on a light band and this one is a lit chip on midnight. */
.rc-cta-panel__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
  padding: 6px var(--space-4);
  border: 1px solid rgba(49, 226, 255, 0.45);
  border-radius: var(--radius-pill);
  background: rgba(0, 140, 255, 0.18);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: #9ef0ff;
}

.rc-cta-panel__eyebrow::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--rc-cyan-400);
  box-shadow: 0 0 8px var(--rc-cyan-400);
}

/* `--rc-tracking-heading`, not the `tracking-tight` the app's markup asks for.
   That utility never lands: `globals.css` sets the tracking on a bare `h1, h2,
   h3, h4` outside any cascade layer, and an unlayered rule beats every Tailwind
   utility whatever its specificity. The app renders this at -0.028em. */
.rc-cta-panel__title {
  font-family: var(--font-display);
  font-size: clamp(1.875rem, 4.2vw, 2.875rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: var(--rc-tracking-heading);
  text-wrap: balance;
  color: #ffffff;
}

.rc-cta-panel .rc-lead {
  max-width: 42rem;
  margin-inline: auto;
  margin-top: var(--space-5);
  line-height: 1.625;
  color: rgba(255, 255, 255, 0.88);
}

/* The reassurance row under the buttons. Flex rather than the grid the trust
   strip uses: these are three short phrases centred as a group, not four
   columns. */
.rc-cta-panel__trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2) var(--space-6);
  margin: var(--space-8) 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  color: rgba(255, 255, 255, 0.72);
}

.rc-cta-panel__trust > li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.rc-cta-panel__trust .rc-trust-strip__check {
  color: var(--rc-success-border);
}

/* ── Hero trust row ────────────────────────────────────────────────────────
   The assurances sit in their own hairlined strip under the hero, not inside
   the copy column. The theme used to print them as a bulleted list beside the
   panel, which is why the hero ran 60px taller and the strip below it did not
   exist. */
.rc-hero__trust {
  border-top: 1px solid var(--rc-line);
}

.rc-hero__trust-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-8);
  padding-block: var(--space-5);
  /* `margin-block`, not the `margin` shorthand. The <ul> carries `.rc-container`
     as well, and the shorthand resets that rule's `margin-inline: auto` — which
     left the assurance row flush to the left edge of a full-bleed section while
     the hero copy above it stayed centred: 43px out at 1366, 80px at 1440 and
     320px at 1920. Only the browser's own block margins on a <ul> need going. */
  margin-block: 0;
  list-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  color: var(--rc-text-secondary);
}

.rc-hero__trust-list > li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ── Fee check panel ───────────────────────────────────────────────────────
   The right-hand column of the fee check band: the surface, in the same glass
   the hero's visual uses, with the band's call to action inside it. What it
   must not do is what it used to: drop the column entirely and leave the band
   with no conversion surface at all.

   This block used to say that the app's rotating sample profiles had no PHP
   equivalent and that the panel therefore showed one static figure. That is no
   longer true and must not be reinstated: `assets/js/theme.js` now carries the
   walk from `apps/web/lib/savings-profiles.ts` and the `.rc-savings-ticker`
   block at the end of this file dresses it. This rule is the panel; the ticker
   is what goes in it, and it deliberately draws no surface of its own so the
   two do not stack into a card inside a card. */
.rc-promo-panel {
  --rc-text-primary: #f7f9ff;
  --rc-text-secondary: #cdd9f6;
  --rc-text-blue: #78c8ff;
  --rc-line: rgba(120, 200, 255, 0.16);
  --rc-line-strong: rgba(44, 203, 255, 0.38);

  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: 28px;
  border: 1px solid rgba(44, 203, 255, 0.42);
  border-radius: var(--rc-radius-card);
  /* The three glass stops are the app's `.rc-glass-panel`'s, and they are
     translucent — 0.72 / 0.62 / 0.7. That panel sits on a midnight band, so they
     composite dark; this one sits on `.rc-section--ice`, which is #e8f1fd in
     the light palette, and the band came through. The panel measured
     rgb(78, 104, 180), and the eyebrow — `--rc-text-blue`, re-pinned above to
     the dark-palette #78c8ff — landed at 2.9:1 against it, well under AA for
     11px text. The opaque base is what the alpha was always assuming: the same
     surface token the bottom stop is drawn from, so the glass composites over
     midnight on either band and the panel keeps the drawing it declares its
     tokens for. */
  background:
    linear-gradient(
      180deg,
      rgba(12, 47, 157, 0.72),
      rgba(6, 31, 130, 0.62),
      rgba(1, 26, 119, 0.7)
    ),
    var(--rc-surface-bottom);
  box-shadow:
    inset 0 1px 0 rgba(223, 249, 255, 0.14),
    0 16px 48px rgba(0, 5, 31, 0.4);
  color: var(--rc-text-secondary);
}

@media (min-width: 640px) {
  .rc-promo-panel {
    padding: var(--space-8);
  }
}

.rc-promo-panel__figure {
  margin: 0;
  font-family: var(--font-mono);
  font-size: clamp(2rem, 4vw, 2.75rem);
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-primary);
}

.rc-promo-panel__note {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--rc-text-secondary);
}

.rc-promo-panel .rc-actions {
  margin-top: var(--space-5);
}

/* ═══════════════════════════════════════════════════════════════════════════
   6. CHROME
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Header ────────────────────────────────────────────────────────────────
   Opaque by default and translucent only where backdrop-filter exists —
   without the filter a 0.82-alpha bar just lets body copy show through it.

   At the very top of the page the app's header has no surface at all: it is
   `bg-transparent` until 24px of scroll and only then becomes the glass bar
   with a shadow. So the theme's header carried a hairline across the top of
   every page that the app does not, which is the difference between the two
   screenshots above the fold.

   The app does that with a scroll listener and React state. Here it is a
   scroll-driven animation, for two reasons: a class added by theme.js could
   only be added after the script runs, which is after first paint, so every
   page would flash a glass bar and then drop it; and making transparency the
   default would leave a reader with scripts off a sticky nav with page copy
   running underneath it. Browsers without scroll timelines keep the glass bar
   they have now, which is the correct floor rather than a broken one. */
.rc-header {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background: var(--rc-band-base);
  border-bottom: 1px solid var(--rc-line);
}

@supports ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .rc-header {
    background: var(--rc-header-bg);
    -webkit-backdrop-filter: blur(20px);
    backdrop-filter: blur(20px);
  }
}

@supports (animation-timeline: scroll()) {
  .rc-header {
    animation: rc-header-settle linear both;
    animation-timeline: scroll(root block);
    /* The app flips at 24px of scroll; over a range rather than at a point,
       because a scroll timeline has no notion of a threshold and 24px of
       crossfade is indistinguishable from the app's 300ms one. */
    animation-range: 0 24px;
  }

  @keyframes rc-header-settle {
    from {
      background: transparent;
      border-bottom-color: transparent;
      box-shadow: none;
    }

    to {
      background: var(--rc-band-base);
      border-bottom-color: var(--rc-line);
      box-shadow: var(--rc-shadow-md);
    }
  }

  @supports ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
    @keyframes rc-header-settle {
      from {
        background: transparent;
        border-bottom-color: transparent;
        box-shadow: none;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
      }

      to {
        background: var(--rc-header-bg);
        border-bottom-color: var(--rc-line);
        box-shadow: var(--rc-shadow-md);
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
      }
    }
  }
}

/* Its own container, and deliberately not .rc-container: the app's header is
   `max-w-[1440px] px-4 sm:px-6 lg:px-8` — a wider measure than the page body,
   on a smaller gutter — while the body below stays on .rc-container's 1280.
   Matching the body's 1280/48 here would pull the logo and the actions 32px in
   from where the app puts them. The steps below are those three Tailwind
   gutters, not a clamp, so the two agree at every width and not just at the
   ends. The second rule cancels the padding if the PHP ever wraps this in a
   container, so the two never stack. */
.rc-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  max-width: var(--content-wide);
  min-height: var(--rc-header-h);
  margin-inline: auto;
  padding-inline: 16px;
}

@media (min-width: 640px) {
  .rc-header__inner {
    padding-inline: 24px;
  }
}

@media (min-width: 1024px) {
  .rc-header__inner {
    padding-inline: 32px;
  }
}

.rc-container > .rc-header__inner {
  max-width: none;
  padding-inline: 0;
}

.rc-header__logo {
  display: inline-flex;
  align-items: center;
  flex: none;
  /* `gap-3` on the app's logo link, and from 1536px there are two children to
     separate: the lockup and the brand slogan. Below that the slogan is
     display:none and the gap has nothing to act on, so this is free everywhere
     else. Without it the slogan's left hairline sits against the wordmark. */
  gap: var(--space-3);
  min-height: 44px;
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 800;
  letter-spacing: var(--rc-tracking-heading);
  color: var(--rc-text-primary);
  text-decoration: none;
}

/* Hidden below the mega-menu breakpoint; .rc-mobile-nav carries navigation
   there, so nothing is unreachable at any width. */
.rc-header__nav {
  display: none;
}

/* Hidden below 1024, as the app's is. Every page was 329px wide in a 320px
   window — a 9px sideways scroll on all fifty of them — because the logo, this
   cluster and the menu button together needed 313px inside a 288px content box.
   The app carries nothing here but the logo and the menu button.

   The theme toggle inside it moved into the phone panel rather than
   disappearing with the cluster: it is the only theme control on the page, and
   the app can drop its own because it has no phone theme control to lose.

   `margin-inline-start: auto` still earns its place from 1024 up, where the nav
   is centred and this needs pushing to the end of the row. */
.rc-header__actions {
  display: none;
  align-items: center;
  flex: none;
  gap: var(--space-3);
  margin-inline-start: auto;
}

@media (min-width: 1024px) {
  .rc-header__actions {
    display: flex;
  }
}

@media (min-width: 1024px) {
  /* Centred between the logo and the actions rather than parked beside the
     logo, which is where the app puts it and the first thing that reads as a
     different header at a glance. */
  .rc-header__nav {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 auto;
    min-width: 0;
  }

  /* The template emits <nav class="rc-header__nav"><ul>…</ul></nav>, so the
     list is a child rather than the element itself. Flexing only the wrapper
     leaves the items stacked with bullets — which is exactly how this shipped
     the first time. Both are flexed so either structure lays out. */
  .rc-header__nav > ul {
    display: flex;
    align-items: center;
    /* 4px read as a single run-on word in the header. The trigger's own padding
       supplies part of the rhythm, so the gap is the remainder rather than the
       whole of it. */
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
  }
}

/* ── Mega menu ─────────────────────────────────────────────────────────────
   position:relative on the item, so the panel resolves against its own trigger
   and hangs from it as a card. It was static, which resolved the panel against
   .rc-header (sticky counts as positioned) and stretched it edge to edge across
   the viewport — a 1920px band of menu over a 1080px card in the app, which is
   the difference the client photographed. */
.rc-nav__item {
  position: relative;
  display: flex;
  align-items: center;
}

.rc-nav__item > a,
.rc-nav__item > button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  /* 44, not the app's 36: a header control has to meet the touch-target floor
     and the app does not. Nothing else about the trigger differs, and because
     it is vertically centred in an 80px bar the extra 8px is invisible — it
     puts the panel 3px lower than the app's and nothing else. */
  min-height: 44px;
  padding-inline: var(--space-3);
  border-radius: var(--radius-md);
  color: var(--rc-text-secondary);
  /* text-sm / leading-5. It shipped at 15/24 — a wider label, a wider nav, and
     a header that could not line up with the app's however the container was
     sized. Set again on the more specific rule near the end of this file. */
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition:
    color var(--rc-motion-fast) var(--rc-ease-premium),
    background-color var(--rc-motion-fast) var(--rc-ease-premium);
}

/* Colour only. A fill behind an open trigger reads as a selected tab, and the
   app changes nothing but the text. */
.rc-nav__item:hover > a,
.rc-nav__item:hover > button,
.rc-nav__item:focus-within > a,
.rc-nav__item:focus-within > button {
  color: var(--rc-text-primary);
}

/* A card centred on its trigger and sized to its content, which is what the
   app renders: 1080px for a wide menu, 920px for Solutions, a hairline border,
   a 16px radius and a shadow. `--rc-nav-panel-w` is the only thing the two
   sizes differ by.

   `--rc-panel-shift` is 0 here and stays 0 with scripts off, so the geometry
   without JavaScript is the app's geometry exactly. theme.js nudges it when a
   panel would otherwise hang past the viewport edge — which the app itself
   does at 1280 and 1440, where opening the last menu widens the document by
   118px and 38px and gives the page a horizontal scrollbar.

   Closed, it is display:none, and that is load-bearing rather than a style
   choice. `visibility: hidden` left the box in the layout, so five closed
   panels — each up to 1080px wide and centred on its own trigger — reached
   past the right edge of the window and the document was permanently wider
   than the viewport: 1388px in a 1280 window, 1468px in a 1440 one, with a
   horizontal scrollbar on every page whether or not anybody opened a menu.
   That is the "entire page is wide" in the client's screenshots, and the app
   does not have it because React hides a closed panel with the `hidden`
   attribute, which is display:none.

   The fade survives: `display` is in the transition list with
   `allow-discrete`, so the panel stays displayed for the whole fade out and
   is only then removed, and `@starting-style` gives it somewhere to fade in
   from. A browser without `allow-discrete` snaps instead, which is what the
   app does — it has no transition on this at all. */
.rc-nav__panel {
  --rc-nav-panel-w: 1080px;
  --rc-panel-shift: 0px;

  position: absolute;
  top: 100%;
  /* The nudge rides on `left`, not on the transform. `translate(calc(-50% +
     96px), …)` computes to a flat -50% in Chrome — the pixel term is dropped
     and the panel does not move — while `left` takes the same calc correctly.
     Measured, not assumed: the transform version reported matrix(1,0,0,1,-460)
     for a 920px panel at every shift value. */
  left: calc(50% + var(--rc-panel-shift));
  z-index: var(--z-nav);
  width: min(var(--rc-nav-panel-w), calc(100vw - 2rem));
  /* `max-h-[calc(100dvh-8rem)]` in MegaMenu.tsx: 8rem is the header plus the
     announcement ribbon above it, not the header alone. Measuring against the
     header only left the Products panel — which is the tallest, now that it
     carries the three terminal rows — with its last link under the fold and
     nothing to scroll it into view at a 900px window. `dvh` because the mobile
     URL bar is exactly the case this cap exists for; the `vh` line above it is
     what a browser without `dvh` reads. */
  max-height: calc(100vh - 8rem);
  max-height: calc(100dvh - 8rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-xl);
  /* Opaque, and deliberately so even though the app's card is white at 0.96
     over a 24px backdrop blur. Both render as flat white in the app, because
     the blur turns whatever is behind into an even wash that 96% white then
     covers — but a backdrop-filter only samples inside the nearest backdrop
     root, and this panel's nearest one is .rc-header, which carries a blur of
     its own. Copying the alpha without the blur that hides it put the hero
     headline through the menu at 4%, legibly. Measured, not assumed. */
  background: var(--rc-band-raised);
  box-shadow: var(--rc-nav-panel-shadow);
  display: none;
  opacity: 0;
  transform: translate(-50%, -8px);
  transition:
    opacity var(--rc-motion-standard) var(--rc-ease-premium),
    transform var(--rc-motion-standard) var(--rc-ease-premium),
    display var(--rc-motion-standard) var(--rc-ease-premium) allow-discrete;
}

/* Three ways in, and the first two are the no-JavaScript floor. BOTH of them
   are gated on `:root:not(.rc-js)`, because the React header opens a menu on
   CLICK and on nothing else — `DesktopNav.tsx` has no hover opener at all, and
   `onMouseEnter` there only cancels a pending close.

   Hover-to-open was the larger of the two defects. A panel opened by the
   pointer left `aria-expanded="false"` on its trigger, so a screen reader
   announced a collapsed control with 24 links live in the tab order behind it,
   and Escape had no `.is-open` to find. It also meant a pointer crossing the
   header on its way somewhere else dropped a 1,080px card over the page.

   Focus-within was the same shape of problem: the trigger is inside the <li>,
   so :focus-within is true for as long as the trigger holds focus, and a panel
   that opens on its own trigger's focus can never be closed by Escape or by a
   second press — closeAllMenus() returns focus to the trigger, and the trigger
   re-opens it. Measured at 1440 with the pointer parked away from the header,
   Escape left display:block and aria-expanded="false" on a panel with 24 links
   in the tab order.

   With scripts off, both stay: hover opens, and tabbing to the trigger opens
   and lets the next Tab land inside. That is what makes the menu operable
   without this theme's JavaScript, and it is why they are written as plain
   rules that need nothing. */
:root:not(.rc-js) .rc-nav__item:hover > .rc-nav__panel,
:root:not(.rc-js) .rc-nav__item:focus-within > .rc-nav__panel,
.rc-nav__item > [aria-expanded="true"] ~ .rc-nav__panel {
  display: block;
  opacity: 1;
  transform: translate(-50%, 0);
}

@starting-style {
  :root:not(.rc-js) .rc-nav__item:hover > .rc-nav__panel,
  :root:not(.rc-js) .rc-nav__item:focus-within > .rc-nav__panel,
  .rc-nav__item > [aria-expanded="true"] ~ .rc-nav__panel {
    opacity: 0;
    transform: translate(-50%, -8px);
  }
}

/* The wide menus: a featured rail, then the link columns beside it. */
.rc-nav__panel-inner {
  display: flex;
  gap: var(--space-8);
  padding: 20px var(--space-8);
}

.rc-nav__columns {
  /* Declared here as well as read below. The template writes the real count
     inline — `style="--rc-nav-columns:4"` — and an inline declaration wins over
     this one, so the default only ever applies to a panel the template did not
     count. Written out because a var() naming a property nothing declares is
     the defect this theme has shipped before, and a fallback inside the var()
     hides it from every mechanical check. */
  --rc-nav-columns: 3;

  display: grid;
  flex: 1 1 auto;
  min-width: 0;
  gap: var(--space-6);
  grid-template-columns: repeat(var(--rc-nav-columns, 3), minmax(0, 1fr));
}

/* The app's columns are `space-y-0.5` under a heading with `mb-2`: two pixels
   between links, eight under the heading. The theme ran the links flush and
   added four under the heading, which is a column eight pixels shorter over
   seven links — and because the promoted rail stretches to the column, eight
   pixels shorter everywhere. Scoped to the columns so the phone panel, which
   uses .rc-nav__group for a <details>, keeps its own spacing. */
.rc-nav__columns .rc-nav__group {
  gap: 0;
}

.rc-nav__columns .rc-nav__group ul {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.rc-nav__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.rc-nav__group > h2,
.rc-nav__group > h3,
.rc-nav__group > h4 {
  margin-bottom: var(--space-2);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-text-disabled);
}

/* `flex-direction: row`, and this is load-bearing. It was `column`, which no
   rule anywhere overrode: the more specific `.rc-nav__item > button` rule set
   `display: inline-flex` but never a direction, so every trigger stacked its
   chevron underneath its label and grew to 64px, and every link in a panel
   stacked its icon above its text. The stacking that is wanted — a label with
   a line of copy beneath it — is .rc-nav__text's, one level in.

   Negative inline margin lets the hover fill bleed past the text without
   pushing the column off the panel's grid line. */
.rc-nav__link {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  margin-inline: calc(var(--space-3) * -1);
  border-radius: var(--radius-md);
  color: var(--rc-text-primary);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  transition:
    background-color var(--rc-motion-fast) var(--rc-ease-premium),
    color var(--rc-motion-fast) var(--rc-ease-premium);
}

/* A trigger and a top-level link keep their label and chevron on one line
   whatever the header has left to give them. */
.rc-nav__link--top {
  white-space: nowrap;
}


.rc-nav__link:hover,
.rc-nav__link:focus-visible {
  background-color: var(--rc-band-panel);
  color: var(--rc-text-blue);
}

.rc-nav__link > span,
.rc-nav__link > small {
  font-size: 13px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--rc-text-secondary);
}

/* ── Mobile navigation ─────────────────────────────────────────────────────
   Markup this is written for: <details><summary class="rc-mobile-toggle">
   <nav class="rc-mobile-nav">. With scripts off the browser opens and closes
   it natively. If the theme swaps in a <button aria-expanded>, the two
   attribute rules below take over. If neither is present the nav is simply a
   visible list, which is the correct no-JS floor — so nothing here may emit
   `hidden` server-side. */
.rc-mobile-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-width: 44px;
  min-height: 44px;
  padding-inline: var(--space-3);
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-md);
  background: none;
  color: var(--rc-text-primary);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  /* Below 1024 the nav and actions are display:none, so the bar is just the
     logo and this button. Without margin-inline-start:auto they sit together
     on the left; the app puts the hamburger on the far right. */
  margin-inline-start: auto;
}

.rc-mobile-toggle::-webkit-details-marker {
  display: none;
}

.rc-mobile-toggle:hover {
  border-color: var(--rc-line-strong);
}

/* Absolutely positioned against .rc-header for the same reason the mega panel
   is: the toggle usually lives inside .rc-header__actions, and a nav left in
   that flex row collapses to the width of its widest word — a 23px column of
   wrapped links with unhittable targets. */
.rc-mobile-nav {
  position: absolute;
  inset-inline: 0;
  top: 100%;
  z-index: var(--z-nav);
  display: block;
  max-height: calc(100vh - var(--rc-header-h));
  padding: var(--space-4) clamp(20px, 4vw, 48px) var(--space-8);
  overflow-y: auto;
  overscroll-behavior: contain;
  border-top: 1px solid var(--rc-line);
  background: var(--rc-band-raised);
  box-shadow: var(--rc-shadow-lg);
}

.rc-mobile-toggle[aria-expanded="false"] + .rc-mobile-nav {
  display: none;
}

.rc-mobile-toggle[aria-expanded="true"] + .rc-mobile-nav {
  display: block;
}

.rc-mobile-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-mobile-nav a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-block: var(--space-2);
  border-bottom: 1px solid var(--rc-line-soft);
  color: var(--rc-text-primary);
  font-size: 1rem;
  font-weight: 500;
  text-decoration: none;
}

.rc-mobile-nav a:hover {
  color: var(--rc-text-blue);
}

/* Second-level links step in and drop to reading weight, so the hierarchy is
   readable even when every group is expanded at once. */
.rc-mobile-nav ul ul a {
  padding-inline-start: var(--space-4);
  font-size: 0.9375rem;
  font-weight: 400;
  color: var(--rc-text-secondary);
}

.rc-mobile-nav summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  padding-block: var(--space-2);
  border-bottom: 1px solid var(--rc-line-soft);
  font-size: 1rem;
  font-weight: 600;
  color: var(--rc-text-primary);
  cursor: pointer;
  list-style: none;
}

.rc-mobile-nav summary::-webkit-details-marker {
  display: none;
}

.rc-mobile-nav summary::after {
  content: "";
  width: 9px;
  height: 9px;
  border-right: 2px solid var(--rc-text-blue);
  border-bottom: 2px solid var(--rc-text-blue);
  transform: rotate(45deg);
  transition: transform var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-mobile-nav details[open] > summary::after {
  transform: rotate(-135deg);
}

/* !important is the one place it earns its keep: it has to beat the
   [aria-expanded="true"] rule above, which is a more specific selector. */
@media (min-width: 1024px) {
  .rc-mobile-toggle,
  .rc-mobile-nav {
    display: none !important;
  }
}

/* ── Theme and locale controls ─────────────────────────────────────────────
   Pill-shaped, hairline, no fill: they are chrome, not calls to action, and
   the page has exactly one filled button family. */
.rc-theme-toggle,
.rc-locale-switcher > summary,
.rc-locale-switcher > button,
.rc-locale-switcher select {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-width: 44px;
  min-height: 44px;
  padding-inline: var(--space-3);
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--rc-text-secondary);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  transition:
    border-color var(--rc-motion-fast) var(--rc-ease-premium),
    color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-theme-toggle::-webkit-details-marker,
.rc-locale-switcher > summary::-webkit-details-marker {
  display: none;
}

.rc-theme-toggle:hover,
.rc-locale-switcher > summary:hover,
.rc-locale-switcher > button:hover,
.rc-locale-switcher select:hover {
  border-color: var(--rc-line-strong);
  color: var(--rc-text-primary);
}

.rc-theme-toggle svg,
.rc-locale-switcher svg {
  width: 16px;
  height: 16px;
}

.rc-locale-switcher {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/* The panel. The template emits a <div> with a <button> and a <ul>, so the
   list has to be hidden here rather than by <details> — an unstyled <ul> in the
   header renders as a visible bulleted list beside the logo, which is how this
   shipped the first time. Shown on .is-open for the scripted path and on
   :focus-within so keyboard users reach it with JavaScript off. */
.rc-locale-switcher > ul {
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + var(--space-2));
  z-index: var(--z-overlay);
  min-width: 200px;
  margin: 0;
  padding: var(--space-2);
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
  background: var(--rc-band-raised);
  box-shadow: var(--rc-shadow-lg);
  list-style: none;
}

.rc-locale-switcher > ul a {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  padding-inline: var(--space-3);
  border-radius: var(--radius-md);
  color: var(--rc-text-primary);
  font-size: 14px;
  text-decoration: none;
}

.rc-locale-switcher > ul a:hover {
  background: var(--rc-band-panel);
  color: var(--rc-text-blue);
}

.rc-locale-switcher > ul {
  visibility: hidden;
  opacity: 0;
  transform: translateY(-4px);
  transition:
    visibility var(--rc-motion-fast) var(--rc-ease-premium),
    opacity var(--rc-motion-fast) var(--rc-ease-premium),
    transform var(--rc-motion-fast) var(--rc-ease-premium);
}

/* `:focus-within` is the no-JavaScript floor and carries the same `rc-js` gate
   the mega menu's panels carry, for the same measured reason: the button is
   inside `.rc-locale-switcher`, so focus-within is true for as long as the
   button holds focus, and a list opened that way cannot be closed by Escape or
   by pressing the button again — closeAllMenus() returns focus to the button,
   which re-opens it. With scripts running, aria-expanded is the only opener and
   it is then always true exactly when the list is on screen. */
.rc-locale-switcher.is-open > ul,
:root:not(.rc-js) .rc-locale-switcher:focus-within > ul {
  visibility: visible;
  opacity: 1;
  transform: none;
}


/* ── Mega-menu contents ────────────────────────────────────────────────────
   The panel's own lists arrive as plain <ul>, so without this they render with
   the browser's default markers and indent — the small open circles that make a
   considered menu look like an unstyled document. */
.rc-nav__panel ul,
.rc-nav__group ul,
.rc-mobile-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-nav__panel .rc-nav__link {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 10px;
  min-height: 0;
  padding: 10px;
  margin-inline: 0;
  border-radius: var(--radius-md);
  text-decoration: none;
}

.rc-nav__panel .rc-nav__link:hover,
.rc-nav__panel .rc-nav__link:focus-visible {
  background: var(--rc-band-blue);
}

/* The column heading. .rc-eyebrow is brand blue at 11px, which is right for a
   section lead-in on a page and too loud for eighteen of them stacked in a
   menu; the app sets these in the muted text colour. */
.rc-nav__group-title {
  margin-bottom: var(--space-2);
  color: var(--rc-text-secondary);
  font-size: 12px;
  /* Pinned, because this composes `.rc-eyebrow` and that class is 700 to match
     the app's section lead-in. The app's menu column heading is a different
     element — `text-xs font-semibold uppercase tracking-wider` in
     `MegaMenu.tsx`, carrying no eyebrow class at all — and eighteen of these
     stacked in a panel at 700 is a menu shouting its own headings. */
  font-weight: 600;
  line-height: 16px;
  /* .rc-eyebrow's --rc-tracking-label is 0.14em, which at 11px is 1.54px and
     reads as a spaced-out caps line. The app sets tracking-wider, 0.05em. */
  letter-spacing: 0.05em;
}

.rc-nav__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.rc-nav__text strong {
  color: var(--rc-text-primary);
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
}

.rc-nav__text span {
  color: var(--rc-text-secondary);
  font-size: 12px;
  line-height: 1.375;
}

/* Muted, and this is the app's choice rather than a compromise: eighteen blue
   glyphs down a menu compete with the eighteen labels beside them, and the app
   draws them in --rc-muted, which is this theme's --rc-text-secondary. The
   promoted card's icon is the exception and stays blue, below. */
.rc-nav__icon {
  flex: none;
  margin-top: 0;
  color: var(--rc-text-secondary);
}

/* ── The terminals rail ────────────────────────────────────────────────────
   Three photographs down the left of the Products panel, under the featured
   cards and inside the same column — `MegaMenu.tsx:154-193` puts them there,
   not in a fourth flex column.

   THE HEIGHT IS THE WHOLE RULE. Read out of the three WebP headers rather than
   assumed from the folder: rivo-go-front is 1086x1448, rivo-link-front is
   1024x1536 and rivo-touch-front is 1122x1402 — exactly 3:4, exactly 2:3, and
   561:701, which is a hair wider than 4:5 and reduces no further. Three
   different shapes, and the third is not the round number it looks like, so do
   not "tidy" it to 4:5 in a width. There is no one intrinsic size to
   declare, so the markup declares a nominal 33x44 box only to reserve space,
   and `height: 44px; width: auto` is what gives each model its own width off
   its own ratio. Constraining the width instead would make the tall one short
   and the wide one tall, and the three rows would not line up. `h-11 w-auto
   object-contain` in the app, which is the same thing said in utilities. */
.rc-nav__devices {
  display: flex;
  flex-direction: column;
}

/* `mt-1` in the app, and only when a featured card precedes it — the rail's own
   12px gap already separates them, and this is the extra 4px on top of it. A
   devices-only menu (no featured card) gets no leading margin. */
.rc-nav__featured + .rc-nav__devices {
  margin-top: var(--space-1);
}

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

/* Three selectors deep on purpose. `.rc-nav__panel .rc-nav__link` sets the
   link-column row — top-aligned, 10px padding, no border — and a device row is
   a different shape: centred on a 44px photograph, with a transparent border
   that the hover state colours in rather than adds. */
.rc-nav__panel .rc-nav__link.rc-nav__device {
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-lg);
}

.rc-nav__panel .rc-nav__link.rc-nav__device:hover,
.rc-nav__panel .rc-nav__link.rc-nav__device:focus-visible {
  /* The fill comes from the shared row rule; this is the hairline the app adds
     on top of it, --rc-primary at 20%. */
  border-color: rgba(25, 125, 251, 0.2);
}

.rc-nav__device-photo {
  flex: none;
  height: 44px;
  width: auto;
  object-fit: contain;
}

/* ── The featured rail ─────────────────────────────────────────────────────
   Down the left of the panel and before the columns in the markup, which is
   where the app has it. It was rendered last, so it landed in the final cell
   of an auto-fit grid — on the right at four columns, and wrapped onto a
   second row at five — and stretched to the full height of the row. */
.rc-nav__featured-rail {
  display: flex;
  flex: none;
  flex-direction: column;
  gap: var(--space-3);
  width: 224px;
}

.rc-nav__featured {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
  /* The page base, not the raised white the panel itself is on — a card the
     same colour as the panel behind it is a border and nothing else, and the
     app tints this one so it reads as promoted. */
  background: var(--rc-band-base);
  text-decoration: none;
  transition:
    border-color var(--rc-motion-fast) var(--rc-ease-premium),
    background-color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-nav__featured:hover,
.rc-nav__featured:focus-visible {
  border-color: var(--rc-line-strong);
  background: var(--rc-band-blue);
}

/* The image the data has carried all along. A fixed height and object-fit
   rather than the file's own ratio, so two cards in one rail are the same size
   whatever art lands in them; 112px for a rail of one, 96px for a rail of two,
   which is the app's h-28 / h-24. */
.rc-nav__featured-media {
  display: block;
  flex: none;
  height: 112px;
  background: var(--rc-band-deep);
}

.rc-nav__featured-rail--stacked .rc-nav__featured-media {
  height: 96px;
}

.rc-nav__featured-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The icon is the fallback for a card with no picture — the Developers,
   Resources and Company menus each have one. */
.rc-nav__featured-icon {
  display: block;
  padding: var(--space-4) var(--space-4) 0;
}

/* The one nav icon that stays blue. It has to be set here rather than
   inherited: .rc-nav__icon carries its own colour, which beats the colour it
   would otherwise pick up from this wrapper. */
.rc-nav__featured-icon .rc-nav__icon {
  margin-top: 0;
  color: var(--rc-text-blue);
}

.rc-nav__featured-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-4) var(--space-4);
}

.rc-nav__featured strong {
  color: var(--rc-text-primary);
  font-size: 14px;
  font-weight: 600;
  line-height: 20px;
}

.rc-nav__featured:hover strong {
  color: var(--rc-text-blue);
}

.rc-nav__featured span {
  color: var(--rc-text-secondary);
  font-size: 12px;
  line-height: 1.625;
}

/* The class alone lost to `.rc-nav__featured span` — two classes to one — so
   the call to action rendered in the muted ink and read as a third line of
   description rather than as the link it is. The app draws it in the brand
   blue at medium weight, and it is the only part of the card that is not
   already the same in both. */
.rc-nav__featured .rc-nav__featured-cta {
  margin-top: var(--space-1);
  color: var(--rc-text-blue);
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
}

/* The arrow is a <span>, so the description rule above reaches it and set its
   line box to 1.625 — four pixels taller than the line it sits on, which grew
   the card, which grew the rail, which grew the panel. */
.rc-nav__featured .rc-nav__featured-cta span {
  font-size: inherit;
  line-height: inherit;
  color: inherit;
}

/* Inside a Solutions pane the same card runs the width of the pane instead of
   a 224px rail, so its picture is a band rather than a thumbnail. */
.rc-nav__featured--inline {
  margin-top: var(--space-4);
  border-radius: var(--radius-xl);
  /* A 5% wash rather than the solid blue band: the app promotes this card with
     a tint, and a solid band beside tinted cards reads as a different
     component rather than as the last card in the set. */
  background: rgba(25, 125, 251, 0.05);
}

.rc-nav__featured--inline .rc-nav__featured-media {
  height: 64px;
}

.rc-nav__featured--inline .rc-nav__featured-icon {
  padding: var(--space-3) var(--space-3) 0;
}

.rc-nav__featured--inline .rc-nav__featured-body {
  padding: var(--space-2) var(--space-3) var(--space-3);
}

/* ── Solutions: categories, then their cards ───────────────────────────────
   Three levels in the app and three here. Which category is showing is the one
   thing CSS cannot hold, so with scripts off every pane is open — a longer
   panel, every link reachable and in the tab order. theme.js adds the marker
   class below and from then on shows one. */
.rc-nav__panel--two {
  --rc-nav-panel-w: 920px;

  overflow: hidden;
  /* Square across the top and no top border: the app renders this one as a
     sheet pulled down out of the header rather than as a card floating under
     it, and the two read differently at a glance. --radius-2xl is the app's
     rounded-b-2xl, which is a step up from the 16px the other panels use. */
  border-top-width: 0;
  border-start-start-radius: 0;
  border-start-end-radius: 0;
  border-end-start-radius: var(--radius-2xl);
  border-end-end-radius: var(--radius-2xl);
}

.rc-nav__two {
  display: flex;
  min-height: 280px;
  max-height: min(460px, calc(100vh - var(--rc-header-h) - var(--space-6)));
}

.rc-nav__rail {
  display: flex;
  flex: none;
  flex-direction: column;
  width: 224px;
  padding-block: var(--space-2);
  overflow-y: auto;
  border-inline-end: 1px solid var(--rc-line);
  background: var(--rc-nav-rail-bg);
}

.rc-nav__rail-title {
  margin: 0;
  padding: var(--space-1) var(--space-4) var(--space-2);
  color: var(--rc-text-secondary);
  font-size: 10px;
  font-weight: 600;
  line-height: 1.5;
  /* Not --rc-tracking-label: 0.14em at 10px is 1.4px, which spaces four
     letters out into a line of its own. The app sets tracking-wider. */
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.rc-nav__cat {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1);
  width: 100%;
  min-height: 44px;
  padding: 10px var(--space-4);
  border: 0;
  background: none;
  color: var(--rc-text-primary);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
  text-align: start;
  cursor: pointer;
  transition:
    background-color var(--rc-motion-fast) var(--rc-ease-premium),
    color var(--rc-motion-fast) var(--rc-ease-premium);
}

/* A wash of the brand blue, not the opaque --rc-band-blue band, and the same
   two literals in both themes because the app's are: TwoLevelMegaMenu tints the
   category with the app's own primary token at 10% on hover and 15% on the
   selected one, and that token is #197dfb in the app's light AND dark palettes
   — measured, both report oklab(0.608302 -0.0447219 -0.202175 / 0.15) for the
   selected fill and the same colour at 4% for the rail. --rc-band-blue is #e8f1fd
   here, which composites 19 points lighter in red than the app's wash over the
   same rail, and it flips to #01144f in dark where the app does not flip at all.
   The rail underneath is already this literal at 4%; these are the same colour
   at the app's two other stops. Contrast is unaffected in the direction that
   matters: --rc-text-blue on the app's tint measures 4.69:1, still AA. */
.rc-nav__cat:hover {
  background: rgba(25, 125, 251, 0.1);
  color: var(--rc-text-blue);
}

/* Colour and fill only. The app does not thicken the selected category, and a
   weight change reflows the rail by a pixel or two every time the selection
   moves — which, on a menu that changes selection on hover, is visible. */
.rc-nav__cat.is-selected {
  background: rgba(25, 125, 251, 0.15);
  color: var(--rc-text-blue);
}

.rc-nav__panes {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
  padding: var(--space-4);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--rc-nav-well-bg);
}

.rc-nav__pane {
  display: flex;
  flex-direction: column;
}

.rc-nav__pane .rc-nav__group-title {
  margin-bottom: var(--space-3);
}

/* Only once theme.js has marked the container, so the no-JS floor is every
   pane on screen rather than every pane hidden. */
.rc-nav__two.is-enhanced .rc-nav__pane {
  display: none;
}

.rc-nav__two.is-enhanced .rc-nav__pane.is-selected {
  display: flex;
}

/* Persistent Solutions promo — the Rivo terminals card, after By industry in
   the left category rail rather than a column of its own on the right. */
.rc-nav__two-promo {
  display: flex;
  flex: none;
  flex-direction: column;
  width: auto;
  margin: var(--space-8) var(--space-2) 0;
  padding: 0;
  overflow: visible;
  border-inline-start: 0;
}

.rc-nav__two-promo .rc-nav__featured {
  flex: none;
}

.rc-nav__two-promo .rc-nav__featured-media {
  flex: none;
  height: 96px;
}

.rc-nav__cards {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.rc-nav__card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-xl);
  /* Tinted, on the tinted well: white cards on a white pane were a grid of
     borders where the app has a grid of cards. */
  background: var(--rc-band-base);
  text-decoration: none;
  transition:
    border-color var(--rc-motion-fast) var(--rc-ease-premium),
    background-color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-nav__card:hover,
.rc-nav__card:focus-visible {
  border-color: var(--rc-line-strong);
  background: var(--rc-band-blue);
}

.rc-nav__card-media {
  display: block;
  flex: none;
  height: 96px;
  background: var(--rc-band-deep);
}

.rc-nav__card-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.rc-nav__card-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--space-1);
  min-height: 44px;
  padding: var(--space-3);
}

/* 16px, not 14: the Solutions cards are the widest thing in any menu and the
   app sets their titles at the base size rather than at the size the narrow
   columns use. */
.rc-nav__card-body strong {
  color: var(--rc-text-primary);
  font-size: 16px;
  font-weight: 600;
  line-height: 24px;
}

.rc-nav__card:hover .rc-nav__card-body strong {
  color: var(--rc-text-blue);
}

.rc-nav__card-body span {
  color: var(--rc-text-secondary);
  font-size: 12px;
  line-height: 16px;
}

/* ── The account pair ──────────────────────────────────────────────────────
   Sign in and sign up read as one hairline control with a tint behind the
   second, which is what the app renders — not two ghost buttons that happen to
   be adjacent. */
.rc-nav__account {
  display: flex;
  align-items: center;
  padding: 2px;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-button);
  background: var(--rc-nav-account-bg);
}

/* 36 and 14/20, which is the app's `px-3 py-2 text-sm` exactly, and the pill
   around them is then 42 rather than 46. The drawn height is under the 44px
   floor on purpose: the touch target is carried by the shared
   `.rc-nav__account-link::after` overlay near the end of this file, which is
   already `max(100%, 44px)` in both axes. 40 was a halfway house that matched
   neither the app nor the floor while the overlay was doing the work anyway.
   The line-height has to be stated: without it these inherit the body's 1.6,
   which is 22.4px against the app's 20 and wraps a longer label a line early
   in French. */
.rc-nav__account-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  padding-inline: var(--space-3);
  border-radius: calc(var(--rc-radius-button) - 2px);
  color: var(--rc-text-secondary);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background-color var(--rc-motion-fast) var(--rc-ease-premium),
    color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-nav__account-link:hover {
  color: var(--rc-text-primary);
}

/* A wash of the brand blue over whatever the pill is on, not the opaque
   --rc-band-blue band: the pill itself is only a 4% tint, so an opaque chip
   inside it reads as a filled button rather than as the second half of one
   control. The hover was --rc-line-strong, which is a border colour at 32% —
   nearly twice the app's hover and the wrong role for a fill. */
.rc-nav__account-link--signup {
  background: var(--rc-nav-signup-bg);
  color: var(--rc-text-primary);
  font-weight: 600;
}

.rc-nav__account-link--signup:hover {
  background: var(--rc-nav-signup-bg-hover);
}

/* The app's header call to action is a bigger control than a body button:
   14/28 rather than 12/24, on a normal leading rather than a tight one, which
   is 51px tall against 44. It was the one thing in the action cluster that was
   visibly a different size from the app's. */
.rc-header__cta {
  padding: 14px 28px;
  line-height: 1.4286;
  white-space: nowrap;
}

.rc-content-hero {
  display: grid;
  gap: 2.5rem;
}

@media (min-width: 1024px) {
  .rc-content-hero {
    grid-template-columns: minmax(0, 1fr) minmax(22rem, 0.85fr);
    align-items: center;
    gap: 4rem;
  }
}

.rc-content-hero__photo {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--rc-radius-card);
  object-fit: cover;
  box-shadow: var(--rc-shadow-lg);
}

.rc-seo-figure {
  margin: 0;
}

.rc-seo-figure__caption {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--rc-text-secondary);
}

.rc-card--photo {
  padding: 0;
  overflow: hidden;
}

.rc-card--photo .rc-card__photo {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.rc-card--photo .rc-card__title,
.rc-card--photo .rc-card__body {
  padding-inline: var(--space-5);
}

.rc-card--photo .rc-card__title {
  padding-top: var(--space-5);
}

.rc-card--photo .rc-card__body {
  padding-bottom: var(--space-5);
}


/* ── Announcement bar ──────────────────────────────────────────────────────
   Sits above the header and scrolls away with the page: it is an announcement,
   not navigation, and pinning it would cost header height on every screen. */
/* The app builds this bar out of the same glass the mega panel uses — the
   `.rc-menu-panel` class is on both — so it shares the panel's token here for
   the same reason. It shipped as a blue band with a solid blue pill, which is
   a different component wearing the same words. */
/* 14/20 — text-sm, leading-5 — and the line-height has to be written down.
   Without it the bar inherits the body's 1.6, which is 22.4px on 14px text and
   makes the whole ribbon 40px tall where the app's is 37. */
.rc-announce {
  background: var(--rc-band-raised);
  border-bottom: 1px solid var(--rc-line);
  font-size: 14px;
  line-height: 20px;
}

@supports ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .rc-announce {
    background: var(--rc-menu-panel-bg);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }
}

/* Centred in the window, not inside the 1280 measure: the app puts this one
   line across the whole bar, so on a wide screen the theme's copy sat 320px
   in from where the app's does. */
.rc-announce__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-1) var(--space-3);
  padding-block: var(--space-2);
  padding-inline: var(--space-4);
  text-align: center;
}

/* A pale cyan chip with blue lettering, which is what the app draws. The tint
   is a literal because the app's is: it is the one colour in this bar that
   does not change between the light and dark themes. */
.rc-announce__pill {
  padding: 2px 10px;
  border-radius: var(--radius-sm);
  background: rgba(0, 191, 255, 0.14);
  color: var(--rc-text-blue);
  font-size: 12px;
  /* text-xs is 12/16, and the chip is the tallest thing in the bar — left on
     the inherited leading it sets the ribbon's height rather than the copy. */
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.025em;
  text-transform: uppercase;
}

.rc-announce__text {
  color: var(--rc-text-secondary);
}

.rc-announce__cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--rc-text-blue);
  font-weight: 600;
  text-decoration: none;
}

.rc-announce__cta:hover {
  text-decoration: underline;
}

.rc-announce__arrow {
  width: 14px;
  height: 14px;
  transition: transform var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-announce__cta:hover .rc-announce__arrow {
  transform: translateX(3px);
}

/* Below the mega-menu breakpoint the sentence is long enough to cost three
   lines of vertical space before the reader has seen anything. */
@media (max-width: 767px) {
  .rc-announce__text {
    display: none;
  }
}

/* ── Logo ──────────────────────────────────────────────────────────────────
   The app tile below 640px, the wordmark lockup from 640px up, and never both.

   `logo-lockup-color.png` already contains the mark — it is the C in "Cents" —
   so the icon-plus-lockup pairing this replaced drew the mark twice and read as
   "Rapid ents" with a stray glyph in front of it. `brand-logo.tsx` was rewritten
   for the same reason; `.rc-logo__icon` no longer exists in the markup and its
   rules are gone with it.

   640px rather than the header's own 1024px nav breakpoint, which is the app's
   choice and its reason: between the two the lockup has room to spare — the nav
   is already one button — and 640 is where "phone" actually ends.

   Both colourways of the lockup ship and CSS shows one, because the colour set
   carries a navy wordmark that vanishes on a dark background and swapping src
   in JavaScript would change the mark after first paint. The tile has no second
   colourway: it is the home-screen icon, it carries its own ground, and an app
   icon that changes colour with the page stops reading as the same icon.

   The tile ships with a `hidden` attribute so that a stylesheet which does not
   know these classes falls back to the lockup alone rather than to the doubling
   this block exists to remove — the same technique `.rc-mobile-nav` and the
   Solutions rail use, except that those two have their attribute REMOVED by
   `assets/js/theme.js` and this one keeps it for the life of the page.

   Which is why revealing it takes `!important` and a doubled selector, and both
   halves are load-bearing:

     `[hidden] { display: none !important }` further down this file, and the
     UA's own `[hidden]` rule on every current engine, are important author- and
     UA-origin declarations. A normal `display: inline-flex` here loses to both
     no matter how specific it is. Written that way the tile stayed hidden at
     every width — and below 640px `.rc-logo` is `display: none`, so the header,
     the footer and the phone panel carried no brand mark at all.

     `!important` alone is still not enough. `.rc-logo-tile` and `[hidden]` are
     both one selector unit, so an important declaration on each is a tie broken
     by source order, and `[hidden]` is ~1,450 lines below this. The attribute in
     the selector is what breaks the tie in the reveal's favour; the bare class
     is kept beside it for the case where something takes the attribute off. */
.rc-logo-tile,
.rc-logo-tile[hidden] {
  display: inline-flex !important;
}

.rc-logo-tile img {
  display: block;
  /* 38px — `markSize` in the app's header. The footer sets its own below. */
  width: 38px;
  height: 38px;
}

.rc-logo {
  display: none;
  align-items: center;
}

.rc-logo__word {
  display: block;
  width: auto;
  height: 26px;
}

@media (min-width: 640px) {
  /* Same two selectors and the same `!important` as the reveal above, because
     the reveal is important: a plain `display: none` here would lose to it and
     draw the tile beside the lockup — the exact doubling this block removes. */
  .rc-logo-tile,
  .rc-logo-tile[hidden] {
    display: none !important;
  }

  .rc-logo--light {
    display: inline-flex;
  }

  :root[data-theme="dark"] .rc-logo--light {
    display: none;
  }

  :root[data-theme="dark"] .rc-logo--dark {
    display: inline-flex;
  }
}

/* ── Brand slogan ──────────────────────────────────────────────────────────
   Two lines: the claim, and what the claim resolves to. They have to stay two
   lines, so every instance sets its own size rather than inheriting one.

   The header instance appears only from 1536px — Tailwind's 2xl, and the app's
   `hidden 2xl:flex`. The header is a fixed 80px bar holding the lockup, a
   nine-item nav and two buttons; anywhere narrower, two lines of brand copy come
   out of the navigation's budget. The footer instance carries no breakpoint
   guard at all — that is the one visitors actually read, and it is why the
   claim counts as visible on default load at every width. */
.rc-brand-slogan {
  display: flex;
  flex-direction: column;
  letter-spacing: -0.01em;
  line-height: 1.25;
}

.rc-brand-slogan__claim {
  color: var(--rc-text-primary);
  font-weight: 600;
}

.rc-brand-slogan__answer {
  color: var(--rc-text-blue);
  font-weight: 500;
}

/* One element where the app has two nested spans: the outer one carries the
   hairline and the padding, the inner one stacks the lines. Merged, because the
   outer span's own `gap-3` sits between the lines and a mark that this instance
   does not render. */
.rc-brand-slogan--beside {
  display: none;
  justify-content: center;
  padding-left: var(--space-3);
  border-left: 1px solid var(--rc-line);
  font-size: 0.8125rem;
}

/* The `[hidden]` half of this selector is gone with the attribute it existed to
   beat: chrome.php no longer prints `hidden` on the header slogan, because the
   attribute is the strongest way HTML has of saying "this is not meant to be
   seen" and an audit read it about the site's own tagline. `!important` stays —
   it costs nothing here and the rule it was written against,
   `[hidden] { display: none !important }`, is still at the end of this file for
   every other element that does carry the attribute. */
@media (min-width: 1536px) {
  .rc-brand-slogan--beside {
    display: flex !important;
  }
}

.rc-brand-slogan--footer {
  font-size: 0.9375rem;
}

.rc-brand-slogan--panel {
  font-size: 0.8125rem;
}

/* ── Nav trigger detail ────────────────────────────────────────────────────
   The caret is the only affordance saying a trigger opens something, so it
   turns with the panel rather than sitting still. */
.rc-nav__caret {
  flex: none;
  /* size-4 and the heading ink, which is what the app draws. It had no size of
     its own and fell back to 14px in the muted colour — a smaller, paler mark
     than the app's beside a label that is now the same size, which is exactly
     the kind of difference that reads as "not the same header" without anyone
     being able to name it. */
  width: 16px;
  height: 16px;
  margin-top: 0;
  color: var(--rc-text-primary);
  transition: transform var(--rc-motion-fast) var(--rc-ease-premium);
}

/* The caret turns when the panel is open, and follows exactly the same three
   conditions the panel does — including both halves of the `rc-js` gate, so a
   scripted header never shows a turned caret over a panel that did not open. */
:root:not(.rc-js) .rc-nav__item--mega:hover .rc-nav__caret,
:root:not(.rc-js) .rc-nav__item--mega:focus-within .rc-nav__caret,
.rc-nav__item--mega.is-open .rc-nav__caret,
.rc-locale-switcher.is-open .rc-nav__caret {
  transform: rotate(180deg);
}

.rc-header__nav > ul > li > .rc-nav__link {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-1);
  padding: 10px var(--space-3);
  margin-inline: 0;
  border-radius: var(--radius-md);
  background: none;
  border: 0;
  color: var(--rc-text-secondary);
  font-family: inherit;
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
}

.rc-header__nav > ul > li > .rc-nav__link:hover,
.rc-header__nav > ul > li > .rc-nav__link:focus-visible {
  color: var(--rc-text-primary);
}

/* The app steps the nav down below 1280 — gap-1 and px-2 rather than gap-2 and
   px-3 — and 1024 to 1279 is exactly the range where the header has the least
   room to give, so without this the theme's nav is the wider of the two at the
   only widths where that matters. */
@media (min-width: 1024px) and (max-width: 1279px) {
  .rc-header__nav > ul {
    gap: var(--space-1);
  }

  .rc-header__nav > ul > li > .rc-nav__link {
    padding-inline: var(--space-2);
  }
}

/* ── Theme toggle ──────────────────────────────────────────────────────────
   Both marks are in the markup; CSS shows whichever the current theme is not,
   because the control offers the other one. */
/* Selector written to beat `.rc-theme-toggle svg` further up, which is a class
   plus a type and so outranked the bare class this rule used to be: the sun and
   moon were drawn at that rule's 16px and never at the 18 declared here, which
   is the app's size. The locale switcher shares that rule and keeps its 16. */
.rc-theme-toggle .rc-theme-toggle__icon {
  width: 18px;
  height: 18px;
}

.rc-theme-toggle__icon--dark {
  display: none;
}

:root[data-theme="dark"] .rc-theme-toggle__icon--light {
  display: none;
}

:root[data-theme="dark"] .rc-theme-toggle__icon--dark {
  display: block;
}


/* ── Header at small widths ────────────────────────────────────────────────
   Measured at 390px the action cluster ran to 346px and pushed the hamburger
   to 557px, so the page scrolled sideways by 167px. Below the mega breakpoint
   the header keeps the logo, the one primary action and the menu control; sign
   in, sign up and the country switcher move into the panel, which is where a
   reader on a phone looks for them anyway. */
@media (max-width: 1023px) {
  .rc-header__inner {
    gap: var(--space-3);
  }

  .rc-header__actions {
    margin-inline-start: auto;
    gap: var(--space-2);
  }

  /* .rc-nav__account as well, and this was the whole of a 98px sideways
     scroll on every page at 390: the rule named .rc-btn--ghost, which is what
     sign in and sign up used to be, and was never updated when they became one
     pill. The cluster measured 202px against a 390px window with a 44px menu
     button beside it, so the document was 488px wide. Both are in the panel
     below, which is where the app puts them — it drops its whole desktop
     action cluster under lg. */
  .rc-header__actions .rc-locale-switcher,
  .rc-header__actions .rc-nav__account,
  .rc-header__actions .rc-btn--ghost {
    display: none;
  }
}

/* Narrower still, the primary CTA goes too and the menu carries everything. */
@media (max-width: 479px) {
  .rc-header__actions .rc-btn--primary {
    display: none;
  }
}

/* The controls the header dropped, restored inside the panel. */
.rc-mobile-nav__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding-block: var(--space-4);
  border-top: 1px solid var(--rc-line);
  margin-top: var(--space-4);
}

.rc-mobile-nav__actions .rc-locale-switcher {
  display: inline-flex;
}


/* ── Hero product story ────────────────────────────────────────────────────
   The panel `inc/hero-visual.php` prints, ported from
   `apps/web/components/sections/hero-visual.tsx`.

   What was here before drove a RETIRED component: five uniform 2.4s steps
   through "OmniCommerce", "$12,778", "Store #104" and "Awaiting payment", none
   of which occurs anywhere in `apps/web` or on any rendered page of the live
   site. The live hero is a three-act product story — a terminal sale is
   approved, the same payment appears across the dashboard, a payment link and
   an invoice, and then AI agents drive the same API through the MCP server — so
   the whole block is replaced rather than adjusted.

   ── The state machine ─────────────────────────────────────────────────────
   Nine phases grouped into three acts. Every phase's markup is in the document
   at once and `assets/js/theme.js` writes two attributes on the root; every
   rule below selects on them:

     data-rc-phase   the phase id: ready, processing, approved, dashboard,
                     paymentLink, invoice, agents, aiEnabled, complete
     data-rc-act     0, 1 or 2

   `.rc-hero-story__act[data-act]` cross-fades on the coarse grain and
   `.rc-hero-story__phase[data-phase]` on the fine one. `data-phase` holds a
   space-separated list, which is why every rule below matches it with `~=`: the
   act-two surface swap needs one node to span two phases — the laptop shows the
   dashboard through `dashboard paymentLink` and the invoice builder through
   `invoice`, off the same flag the React ternary branches on.

   `hidden` is deliberately NOT the mechanism, and `inc/hero-visual.php` says so
   too: `visibility` is what hides a phase here, so the transition has something
   to animate and the driver never has to fight the attribute.

   ── The floor ─────────────────────────────────────────────────────────────
   The root ships with neither attribute, so the `:not([data-rc-phase])` rules
   are what a visitor with JavaScript blocked sees: act one, phase `ready` — the
   frame the Next.js server renders, down to `aria-valuenow="1"` and the first
   rail segment filled. Under `prefers-reduced-motion` the same rules rest it on
   the completed frame instead, which is what the React component shows a
   reduced-motion visitor, and the "Motion reduced" badge appears with it. With
   scripts running the driver reaches the same two resting states by writing the
   attributes, so the two paths agree rather than merely coexist.

   ── Both themes ───────────────────────────────────────────────────────────
   Every colour is an `--hs-*` token, carried across from
   `apps/web/app/globals.css` with its dark counterpart. The theme-token
   re-point that used to sit on `.rc-hero` is gone with the rest of the old
   panel: this one is NOT a midnight island in a light page, it is a light panel
   that flips with the theme, and leaving that block in place would have put
   near-white text on the `#eef4fd` ground.

   Three surfaces deliberately do not flip, and they are hardcoded in the
   markup rather than tokenised here: the laptop screen, the phone screen and
   the flying credit card. They hold screenshots of a white product UI and a
   white card; inverting either would show a product that does not exist.

   ── Motion, and what it may touch ─────────────────────────────────────────
   Nothing in this section animates a layout property, which rules out three
   things the component does with framer-motion and forces a different spelling
   of each. They are marked where they occur:

     * the card that flies into the terminal animates `left` and `top`; here it
       is parked on its landing spot and travels by transform;
     * the sale panel's progress fill animates `width`; here it is a scaleX;
     * the typed titles animate `width` from zero to the text's own length;
       here the text is already its settled width and a clip uncovers it, which
       costs the caret its travel — see the note on `__typed-text`.

   The second rule is subtler and it is what a `visibility`-based phase machine
   makes easy to get wrong. An animation outranks a normal declaration, so a
   keyframe that sets `opacity` on a `.rc-hero-story__phase` node beats the
   cross-fade above for as long as that animation applies. What keeps that safe
   is not the property list but the SELECTOR: every animation on a phase-scoped
   node here is gated on a single `[data-rc-phase="…"]` value that the node's
   own `data-phase` list contains. The moment the driver writes a different
   phase the rule stops matching, the animation is removed, and the cross-fade
   is back in charge — `both` fill and all.

   Three rules rely on exactly that and would be bugs without it: the card's
   fly-in ends on `opacity: 0.96`, the phone's link card pops in from
   `opacity: 0`, and the typed titles animate a `clip-path`. What would pin a
   phase visible through all nine is an animation touching `opacity` gated on
   the coarse `[data-rc-act]` instead, because an act spans three phases. None
   of the act-gated animations here touches a phase node: they are the horizon,
   the laptop, the phone chassis, the connectors, the agent tiles and dots, and
   the hub — every one of them a node the phase machine does not select.

   ── One class here carries no rule ────────────────────────────────────────
   `__wire-group` is the `<g>` around each connector and its pulse. It exists
   to hold `--rc-hs-i`, the agent's index, which both children read for their
   stagger; it has no geometry of its own, exactly as in the component. Every
   other class `inc/hero-visual.php` prints is styled below. */

.rc-hero-story {
  --hs-ground: #eef4fd;
  --hs-wash:
    radial-gradient(circle at 18% 34%, rgba(8, 125, 255, 0.16), transparent 40%),
    radial-gradient(circle at 86% 22%, rgba(1, 80, 234, 0.1), transparent 32%),
    linear-gradient(150deg, #f6f9ff 0%, #e4edfb 56%, #eff4ff 100%);
  --hs-frame: #ccdbef;

  --hs-panel: rgba(255, 255, 255, 0.93);
  --hs-panel-border: #c6d6ec;
  --hs-panel-shadow: 0 18px 40px rgba(13, 21, 38, 0.14);

  --hs-ink: #0d1526;
  --hs-ink-secondary: #46556c;
  --hs-ink-muted: #5b6a80;
  --hs-ink-faint: #93a1b5;

  --hs-accent: #0b5fd0;
  --hs-accent-deep: #0a3f92;
  --hs-accent-glow: rgba(11, 95, 208, 0.45);
  --hs-accent-soft-ink: #0a4fae;

  /* #0aa356 put white on 3.29:1 under the approved checkmark, which the theme
     audit failed at AA. This is the same green two stops darker: 6.6:1 with
     white, and still unmistakably green where it is used as a dot or a bar. */
  --hs-success: #046b35;
  --hs-success-ink: #ffffff;
  --hs-success-text: #046b35;
  --hs-success-bg: rgba(223, 243, 230, 0.95);
  --hs-success-border: #86d6a8;
  --hs-success-glow: rgba(10, 163, 86, 0.28);

  --hs-track: rgba(13, 21, 38, 0.12);
  --hs-chip: rgba(13, 21, 38, 0.06);

  --hs-bloom: rgba(8, 125, 255, 0.12);
  --hs-bloom-strong: rgba(8, 125, 255, 0.16);
  --hs-horizon: rgba(8, 125, 255, 0.1);
  --hs-horizon-border: rgba(11, 95, 208, 0.18);

  --hs-badge: rgba(255, 255, 255, 0.9);
  --hs-badge-border: rgba(11, 95, 208, 0.28);

  --hs-card: linear-gradient(145deg, #ffffff, #e4eefb);
  --hs-card-border: #b9cbe4;

  --hs-chassis: linear-gradient(145deg, #dbe4f1, #b0c0d6);
  --hs-chassis-border: #a3b5cd;
  --hs-chassis-speaker: rgba(13, 21, 38, 0.22);
  --hs-hinge: linear-gradient(180deg, #c9d5e5, #93a4bd);
  --hs-hinge-notch: rgba(37, 50, 73, 0.3);

  --hs-tile: rgba(255, 255, 255, 0.97);
  --hs-tile-border: #c2d2e8;

  --hs-hub: rgba(255, 255, 255, 0.98);
  --hs-hub-border: rgba(11, 95, 208, 0.35);
  --hs-hub-glow: rgba(8, 125, 255, 0.22);

  --hs-drop: rgba(13, 21, 38, 0.18);
  --hs-pulse: #0b5fd0;

  position: relative;
  width: 100%;
  /* 5/4, and 1/1 from 640px. Not 4/3: the panel this replaced was 4/3 and the
     three acts do not fit it — act three puts four agent tiles at the corners
     of a square field with the hub in the middle. */
  aspect-ratio: 5 / 4;
  overflow: hidden;
  overflow: clip;
  border: 1px solid var(--hs-frame);
  border-radius: var(--radius-3xl);
  background: var(--hs-ground);
  box-shadow: var(--shadow-card);
  /* So the acts can size themselves against the panel rather than against the
     viewport. The panel sits in a half-width hero column on a laptop and
     full-bleed on a phone, and `vw` measures the wrong box in the first case. */
  container-type: inline-size;
  font-family: var(--font-sans);
}

@media (min-width: 640px) {
  .rc-hero-story {
    aspect-ratio: 1 / 1;
  }
}

:root[data-theme="dark"] .rc-hero-story {
  --hs-ground: #020822;
  --hs-wash:
    radial-gradient(circle at 18% 34%, rgba(8, 125, 255, 0.32), transparent 37%),
    radial-gradient(circle at 86% 22%, rgba(49, 226, 255, 0.16), transparent 30%),
    linear-gradient(145deg, #071b63 0%, #020822 54%, #06103d 100%);
  --hs-frame: rgba(49, 226, 255, 0.18);

  --hs-panel: rgba(4, 18, 66, 0.86);
  --hs-panel-border: rgba(255, 255, 255, 0.2);
  --hs-panel-shadow: 0 18px 50px rgba(0, 5, 31, 0.36);

  --hs-ink: #f7f9ff;
  --hs-ink-secondary: rgba(247, 249, 255, 0.65);
  --hs-ink-muted: rgba(247, 249, 255, 0.58);
  --hs-ink-faint: rgba(247, 249, 255, 0.35);

  --hs-accent: #31e2ff;
  --hs-accent-deep: #087dff;
  --hs-accent-glow: rgba(49, 226, 255, 0.75);
  --hs-accent-soft-ink: #93dfff;

  --hs-success: #18e86f;
  --hs-success-ink: #041e16;
  --hs-success-text: #7cffb0;
  --hs-success-bg: rgba(8, 43, 39, 0.9);
  --hs-success-border: rgba(124, 255, 176, 0.35);
  --hs-success-glow: rgba(24, 232, 111, 0.52);

  --hs-track: rgba(255, 255, 255, 0.14);
  --hs-chip: rgba(255, 255, 255, 0.1);

  --hs-bloom: rgba(8, 125, 255, 0.24);
  --hs-bloom-strong: rgba(8, 125, 255, 0.3);
  --hs-horizon: rgba(8, 125, 255, 0.12);
  --hs-horizon-border: rgba(49, 226, 255, 0.2);

  --hs-badge: rgba(6, 23, 79, 0.78);
  --hs-badge-border: rgba(115, 243, 255, 0.35);

  --hs-card: linear-gradient(145deg, #f8fbff, #dce9f8);
  --hs-card-border: rgba(255, 255, 255, 0.35);

  --hs-chassis: linear-gradient(145deg, #121b35, #020719);
  --hs-chassis-border: rgba(255, 255, 255, 0.18);
  --hs-chassis-speaker: rgba(255, 255, 255, 0.25);
  --hs-hinge: linear-gradient(180deg, #b8c5d5, #55657b);
  --hs-hinge-notch: rgba(37, 50, 73, 0.45);

  --hs-tile: rgba(255, 255, 255, 0.94);
  --hs-tile-border: rgba(255, 255, 255, 0.2);

  --hs-hub: rgba(247, 251, 255, 0.97);
  --hs-hub-border: rgba(115, 243, 255, 0.45);
  --hs-hub-glow: rgba(8, 125, 255, 0.42);

  --hs-drop: rgba(0, 5, 31, 0.42);
  --hs-pulse: #7cfff2;
}

/* ── Ground ──────────────────────────────────────────────────────────────── */

.rc-hero-story__wash {
  position: absolute;
  inset: 0;
  background: var(--hs-wash);
}

/* The curved horizon under the panel. It drifts while the story is playing and
   is still otherwise, which is what `animate={playing ? … : undefined}` does —
   so the attribute the driver writes is also what gates the animation, and a
   panel nobody is looking at is not animating anything. */
.rc-hero-story__horizon {
  position: absolute;
  inset-inline: -18%;
  bottom: -36%;
  height: 58%;
  border: 1px solid var(--hs-horizon-border);
  border-radius: 50%;
  background: var(--hs-horizon);
  filter: blur(24px);
}

.rc-hero-story[data-rc-act] .rc-hero-story__horizon {
  animation: rc-hero-story-horizon 4.2s ease-in-out infinite;
}

/* One glow per act, and each act puts it somewhere different: behind the
   terminal on the left, across the middle behind the laptop, and in the centre
   behind the hub. `blur-3xl` is 64px.

   The strong one is nested inside the agent stage in the component —
   `inset-x-[3%] top-0 bottom-[15%]` of the act — and `inc/hero-visual.php`
   prints it in the same place, as the first child of `.rc-hero-story__agents`.
   So its four percentages are copied from the component rather than converted
   into the act's coordinate space: an earlier pass here converted them for a
   parent this markup does not have, which moved the glow up seven points of
   the act and shrank it. Its parent is the stage, and the stage is the box
   these percentages already speak in. */
.rc-hero-story__bloom {
  position: absolute;
  left: 7%;
  top: 9%;
  width: 42%;
  height: 72%;
  border-radius: 999px;
  background: var(--hs-bloom);
  filter: blur(64px);
}

.rc-hero-story__bloom--wide {
  left: 8%;
  top: 22%;
  width: 66%;
  height: 54%;
}

.rc-hero-story__bloom--strong {
  left: 50%;
  top: 47%;
  width: 54%;
  height: 54%;
  transform: translate(-50%, -50%);
  background: var(--hs-bloom-strong);
}

/* ── Header: badge and act name ──────────────────────────────────────────── */

.rc-hero-story__header {
  position: absolute;
  inset-inline: 4%;
  top: 4%;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.rc-hero-story__badge {
  padding: 4px 8px;
  border: 1px solid var(--hs-badge-border);
  border-radius: 999px;
  background: var(--hs-badge);
  color: var(--hs-accent-soft-ink);
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  backdrop-filter: blur(12px);
}

.rc-hero-story__status {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--hs-ink-secondary);
  font-size: 7px;
  font-weight: 600;
}

.rc-hero-story__status-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--hs-success);
  box-shadow: 0 0 8px var(--hs-success-glow);
}

/* "Terminal · live product story", rewritten by the driver as the act changes.
   Truncated rather than wrapped: the header is one line beside a badge, and the
   French act names are the longest of the six. */
.rc-hero-story__act-name {
  overflow: hidden;
  min-width: 0;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (min-width: 640px) {
  .rc-hero-story__badge,
  .rc-hero-story__status {
    font-size: 9px;
  }
}

/* ── The three acts ──────────────────────────────────────────────────────── */

/* Every act occupies the same box, so they cross-fade in place. `visibility`
   rather than `display` so the fade has something to animate, and rather than
   opacity alone so a hidden act leaves the accessibility tree and the tab
   order — the React version unmounts them and this is the nearest equivalent.
   Transitioning `visibility` alongside `opacity` keeps the outgoing act
   rendered for the whole fade and only then removes it. */
.rc-hero-story__act {
  position: absolute;
  inset-inline: 0;
  top: 12%;
  bottom: 10%;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 360ms var(--rc-ease-premium),
    visibility 360ms var(--rc-ease-premium);
}

.rc-hero-story:not([data-rc-act]) .rc-hero-story__act[data-act="0"],
.rc-hero-story[data-rc-act="0"] .rc-hero-story__act[data-act="0"],
.rc-hero-story[data-rc-act="1"] .rc-hero-story__act[data-act="1"],
.rc-hero-story[data-rc-act="2"] .rc-hero-story__act[data-act="2"] {
  opacity: 1;
  visibility: visible;
}

/* The finer grain, inside an act. `data-phase` takes a space-separated list, so
   `~=` is what matches one name in it and a surface can span several phases. */
.rc-hero-story__phase {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 260ms var(--rc-ease-premium),
    visibility 260ms var(--rc-ease-premium);
}

.rc-hero-story:not([data-rc-phase]) .rc-hero-story__phase[data-phase~="ready"],
.rc-hero-story[data-rc-phase="ready"] .rc-hero-story__phase[data-phase~="ready"],
.rc-hero-story[data-rc-phase="processing"] .rc-hero-story__phase[data-phase~="processing"],
.rc-hero-story[data-rc-phase="approved"] .rc-hero-story__phase[data-phase~="approved"],
.rc-hero-story[data-rc-phase="dashboard"] .rc-hero-story__phase[data-phase~="dashboard"],
.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__phase[data-phase~="paymentLink"],
.rc-hero-story[data-rc-phase="invoice"] .rc-hero-story__phase[data-phase~="invoice"],
.rc-hero-story[data-rc-phase="agents"] .rc-hero-story__phase[data-phase~="agents"],
.rc-hero-story[data-rc-phase="aiEnabled"] .rc-hero-story__phase[data-phase~="aiEnabled"],
.rc-hero-story[data-rc-phase="complete"] .rc-hero-story__phase[data-phase~="complete"] {
  opacity: 1;
  visibility: visible;
}

/* The act-two surface swap. Both screenshots sit in the same frame inside the
   laptop lid and the phone screen; `.rc-hero-story__frame` is also a
   `.rc-hero-story__phase`, so the fade above is what moves between them. */
.rc-hero-story__frame {
  position: absolute;
  inset: 0;
}

.rc-hero-story__shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── Act one: the terminal ───────────────────────────────────────────────────
   `TerminalAct` and `TerminalStatus`. Every percentage in those two components
   is a percentage of the act box, and `.rc-hero-story__act` IS that box, so
   they transcribe one for one. Tailwind's `sm:` is 640px, the breakpoint this
   whole section already uses. Its spacing scale is 0.25rem, so `gap-1.5` is
   6px, `px-2.5` 10px, `h-7` 28px; its `rounded-lg` is 8px, `rounded-2xl` 16px.

   `.font-financial` in the app is `var(--font-jetbrains)`, which is this
   theme's `--font-mono`. */

/* `absolute bottom-[3%] left-[7%] h-[94%] w-[43%] sm:left-[10%] sm:w-[39%]`,
   and `animate={phase === "approved" ? { y: -3, scale: 1.015 } : …}` — written
   as a transform so the lift costs no layout. */
.rc-hero-story__terminal {
  position: absolute;
  left: 7%;
  bottom: 3%;
  width: 43%;
  height: 94%;
  transition: transform 340ms var(--rc-ease-premium);
}

@media (min-width: 640px) {
  .rc-hero-story__terminal {
    left: 10%;
    width: 39%;
  }
}

.rc-hero-story[data-rc-phase="approved"] .rc-hero-story__terminal {
  transform: translateY(-3px) scale(1.015);
}

/* `fill` + `object-contain` + `drop-shadow-[0_24px_22px_var(--hs-drop)]`. A
   filter, not a box-shadow: the terminal is a cut-out on transparency, so a
   shadow cast by its box would be a rectangle behind a photograph of a device.
   The global reset gives every img `height: auto`, which is why the height is
   restated here. */
.rc-hero-story__terminal-photo {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 24px 22px var(--hs-drop));
}

/* The card that flies into the terminal.

   React animates `left` 71% → 44% and `top` 17% → 22%. Both are layout
   properties, so the card is parked at its landing position here and the
   travel is a transform. The panel is a fixed-ratio inline-size container, so
   the two offsets convert exactly rather than approximately:

     x  27% of the act's width, and the act is `inset-x-0`      → 27cqw
     y   5% of the act's height. The act is `top: 12%; bottom: 10%`, so its
         height is 78% of the panel's, and the panel is 5/4 until 640px and
         1/1 after: 0.05 × 0.78 × 0.80 = 3.12cqw, then 0.05 × 0.78 = 3.9cqw. */
.rc-hero-story__card {
  --rc-hs-card-rise: 3.12cqw;

  position: absolute;
  left: 44%;
  top: 22%;
  z-index: 10;
  width: 24%;
  padding: 2.4%;
  border: 1px solid var(--hs-card-border);
  border-radius: 8px;
  background: var(--hs-card);
  box-shadow: 0 14px 30px var(--hs-drop);
  /* One of the three surfaces that do not flip with the theme — see the head
     of this section. A white card is drawn with its own ink. */
  color: #07133f;
  transform: rotate(-7deg);
}

@media (min-width: 640px) {
  .rc-hero-story__card {
    --rc-hs-card-rise: 3.9cqw;
  }
}

.rc-hero-story[data-rc-phase="ready"] .rc-hero-story__card {
  animation: rc-hero-story-card 620ms var(--rc-ease-premium) both;
}

/* The card settles at `opacity: 0.96`, not 1 — that is the last value of the
   fly-in and it is what `en-ca__home.html` carries in the server frame:
   `left:44%;top:22%;opacity:0.96;transform:rotate(-7deg)`. The animation ends
   there on its own, so this is only for the attribute-less floor, where the
   animation never runs and the reveal rule would otherwise leave it at 1. */
.rc-hero-story:not([data-rc-phase]) .rc-hero-story__card[data-phase] {
  opacity: 0.96;
}

/* React keeps the card mounted through `processing` and animates it to opacity
   0 there over 0.18s; `phase !== "approved"` is what finally unmounts it. That
   is why the node's phase list is `ready processing` rather than `ready`, and
   this is the fade.

   `[data-phase]` is on the selector to match the weight of the reveal rule
   above — `.rc-hero-story[data-rc-phase="processing"] .rc-hero-story__phase[data-phase~="processing"]`
   is four compound parts, and three would lose to it. Same weight, later in
   the file, so this wins; `visibility: visible` still comes from the reveal,
   which is what keeps the card rendered while it fades. */
.rc-hero-story[data-rc-phase="processing"] .rc-hero-story__card[data-phase] {
  opacity: 0;
  transition: opacity 180ms var(--rc-ease-premium);
}

.rc-hero-story__card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}

.rc-hero-story__card-mark {
  font-size: 9px;
  font-weight: 900;
  letter-spacing: -0.025em;
}

.rc-hero-story__card-wave {
  font-size: 10px;
  font-weight: 700;
  color: #0150ea;
}

/* `bg-[#6680a0]/35`. A span here and a div in the component, so it is
   blockified rather than assumed to be a block. */
.rc-hero-story__card-rule {
  display: block;
  width: 48%;
  height: 1px;
  margin-top: 18%;
  background: rgba(102, 128, 160, 0.35);
}

.rc-hero-story__card-mask {
  margin-top: 7%;
  color: #42566f;
  font-size: 6px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

@media (min-width: 640px) {
  .rc-hero-story__card-mark {
    font-size: 12px;
  }

  .rc-hero-story__card-wave {
    font-size: 14px;
  }

  .rc-hero-story__card-mask {
    font-size: 8px;
  }
}

/* The line from the terminal to the sale panel. */
.rc-hero-story__hairline {
  position: absolute;
  left: 39%;
  top: 31%;
  width: 16%;
  height: 1px;
  background: linear-gradient(to right, var(--hs-accent), transparent);
}

.rc-hero-story__panel {
  position: absolute;
  right: 5%;
  top: 28%;
  width: 43%;
  overflow: hidden;
  padding: 4%;
  border: 1px solid var(--hs-panel-border);
  border-radius: 16px;
  background: var(--hs-panel);
  box-shadow: var(--hs-panel-shadow);
  color: var(--hs-ink);
  backdrop-filter: blur(24px);
}

@media (min-width: 640px) {
  .rc-hero-story__panel {
    right: 7%;
    width: 40%;
  }
}

.rc-hero-story__panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  color: var(--hs-accent-soft-ink);
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.rc-hero-story__panel-chip {
  padding: 2px 6px;
  border-radius: 999px;
  background: var(--hs-chip);
  color: var(--hs-ink-muted);
}

@media (min-width: 640px) {
  .rc-hero-story__panel-head {
    font-size: 9px;
  }
}

/* `text-[clamp(18px,5.2vw,34px)]` — viewport units, copied as they are. This
   one number is deliberately NOT converted to the panel's container: it is
   type, and the component sizes it against the same viewport the `sm:` rules
   above it break on. */
.rc-hero-story__amount {
  margin-top: 5%;
  font-family: var(--font-mono);
  font-size: clamp(18px, 5.2vw, 34px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

/* `mt-[8%] min-h-[54px] sm:min-h-[66px]`. React mounts one status at a time
   inside an AnimatePresence; all three are in the document here, so they are
   stacked on each other and the box keeps the reserved height that stops the
   bar under them jumping between the three. */
.rc-hero-story__states {
  position: relative;
  margin-top: 8%;
  min-height: 54px;
}

@media (min-width: 640px) {
  .rc-hero-story__states {
    min-height: 66px;
  }
}

.rc-hero-story__state {
  position: absolute;
  inset-inline: 0;
  top: 0;
}

.rc-hero-story__state--row {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* `initial={{ opacity: 0, y: 8 }}`. The keyframes touch nothing but transform,
   so the opacity half of the entrance is still the phase cross-fade's and an
   off-phase state cannot be dragged back into view by its own animation. */
.rc-hero-story[data-rc-phase="ready"] .rc-hero-story__state[data-phase~="ready"],
.rc-hero-story[data-rc-phase="processing"] .rc-hero-story__state[data-phase~="processing"],
.rc-hero-story[data-rc-phase="approved"] .rc-hero-story__state[data-phase~="approved"] {
  animation: rc-hero-story-rise-8 200ms var(--rc-ease-premium) both;
}

.rc-hero-story__state-title {
  font-size: 10px;
  font-weight: 600;
}

.rc-hero-story__state-title--ok {
  color: var(--hs-success-text);
  font-size: 11px;
  font-weight: 700;
}

.rc-hero-story__state-hint {
  margin-top: 4px;
  color: var(--hs-ink-muted);
  font-size: 8px;
}

/* `mt-0.5` under the approved title against `mt-1` under the other two. */
.rc-hero-story__state-title--ok + .rc-hero-story__state-hint {
  margin-top: 2px;
}

@media (min-width: 640px) {
  .rc-hero-story__state-title {
    font-size: 12px;
  }

  .rc-hero-story__state-title--ok {
    font-size: 14px;
  }

  .rc-hero-story__state-hint {
    font-size: 10px;
  }
}

.rc-hero-story__spinner {
  flex: none;
  width: 20px;
  height: 20px;
  border: 2px solid var(--hs-track);
  border-top-color: var(--hs-accent);
  border-radius: 999px;
  animation: rc-hero-story-spin 600ms linear infinite;
}

@media (min-width: 640px) {
  .rc-hero-story__spinner {
    width: 24px;
    height: 24px;
  }
}

.rc-hero-story__tick {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: var(--hs-success);
  box-shadow: 0 0 22px var(--hs-success-glow);
  color: var(--hs-success-ink);
  font-size: 14px;
  font-weight: 900;
}

/* React pops this with a spring (stiffness 420, damping 20). CSS has no
   spring, so the panel's own ease carries the same 0.55 → 1 over a comparable
   beat; the overshoot is the part that is lost. */
.rc-hero-story[data-rc-phase="approved"] .rc-hero-story__tick {
  animation: rc-hero-story-pop 260ms var(--rc-ease-premium) both;
}

.rc-hero-story__bar {
  display: block;
  height: 4px;
  margin-top: 5%;
  overflow: hidden;
  border-radius: 999px;
  background: var(--hs-track);
}

/* 18% / 68% / 100%, as a scaleX rather than an animated width so the fill does
   not lay out on every frame. The pill caps are 2px wide at this height, so
   squashing them is not something the eye can resolve. */
.rc-hero-story__bar-fill {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background: var(--hs-accent);
  transform: scaleX(0.18);
  transform-origin: left center;
  transition:
    transform 360ms var(--rc-ease-premium),
    background-color 360ms var(--rc-ease-premium);
}

.rc-hero-story[data-rc-phase="processing"] .rc-hero-story__bar-fill {
  transform: scaleX(0.68);
}

.rc-hero-story[data-rc-phase="approved"] .rc-hero-story__bar-fill {
  background: var(--hs-success);
  transform: scaleX(1);
}

/* `x: [-12, 0, 10]` — it slides in past its mark and then drifts, so the
   resting transform is the +10 and the keyframes start behind it. */
.rc-hero-story__sent {
  position: absolute;
  right: 8%;
  bottom: 7%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid var(--hs-success-border);
  border-radius: 999px;
  background: var(--hs-success-bg);
  box-shadow: 0 0 22px var(--hs-success-glow);
  color: var(--hs-success-text);
  font-size: 8px;
  font-weight: 600;
  transform: translateX(10px);
}

@media (min-width: 640px) {
  .rc-hero-story__sent {
    font-size: 10px;
  }
}

.rc-hero-story[data-rc-phase="approved"] .rc-hero-story__sent {
  animation: rc-hero-story-sent 600ms var(--rc-ease-premium) both;
}

.rc-hero-story__sent-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--hs-success);
}

/* ── Act two: the connected workspace ────────────────────────────────────────
   `WorkspaceAct`, `Laptop` and `Phone`. Two surfaces here are hardcoded white
   in both themes — the laptop screen and the phone screen — because they hold
   screenshots of a white product UI. */

.rc-hero-story__ws-head {
  position: absolute;
  inset-inline: 6%;
  top: 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
}

.rc-hero-story__ws-head-main {
  min-width: 0;
}

.rc-hero-story__eyebrow {
  color: var(--hs-accent-soft-ink);
  font-size: 5px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

@media (min-width: 640px) {
  .rc-hero-story__eyebrow {
    font-size: 7px;
  }
}

/* `TypedLabel` and the box it sits in. React is two elements — an
   `inline-flex … font-mono` span inside a sized div — and the port prints one,
   so both sets of declarations land here. */
.rc-hero-story__typed {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
  height: 1.35em;
  margin-top: 4px;
  color: var(--hs-ink);
  font-family: var(--font-mono);
  font-size: clamp(13px, 3.8vw, 22px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.04em;
}

/* React animates the text's width 0 → `${text.length}ch`. Width is a layout
   property, so the reveal is a clip and `--rc-hs-chars` — the character count
   the template measures per locale, which is why it is an attribute and not a
   constant — sets the settled width instead, so the caret still lands hard
   against the last glyph. What this cannot reproduce is the caret travelling
   with the reveal: that needs the width itself to animate. The caret blinks in
   place while the text uncovers under it. */
.rc-hero-story__typed-text {
  position: relative;
  flex: none;
  display: block;
  width: calc(var(--rc-hs-chars, 0) * 1ch);
  overflow: hidden;
  white-space: nowrap;
}

.rc-hero-story__typed-caret {
  flex: none;
  display: block;
  width: 1px;
  height: 0.9em;
  margin-left: 2px;
  background: var(--hs-accent);
  box-shadow: 0 0 8px var(--hs-accent-glow);
  animation: rc-hero-story-caret 600ms linear infinite;
}

.rc-hero-story__step {
  padding: 4px 8px;
  border: 1px solid var(--hs-panel-border);
  border-radius: 999px;
  background: var(--hs-chip);
  color: var(--hs-ink-muted);
  font-size: 5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  white-space: nowrap;
}

@media (min-width: 640px) {
  .rc-hero-story__step {
    font-size: 7px;
  }
}

/* Act two prints all three titles and all three step chips; React mounts one
   of each. Hiding the other two with `visibility` is not enough here, because
   a hidden element still takes its place in the line — three titles would lay
   out end to end and push the caret to the far right, three chips would sit in
   a row. So the off-phase copies are taken out of flow and the current one is
   put back in it.

   The `:not([data-rc-phase])` arm rests the layout on `dashboard`, the first
   phase of this act, for the same reason the reveal rules rest on `ready`: a
   panel nobody is driving still has to lay out like a panel. */
.rc-hero-story__typed-text[data-phase],
.rc-hero-story__step[data-phase] {
  position: absolute;
}

.rc-hero-story:not([data-rc-phase]) .rc-hero-story__typed-text[data-phase~="dashboard"],
.rc-hero-story:not([data-rc-phase]) .rc-hero-story__step[data-phase~="dashboard"],
.rc-hero-story[data-rc-phase="dashboard"] .rc-hero-story__typed-text[data-phase~="dashboard"],
.rc-hero-story[data-rc-phase="dashboard"] .rc-hero-story__step[data-phase~="dashboard"],
.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__typed-text[data-phase~="paymentLink"],
.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__step[data-phase~="paymentLink"],
.rc-hero-story[data-rc-phase="invoice"] .rc-hero-story__typed-text[data-phase~="invoice"],
.rc-hero-story[data-rc-phase="invoice"] .rc-hero-story__step[data-phase~="invoice"] {
  position: relative;
}

/* The typing pass, and the same clip for act three's one-off line. */
.rc-hero-story[data-rc-phase="dashboard"] .rc-hero-story__typed-text[data-phase~="dashboard"],
.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__typed-text[data-phase~="paymentLink"],
.rc-hero-story[data-rc-phase="invoice"] .rc-hero-story__typed-text[data-phase~="invoice"],
.rc-hero-story[data-rc-phase="aiEnabled"] .rc-hero-story__typed--wide .rc-hero-story__typed-text {
  animation: rc-hero-story-type 340ms linear both;
}

.rc-hero-story[data-rc-phase="dashboard"] .rc-hero-story__step[data-phase~="dashboard"],
.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__step[data-phase~="paymentLink"],
.rc-hero-story[data-rc-phase="invoice"] .rc-hero-story__step[data-phase~="invoice"] {
  animation: rc-hero-story-drop 260ms var(--rc-ease-premium) both;
}

/* The positioned wrapper and the laptop's own `relative w-full` are one
   element here. */
.rc-hero-story__laptop {
  position: absolute;
  left: 4%;
  top: 25%;
  width: 72%;
}

@media (min-width: 640px) {
  .rc-hero-story__laptop {
    left: 6%;
    width: 69%;
  }
}

.rc-hero-story[data-rc-act="1"] .rc-hero-story__laptop {
  animation: rc-hero-story-laptop 400ms var(--rc-ease-premium) both;
}

.rc-hero-story__laptop-lid {
  padding: 1.8%;
  border: 1px solid var(--hs-chassis-border);
  border-radius: 10px 10px 0 0;
  background: var(--hs-chassis);
  box-shadow: 0 22px 48px var(--hs-drop);
}

.rc-hero-story__laptop-screen {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 5px;
  background: #ffffff;
}

/* `mx-auto w-[108%] -translate-x-[3.7%] rounded-b-[70%]` — wider than the lid
   on purpose, so the hinge reads as the machine's own edge rather than as a
   bar under a picture. */
.rc-hero-story__laptop-hinge {
  width: 108%;
  height: 8px;
  margin-inline: auto;
  border-radius: 0 0 70% 70%;
  background: var(--hs-hinge);
  box-shadow: 0 8px 10px var(--hs-drop);
  transform: translateX(-3.7%);
}

@media (min-width: 640px) {
  .rc-hero-story__laptop-hinge {
    height: 10px;
  }
}

.rc-hero-story__laptop-notch {
  display: block;
  width: 18%;
  height: 3px;
  margin-inline: auto;
  border-radius: 0 0 999px 999px;
  background: var(--hs-hinge-notch);
}

/* Both toasts sit on the white screenshot, so their ink is the screenshot's
   and not the theme's. */
.rc-hero-story__toast {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 6px;
  border: 1px solid;
  background: rgba(255, 255, 255, 0.96);
}

.rc-hero-story__toast--approved {
  right: 3%;
  bottom: 5%;
  width: 45%;
  padding: 2.4%;
  border-color: #bcefd2;
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.2);
}

.rc-hero-story__toast--invoice {
  right: 4%;
  top: 6%;
  padding: 1.5% 3%;
  border-color: #bfdbfe;
  border-radius: 999px;
  /* Tailwind v4's `shadow-sm`. */
  box-shadow:
    0 1px 3px 0 rgba(0, 0, 0, 0.1),
    0 1px 2px -1px rgba(0, 0, 0, 0.1);
  color: #1d4ed8;
  font-size: 6px;
  font-weight: 700;
  white-space: nowrap;
}

@media (min-width: 640px) {
  .rc-hero-story__toast--invoice {
    font-size: 8px;
  }
}

.rc-hero-story[data-rc-phase="dashboard"] .rc-hero-story__toast--approved {
  animation: rc-hero-story-toast 260ms var(--rc-ease-premium) 280ms both;
}

.rc-hero-story[data-rc-phase="invoice"] .rc-hero-story__toast--invoice {
  animation: rc-hero-story-rise-8 260ms var(--rc-ease-premium) 260ms both;
}

.rc-hero-story__toast-tick {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 999px;
  background: #dcfce7;
  color: #087d4e;
  font-size: 8px;
  font-weight: 900;
}

.rc-hero-story__toast-body {
  min-width: 0;
}

.rc-hero-story__toast-title {
  overflow: hidden;
  color: #0f172a;
  font-size: 6px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rc-hero-story__toast-amount {
  margin-top: 2px;
  color: #0f172a;
  font-family: var(--font-mono);
  font-size: 7px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.rc-hero-story__toast-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: #18e86f;
}

@media (min-width: 640px) {
  .rc-hero-story__toast-title {
    font-size: 8px;
  }

  .rc-hero-story__toast-amount {
    font-size: 10px;
  }
}

.rc-hero-story__linkpanel {
  position: absolute;
  right: 3%;
  top: 7%;
  bottom: 7%;
  width: 43%;
  padding: 3%;
  border: 1px solid #dbe7f5;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.97);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.25);
  color: #0f172a;
}

.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__linkpanel {
  animation: rc-hero-story-linkpanel 300ms var(--rc-ease-premium) 220ms both;
}

.rc-hero-story__linkpanel-label {
  color: #2563eb;
  font-size: 5px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.rc-hero-story__linkpanel-name {
  margin-top: 7%;
  font-size: 6px;
  font-weight: 700;
}

.rc-hero-story__linkpanel-amount {
  margin-top: 2%;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 900;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

/* The button settles green. React starts it at the brand blue and crosses to
   `#059669` half a second in, which is the moment the link is "created" — so
   the settled colour is the declaration and the blue lives in the keyframes. */
.rc-hero-story__linkpanel-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 8%;
  padding-block: 4%;
  border-radius: 4px;
  background: #059669;
  color: #ffffff;
  font-size: 5px;
  font-weight: 700;
}

.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__linkpanel-cta {
  animation: rc-hero-story-cta 160ms linear 500ms both;
}

.rc-hero-story__linkpanel-url {
  margin-top: 6%;
  padding: 4% 5%;
  overflow: hidden;
  border-radius: 4px;
  background: #eff6ff;
  color: #31517d;
  font-size: 4px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__linkpanel-url {
  animation: rc-hero-story-fade-up 200ms var(--rc-ease-premium) 560ms both;
}

@media (min-width: 640px) {
  .rc-hero-story__linkpanel-label {
    font-size: 7px;
  }

  .rc-hero-story__linkpanel-name {
    font-size: 8px;
  }

  .rc-hero-story__linkpanel-amount {
    font-size: 13px;
  }

  .rc-hero-story__linkpanel-cta {
    font-size: 7px;
  }

  .rc-hero-story__linkpanel-url {
    font-size: 6px;
  }
}

/* The one place the port's element merge changes what a percentage means, and
   it has to be undone by hand.

   React is two elements: an `absolute … w-[20%]` wrapper and, inside it, the
   chassis — `relative aspect-[9/18] w-full … p-[6%]`. Its 6% is 6% of the
   WRAPPER, because percentage padding resolves against the containing block's
   inline size and the chassis's containing block is the wrapper. The port
   prints one element, so a literal `padding: 6%` here is 6% of the act — five
   times too much, and it squeezed the screen to a third of its width with the
   screenshot barely legible inside it.

   The panel is an inline-size container of known aspect, so the real figure is
   exact rather than eyeballed: the phone is 19% of the act, the act is the
   panel's full width, so 6% of the phone is 0.06 × 19 = 1.14cqw — and 1.2cqw
   below 640px, where the phone is 20%. */
.rc-hero-story__phone {
  position: absolute;
  right: 5%;
  top: 22%;
  width: 20%;
  aspect-ratio: 9 / 18;
  padding: 1.2cqw;
  border: 1px solid var(--hs-chassis-border);
  border-radius: 15px;
  background: var(--hs-chassis);
  box-shadow: 0 20px 40px var(--hs-drop);
}

@media (min-width: 640px) {
  .rc-hero-story__phone {
    right: 6%;
    width: 19%;
    padding: 1.14cqw;
  }
}

/* Not a `.rc-hero-story__phase`, so its own opacity is nobody else's. */
.rc-hero-story[data-rc-act="1"] .rc-hero-story__phone {
  animation: rc-hero-story-phone 360ms var(--rc-ease-premium) 150ms both;
}

.rc-hero-story__phone-speaker {
  position: absolute;
  left: 50%;
  top: 2.8%;
  z-index: 10;
  width: 25%;
  height: 2px;
  border-radius: 999px;
  background: var(--hs-chassis-speaker);
  transform: translateX(-50%);
}

@media (min-width: 640px) {
  .rc-hero-story__phone-speaker {
    height: 3px;
  }
}

.rc-hero-story__phone-screen {
  position: relative;
  height: 100%;
  overflow: hidden;
  border-radius: 10px;
  background: #ffffff;
}

.rc-hero-story__phone-link {
  position: absolute;
  inset-inline: 8%;
  top: 14%;
  bottom: 8%;
  display: flex;
  flex-direction: column;
  padding: 8%;
  border: 1px solid #dbeafe;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.96);
  /* Tailwind v4's `shadow-lg`. */
  box-shadow:
    0 10px 15px -3px rgba(0, 0, 0, 0.1),
    0 4px 6px -4px rgba(0, 0, 0, 0.1);
  color: #0f172a;
  backdrop-filter: blur(8px);
}

.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__phone-link {
  animation: rc-hero-story-pop-94 260ms var(--rc-ease-premium) 260ms both;
}

.rc-hero-story__lockup {
  width: 64%;
  height: auto;
}

/* `mt-auto` is what pushes the label and everything under it to the foot of
   the payment-link card. The strip below reuses the class without the column,
   so the modifier takes it back off. */
.rc-hero-story__phone-label {
  margin-top: auto;
  color: #2563eb;
  font-size: 5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.rc-hero-story__phone-label--strip {
  margin-top: 0;
  color: #78dfff;
}

.rc-hero-story__phone-amount {
  margin-top: 6%;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 900;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.rc-hero-story__phone-cta {
  margin-top: 8%;
  padding-block: 7%;
  border-radius: 4px;
  background: #2563eb;
  color: #ffffff;
  font-size: 5px;
  font-weight: 700;
  text-align: center;
}

.rc-hero-story__phone-secure {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 7%;
  color: #087d4e;
  font-size: 4px;
  font-weight: 600;
}

.rc-hero-story__phone-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: #18e86f;
}

/* The strip under the phone screenshot: a midnight card on the white screen,
   so it too is drawn in its own colours rather than the theme's. */
.rc-hero-story__phone-strip {
  position: absolute;
  inset-inline: 8%;
  bottom: 6%;
  padding: 6%;
  border-radius: 6px;
  background: rgba(6, 31, 102, 0.94);
  box-shadow:
    0 10px 15px -3px rgba(0, 0, 0, 0.1),
    0 4px 6px -4px rgba(0, 0, 0, 0.1);
  color: #ffffff;
  backdrop-filter: blur(8px);
}

.rc-hero-story__phone-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  margin-top: 6%;
}

.rc-hero-story__phone-value {
  font-size: 6px;
  font-weight: 600;
}

.rc-hero-story__phone-check {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border-radius: 999px;
  background: #18e86f;
  color: #041e16;
  font-size: 7px;
  font-weight: 900;
}

@media (min-width: 640px) {
  .rc-hero-story__phone-label {
    font-size: 7px;
  }

  .rc-hero-story__phone-amount {
    font-size: 14px;
  }

  .rc-hero-story__phone-cta {
    font-size: 7px;
  }

  .rc-hero-story__phone-secure {
    font-size: 6px;
  }

  .rc-hero-story__phone-value {
    font-size: 8px;
  }

  .rc-hero-story__phone-check {
    width: 16px;
    height: 16px;
  }
}

/* All three pills are centred on the same point, so they cross-fade in place
   the way the acts above them do. */
.rc-hero-story__statusbar {
  position: absolute;
  left: 50%;
  bottom: 1%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid var(--hs-panel-border);
  border-radius: 999px;
  background: var(--hs-panel);
  box-shadow: var(--hs-panel-shadow);
  color: var(--hs-ink);
  font-size: 7px;
  font-weight: 600;
  white-space: nowrap;
  backdrop-filter: blur(12px);
  transform: translateX(-50%);
}

@media (min-width: 640px) {
  .rc-hero-story__statusbar {
    font-size: 9px;
  }
}

.rc-hero-story[data-rc-phase="dashboard"] .rc-hero-story__statusbar[data-phase~="dashboard"],
.rc-hero-story[data-rc-phase="paymentLink"] .rc-hero-story__statusbar[data-phase~="paymentLink"],
.rc-hero-story[data-rc-phase="invoice"] .rc-hero-story__statusbar[data-phase~="invoice"] {
  animation: rc-hero-story-statusbar 260ms var(--rc-ease-premium) 400ms both;
}

.rc-hero-story__statusbar-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--hs-accent);
}

.rc-hero-story__statusbar-dot--ok {
  background: var(--hs-success);
}

/* ── Act three: the agents ───────────────────────────────────────────────────
   `AgentsAct`. The tiles, the hub and the connectors all live in one stage
   inset inside the act — `absolute inset-x-[3%] top-0 bottom-[15%]` — and the
   agent coordinates in `rc_theme_hero_agents()` are percentages of THAT box,
   not of the act, which is why the stage has to be a positioned element in its
   own right. */

.rc-hero-story__agents {
  position: absolute;
  inset-inline: 3%;
  top: 0;
  bottom: 15%;
}

.rc-hero-story__wires {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* React draws each connector with `pathLength` 0 → 1 alongside its opacity
   0.2 → 1, staggered by `0.26 + index * 0.3`. The path carries a literal
   `stroke-dasharray="1.2 1.6"` in the markup — the dashes ARE the connector —
   and a stroke-dashoffset reveal cannot both hold that pattern and uncover the
   line, because offsetting a repeating dash pattern slides the dashes instead
   of shortening the drawn part. So the opacity half of that animation is what
   is reproduced, with the same stagger, and the connector rests as the dashed
   stroke the markup itself declares. The draw-on is the part that is lost. */
.rc-hero-story__wire-path {
  opacity: 1;
}

.rc-hero-story[data-rc-act="2"] .rc-hero-story__wire-path {
  animation: rc-hero-story-wire 440ms var(--rc-ease-premium)
    calc(260ms + var(--rc-hs-i, 0) * 300ms) both;
}

/* The dot that runs down each connector into the hub, and only while they are
   being drawn: React renders it on `!confirmed && !reducedMotion`, so it is
   gated on the `agents` phase here and the section's reduced-motion block
   stops it there. Invisible by default, which is the same condition.

   `cx`/`cy` are SVG geometry attributes, so the travel is a transform in the
   svg's own 100×100 user space. The hub is at (50, 47) and every agent sits 31
   units to one side of it and 24 above or below, so the four deltas are read
   straight off each circle's own coordinates rather than off sibling order. */
.rc-hero-story__wire-pulse {
  opacity: 0;
}

.rc-hero-story__wire-pulse[cx="19"] {
  --rc-hs-dx: 31px;
}

.rc-hero-story__wire-pulse[cx="81"] {
  --rc-hs-dx: -31px;
}

.rc-hero-story__wire-pulse[cy="23"] {
  --rc-hs-dy: 24px;
}

.rc-hero-story__wire-pulse[cy="71"] {
  --rc-hs-dy: -24px;
}

.rc-hero-story[data-rc-phase="agents"] .rc-hero-story__wire-pulse {
  animation: rc-hero-story-pulse 500ms ease-in-out
    calc(500ms + var(--rc-hs-i, 0) * 300ms) both;
}

/* `left`/`top` are inline on each tile — they are the agent's own coordinates
   — and the half-tile pull-back that centres it on them is here. */
.rc-hero-story__agent {
  position: absolute;
  z-index: 10;
  width: 28%;
  padding: 2.2%;
  border: 1px solid var(--hs-tile-border);
  border-radius: 12px;
  background: var(--hs-tile);
  box-shadow: 0 14px 36px var(--hs-drop);
  color: #0f172a;
  backdrop-filter: blur(8px);
  transform: translate(-50%, -50%);
}

@media (min-width: 640px) {
  .rc-hero-story__agent {
    width: 24%;
  }
}

.rc-hero-story[data-rc-act="2"] .rc-hero-story__agent {
  animation: rc-hero-story-agent 320ms var(--rc-ease-premium)
    calc(180ms + var(--rc-hs-i, 0) * 300ms) both;
}

.rc-hero-story__agent-head {
  display: flex;
  align-items: center;
  gap: 6px;
}

@media (min-width: 640px) {
  .rc-hero-story__agent-head {
    gap: 8px;
  }
}

/* The vendor marks are SVGs with no width or height asserted in the markup, on
   purpose: this is their box. */
.rc-hero-story__agent-icon {
  display: block;
  flex: none;
  width: 16px;
  height: 16px;
}

.rc-hero-story__agent-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

@media (min-width: 640px) {
  .rc-hero-story__agent-icon {
    width: 24px;
    height: 24px;
  }
}

.rc-hero-story__agent-name {
  overflow: hidden;
  font-size: 7px;
  font-weight: 800;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (min-width: 640px) {
  .rc-hero-story__agent-name {
    font-size: 10px;
  }
}

.rc-hero-story__agent-dot {
  flex: none;
  width: 6px;
  height: 6px;
  margin-left: auto;
  border-radius: 999px;
  background: #18e86f;
  box-shadow: 0 0 8px rgba(24, 232, 111, 0.65);
}

/* Later than its tile — the tile lands, then the connection reports itself. */
.rc-hero-story[data-rc-act="2"] .rc-hero-story__agent-dot {
  animation: rc-hero-story-dot 180ms linear
    calc(720ms + var(--rc-hs-i, 0) * 300ms) both;
}

/* `hidden … min-[390px]:block`: on the narrowest phones the tile is not wide
   enough to hold the action line, so it is dropped rather than wrapped. */
.rc-hero-story__agent-action {
  display: none;
  margin-top: 6%;
  overflow: hidden;
  color: #526176;
  font-size: 5px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (min-width: 390px) {
  .rc-hero-story__agent-action {
    display: block;
  }
}

@media (min-width: 640px) {
  .rc-hero-story__agent-action {
    font-size: 7px;
  }
}

.rc-hero-story__hub {
  position: absolute;
  left: 50%;
  top: 47%;
  z-index: 20;
  width: 37%;
  padding: 2.6%;
  border: 1px solid var(--hs-hub-border);
  border-radius: 16px;
  background: var(--hs-hub);
  box-shadow:
    0 0 34px var(--hs-hub-glow),
    0 20px 50px var(--hs-drop);
  text-align: center;
  transform: translate(-50%, -50%);
}

@media (min-width: 640px) {
  .rc-hero-story__hub {
    width: 33%;
  }
}

.rc-hero-story[data-rc-act="2"] .rc-hero-story__hub {
  animation: rc-hero-story-hub 320ms var(--rc-ease-premium) both;
}

.rc-hero-story__hub-lockup {
  width: 82%;
  height: auto;
  margin-inline: auto;
}

/* Stacked on a phone and side by side from 640px: two uppercase chips at 4.5px
   do not both fit across a 37%-wide hub on a narrow screen. */
.rc-hero-story__hub-chips {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  margin-top: 7%;
}

@media (min-width: 640px) {
  .rc-hero-story__hub-chips {
    flex-direction: row;
  }
}

.rc-hero-story__hub-chip {
  padding: 3% 7%;
  border-radius: 999px;
  font-size: 4.5px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The hub ground stays near-white in both themes, so these two keep their own
   colours rather than taking a token. */
.rc-hero-story__hub-chip--mcp {
  background: #e8f3ff;
  color: #0150ea;
}

.rc-hero-story__hub-chip--api {
  background: #e8fff4;
  color: #087d4e;
}

@media (min-width: 640px) {
  .rc-hero-story__hub-chip {
    font-size: 6px;
  }
}

.rc-hero-story__agents-foot {
  position: absolute;
  inset-inline: 4%;
  bottom: 0;
  text-align: center;
}

/* React swaps these two inside an AnimatePresence, so only ever one of them is
   laid out. Both are printed here, so both are taken out of flow and anchored
   to the same bottom edge — in flow they would stack and the act would end two
   lines taller in three phases out of nine. */
.rc-hero-story__connecting,
.rc-hero-story__enabled {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
}

.rc-hero-story__connecting {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--hs-ink-muted);
  font-size: 7px;
  font-weight: 600;
}

@media (min-width: 640px) {
  .rc-hero-story__connecting {
    font-size: 9px;
  }
}

.rc-hero-story__connecting-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--hs-accent);
  animation: rc-hero-story-blink 900ms linear infinite;
}

/* Transform only, for the same reason as the terminal's states: the fade is
   the phase machine's and this must not be able to override it. */
.rc-hero-story[data-rc-phase="aiEnabled"] .rc-hero-story__enabled {
  animation: rc-hero-story-rise-7 260ms var(--rc-ease-premium) both;
}

/* The one-line variant: centred in the act's foot rather than left-aligned
   under an eyebrow, and its own size. It comes after `.rc-hero-story__typed`
   because the two carry the same weight. */
.rc-hero-story__typed--wide {
  justify-content: center;
  margin-top: 0;
  margin-inline: auto;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

@media (min-width: 640px) {
  .rc-hero-story__typed--wide {
    font-size: 11px;
  }
}

.rc-hero-story__disclaimer {
  margin-top: 2px;
  color: var(--hs-ink-muted);
  font-size: 5px;
}

@media (min-width: 640px) {
  .rc-hero-story__disclaimer {
    font-size: 7px;
  }
}

/* ── The act and phase entrances ─────────────────────────────────────────────
   Every one of these animates transform, opacity or a colour, and nothing that
   lays out. The ones applied to a `.rc-hero-story__phase` node touch transform
   alone, so the cross-fade above stays the only thing deciding what is
   visible; the ones applied to a node that is not phase-scoped may fade. */

@keyframes rc-hero-story-card {
  0% {
    opacity: 0;
    transform: translate(27cqw, calc(var(--rc-hs-card-rise) * -1)) rotate(8deg);
  }

  /* `times: [0, 0.72, 1]` — the card is on its mark at 72% and only settles
     its opacity after that. */
  72% {
    opacity: 1;
    transform: translate(0, 0) rotate(-7deg);
  }

  100% {
    opacity: 0.96;
    transform: translate(0, 0) rotate(-7deg);
  }
}

@keyframes rc-hero-story-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes rc-hero-story-pop {
  from {
    transform: scale(0.55);
  }

  to {
    transform: none;
  }
}

@keyframes rc-hero-story-pop-94 {
  from {
    opacity: 0;
    transform: scale(0.94);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes rc-hero-story-rise-7 {
  from {
    transform: translateY(7px);
  }

  to {
    transform: none;
  }
}

@keyframes rc-hero-story-rise-8 {
  from {
    transform: translateY(8px);
  }

  to {
    transform: none;
  }
}

@keyframes rc-hero-story-drop {
  from {
    transform: translateY(-3px);
  }

  to {
    transform: none;
  }
}

@keyframes rc-hero-story-sent {
  0% {
    transform: translateX(-12px) scale(0.9);
  }

  50% {
    transform: translateX(0) scale(0.95);
  }

  100% {
    transform: translateX(10px) scale(1);
  }
}

@keyframes rc-hero-story-type {
  from {
    clip-path: inset(0 100% 0 0);
  }

  to {
    clip-path: inset(0 0 0 0);
  }
}

@keyframes rc-hero-story-caret {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.15;
  }
}

@keyframes rc-hero-story-blink {
  0%,
  100% {
    opacity: 0.3;
  }

  50% {
    opacity: 1;
  }
}

@keyframes rc-hero-story-laptop {
  from {
    transform: translateY(14px) scale(0.97);
  }

  to {
    transform: none;
  }
}

@keyframes rc-hero-story-phone {
  from {
    opacity: 0;
    transform: translateX(16px) rotate(2deg);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes rc-hero-story-toast {
  from {
    transform: translate(12px, 4px);
  }

  to {
    transform: none;
  }
}

@keyframes rc-hero-story-linkpanel {
  from {
    transform: translateX(14px) scale(0.97);
  }

  to {
    transform: none;
  }
}

@keyframes rc-hero-story-cta {
  from {
    background-color: #2563eb;
  }

  to {
    background-color: #059669;
  }
}

@keyframes rc-hero-story-fade-up {
  from {
    opacity: 0;
    transform: translateY(3px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes rc-hero-story-statusbar {
  from {
    transform: translate(-50%, 8px);
  }

  to {
    transform: translate(-50%, 0);
  }
}

@keyframes rc-hero-story-wire {
  from {
    opacity: 0.2;
  }

  to {
    opacity: 1;
  }
}

@keyframes rc-hero-story-pulse {
  0% {
    opacity: 0;
    transform: translate(0, 0);
  }

  50% {
    opacity: 1;
  }

  100% {
    opacity: 0;
    transform: translate(var(--rc-hs-dx, 0), var(--rc-hs-dy, 0));
  }
}

@keyframes rc-hero-story-agent {
  from {
    opacity: 0;
    transform: translate(-50%, calc(-50% + 8px)) scale(0.78);
  }

  to {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}

@keyframes rc-hero-story-dot {
  from {
    opacity: 0;
    transform: scale(0.5);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes rc-hero-story-hub {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.82);
  }

  to {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}

/* ── Progress rail ───────────────────────────────────────────────────────── */

.rc-hero-story__footer {
  position: absolute;
  inset-inline: 4%;
  bottom: 3%;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

/* role="progressbar" in the markup, with aria-valuemin 1, aria-valuemax 3 and
   the act index as its value. A bare div cannot carry an accessible name, so
   the "Act n of 3" string that used to sit on one reached nobody; as a
   progressbar the name is the rail and the act is the value, which is what the
   role is for. Its children are presentational under that role — the act names
   are still announced by the live region. */
.rc-hero-story__rail {
  display: flex;
  flex: 1;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
}

.rc-hero-story__rail-step {
  display: flex;
  flex: 1;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
}

.rc-hero-story__rail-bar {
  flex: 1;
  height: 4px;
  border-radius: 999px;
  background: var(--hs-track);
  transition: background-color 300ms var(--rc-ease-premium);
}

/* Filled up to and including the current act, so the rail reads as progress
   rather than as a position marker. */
.rc-hero-story:not([data-rc-act]) .rc-hero-story__rail-step[data-act="0"] .rc-hero-story__rail-bar,
.rc-hero-story[data-rc-act="0"] .rc-hero-story__rail-step[data-act="0"] .rc-hero-story__rail-bar,
.rc-hero-story[data-rc-act="1"] .rc-hero-story__rail-step[data-act="0"] .rc-hero-story__rail-bar,
.rc-hero-story[data-rc-act="1"] .rc-hero-story__rail-step[data-act="1"] .rc-hero-story__rail-bar,
.rc-hero-story[data-rc-act="2"] .rc-hero-story__rail-bar {
  background: var(--hs-accent);
}

/* Hidden below 640px, where three act names beside three bars leave the bars
   too short to read as bars. */
.rc-hero-story__rail-label {
  display: none;
  color: var(--hs-ink-faint);
  font-size: 6px;
  font-weight: 600;
}

@media (min-width: 640px) {
  .rc-hero-story__rail-label {
    display: block;
  }
}

.rc-hero-story:not([data-rc-act]) .rc-hero-story__rail-step[data-act="0"] .rc-hero-story__rail-label,
.rc-hero-story[data-rc-act="0"] .rc-hero-story__rail-step[data-act="0"] .rc-hero-story__rail-label,
.rc-hero-story[data-rc-act="1"] .rc-hero-story__rail-step[data-act="1"] .rc-hero-story__rail-label,
.rc-hero-story[data-rc-act="2"] .rc-hero-story__rail-step[data-act="2"] .rc-hero-story__rail-label {
  color: var(--hs-ink);
}

/* Shown only to a visitor who asked for less motion, and shown by CSS rather
   than by script — the badge has to be right whether or not theme.js ran. */
.rc-hero-story__reduced {
  display: none;
  color: var(--hs-ink-muted);
  font-size: 7px;
  font-weight: 600;
}

/* ── Announced, not drawn ────────────────────────────────────────────────── */

/* The whole story summarised once, for a reader who will never see any of it,
   and the live region that names the act as it changes. The panel is a
   role="group" with a label and decorative children, so these two are the only
   things inside it that are meant to be read. */
.rc-hero-story__sr,
.rc-hero-story__live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@keyframes rc-hero-story-horizon {
  0%,
  100% {
    transform: translateX(0);
    opacity: 0.45;
  }

  50% {
    transform: translateX(12px);
    opacity: 0.7;
  }
}

/* A visitor who asked for less motion gets a still panel and the badge that
   says so. Which frame they are left on depends on whether theme.js ran, and
   the difference is not cosmetic — it is which frame the page can tell the
   truth about.

   With scripts running, `sync()` calls `show(last)`: the panel rests on
   `complete`, and the same call rewrites the header status line, the live
   region, and the rail's `aria-valuenow`/`aria-valuetext` to match act three.
   Picture and announcement agree, and that is React's behaviour.

   With scripts blocked, only the picture can move. Every string in this panel
   is server-rendered at act one — "Terminal · live product story", "Act 1 of
   3. A terminal payment is approved.", `aria-valuenow="1"` — and no stylesheet
   can rewrite text or an ARIA attribute. `prefers-reduced-motion` is a client
   media query, so the server cannot branch on it either; there is no frame it
   could have rendered instead.

   So this block used to park the attribute-less panel on act three, which left
   a screen reader announcing "Act 1 of 3. A terminal payment is approved." over
   a picture of four AI agents, with the progressbar reporting act 1 of 3 while
   all three of its segments were painted full. Measured on the shipped markup
   with the query forced on and scripts stripped. The frame was wrong in every
   way a non-visual reader could detect it.

   What is left is the rule that holds in both directions: with no script the
   panel rests on the frame the server actually wrote — act one, phase `ready`,
   the same frame a visitor with no motion preference gets — and reduced motion
   only stops the movement and shows the badge. Nothing here asserts an act that
   is not on screen.

   NOTE for whoever edits `inc/hero-visual.php` next: that file's docblock still
   describes the old behaviour ("rests the same attribute-less panel on the
   completed frame instead"). It is stale, and this comment is why. */
@media (prefers-reduced-motion: reduce) {
  .rc-hero-story *,
  .rc-hero-story *::before,
  .rc-hero-story *::after {
    animation: none !important;
    transition: none !important;
  }

  .rc-hero-story__reduced {
    display: block;
  }
}

@media (min-width: 640px) {
  .rc-hero-story__reduced {
    font-size: 8px;
  }
}


/* ── Hero layout ───────────────────────────────────────────────────────────
   Copy against the panel. Single column until there is room for both: the
   panel is a diagram with a dozen labels in it, and half a phone's width turns
   those labels into slivers. minmax(0, …) on both tracks because the panel is a
   container-query context and would otherwise take its minimum from its own
   widest child and push the copy off the grid. */
/* `gap-14 lg:gap-8 py-16 lg:py-24`, and the grid is the container rather than
   a child of one — the arrangement the app uses. The gap narrows rather than
   widens at lg, because that is where the panel appears beside the copy and
   the two tracks stop being stacked. It narrows to 32px, not 40: the extra
   8px came out of the copy column, which is where the 17ch headline decides
   whether it wraps. */
.rc-hero-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 56px;
  align-items: center;
  padding-block: var(--space-16);
}

/* Twelve tracks with a 7/5 span, not two tracks weighted 7fr and 5fr. They are
   not the same measure: two tracks divide one gutter between them and twelve
   divide eleven, so the copy column comes out narrower — enough to move where
   a 17ch heading wraps. */
@media (min-width: 1024px) {
  .rc-hero-layout {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--space-8);
    padding-block: var(--space-24);
  }

  .rc-hero-layout__copy {
    grid-column: 1 / span 7;
    min-width: 0;
  }

  .rc-hero-layout__visual {
    grid-column: 8 / span 5;
    min-width: 0;
  }
}

.rc-hero-layout > * {
  min-width: 0;
}

.rc-hero-layout__copy > :first-child {
  margin-top: 0;
}

.rc-hero-layout__visual {
  min-width: 0;
}

/* The hero's own vertical rhythm lives on the grid above and on the trust
   strip below it, so the section itself adds nothing — a padding here would
   push the strip's hairline away from the edge it is supposed to sit on. */
.rc-section.rc-section--hero {
  padding-block: 0;
}

/* `mt-5` under the eyebrow and `mt-6` under the heading. The eyebrow gives up
   its own bottom margin here so the two do not stack. */
.rc-hero-layout__copy .rc-eyebrow {
  margin-bottom: 0;
}

.rc-hero-layout__copy .rc-h1 {
  margin-top: var(--space-5);
}

.rc-hero-layout__copy .rc-lead {
  margin-top: var(--space-6);
}


/* ── Hit areas ─────────────────────────────────────────────────────────────
   One control is deliberately small: the announcement link sits in a slim bar
   that a 44px control would double the height of. It keeps its drawn size and
   gains a transparent overlay that carries the touch. The overlay is the
   control's own pseudo-element, so it moves with it and needs no wrapper.

   The hero panel's Replay button used to be listed here too. It is gone: the
   string "Replay" occurs on none of the sixty rendered pages of the live site,
   and the story that replaced the old panel plays itself on a loop.

   Sign in and sign up are the second case: the app draws them 36px tall, the
   theme draws them 40 inside a 46px pill, and both are under the floor. Growing
   them to 44 would grow the pill to 50 and put the account control out of step
   with the app it is meant to match, so they keep their drawn height and take
   the same overlay. Measured before: 67.6x40 and 72.3x40. */
.rc-announce__cta,
.rc-nav__account-link {
  position: relative;
}

.rc-announce__cta::after,
.rc-nav__account-link::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}


/* ── Announcement bar: the Details disclosure ───────────────────────────────
 *
 * The app opens this copy in a modal. A modal needs script and a focus trap,
 * and the ribbon sits above the page's h1 on all 1,737 pages, so the theme uses
 * a native <details> instead: same content, same order, keyboard-operable and
 * correct with JavaScript off. These rules existed nowhere, so the disclosure
 * rendered with the browser's default marker and no containment — six classes
 * emitted on every page of the site and not one of them styled. */
.rc-announce__details {
  display: inline;
}

.rc-announce__more {
  display: inline;
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  color: var(--rc-text-blue);
  text-underline-offset: 3px;
  text-decoration: underline;
}

/* Safari still paints the disclosure triangle through `list-style: none`. */
.rc-announce__more::-webkit-details-marker {
  display: none;
}

.rc-announce__more:hover,
.rc-announce__more:focus-visible {
  color: var(--rc-text-primary);
}

/* Absolutely positioned so opening the disclosure does not push the whole page
   down by the height of the panel — the ribbon is the first thing on the page
   and a reflow there moves everything the reader is looking at. */
.rc-announce__detail {
  position: absolute;
  z-index: 60;
  inset-inline: 0;
  margin-inline: auto;
  margin-block-start: var(--space-2);
  max-width: 34rem;
  padding: var(--space-5);
  text-align: start;
  background: var(--rc-band-raised);
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
  box-shadow: var(--rc-shadow-lg);
}

.rc-announce__detail-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  color: var(--rc-text-primary);
}

.rc-announce__detail-body {
  margin: var(--space-2) 0 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--rc-text-secondary);
}

.rc-announce__detail-cta {
  margin-block-start: var(--space-4);
}

/* The product category line, above the h1 rather than below it — where
   product-hero.tsx draws it. `.rc-eyebrow` carries the type; this only sets the
   gap to the heading it now precedes. */
.rc-eyebrow--page {
  margin: 0 0 var(--space-3);
}

/* ── Footer ────────────────────────────────────────────────────────────────
   Three bands: who this is, where the whole site is, and the legal floor. The
   link columns are the site's comprehensive discovery surface — everything the
   header had to leave out is reachable from here, for a visitor and a crawler
   alike — so every column is a real <nav> with a heading and a plain list. */
.rc-footer {
  padding-block: clamp(48px, 6vw, 80px) var(--space-8);
  border-top: 1px solid var(--rc-line);
  background: var(--rc-band-deep);
  color: var(--rc-text-secondary);
  font-size: 0.9375rem;
}

/* ── Brand band ───────────────────────────────────────────────────────── */
.rc-footer__brand {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  padding-bottom: var(--space-10);
  border-bottom: 1px solid var(--rc-line);
}

@media (min-width: 1024px) {
  .rc-footer__brand {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
  }
}

/* `space-y-5` on the app's brand column — logo, slogan, blurb, social links. */
.rc-footer__identity {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
  min-width: 0;
}

/* Except between the lockup and the slogan, which the app nests in their own
   `space-y-3`: the slogan is the second half of the lockup, not the next item
   down the page, and at the column's own rhythm it reads as one. The negative
   margin is the difference between the two, so there is one gap value to keep
   in step rather than two. */
.rc-footer__logo + .rc-brand-slogan {
  margin-top: calc(var(--space-3) - var(--space-5));
}

.rc-footer__logo {
  display: inline-flex;
  border-radius: var(--radius-sm);
}

/* The footer draws the brand larger than the header does: `BrandLogo size={28}
   markSize={44}` against the header's 26 and 38. Sized on the images, not on the
   wrapper — `.rc-logo` is the <span> around the wordmark, and a `display` on it
   here would beat the colourway rules above on order and draw both lockups.

   These used to target `.rc-logo__icon`, which no longer exists in the markup;
   the tile is what stands in its place below 640px. */
.rc-footer__logo .rc-logo-tile img {
  width: 44px;
  height: 44px;
}

.rc-footer__logo .rc-logo__word {
  height: 28px;
}

.rc-footer__blurb {
  max-width: 24rem;
  margin: 0;
  color: var(--rc-text-secondary);
  font-size: 0.875rem;
  line-height: 1.65;
}

.rc-footer__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The mark is 20px and the target is 44px, so the padding is the hit area
   rather than decoration. Without it these are five 20px squares 8px apart,
   which is the smallest thing on the page and the hardest to hit. */
.rc-footer__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  color: var(--rc-text-disabled);
  transition: color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-footer__social a:hover,
.rc-footer__social a:focus-visible {
  color: var(--rc-text-blue);
}

.rc-footer__offices {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* <address> is italic in the UA stylesheet, and a postal address set in
     italic reads as an aside rather than as the company's own details. */
  font-style: normal;
  font-size: 0.875rem;
  color: var(--rc-text-secondary);
}

.rc-footer__offices p {
  margin: 0;
}

@media (min-width: 1024px) {
  .rc-footer__offices {
    text-align: right;
  }
}

.rc-footer__office-city {
  color: var(--rc-text-primary);
  font-weight: 500;
}

.rc-footer__offices a {
  color: inherit;
  text-decoration: none;
}

.rc-footer__offices a:hover {
  color: var(--rc-text-blue);
  text-decoration: underline;
}

/* ── Link columns ─────────────────────────────────────────────────────────
   Seven columns is more than a 1024px viewport can hold legibly, so the grid
   steps 3 → 4 → 7 and hands over to the accordion below 768px entirely.
   `display: none` and not `visibility` or an offscreen shift: the accordion
   carries the same seventy links, and two copies in the accessibility tree
   would have a screen reader read the whole footer twice. */
.rc-footer__grid {
  display: none;
  gap: var(--space-6) var(--space-4);
  padding-block: var(--space-10);
}

.rc-footer__accordion {
  display: block;
  padding-block: var(--space-4);
}

@media (min-width: 768px) {
  .rc-footer__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .rc-footer__accordion {
    display: none;
  }
}

@media (min-width: 1024px) {
  .rc-footer__grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (min-width: 1280px) {
  .rc-footer__grid {
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }
}

.rc-footer__group {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.rc-footer__group-title {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-text-primary);
}

.rc-footer__grid ul,
.rc-footer__accordion ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* display:flex, not inline-flex: the link fills its column, so the target is
   the whole row rather than the width of the word inside it. */
.rc-footer__grid a,
.rc-footer__accordion ul a {
  display: flex;
  align-items: center;
  min-width: 44px;
  min-height: 36px;
  color: var(--rc-text-secondary);
  font-size: 0.875rem;
  line-height: 1.35;
  text-decoration: none;
}

.rc-footer__accordion ul a {
  min-height: 44px;
}

.rc-footer__grid a:hover,
.rc-footer__accordion ul a:hover {
  color: var(--rc-text-blue);
  text-decoration: underline;
}

/* ── Accordion (phones) ───────────────────────────────────────────────── */
.rc-footer__panel {
  border-bottom: 1px solid var(--rc-line-soft);
}

.rc-footer__panel:last-child {
  border-bottom: 0;
}

.rc-footer__panel > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: 44px;
  padding-block: var(--space-4);
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-text-primary);
  list-style: none;
}

/* Both are needed: WebKit uses the pseudo-element, everyone else honours the
   list-style above. Leaving either one out ships a stray triangle. */
.rc-footer__panel > summary::-webkit-details-marker {
  display: none;
}

/* 16px, the same box `.rc-nav__caret` gives the same glyph — and the size the
   chevron's stroke is calibrated for. `rc_theme_icon()` writes width="20" on
   every icon it emits, and the caret carries a heavier nominal stroke (2, not
   1.5) precisely because it is meant to be drawn small: 2 at 16px is 1.33px of
   ink, a hair above the 1.25px of the icons around it. Left at the attribute's
   20px it renders 1.67px — the heaviest mark in the theme and half again the
   weight of the header caret it rhymes with, on the one glyph that appears
   seven times down a phone footer. The other two chevrons are already sized in
   CSS; this one was the only call site relying on the attribute. */
.rc-footer__panel-caret {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--rc-text-disabled);
  transition: transform var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-footer__panel[open] > summary .rc-footer__panel-caret {
  transform: rotate(180deg);
}

.rc-footer__panel > ul {
  padding-bottom: var(--space-4);
}

@media (prefers-reduced-motion: reduce) {
  .rc-footer__panel-caret {
    transition: none;
  }
}

/* ── Bottom bar ───────────────────────────────────────────────────────── */
.rc-footer__bottom {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding-top: var(--space-8);
  border-top: 1px solid var(--rc-line);
  font-size: 0.8125rem;
  color: var(--rc-text-disabled);
}

.rc-footer__bottom-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

@media (min-width: 768px) {
  .rc-footer__bottom-row {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.rc-footer__copy {
  margin: 0;
  font-size: 0.75rem;
}

/* The switcher's panel opens upward here. Anchored to the bottom edge it would
   open off the end of the document and be unreachable. */
.rc-footer__bottom .rc-locale-switcher > ul {
  top: auto;
  bottom: calc(100% + 8px);
}

.rc-footer__legal ul {
  display: flex;
  flex-wrap: wrap;
  gap: 4px var(--space-6);
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-footer__legal a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  color: var(--rc-text-disabled);
  font-size: 0.75rem;
  text-decoration: none;
}

.rc-footer__legal a:hover {
  color: var(--rc-text-primary);
  text-decoration: underline;
}

/* ── Industry filter ───────────────────────────────────────────────────────
   One hundred and twenty cards, so the controls are the page rather than an
   ornament on it. They are `hidden` in the markup until the script reveals
   them; nothing here needs a no-JS state because without the script they are
   never displayed and the full grid stands. */
/* `:not([hidden])` is load-bearing. The controls ship with the `hidden`
   attribute and `assets/js/theme.js` removes it, so a visitor without
   JavaScript gets the complete 120-item grid instead of a search box that does
   nothing. A bare `display: flex` here re-reveals them: Chrome's UA rule for
   `[hidden]` is `!important` and would still win, but older engines' is not,
   which is the worst kind of difference — a dead control that appears for some
   readers and not others. */
.rc-industry-filter__controls:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-block: var(--space-8) 0;
}

/* The grid opens `mt-10` below the controls rather than the `mt-12` every
   other section's grid takes. */
.rc-industry-filter .rc-grid {
  margin-top: var(--space-10);
}

@media (min-width: 1024px) {
  .rc-industry-filter__controls:not([hidden]) {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.rc-industry-filter__search {
  display: block;
  width: 100%;
  max-width: 28rem;
}

.rc-industry-filter__search input {
  width: 100%;
  /* 44px target, and 16px type: anything smaller makes iOS Safari zoom the page
     on focus and it does not zoom back out. */
  min-height: 44px;
  padding: 10px 16px;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-input);
  background: var(--rc-band-raised);
  color: var(--rc-text-primary);
  font-family: inherit;
  font-size: 16px;
}

.rc-industry-filter__search input:focus-visible {
  outline: 2px solid var(--rc-text-blue);
  outline-offset: 1px;
}

.rc-industry-filter__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* A real <button>, so it is in the tab order and answers Space and Enter. The
   44px floor is the reason for the padding rather than the type size. */
.rc-badge--button {
  min-height: 44px;
  padding-inline: var(--space-4);
  border: 1px solid var(--rc-line);
  background: var(--rc-band-raised);
  color: var(--rc-text-secondary);
  font-family: inherit;
  cursor: pointer;
  transition:
    background var(--rc-motion-fast) var(--rc-ease-premium),
    color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-badge--button:hover {
  color: var(--rc-text-primary);
}

/* The active tag is carried by more than colour: the border thickens and the
   fill inverts, so it is distinguishable without relying on hue. */
.rc-badge--button[aria-pressed="true"] {
  border-color: var(--rc-text-blue);
  background: var(--rc-text-blue);
  color: #ffffff;
  font-weight: 600;
}

.rc-badge--button:focus-visible {
  outline: 2px solid var(--rc-text-primary);
  outline-offset: 2px;
}

.rc-industry-filter__count {
  margin: var(--space-4) 0 0;
  min-height: 1.25rem;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--rc-text-disabled);
}

/* Empty until a filter has run — and until then it takes no height, so the
   grid opens exactly where the app's does. Still rendered rather than
   `display:none`, because a live region removed from the render tree stops
   announcing in several screen readers. */
.rc-industry-filter__count:empty {
  min-height: 0;
  margin: 0;
}

.rc-industry-filter__empty {
  margin: var(--space-6) 0 0;
  color: var(--rc-text-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .rc-badge--button {
    transition: none;
  }
}

/* ── Skip link ─────────────────────────────────────────────────────────────
   First element in <body>. Parked off-canvas rather than display:none so it
   stays in the tab order, and it answers :focus as well as :focus-visible —
   a programmatic focus from a "skip" shortcut does not always set the latter. */
.rc-skip-link {
  position: absolute;
  inset-inline-start: 16px;
  top: -100px;
  z-index: var(--z-grain);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 12px 20px;
  border-radius: var(--rc-radius-button);
  background: var(--rc-primary-middle);
  color: #ffffff;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: top var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-skip-link:focus,
.rc-skip-link:focus-visible {
  top: 16px;
  color: #ffffff;
}

/* ═══════════════════════════════════════════════════════════════════════════
   7. UTILITIES
   ═══════════════════════════════════════════════════════════════════════════ */

/* Fixed grain layer — breaks the flatness of large midnight fields.
   Fixed + pointer-events:none so it never repaints on scroll. Effectively off
   in light, where the noise would read as a dirty screen rather than texture. */
.rc-grain {
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.012;
}

:root[data-theme="dark"] .rc-grain {
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

[hidden] {
  display: none !important;
}

/* Motion is decoration here — every state it animates is also expressed by a
   colour or a border, so collapsing it costs nothing but the flourish.
   Near-zero rather than zero so transitionend/animationend still fire. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }

  a.rc-card:hover,
  .rc-btn--primary:hover,
  .rc-btn--primary:active {
    transform: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   8. PRINT
   ═══════════════════════════════════════════════════════════════════════════
   Legal documents and fee tables get printed and filed, so print is a real
   output here, not an afterthought. Tokens are re-pointed at ink-on-paper
   once and every component follows, exactly as it does for a theme flip. */

@media print {
  /* A deferred section has never been scrolled into view, so on a page printed
     straight from load the browser has nothing laid out for it. Print the lot. */
  .rc-singular > .rc-section {
    content-visibility: visible;
    contain-intrinsic-size: none;
  }

  :root {
    --rc-text-primary: #000000;
    --rc-text-financial: #000000;
    --rc-text-secondary: #1a1a1a;
    --rc-text-disabled: #333333;
    --rc-text-blue: #00008b;
    --rc-line-soft: #cccccc;
    --rc-line: #999999;
    --rc-line-strong: #666666;
    --rc-band-base: #ffffff;
    --rc-band-deep: #ffffff;
    --rc-band-raised: #ffffff;
    --rc-band-blue: #ffffff;
    --rc-band-panel: transparent;
    --rc-shadow-sm: none;
    --rc-shadow-md: none;
    --rc-shadow-lg: none;
  }

  @page {
    margin: 18mm;
  }

  body {
    background: #ffffff;
    color: #000000;
    font-size: 11pt;
  }

  .rc-header,
  .rc-footer,
  .rc-mobile-toggle,
  .rc-mobile-nav,
  .rc-nav__panel,
  .rc-theme-toggle,
  .rc-locale-switcher,
  .rc-skip-link,
  .rc-grain {
    display: none !important;
  }

  .rc-section,
  .rc-section--tight {
    padding-block: var(--space-6);
  }

  .rc-container,
  .rc-prose {
    max-width: none;
  }

  .rc-card,
  .rc-mock,
  .rc-faq__item,
  .rc-table-wrap,
  .rc-steps > li,
  blockquote,
  figure {
    break-inside: avoid;
  }

  h1,
  h2,
  h3 {
    break-after: avoid;
  }

  /* A collapsed <details> would print as a list of questions with no answers.
     ::details-content is the modern hook; the sibling rule catches engines
     that still hide the children with display. */
  .rc-faq__item:not([open])::details-content {
    content-visibility: visible;
  }

  .rc-faq__item:not([open]) > .rc-faq__a {
    display: block;
  }

  .rc-faq__q::after {
    display: none;
  }

  /* The wrapper cannot scroll on paper, so the table has to fit instead. */
  .rc-table-wrap {
    overflow: visible;
  }

  .rc-table {
    min-width: 0;
    font-size: 9pt;
  }

  /* Only prose links get their target spelled out — doing it to navigation
     would bury the page in URLs. */
  .rc-prose a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 8pt;
    color: #333333;
    word-break: break-all;
  }
}

/* ── Footer: regulatory standing band ─────────────────────────────────────
   Fine print in size, not in substance: a bordered card above the bottom
   bar, statement on the left, verify links with shield marks on the right.
   Single-column below 1024 where the two halves would crush each other. */

.rc-footer__trust {
  margin: var(--space-10) 0 var(--space-8);
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-xl);
  padding: var(--space-6) var(--space-8);
}

.rc-footer__trust-heading {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-text-secondary);
}

.rc-footer__trust-body {
  display: grid;
  gap: var(--space-6);
  margin-top: var(--space-4);
}

@media (min-width: 1024px) {
  .rc-footer__trust-body {
    grid-template-columns: 2fr 1fr;
  }
}

.rc-footer__trust-copy p {
  margin: 0 0 var(--space-3);
  font-size: 12px;
  line-height: 1.7;
  color: var(--rc-text-secondary);
}

.rc-footer__trust-copy p:last-child {
  margin-bottom: 0;
}

.rc-footer__trust-verify h3 {
  margin: 0 0 var(--space-2);
  font-size: 12px;
  font-weight: 600;
}

.rc-footer__trust-verify ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-footer__trust-verify li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.rc-footer__trust-shield {
  width: 14px;
  height: 14px;
  flex: none;
  margin-top: 6px;
  color: var(--rc-blue-600);
}

.rc-footer__trust-verify a {
  font-size: 12px;
  line-height: 1.6;
  /* The 30px line keeps these comfortable tap targets in a dense block. */
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  color: var(--rc-text-secondary);
  text-decoration: none;
}

.rc-footer__trust-verify a:hover {
  color: var(--rc-blue-600);
  text-decoration: underline;
}

/* ── Article: quick answer, sources, change log ───────────────────────────
   The answer-first block leads the body with a rule down its left edge — the
   same emphasis the React view gives it, so a reader moving between the two
   front ends meets the same page. */

/* One measure for the whole article, not two.
   `.rc-prose` caps body copy at 68ch, but the rail, the answer block and the
   takeaways sat in the bare container and ran the full 1234px of it. The
   result was a column of callout cards overhanging the paragraphs beneath
   them by some 500px, with a ragged right edge down the page and no line
   anywhere that agreed with another.

   The shared cap is a length rather than `ch` because these blocks are set at
   different sizes — the rail at 15px, the takeaways at 16px, the prose at 17px
   — and 68ch of each is a different number of pixels, which reintroduces a
   ragged edge about 40px deep. One length holds every block to the same right
   edge. 46rem is the 68ch prose measure at its own font size, so the body copy
   keeps the line length it was tuned for.

   Scoped to `[data-rc-article-body]` so the two-column legal rail, which
   shares `.rc-toc`, keeps the width its clause labels are set for. */
[data-rc-article-body] {
  --rc-article-measure: 46rem;
}

[data-rc-article-body] .rc-prose,
[data-rc-article-body] .rc-toc,
[data-rc-article-body] .rc-quick-answer,
[data-rc-article-body] .rc-takeaways,
[data-rc-article-body] .rc-scope {
  max-width: var(--rc-article-measure);
}

.rc-quick-answer {
  border-left: 3px solid var(--rc-blue-600);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  background: var(--rc-band-panel);
  padding: var(--space-5) var(--space-6);
}

.rc-quick-answer__label {
  margin: 0 0 var(--space-2);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-blue-600);
}

.rc-quick-answer__text {
  margin: 0;
  font-size: 17px;
  line-height: 1.7;
  color: var(--rc-text-primary);
}

.rc-takeaways {
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
  background: var(--rc-band-panel);
  padding: var(--space-5) var(--space-6);
}

.rc-takeaways__label {
  margin: 0 0 var(--space-3);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-blue-600);
}

.rc-takeaways__list {
  margin: 0;
  padding-left: var(--space-5);
}

.rc-takeaways__list li {
  margin-bottom: var(--space-2);
  font-size: 16px;
  line-height: 1.7;
  color: var(--rc-text-primary);
}

.rc-scope {
  margin: 0;
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
  background: var(--rc-band-panel);
  padding: var(--space-3) var(--space-4);
  font-size: 14px;
  line-height: 1.7;
  color: var(--rc-text-secondary);
}

.rc-scope__label {
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-related-product {
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
  background: var(--rc-band-panel);
  padding: var(--space-5) var(--space-6);
}

.rc-related-product__label {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-blue-600);
}

.rc-related-product__title {
  margin: var(--space-2) 0 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--rc-text-primary);
}

.rc-related-product__cta {
  display: inline-block;
  margin-top: var(--space-4);
  font-weight: 600;
  color: var(--rc-blue-600);
}

.rc-sources__label {
  margin: 0 0 var(--space-3);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--rc-tracking-label);
  text-transform: uppercase;
  color: var(--rc-text-secondary);
}

.rc-sources,
.rc-changelog {
  border-top: 1px solid var(--rc-line);
  padding-top: var(--space-5);
}

.rc-sources__list {
  margin: 0;
  padding-left: var(--space-5);
}

.rc-sources__list li {
  margin-bottom: var(--space-2);
  font-size: 14px;
  line-height: 1.7;
  color: var(--rc-text-secondary);
}

.rc-sources__date {
  color: var(--rc-text-secondary);
}

.rc-changelog__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-changelog__list li {
  display: flex;
  gap: var(--space-4);
  margin-bottom: var(--space-2);
  font-size: 14px;
}

.rc-changelog__list time {
  flex: none;
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-secondary);
}

/* ── Byline and generated-article furniture ─────────────────────────────── */

/* The byline is a link that has to read as attribution rather than as one more
   navigation item, so it carries weight without the underline treatment the
   prose links get. */
.rc-byline {
  color: var(--rc-text-primary);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--rc-line);
}

.rc-byline:hover,
.rc-byline:focus-visible {
  border-bottom-color: var(--rc-line-strong);
}

.rc-author__photo {
  border-radius: 999px;
  width: 120px;
  height: 120px;
  object-fit: cover;
}

/* A citation is not an aside; it is the reason a number can be trusted. The
   dotted underline signals there is a source behind it without turning every
   figure into something that looks clickable when it is not. */
.rc-cite {
  font-style: normal;
  border-bottom: 1px dotted var(--rc-line-strong);
  cursor: help;
}

.rc-figure {
  margin-block: var(--space-8);
}

.rc-figure img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: var(--radius-md, 8px);
}

.rc-figure figcaption {
  margin-top: var(--space-2);
  font-size: 0.875rem;
  color: var(--rc-text-secondary);
}

/* The AI-involvement disclosure. Deliberately quiet but never hidden: the
   point of a disclosure is that a reader who looks for it finds it. */
.rc-ai-disclosure {
  margin-block: var(--space-8) 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--rc-line);
  font-size: 0.875rem;
  color: var(--rc-text-secondary);
}

/* A retraction has to be impossible to miss and impossible to mistake for
   ordinary editorial furniture, because a reader who skims past it acts on a
   claim the site has already withdrawn. */
.rc-retraction {
  display: block;
  margin-block: 0 var(--space-6);
  padding: var(--space-4);
  border-left: 4px solid var(--rc-danger-border);
  /* Border and weight rather than a filled panel. The danger tokens in this
     theme are gradient stops, not surface colours, and using one as a
     background puts body text on saturated orange in light mode and fails
     contrast outright. The rule carries the signal; the text stays readable. */
  background: none;
  color: var(--rc-text-primary);
  font-size: 0.9375rem;
}

.rc-retraction strong {
  display: block;
  margin-bottom: 0.25rem;
}

/* ── Device showcase: photographed hardware, list of the other models ───────
   Same grid discipline as .rc-hero-layout — twelve tracks with a span rather
   than two tracks weighted, for the same sub-pixel reason documented there.
   Single column until the breakpoint, because a photo and a three-item list
   squeezed into two narrow columns on a phone is worse than either stacked. */
.rc-device-showcase {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-10);
  align-items: center;
}

@media (min-width: 1024px) {
  .rc-device-showcase {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--space-16);
  }

  .rc-device-showcase__photo {
    grid-column: 1 / span 5;
    min-width: 0;
  }

  .rc-device-showcase__copy {
    grid-column: 6 / span 7;
    min-width: 0;
  }
}

.rc-device-showcase__photo {
  min-width: 0;
}

/* The hero photo is the one image on the page with no width/height attribute:
   the exported `deviceShowcase.heroImage` carries a src and an alt and nothing
   else, so the browser reserves no box for it and the whole section jumps when
   it decodes. `aspect-ratio` reserves the same box from CSS instead, and 1086
   by 1448 is not a guess — it is the intrinsic size of
   `/devices/rivo-go-front.338b28d6.avif`, the only heroImage the content layer
   defines. The three chapter photos below already have their height reserved.
   When the exporter starts emitting real dimensions this rule stops being
   load-bearing and can go. */
.rc-device-showcase__photo img {
  width: 100%;
  max-width: 26rem;
  height: auto;
  aspect-ratio: 1086 / 1448;
  margin-inline: auto;
  display: block;
  filter: drop-shadow(0 32px 48px rgba(4, 12, 32, 0.45));
}

.rc-device-showcase__copy > :first-child {
  margin-top: 0;
}

.rc-device-showcase__list {
  list-style: none;
  margin: var(--space-8) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.rc-device-showcase__row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--rc-line);
  border-radius: 12px;
  text-decoration: none;
  transition: border-color 0.15s ease;
}

.rc-device-showcase__row:hover,
.rc-device-showcase__row:focus-visible {
  border-color: var(--rc-line-strong);
}

.rc-device-showcase__row img {
  height: 48px;
  width: auto;
  flex-shrink: 0;
  object-fit: contain;
}

.rc-device-showcase__row-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.rc-device-showcase__row-text strong {
  font-size: 1rem;
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-device-showcase__row-text span {
  font-size: 0.9rem;
  color: var(--rc-text-secondary);
}


/* ── Cookie consent ────────────────────────────────────────────────────────
   The banner `assets/js/theme.js` builds, ported from
   `apps/web/components/shell/cookie-banner.tsx`. The package shipped none at
   all — no markup, no styles, no storage — so a first-time visitor was never
   asked.

   It is built by script rather than printed by a template, and that is the
   right split for this one control: with scripts blocked nothing reads the
   record and nothing writes it, so a banner in the HTML would be a question
   whose answer could not be stored. Nothing here is therefore a no-JS floor;
   it is the presentation of something that only exists when scripts run.

   Bottom-right from 768px and full-width above the fold's edge below it, which
   is where the app puts it. Not a dialog: the page behind stays live and the
   focus order is unchanged, because a visitor is allowed to read first and
   answer second. */
.rc-cookie {
  position: fixed;
  inset-inline: var(--space-4);
  bottom: var(--space-4);
  z-index: var(--z-overlay);
  margin-inline: auto;
  max-width: 28rem;
  padding: var(--space-5);
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
  background: var(--rc-menu-panel-bg);
  box-shadow: var(--rc-shadow-lg);
  backdrop-filter: blur(24px);
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity 240ms var(--rc-ease-premium),
    transform 240ms var(--rc-ease-premium);
}

/* Added a frame after insertion, and removed again on the way out, so the
   panel has somewhere to animate from and to. */
.rc-cookie.is-open {
  opacity: 1;
  transform: none;
}

.rc-cookie.is-leaving {
  opacity: 0;
  transform: translateY(16px);
}

@media (min-width: 768px) {
  .rc-cookie {
    inset-inline: auto;
    right: var(--space-6);
    bottom: var(--space-6);
    margin-inline: 0;
  }
}

.rc-cookie__title {
  margin: 0;
  color: var(--rc-text-primary);
  font-size: 0.875rem;
  font-weight: 600;
}

.rc-cookie__message {
  margin: var(--space-2) 0 0;
  color: var(--rc-text-secondary);
  font-size: 0.875rem;
  line-height: 1.625;
}

.rc-cookie__choices {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.rc-cookie__manage {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

/* Inside the manage panel the row is separated by the stack's own gap, so it
   takes padding rather than a second margin on top of it. */
.rc-cookie__manage .rc-cookie__choices {
  margin-top: 0;
  padding-top: var(--space-2);
}

.rc-cookie__toggle {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: border-color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-cookie__toggle:hover {
  border-color: var(--rc-line-strong);
}

/* Strictly necessary cookies are not a choice, and the row says so by being
   dimmed and by carrying a checked, disabled control rather than by leaving
   the reader a switch that refuses to move without explanation. */
.rc-cookie__toggle--locked {
  opacity: 0.7;
  cursor: default;
}

.rc-cookie__toggle--locked:hover {
  border-color: var(--rc-line);
}

.rc-cookie__check {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 2px;
  accent-color: var(--rc-primary-top);
}

.rc-cookie__toggle-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.rc-cookie__toggle-label {
  color: var(--rc-text-primary);
  font-size: 0.875rem;
  font-weight: 600;
}

.rc-cookie__toggle-note {
  color: var(--rc-text-secondary);
  font-size: 0.75rem;
  line-height: 1.625;
}

/* The app draws these at `px-4 py-2.5 text-sm`, which is smaller than this
   theme's standard button — three of them at 28px side padding do not fit a
   448px panel. Matching the app's size means a 41px control, under the 44px
   floor, so they take the same transparent overlay the announcement link and
   the account pills take: the drawing stays the app's and the target does not. */
.rc-cookie__btn {
  position: relative;
  min-height: 0;
  padding: 10px var(--space-4);
  font-size: 0.875rem;
}

.rc-cookie__link {
  position: relative;
  padding: 10px var(--space-3);
  border: 0;
  border-radius: var(--rc-radius-button);
  background: none;
  color: var(--rc-text-blue);
  font-family: var(--font-sans);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-cookie__link:hover {
  color: var(--rc-text-primary);
}

/* Back out of the manage panel, which is a retreat rather than an offer — the
   app draws it in the muted ink and "Manage preferences" in the blue. */
.rc-cookie__link--muted {
  color: var(--rc-text-secondary);
}

.rc-cookie__btn::after,
.rc-cookie__link::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

@media (prefers-reduced-motion: reduce) {
  .rc-cookie {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* The script removes the panel immediately under reduced motion, so this only
     matters if it is mid-flight when the preference changes. */
  .rc-cookie.is-leaving {
    opacity: 0;
  }
}


/* ── Fee Check activity ────────────────────────────────────────────────────
   The rotating sample-profile panel from
   `apps/web/components/sections/savings-ticker.tsx`. The theme replaced it with
   one static figure, which reads as a claim about one merchant rather than as
   the sample it is.

   Layout only, deliberately: no surface, no border, no background. The panel
   this sits in is drawn by the section that renders it, and giving the ticker a
   second card would put a card inside a card.

   The two things this block has to get right are the reserved height — the
   profile is variable-length prose and a section that resizes under the reader
   every few seconds is worse than a static number — and the disclaimer, which
   is set at a readable size rather than as fine print. It is not decoration:
   the figures are generated, and the line saying so is what makes showing them
   honest. */
.rc-savings-ticker__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.rc-savings-ticker__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* A dot with a ring expanding out of it. Two elements because the ring is the
   one that animates and the dot has to stay put. */
.rc-savings-ticker__pulse {
  position: relative;
  display: inline-flex;
  flex: none;
  width: 8px;
  height: 8px;
}

.rc-savings-ticker__pulse::before,
.rc-savings-ticker__pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--rc-success-top);
}

.rc-savings-ticker__pulse::before {
  opacity: 0.6;
  animation: rc-savings-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
}

.rc-savings-ticker__toggle {
  padding: 4px var(--space-3);
  border: 1px solid var(--rc-line);
  border-radius: 999px;
  background: none;
  color: var(--rc-text-secondary);
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition:
    border-color var(--rc-motion-fast) var(--rc-ease-premium),
    color var(--rc-motion-fast) var(--rc-ease-premium);
}

.rc-savings-ticker__toggle:hover {
  border-color: var(--rc-line-strong);
  color: var(--rc-text-primary);
}

/* 188px, and it is a floor rather than a fixed height: the longest profile —
   a French-length business type in a two-word city with a four-figure saving —
   sets it, and reserving it means the CTA below never moves. */
.rc-savings-ticker__body {
  position: relative;
  min-height: 188px;
  margin-top: var(--space-6);
}

.rc-savings-ticker__card.is-entering {
  animation: rc-savings-in 350ms var(--rc-ease-premium);
}

.rc-savings-ticker__merchant {
  margin: 0;
  color: var(--rc-text-primary);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.375;
}

/* Tabular figures and a little tracking, because the masked half of the name is
   a run of identical bullets and a proportional face closes them up into a
   smear. */
.rc-savings-ticker__business {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.rc-savings-ticker__context {
  color: var(--rc-text-secondary);
}

.rc-savings-ticker__owner {
  margin: 6px 0 0;
  color: var(--rc-text-secondary);
  font-size: 0.875rem;
}

.rc-savings-ticker__figures {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  column-gap: var(--space-8);
  row-gap: var(--space-4);
  margin-top: var(--space-6);
}

.rc-savings-ticker__amount-label {
  margin: 0;
  color: var(--rc-text-disabled);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.rc-savings-ticker__amount {
  margin: 6px 0 0;
  color: var(--rc-success-top);
  font-family: var(--font-mono);
  font-size: 3rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.rc-savings-ticker__shield {
  width: 14px;
  height: 14px;
  flex: none;
}

.rc-savings-ticker__chargeback {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 6px 14px;
  border: 1px solid var(--rc-line-strong);
  border-radius: 999px;
  background: rgba(24, 190, 124, 0.12);
  color: var(--rc-success-border);
  font-size: 0.875rem;
  font-weight: 600;
}

.rc-savings-ticker__foot {
  margin-top: 28px;
  padding-top: var(--space-5);
  border-top: 1px solid var(--rc-line);
}

.rc-savings-ticker__note {
  margin: var(--space-4) 0 0;
  color: var(--rc-text-disabled);
  font-size: 0.75rem;
  line-height: 1.625;
}

@keyframes rc-savings-ping {
  75%,
  100% {
    transform: scale(2);
    opacity: 0;
  }
}

@keyframes rc-savings-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* No entry animation and no pulse. The rotation itself also stops — theme.js
   reads the same query and swaps the Pause control for a manual "Show
   another" — so nothing in the panel changes unless the reader asks it to. */
@media (prefers-reduced-motion: reduce) {
  .rc-savings-ticker__pulse::before,
  .rc-savings-ticker__card.is-entering {
    animation: none;
  }
}


/* ── Article furniture the last wave shipped unstyled ──────────────────────
   Nine selectors, all emitted by `functions.php` and none of them defined
   anywhere in this file, so every one of them was rendering as a browser
   default on a real page. The list is that file's own — it names all nine in
   the docblock above `rc_theme_render_reading_progress()` — and each rule below
   answers the specific default it was falling back to. */

/* The reading-progress rail: a fixed 4px strip across the top of the viewport
   whose inner bar is widened on scroll by `assets/js/theme.js`. Without a rule
   the strip is a zero-height div and the bar an empty inline span, which is why
   it was safe to ship ahead of this — it drew nothing rather than drawing
   something wrong. `aria-hidden` in the markup, because it says nothing the
   scrollbar does not.

   `z-index` is a literal 50 rather than a `--z-*` token: the strip's one job is
   to sit over the header, and the header's own stack is what it has to clear. */
.rc-reading-progress {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 50;
  height: 4px;
  background: var(--surface-cloud);
}

.rc-reading-progress__bar {
  display: block;
  width: 0;
  height: 100%;
  background: var(--rc-blue-600);
  transition: width 150ms linear;
}

/* Nothing widens without the scroll handler, so nothing needs to animate when
   the reader has asked for less motion either. */
@media (prefers-reduced-motion: reduce) {
  .rc-reading-progress__bar {
    transition: none;
  }
}

/* The legal document's published/reviewed pair. A browser draws a bare <dl> as
   a stacked, indented list — the <dd> carries a 40px start margin by default —
   which on all 39 legal documents put two dates in a four-line block where the
   app draws one small row. */
.rc-doc-dates {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin: var(--space-4) 0 0;
  font-size: 0.875rem;
  line-height: 1.25rem;
  color: var(--rc-text-secondary);
}

.rc-doc-dates__pair {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.rc-doc-dates dt {
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-doc-dates dd {
  /* The UA's 40px `margin-inline-start` on a <dd> is the whole reason this
     block reads as an indented list rather than as a row. */
  margin: 0;
}

/* The two contents rails — the article's and the legal document's. Both borrow
   `.rc-list`, which is right for its `list-style: none` and wrong for
   everything else it brings: an 8px blue dot per item and a `--space-3` gap
   between them. The app draws neither. Counted off the shipped bundle, that is
   7,597 dots across 807 article rails and 381 across 39 legal ones, on lists
   that run to 17 and 16 entries at their longest. `.rc-list` is kept rather
   than dropped because it also sets `list-style: none`, and the legal <ol>'s
   labels already begin "1.", "2." — a bare list would number them twice. */
.rc-toc {
  margin-top: var(--space-8);
}

.rc-toc__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: var(--space-4) 0 0;
  padding: 0;
}

.rc-toc__list > li {
  padding-inline-start: 0;
  font-size: 0.9375rem;
  line-height: 1.5rem;
}

/* The dot is drawn by `.rc-list > li::before`, which this has to switch off
   rather than merely recolour: it is positioned as well as painted. */
.rc-toc__list > li::before {
  content: none;
}

.rc-toc__list a {
  color: var(--rc-text-secondary);
  text-decoration: none;
}

.rc-toc__list a:hover,
.rc-toc__list a:focus-visible {
  color: var(--rc-text-blue);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Two columns for the legal rail, which is the only difference between the
   two. Its entries are clause numbers and short titles — "3. Eligibility" —
   where an article's are full section headings that would hyphenate in half a
   measure. */
.rc-toc--legal .rc-toc__list {
  display: block;
  columns: 2;
  column-gap: var(--space-10);
}

.rc-toc--legal .rc-toc__list > li {
  break-inside: avoid;
  margin-block-end: var(--space-1);
}

@media (max-width: 639px) {
  .rc-toc--legal .rc-toc__list {
    columns: 1;
  }
}

/* `#direct-answer` — the citable passage, and the one paragraph on a content
   page an answer engine deep-links. `PageIntro` gives it a left cyan rule and a
   68ch measure, and it inherits neither from `.rc-lead`. */
.rc-lead--answer {
  max-width: 68ch;
  padding-inline-start: var(--space-5);
  border-inline-start: 2px solid var(--rc-border-cyan);
  color: var(--rc-text-primary);
}

/* The article's date line sits a step under the byline above it. */
.rc-card__meta--dates {
  font-size: 0.75rem;
  color: var(--rc-text-disabled);
}


/* ── Section heading, promoted to the page h1 ──────────────────────────────
   `.rc-dev-copy .rc-h2` already carries the `mt-4` the app puts under the
   eyebrow. On the 137 pages whose lead darkFeature IS the page title the same
   heading is an <h1>, so it needs the same margin — without this the promoted
   heading sits flush against the eyebrow on every one of them. */
.rc-dev-copy .rc-h1 {
  margin-top: var(--space-4);
}


/* ── Product hero ──────────────────────────────────────────────────────────
   One band, matching `ProductHero`. Copy (eyebrow, h1, answer, benefits,
   buttons) on the wide side; photograph or interface mock on the narrow side.
   Both halves are one surface — flat white rather than the app token's radial
   pool, because a gradient laid on two stacked elements used to draw two light
   pools with a seam between them. */

.rc-h1-scale--product,
.rc-product-hero {
  background: var(--rc-band-raised);
}

/* `py-16 lg:py-24` on the grid in the app, and the rule is its `border-b`.
   Top padding is this band's now: the page header no longer sits above it. */
.rc-section.rc-product-hero {
  padding-block: var(--space-16);
  border-block-end: 1px solid var(--rc-line);
}

@media (min-width: 1024px) {
  .rc-section.rc-product-hero {
    padding-block: var(--space-24);
  }
}

.rc-product-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-12);
  align-items: start;
}

@media (min-width: 1024px) {
  /* Twelve tracks with a span, not two weighted tracks — the same reason
     `.rc-hero-layout` gives: 7/5 of twelve is not expressible as a two-track
     ratio without sub-pixel drift against the rest of the page. The copy
     takes the wide side. Explicit columns, never auto-flow: a child that
     sized itself from its text used to push the visual onto the next row. */
  .rc-product-hero__grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--space-10);
  }

  .rc-product-hero__copy {
    grid-column: 1 / span 7;
    min-width: 0;
  }

  .rc-product-hero__visual {
    grid-column: 8 / span 5;
    min-width: 0;
    align-self: start;
    /* Sticky on tall viewports so the visual stays beside the copy as the
       reader moves down it. */
    position: sticky;
    top: 112px;
  }
}

.rc-product-hero__grid > * {
  min-width: 0;
  overflow-wrap: break-word;
}

.rc-product-hero__copy > :first-child {
  margin-top: 0;
}

.rc-product-hero__copy .rc-eyebrow {
  margin-bottom: var(--space-4);
}

.rc-product-hero__copy .rc-h1 {
  margin-top: 0;
}

.rc-product-hero__copy .rc-lead--answer {
  margin-top: var(--space-6);
  max-width: 54ch;
}

.rc-product-hero__copy .rc-actions {
  margin-top: var(--space-8);
}

.rc-product-hero__benefits {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-6) 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  color: var(--rc-text-secondary);
}

.rc-product-hero__benefits > li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.rc-product-hero__benefits .rc-trust-strip__check {
  flex: none;
  color: var(--rc-success-top);
}

.rc-product-hero__visual {
  min-width: 0;
}

/* `rounded-[var(--rc-radius-card)] border border-[var(--rc-line)]
   shadow-[var(--rc-shadow-lg)]` — the app names all three tokens and this file
   defines all three, so none of them is substituted. */
.rc-product-hero__photo {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
  box-shadow: var(--rc-shadow-lg);
}

/* ── Device gallery: three photographed chapters, then the other terminals ──
   `TerminalGallery.tsx`, which leads all three device pages. Its own container
   is capped at 1180 rather than at the site's 1440: a device photograph beside
   one paragraph on a 1440 measure leaves the paragraph on a 700px line. */
.rc-device-gallery .rc-container,
.rc-device-siblings .rc-container {
  max-width: 1180px;
}

/* `py-16 lg:py-24` — its own rhythm, a notch under the showcase band's. */
.rc-section.rc-section--gallery {
  padding-block: var(--space-16);
}

@media (min-width: 1024px) {
  .rc-section.rc-section--gallery {
    padding-block: var(--space-24);
  }
}

.rc-device-gallery__chapters {
  display: flex;
  flex-direction: column;
  gap: var(--space-20);
}

.rc-device-gallery__chapter {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-10);
  align-items: center;
}

@media (min-width: 1024px) {
  .rc-device-gallery__chapters {
    gap: 112px;
  }

  .rc-device-gallery__chapter {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-16);
  }

  /* The photograph is always first in the markup and the sides alternate here,
     which is exactly what `lg:[&>*:first-child]:order-2` does in the app. Below
     this width the grid is one column and the order is the source order on
     every chapter: the photo, then the claim it illustrates. */
  .rc-device-gallery__chapter--flip > .rc-device-gallery__frame {
    order: 2;
  }
}

/* The frame is what the accent pool is positioned against, so it establishes
   the containing block. `62%` on a phone: the devices are portrait cutouts and
   a full-width one pushes the copy a screen and a half down the page. */
.rc-device-gallery__frame {
  position: relative;
  width: 62%;
  max-width: 22rem;
  margin-inline: auto;
}

@media (min-width: 1024px) {
  .rc-device-gallery__frame {
    width: 100%;
    max-width: none;
  }
}

/* The light behind the device. The app floats a blurred disc of `--rc-accent`
   at 18%; a radial stop is the same picture and needs no extra element, no
   library and no compositor layer. Sized in per cent so it tracks the photo at
   every width rather than needing its own breakpoints.

   THE COLOUR IS THE ACCENT, not the page's glow blue. `--rc-accent` is
   `var(--rc-teal)` in the app's `.variant-n`, which wraps the whole device
   page, so the pool is #077f95 on a light page and #11d9e8 on a dark one —
   this file's own `--rc-teal`, and the reason it is read as a token rather
   than frozen: painting one value would put the light page's disc on the dark
   one. `color-mix` carries the alpha; the rgba pair above it is the light
   value for a browser that cannot parse the function, since a `background`
   that does not parse is dropped and leaves no pool at all. */
.rc-device-gallery__frame::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 82%;
  height: 72%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(7, 127, 149, 0.28) 0%, rgba(7, 127, 149, 0) 70%);
  background: radial-gradient(circle, color-mix(in srgb, var(--rc-teal) 28%, transparent) 0%, transparent 70%);
  pointer-events: none;
}

.rc-device-gallery__photo {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 40px 70px rgba(4, 12, 32, 0.35));
}

.rc-device-gallery__copy > :first-child {
  margin-top: 0;
}

/* 12px semibold rather than `.rc-eyebrow`'s 11px bold: the gallery kicker is
   the one eyebrow on the site the app draws a step larger and a weight lighter,
   and it is the first line of a chapter rather than a label above a band. */
.rc-device-gallery__kicker {
  margin-bottom: 0;
  font-size: 0.75rem;
  font-weight: 600;
}

.rc-device-gallery__title {
  margin-top: var(--space-3);
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.02em;
  max-width: none;
}

.rc-device-gallery__body {
  max-width: 46ch;
  font-size: 1.05rem;
  line-height: 1.625;
}

/* ── The other two terminals ── */
.rc-device-siblings__title {
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  max-width: none;
}

.rc-device-siblings__summary {
  max-width: 52ch;
  margin-top: var(--space-3);
  font-size: 1.02rem;
}

.rc-device-siblings__list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  margin: var(--space-10) 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 640px) {
  .rc-device-siblings__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.rc-device-siblings__card {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  height: 100%;
  padding: var(--space-6);
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-2xl);
  background: var(--rc-band-panel);
  text-decoration: none;
  transition: border-color var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-device-siblings__card:hover,
.rc-device-siblings__card:focus-visible {
  border-color: var(--rc-border-cyan);
}

.rc-device-siblings__photo {
  flex: none;
  width: auto;
  height: 112px;
  object-fit: contain;
  filter: drop-shadow(0 18px 30px rgba(4, 12, 32, 0.28));
}

.rc-device-siblings__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.rc-device-siblings__name {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-device-siblings__tag {
  margin-top: var(--space-1);
  font-size: 0.95rem;
  color: var(--rc-text-secondary);
}

.rc-device-siblings__cta {
  margin-top: var(--space-3);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--rc-text-blue);
}

.rc-device-siblings__card:hover .rc-device-siblings__cta,
.rc-device-siblings__card:focus-visible .rc-device-siblings__cta {
  text-decoration: underline;
  text-underline-offset: 3px;
}


/* ── Terminal cinema ───────────────────────────────────────────────────────
   A midnight island in both palettes, like `.rc-island-dark` in the app: it
   re-pins the tokens its children read, so the band is light-on-dark whichever
   way the page is themed. `.rc-cta-panel` does the same thing for the same
   reason, and the values below are the app's own `[data-theme="light"]
   .rc-island-dark` block.

   `--rc-bg-midnight` is re-pinned first because the section's own gradient ends
   on it: left at the page value the band would fade from #01031c to #f6f8fd and
   put white text on a white surface at the bottom edge. */
.rc-cinema {
  --rc-bg-midnight: #010526;
  --rc-text-primary: #f7f9ff;
  --rc-text-secondary: #cdd9f6;
  --rc-text-blue: #78c8ff;
  --rc-text-disabled: #7085bc;
  --rc-teal: #11d9e8;
  --rc-line-soft: rgba(120, 200, 255, 0.1);
  --rc-line: rgba(120, 200, 255, 0.16);
  --rc-line-strong: rgba(44, 203, 255, 0.38);

  position: relative;
  overflow: hidden;
  border-block: 1px solid var(--rc-line);
  background:
    radial-gradient(ellipse 90% 60% at 50% 0%, rgba(1, 80, 234, 0.14), transparent 60%),
    linear-gradient(180deg, #01031c 0%, var(--rc-bg-midnight) 100%);
  color: var(--rc-text-primary);
  color-scheme: dark;
}

.rc-cinema .rc-container {
  max-width: 1280px;
}

.rc-cinema__intro {
  max-width: 48rem;
}

.rc-cinema__readout {
  margin-top: 56px;
  border: 1px solid var(--rc-line-strong);
  border-radius: var(--rc-radius-panel);
  background: rgba(2, 6, 32, 0.72);
}

/* "Rivo Go · Live demo". Mono and widely tracked, because it labels a readout
   rather than a section. */
.rc-cinema__label {
  margin: 0;
  padding: var(--space-4) var(--space-6);
  border-block-end: 1px solid var(--rc-line);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rc-teal);
}

/* The five steps of the flow. An ordered list, not the app's column of buttons:
   the buttons drive the digital twin, the twin does not port, and a control
   that changes nothing is worse than the sentence it holds. The numbers are
   suppressed because the labels are the flow — "Charge $100.00" reading as
   "3. Charge $100.00" states an order the copy already states. */
.rc-cinema__states {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}

.rc-cinema__state {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border-block-end: 1px solid var(--rc-line-soft);
}

.rc-cinema__state:last-child {
  border-block-end: 0;
}

.rc-cinema__state-label {
  flex: none;
  font-size: 15px;
  font-weight: 600;
  color: var(--rc-text-primary);
}

/* Hidden on a phone, as it is in the app: the detail is a gloss on the label
   beside it, and two lines of it under every step turns a five-item rail into
   half a screen. */
.rc-cinema__state-detail {
  display: none;
  min-width: 0;
  font-size: 0.875rem;
  color: var(--rc-text-disabled);
}

@media (min-width: 640px) {
  .rc-cinema__state-detail {
    display: block;
  }
}

.rc-cinema__meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-6);
  border-block-start: 1px solid var(--rc-line);
}

.rc-cinema__meta-label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rc-text-disabled);
}

/* Square, not pills. These are the five ways the reader can pay on the device
   and the app draws them as hard-edged mono chips — a rounded lozenge here
   would read as a status badge. */
.rc-cinema__inputs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

.rc-cinema__inputs > li {
  padding: 6px 10px;
  border: 1px solid var(--rc-line);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.18em;
  color: var(--rc-text-secondary);
}

.rc-cinema__facts {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3) var(--space-8);
  margin: 0;
}

@media (min-width: 640px) {
  .rc-cinema__facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.rc-cinema__fact {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
}

.rc-cinema__fact dt {
  flex: none;
  width: 64px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--rc-text-disabled);
}

.rc-cinema__fact dd {
  margin: 0;
  font-size: 0.875rem;
  color: var(--rc-text-secondary);
}

/* The side-profile band: the studio photograph and what it shows. */
.rc-cinema__profile {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-8);
  align-items: center;
  margin: 56px 0 0;
  padding: var(--space-8);
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-panel);
  background: rgba(2, 6, 32, 0.5);
}

@media (min-width: 1024px) {
  .rc-cinema__profile {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr);
    padding: var(--space-10);
  }
}

.rc-cinema__photo {
  display: block;
  width: 100%;
  max-width: 520px;
  height: auto;
  margin-inline: auto;
}

.rc-cinema__profile-text {
  display: block;
  min-width: 0;
}

.rc-cinema__device {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rc-text-secondary);
}

.rc-cinema__caption {
  display: block;
  max-width: 46ch;
  margin-top: var(--space-4);
  line-height: 1.625;
  color: var(--rc-text-secondary);
}


/* ── Terminal teardown ─────────────────────────────────────────────────────
   Two renderings of the same content, and exactly one of them is ever shown.

   The scrolling stage needs `assets/js/theme.js` to move: without it the four
   frames hold on the first and the reader gets four screens of scroll in which
   nothing happens. So the static rendering is the DEFAULT and the stage is the
   enhancement — `is-live` is added by the handler once it has attached, which
   is a stricter test than the site-wide `.rc-js` class (that one is set by the
   header's own enhancer and would be true on a page where this handler never
   ran). `prefers-reduced-motion` then hands the page back to the static
   rendering, which is the only condition the app itself tests. */
.rc-teardown__static {
  display: block;
  padding-block: var(--space-16);
}

@media (min-width: 1024px) {
  .rc-teardown__static {
    padding-block: var(--space-24);
  }
}

.rc-teardown__story {
  display: none;
}

.rc-teardown.is-live .rc-teardown__static {
  display: none;
}

.rc-teardown.is-live .rc-teardown__story {
  display: block;
}

@media (prefers-reduced-motion: reduce) {
  .rc-teardown.is-live .rc-teardown__static {
    display: block;
  }

  .rc-teardown.is-live .rc-teardown__story {
    display: none;
  }
}

.rc-teardown .rc-container {
  max-width: 1280px;
}

.rc-teardown__sub {
  max-width: 52ch;
}

/* The annotated still, absolutely positioned inside its own box, so the box
   has to be given a height: 1672 by 941, which is `terminal-exploded.tsx`'s
   stated geometry and the measured size of every file in
   `assets/media/terminal/`. The still's own two images do carry `width` and
   `height` from the export — it is the four frame pairs below that ship a `src`
   and nothing else. */
.rc-teardown__still {
  position: relative;
  aspect-ratio: 1672 / 941;
  width: 100%;
  margin-top: var(--space-10);
  overflow: hidden;
  border-radius: var(--radius-2xl);
}

.rc-teardown__still .rc-tframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Both sets are in the DOM and CSS chooses, rather than a script swapping
   `src`: a swap decodes a fresh 100KB image at the moment the reader toggles
   the theme, which is exactly when a blank frame is most visible. */
.rc-tframe--dark {
  opacity: 0;
}

.rc-tframe--light {
  opacity: 1;
}

[data-theme="dark"] .rc-tframe--dark {
  opacity: 1;
}

[data-theme="dark"] .rc-tframe--light {
  opacity: 0;
}

.rc-teardown__beats {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  margin: var(--space-10) 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 640px) {
  .rc-teardown__beats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.rc-teardown__kicker {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--rc-text-blue);
}

.rc-teardown__beat-title {
  margin: var(--space-2) 0 0;
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: var(--rc-tracking-heading);
  color: var(--rc-text-primary);
}

.rc-teardown__beat-body {
  margin: var(--space-1) 0 0;
  font-size: 0.9375rem;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

/* ── The scrolling stage ── */
/* 420vh of travel for four frames leaves roughly a screen of scroll per frame,
   which is slow enough to read the beat beside it. */
.rc-teardown__story {
  position: relative;
  height: 420vh;
}

.rc-teardown__stage {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  height: 100vh;
  overflow: hidden;
}

.rc-teardown__inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-8);
  align-items: center;
  width: 100%;
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: clamp(20px, 4vw, 48px);
}

@media (min-width: 1024px) {
  .rc-teardown__inner {
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr);
    gap: var(--space-12);
  }
}

/* The heading and all four beats occupy the same column and the same box: the
   heading leads, then hands the space to whichever beat is current. Absolute
   positioning is what stops the column resizing as they hand over, and the
   `min-height` is what stops the frame beside it moving while they do. */
.rc-teardown__column {
  position: relative;
  z-index: var(--z-raised);
  min-height: 13rem;
}

.rc-teardown__lead,
.rc-teardown__beat {
  position: absolute;
  inset-inline: 0;
  top: 0;
}

.rc-teardown__beat {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
}

.rc-teardown__beat .rc-teardown__beat-title {
  max-width: 16ch;
  margin-top: var(--space-3);
  font-size: clamp(1.6rem, 2.8vw, 2.4rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.rc-teardown__beat .rc-teardown__beat-body {
  max-width: 44ch;
  margin-top: var(--space-4);
  font-size: 1.125rem;
  line-height: 1.625;
}

.rc-teardown__chips {
  display: flex;
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
}

.rc-teardown__chips > span {
  padding: 6px var(--space-3);
  border: 1px solid var(--rc-line-strong);
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rc-text-blue);
}

.rc-teardown__frames {
  position: relative;
  aspect-ratio: 1672 / 941;
  width: 100%;
}

/* Only opacity and transform move during the scroll. Both are compositor
   properties, so the sequence never triggers layout. */
.rc-teardown__frame {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.rc-teardown__frame:first-child {
  opacity: 1;
}

.rc-teardown__frame .rc-tframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.rc-teardown__progress {
  position: absolute;
  inset-inline: 0;
  bottom: var(--space-8);
  width: 100%;
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: clamp(20px, 4vw, 48px);
}

.rc-teardown__track {
  display: block;
  width: 100%;
  height: 1px;
  background: var(--rc-line);
}

.rc-teardown__fill {
  display: block;
  width: 0;
  height: 1px;
  background: var(--rc-text-blue);
}

.rc-teardown__progress-label {
  display: block;
  margin-top: var(--space-3);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--rc-text-secondary);
}


/* ── The fee-check page's own sub-blocks ───────────────────────────────────
   Two of them — the savings estimate and the closing link list — and both are
   secondary to the statement tool above rather than bands of their own. The app
   draws each as a rule across the content measure with the block under it, at a
   heading two steps down from `.rc-h2`: they are subheadings inside one page,
   not the openings of new sections. */
/* The rule is inset to the content measure rather than run across the band,
   because that is where the app draws it: these are subheadings inside one page
   and a full-bleed hairline would read as the seam between two. Doubled
   selectors to out-order `.rc-section`'s own padding. */
.rc-section.rc-link-list,
.rc-section.rc-fee-estimate {
  padding-block: 0;
}

.rc-link-list > .rc-container,
.rc-fee-estimate > .rc-container {
  margin-top: var(--space-10);
  padding-block-start: var(--space-10);
  border-block-start: 1px solid var(--rc-line);
}

@media (min-width: 768px) {
  .rc-link-list > .rc-container,
  .rc-fee-estimate > .rc-container {
    margin-top: var(--space-12);
    padding-block-start: var(--space-12);
  }
}

/* `text-xl font-bold md:text-2xl` — flat, not a clamp: the app steps this once
   at md and holds still either side. */
.rc-h2--sub {
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.4;
  max-width: none;
}

@media (min-width: 768px) {
  .rc-h2--sub {
    font-size: 1.5rem;
  }
}

.rc-lead--sub {
  max-width: 42rem;
  margin-top: var(--space-2);
  font-size: 0.875rem;
  line-height: 1.625;
}

.rc-rate-calculator {
  max-width: 48rem;
  margin-top: var(--space-6);
  padding: var(--space-6);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-xl);
  background: var(--surface-white);
  box-shadow: var(--shadow-card);
}

.rc-rate-calculator__period {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-primary);
}

.rc-rate-calculator__example,
.rc-rate-calculator__privacy {
  margin: var(--space-1) 0 0;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--text-muted);
}

.rc-rate-calculator__fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  margin-top: var(--space-6);
}

@media (min-width: 640px) {
  .rc-rate-calculator__fields {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .rc-rate-calculator__field--transactions {
    grid-column: 1 / -1;
  }
}

.rc-rate-calculator__field {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.rc-rate-calculator__input-wrap {
  position: relative;
  display: block;
}

.rc-rate-calculator__input-wrap input {
  width: 100%;
  min-height: 48px;
  padding: 0.75rem 3.5rem 0.75rem 1.75rem;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  background: var(--surface-white);
  color: var(--text-primary);
  font: inherit;
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
}

.rc-rate-calculator__field--transactions input {
  padding-inline-start: 0.75rem;
}

.rc-rate-calculator__input-wrap input:focus-visible {
  border-color: var(--rc-blue-600);
  outline: 2px solid color-mix(in srgb, var(--rc-blue-600) 22%, transparent);
  outline-offset: 1px;
}

.rc-rate-calculator__prefix,
.rc-rate-calculator__suffix {
  position: absolute;
  top: 50%;
  z-index: 1;
  transform: translateY(-50%);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: normal;
  color: var(--text-muted);
}

.rc-rate-calculator__prefix {
  left: 0.75rem;
}

.rc-rate-calculator__suffix {
  right: 0.75rem;
}

.rc-rate-calculator__results {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
  margin: var(--space-6) 0 0;
  padding: var(--space-6) 0 0;
  border-top: 1px solid var(--border-light);
}

@media (min-width: 640px) {
  .rc-rate-calculator__results {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.rc-rate-calculator__results div,
.rc-rate-calculator__results dt,
.rc-rate-calculator__results dd {
  margin: 0;
}

.rc-rate-calculator__results dt {
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--text-muted);
}

.rc-rate-calculator__results dd {
  margin-top: var(--space-1);
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--text-primary);
}

.rc-rate-calculator__results div:first-child dd {
  font-size: 1.5rem;
  color: var(--rc-blue-600);
}

.rc-rate-calculator__results small {
  display: block;
  margin-top: var(--space-1);
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--text-muted);
}

.rc-rate-calculator__invalid {
  margin-top: var(--space-6);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--surface-cloud);
  font-size: 0.875rem;
  color: var(--text-secondary);
}

.rc-rate-calculator__formula {
  margin: var(--space-6) 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--text-secondary);
}

@media (min-width: 768px) {
  .rc-lead--sub {
    font-size: 1rem;
  }
}

/* The sentence over the links, where the block has one — the sign-in card's
   "No merchant account yet?" and the paragraph under a closed job posting's
   heading. `job-posting-view.tsx:173` draws it at `mt-3 text-[15px]
   leading-relaxed text-[var(--rc-text-secondary)]`, and the sign-in card sets
   the same size in the same colour. Its top margin only applies where a heading
   is above it; standing alone it is the block's first line. */
.rc-link-list__lead {
  max-width: 52ch;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

.rc-link-list .rc-h2--sub + .rc-link-list__lead {
  margin-top: var(--space-3);
}

/* A plain list of links: no cards, no summaries, no bullets. Two columns from
   `sm`, because eight short labels in one column is a tall thin block at the
   bottom of a long page. */
.rc-link-list__items {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 640px) {
  .rc-link-list__items {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.rc-link-list__items a {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--rc-text-blue);
  text-decoration: none;
}

.rc-link-list__items a:hover,
.rc-link-list__items a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 4px;
}


/* ── App directory: the RapidBridge detection catalogue ────────────────────
   178 applications in 15 categories, with the vendor's own logo on each. The
   whole block was shipping with no rule of any kind in this file — group heads,
   monogram plates, capability flags and the trademark notice were all browser
   defaults on the one page whose reader is scanning for a single name. */
.rc-h2--m24 {
  max-width: 24ch;
}

/* `id="applications"` is the target of the darkFeature button above this band,
   so the band has to clear the sticky header when that link is followed —
   without this the eyebrow and the heading land underneath it. */
.rc-app-directory {
  scroll-margin-top: 96px;
}

.rc-app-directory__summary {
  max-width: 68ch;
  margin-top: var(--space-5);
  font-size: 0.9375rem;
}

/* The toolbar is `hidden` in the markup and revealed by theme.js, so a visitor
   without that file gets the catalogue rather than controls that do nothing.
   Sticky under the 80px header: the search field has to stay reachable while
   the reader is 1,200px down a list of 178. */
.rc-app-directory__toolbar {
  position: sticky;
  top: 80px;
  z-index: var(--z-raised);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-10);
  padding: var(--space-4);
  border: 1px solid var(--rc-line-strong);
  border-radius: var(--rc-radius-card);
  background: var(--rc-band-raised);
  box-shadow: var(--shadow-card);
}

@media (min-width: 1024px) {
  .rc-app-directory__toolbar {
    flex-direction: row;
    align-items: center;
  }
}

.rc-app-directory__search {
  flex: 1;
  min-width: 0;
}

.rc-app-directory__search input {
  width: 100%;
  height: 48px;
  padding-inline: var(--space-4);
  border: 1px solid var(--rc-line-strong);
  border-radius: var(--rc-radius-input);
  background: var(--rc-band-raised);
  color: var(--rc-text-primary);
  font-family: var(--font-sans);
  font-size: 15px;
}

/* The WebKit cancel button is suppressed because the design already has one
   answer to clearing the field — the reset control in the empty state — and two
   × glyphs an inch apart, one of which this file does not control, reads as a
   rendering fault. */
.rc-app-directory__search input::-webkit-search-cancel-button {
  appearance: none;
}

.rc-app-directory__scopes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.rc-app-directory__scope {
  min-height: 44px;
  padding-inline: var(--space-4);
  border: 1px solid var(--rc-line);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--rc-text-secondary);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition:
    border-color var(--rc-motion-standard) var(--rc-ease-premium),
    background-color var(--rc-motion-standard) var(--rc-ease-premium),
    color var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-app-directory__scope:hover {
  border-color: var(--rc-line-strong);
  color: var(--rc-text-primary);
}

.rc-app-directory__scope[aria-pressed="true"] {
  border-color: transparent;
  background: var(--rc-text-blue);
  color: #ffffff;
}

.rc-app-directory__count {
  margin: var(--space-3) 0 0;
  font-family: var(--font-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-secondary);
}

.rc-app-directory__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-10);
  margin-top: var(--space-10);
}

@media (min-width: 1024px) {
  .rc-app-directory__layout {
    grid-template-columns: 236px minmax(0, 1fr);
    gap: var(--space-12);
  }
}

/* `min-width: 0` is load-bearing. Below the breakpoint the rail is a
   horizontally scrolling row of sixteen chips, and a grid item defaults to
   `min-width: auto` — so the track grows to the row's full content width and
   puts a horizontal scrollbar on the whole page. */
.rc-app-directory__rail {
  min-width: 0;
}

@media (min-width: 1024px) {
  .rc-app-directory__rail {
    position: sticky;
    top: 224px;
    align-self: start;
  }
}

.rc-app-directory__rail ul {
  display: flex;
  gap: var(--space-2);
  margin: 0;
  padding: 0 0 var(--space-2);
  overflow-x: auto;
  list-style: none;
}

@media (min-width: 1024px) {
  .rc-app-directory__rail ul {
    flex-direction: column;
    padding-bottom: 0;
    overflow: visible;
  }
}

.rc-app-directory__rail > ul > li {
  flex: none;
}

@media (min-width: 1024px) {
  .rc-app-directory__rail > ul > li {
    flex: initial;
  }
}

/* Anchors rather than the app's buttons. They jump to the group heading without
   this theme's JavaScript, and theme.js turns the same elements into the app's
   filter — which is why they are not hidden the way the toolbar above is. */
.rc-app-directory__rail-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 44px;
  padding: 10px var(--space-3);
  border-radius: 10px;
  color: var(--rc-text-secondary);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background-color var(--rc-motion-standard) var(--rc-ease-premium),
    color var(--rc-motion-standard) var(--rc-ease-premium);
}

@media (min-width: 1024px) {
  .rc-app-directory__rail-link {
    white-space: normal;
  }
}

.rc-app-directory__rail-link:hover,
.rc-app-directory__rail-link:focus-visible {
  background: rgba(120, 200, 255, 0.12);
  color: var(--rc-text-primary);
}

.rc-app-directory__rail-link[aria-current="true"] {
  background: rgba(120, 200, 255, 0.12);
  color: var(--rc-text-primary);
}

/* A category the current filter has emptied. `aria-disabled` rather than
   `hidden`, so the rail keeps its shape and the reader can see that the
   category exists and holds nothing right now. */
.rc-app-directory__rail-link[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}

.rc-app-directory__rail-count {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-secondary);
}

.rc-app-directory__results {
  min-width: 0;
}

.rc-app-directory__group {
  margin-bottom: var(--space-12);
  /* The heading has to clear the sticky toolbar when the rail links jump to
     it, or the group name lands under the search field. */
  scroll-margin-top: 168px;
}

.rc-app-directory__group:last-of-type {
  margin-bottom: 0;
}

.rc-app-directory__group-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-block-end: 1px solid var(--rc-line);
}

.rc-app-directory__group-icon {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--rc-text-blue);
}

.rc-app-directory__group-title {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-app-directory__group-count {
  font-family: var(--font-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-secondary);
}

.rc-app-directory__list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 640px) {
  .rc-app-directory__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1280px) {
  .rc-app-directory__list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.rc-app-directory__app {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--rc-line);
  border-radius: 12px;
  transition:
    border-color var(--rc-motion-standard) var(--rc-ease-premium),
    background-color var(--rc-motion-standard) var(--rc-ease-premium);
}

.rc-app-directory__app:hover {
  border-color: var(--rc-line-strong);
  background: rgba(120, 200, 255, 0.04);
}

/* The plate is white in BOTH themes, which is the component's own note and not
   a styling preference: vendor marks are drawn for light backgrounds and a good
   half of these are dark ink on transparent, so on the midnight surface they
   would disappear. */
.rc-app-directory__mark {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  overflow: hidden;
  border-radius: 10px;
  background: #ffffff;
  box-shadow: 0 0 0 1px rgba(10, 23, 51, 0.12);
}

.rc-app-directory__mark img {
  width: 32px;
  height: 32px;
  object-fit: contain;
}

/* The six vendors with no logo file. The hue travels with the row — the export
   computes it from the vendor's name so the tile keeps its colour between
   renders — and the two lightnesses are the component's. */
.rc-app-directory__mark--mono {
  background: hsl(var(--rc-mono-hue, 210) 62% 94%);
  color: hsl(var(--rc-mono-hue, 210) 55% 32%);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.rc-app-directory__app-text {
  display: block;
  flex: 1;
  min-width: 0;
}

.rc-app-directory__app-name {
  display: block;
  overflow: hidden;
  font-size: 14px;
  font-weight: 600;
  color: var(--rc-text-primary);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rc-app-directory__flags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: var(--space-1);
}

.rc-app-directory__flag {
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.rc-app-directory__flag--tier {
  border: 1px solid rgba(11, 95, 208, 0.34);
  background: rgba(44, 203, 255, 0.14);
  color: var(--rc-text-blue);
}

.rc-app-directory__flag--write {
  border: 1px solid rgba(10, 122, 68, 0.34);
  background: rgba(12, 143, 79, 0.1);
  color: var(--rc-success-top);
}

.rc-app-directory__empty {
  padding: var(--space-10);
  border: 1px dashed var(--rc-line-strong);
  border-radius: var(--rc-radius-card);
  text-align: center;
}

.rc-app-directory__empty-title {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-app-directory__empty-body {
  max-width: 52ch;
  margin: var(--space-3) auto 0;
  font-size: 0.9375rem;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

.rc-app-directory__empty .rc-btn {
  margin-top: var(--space-6);
}

.rc-app-directory__attribution {
  max-width: 76ch;
  margin: var(--space-10) 0 0;
  font-size: 0.75rem;
  line-height: 1.625;
  color: var(--rc-text-disabled);
}


/* ── Card media ────────────────────────────────────────────────────────────
   The box every product card opens with. `rc_theme_sections_card_media()` has
   emitted it since the wave that taught the cards to read `image` and `icon`,
   and this file has never defined it — so 1,302 photographs were drawing at
   whatever width the card gave them, on top of each other's rows, and the 1,827
   icon cards were drawing a 24px glyph flush against the title.

   `section-renderer.tsx:293` is the specification and every value here is from
   it: `mb-5 flex aspect-[4/3] items-center justify-center overflow-hidden
   rounded-[var(--radius-lg)] bg-[var(--surface-ice)]`, with the image at
   `h-full w-full object-contain p-4`. The box is drawn whether or not there is
   anything in it, which is the app's own note: a grid where only some cards
   reserve image height steps up and down as it reads.

   `object-contain`, never cover — the device shots are cutouts with transparent
   margin and cover crops the terminal. */
.rc-card__media {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 3;
  margin-bottom: var(--space-5);
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--surface-ice);
}

.rc-card__media img {
  width: 100%;
  height: 100%;
  padding: var(--space-4);
  object-fit: contain;
  transition: transform 300ms var(--rc-ease-premium);
}

a.rc-card:hover .rc-card__media img {
  transform: scale(1.03);
}

/* The icon a card falls back to when it carries no photograph. 40px at 70%,
   opening to full on hover, which is `Icon size={40}` and the `opacity-70`
   beside it. */
.rc-card__glyph {
  width: 40px;
  height: 40px;
  color: var(--rc-text-blue);
  opacity: 0.7;
  transition: opacity 300ms var(--rc-ease-premium);
}

a.rc-card:hover .rc-card__glyph {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .rc-card__media img,
  .rc-card__glyph {
    transition: none;
  }

  a.rc-card:hover .rc-card__media img {
    transform: none;
  }
}

/* ── Awards ────────────────────────────────────────────────────────────────
   The row of third-party awards on the home page. `rc_theme_section_awards()`
   has emitted every class below since the awards case was added and this file
   defined none of them, so on all six home pages the row rendered as a stack of
   full-width badge images with three unstyled lines of text under each.

   `section-renderer.tsx:709` is the specification. One deliberate difference
   from it, and it is in the markup rather than here: the app lays the awards
   out as a centred flex-wrap row of `basis-[300px]` cards, the theme puts them
   in `.rc-grid`. Both give three across at desktop and one on a phone; the grid
   is what the markup already asks for, and changing it is a markup decision,
   not a stylesheet one. */

/* `mt-9`, not `.rc-grid`'s `mt-12`: the row opens a notch higher than a card
   grid because the copy above it is two centred lines rather than a heading
   and a lead. */
.rc-awards {
  margin-top: 36px;
}

/* `.rc-badges__title` already draws this heading — 18px semibold, centred, the
   same as the app's `text-lg font-semibold text-center`. All it brings that is
   wrong here is its own 28px bottom margin: the summary under it carries `mt-3`
   and the two would stack into 40px of white space. */
.rc-awards__title {
  margin-bottom: 0;
}

.rc-awards__note {
  max-width: 60ch;
  margin: var(--space-3) auto 0;
  font-size: 0.875rem;
  line-height: 1.625;
  text-align: center;
  color: var(--rc-text-secondary);
}

/* The card. `.rc-card` supplies the border, the radius and the hover; this
   turns it into the app's horizontal tile — badge left, three lines right — and
   fills the grid cell so a two-line award and a three-line one sit on the same
   baseline. */
.rc-awards__item {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  height: 100%;
  padding: var(--space-4);
  background: var(--rc-band-panel);
}

.rc-awards__item:hover,
.rc-awards__item:focus-visible {
  border-color: var(--rc-border-cyan);
}

/* The plate is white in both palettes, for the reason the app-directory tiles
   are: these are other people's marks, drawn for a light ground, and several of
   them are dark ink on transparent. */
.rc-awards__badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 104px;
  height: 104px;
  padding: 10px;
  border-radius: var(--radius-xl);
  background: #ffffff;
  box-shadow: var(--rc-shadow-md);
}

.rc-awards__badge img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.rc-awards__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.rc-awards__name {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--rc-text-primary);
}

.rc-awards__body {
  margin-top: 2px;
  font-size: 0.75rem;
  color: var(--rc-text-secondary);
}

.rc-awards__date {
  margin-top: var(--space-1);
  font-size: 0.75rem;
  color: var(--rc-text-disabled);
}


/* ── Fee check promo ───────────────────────────────────────────────────────
   The band that sends a reader to the statement comparison. Same story as the
   awards row: `rc_theme_section_fee_check_promo()` emits all six of these and
   the stylesheet defined none, so the pill rendered as a bare line of text, the
   numbered steps as a browser-default ordered list with the zero-padded indices
   read out beside the automatic ones, and the reassurance ticks as bullets.
   Values from `section-renderer.tsx`'s `feeCheckPromo` case. */
.rc-promo-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 6px 14px;
  border: 1px solid var(--rc-primary-border);
  border-radius: var(--radius-pill);
  background: var(--rc-band-panel);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--rc-text-blue);
}

/* The heading takes its top margin from the pill rather than from the band,
   which is what `${section.badge ? "mt-5" : ""}` does in the app: with no pill
   the heading opens the column and needs no margin at all. */
.rc-promo-badge + .rc-h2 {
  margin-top: var(--space-5);
}

/* The live dot, and the ring that pulses off it. The app draws two stacked
   spans; one element with a ::before is the same picture. */
.rc-promo-badge__dot {
  position: relative;
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rc-success-top);
}

.rc-promo-badge__dot::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--rc-success-top);
  opacity: 0.6;
}

/* `motion-safe:animate-ping` — the ring expands and fades, and only for a
   reader who has not asked for less motion. */
@media (prefers-reduced-motion: no-preference) {
  .rc-promo-badge__dot::before {
    animation: rc-promo-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
  }
}

@keyframes rc-promo-ping {
  75%,
  100% {
    transform: scale(2);
    opacity: 0;
  }
}

/* The three steps, against the accent rule the app draws down their left. */
.rc-promo-steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: var(--space-8) 0 0;
  padding: 0 0 0 var(--space-5);
  border-inline-start: 2px solid var(--rc-primary-border);
  list-style: none;
}

.rc-promo-steps > li {
  display: flex;
  gap: 14px;
}

/* Mono and tabular, so "01" and "02" occupy the same width and the copy beside
   them starts on one line. */
.rc-promo-steps__index {
  flex: none;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--rc-text-blue);
}

.rc-promo-steps__text {
  max-width: 52ch;
  font-size: 15px;
  line-height: 1.625;
  color: var(--rc-text-secondary);
}

/* The ticked assurances beside the button, not under it: they sit in the same
   `.rc-actions` row the app puts them in. */
.rc-promo-reassure {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.rc-promo-reassure > li {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--rc-text-secondary);
}


/* ── Developer band: the photograph that replaces the code panel ───────────
   Three of the 144 darkFeature bands carry an `image` instead of the API demo,
   and RapidBridge is the one a reader sees: its product is a browser panel
   reading someone else's screen, and a payment request beside its response is
   the wrong illustration for that. The <img> was drawing at the column's full
   width with no frame; the app gives it the card radius, the hairline and the
   deep shadow. */
.rc-dev-panel__image {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rc-line);
  border-radius: var(--rc-radius-card);
  box-shadow: var(--rc-shadow-lg);
}


/* ── Trust strip: the hairline and the named icon ──────────────────────────
   Two more classes `rc_theme_section_trust_strip()` emits that this file never
   defined. The separator was rendering as an empty inline span — invisible, so
   the chips ran together with nothing between them — and the icon, on the day
   `inc/icons.php` learns the five names the home page uses, would have drawn at
   whatever size the SVG box gave it.

   `section-renderer.tsx`'s `trustStrip` case is the specification for both:
   `hidden h-7 w-px shrink-0 bg-[var(--rc-line)] lg:block` on the rule, and
   `size={17} weight="bold" shrink-0 text-[var(--rc-text-blue)]` on the icon. */
.rc-trust-strip__rule {
  display: none;
  flex: none;
  width: 1px;
  height: 28px;
  background: var(--rc-line);
}

/* Desktop only. Below the breakpoint the strip is one or two columns and a
   vertical rule between stacked rows separates nothing. */
@media (min-width: 1024px) {
  .rc-trust-strip--chips > li > .rc-trust-strip__rule {
    display: block;
  }
}

/* The named glyph, where the pack draws one. Today every one of the five names
   the home page carries falls through to the tick, so nothing on the site
   reaches this rule yet — it is here so that adding the icons is one change
   rather than two. */
.rc-trust-strip__icon {
  flex: none;
  width: 17px;
  height: 17px;
  color: var(--rc-text-blue);
}


/* ── The new bands, on paper ───────────────────────────────────────────────
   Four of the blocks above are wrong on a printer for reasons no other rule
   here covers, so they are answered rather than left to chance. The main print
   block further up runs before these rules in source order and cannot reach
   them from there.

   `.rc-cinema` is the one that actually loses content: it re-pins its text
   tokens to near-white for the midnight surface it draws, and a printer drops
   the surface and keeps the text — white on white, four spec facts and five
   flow steps gone. `.rc-stats-band` is the same class of defect. */
@media print {
  .rc-cinema,
  .rc-stats-band {
    --rc-text-primary: #000000;
    --rc-text-financial: #000000;
    --rc-text-secondary: #1a1a1a;
    --rc-text-disabled: #333333;
    --rc-text-blue: #00008b;
    --rc-teal: #00008b;
    --rc-line-soft: #cccccc;
    --rc-line: #999999;
    --rc-line-strong: #666666;
    --rc-band-deep: #ffffff;

    background: #ffffff;
    color: #000000;
    color-scheme: light;
  }

  .rc-cinema__readout,
  .rc-cinema__profile {
    background: #ffffff;
  }

  /* Fixed to the viewport, so on paper it lands across the top of page one and
     says nothing about anything. */
  .rc-reading-progress {
    display: none !important;
  }

  /* Four screens of scroll collapse to four empty pages. The static rendering
     holds the same content, and on paper it is the only one that can. */
  .rc-teardown__story {
    display: none !important;
  }

  .rc-teardown__static {
    display: block !important;
  }

  /* Controls and a jump rail are both instructions to click something. */
  .rc-app-directory__toolbar,
  .rc-app-directory__rail,
  .rc-app-directory__empty {
    display: none !important;
  }

  .rc-app-directory__layout {
    display: block;
  }
}
