/* CLAN-TV — setup guide.
   App layout: the satellite map is the visual bed, content rides over it
   in a single dark column. Near-black surfaces, one cool accent for live data. */

:root {
  --void: #08090B;
  --panel: #1B1F26;
  --panel-2: #222730;
  --panel-3: #2A303A;

  --line: rgba(255, 255, 255, .12);
  --line-2: rgba(255, 255, 255, .2);

  --text: #ECEDEF;
  --text-2: rgba(236, 237, 239, .58);
  --text-3: rgba(236, 237, 239, .36);

  --accent: #7FD1FF;
  --accent-dim: rgba(127, 209, 255, .14);
  --lock: #3ED598;
  --alert: #FF8A6B;

  --s-1: 0.8125rem;
  --s0: 0.9375rem;
  --s1: 1.0625rem;
  --s2: 1.25rem;
  --s3: 1.625rem;
  --s4: 2.125rem;
  --s5: 2.75rem;
  --s6: clamp(2.25rem, 6.4vw, 3.25rem);

  --r: 10px;
  --r-sm: 7px;
  --panel-w: 28rem;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--void);
  color: var(--text);
  font-family: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: var(--s0);
  line-height: 1.5;
  font-feature-settings: 'tnum' 1, 'cv05' 1;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
  overflow-x: hidden;
}

h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.08; letter-spacing: -0.028em; }
h1 { font-size: var(--s6); }
h2 { font-size: var(--s4); }
h3 { font-size: var(--s1); letter-spacing: -0.01em; font-weight: 550; }
p { margin: 0; }
a { color: var(--accent); text-decoration: none; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }

.lead { color: var(--text-2); font-size: var(--s1); line-height: 1.45; }
.note { color: var(--text-2); font-size: var(--s-1); line-height: 1.5; }
.stack > * + * { margin-top: .75rem; }
.stack-sm > * + * { margin-top: .5rem; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* =========================================================
   Shell: map bed + content column
   ========================================================= */

.app { min-height: 100vh; min-height: 100svh; }

.stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: #0B0D10;
}

.stage::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(8, 9, 11, .55) 0%, rgba(8, 9, 11, 0) 22%, rgba(8, 9, 11, 0) 55%, rgba(8, 9, 11, .8) 100%);
}

.map { position: absolute; inset: 0; }

.crosshair {
  position: absolute;
  left: 50%; top: 50%;
  width: 96px; height: 96px;
  margin: -48px 0 0 -48px;
  z-index: 3;
  display: none;
  pointer-events: none;
  filter: drop-shadow(0 0 6px rgba(0, 0, 0, .8));
}

.crosshair svg { width: 100%; height: 100%; }

/* Phones only (shown in the narrow-screen rules below): full-screen map toggle,
   top left — Yandex's own controls hold the right side. */
.map-full {
  position: absolute;
  left: 1rem; top: 4rem;
  z-index: 4;
  display: none;
  place-items: center;
  width: 2.5rem; height: 2.5rem;
  padding: 0;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: rgba(8, 9, 11, .78);
  color: var(--text);
  cursor: pointer;
}
.map-full svg { width: 1.25rem; height: 1.25rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
body[data-adjust='true'] .crosshair { display: block; }
[class^='ymaps'] { font-family: inherit; }

/* Yandex renders vector objects into one pane. Blurring it turns the nested
   coverage contours into a soft glowing body and gives the signal path its
   halo for free. Markers live in a separate pane and stay sharp.
   The class carries a build number, so match it by substring. */
[class*='-graphics-pane'] {
  filter: blur(8px) saturate(1.1);
  mix-blend-mode: screen;
  will-change: filter;
}

.shell {
  position: relative;
  z-index: 2;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  pointer-events: none;
}

/* Only the parts that actually carry content take pointer events — otherwise
   the full-width step containers sit on top of the map and swallow every
   click, drag and wheel meant for it. */
.topbar,
.column,
.hero__mark,
.hero__body,
.hero__foot { pointer-events: auto; }

.hero { pointer-events: none; }
.column > * { pointer-events: auto; }

/* =========================================================
   Hero
   ========================================================= */

.hero {
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 1.25rem;
}

.hero[hidden] { display: none; }

.hero__mark { display: flex; align-items: center; justify-content: flex-start; }
.hero__mark span { font-weight: 600; letter-spacing: .14em; font-size: var(--s-1); }

.hero__body { align-self: center; max-width: 38rem; padding-block: 2rem; }
.hero .lead { max-width: 33rem; margin-top: 1.125rem; }
.hero__cta { margin-top: 1.75rem; }

/* The name is the mark: set large, everything else steps down from it. */
.wordmark { margin-bottom: .625rem; line-height: 1; }
.wordmark__text {
  display: block;
  font-size: clamp(3rem, 11vw, 5.5rem);
  font-weight: 600;
  letter-spacing: -0.035em;
}

.hero__definition {
  font-size: clamp(1.125rem, 2.8vw, 1.5rem);
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--text);
  line-height: 1.25;
  max-width: 26rem;
}

.hero__foot { display: flex; justify-content: space-between; align-items: end; gap: 1rem; color: var(--text-3); font-size: var(--s-1); }

/* an image can be dropped in behind the hero later */
.hero__image {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-size: cover;
  background-position: center;
}

/* =========================================================
   Working view
   ========================================================= */

.work { display: none; flex: 1; }
.work[data-active='true'] { display: block; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: rgba(8, 9, 11, .72);
  backdrop-filter: blur(16px) saturate(140%);
  border-bottom: 1px solid var(--line);
}

.topbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 3.25rem;
  padding-inline: 1.25rem;
}

.brand { display: flex; align-items: center; gap: .5rem; color: var(--text); }
.brand__name { font-weight: 600; letter-spacing: .14em; font-size: var(--s-1); }

/* The logo in every page's header (img/logo.svg, white, ~10:1). */
.logo { display: block; height: 15px; width: auto; }
@media (max-width: 47.99rem) { .logo { height: 13px; } }

.langs { display: flex; gap: .125rem; }
.langs button {
  font: inherit; font-size: var(--s-1); font-weight: 500;
  color: var(--text-3); background: none; border: 0;
  padding: .3125rem .5rem; border-radius: var(--r-sm); cursor: pointer;
}
.langs button:hover { color: var(--text); background: rgba(255, 255, 255, .06); }
.langs button[aria-pressed='true'] { color: var(--void); background: var(--text); }

/* content column */

.column {
  width: 100%;
  max-width: var(--panel-w);
  padding: 1.25rem 1.25rem 7rem;
}

/* progress */

.progress { display: flex; gap: .375rem; margin-bottom: 1.5rem; }
.progress__seg { flex: 1; height: 2px; background: rgba(255, 255, 255, .14); border-radius: 2px; transition: background 260ms ease; }
.progress__seg[data-state='done'] { background: rgba(255, 255, 255, .4); }
.progress__seg[data-state='now'] { background: var(--accent); }

.step-label { font-size: var(--s-1); color: var(--text-3); margin-bottom: .5rem; letter-spacing: .01em; }

/* steps */

.step { display: none; animation: rise 420ms cubic-bezier(.16, .84, .32, 1) both; }
.step[data-active='true'] { display: block; }

@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .step { animation: none; } }

.step__head { margin-bottom: 1.25rem; }
.step__head h2 { margin-bottom: .5rem; }

/* =========================================================
   Surfaces
   ========================================================= */

.card {
  background: rgba(34, 39, 48, .88);
  backdrop-filter: blur(22px) saturate(130%);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 1.125rem 1.25rem;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .05) inset;
}

.card--plain { background: var(--panel); backdrop-filter: none; }
.card__title { font-size: var(--s0); font-weight: 550; margin-bottom: .1875rem; }

/* =========================================================
   Buttons and inputs
   ========================================================= */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 3rem; padding: .6875rem 1.5rem;
  font: inherit; font-weight: 550; letter-spacing: -0.008em;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-2);
  background: rgba(255, 255, 255, .05);
  color: var(--text);
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, transform 150ms ease;
}

.btn:hover { background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .28); }
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--text); border-color: var(--text); color: var(--void); font-weight: 600; }
.btn--primary:hover { background: #fff; border-color: #fff; }
.btn--block { display: flex; width: 100%; }
.btn[disabled] { opacity: .35; cursor: not-allowed; }

.btn--ghost { border-color: transparent; background: none; color: var(--text-2); min-height: 2.5rem; padding-inline: .625rem; }
.btn--ghost:hover { background: rgba(255, 255, 255, .06); border-color: transparent; color: var(--text); }

.actions { display: flex; gap: .625rem; align-items: center; margin-top: 1.5rem; }
.actions .btn--primary { flex: 1; }

/* The phone's one-page guide (main.js, 'guide'): the five sections after the
   map steps stacked in one scroll. Their own back/next buttons go — one way
   out at the end instead — and each section opens with a rule so the page
   still reads as a sequence. The out-of-coverage notice keeps its button. */
.guide-actions { display: none; }
body[data-guide='true'] .guide-actions { display: flex; }
body[data-guide='true'] #setup-covered > .actions,
body[data-guide='true'] .step:not([data-step='setup']) > .actions:not(.guide-actions) { display: none; }
body[data-guide='true'] .step[data-active='true'] + .step[data-active='true'] {
  margin-top: 2.25rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}

.input {
  width: 100%; min-height: 3rem; padding: .6875rem .875rem;
  font: inherit; color: var(--text);
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
}
.input::placeholder { color: var(--text-3); }
.input:focus { outline: none; border-color: var(--accent); background: rgba(255, 255, 255, .09); }

.row { display: flex; gap: .5rem; }
.row > .input { flex: 1; min-width: 0; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: .625rem; }

.field__label { display: block; font-size: var(--s-1); color: var(--text-2); margin-bottom: .3125rem; }

/* =========================================================
   Data
   ========================================================= */

.readout { display: flex; align-items: baseline; gap: .375rem; }
.readout__value { font-size: var(--s5); font-weight: 600; line-height: .92; letter-spacing: -0.045em; font-variant-numeric: tabular-nums; }
.readout__unit { font-size: var(--s2); color: var(--text-3); }

.metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; margin-top: .875rem; }
.metric { background: var(--panel-2); padding: .8125rem .75rem; }
.metric .k { display: block; font-size: var(--s-1); color: var(--text-3); }
.metric .v { display: block; font-size: var(--s2); font-weight: 600; font-variant-numeric: tabular-nums; margin-top: .125rem; }

.facts { list-style: none; margin: 0; padding: 0; }
.facts li { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding-block: .625rem; }
.facts li + li { border-top: 1px solid var(--line); }
.facts__key { color: var(--text-2); font-size: var(--s-1); }
.facts__val { font-weight: 550; font-variant-numeric: tabular-nums; text-align: right; }

.gauge { margin-top: .875rem; }
.gauge__track { height: 3px; background: rgba(255, 255, 255, .12); overflow: hidden; }
.gauge__fill { height: 100%; background: var(--accent); transition: width 700ms cubic-bezier(.2, .7, .3, 1); }
.gauge__scale { display: flex; justify-content: space-between; font-size: var(--s-1); color: var(--text-3); margin-top: .4375rem; }
.grade { font-weight: 600; color: var(--accent); }

/* equipment list */

.kit { list-style: none; margin: 0; padding: 0; }
.kit li { padding-block: .875rem; }
.kit li + li { border-top: 1px solid var(--line); }
.kit__name { font-weight: 550; margin-bottom: .125rem; }


/* =========================================================
   Instruments
   ========================================================= */

.compass { display: block; width: 100%; max-width: 17rem; margin: .5rem auto .25rem; aspect-ratio: 1; touch-action: none; }
.compass__ring { fill: rgba(255, 255, 255, .02); stroke: rgba(255, 255, 255, .2); stroke-width: 1; }
.compass__inner { fill: none; stroke: rgba(255, 255, 255, .08); stroke-width: 1; }
.compass__tick { stroke: rgba(255, 255, 255, .22); stroke-width: 1; }
.compass__tick--major { stroke: rgba(255, 255, 255, .6); stroke-width: 1.6; }
.compass__cardinal { fill: var(--text-3); font-size: 6.5px; font-weight: 500; text-anchor: middle; }
.compass__target { fill: var(--accent); }
.compass__needle { stroke: var(--text); stroke-width: 2.2; stroke-linecap: round; }
.compass__hub { fill: var(--text); }
.compass__rotor { transition: transform 90ms linear; }

.compass[data-locked='true'] .compass__ring { stroke: var(--lock); stroke-width: 2.4; fill: rgba(62, 213, 152, .08); }
.compass[data-locked='true'] .compass__target,
.compass[data-locked='true'] .compass__hub { fill: var(--lock); }
.compass[data-locked='true'] .compass__needle { stroke: var(--lock); }
@media (prefers-reduced-motion: reduce) { .compass__rotor { transition: none; } }

.aim-status { text-align: center; min-height: 1.5rem; font-weight: 600; color: var(--text-3); }
.aim-status[data-locked='true'] { color: var(--lock); }

.aim-figures { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; margin-top: .875rem; }
.aim-figures div { background: var(--panel-2); padding: .75rem .875rem; }
.aim-figures .k { display: block; font-size: var(--s-1); color: var(--text-3); }
.aim-figures .v { display: block; font-size: var(--s3); font-weight: 600; font-variant-numeric: tabular-nums; }

.dial { display: block; width: 100%; max-width: 12rem; margin: .5rem auto .25rem; aspect-ratio: 1; }
.dial__tick { stroke: rgba(255, 255, 255, .2); stroke-width: 1; }
.dial__tick--major { stroke: rgba(255, 255, 255, .5); stroke-width: 1.4; }
.dial__label { fill: var(--text-3); font-size: 5.5px; text-anchor: middle; }
.dial__arm { stroke: var(--accent); stroke-width: 2.4; stroke-linecap: round; }
.dial__ghost { stroke: rgba(255, 255, 255, .18); stroke-width: 1; stroke-dasharray: 3 3; }
.dial__hub { fill: var(--text); }

/* =========================================================
   Misc
   ========================================================= */

details.more { border-top: 1px solid var(--line); margin-top: .875rem; padding-top: .6875rem; }
details.more > summary {
  cursor: pointer; font-size: var(--s-1); color: var(--text-2); list-style: none;
  display: inline-flex; align-items: center; gap: .4375rem; min-height: 1.75rem;
}
details.more > summary::-webkit-details-marker { display: none; }
details.more > summary::after {
  content: ''; width: .375rem; height: .375rem;
  border-right: 1.25px solid currentColor; border-bottom: 1.25px solid currentColor;
  transform: translateY(-2px) rotate(45deg); transition: transform 160ms ease;
}
details.more[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
details.more > *:not(summary) { margin-top: .625rem; }
details.card.more { border-top: 1px solid var(--line); padding: 1.125rem 1.25rem; margin-top: 0; }

.banner { padding: .75rem .875rem; font-size: var(--s0); border-radius: var(--r-sm); border: 1px solid var(--line); background: rgba(255, 255, 255, .04); }
.banner--ok { border-color: rgba(62, 213, 152, .35); color: var(--lock); }
.banner--warn { border-color: rgba(255, 138, 107, .35); color: var(--alert); }
.banner--busy { color: var(--text-2); }
.banner[hidden] { display: none; }

.params { list-style: none; margin: 0; padding: 0; }
.params li { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding-block: .6875rem; }
.params li + li { border-top: 1px solid var(--line); }
.params .k { color: var(--text-2); font-size: var(--s-1); }
.params .v { font-weight: 600; font-size: var(--s1); font-variant-numeric: tabular-nums; text-align: right; }

.steps-list { list-style: none; margin: 0; padding: 0; counter-reset: s; }
.steps-list > li { counter-increment: s; display: grid; grid-template-columns: 1.25rem 1fr; gap: .875rem; padding-block: .8125rem; }
.steps-list > li + li { border-top: 1px solid var(--line); }
.steps-list > li::before { content: counter(s); font-variant-numeric: tabular-nums; font-weight: 600; font-size: var(--s-1); color: var(--text-3); padding-top: .125rem; }
/* Inside a card, where the card's own padding already frames the list. */
.steps-list--compact > li { padding-block: .625rem; }
.steps-list--compact > li:first-child { padding-top: 0; }
.steps-list--compact > li:last-child { padding-bottom: 0; }
.steps-list--compact > li::before { color: var(--accent); }

.bullets { margin: .4375rem 0 0; padding-left: 1rem; color: var(--text-2); font-size: var(--s-1); }
.bullets li + li { margin-top: .3125rem; }

.problems { display: grid; gap: .625rem; }


.footer-links { display: flex; flex-wrap: wrap; gap: .5rem 1.125rem; font-size: var(--s-1); margin-top: 2.5rem; }
.link-button {
  font: inherit;
  font-size: var(--s-1);
  color: var(--text-3);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.link-button:hover { color: var(--text-2); }
.footer-links a { color: var(--text-3); }
.footer-links a:hover { color: var(--text-2); }

.aim-desktop { display: none; }
.aim-desktop .readout__value { font-size: var(--s5); }

/* =========================================================
   Desktop: content in a column, map beside it
   ========================================================= */

@media (min-width: 62rem) {
  :root { --s5: 3.25rem; --s6: clamp(3rem, 4.4vw, 3.875rem); }
  .wordmark__text { font-size: clamp(4rem, 7vw, 6.5rem); }

  /* The compass reads a phone's magnetometer; on a desktop it is dead weight. */
  .compass-tools { display: none; }
  .aim-desktop { display: block; }

  .topbar__inner { max-width: none; padding-inline: 2rem; }
  .hero { padding: 2rem 3rem; }
  .column { padding: 2rem 2rem 7rem; }

  /* The map stays full-bleed. The column floats over its left edge and scrolls
     on its own, so the wheel scrolls text under the cursor and zooms the map
     everywhere else. The page itself never scrolls. */
  body[data-view='work'] { height: 100dvh; overflow: hidden; }

  .work[data-active='true'] .topbar {
    position: fixed;
    top: 0; left: 0;
    width: var(--panel-w);
    background: none;
    backdrop-filter: none;
    border-bottom: none;
  }

  .work[data-active='true'] .column {
    position: fixed;
    top: 3.25rem; left: 0; bottom: 0;
    width: var(--panel-w);
    max-width: none;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    background: none;
    padding: 1.5rem 1.75rem 7rem;
    pointer-events: auto;
    scrollbar-width: none;
  }

  .work[data-active='true'] .column::-webkit-scrollbar { width: 0; height: 0; }

  /* A single scrim drawn over the map carries all the darkening, so the text
     side has no edge of its own to give away. It never takes the cursor. */
  .stage::after {
    background:
      linear-gradient(90deg,
        rgba(8, 9, 11, .95) 0,
        rgba(8, 9, 11, .93) calc(var(--panel-w) - 8rem),
        rgba(8, 9, 11, .72) calc(var(--panel-w) + 1rem),
        rgba(8, 9, 11, .3) calc(var(--panel-w) + 7rem),
        rgba(8, 9, 11, 0) calc(var(--panel-w) + 14rem)),
      linear-gradient(180deg, rgba(8, 9, 11, .45) 0%, rgba(8, 9, 11, 0) 18%, rgba(8, 9, 11, 0) 68%, rgba(8, 9, 11, .6) 100%);
  }

  .work[data-active='true'] .topbar { background: rgba(8, 9, 11, .8); }
}

@media (max-width: 61.99rem) {
  .aim-desktop { display: none; }
  /* svh, not dvh: dvh follows the browser's toolbar as it hides and shows
     on scroll, so the map and the column under it were resized on every
     frame of a scroll — the map visibly grew and shrank and the page
     stuttered while Yandex re-laid it out. svh is the height with the
     toolbar shown and never changes; vh is the fallback for old engines. */
  .stage { top: 0; height: 42vh; height: 42svh; bottom: auto; }
  /* The column starts where the map ends. It used to ride 4vh up over it,
     which covered the Yandex logo and copyright — they have to stay visible. */
  .work[data-active='true'] .column { margin-top: 42vh; margin-top: 42svh; border-radius: 16px 16px 0 0; background: var(--void); border-top: 1px solid var(--line); }
  .work[data-active='true'] .topbar { background: rgba(8, 9, 11, .9); }

  /* First screen: the text below the map, not on top of it (it sat on the
     country labels, the zoom buttons and the copyright). */
  .hero { padding-top: calc(42vh + 1.75rem); padding-top: calc(42svh + 1.75rem); grid-template-rows: 1fr auto; }
  .hero__mark {
    position: absolute; top: .75rem; left: .75rem; z-index: 3;
    padding: .25rem;
    border-radius: 10px;
    background: rgba(8, 9, 11, .8);
    border: 1px solid var(--line);
  }
  .hero__body { align-self: start; padding-block: 0 2rem; }
  .wordmark__text { font-size: clamp(2.5rem, 12vw, 3.5rem); }

  /* Weak phones: every one of these is re-rendered on each scroll or map
     move. Backdrop blur behind the cards and the bar, blur and screen
     blending on the map's coverage layer. Solid surfaces and crisp contours
     cost almost nothing by comparison. */
  .card, .topbar { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .card { background: var(--panel); }
  [class*='-graphics-pane'] { filter: none; mix-blend-mode: normal; will-change: auto; }

  /* Placing the crosshair on a wall needs room: on the pin step the map
     takes most of the screen, and loses the scrim — the text is below it,
     not on it. */
  /* Full-screen map: the stage is lifted over the whole page (the shell sits
     at z-index 2) and the page under it stops scrolling. */
  body[data-view='work'] .map-full { display: grid; }
  body[data-map-full='true'] { overflow: hidden; }
  body[data-map-full='true'] .stage,
  body[data-adjust='true'][data-map-full='true'] .stage { height: 100vh; height: 100dvh; z-index: 20; }
  body[data-map-full='true'] .stage::after { background: none; }
  body[data-map-full='true'] .map-full { top: max(.75rem, env(safe-area-inset-top)); }
  body[data-map-full='true'] .map-full__open,
  body:not([data-map-full='true']) .map-full__close { display: none; }

  body[data-adjust='true'] .stage { height: 62vh; height: 62svh; }
  body[data-adjust='true'] .work[data-active='true'] .column { margin-top: 62vh; margin-top: 62svh; }
  body[data-adjust='true'] .stage::after { background: linear-gradient(180deg, rgba(8, 9, 11, .5) 0, rgba(8, 9, 11, 0) 16%); }
}

/* =========================================================
   Static pages (legal)
   ========================================================= */

.page {
  width: 100%;
  max-width: 58rem;
  margin-inline: auto;
  padding: 2.5rem 1.25rem 5rem;
}

.page-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(90% 60% at 15% 0%, rgba(127, 209, 255, .10), transparent 60%),
    radial-gradient(70% 50% at 95% 20%, rgba(107, 255, 184, .07), transparent 60%),
    var(--void);
}

.page-section { margin-top: 4rem; }
.page-section > h2 { margin-bottom: 1.25rem; }

.page-hero { padding-block: 3rem 1rem; }
.page-hero .kicker { font-size: var(--s-1); letter-spacing: .16em; color: var(--text-3); margin-bottom: .875rem; }
.page-hero h1 { font-size: clamp(2.75rem, 8vw, 5rem); letter-spacing: -0.04em; margin-bottom: 1rem; }
.page-hero .lead { max-width: 38rem; }
.page-hero .actions { margin-top: 1.75rem; }

.prose { display: grid; gap: 1rem; max-width: 44rem; color: var(--text-2); font-size: var(--s1); line-height: 1.5; }

.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin-top: 2rem; }
.stat { background: var(--panel); padding: 1.5rem 1.25rem; }
.stat .n { display: block; font-size: var(--s5); font-weight: 600; letter-spacing: -0.04em; line-height: 1; font-variant-numeric: tabular-nums; }
.stat .k { display: block; font-size: var(--s-1); color: var(--text-3); margin-top: .5rem; }

.tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; }
.tile { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 1.25rem; }
.tile h3 { margin-bottom: .3125rem; }

.channels { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.channels li { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: .9375rem 1.25rem; background: var(--panel); }
.channels li + li { border-top: 1px solid var(--line); }
.channels .name { font-weight: 550; }
.channels .reach { color: var(--text-3); font-size: var(--s-1); font-variant-numeric: tabular-nums; text-align: right; }

.contact-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .75rem; }
.contact-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 1.25rem; }
.contact-card .k { display: block; font-size: var(--s-1); color: var(--text-3); margin-bottom: .375rem; }
.contact-card a, .contact-card span { color: var(--text); font-size: var(--s1); }

/* Legal documents (privacy, cookies, terms). The text comes from the old
   site as plain paragraphs; a paragraph holding only <strong> is a section
   heading there, so it is set as one here. */
.page-hero .doc-title { font-size: clamp(2.25rem, 6vw, 3.75rem); max-width: 18ch; }
.doc {
  max-width: 44rem;
  margin-top: 1rem;
  color: rgba(236, 237, 239, .76);   /* brighter than --text-2: this is long reading */
  font-size: var(--s0);
  line-height: 1.65;
}
.doc p + p { margin-top: .75rem; }
.doc p:first-child { color: var(--text); font-size: var(--s1); line-height: 1.55; }
.doc p > strong:only-child {
  display: block;
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  color: var(--text);
  font-size: var(--s2);
  font-weight: 600;
  letter-spacing: -0.015em;
}
.doc ul { margin: .5rem 0 0; padding-left: 1.25rem; }
.doc li + li { margin-top: .375rem; }
.doc a { color: var(--accent); }

.legal { color: var(--text-3); font-size: var(--s-1); line-height: 1.6; margin-top: 3rem; }

.cta {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 2.25rem;
  background:
    radial-gradient(80% 120% at 100% 0%, rgba(127, 209, 255, .12), transparent 65%),
    var(--panel);
}

.cta h2 { margin-bottom: .5rem; }

@media (max-width: 44rem) {
  .stats, .tiles, .contact-grid { grid-template-columns: 1fr; }
  .page-section { margin-top: 3rem; }
  .cta { padding: 1.5rem; }
}

/* =========================================================
   Cinematic landing
   ========================================================= */

.landing { background: #010206; }

/* ---------- loader ---------- */

.landing .loader {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: #010206;
  transition: opacity 700ms ease;
}
.landing .loader[data-done='true'] { opacity: 0; pointer-events: none; }
.landing .loader[hidden] { display: none; }

.landing .loader__inner { width: min(22rem, 76vw); }
.landing .loader__mark { display: block; font-weight: 600; letter-spacing: .22em; font-size: var(--s-1); margin-bottom: 1.25rem; }
.landing .loader__track { height: 1px; background: rgba(255,255,255,.14); overflow: hidden; }
.landing .loader__bar { display: block; height: 100%; background: var(--accent); transform: scaleX(0); transform-origin: 0 50%; transition: transform 200ms ease; }
.landing .loader__row { display: flex; justify-content: space-between; margin-top: .75rem; font-size: var(--s-1); color: var(--text-3); font-variant-numeric: tabular-nums; }

/* ---------- navigation ---------- */

.landing .topnav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  padding: 1rem 0;
  background: linear-gradient(180deg, rgba(1,2,6,.8), rgba(1,2,6,0));
}
.landing .topnav__inner {
  display: flex; align-items: center; gap: 2rem;
  max-width: 84rem; margin-inline: auto; padding-inline: 2rem;
}
.landing .topnav__mark { display: block; flex-shrink: 0; color: var(--text); }
.landing .topnav__links { display: flex; gap: 1.75rem; margin-left: auto; font-size: var(--s-1); }
.landing .topnav__links a { color: var(--text-2); }
.landing .topnav__links a:hover { color: var(--text); }

@media (max-width: 52rem) {
  .landing .topnav__inner { padding-inline: 1.25rem; gap: 1rem; }
  /* On a phone the page scrolls under the bar: a fade let the text show
     through and tangle with the logo. Solid, and no backdrop blur — that is
     a full-width re-render on every scroll step on a weak phone. */
  .landing .topnav {
    padding: .75rem 0;
    background: rgba(1, 2, 6, .94);
    border-bottom: 1px solid var(--line);
  }
  .landing .topnav__links { display: none; }
}

/* ---------- the journey ---------- */

.landing .journey { position: relative; }
.landing .journey__track { height: 620vh; }

/* The setup page's `.stage` (map bed) rules match here too. Its opaque
   #0B0D10 background became the colour Chrome paints into tiles it has not
   rasterised yet while scrolling — the dark rectangles over the planet — and
   its `::after` scrim was a second full-screen gradient drawn over the canvas
   on top of .stage__vignette. Neither belongs on the landing. */
.landing .stage {
  position: sticky; top: 0; bottom: auto;
  height: 100dvh;
  overflow: hidden;
  background: transparent;
}
.landing .stage::after { content: none; }

.landing .stage canvas {
  display: block; width: 100%; height: 100%;
  /* Keeps the canvas on its own composited layer instead of Chrome
     re-evaluating it against the sticky container on every scroll tick —
     that re-evaluation is what showed up as a black flicker under load. */
  will-change: transform;
  transform: translateZ(0);
}

.landing .stage__fallback {
  position: absolute; inset: 0;
  display: none;
  /* Also what a device too slow for the 3D scene is left with: the same
     planet the mobile page shows, instead of an empty gradient. */
  background:
    url('../textures/earth-still.webp') 62% 45% / auto 78% no-repeat,
    radial-gradient(60% 55% at 62% 42%, rgba(60,110,190,.5), transparent 62%),
    radial-gradient(40% 40% at 30% 70%, rgba(20,60,120,.35), transparent 70%),
    #010206;
}
.landing .stage[data-fallback='true'] canvas { display: none; }
.landing .stage[data-fallback='true'] .stage__fallback { display: block; }

.landing .stage__vignette {
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(125% 95% at 50% 50%, transparent 52%, rgba(1,2,6,.70) 100%),
    linear-gradient(180deg, rgba(1,2,6,.45) 0%, transparent 18%, transparent 64%, rgba(1,2,6,.85) 100%);
}

/* ---------- hero over the first screen ---------- */

.landing .hero-cine {
  position: absolute; top: 0; left: 0; right: 0;
  height: 100dvh;
  display: flex; align-items: flex-end;
  pointer-events: none;
  z-index: 3;
}
.landing .hero-cine__inner {
  width: 100%; max-width: 84rem;
  margin-inline: auto; padding: 0 2rem 5rem;
  pointer-events: auto;
}
.landing .hero-cine h1 {
  font-size: clamp(2.5rem, 6.4vw, 5.25rem);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.02;
  max-width: 18ch;
}
/* "Free", in the headline: the same mint as the manifesto's highlight, so
   the page says it in one voice from the first screen to the last. */
.landing .accent-free {
  background: linear-gradient(95deg, var(--accent), #A9FFDD);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.landing .hero-cine__lead { color: var(--text-2); font-size: var(--s1); margin-top: 1.25rem; max-width: 32rem; }
.landing .hero-cine__actions { margin-top: 2rem; }
.landing .hero-cine__scroll {
  margin-top: 3rem; font-size: var(--s-1); color: var(--text-3);
  display: flex; align-items: center; gap: .75rem;
}
.landing .hero-cine__scroll::before {
  content: ''; width: 2.5rem; height: 1px; background: currentColor;
  animation: reach 2.6s ease-in-out infinite;
  transform-origin: 0 50%;
}
@keyframes reach { 0%,100% { transform: scaleX(.35); opacity: .5; } 50% { transform: scaleX(1); opacity: 1; } }

/* ---------- narrative captions ---------- */

.landing .captions {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
}

.landing .caption {
  position: absolute;
  left: 0; right: 0; bottom: 14vh;
  margin: 0;
  padding-inline: 2rem;
  max-width: 84rem;
  margin-inline: auto;
  opacity: 0;
  transition: opacity 480ms ease;
  will-change: opacity, transform;
}
.landing .caption > * { max-width: 34rem; }
.landing .caption__kicker {
  display: block; font-size: var(--s-1); letter-spacing: .18em;
  color: var(--accent); margin-bottom: .875rem;
}
.landing .caption h2 {
  font-size: clamp(1.75rem, 3.4vw, 2.875rem);
  font-weight: 500; letter-spacing: -0.028em; line-height: 1.1;
}
.landing .caption p { color: var(--text-2); font-size: var(--s1); margin-top: 1rem; }

.landing .caption--final { bottom: 22vh; }
.landing .caption__final {
  font-size: clamp(2rem, 4.6vw, 4rem);
  line-height: 1.06;
  max-width: 22ch;
}
.landing .caption__actions { display: flex; gap: .75rem; margin-top: 2rem; pointer-events: auto; flex-wrap: wrap; }

@media (max-width: 52rem) {
  .landing .journey__track { height: 520vh; }
  .landing .hero-cine__inner { padding: 0 1.25rem 3.5rem; }
  .landing .caption { padding-inline: 1.25rem; bottom: 10vh; }
  .landing .caption--final { bottom: 16vh; }
}

@media (prefers-reduced-motion: reduce) {
  .landing .hero-cine__scroll::before { animation: none; transform: scaleX(1); }
  .landing .caption { transition: none; }
}

/* ---------- below the journey ---------- */
/* Four sections and a footer (js/landing/after.js). Each section gets
   `data-seen` once it has come into view, which starts its entrance, and
   `data-live` while it is on screen, which runs its loops. */

.landing .after { position: relative; z-index: 4; background: #010206; overflow-x: hidden; overflow-x: clip; }
/* Pieces that are meant to bleed past the edge (the map on a phone, the
   drifting channel rows, the planet in the finale) must not widen the page:
   on a phone that made the whole layout wider than the screen. */
.landing .mstory { overflow-x: hidden; overflow-x: clip; }
/* `hidden` first for Safari before iOS 16, which ignores `clip`: there the
   page stayed wider than the screen and text ran off the right edge. Nothing
   inside these two needs position: sticky, so a scroll container is fine. */
/* Jumps from the menu (#about, #channels, #coverage) land below the fixed bar. */
.landing .after [id] { scroll-margin-top: 4.5rem; }
.landing .after .page,
.landing .site-footer .page { max-width: 72rem; padding: 0 clamp(1.25rem, 4vw, 2.5rem); }
.landing .section-lead { font-size: clamp(1.875rem, 4vw, 3.25rem); font-weight: 500; letter-spacing: -0.034em; line-height: 1.06; max-width: 20ch; }
.landing .kicker { font-size: var(--s-1); letter-spacing: .18em; color: var(--accent); margin-bottom: 1rem; }

/* ---------- 1. manifesto ---------- */

.landing .manifesto { padding: clamp(5rem, 16vh, 10rem) 0 clamp(4rem, 12vh, 8rem); }

.landing .manifesto__lines,
.landing .manifesto__answer {
  font-size: clamp(2.125rem, 5.4vw, 4.75rem);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 1.02;
}
.landing .manifesto__lines { display: grid; gap: .08em; margin: 0; }

.landing .manifesto__line {
  display: block;
  opacity: 0;
  transform: translateY(.35em);
  transition: opacity 700ms ease, transform 900ms cubic-bezier(.16, .84, .32, 1);
  transition-delay: calc(var(--n) * 650ms);
}

/* The struck word. A background line rather than ::after, so a word that
   wraps is crossed out on both of its lines. */
.landing .manifesto__line s {
  text-decoration: none;
  color: var(--text);
  background: linear-gradient(90deg, var(--accent), #A9FFDD) no-repeat 0 58% / 0 .075em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-size 550ms cubic-bezier(.65, 0, .35, 1), color 600ms ease;
  transition-delay: calc(var(--n) * 650ms + 450ms);
}

.landing .manifesto__answer {
  margin-top: .45em;
  background: linear-gradient(95deg, #fff 10%, var(--accent) 55%, #A9FFDD 90%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  opacity: 0;
  transform: translateY(.3em);
  transition: opacity 900ms ease 2200ms, transform 1100ms cubic-bezier(.16, .84, .32, 1) 2200ms;
}

/* The price, said last and loudest. The struck lines cross out what you
   don't need; this one marks what you get — the same sweep, but a full-height
   highlight instead of a thin strike. */
.landing .manifesto__free {
  margin-top: .3em;
  font-size: clamp(2.125rem, 5.4vw, 4.75rem);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 1.1;
  opacity: 0;
  transform: translateY(.3em);
  transition: opacity 900ms ease 2900ms, transform 1100ms cubic-bezier(.16, .84, .32, 1) 2900ms;
}
.landing .manifesto__free mark {
  color: var(--text);
  padding: 0 .14em;
  margin: 0 -.04em;
  border-radius: .14em;
  background: linear-gradient(90deg, var(--accent), #A9FFDD) no-repeat 0 0 / 0 100%;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-size 650ms cubic-bezier(.65, 0, .35, 1) 3500ms, color 400ms ease 3700ms;
}

.landing .manifesto__who {
  max-width: 34rem;
  margin-top: 2.25rem;
  color: var(--text-2);
  font-size: var(--s2);
  line-height: 1.45;
  opacity: 0;
  transition: opacity 900ms ease 3600ms;
}

.landing .manifesto[data-seen] .manifesto__line,
.landing .manifesto[data-seen] .manifesto__answer,
.landing .manifesto[data-seen] .manifesto__free { opacity: 1; transform: none; }
.landing .manifesto[data-seen] .manifesto__line s { background-size: 100% .075em; color: var(--text-3); }
.landing .manifesto[data-seen] .manifesto__free mark { background-size: 100% 100%; color: #04060b; }
.landing .manifesto[data-seen] .manifesto__who { opacity: 1; }

/* ---------- channels ---------- */

.landing .channels {
  padding: clamp(4rem, 12vh, 8rem) 0;
  border-top: 1px solid var(--line);
  overflow: hidden;
}
.landing .channels__lead { max-width: 36rem; margin-top: 1.25rem; }

.landing .channels__rows {
  display: grid;
  gap: 1rem;
  /* The mask below clips to this box, so it needs room for a plate lifting
     on hover and for the shadows; margin gives the room back outside. */
  padding-block: .75rem 2.25rem;
  margin: calc(clamp(2rem, 5vh, 3.5rem) - .75rem) 0 -2.25rem;
  /* Logos slide in and out of view rather than being cut at the page edge. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 800ms ease 200ms, transform 900ms cubic-bezier(.16, .84, .32, 1) 200ms;
}
.landing .channels[data-seen] .channels__rows { opacity: 1; transform: none; }

.landing .channels__row { display: flex; }
.landing .channels__track {
  --gap: 1rem;
  display: flex;
  gap: var(--gap);
  list-style: none;
  margin: 0;
  /* Half the track is one full copy; the trailing gap keeps the loop even. */
  padding: 0 var(--gap) 0 0;
  flex-shrink: 0;
  animation: channels-drift 70s linear infinite;
  animation-play-state: paused;
}
.landing .channels__row--back .channels__track { animation-direction: reverse; animation-duration: 80s; }
.landing .channels[data-live='true'] .channels__track { animation-play-state: running; }
.landing .channels[data-live='true'] .channels__row:hover .channels__track { animation-play-state: paused; }
@keyframes channels-drift { to { transform: translateX(-50%); } }

/* Light plates, not the page's dark: half of these logos are navy or black
   and would vanish on it. One plate for all keeps them reading as a set. */
.landing .channels__tile {
  position: relative;
  flex: none;
  /* A fixed height, not aspect-ratio: that is only a minimum, and the tall
     logos (РЕН ТВ, Пятый) stretched their plates past the rest. */
  width: clamp(9.5rem, 15vw, 12.5rem);
  height: clamp(5.375rem, 8.4vw, 7rem);
  padding: 1rem 1.25rem;
  border-radius: 14px;
  background: linear-gradient(180deg, #F7F8FA, #E6E9EE);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .6) inset, 0 10px 30px rgba(0, 0, 0, .35);
  transition: transform 250ms ease, box-shadow 250ms ease;
}
.landing .channels__tile:hover {
  transform: translateY(-3px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .6) inset, 0 16px 40px rgba(0, 0, 0, .45), 0 0 0 1px rgba(127, 209, 255, .5);
}
/* The logo box is the plate's inner area exactly, and the logo is fitted
   into it centred both ways. Sizing it as a grid or flex item left the
   narrow logos (Домашний, iz, FON) sitting against the left edge. */
.landing .channels__tile img {
  position: absolute;
  inset: 1rem 1.25rem;
  width: calc(100% - 2.5rem);
  height: calc(100% - 2rem);
  object-fit: contain;
  object-position: center;
}

/* The full list, behind a button under the rows. */
.landing .channels__more { margin-top: clamp(2rem, 4vh, 3rem); }
.landing .channels__toggle { gap: .625rem; }
.landing .channels__toggle svg { transition: transform 250ms ease; }
.landing .channels__toggle[aria-expanded='true'] svg { transform: rotate(180deg); }
.landing .channels__toggle[aria-expanded='true'] .channels__toggle-open,
.landing .channels__toggle[aria-expanded='false'] .channels__toggle-close { display: none; }

.landing .channels__panel { margin-top: 1.75rem; animation: rise 420ms cubic-bezier(.16, .84, .32, 1) both; }
.landing .channels__panel[hidden] { display: none; }

.landing .channels__filters { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.5rem; }
.landing .channels__chip {
  font: inherit; font-size: var(--s-1);
  padding: .4375rem .875rem;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: none;
  color: var(--text-2);
  cursor: pointer;
  white-space: nowrap;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.landing .channels__chip:hover { color: var(--text); border-color: rgba(255, 255, 255, .3); }
.landing .channels__chip[aria-pressed='true'] { background: var(--text); border-color: var(--text); color: var(--void); }

.landing .channels__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .75rem;
  list-style: none; margin: 0; padding: 0;
}
.landing .channels__item {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
  padding: .875rem;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(255, 255, 255, .03);
}
.landing .channels__item[hidden] { display: none; }
.landing .channels__logo {
  position: relative;
  height: 3.75rem;
  border-radius: 10px;
  background: linear-gradient(180deg, #F7F8FA, #E6E9EE);
}
.landing .channels__logo img {
  position: absolute; inset: .5rem .625rem;
  width: calc(100% - 1.25rem); height: calc(100% - 1rem);
  object-fit: contain;
}
.landing .channels__item strong { display: block; font-size: var(--s1); font-weight: 600; letter-spacing: -0.01em; }
.landing .channels__genre { display: block; margin-top: .125rem; font-size: .75rem; letter-spacing: .06em; color: var(--accent); }
.landing .channels__text { margin-top: .375rem; font-size: var(--s-1); line-height: 1.45; color: var(--text-2); }

@media (max-width: 44rem) {
  .landing .channels__toggle { width: 100%; }
  .landing .channels__list { grid-template-columns: 1fr; }
  .landing .channels__item { grid-template-columns: 5.25rem minmax(0, 1fr); gap: .875rem; }
  .landing .channels__logo { height: 3.25rem; }
  /* One swipeable line of chips rather than three wrapped rows. */
  .landing .channels__filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    margin-inline: calc(-1 * clamp(1.25rem, 4vw, 2.5rem));
    padding-inline: clamp(1.25rem, 4vw, 2.5rem);
    scrollbar-width: none;
  }
  .landing .channels__filters::-webkit-scrollbar { display: none; }
}

/* Less motion: no drift, just the logos laid out once. */
@media (prefers-reduced-motion: reduce) {
  .landing .channels__rows { -webkit-mask-image: none; mask-image: none; padding-inline: clamp(1.25rem, 4vw, 2.5rem); transition: none; }
  .landing .channels__track { animation: none; flex-wrap: wrap; flex-shrink: 1; padding: 0; justify-content: center; }
  .landing .channels__tile[aria-hidden='true'] { display: none; }
}

/* ---------- 2. signal chain ---------- */

.landing .chain {
  padding: clamp(4rem, 12vh, 8rem) 0;
  border-top: 1px solid var(--line);
  background: radial-gradient(60% 50% at 10% 0%, rgba(127, 209, 255, .07), transparent 70%);
}
.landing .chain__lead { max-width: 38rem; margin-top: 1.25rem; }

/* Seven columns: the satellite, the long leg down to Earth (1.6 wide), then
   the five things on the ground. The rail runs from the first icon's centre
   to the last one's, so it starts and ends half a column in. */
.landing .chain__track {
  --cols: 7.6;
  --half: calc(100% / var(--cols) / 2);
  --icon: 4.5rem;
  --cycle: 3.6s;
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1.6fr repeat(5, 1fr);
  list-style: none;
  margin: 4rem 0 0;
  padding: 0;
}

.landing .chain__track::before,
.landing .chain__track::after {
  content: '';
  position: absolute;
  left: var(--half); right: var(--half);
  top: calc(var(--icon) / 2);
  height: 2px;
  margin-top: -1px;
  border-radius: 2px;
}
.landing .chain__track::before { background: rgba(255, 255, 255, .12); }

/* The signal itself: a short bright stretch, 18% of the rail, sliding its
   length. It moves as a whole layer (transform) rather than by shifting a
   background, and has no glow filter: both of those repaint every frame,
   which a weak phone feels. 505.6% = the rail's length in the stretch's
   own widths (1 / .18), less half of one so it ends centred on the TV. */
.landing .chain__track::after {
  right: auto;
  width: calc((100% - 2 * var(--half)) * .18);
  height: 3px;
  margin-top: -1.5px;
  background: linear-gradient(90deg, transparent, var(--accent) 40%, #fff 50%, var(--accent) 60%, transparent);
  opacity: 0;
  will-change: transform, opacity;
}
.landing .chain[data-live='true'] .chain__track::after { animation: chain-run var(--cycle) linear infinite; }
/* Linear, not eased: each icon lights at a delay proportional to how far
   along the rail it sits (--at), which only holds at a constant speed. With
   an ease-in-out the pulse lagged at the start and outran the icons late. */
@keyframes chain-run {
  0% { transform: translateX(-50%); opacity: 1; }
  72% { transform: translateX(505.6%); opacity: 1; }
  73%, 100% { transform: translateX(505.6%); opacity: 0; }
}

.landing .chain__node {
  position: relative;
  z-index: 1;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  padding-inline: .375rem;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 600ms ease, transform 700ms cubic-bezier(.16, .84, .32, 1);
  transition-delay: calc(var(--i) * 110ms + 150ms);
}
.landing .chain[data-seen] .chain__node { opacity: 1; transform: none; }

.landing .chain__icon {
  /* The circle and its glow sit on a plain box around the SVG, not on the
     SVG itself: iOS Safari clips an <svg> to its own box, glow included, so
     the lit icon showed a square halo there. */
  display: grid;
  place-items: center;
  width: var(--icon); height: var(--icon);
  margin-bottom: 1.125rem;
  border-radius: 50%;
  background: #0A0D12;
  border: 1px solid var(--line-2);
  color: var(--text-2);
  position: relative;
}
/* The lit state as its own layer, drawn once: an accent ring with its glow.
   Only its opacity animates. Animating box-shadow and border-color on the
   circle itself made iOS Safari repaint the node every frame, and the
   repaint nudged the whole block up and down as the signal passed. */
.landing .chain__icon::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  border: 1px solid var(--accent);
  box-shadow: 0 0 0 4px rgba(127, 209, 255, .14), 0 0 24px rgba(127, 209, 255, .55);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}
.landing .chain__icon svg {
  width: 52%; height: 52%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}

/* Each icon lights up as the signal reaches it. --at is where its centre
   sits along the rail (0 → 1), so the delay keeps it in step with the run. */
.landing .chain[data-live='true'] .chain__icon,
.landing .chain[data-live='true'] .chain__icon::after {
  animation: chain-hit var(--cycle) ease-out infinite;
  animation-delay: calc(var(--at) * var(--cycle) * .72);
}
.landing .chain[data-live='true'] .chain__icon::after { animation-name: chain-glow; }
@keyframes chain-hit {
  0% { color: #fff; }
  30%, 100% { color: var(--text-2); }
}
@keyframes chain-glow {
  0% { opacity: 1; }
  30%, 100% { opacity: 0; }
}

/* --at is measured from the real layout by js/landing/after.js (syncChain),
   in either direction; these are the desktop values, used until it runs. */
.landing .chain__node:nth-child(1) { --at: 0; }
.landing .chain__node:nth-child(3) { --at: .394; }
.landing .chain__node:nth-child(4) { --at: .545; }
.landing .chain__node:nth-child(5) { --at: .697; }
.landing .chain__node:nth-child(6) { --at: .848; }
.landing .chain__node:nth-child(7) { --at: 1; }

.landing .chain__node strong { font-size: var(--s1); font-weight: 550; letter-spacing: -0.01em; }
.landing .chain__node > span:not(.chain__icon) { margin-top: .375rem; color: var(--text-3); font-size: var(--s-1); line-height: 1.4; max-width: 11rem; }

.landing .chain__gap {
  position: relative;
  display: flex; justify-content: center;
  padding-top: calc(var(--icon) / 2 - 2.2rem);
  color: var(--accent);
  font-size: var(--s0);
  font-weight: 550;
  letter-spacing: .06em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 800ms ease 600ms;
}
.landing .chain[data-seen] .chain__gap { opacity: 1; }

/* The leg through space, dashed over the solid rail: the one stretch that is
   not a cable. Painted over the rail with the section's own dark behind it. */
.landing .chain__gap::before {
  content: '';
  position: absolute;
  left: -.5rem; right: -.5rem;
  top: calc(var(--icon) / 2 - 1px);
  height: 2px;
  background: repeating-linear-gradient(90deg, rgba(127, 209, 255, .55) 0 6px, transparent 6px 13px), #04060A;
}

.landing .chain__why {
  max-width: 40rem;
  margin-top: 4rem;
  padding-left: 1.25rem;
  border-left: 2px solid var(--accent);
  color: var(--text-2);
  font-size: var(--s1);
  line-height: 1.5;
}

/* A phone gets the chain top to bottom, rail on the left. */
@media (max-width: 52rem) {
  .landing .chain__track {
    grid-template-columns: 1fr;
    gap: 1.5rem;
    margin-top: 2.5rem;
  }
  .landing .chain__track::before,
  .landing .chain__track::after {
    left: calc(var(--icon) / 2); right: auto;
    top: calc(var(--icon) / 2); bottom: calc(var(--icon) / 2);
    width: 2px; height: auto;
    margin: 0 0 0 -1px;
  }
  .landing .chain__track::after {
    bottom: auto;
    width: 3px;
    height: calc((100% - var(--icon)) * .18);
    margin: 0 0 0 -1.5px;
    background: linear-gradient(180deg, transparent, var(--accent) 40%, #fff 50%, var(--accent) 60%, transparent);
  }
  @keyframes chain-run {
    0% { transform: translateY(-50%); opacity: 1; }
    72% { transform: translateY(505.6%); opacity: 1; }
    73%, 100% { transform: translateY(505.6%); opacity: 0; }
  }
  .landing .chain__node {
    display: grid;
    grid-template-columns: var(--icon) 1fr;
    column-gap: 1rem;
    align-items: start;
    text-align: left;
    padding: 0;
  }
  .landing .chain__icon { grid-row: span 2; margin: 0; }
  .landing .chain__node strong { padding-top: .5rem; }
  .landing .chain__node > span:not(.chain__icon) { margin-top: .125rem; max-width: none; }
  .landing .chain__gap { justify-content: flex-start; padding: 0 0 0 calc(var(--icon) + 1rem); }
  .landing .chain__gap::before { display: none; }
}

/* ---------- 3. coverage map ---------- */

.landing .reach { padding: clamp(4rem, 12vh, 8rem) 0 clamp(3rem, 8vh, 5rem); border-top: 1px solid var(--line); }
.landing .reach__lead { max-width: 40rem; margin-top: 1.25rem; }

.landing .reach__map {
  position: relative;
  width: min(100%, 120rem);
  aspect-ratio: 2 / 1;
  margin: clamp(1.5rem, 4vh, 3rem) auto 0;
  /* Fade to the page on every side, so the crop reads as a view, not a box. */
  -webkit-mask-image: radial-gradient(ellipse 68% 70% at 50% 52%, #000 58%, transparent 100%);
  mask-image: radial-gradient(ellipse 68% 70% at 50% 52%, #000 58%, transparent 100%);
}

.landing .reach__svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.landing .reach__earth { opacity: .95; }

.landing .reach__zones path { fill-opacity: .2; }

/* Whole-layer animation only: the compositor scales and fades an <svg>
   element without repainting it, so the blur is drawn once. The origin is
   the satellite's sub-point (42°E 0°N) as a share of the viewBox. */
.landing .reach__layer { pointer-events: none; will-change: transform, opacity; }
.landing .reach__layer--zones {
  mix-blend-mode: screen;
  opacity: 0;
  transform: scale(.25);
  transform-origin: 48.125% 90%;
  transition: opacity 1200ms ease 200ms, transform 1800ms cubic-bezier(.16, .84, .32, 1) 200ms;
}
.landing .reach__layer--edge { opacity: 0; transition: opacity 1000ms ease 1400ms; }
.landing .reach[data-seen] .reach__layer--zones { opacity: 1; transform: none; }
.landing .reach[data-seen] .reach__layer--edge { opacity: 1; }

.landing .reach__edge path {
  fill: none;
  stroke: var(--accent);
  stroke-opacity: .55;
  stroke-width: 1.2px;
  vector-effect: non-scaling-stroke;
}

/* The satellite's sub-point, with a ring going out from it. */
.landing .reach__sat {
  position: absolute;
  left: var(--x); top: var(--y);
  width: .5rem; height: .5rem;
  margin: -.25rem 0 0 -.25rem;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 12px 3px rgba(127, 209, 255, .8);
}
.landing .reach__pulse,
.landing .reach__pulse::after {
  position: absolute; left: 50%; top: 50%;
  width: 7rem; height: 7rem;
  margin: -3.5rem 0 0 -3.5rem;
  border-radius: 50%;
  border: 1px solid rgba(127, 209, 255, .7);
  opacity: 0;
}
.landing .reach__pulse::after { content: ''; animation-delay: 1.5s !important; }
.landing .reach[data-live='true'] .reach__pulse,
.landing .reach[data-live='true'] .reach__pulse::after { animation: reach-ring 3s ease-out infinite; }
@keyframes reach-ring {
  0% { transform: scale(.08); opacity: .9; }
  100% { transform: scale(1); opacity: 0; }
}
.landing .reach__sat-label {
  position: absolute; left: 1rem; top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  font-size: var(--s-1);
  letter-spacing: .06em;
  color: var(--accent);
}

.landing .reach__cities { position: absolute; inset: 0; pointer-events: none; }
.landing .reach__city {
  position: absolute;
  left: var(--x); top: var(--y);
  opacity: 0;
  transition: opacity 600ms ease;
  transition-delay: calc(var(--k) * 70ms + 1500ms);
}
.landing .reach[data-seen] .reach__city { opacity: 1; }

.landing .reach__dot {
  position: absolute;
  width: .4375rem; height: .4375rem;
  margin: -.21875rem 0 0 -.21875rem;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .14), 0 0 10px rgba(169, 255, 221, .7);
}
.landing .reach__label {
  position: absolute;
  top: 0; left: .75rem;
  transform: translateY(-50%);
  display: flex; align-items: baseline; gap: .4rem;
  padding: .25rem .5rem;
  border-radius: 999px;
  background: rgba(1, 2, 6, .62);
  border: 1px solid rgba(255, 255, 255, .1);
  white-space: nowrap;
  font-size: .75rem;
  line-height: 1.2;
  color: var(--text-2);
}
.landing .reach__city[data-side='left'] .reach__label { left: auto; right: .75rem; }
.landing .reach__label b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }

.landing .reach__foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 1.25rem 3rem;
  margin-top: clamp(1rem, 3vh, 2rem);
}
.landing .reach__legend { max-width: 22rem; }
.landing .reach__legend-bar {
  display: block; height: .375rem; border-radius: 999px;
  background: linear-gradient(90deg, #2F6BD8, #2E8FE6, #29B6E8, #35D8D0, #62F0C4, #A9FFDD);
  box-shadow: 0 0 16px rgba(53, 216, 208, .25);
}
.landing .reach__legend-ends {
  display: flex; justify-content: space-between;
  margin-top: .5rem;
  font-size: var(--s-1);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.landing .reach__legend-words { margin-top: .125rem; color: var(--text-3); }
.landing .reach__note { grid-column: 1; max-width: 30rem; color: var(--text-3); }
.landing .reach__cta { grid-column: 2; grid-row: 1 / span 2; align-self: end; }
.landing .reach__list { display: none; }

/* Below ~1200px the city labels start landing on each other (sixteen cities,
   Europe and India both crowded), so the figures move to a list under the
   map — dots stay on it. Phones get the same, in two columns. */
@media (max-width: 74.99rem) {
  .landing .reach__label { display: none; }
  .landing .reach__list {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: .5rem 1.5rem;
    list-style: none; margin: .5rem 0 0; padding: 0;
    font-size: var(--s-1);
  }
  .landing .reach__list li { display: flex; justify-content: space-between; gap: .5rem; padding-bottom: .5rem; border-bottom: 1px solid var(--line); color: var(--text-2); }
  .landing .reach__list b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
}

/* On a phone the map is too small for labels: dots on the map, figures in
   a list underneath. */
@media (max-width: 48rem) {
  .landing .reach__map { width: 118%; margin-left: -9%; }
  /* Weak phones: the SVG blur and screen blending on sixteen overlapping
     contours are the costliest thing on the page to draw. Crisp nested
     contours read almost the same at this size. */
  .landing .reach__zones { filter: none; }
  .landing .reach__layer--zones { mix-blend-mode: normal; }
  .landing .finale__horizon::before { filter: none; }
  .landing .reach__label, .landing .reach__sat-label { display: none; }
  .landing .reach__pulse, .landing .reach__pulse::after { width: 4rem; height: 4rem; margin: -2rem 0 0 -2rem; }
  .landing .reach__foot { grid-template-columns: 1fr; }
  .landing .reach__cta { grid-column: 1; grid-row: auto; width: 100%; }
  .landing .reach__list {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .5rem 1.25rem;
    list-style: none; margin: .5rem 0 0; padding: 0;
    font-size: var(--s-1);
  }
  .landing .reach__list li { display: flex; justify-content: space-between; gap: .5rem; padding-bottom: .5rem; border-bottom: 1px solid var(--line); color: var(--text-2); }
  .landing .reach__list b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
}

/* ---------- 4. finale ---------- */

.landing .finale {
  position: relative;
  overflow: hidden;
  padding: clamp(5rem, 14vh, 9rem) 0 clamp(15rem, 30vw, 26rem);
  text-align: center;
  border-top: 1px solid var(--line);
}

/* The top of the planet, rising out of the page's bottom edge. */
.landing .finale__horizon {
  position: absolute;
  left: 50%; bottom: 0;
  width: max(115vw, 44rem);
  aspect-ratio: 1;
  transform: translate(-50%, 86%);
  transition: transform 2200ms cubic-bezier(.16, .84, .32, 1);
  pointer-events: none;
}
.landing .finale[data-seen] .finale__horizon { transform: translate(-50%, 79%); }
.landing .finale__horizon img {
  position: relative;
  width: 100%; height: 100%; display: block;
  filter: brightness(.82) saturate(1.1);
  /* The picture carries its own halo out to the square's edges, which showed
     as a hard straight line across the top. Cut it to the disc; the glow
     comes from ::before instead. */
  -webkit-mask-image: radial-gradient(circle closest-side, #000 97.5%, transparent 99%);
  mask-image: radial-gradient(circle closest-side, #000 97.5%, transparent 99%);
}
.landing .finale__horizon::before {
  content: '';
  position: absolute; inset: -6%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(127, 209, 255, .38) 86%, rgba(127, 209, 255, .08) 93%, transparent 100%);
  filter: blur(18px);
}

.landing .finale__horizon::after {
  content: '';
  position: absolute; inset: 1.2%;
  border-radius: 50%;
  box-shadow:
    0 0 0 1px rgba(169, 220, 255, .35),
    0 -6px 30px 2px rgba(127, 209, 255, .45),
    0 -30px 120px 10px rgba(60, 130, 230, .3);
}

.landing .finale__inner { position: relative; display: flex; flex-direction: column; align-items: center; }
.landing .finale__title {
  font-size: clamp(2.75rem, 8vw, 6.5rem);
  font-weight: 500;
  letter-spacing: -0.05em;
  line-height: .98;
}
.landing .finale .lead { max-width: 32rem; margin-top: 1.25rem; }

/* Three cards strung on one line of signal — the chain's idea again, closing
   the page. The line runs through the icons; a pulse travels along it. */
.landing .finale__steps {
  --icon: 3rem;
  --pad: 1.5rem;
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem;
  width: 100%;
  max-width: 62rem;
  list-style: none;
  margin: 3.25rem 0 0; padding: 0;
  text-align: left;
}
.landing .finale__steps::before,
.landing .finale__steps::after {
  content: '';
  position: absolute;
  left: 4%; right: 4%;
  top: calc(var(--pad) + var(--icon) / 2);
  height: 1px;
  pointer-events: none;
}
.landing .finale__steps::before {
  background: linear-gradient(90deg, transparent, var(--line-2) 12%, var(--line-2) 88%, transparent);
}
.landing .finale__steps::after {
  background: linear-gradient(90deg, transparent, var(--accent) 45%, #A9FFDD 55%, transparent) no-repeat;
  background-size: 22% 100%;
  background-position: -30% 0;
  opacity: 0;
  animation: fin-pulse 3.2s cubic-bezier(.45, 0, .25, 1) infinite;
}
.landing .finale[data-seen] .finale__steps::after { opacity: 1; transition: opacity 600ms ease 900ms; }
@keyframes fin-pulse { to { background-position: 130% 0; } }

.landing .finale__step {
  position: relative;
  z-index: 1;
  display: grid;
  align-content: start;
  gap: .5rem;
  padding: var(--pad);
  border-radius: 18px;
  border: 1px solid var(--line);
  background:
    linear-gradient(180deg, rgba(127, 209, 255, .07), rgba(127, 209, 255, 0) 55%),
    #0b0d12;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06), 0 20px 50px -30px rgba(0, 0, 0, .9);
  overflow: hidden;
  opacity: 0;
  transform: translateY(1.25rem);
  transition:
    opacity 700ms ease calc(var(--n) * 140ms + 200ms),
    transform 900ms cubic-bezier(.16, .84, .32, 1) calc(var(--n) * 140ms + 200ms),
    border-color 300ms ease;
}
.landing .finale[data-seen] .finale__step { opacity: 1; transform: none; }
.landing .finale__step:hover { border-color: rgba(127, 209, 255, .35); }

/* The step number: small and crisp, in a hairline pill level with the icon —
   "01 / 03" says where you are without competing with the title. (Two
   larger, decorative versions were tried and read as noise.) */
.landing .finale__num {
  position: absolute;
  top: calc(var(--pad) + var(--icon) / 2);
  right: var(--pad);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: baseline;
  gap: .375rem;
  padding: .3125rem .625rem;
  border: 1px solid rgba(127, 209, 255, .22);
  border-radius: 999px;
  background: rgba(127, 209, 255, .06);
  font-size: var(--s-1);
  font-weight: 600;
  line-height: 1;
  letter-spacing: .08em;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  pointer-events: none;
  transition: border-color 300ms ease, background 300ms ease;
}
.landing .finale__of { font-weight: 500; color: var(--text-3); letter-spacing: .04em; }
.landing .finale__step:hover .finale__num { border-color: rgba(127, 209, 255, .45); background: rgba(127, 209, 255, .1); }

.landing .finale__icon {
  display: grid;
  place-items: center;
  width: var(--icon); height: var(--icon);
  margin-bottom: .6rem;
  border-radius: 50%;
  color: var(--accent);
  background: radial-gradient(circle at 50% 35%, rgba(127, 209, 255, .22), rgba(127, 209, 255, .06) 70%);
  box-shadow: inset 0 0 0 1px rgba(127, 209, 255, .3), 0 0 24px -4px rgba(127, 209, 255, .45);
}
.landing .finale__icon svg {
  width: 1.4rem; height: 1.4rem;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}

.landing .finale__name {
  font-size: var(--s2);
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.25;
  color: var(--text);
}
.landing .finale__note {
  font-size: var(--s0);
  line-height: 1.5;
  color: var(--text-2);
}

/* Phones: a column, the line turned vertical through the icons. */
@media (max-width: 47.99rem) {
  .landing .finale__steps { grid-template-columns: 1fr; gap: .875rem; margin-top: 2.5rem; }
  .landing .finale__steps::before,
  .landing .finale__steps::after {
    left: calc(var(--pad) + var(--icon) / 2); right: auto;
    top: 4%; bottom: 4%;
    width: 1px; height: auto;
  }
  .landing .finale__steps::before {
    background: linear-gradient(180deg, transparent, var(--line-2) 10%, var(--line-2) 90%, transparent);
  }
  .landing .finale__steps::after {
    background: linear-gradient(180deg, transparent, var(--accent) 45%, #A9FFDD 55%, transparent) no-repeat;
    background-size: 100% 22%;
    background-position: 0 -30%;
    animation-name: fin-pulse-v;
  }
}
@keyframes fin-pulse-v { to { background-position: 0 130%; } }

.landing .finale__cta { margin-top: 2.75rem; min-width: 16rem; min-height: 3.5rem; font-size: var(--s1); }

/* ---------- footer ---------- */

.landing .site-footer {
  position: relative;
  z-index: 4;
  background: #010206;
  border-top: 1px solid var(--line);
  padding-top: 3.5rem;
}
.landing .site-footer__grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: 2.5rem 2rem;
  padding-bottom: 3rem !important;
}
.landing .site-footer__mark { font-weight: 600; letter-spacing: .18em; font-size: var(--s0); color: var(--text); }
.landing .site-footer__brand .note { margin: .75rem 0 1.25rem; max-width: 18rem; }
.landing .site-footer__col { display: flex; flex-direction: column; gap: .625rem; font-size: var(--s-1); }
.landing .site-footer__head { color: var(--text-3); letter-spacing: .14em; text-transform: uppercase; font-size: .6875rem; margin-bottom: .25rem; }
.landing .site-footer__col a { color: var(--text-2); }
.landing .site-footer__col a:hover { color: var(--text); }
.landing .site-footer__base {
  padding-block: 1.5rem 2rem !important;
  border-top: 1px solid var(--line);
  font-size: var(--s-1);
  color: var(--text-3);
}

@media (max-width: 52rem) {
  .landing .site-footer__grid { grid-template-columns: 1fr 1fr; }
  .landing .site-footer__brand { grid-column: 1 / -1; }
}

/* ---------- less motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .landing .manifesto__line, .landing .manifesto__line s, .landing .manifesto__answer, .landing .manifesto__who,
  .landing .manifesto__free, .landing .manifesto__free mark,
  .landing .chain__node, .landing .chain__gap,
  .landing .reach__layer, .landing .reach__city,
  .landing .finale__horizon, .landing .finale__step { transition: none !important; }
  .landing .finale__steps::after { animation: none !important; opacity: 0 !important; }
  .landing .chain__track::after, .landing .chain__icon, .landing .chain__icon::after,
  .landing .reach__pulse, .landing .reach__pulse::after { animation: none !important; }
}

/* =========================================================
   Two experiences: the WebGL journey, and a static story
   ========================================================= */

body[data-mode='cinematic'] .mstory { display: none; }
body[data-mode='static'] .journey { display: none; }
body:not([data-mode]) .mstory,
body:not([data-mode]) .journey { visibility: hidden; }

/* ---------- mobile hero ---------- */

.landing .mstory { padding-top: 4.5rem; }

.landing .mhero { padding: 1rem 1.25rem 1rem; text-align: left; }

.landing .mhero__globe {
  position: relative;
  /* Full bleed past .mhero's padding, and up under the bar's lower edge. */
  width: 100vw;
  max-width: 40rem;
  margin: -1rem 0 0 -1.25rem;
  aspect-ratio: 3 / 4;
  overflow: hidden;
}
/* Portrait frame rendered from the live scene by tools/render-hero.html:
   the planet runs off the top and the left, the satellite hangs in the
   middle. The picture dissolves into the page at the top (under the bar)
   and over its lower third, where the headline is set on it. */
.landing .mhero__globe img {
  width: 100%; height: 100%; display: block;
  object-fit: cover;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 7%, #000 58%, rgba(0, 0, 0, .35) 82%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 7%, #000 58%, rgba(0, 0, 0, .35) 82%, transparent 100%);
}
/* The text rides up over the darkened bottom of the picture. */
.landing .mhero__text {
  position: relative;
  z-index: 1;
  margin-top: calc(min(100vw, 40rem) * -4 / 3 * .3);
  text-shadow: 0 1px 18px rgba(8, 9, 11, .85);
}
.landing .mhero__text .btn { text-shadow: none; }
/* Safari paints text-shadow over background-clip:text, which muddied the
   mint "free"; a drop-shadow filter sits behind it in every engine. */
.landing .mhero__text .accent-free { text-shadow: none; filter: drop-shadow(0 1px 12px rgba(8, 9, 11, .85)); }

.landing .mhero h1 {
  font-size: clamp(2.125rem, 9vw, 3rem);
  font-weight: 500; letter-spacing: -0.035em; line-height: 1.05;
}
.landing .mhero__lead { color: var(--text-2); font-size: var(--s1); margin: 1rem 0 1.75rem; }

