/* ==========================================================================
   SPSLink homepage (static prototype)
   --------------------------------------------------------------------------
   1. Fonts            5. Components shared with Hyvä names (.btn, .card, .container)
   2. Design tokens    6. Page sections (.sl-*), in page order
   3. Base / reset     7. Motion + accessibility
   4. Utilities

   The hero marquee has its own stylesheet: hp-marquee.css (loaded after this file).
   The site header and footer are NOT part of this page: Magento generates them.

   Integration notes (see ../../README.md):
   - Token names match Hyvä's (--color-primary, --color-secondary, --color-fg, --color-bg ...),
     so section 2 maps straight onto web/tailwind/hyva.config.json + the @theme block.
   - .btn / .btn-primary / .btn-secondary / .btn-size-* / .card / .container intentionally use
     Hyvä's class names, so markup that uses them needs no renaming inside a Hyvä theme.
   - Everything page-specific is prefixed .sl- and is one block per page section.
   ========================================================================== */

/* 1. Fonts: Nunito Sans variable (SIL OFL 1.1, see ../fonts/OFL-Nunito-Sans.txt), the project font ------------------- */
@font-face {
  font-family: "Nunito Sans";
  font-style: normal;
  font-weight: 200 1000;
  font-display: swap;
  src: url("../fonts/nunito-sans-latin-ext-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Nunito Sans";
  font-style: normal;
  font-weight: 200 1000;
  font-display: swap;
  src: url("../fonts/nunito-sans-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* 2. Design tokens ------------------------------------------------------------------------- */
:root {
  /* Brand (same values as the SPS Hyvä child theme: hyva.config.json) */
  --color-primary: #c8102e;
  --color-primary-darker: #a00d25;
  --color-cta: #d40f17; /* the main call-to-action buttons (.btn-primary), set by the client 2026-10-15; the brand red above stays for labels, icons and the red band */
  --color-primary-lighter: color-mix(in oklch, var(--color-primary) 80%, white);
  --color-secondary: #15191f;
  --color-night: #030304; /* the black of the Earth photo's bottom edge; the Support (FAQ) section is this colour so the two run together (2026-10-15) */
  --color-on-primary: #fff;
  --color-on-secondary: #fff;

  /* Neutrals (same names as the Hyvä @theme block) */
  --color-ink: #15191f;
  --color-ink-muted: #3d4451;
  --color-fg: var(--color-ink);
  --color-fg-secondary: var(--color-ink-muted);
  --color-bg: #f6f7f8;
  --color-surface: #fff;

  /* Extra tokens used by this page only */
  --color-border: #e5e7eb;
  --color-border-strong: #d1d5db;
  --color-primary-tint: #fef2f2;

  --font-sans: "Nunito Sans", ui-sans-serif, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";

  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
  --radius-2xl: 1rem;
  --radius-full: 9999px;
  --shadow-sm: 0 1px 2px rgb(21 25 31 / 0.06), 0 1px 3px rgb(21 25 31 / 0.08);
  --shadow-gentle: 0 0 0 1px rgb(15 23 42 / 0.03), 0 1px 2px rgb(15 23 42 / 0.04), 0 3px 12px rgb(15 23 42 / 0.045); /* very, very gentle: the trust strip's white band and the section labels (2026-10-15) */
  --shadow-lg: 0 10px 15px -3px rgb(21 25 31 / 0.1), 0 4px 6px -4px rgb(21 25 31 / 0.1);
  --shadow-2xl: 0 25px 50px -12px rgb(21 25 31 / 0.35);

  /* Space left above in-page anchor targets. 1rem now; raise it to the sticky header height once Magento's header is on the page. */
  --anchor-offset: 1rem;
  /* Page width, matched to spslink.com's page content area (measured 2026-10-14): content is 1472px max, centred, inset 40px from the
     screen edge below 1024px and 64px from 1024px up. --container-max is the box INCLUDING the gutters: 1472 + 2 x 64 = 1600px. */
  --container-max: 100rem;
  --gutter: 2.5rem;
}
@media (min-width: 1024px) { :root { --gutter: 4rem; } }

/* The page's column grid below the hero. The trust strip and the hero's tab strip are BOTH laid out on these columns from 1024px up,
   so each tab sits exactly above its trust-strip item. They are 5 because the marquee has 5 tabs and the strip has 5 points. */
:root { --sl-cols: 5; --sl-col-gap: 1.5rem; }
/* The height of the trust strip under the hero: the hero is the first screen minus this, so the strip and its five mini-cards are on the first screen too. main.js measures the real height and overrides these starting values. */
:root { --hp-below: 6.375rem; }
@media (min-width: 1024px) { :root { --hp-below: 4.75rem; } }

/* 3. Base / reset -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 0; }
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--color-fg);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, h4, p, ul, ol, figure, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
h1, h2, h3, h4 { font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; text-wrap: balance; }
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
img, svg { display: block; max-width: 100%; }
button, input { font: inherit; color: inherit; }
button { cursor: pointer; }
summary { cursor: pointer; }
table { border-collapse: collapse; }
[hidden] { display: none !important; }

.icon { width: 1.25rem; height: 1.25rem; flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* 4. Utilities ----------------------------------------------------------------------------- */
.container { width: 100%; max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Content still to be confirmed by the client: shown as [bracketed] text from the low-fi draft */
.ph { -webkit-box-decoration-break: clone; box-decoration-break: clone; padding: 0 0.25rem; border-radius: 0.25rem; background: #fef3c7; color: #78350f; font-weight: 600; box-shadow: inset 0 0 0 1px rgb(245 158 11 / 0.5); }
.ph--dark { background: rgb(245 158 11 / 0.22); color: #fde68a; }

/* 5. Components that mirror Hyvä class names ------------------------------------------------ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
  padding: 0.5rem 1rem; border: 2px solid transparent; border-radius: var(--radius-full); /* every button is a full pill (rounded-full, 2026-10-15; was --radius-lg) */
  font-weight: 600; line-height: 1.4; text-decoration: none; user-select: none; vertical-align: middle;
  background: color-mix(in srgb, var(--color-primary) 10%, transparent); color: var(--color-fg);
  transition: color 0.15s, background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.btn-primary { background: var(--color-cta); color: var(--color-on-primary); }
.btn-primary:hover { background: color-mix(in oklch, var(--color-cta) 80%, white); }
.btn-primary:active { background: var(--color-cta); }
.btn-secondary { background: var(--color-surface); border-color: var(--color-primary-lighter); color: var(--color-primary-darker); }
.btn-secondary:hover { border-color: var(--color-primary); color: var(--color-primary); }
.btn-size-sm { padding: 0.5rem 0.75rem; font-size: 0.875rem; }
.btn-size-lg { padding: 1rem 2.25rem; font-size: 1.125rem; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.6; cursor: not-allowed; }

.card {
  position: relative; border: 1px solid var(--color-border-strong); border-radius: var(--radius-xl);
  padding: 1.5rem; background: var(--color-surface); color: var(--color-fg);
  transition: box-shadow 0.15s, border-color 0.15s;
}
@media (hover: hover) { .card-interactive:hover { border-color: transparent; box-shadow: var(--shadow-lg); } }
.card-interactive:focus-within { border-color: transparent; box-shadow: var(--shadow-lg); }

/* Glass (2026-10-15): the page's boxes are translucent white (55%) with a 14 px background blur, the very gentle section-label shadow and a faint white edge instead of a grey border: the radio cards,
   the "Why a radio" table, the add-on cards and the bundle line, and the plan cards and their "Yearly renewal" box (the dark plan re-tints it below). One rule, so "more or less translucent" is one edit. */
.sl-radio-card, .sl-plan, .sl-addon, .sl-bundle, .sl-table-wrap, .sl-disclosure { border: 1px solid rgb(255 255 255 / 0.6); background: rgb(255 255 255 / 0.55); -webkit-backdrop-filter: blur(14px) saturate(1.1); backdrop-filter: blur(14px) saturate(1.1); box-shadow: var(--shadow-gentle); }

/* 6. Page sections ------------------------------------------------------------------------- */

/* Shared section scaffolding */
.sl-section { padding-block: 4rem; scroll-margin-top: var(--anchor-offset); }
@media (min-width: 1024px) { .sl-section { padding-block: 6rem; } }
.sl-section--white { background: var(--color-surface); }
.sl-section--bg { background: var(--color-bg); }
.sl-section--dark { background: var(--color-secondary); color: var(--color-on-secondary); }
.sl-head { max-width: 42rem; }
/* Section labels, one style everywhere (2026-10-15): the eyebrow above each section title (.sl-eyebrow), the hero slides' label (.hp-marquee__eyebrow, in hp-marquee.css) and the carousel cards' audience label (.sl-fit__audience) are all the same
   small translucent pill (white at 72% with a background blur) with the very gentle shadow, 10 px (was 12 / 13 / 11 px), 800 weight, 0.08em tracking, the darker brand red, with room below it. Labels that sit ON A PHOTO (the hero's, the carousel cards' and the brand band's) are black at 55% instead (same blur and size) with the brand red text before the content. If you change one, change the other two to match. */
.sl-eyebrow, .sl-fit__audience { padding: 0.3rem 0.7rem; border-radius: 999px; background: rgb(255 255 255 / 0.72); -webkit-backdrop-filter: blur(10px) saturate(1.1); backdrop-filter: blur(10px) saturate(1.1); box-shadow: var(--shadow-gentle); font-size: 0.625rem; font-weight: 800; letter-spacing: 0.08em; line-height: 1.2; text-transform: uppercase; color: var(--color-primary-darker); } /* the darker brand red: on a 72% pill over a dark photo it is about 4.5:1 (the plain brand red is 3.3:1) */
.sl-eyebrow { display: inline-block; margin-bottom: 0.75rem; }
.sl-title { margin-top: 0.75rem; font-size: clamp(1.875rem, 1.4rem + 1.6vw, 2.5rem); font-weight: 800; }
.sl-lede { margin-top: 1rem; font-size: 1.125rem; color: var(--color-fg-secondary); }

/* sps-link.hero ------------------------------------------------------------------------------ */
.sl-hero { position: relative; isolation: isolate; overflow: clip; background: linear-gradient(135deg, #fff 0%, #f9fafb 50%, var(--color-primary-tint) 100%); }
/* The intro's two sections (the scene, and the line-up with its cards) share one background, and so do all the light sections after them: the gradient is on the .sl-flow wrapper (see "Light section backgrounds" below), not on each section, so there is no seam anywhere. */
.sl-intro { isolation: auto; } /* the .sl-flow wrapper around it is the isolated group and carries the gradient */
/* The wrapper, not the sections, is the isolated group: the static photos are drawn with mix-blend-mode: multiply, which only drops their white if the gradient behind them is in the same group. */
.sl-intro .sl-hero { isolation: auto; background: none; }
.sl-hero__grid { display: grid; gap: 3rem; align-items: center; padding-block: 3.5rem; }
.sl-hero__title { margin-top: 1rem; font-size: clamp(2.25rem, 1.5rem + 3.2vw, 3.5rem); line-height: 1.05; font-weight: 800; }
.sl-hero__lede { margin-top: 1.5rem; max-width: 36rem; font-size: 1.125rem; color: var(--color-fg-secondary); }
.sl-hero__ctas { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin-top: 2rem; }
.sl-hero__checks { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; margin-top: 2rem; font-size: 0.875rem; font-weight: 600; }
.sl-hero__checks li { display: flex; align-items: center; gap: 0.5rem; }
.sl-hero__checks .icon { color: var(--color-primary); }
.sl-hero__fine { margin-top: 1rem; font-size: 0.75rem; color: var(--color-fg-secondary); }
@media (max-width: 479px) { .sl-hero__ctas .btn { width: 100%; } }
@media (min-width: 1024px) { .sl-hero__grid { grid-template-columns: 1.1fr 0.9fr; padding-block: 6rem; } }

/* Centred intro: label, headline, text, one button, then the product photography large underneath, in the middle. */
.sl-hero__center { display: flex; flex-direction: column; align-items: center; padding-top: 4rem; text-align: center; }
.sl-hero__center .sl-hero__title { margin-top: 0.75rem; }
.sl-hero__center .sl-hero__lede { max-width: 40rem; }
.sl-hero__center .sl-hero__ctas { justify-content: center; }
.sl-hero__center[data-ptt-demo] { padding-bottom: 3rem; }
/* There is no static ring any more, so this is just the space under the button. The talk's ripples reach up to about 9% of the stage width above the stage, but they are faint by then and draw behind the button. */
.sl-hero__center .sl-demo { margin-top: 3rem; }
/* The stage: three studio shots on white (SPSLink Go). mix-blend-mode: multiply makes the white disappear into the section background and keeps the radios black.
   --w is the centre picture's width; the side pictures are 82% of it and tuck in 20% so the radios stand close but never touch. Phones show the centre picture only. */
.sl-hero__stage { --w: min(88vw, 24rem); display: flex; justify-content: center; align-items: flex-end; margin-top: 1rem; padding-bottom: 2rem; }
.sl-hero__shot { display: block; flex: none; height: auto; mix-blend-mode: multiply; }
.sl-hero__shot--center { position: relative; z-index: 2; width: var(--w); }
.sl-hero__shot--side { display: none; width: calc(var(--w) * 0.82); }
@media (min-width: 640px) {
  .sl-hero__stage { --w: clamp(12rem, 34vw, 40rem); padding-bottom: 3rem; }
  .sl-hero__shot--side { display: block; }
  /* margin-bottom lifts each side picture so all three radios stand on the same line: each studio shot has a different amount of floor under the radio
     (measured: 10.3% of the picture for the centre one, 8.3% left, 7.2% right, the sides being 82% as big). */
  .sl-hero__shot--side:first-child { margin-right: calc(var(--w) * -0.2); margin-bottom: calc(var(--w) * 0.035); }
  .sl-hero__shot--side:last-child { width: calc(var(--w) * 0.82 * 1.26); margin-left: calc(var(--w) * -0.2); margin-bottom: calc(var(--w) * 0.0428); } /* the Commander: 1.26 x the handhelds' box (see the scene rule), its base on the same line */
}
@media (min-width: 1024px) { .sl-hero__center { padding-top: 6rem; } .sl-hero__stage { --w: clamp(24rem, 38vw, 42rem); } }

/* The scroll scene: "Loop everyone in" (the talk animation, unchanged) turning into "The product line-up" (2026-10-14; the old Option B is its final state).
   Only desktop gets the scene (main.js sets data-sequence="on"). Phones, tablets, no JS and reduced motion get the animation, and "The product line-up" as its own static section after it
   (sps-link.lineup-static, which main.js hides while the scene is on). So by default the line-up copy and the side devices inside the scene are not shown at all. */
.sl-lineup__pin { display: flex; flex-direction: column; align-items: center; width: 100%; }
.sl-lineup__copy, .sl-lineup__a { display: flex; flex-direction: column; align-items: center; }
.sl-lineup__b, .sl-lineup__runway, .sl-demo__side { display: none; }
/* From 1024px the stage is sized by the width (a third device fits each side of it) and by the height, so the whole pinned scene (copy, stage, message bubble) fits the screen:
   --sl-stage-w is the stage's width (576px at most), --sl-w the centre device's picture (95% of it). Below that, the stage is the plain 36rem it was. */
@media (min-width: 1024px) {
  .sl-intro { --sl-stage-w: min(36rem, 40vw, max(18rem, calc((100svh - 27rem) / 0.9))); --sl-w: calc(var(--sl-stage-w) * 0.95); }
  .sl-lineup .sl-demo--lg { max-width: var(--sl-stage-w); }
}
/* The sequence (main.js sets data-sequence="on" on the host from 1024px, not reduced motion, and --seq-a/-b/-l/-r, each 0..1, as you scroll through the runway):
   a  the Loop-everyone-in copy leaves (up and out)      l / r  the left / right device fades up in place      b  the line-up copy fades up in place
   The Go and its stage never move: the pin holds them while the rest of the scene changes. The talk's own elements (group, ripples, lines, bubble) are hidden once it starts (.is-past). */
[data-sequence="on"] .sl-lineup__pin { position: sticky; top: 4rem; display: block; }
[data-sequence="on"] .sl-lineup__copy { display: grid; justify-items: center; }
[data-sequence="on"] .sl-lineup__a, [data-sequence="on"] .sl-lineup__b { display: flex; flex-direction: column; align-items: center; grid-area: 1 / 1; }
[data-sequence="on"] .sl-lineup__a { opacity: calc(1 - var(--seq-a, 0)); transform: translateY(calc(var(--seq-a, 0) * -1.5rem)); }
[data-sequence="on"] .sl-lineup__b { opacity: var(--seq-b, 0); transform: translateY(calc((1 - var(--seq-b, 0)) * 2rem)); }
[data-lineup][data-sequence="on"].is-a-gone .sl-lineup__a, [data-lineup][data-sequence="on"]:not(.is-b-shown) .sl-lineup__b { visibility: hidden; }
[data-sequence="on"].is-past .sl-lineup__a { pointer-events: none; }
[data-sequence="on"] .sl-lineup__runway { display: block; height: 85svh; }
[data-sequence="on"] .sl-lineup__a, [data-sequence="on"] .sl-lineup__b, [data-sequence="on"] .sl-demo__side { will-change: opacity, transform; }
[data-sequence="on"] .sl-demo__side { display: block; position: absolute; z-index: 0; max-width: none; height: auto; width: calc(var(--sl-w) * 0.82); pointer-events: none; }
/* Where the two side devices stand: 82% of the centre picture's width, their centres exactly over the outer radio cards (--sl-pitch, the distance between card centres, measured by main.js; the old
   Option B's 0.71 of the centre picture's width is the fallback), and lifted by the measured floor gap of each studio shot (3.5% / 4.4% of the centre picture's width) so all three stand on one line. */
[data-sequence="on"] .sl-demo__side--left { left: calc(50% - var(--sl-pitch, var(--sl-w) * 0.71) - var(--sl-w) * 0.41); top: calc(var(--sl-stage-w) * 0.11615); opacity: var(--seq-l, 0); transform: translateY(calc((1 - var(--seq-l, 0)) * 3rem)); }
[data-sequence="on"] .sl-demo__side--right { --sl-k: 1.26; /* the Commander is drawn larger than the handhelds' 0.82 box so the three devices read as somewhat proportionate (2026-10-15); same centre over its card, same baseline */ width: calc(var(--sl-w) * 0.82 * var(--sl-k)); left: calc(50% + var(--sl-pitch, var(--sl-w) * 0.71) - var(--sl-w) * 0.41 * var(--sl-k)); top: calc(var(--sl-stage-w) * 0.1076 - var(--sl-w) * 0.7735 * (var(--sl-k) - 1)); opacity: var(--seq-r, 0); transform: translateY(calc((1 - var(--seq-r, 0)) * 3rem)); }
[data-sequence="on"].is-past .sl-demo__node, [data-sequence="on"].is-past .sl-demo__bubble, [data-sequence="on"].is-past .sl-demo__rings { opacity: 0 !important; transition: opacity 0.25s ease; }

/* Talk-group demo (hero visual). JS toggles .is-talking on [data-ptt-demo]. */
.sl-demo { width: 100%; max-width: 27rem; margin-inline: auto; }
.sl-demo--lg { max-width: 36rem; } /* the centred intro: a bigger stage than the old two-column hero had */
.sl-demo__stage { position: relative; aspect-ratio: 1 / 1.08; }
/* At rest the stage is just the radio and the group: no rings, no lines. Both are drawn only while the talk plays (see [data-ptt-demo].is-talking below). */
.sl-demo__rings { position: absolute; left: 50%; top: 40.7%; width: 118%; max-width: none; translate: -50% -50%; z-index: -1; pointer-events: none; overflow: visible; }
/* The voice ripples (main.js block 3a, ported from the pixai-digital read-aloud ripples, with reds in place of its blues): rings spread from the radio with each stressed syllable of the message,
   a thick band that fades out towards the middle of the ring (a radial gradient: clear in the middle, strongest at the rim) and gets thicker, blurrier and fainter the further out, each taking on more of the other red on the way. JS sets radius, thickness, blur, colour and opacity every frame. */
.sl-demo__rings, .sl-demo__echo { --sl-ripple-a: var(--color-primary); --sl-ripple-b: #ff4a3a; }
.sl-demo__rings circle, .sl-demo__echo circle { visibility: hidden; }
.sl-demo__rings stop, .sl-demo__echo stop { stop-color: currentColor; }
/* The members' own ripples: the same band-that-fades-inward rings, smaller, spreading from the avatar when that member answers. The svg is built by main.js inside the avatar and sits behind it (z-index -1
   in the member's own stacking context). 340% of the avatar wide, so the avatar's radius is 29.4 of its 200 units. */
.sl-demo__echo { position: absolute; left: 50%; top: 50%; width: 340%; max-width: none; aspect-ratio: 1; translate: -50% -50%; z-index: -1; pointer-events: none; overflow: visible; } /* each gradient's `color` is set every frame: the mix of the two reds */
/* The radio is the SPSLink Trek front photo cut out of its white background (assets/img/trek-cutout.webp, made by tools/cutout-radio.mjs: a real alpha channel, soft floor shadow kept),
   so it sits IN FRONT of the animation (z-index 1: over the ripples at -1, under the group at 2) and nothing shows through it. The square picture holds a radio that is
   39% of its width and 84% of its height, so it is drawn at 95% of the stage to give a radio about 80% as tall as the stage, centred on the ripples.
   Scroll lift (main.js sets --lift on [data-lift], 0..1, 1 = finished; with no JS or reduced motion it stays 1): the radio rises and enlarges into place (starts 14% lower and 22% smaller, always fully opaque: no fade). */
.sl-demo__radio { --p: calc(1 - var(--lift, 1)); position: absolute; left: 50%; top: -2%; width: 95%; max-width: none; height: auto; translate: -50% 0; z-index: 1;
  transform: translateY(calc(var(--p) * 14%)) scale(calc(1 - var(--p) * 0.22)); transition: scale 0.25s; }
@media (prefers-reduced-motion: reduce) { .sl-demo__radio { transform: none; } }
.sl-demo__node {
  position: absolute; z-index: 2; display: grid; justify-items: center; gap: 0.25rem; width: 5.25rem; text-align: center;
  font-size: 0.6875rem; line-height: 1.2; color: var(--color-fg-secondary);
  opacity: 0; translate: 0 0.5rem; transition: opacity 0.4s ease, translate 0.4s ease; /* the group is not there at rest: it appears when the talk starts (below) */
}
.sl-demo__node strong { display: block; font-size: 0.75rem; color: var(--color-fg); }
.sl-demo__avatar { position: relative; display: grid; place-items: center; width: 3.25rem; height: 3.25rem; border-radius: 50%; background: var(--color-surface); box-shadow: 0 0 0 1px var(--color-border-strong), var(--shadow-sm); color: var(--color-fg); transition: background 0.3s, color 0.3s, box-shadow 0.3s; }
.sl-demo__avatar .icon { width: 1.5rem; height: 1.5rem; }
/* The group sits in two level pairs, mirrored left and right. */
.sl-demo__node--1 { left: 0; top: 8%; }
.sl-demo__node--2 { right: 0; top: 8%; }
.sl-demo__node--3 { left: 0; top: 58%; }
.sl-demo__node--4 { right: 0; top: 58%; }
/* The message bubble: the dark pill with what was said, and "You" under it, outside it, set like the members' names. It sits just under the radio (the device's base is at 76.5% of the stage, its
   floor shadow about 79%), between the lower pair's answers. Where the stage is narrower than about 520px (screens under 600px) the pill is wider than the gap between those answers, so it is placed from the lower pair instead, just under them. */
.sl-demo__bubble { position: absolute; z-index: 3; left: 50%; top: 81%; translate: -50% 0.5rem; display: grid; justify-items: center; gap: 0.3rem; width: max-content; max-width: min(26rem, 100%); opacity: 0; transition: opacity 0.25s, translate 0.25s; pointer-events: none; }
.sl-demo__text { padding: 0.6rem 0.9rem; border-radius: var(--radius-2xl); background: var(--color-secondary); color: #fff; font-size: 0.8125rem; line-height: 1.35; text-wrap: balance; box-shadow: var(--shadow-lg); }
.sl-demo__bubble b { font-size: 0.75rem; line-height: 1.2; color: var(--color-fg); }
/* Each answer lives inside its member, centred right under the name. */
.sl-demo__reply { position: absolute; z-index: 3; top: 100%; left: 50%; margin: 0.3rem 0 0; padding: 0.3rem 0.6rem; border-radius: 999px; background: var(--color-surface); box-shadow: var(--shadow-lg), 0 0 0 1px var(--color-border); color: var(--color-fg); font-size: 0.6875rem; line-height: 1.6; font-weight: 700; white-space: nowrap; opacity: 0; translate: -50% 0.35rem; transition: opacity 0.25s, translate 0.25s; pointer-events: none; }
.sl-demo__controls { display: grid; justify-items: center; gap: 0.5rem; margin-top: 0.5rem; }
.sl-demo__help { font-size: 0.8125rem; color: var(--color-fg-secondary); }

[data-ptt-demo].is-talking .sl-demo__radio { scale: 1.03; }
[data-ptt-demo].is-talking { --sl-ptt-fill: var(--color-primary-lighter); }
/* The group comes in with the talk, one after another, and stays through the answers (.is-heard); it fades away when they have gone. */
[data-ptt-demo].is-talking .sl-demo__node, [data-ptt-demo].is-heard .sl-demo__node { opacity: 1; translate: 0 0; }
[data-ptt-demo].is-talking .sl-demo__node--2 { transition-delay: 0.1s; }
[data-ptt-demo].is-talking .sl-demo__node--3 { transition-delay: 0.2s; }
[data-ptt-demo].is-talking .sl-demo__node--4 { transition-delay: 0.3s; }
[data-ptt-demo].is-talking .sl-demo__bubble, [data-ptt-demo].is-heard .sl-demo__bubble { opacity: 1; translate: -50% 0; }
.sl-demo__node.is-answered .sl-demo__avatar { background: var(--color-primary-tint); box-shadow: 0 0 0 2px var(--color-primary), var(--shadow-sm); color: var(--color-primary); }
/* A member answers (main.js adds .is-answered at a random moment after the message): the avatar lights up, the answer appears under the name, and ripples spread from the avatar (.sl-demo__echo). */
.sl-demo__node.is-answered .sl-demo__reply { opacity: 1; translate: -50% 0; }
@media (max-width: 599px) { .sl-demo__bubble { top: calc(58% + 6.9rem); } } /* the stage is narrow: the pill is wider than the gap between the lower pair's answers, so it goes under them */
@media (max-width: 359px) { .sl-hero__center[data-ptt-demo] { padding-bottom: 4.5rem; } } /* the message needs two lines here, so the bubble hangs further below the stage */
@media (max-width: 479px) {
  .sl-demo__node { width: 4.25rem; font-size: 0.625rem; }
  .sl-demo__avatar { width: 2.75rem; height: 2.75rem; }
  .sl-demo__bubble { top: calc(58% + 6.1rem); } /* smaller members: just under the lower pair's names and answers */
}

/* sps-link.proof ----------------------------------------------------------------------------- */
.sl-proof { position: relative; z-index: 2; background: var(--color-surface); box-shadow: var(--shadow-gentle); } /* the white band itself has the very gentle shadow (z-index: so it shows over the intro's background below); no rule under it, the intro starts at the same white */
/* Below 1024px the points are mini-cards in a horizontal scroller (snap, next card peeking in from the right); from 1024px up they are the 5-column grid. */
.sl-proof__list { display: flex; gap: 0.75rem; padding-block: 1.125rem; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; scroll-padding-inline: var(--gutter); scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.sl-proof__list::-webkit-scrollbar { display: none; }
.sl-proof__list::after { content: ""; flex: none; width: calc(var(--gutter) - 0.75rem); } /* end spacing: a scroller ignores its own end padding in some browsers */
.sl-proof__item { display: flex; align-items: center; gap: 0.75rem; flex: 0 0 auto; width: max-content; padding: 0.75rem 1rem; border: 1px solid var(--color-border); border-radius: var(--radius-xl); background: var(--color-bg); scroll-snap-align: start; font-size: 0.875rem; line-height: 1.35; }
.sl-proof__icon { display: grid; place-items: center; flex: none; width: 2.5rem; height: 2.5rem; border-radius: var(--radius-lg); background: var(--color-primary-tint); color: var(--color-primary); }
/* One line of text per mini-card (phones: the card is as wide as its text; from 1024px the text may wrap, evenly, inside its column). */
.sl-proof__item strong { min-width: 0; font-weight: 800; white-space: nowrap; }
@media (min-width: 1024px) {
  /* minmax(0,..): a plain 1fr cannot shrink below its content (it pushed the page wider than ~300px screens). Same columns as the hero tabs. */
  /* Each column is as wide as its text (one line), spread edge to edge; if the row ever gets too narrow the columns shrink evenly and the text wraps, balanced. */
  .sl-proof__list { display: grid; grid-template-columns: repeat(var(--sl-cols), minmax(0, max-content)); justify-content: space-between; gap: 1.25rem var(--sl-col-gap); overflow: visible; scroll-snap-type: none; }
  .sl-proof__list::after { display: none; }
  .sl-proof__item { width: auto; padding: 0; border: 0; border-radius: 0; background: none; }
  .sl-proof__item strong { white-space: normal; text-wrap: balance; overflow-wrap: anywhere; }
}

/* sps-link.use-cases ------------------------------------------------------------------------- */
/* The filter chips stay on ONE line and scroll sideways when they do not fit (phones); below 640px the row runs to the screen edges, like the page's other scrollers. */
.sl-filter { display: flex; flex-wrap: nowrap; gap: 0.5rem; margin: 1rem -0.75rem -1rem; padding: 1rem 0.75rem; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.sl-filter::-webkit-scrollbar { display: none; }
.sl-filter[hidden] { display: none; }
@media (max-width: 639px) { .sl-filter { margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); scroll-padding-inline: var(--gutter); } .sl-filter::after { content: ""; flex: none; width: 0.5rem; } }
/* The filter chips and the arrows use the section-label look (2026-10-15): translucent white with a background blur and the very gentle shadow, no border (the row has padding so the shadow is not clipped by its scroller). */
.sl-chip { flex: none; white-space: nowrap; padding: 0.5rem 1rem; border: 0; border-radius: 999px; background: rgb(255 255 255 / 0.72); -webkit-backdrop-filter: blur(10px) saturate(1.1); backdrop-filter: blur(10px) saturate(1.1); box-shadow: var(--shadow-gentle); font-size: 0.875rem; font-weight: 700; transition: background 0.15s, color 0.15s; }
.sl-chip:hover { background: rgb(255 255 255 / 0.95); color: var(--color-primary); }
.sl-chip[aria-pressed="true"] { background: var(--color-secondary); color: #fff; }
/* sps-link.use-cases: "Where SPSLink fits" as a carousel of portrait situation cards, in the style of Aceternity's "Testimonials Photo Carousel" (a Pro React block, not used: this is plain
   HTML/CSS and a small script, nothing to download). Equal portrait photo cards in a full-bleed row; the chosen card expands to show its text over the photo and the row slides so it sits on the
   left. Only flex-basis and the text's grid row animate, on 14 cards; images load lazily. Without JS every card is shown open in a row you can scroll. ---------------------------------------- */
.sl-fits__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 2rem; }
.sl-fits__head > :first-child { min-width: 0; } /* so the chip row can scroll inside its column instead of widening the page */
.sl-fits__nav { display: flex; flex: none; gap: 0.5rem; }
.sl-fits__nav[hidden] { display: none; }
.sl-fits__arrow { display: grid; place-items: center; width: 3rem; height: 3rem; border: 0; border-radius: 50%; background: rgb(255 255 255 / 0.72); -webkit-backdrop-filter: blur(10px) saturate(1.1); backdrop-filter: blur(10px) saturate(1.1); box-shadow: var(--shadow-gentle); color: var(--color-fg); transition: background 0.15s, color 0.15s, opacity 0.15s; }
.sl-fits__arrow:hover:not(:disabled) { background: var(--color-secondary); color: #fff; }
.sl-fits__arrow:disabled { opacity: 0.35; cursor: default; }
.sl-fits__arrow .icon { width: 1.25rem; height: 1.25rem; }
.sl-fits { --fit-h: 33rem; --fit-w: 10.5rem; --fit-w-active: min(86vw, 22rem); --fit-gap: 0.75rem; --fit-r: var(--radius-xl); margin-top: 2.5rem; } /* --fit-r: the cards' corner radius, the site's own scale: 12px on phones (narrow cards), 16px from 640px */
@media (min-width: 640px) { .sl-fits { --fit-h: 36rem; --fit-w: 13rem; --fit-w-active: 30rem; --fit-r: var(--radius-2xl); } }
@media (min-width: 1024px) { .sl-fits { --fit-h: 38rem; --fit-w: 15.5rem; --fit-w-active: 42rem; } }
/* The row runs to both screen edges; its first card lines up with the page's content (the container's left edge). */
.sl-fits__track { display: flex; gap: var(--fit-gap); padding-inline: calc((100% - min(100%, var(--container-max))) / 2 + var(--gutter)); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.sl-fits__track::-webkit-scrollbar { display: none; }
.sl-fits[data-ready] .sl-fits__track { cursor: grab; }
.sl-fits__track.is-dragging { cursor: grabbing; -webkit-user-select: none; user-select: none; }
.sl-fits__track.is-dragging .sl-fit { pointer-events: none; }
.sl-fit__media img { -webkit-user-drag: none; pointer-events: none; }
.sl-fits__track::after { content: ""; flex: none; width: var(--fit-tail, 0px); } /* room at the end, so the last card can slide to the left (main.js sets --fit-tail) */
.sl-fit { position: relative; isolation: isolate; flex: 0 0 var(--fit-w); height: var(--fit-h); overflow: clip; border-radius: var(--fit-r); background: #0f172a; color: #fff; cursor: pointer; contain: layout paint; transition: flex-basis 0.55s cubic-bezier(0.22, 0.8, 0.2, 1); }
.sl-fit[hidden] { display: none; }
.sl-fit.is-active { flex-basis: var(--fit-w-active); cursor: default; }
.sl-fit__media { position: absolute; inset: 0; z-index: -1; }
.sl-fit__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.sl-fit__media .sl-slot { width: 100%; height: 100%; aspect-ratio: auto; border-radius: 0; }
.sl-fit__media::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to top, rgb(2 6 23 / 0.9) 0%, rgb(2 6 23 / 0.6) 40%, rgb(2 6 23 / 0) 72%); }
/* The placeholder tiles keep their art-direction note, moved to the top so the text has the bottom. */
.sl-fit .sl-slot__note { top: 1rem; bottom: auto; } /* the placeholder cards show only their "Photo: ..." note (the big temporary icons were removed 2026-10-15) */
.sl-fit__body { position: absolute; inset: auto 0 0; display: flex; flex-direction: column; gap: 0.5rem; padding: 1.25rem; }
.sl-fit__audience { width: fit-content; max-width: 100%; margin-bottom: 0.5rem; background: rgb(0 0 0 / 0.55); box-shadow: 0 0 0 1px rgb(255 255 255 / 0.08); color: var(--color-primary); } /* on a photo: black translucent with the brand red text (2026-10-15), same size and blur as the other section labels */ /* the pill is as wide as its text (the body is a flex column, which would stretch it); the look is the shared section-label rule above */
.sl-fit__title { font-size: 1.0625rem; line-height: 1.2; font-weight: 800; }
.sl-fit.is-active .sl-fit__title { font-size: 1.625rem; }
.sl-fit__toggle { display: block; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.sl-fit__toggle:focus-visible { outline: none; }
.sl-fit:has(.sl-fit__toggle:focus-visible) { outline: 3px solid #fff; outline-offset: -4px; } /* the focus ring follows the card's rounded corners */
/* Before the script runs (or without it) every card is open. */
.sl-fits:not([data-ready]) .sl-fit { flex-basis: var(--fit-w-active); cursor: default; }
.sl-fits:not([data-ready]) .sl-fit__title { font-size: 1.625rem; }
@media (prefers-reduced-motion: reduce) { .sl-fit { transition: none; } }
@media (max-width: 639px) { .sl-fits__head { align-items: stretch; flex-direction: column; gap: 1.25rem; } .sl-fits__nav { align-self: flex-start; } } /* stretch: the chip row gets the column's width, so it scrolls instead of growing */

/* Photo slot: swap the whole element for an <img class="sl-photo"> when photography is chosen */
.sl-slot { position: relative; isolation: isolate; display: grid; place-items: center; overflow: hidden; background: linear-gradient(135deg, var(--from), var(--to)); color: rgb(255 255 255 / 0.25); }
.sl-slot::before { content: ""; position: absolute; inset: 0; z-index: -1; opacity: 0.4; background: radial-gradient(circle at 20% 15%, rgb(255 255 255 / 0.22), transparent 45%), radial-gradient(circle at 85% 90%, rgb(0 0 0 / 0.35), transparent 50%); }
.sl-slot .icon { width: 6rem; height: 6rem; }
.sl-slot__note { position: absolute; inset-inline: 0.75rem; bottom: 0.75rem; font-size: 0.6875rem; line-height: 1.35; color: rgb(255 255 255 / 0.8); }
.sl-slot--16x10 { aspect-ratio: 16 / 10; }
.sl-slot--4x3 { aspect-ratio: 4 / 3; border-radius: var(--radius-2xl); }
.sl-slot--amber { --from: #d97706; --to: #7c2d12; }
.sl-slot--emerald { --from: #059669; --to: #134e4a; }
.sl-slot--slate { --from: #64748b; --to: #0f172a; }
.sl-slot--lime { --from: #65a30d; --to: #14532d; }
.sl-slot--rose { --from: #e11d48; --to: #7f1d1d; }
.sl-slot--indigo { --from: #4f46e5; --to: #0f172a; }
.sl-slot--steel { --from: #64748b; --to: #1e293b; }
.sl-photo { width: 100%; height: 100%; object-fit: cover; }

/* sps-link.compare --------------------------------------------------------------------------- */
.sl-table-wrap { margin-top: 2.5rem; overflow-x: auto; border-radius: var(--radius-2xl); }
.sl-table { width: 100%; min-width: 45rem; font-size: 0.875rem; text-align: left; }
.sl-table thead tr { background: rgb(255 255 255 / 0.45); font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-fg-secondary); }
.sl-table th, .sl-table td { padding: 1.25rem; vertical-align: top; }
.sl-table tbody tr + tr { border-top: 1px solid rgb(15 23 42 / 0.07); }
.sl-table tbody th { font-weight: 800; }
.sl-table td { color: var(--color-fg-secondary); }
.sl-table .sl-us { background: rgb(254 242 242 / 0.6); color: var(--color-fg); font-weight: 600; }
.sl-table thead .sl-us { border-top: 4px solid var(--color-primary); background: var(--color-primary-tint); color: var(--color-primary); font-weight: 800; }
.sl-table .sl-us span { display: flex; align-items: flex-start; gap: 0.5rem; }
.sl-table .sl-us .icon { margin-top: 0.125rem; color: var(--color-primary); }


/* sps-link.radios: the three radio cards, no pictures, under the devices (part of the intro, see index.html). ---------------------------------------------------------- */
.sl-radios { display: grid; gap: 1.5rem; padding-block: 1rem 4rem; }
.sl-radio-card { display: flex; flex-direction: column; align-items: flex-start; }
.sl-radio-card h3 { font-size: 1.5rem; } /* the name is the first thing in the card now that the availability tags are gone (2026-10-15) */
.sl-radio-card p { margin-top: 0.5rem; color: var(--color-fg-secondary); }
.sl-bullets { display: grid; gap: 0.5rem; margin-top: 1rem; font-size: 0.875rem; }
.sl-bullets li { display: flex; align-items: flex-start; gap: 0.5rem; }
.sl-bullets .icon { width: 1rem; height: 1rem; margin-top: 0.2rem; color: var(--color-primary); }
.sl-radio-card .sl-bullets { margin-bottom: 1.5rem; }
.sl-radio-card .btn { margin-top: auto; } /* the buttons line up along the bottom of the cards */
/* The cards fade up into place as they come into view (main.js block 2c adds .is-in): up from 3.5rem and in, in a waterfall (0.2 s apart) when they sit in a row. Only once the script
   has said it is ready, so without JS they are simply there; none of it with reduced motion. */
.sl-radios[data-reveal] .sl-radio-card { opacity: 0; transform: translateY(3.5rem); transition: opacity 0.9s ease, transform 1s cubic-bezier(0.22, 0.8, 0.2, 1); }
.sl-radios[data-reveal] .sl-radio-card.is-in { opacity: 1; transform: none; }
@media (min-width: 1024px) {
  .sl-radios[data-reveal] .sl-radio-card:nth-child(1) { transition-delay: 0.1s; }
  .sl-radios[data-reveal] .sl-radio-card:nth-child(2) { transition-delay: 0.3s; }
  .sl-radios[data-reveal] .sl-radio-card:nth-child(3) { transition-delay: 0.5s; }
}
/* One card per row, three side by side from 1024px. On desktop the scene (main.js sets data-sequence="on" on .sl-intro) pins the devices and the cards start under them: they are pulled up over the
   empty strip below the devices' floor line, which is 21% of the stage's width tall plus the intro's own spacing, leaving a gap of about 10%. */
@media (min-width: 1024px) {
  .sl-radios { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .sl-intro[data-sequence="on"] .sl-lineup-cards { margin-top: calc(var(--sl-stage-w) * -0.23); }
}

/* sps-link.add-ons --------------------------------------------------------------------------- */
.sl-addons { display: grid; gap: 1.5rem; margin-top: 3rem; }
.sl-addon { display: flex; flex-direction: column; gap: 0.75rem; }
.sl-addon__icon { display: grid; place-items: center; width: 3rem; height: 3rem; border-radius: var(--radius-xl); background: var(--color-primary-tint); color: var(--color-primary); }
.sl-addon__icon .icon { width: 1.5rem; height: 1.5rem; }
.sl-addon h3 { font-size: 1.125rem; }
.sl-addon__text { font-size: 0.875rem; color: var(--color-fg-secondary); }
.sl-addon__price { margin-top: auto; padding-top: 0.75rem; font-size: 0.875rem; font-weight: 800; }
.sl-addon__for { font-size: 0.75rem; color: var(--color-fg-secondary); }
.sl-bundle { margin-top: 2rem; padding: 1.25rem; border-radius: var(--radius-xl); font-size: 0.875rem; }
.sl-addons__monthly { margin-top: 0.75rem; font-size: 0.875rem; color: var(--color-fg-secondary); }
@media (min-width: 640px) { .sl-addons { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .sl-addons { grid-template-columns: repeat(4, 1fr); } }

/* sps-link.plans ----------------------------------------------------------------------------- */
.sl-plans { display: grid; gap: 1.5rem; margin-top: 3rem; }
.sl-plan { display: flex; flex-direction: column; gap: 1rem; }
.sl-plan h3 { font-size: 1.125rem; }
.sl-plan__price { font-size: 3rem; font-weight: 800; line-height: 1; letter-spacing: -0.02em; }
.sl-plan__price small { font-size: 1rem; font-weight: 500; letter-spacing: 0; color: var(--color-fg-secondary); }
.sl-plan__lede { font-size: 0.875rem; color: var(--color-fg-secondary); }
.sl-plan .sl-bullets { margin-top: 0; }
.sl-plan .btn { align-self: flex-start; margin-top: auto; }
.sl-plan--dark { border-color: rgb(255 255 255 / 0.08); background: rgb(21 25 31 / 0.86); color: var(--color-on-secondary); } /* the dark plan: the same glass, tinted dark (86%) so its white text stays readable */
.sl-plan--dark h3 { color: #fff; }
.sl-plan--dark .sl-plan__price small, .sl-plan--dark .sl-plan__lede { color: rgb(255 255 255 / 0.75); }
.sl-plan--dark .sl-bullets .icon { color: #fca5a5; }
@media (min-width: 1024px) { .sl-plans { grid-template-columns: repeat(2, 1fr); } }

.sl-disclosure { margin-top: 1.5rem; border-radius: var(--radius-xl); }
.sl-disclosure > summary { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem 1.5rem; font-weight: 800; list-style: none; }
.sl-disclosure > summary::-webkit-details-marker { display: none; }
.sl-disclosure > summary .icon { transition: transform 0.2s; }
.sl-disclosure[open]:not([data-closing]) > summary .icon { transform: rotate(180deg); }
.sl-disclosure__body { overflow-x: auto; padding: 0 1.5rem 1.5rem; }
.sl-mini-table { width: 100%; min-width: 30rem; font-size: 0.875rem; text-align: left; }
.sl-mini-table thead { font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-fg-secondary); }
.sl-mini-table th, .sl-mini-table td { padding-block: 0.75rem; }
.sl-mini-table tbody tr { border-top: 1px solid var(--color-border); }
.sl-mini-table td { color: var(--color-fg-secondary); }
.sl-mini-table .sl-right { text-align: right; color: var(--color-fg); font-weight: 800; }

/* sps-link.brand ----------------------------------------------------------------------------- */
.sl-brand-band { display: grid; gap: 2.5rem; align-items: center; }
/* The SatellitePhoneStore band (2026-10-15): the Earth-at-night photo is the section's background (it replaced the team-member photo placeholder), the text sits on its dark
   sky at the left, and a soft scrim keeps it readable. The photo's own edges are near-black, so the band's hard edges stay hard. */
.sl-brand { display: flex; align-items: center; min-height: clamp(30rem, 46vw, 42rem); background: linear-gradient(to bottom, rgb(3 3 4 / 0) calc(100% - 7rem), #030304 100%), linear-gradient(to bottom, rgb(2 5 15 / 0.72) 0%, rgb(2 5 15 / 0.35) 55%, rgb(2 5 15 / 0) 100%), #030304 url("../img/brand-earth.webp") center bottom / cover no-repeat; }
.sl-brand .sl-brand-band { width: 100%; grid-template-columns: minmax(0, 1fr); }
@media (max-width: 639px) { .sl-brand { padding-bottom: 11rem; background: linear-gradient(to bottom, rgb(3 3 4 / 0) calc(100% - 7rem), #030304 100%), linear-gradient(to bottom, rgb(2 5 15 / 0.78) 0%, rgb(2 5 15 / 0.5) 62%, rgb(2 5 15 / 0) 100%), #030304 url("../img/brand-earth.webp") center bottom / cover no-repeat; } } /* phones: the text sits above the Earth instead of on it */
.sl-brand .sl-brand-band__text { max-width: 36rem; }
@media (min-width: 1024px) { .sl-brand { background: linear-gradient(to bottom, rgb(3 3 4 / 0) calc(100% - 7rem), #030304 100%), linear-gradient(90deg, rgb(2 5 15 / 0.8) 0%, rgb(2 5 15 / 0.55) 38%, rgb(2 5 15 / 0) 68%), #030304 url("../img/brand-earth.webp") center bottom / cover no-repeat; } }
.sl-brand-band .sl-eyebrow { margin-top: 0; font-size: 0.625rem; letter-spacing: 0.08em; background: rgb(0 0 0 / 0.55); box-shadow: 0 0 0 1px rgb(255 255 255 / 0.08); color: var(--color-primary); } /* also on a photo (the Earth): black translucent like the hero's and the carousel cards' labels */ /* `.sl-brand-band p` (18 px, white) would otherwise win over the shared section-label rule */
.sl-brand-band h2 { margin-top: 0.75rem; font-size: clamp(1.875rem, 1.4rem + 1.6vw, 2.5rem); color: #fff; }
.sl-brand-band p { margin-top: 1.25rem; font-size: 1.125rem; color: rgb(255 255 255 / 0.75); }
.sl-brand-band a.sl-link { display: inline-block; margin-top: 2rem; font-weight: 800; color: #fff; text-underline-offset: 0.3em; }
.sl-brand-band a.sl-link:hover { color: #fca5a5; }
@media (min-width: 1024px) { .sl-brand-band { grid-template-columns: repeat(2, 1fr); } }

/* sps-link.faq ------------------------------------------------------------------------------- */
.sl-faq { display: grid; gap: 2.5rem; }
.sl-faq__list { border: 1px solid var(--color-border); border-radius: var(--radius-2xl); background: var(--color-surface); }
.sl-faq__item + .sl-faq__item { border-top: 1px solid var(--color-border); }
.sl-faq__item summary { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.25rem 1.5rem; font-weight: 800; list-style: none; }
.sl-faq__item summary::-webkit-details-marker { display: none; }
.sl-faq__item summary .icon { color: var(--color-fg-secondary); transition: transform 0.2s; }
.sl-faq__item[open]:not([data-closing]) summary .icon { transform: rotate(180deg); } /* data-closing: set by main.js block 2d while it animates shut, so the chevron turns back at once */
.sl-faq__item p { padding: 0 1.5rem 1.5rem; color: var(--color-fg-secondary); }
/* The Support section is black (it runs on from the Earth photo in the band above), so its text and list are the light-on-dark versions (2026-10-15). */
.sl-faq-section { color: #fff; }
.sl-faq-section .sl-title { color: #fff; }
.sl-faq-section .sl-lede { color: rgb(255 255 255 / 0.72); }
.sl-faq-section .sl-faq__list { border-color: rgb(255 255 255 / 0.1); background: rgb(255 255 255 / 0.04); }
.sl-faq-section .sl-faq__item + .sl-faq__item { border-top-color: rgb(255 255 255 / 0.1); }
.sl-faq-section .sl-faq__item summary { color: #fff; }
.sl-faq-section .sl-faq__item summary .icon { color: rgb(255 255 255 / 0.6); }
.sl-faq-section .sl-faq__item p { color: rgb(255 255 255 / 0.74); }
.sl-faq-section .sl-eyebrow { background: rgb(0 0 0 / 0.55); box-shadow: 0 0 0 1px rgb(255 255 255 / 0.08); color: var(--color-primary); } /* a label on black: the same black translucent pill as on photos */
.sl-faq-section :focus-visible { outline-color: #fff; }
@media (min-width: 1024px) { .sl-faq { grid-template-columns: 1fr 2fr; } }

/* sps-link.updates --------------------------------------------------------------------------- */
.sl-updates { position: relative; isolation: isolate; overflow: hidden; padding-block: 4rem; background: var(--color-primary); color: var(--color-on-primary); scroll-margin-top: var(--anchor-offset); }
.sl-updates__rings { position: absolute; left: -5rem; top: -8rem; z-index: -1; width: auto; height: 140%; color: rgb(255 255 255 / 0.1); fill: none; stroke: currentColor; stroke-width: 2; }
.sl-updates__grid { display: grid; gap: 2rem; align-items: center; }
.sl-updates h2 { font-size: clamp(1.875rem, 1.4rem + 1.6vw, 2.5rem); color: #fff; }
.sl-updates p.sl-updates__lede { margin-top: 1rem; font-size: 1.125rem; color: rgb(255 255 255 / 0.85); }
.sl-form-row { display: flex; flex-direction: column; gap: 0.75rem; }
.sl-input { width: 100%; padding: 0.75rem 1.25rem; border: 1px solid var(--color-border-strong); border-radius: var(--radius-full); background: #fff; color: var(--color-ink); } /* a pill, like the buttons beside it (2026-10-15); a little more side padding so the text clears the curve */
.sl-input::placeholder { color: #6b7280; }
.sl-input:focus-visible { outline: 2px solid var(--color-secondary); outline-offset: 2px; }
.sl-updates .sl-input { border-color: transparent; }
.sl-updates .sl-input:focus-visible { outline-color: #fff; }
.btn-dark { background: var(--color-secondary); color: var(--color-on-secondary); padding: 0.75rem 2rem; white-space: nowrap; }
.btn-dark:hover { background: var(--color-ink-muted); }
.sl-form-status { margin-top: 0.75rem; min-height: 1.5rem; font-size: 0.875rem; }
.sl-updates .sl-form-status { color: #fff; font-weight: 600; }
.sl-input[aria-invalid="true"] { outline: 2px solid #fecaca; outline-offset: 2px; }
/* The button sits INSIDE the field (2026-10-15): from 480 px the row itself is the white pill (border, focus ring) and the input and the button are inside it; below 480 px they stack as two separate pills. */
@media (min-width: 480px) {
  .sl-form-row { flex-direction: row; align-items: center; gap: 0.5rem; padding: 0.3125rem; border: 1px solid var(--color-border-strong); border-radius: var(--radius-full); background: #fff; }
  .sl-form-row .sl-input { flex: 1; min-width: 0; padding: 0.5625rem 0.5rem 0.5625rem 1rem; border: 0; border-radius: 0; background: transparent; }
  .sl-form-row .sl-input:focus-visible, .sl-form-row .sl-input[aria-invalid="true"] { outline: 0; }
  .sl-form-row .btn { flex: none; padding: 0.5rem 1.5rem; }
  .sl-form-row:focus-within { outline: 2px solid var(--color-secondary); outline-offset: 2px; }
  .sl-updates .sl-form-row { border-color: transparent; }
  .sl-updates .sl-form-row:focus-within { outline-color: #fff; }
  .sl-form-row:has(.sl-input[aria-invalid="true"]), .sl-updates .sl-form-row:has(.sl-input[aria-invalid="true"]) { outline: 2px solid #fecaca; outline-offset: 2px; } /* after the focus rules, so an error shows even while the field has focus */
}
@media (min-width: 1024px) { .sl-updates__grid { grid-template-columns: repeat(2, 1fr); } }

/* sps-link.activate -------------------------------------------------------------------------- */
.sl-activate { padding-block: 3.5rem; background: var(--color-surface); scroll-margin-top: var(--anchor-offset); }
.sl-activate__grid { display: grid; gap: 1.5rem; align-items: center; }
.sl-activate h2 { font-size: clamp(1.5rem, 1.2rem + 1vw, 1.875rem); }
.sl-activate p.sl-activate__lede { margin-top: 0.5rem; color: var(--color-fg-secondary); }
.sl-activate .sl-form-status { color: var(--color-fg-secondary); }
@media (max-width: 479px) { .sl-activate .btn-primary { padding: 0.75rem 2rem; } } /* stacked button only; inside the pill field it has the shared inset size */
@media (min-width: 1024px) { .sl-activate__grid { grid-template-columns: repeat(2, 1fr); } }

/* Light section backgrounds (2026-10-15) ---------------------------------------------------------------
   One continuous background for all the light sections from the intro to Plans (the .sl-flow wrapper in index.html; the sections inside are transparent), so there is no seam
   anywhere. It is ONE long diagonal linear gradient, the same one the intro always had (white at the top-left, off-white, then light red toward the bottom-right, which is how
   "Loop everyone in" turns into the line-up), only continued down the whole run (about 6,000 px on desktop): off-white, a gray stretch, and a second light-red stretch at
   the bottom. Because the colour depends on x + y, the light red is a hint on ONE side at any height, and it slides from the right (the line-up) to the left (further down)
   as you scroll. Every step is eased (smoothstep), so there are no kinks. Nothing moves.
   The dark band and the red updates band are NOT blended (the user's call, 2026-10-15). The FAQ (between them) and Activate have their own short diagonal gradients: light red
   at the bottom-left of the FAQ, at the right of Activate.
   Tuning: --tone-* are the tones; the stops of the first gradient say where along the diagonal each one peaks (percent). */
:root {
  --tone-white: #fff;
  --tone-off: #f8f9fa;
  --tone-gray: #eceef1;
  --tone-rose: #fef3f4; /* the red hint: paler (2026-10-15; was #fdeaec; the intro's very first end colour was #fef2f2) */
}
.sl-flow {
  isolation: isolate; /* the static line-up photos are multiplied onto this background, which only drops their white if it is in the same group */
  background: linear-gradient(135deg,
    var(--tone-white) 0%,
    color-mix(in oklab, var(--tone-off) 4.3%, var(--tone-white)) 3%,
    color-mix(in oklab, var(--tone-off) 15.6%, var(--tone-white)) 6%,
    color-mix(in oklab, var(--tone-off) 31.6%, var(--tone-white)) 9%,
    color-mix(in oklab, var(--tone-off) 50%, var(--tone-white)) 12%,
    color-mix(in oklab, var(--tone-off) 68.4%, var(--tone-white)) 15%,
    color-mix(in oklab, var(--tone-off) 84.4%, var(--tone-white)) 18%,
    color-mix(in oklab, var(--tone-off) 95.7%, var(--tone-white)) 21%,
    var(--tone-off) 24%,
    color-mix(in oklab, var(--tone-rose) 4.3%, var(--tone-off)) 27%,
    color-mix(in oklab, var(--tone-rose) 15.6%, var(--tone-off)) 30%,
    color-mix(in oklab, var(--tone-rose) 31.6%, var(--tone-off)) 33%,
    color-mix(in oklab, var(--tone-rose) 50%, var(--tone-off)) 36%,
    color-mix(in oklab, var(--tone-rose) 68.4%, var(--tone-off)) 39%,
    color-mix(in oklab, var(--tone-rose) 84.4%, var(--tone-off)) 42%,
    color-mix(in oklab, var(--tone-rose) 95.7%, var(--tone-off)) 45%,
    var(--tone-rose) 48%,
    color-mix(in oklab, var(--tone-off) 4.3%, var(--tone-rose)) 49.8%,
    color-mix(in oklab, var(--tone-off) 15.6%, var(--tone-rose)) 51.5%,
    color-mix(in oklab, var(--tone-off) 31.6%, var(--tone-rose)) 53.2%,
    color-mix(in oklab, var(--tone-off) 50%, var(--tone-rose)) 55%,
    color-mix(in oklab, var(--tone-off) 68.4%, var(--tone-rose)) 56.8%,
    color-mix(in oklab, var(--tone-off) 84.4%, var(--tone-rose)) 58.5%,
    color-mix(in oklab, var(--tone-off) 95.7%, var(--tone-rose)) 60.2%,
    var(--tone-off) 62%,
    color-mix(in oklab, var(--tone-gray) 4.3%, var(--tone-off)) 63.5%,
    color-mix(in oklab, var(--tone-gray) 15.6%, var(--tone-off)) 65%,
    color-mix(in oklab, var(--tone-gray) 31.6%, var(--tone-off)) 66.5%,
    color-mix(in oklab, var(--tone-gray) 50%, var(--tone-off)) 68%,
    color-mix(in oklab, var(--tone-gray) 68.4%, var(--tone-off)) 69.5%,
    color-mix(in oklab, var(--tone-gray) 84.4%, var(--tone-off)) 71%,
    color-mix(in oklab, var(--tone-gray) 95.7%, var(--tone-off)) 72.5%,
    var(--tone-gray) 74%,
    color-mix(in oklab, var(--tone-off) 4.3%, var(--tone-gray)) 75.5%,
    color-mix(in oklab, var(--tone-off) 15.6%, var(--tone-gray)) 77%,
    color-mix(in oklab, var(--tone-off) 31.6%, var(--tone-gray)) 78.5%,
    color-mix(in oklab, var(--tone-off) 50%, var(--tone-gray)) 80%,
    color-mix(in oklab, var(--tone-off) 68.4%, var(--tone-gray)) 81.5%,
    color-mix(in oklab, var(--tone-off) 84.4%, var(--tone-gray)) 83%,
    color-mix(in oklab, var(--tone-off) 95.7%, var(--tone-gray)) 84.5%,
    var(--tone-off) 86%,
    color-mix(in oklab, var(--tone-rose) 4.3%, var(--tone-off)) 87.4%,
    color-mix(in oklab, var(--tone-rose) 15.6%, var(--tone-off)) 88.8%,
    color-mix(in oklab, var(--tone-rose) 31.6%, var(--tone-off)) 90.1%,
    color-mix(in oklab, var(--tone-rose) 50%, var(--tone-off)) 91.5%,
    color-mix(in oklab, var(--tone-rose) 68.4%, var(--tone-off)) 92.9%,
    color-mix(in oklab, var(--tone-rose) 84.4%, var(--tone-off)) 94.2%,
    color-mix(in oklab, var(--tone-rose) 95.7%, var(--tone-off)) 95.6%,
    var(--tone-rose) 97%,
    var(--tone-rose) 97.4%,
    var(--tone-rose) 97.8%,
    var(--tone-rose) 98.1%,
    var(--tone-rose) 98.5%,
    var(--tone-rose) 98.9%,
    var(--tone-rose) 99.2%,
    var(--tone-rose) 99.6%,
    var(--tone-rose) 100%);
}
.sl-flow .sl-section { background: none; }
#faq { background: var(--color-night); } /* black, so it runs on from the Earth photo above (2026-10-15); was a light gray / light red gradient */
.sl-activate {
  background: linear-gradient(135deg,
    var(--tone-white) 0%,
    color-mix(in oklab, var(--tone-off) 4.3%, var(--tone-white)) 6.2%,
    color-mix(in oklab, var(--tone-off) 15.6%, var(--tone-white)) 12.5%,
    color-mix(in oklab, var(--tone-off) 31.6%, var(--tone-white)) 18.8%,
    color-mix(in oklab, var(--tone-off) 50%, var(--tone-white)) 25%,
    color-mix(in oklab, var(--tone-off) 68.4%, var(--tone-white)) 31.2%,
    color-mix(in oklab, var(--tone-off) 84.4%, var(--tone-white)) 37.5%,
    color-mix(in oklab, var(--tone-off) 95.7%, var(--tone-white)) 43.8%,
    var(--tone-off) 50%,
    color-mix(in oklab, var(--tone-rose) 4.3%, var(--tone-off)) 56.2%,
    color-mix(in oklab, var(--tone-rose) 15.6%, var(--tone-off)) 62.5%,
    color-mix(in oklab, var(--tone-rose) 31.6%, var(--tone-off)) 68.8%,
    color-mix(in oklab, var(--tone-rose) 50%, var(--tone-off)) 75%,
    color-mix(in oklab, var(--tone-rose) 68.4%, var(--tone-off)) 81.2%,
    color-mix(in oklab, var(--tone-rose) 84.4%, var(--tone-off)) 87.5%,
    color-mix(in oklab, var(--tone-rose) 95.7%, var(--tone-off)) 93.8%,
    var(--tone-rose) 100%);
}

/* In-page links (the nav, the hero buttons, "See the radios") scroll smoothly (html { scroll-behavior }, below) and land with a little air above the target. */
#radios, #lineup { scroll-margin-top: 1.5rem; }

/* sps-link.sticky-cta (mobile only) ---------------------------------------------------------- */
/* visibility:hidden while off-screen so the link is not reachable by keyboard when the bar is not shown */
.sl-sticky { position: fixed; inset-inline: 0; bottom: 0; z-index: 40; padding: 0.75rem; border-top: 1px solid var(--color-border); background: rgb(255 255 255 / 0.95); backdrop-filter: blur(8px); visibility: hidden; transform: translateY(100%); transition: transform 0.25s, visibility 0s 0.25s; }
.sl-sticky.is-visible { visibility: visible; transform: none; transition: transform 0.25s, visibility 0s; }
.sl-sticky .btn { width: 100%; }
@media (min-width: 640px) { .sl-sticky { display: none; } }

/* 7. Motion + accessibility ---------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}
:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.sl-section--dark :focus-visible, .sl-updates :focus-visible { outline-color: #fff; }
