/* =========================================================================
   Circly — landing page only. Scoped under .landing-body. Type scale and
   spacing here are landing-specific and do not leak into the app shell;
   the shared palette is consumed only through var(--d-*) from tokens.css.

   Two rules this file must never break, both enforced by
   test-landing-static.mjs:

     1. NO physical left/right anywhere — not as a property, not as an offset.
        Everything is logical (inline-start/inline-end), so RTL and LTR mirror
        for free rather than needing a second stylesheet.
     2. Every animated class must be answered inside the reduced-motion block
        at the end of this file. (Do not name that media query up here: the
        guard reads the stylesheet from its FIRST mention onward, so a mention
        in a comment would hide the real block from it.)

   The accent is the app's v2 sky (V2-DESIGN-LANGUAGE.md section 1.4), held in
   --lp-* names here because this page does not carry data-ui="2" and so does
   not inherit tokens.css's v2 block. Contrast, measured on this page's ground
   (--d-main #0f1216):
     sky #3abff8 as text ......................... 8.93:1  (floor 4.5)
     #0b111e label ON a sky fill ................. 8.97:1  (white on sky is 2.1:1
                                                  and is forbidden, never used)
     #0b111e on the pressed fill #0ea5e9 ......... 6.81:1
   Nothing in tokens.css changes; the landing keeps the surfaces it has and only
   its brand colour moves.
   ========================================================================= */

.landing-body {
  /* type scale (landing-only) */
  --lp-fs-label: 0.875rem;
  --lp-fs-body: 1rem;
  --lp-fs-heading: 1.5rem;
  --lp-fs-h2: clamp(1.875rem, 4.5vw, 3.25rem);
  --lp-fs-display: clamp(2.5rem, 8vw, 5.5rem);
  --lp-fs-lead: clamp(1.0625rem, 2.2vw, 1.375rem);

  /* spacing scale (landing-only) */
  --lp-sp-4: 4px;
  --lp-sp-8: 8px;
  --lp-sp-16: 16px;
  --lp-sp-24: 24px;
  --lp-sp-32: 32px;
  --lp-sp-48: 48px;
  --lp-sp-64: 64px;
  --lp-sp-96: 96px;
  --lp-section: clamp(88px, 13vh, 168px);

  /* v2 accent layer (see header note). Hex is allowed here, in the custom
     property declarations, and nowhere in a component rule. */
  --lp-accent: #3abff8;          /* fills, text, focus rings, glow */
  --lp-accent-2: #67e8f9;        /* gradient end, hover */
  --lp-accent-press: #0ea5e9;    /* pressed filled accent */
  --lp-accent-fg: #0b111e;       /* label on a filled accent */
  --lp-aurora-a: rgba(13, 162, 231, .28);   /* sky, V2 section 2 */
  --lp-aurora-b: rgba(9, 196, 220, .14);    /* cyan */
  --lp-aurora-c: rgba(67, 70, 239, .16);    /* indigo, hue 239: aurora light, not brand chrome */
  --lp-accent-text: var(--lp-accent);
  --lp-cta-fill: var(--lp-accent);
  --lp-grad: linear-gradient(140deg, var(--lp-accent), var(--lp-accent-2));
  --lp-glow-btn: 0 8px 20px -8px color-mix(in srgb, var(--lp-accent) 80%, transparent);
  --lp-glow-btn-hover: 0 12px 26px -8px color-mix(in srgb, var(--lp-accent) 90%, transparent);
  --lp-well-1: #0c0e13;   /* scrim gradient, one step under --d-main */
  --lp-well-2: #0a0c10;   /* its darkest point */
  --lp-glass: rgba(255, 255, 255, .035);
  --lp-edge: rgba(255, 255, 255, .09);
  --lp-edge-hi: rgba(255, 255, 255, .16);

  --lp-ease: cubic-bezier(.16, 1, .3, 1);

  /* Buttons are rectangular with a curve, not pills. Chips and status flags
     stay fully round — they are labels, not actions, and the difference in
     shape is what tells them apart at a glance. */
  --lp-radius-btn: 12px;

  margin: 0;
  background: var(--d-main);
  color: var(--d-text);
  font-family: 'Vazirmatn', system-ui, -apple-system, sans-serif;
  font-size: var(--lp-fs-body);
  font-weight: 400;
  line-height: 1.7;
  /* Decorative glows deliberately bleed past their box; clip them site-wide so
     a bleed can never grow document.scrollWidth into a horizontal scrollbar,
     without touching normal vertical scrolling. */
  overflow-x: hidden;
}

/* The hero is 100dvh and the top bar is sticky over it; without this every
   in-page anchor would land under the bar. */
:root { scroll-padding-block-start: 76px; }

/* =========================================================================
   Reveal primitive — ONE IntersectionObserver for the whole page (landing.js
   adds .is-in). --i is the stagger index, set inline, capped at 8 by the
   observer: past that the last item reads as broken rather than choreographed.
   The <noscript> block in landing.html un-hides all of this when JS is off.
   ========================================================================= */
.lp-rise { opacity: 0; transform: translateY(24px); }
.is-in.lp-rise,
.is-in .lp-rise {
  opacity: 1;
  transform: none;
  transition:
    opacity .55s var(--lp-ease) calc(var(--i, 0) * 70ms),
    transform .55s var(--lp-ease) calc(var(--i, 0) * 70ms);
}

/* =========================================================================
   Aurora — three blurred blobs on a slow drift. Pure decoration, no bytes.
   ========================================================================= */
.lp-aurora {
  position: absolute;
  inset: -25%;
  pointer-events: none;
  filter: blur(90px);
  z-index: 0;
}
.lp-aurora i {
  position: absolute;
  display: block;
  border-radius: 50%;
}
.lp-aurora i:nth-child(1) {
  inline-size: 46%; block-size: 58%;
  inset-inline-start: 6%; inset-block-start: 4%;
  background: var(--lp-aurora-a);
  animation: lp-drift-a 38s ease-in-out infinite alternate;
}
.lp-aurora i:nth-child(2) {
  inline-size: 40%; block-size: 54%;
  inset-inline-start: 50%; inset-block-start: 16%;
  background: var(--lp-aurora-b);
  animation: lp-drift-b 44s ease-in-out infinite alternate;
}
.lp-aurora i:nth-child(3) {
  inline-size: 34%; block-size: 44%;
  inset-inline-start: 28%; inset-block-start: 40%;
  background: var(--lp-aurora-c);
  animation: lp-drift-c 52s ease-in-out infinite alternate;
}
.lp-aurora--soft { opacity: .55; }
@keyframes lp-drift-a { to { transform: translate3d(12%, 8%, 0) scale(1.14); } }
@keyframes lp-drift-b { to { transform: translate3d(-14%, 7%, 0) scale(1.1); } }
@keyframes lp-drift-c { to { transform: translate3d(9%, -10%, 0) scale(1.18); } }

/* =========================================================================
   Scroll progress ring — the circle motif, applied to the page itself.
   Driven entirely by a scroll-driven animation, so it costs no listener. In a
   browser without scroll timelines it simply does not appear: it is pure
   decoration and is not worth a scroll handler.
   ========================================================================= */
.lp-prog { display: none; }
@supports (animation-timeline: scroll()) {
  @media (min-width: 900px) {
    .lp-prog {
      display: block;
      position: fixed;
      inset-block-end: 26px;
      inset-inline-end: 26px;
      inline-size: 44px;
      block-size: 44px;
      z-index: 40;
      pointer-events: none;
    }
    .lp-prog svg { inline-size: 100%; block-size: 100%; transform: rotate(-90deg); }
    .lp-prog circle { fill: none; stroke-width: 2.5; }
    .lp-prog-bg { stroke: var(--lp-edge); }
    .lp-prog-fg {
      stroke: var(--lp-accent-text);
      stroke-linecap: round;
      stroke-dasharray: 119.4;
      animation: lp-prog-fill linear both;
      animation-timeline: scroll(root block);
    }
  }
}
@keyframes lp-prog-fill { from { stroke-dashoffset: 119.4; } to { stroke-dashoffset: 0; } }

/* =========================================================================
   Skip link — keyboard users land here first; invisible until focused.
   ========================================================================= */
.lp-skip {
  position: absolute;
  inset-block-start: -100%;
  inset-inline-start: 0;
  z-index: 60;
  padding: 10px var(--lp-sp-16);
  background: var(--lp-accent);
  color: var(--lp-accent-fg);
  font-weight: 700;
  text-decoration: none;
  border-end-end-radius: 8px;
}
.lp-skip:focus { inset-block-start: 0; }

/* =========================================================================
   Top bar
   ========================================================================= */
.lp-topbar {
  position: sticky;
  inset-block-start: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lp-sp-16);
  min-block-size: 64px;
  padding-inline: clamp(16px, 4vw, 40px);
  background: transparent;
  border-block-end: 1px solid transparent;
  transition: background-color .25s, border-color .25s, backdrop-filter .25s;
}
.lp-topbar.is-stuck {
  background: rgba(15, 18, 22, .72);
  border-block-end-color: var(--lp-edge);
}
@supports (backdrop-filter: blur(1px)) {
  .lp-topbar.is-stuck { backdrop-filter: blur(18px) saturate(1.3); }
}
.lp-topbrand {
  display: inline-flex;
  align-items: center;
  gap: var(--lp-sp-8);
  color: var(--d-text);
  font-weight: 700;
  text-decoration: none;
}
.lp-topnav { display: flex; align-items: center; gap: clamp(10px, 2vw, 22px); }
.lp-topnav a {
  color: var(--d-dim);
  font-size: var(--lp-fs-label);
  text-decoration: none;
  transition: color .15s;
}
.lp-topnav a:hover { color: var(--d-text); }
.lp-topnav .lp-topcta,
.lp-topnav .lp-toplogin {
  box-sizing: border-box;
  min-block-size: 44px;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  border-radius: var(--lp-radius-btn);
  font-weight: 700;
  text-decoration: none;
}
/* Filled primary: the v2 sky gradient with the dark label (never white) and the
   section-5 glow. «ورود» beside it stays quiet so there is one loud thing. */
.lp-topnav .lp-topcta {
  padding-inline: 16px;
  background: var(--lp-grad);
  color: var(--lp-accent-fg);
  box-shadow: var(--lp-glow-btn);
  transition: transform .15s, box-shadow .15s, background-color .15s;
}
.lp-topnav .lp-topcta:hover {
  background: var(--lp-accent-2);
  color: var(--lp-accent-fg);
  transform: translateY(-1px);
  box-shadow: var(--lp-glow-btn-hover);
}
.lp-topnav .lp-topcta:active { background: var(--lp-accent-press); transform: none; }
.lp-topnav .lp-toplogin {
  padding-inline: 12px;
  color: var(--d-text);
  transition: color .15s;
}
.lp-topnav .lp-toplogin:hover { color: var(--lp-accent-text); }

/* Every interactive thing on the page answers keyboard focus in the accent. */
.lp-skip:focus-visible,
.lp-topbrand:focus-visible,
.lp-topnav a:focus-visible,
.lp-lang:focus-visible,
.lp-foot-links a:focus-visible { outline: 2px solid var(--lp-accent); outline-offset: 3px; }

/* Language toggle. A real <button> — it changes state, it does not navigate. */
.lp-lang {
  min-block-size: 32px;
  min-inline-size: 40px;
  padding-inline: 10px;
  border-radius: var(--lp-radius-btn);
  border: 1px solid var(--lp-edge);
  background: transparent;
  color: var(--d-dim);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.lp-lang:hover { color: var(--d-text); border-color: var(--lp-edge-hi); }

/* Hide the nav links on small screens; the two buttons and the toggle stay,
   and must all fit one row at 390 (they do not shrink below the 44px target;
   the gaps and side padding give instead). */
@media (max-width: 720px) {
  .lp-topnav a:not(.lp-topcta):not(.lp-toplogin) { display: none; }
  .lp-topnav { gap: 4px; }
  .lp-topnav .lp-topcta { padding-inline: 12px; }
  .lp-topnav .lp-toplogin { padding-inline: 8px; }
}

/* =========================================================================
   Hero
   ========================================================================= */
.lp-hero {
  position: relative;
  min-block-size: calc(100dvh - 64px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding-block: var(--lp-sp-48) var(--lp-sp-64);
  padding-inline: var(--lp-sp-24);
  isolation: isolate;
  /* The aurora bleeds 25% past the box on purpose. clip (not hidden) cuts the
     bleed off the scrollable area without making the hero a scroll container. */
  overflow-x: clip;
}
.lp-hero > *:not(.lp-aurora) { position: relative; z-index: 1; }

@media (min-width: 640px) {
  .lp-hero { padding-inline: var(--lp-sp-32); }
}

/* Brand lockup inside its orbit. Width/height are on the <img> too, so the
   hero never reflows while it decodes (the CLS guard asserts this). */
.lp-mark-wrap {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 240px;
  block-size: 240px;
  margin-block-end: var(--lp-sp-24);
}
.lp-mark {
  display: block;
  inline-size: 150px;
  block-size: auto;
  aspect-ratio: 340 / 374;
  filter: drop-shadow(0 10px 34px color-mix(in srgb, var(--lp-accent) 42%, transparent));
}
.lp-orbit {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  animation: lp-spin 60s linear infinite;
}
.lp-orbit-ring { fill: none; stroke: var(--lp-edge); stroke-width: 1; }
.lp-orbit-dot { fill: var(--lp-accent-text); }
.lp-orbit-dot--b { fill: var(--lp-accent-2); transform: rotate(132deg); transform-origin: 120px 120px; }
.lp-orbit-dot--c { fill: var(--d-green); transform: rotate(238deg); transform-origin: 120px 120px; }
@keyframes lp-spin { to { transform: rotate(360deg); } }

.lp-tagline {
  font-size: var(--lp-fs-display);
  font-weight: 700;
  line-height: 1.14;
  letter-spacing: -.015em;
  margin-block: 0 var(--lp-sp-24);
  max-inline-size: 15ch;
  text-wrap: balance;
}
/* Word-level stagger. Persian is a cursive, connected script — splitting into
   CHARACTERS breaks the glyph joining and renders disconnected letterforms, so
   landing.js only ever wraps whole words. */
.lp-tagline .lp-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(.35em);
  animation: lp-word-in .6s var(--lp-ease) forwards;
  animation-delay: calc(var(--i, 0) * 60ms + 120ms);
}
@keyframes lp-word-in { to { opacity: 1; transform: none; } }

.lp-lead {
  font-size: var(--lp-fs-lead);
  font-weight: 400;
  line-height: 1.7;
  color: var(--d-dim);
  max-inline-size: 44ch;
  margin-inline: auto;
  margin-block: 0 var(--lp-sp-24);
}
.lp-microcopy {
  margin-block: var(--lp-sp-16) 0;
  font-size: var(--lp-fs-label);
  color: var(--d-dim);
}

/* =========================================================================
   Buttons
   ========================================================================= */
.lp-cta {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 46px;
  padding-inline: var(--lp-sp-24);
  border-radius: var(--lp-radius-btn);
  /* The v2 signature gradient with the DARK label: #0b111e on sky is 8.97:1.
     White on sky is 2.1:1 and is never used. */
  background: var(--lp-grad);
  color: var(--lp-accent-fg);
  font-family: inherit;
  font-weight: 700;
  font-size: var(--lp-fs-body);
  text-decoration: none;
  box-shadow: var(--lp-glow-btn);
  transition: background-color .15s, transform .15s, box-shadow .15s;
}
.lp-cta:hover {
  background: var(--lp-accent-2);
  transform: translateY(-1px);
  box-shadow: var(--lp-glow-btn-hover);
}
.lp-cta:focus-visible { outline: 2px solid var(--lp-accent); outline-offset: 3px; }

.lp-cta-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--lp-sp-16);
}

.lp-cta--ghost {
  background: transparent;
  color: var(--d-text);
  font-weight: 700;
  border: 1px solid color-mix(in srgb, var(--lp-accent) 45%, transparent);
  box-shadow: none;
}
.lp-cta--ghost:hover {
  border-color: var(--lp-accent);
  color: var(--lp-accent-text);
  background: transparent; /* D-11: never a filled second CTA, even on hover */
  box-shadow: none;
}
.lp-cta--ghost:focus-visible { outline: 2px solid var(--lp-accent); outline-offset: 3px; }
.lp-cta:active { background: var(--lp-accent-press); transform: translateY(0); }
.lp-cta--ghost:active { background: transparent; transform: translateY(0); }

/* =========================================================================
   Hero screenshot
   ========================================================================= */
.lp-shot {
  position: relative;
  margin: var(--lp-sp-48) auto 0;
  inline-size: min(880px, 100%);
  border-radius: 14px;
  perspective: 1400px;
}
.lp-shot::before {
  content: '';
  position: absolute;
  inset: -10%;
  background: radial-gradient(50% 50% at 50% 40%, color-mix(in srgb, var(--lp-accent) 30%, transparent), transparent 70%);
  filter: blur(50px);
  z-index: -1;
}
.lp-shot picture,
.lp-shot img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  border-radius: 14px;
  border: 1px solid var(--lp-edge);
  box-shadow: 0 30px 80px rgba(0, 0, 0, .55);
}
/* The tilt lives on the FIGURE, never on the <img> — the image keeps its
   intrinsic width/height attributes untouched, so the CLS guard still holds. */
@supports (animation-timeline: view()) {
  .lp-shot {
    animation: lp-untilt linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 40%;
    transform-style: preserve-3d;
  }
}
@keyframes lp-untilt {
  from { transform: rotateX(9deg) scale(.96); }
  to { transform: none; }
}

/* =========================================================================
   Generic section furniture
   ========================================================================= */
.lp-section {
  padding-block: var(--lp-section);
  padding-inline: clamp(20px, 5vw, 48px);
  max-inline-size: 1180px;
  margin-inline: auto;
}
.lp-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 var(--lp-sp-16);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--lp-accent-text);
}
.lp-eyebrow::before {
  content: '';
  inline-size: 14px;
  block-size: 14px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  border-block-start-color: transparent;
  border-inline-end-color: transparent;
}
.lp-h2 {
  font-size: var(--lp-fs-h2);
  font-weight: 700;
  line-height: 1.22;
  letter-spacing: -.012em;
  margin-block: 0 var(--lp-sp-16);
  max-inline-size: 22ch;
  text-wrap: balance;
}
.lp-sub {
  margin-block: 0 var(--lp-sp-48);
  color: var(--d-dim);
  font-size: var(--lp-fs-lead);
  line-height: 1.7;
  max-inline-size: 52ch;
}

/* =========================================================================
   Sync demo — the flagship. A tall section with a sticky inner panel; scroll
   progress arrives as --t (0 to 1). Sticky rather than JS pinning: it is
   compositor-friendly, survives the mobile URL-bar resize, and degrades to
   "the section just scrolls" if anything fails.

   Three big screens play ONE film. Every moving part of the film (sun, moon,
   stars, three hill layers, a bird, the sky, the progress bar, the timecode) is
   a pure function of --t and nothing else, and --t is inherited from this one
   element, so the three screens are frame-identical at every scroll position by
   construction. Only transform and opacity move.
   ========================================================================= */
/* The timecode: seconds derived from --t, then split into minutes and seconds.
   Registered as integers so calc() lands on whole numbers; the minutes are
   round((sec - 30) / 60), which equals floor(sec / 60) for whole seconds. A
   browser without @property shows 00:00 on all three, which is still identical. */
@property --sec { syntax: '<integer>'; inherits: true; initial-value: 0; }
@property --min { syntax: '<integer>'; inherits: true; initial-value: 0; }
@property --ss { syntax: '<integer>'; inherits: true; initial-value: 0; }
@counter-style lp-clock { system: numeric; symbols: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9'; pad: 2 '0'; }
@counter-style lp-clock-fa { system: numeric; symbols: '۰' '۱' '۲' '۳' '۴' '۵' '۶' '۷' '۸' '۹'; pad: 2 '۰'; }

/* The view timeline belongs to the TALL SECTION, not to the sticky panel: the
   panel can be taller than a short phone viewport, and "contain" is empty for a
   subject that does not fit. The section always covers the viewport, so its
   contain range runs from the moment it pins to the moment it lets go, exactly
   the (height - viewport) span the scroll fallback in landing.js uses. */
@supports (animation-timeline: view()) {
  @property --t { syntax: '<number>'; inherits: true; initial-value: 0; }
  .lp-sync-sec { view-timeline: --lp-sync block; view-timeline-inset: 0px; }   /* 0, not the 76px scroll-padding, so it matches the fallback maths */
  .lp-sync {
    animation: lp-scrub linear both;
    animation-timeline: --lp-sync;
    animation-range: contain 0% contain 100%;
  }
}
@keyframes lp-scrub { from { --t: 0; } to { --t: 1; } }

/* The well fades INTO and OUT OF the page ground at both ends, so the
   darkening is felt rather than seen. */
.lp-sync-sec {
  position: relative;
  min-block-size: 300vh;
  padding-inline: clamp(16px, 4vw, 48px);
  background:
    radial-gradient(70% 40% at 50% 22%, color-mix(in srgb, var(--lp-accent) 12%, transparent), transparent 72%),
    linear-gradient(180deg,
      var(--d-main) 0%,
      var(--lp-well-1) 14%,
      var(--lp-well-2) 50%,
      var(--lp-well-1) 86%,
      var(--d-main) 100%);
}
.lp-sync {
  --t: 0;
  --sec: calc(var(--t) * 120);
  --min: calc((var(--sec) - 30) / 60);
  --ss: calc(var(--sec) - var(--min) * 60);
  position: sticky;
  inset-block-start: 0;
  min-block-size: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  max-inline-size: 1200px;
  margin-inline: auto;
}
.lp-sync .lp-h2 { max-inline-size: 20ch; }
.lp-sync .lp-eyebrow { justify-content: center; }

/* Media timelines read start-to-end in every locale, so this block is pinned
   LTR in both directions rather than mirroring like the rest of the page. Three
   equal screens from 640px; below that one wide screen over two half-width
   ones, so all three stay inside one phone viewport under the heading. */
.lp-players {
  direction: ltr;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(10px, 2vw, 24px);
  inline-size: 100%;
  margin-block: var(--lp-sp-24);
}
.lp-pl:first-child { grid-column: 1 / -1; }
@media (min-width: 640px) {
  .lp-players { grid-template-columns: repeat(3, 1fr); }
  .lp-pl:first-child { grid-column: auto; }
}
.lp-pl {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--lp-sp-8) var(--lp-sp-16);
  padding: 8px 8px 10px;
  border-radius: 14px;
  border: 1px solid var(--lp-edge-hi);
  background: var(--lp-glass);
  box-shadow: 0 24px 60px -30px color-mix(in srgb, var(--lp-accent) 40%, transparent);
  /* A locked screen says so: the frame turns green as the film plays out. */
  border-color: color-mix(in srgb, var(--d-green) calc(var(--t) * 45%), var(--lp-edge-hi));
}
.lp-scene {
  grid-column: 1 / -1;
  display: block;
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  background: var(--sc-night);
  /* The film's palette. No purples: dusk here is peach and slate. */
  --sc-night: rgb(10, 17, 36);
  --sc-day: rgb(66, 146, 214);
  --sc-dusk: rgb(238, 138, 92);
  --sc-far: rgb(28, 58, 88);
  --sc-mid: rgb(17, 38, 62);
  --sc-near: rgb(9, 20, 36);
  --sc-star: rgb(238, 244, 255);
  --sc-sun: rgb(255, 214, 128);
  --sc-moon: rgb(226, 234, 246);
}
.lp-scene .sc-day { fill: var(--sc-day); opacity: clamp(0, 1 - var(--t) * 2.2, 1); }
.lp-scene .sc-dusk { opacity: clamp(0, 1 - max(var(--t) - .38, .38 - var(--t)) * 2.8, 1); }
.lp-scene .sc-dusk rect { fill: var(--sc-dusk); fill-opacity: .36; }
.lp-scene .sc-stars { fill: var(--sc-star); opacity: clamp(0, (var(--t) - .5) * 4, 1); }
.lp-scene .sc-sun {
  fill: var(--sc-sun);
  transform: translate(calc(var(--t) * 44px), calc(var(--t) * var(--t) * 78px));
}
.lp-scene .sc-moon {
  fill: var(--sc-moon);
  opacity: clamp(0, (var(--t) - .38) * 3.2, 1);
  transform: translate(calc(var(--t) * -34px), calc((1 - var(--t)) * 46px));
}
.lp-scene .sc-hill { fill: var(--sc-far); }
.lp-scene .sc-far { transform: translateX(calc(var(--t) * -10px)); }
.lp-scene .sc-mid { fill: var(--sc-mid); transform: translateX(calc(var(--t) * -22px)); }
.lp-scene .sc-near { fill: var(--sc-near); transform: translateX(calc(var(--t) * -40px)); }
.lp-scene .sc-bird {
  fill: none;
  stroke: var(--sc-star);
  stroke-width: 1.2;
  stroke-linecap: round;
  transform: translate(calc(-20px + var(--t) * 190px), 20px);
}

/* The player bar under each screen: a progress fill scaled by --t, and the
   timecode. The track reads start to end, so it is anchored at its start edge
   in the block's own (left to right) direction. */
.lp-pl-bar {
  position: relative;
  display: block;
  block-size: 4px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--lp-accent) 16%, transparent);
  overflow: hidden;
}
.lp-pl-fill {
  position: absolute;
  inset: 0;
  background: var(--lp-grad);
  transform-origin: 0 50%;
  transform: scaleX(var(--t));
}
.lp-pl-time {
  counter-reset: lp-m var(--min) lp-s var(--ss);
  font-size: var(--lp-fs-label);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--d-dim);
}
.lp-pl-time::before { content: counter(lp-m, lp-clock) ':' counter(lp-s, lp-clock); }
:lang(fa) .lp-pl-time::before { content: counter(lp-m, lp-clock-fa) ':' counter(lp-s, lp-clock-fa); }

/* The three beats sit DIRECTLY under the players in a reserved box. The box
   keeps its height whichever caption is showing, so nothing reflows as they
   cross-fade. Beat 1: someone presses play. Beat 2: the film moves for all.
   Beat 3: the screens agree. */
.lp-sync-caps {
  position: relative;
  display: grid;
  place-items: center;
  min-block-size: 4.2em;
  inline-size: min(640px, 100%);
  margin-block-end: var(--lp-sp-24);
}
.lp-sync-cap {
  grid-area: 1 / 1;
  margin: 0;
  font-size: var(--lp-fs-lead);
  font-weight: 700;
  color: var(--d-text);
  text-wrap: balance;
}
.lp-sync-cap[data-beat="1"] { opacity: calc(1 - clamp(0, (var(--t) - .16) / .08, 1)); }
.lp-sync-cap[data-beat="2"] { opacity: calc(clamp(0, (var(--t) - .2) / .08, 1) - clamp(0, (var(--t) - .66) / .08, 1)); }
.lp-sync-cap[data-beat="3"] { opacity: calc(clamp(0, (var(--t) - .72) / .1, 1)); color: var(--d-green); }

/* The prose version of the same argument, given a card of its own so it reads
   as the conclusion rather than as a trailing caption. Always fully visible,
   whatever the scrub is doing. */
.lp-sync-card {
  display: flex;
  align-items: center;
  gap: var(--lp-sp-16);
  max-inline-size: 620px;
  padding: var(--lp-sp-16) var(--lp-sp-24);
  border-radius: 14px;
  border: 1px solid var(--lp-edge-hi);
  background: var(--lp-glass);
  text-align: start;
}
@supports (backdrop-filter: blur(1px)) {
  .lp-sync-card { backdrop-filter: blur(12px); }
}
.lp-sync-ic {
  flex: none;
  display: inline-grid;
  place-items: center;
  inline-size: 38px;
  block-size: 38px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--lp-accent) 16%, transparent);
  color: var(--lp-accent-text);
}
.lp-sync-ic svg { inline-size: 20px; block-size: 20px; }
.lp-sync-static { margin: 0; color: var(--d-dim); line-height: 1.8; }

@media (max-width: 640px) and (max-height: 740px) {
  .lp-sync .lp-eyebrow,
  .lp-sync-card { display: none; }
}
@media (max-width: 640px) {
  .lp-sync-sec { min-block-size: 240vh; }
  .lp-sync { padding-block: var(--lp-sp-16); }
  .lp-sync .lp-h2 { font-size: var(--lp-fs-heading); }
  .lp-players { margin-block: var(--lp-sp-16); gap: 8px; }
  .lp-pl { padding: 6px 6px 8px; border-radius: 12px; gap: 4px 8px; }
  .lp-sync-cap { font-size: var(--lp-fs-body); }
  .lp-sync-caps { min-block-size: 3.6em; margin-block-end: var(--lp-sp-16); }
  .lp-sync-card { padding: 12px var(--lp-sp-16); }
  .lp-sync-static { font-size: var(--lp-fs-label); line-height: 1.7; }
}

/* =========================================================================
   Hairline figures. Each is an isometric line drawing from the vendored
   @lucasmarkes/hairline kernel, mounted by landing.js only after the first
   view. The panel is OPAQUE: Hairline's plates are filled with the ground
   colour, so the panel background and --hairline-plate must be one colour or
   the drawing shows its own construction. Brightest stroke is the accent's
   cyan end; the other three weights are the page's dim text mixed into the
   ground. A figure never carries a caption or a label (the stage holds no text
   at all); the card's own heading and paragraph say what it means.
   ========================================================================= */
.lp-fig {
  position: relative;
  overflow: hidden;
  border-radius: 14px;
  border: 1px solid var(--lp-edge);
  background: var(--d-rail);
  --hairline-plate: var(--d-rail);
  --hairline-hi: var(--lp-accent-2);
  --hairline-edge: color-mix(in srgb, var(--d-dim) 78%, var(--d-rail));
  --hairline-mid: color-mix(in srgb, var(--d-dim) 40%, var(--d-rail));
  --hairline-lo: color-mix(in srgb, var(--d-dim) 20%, var(--d-rail));
  --hairline-stroke: 1.05;
}
/* The box is reserved before the kernel loads (5:4, the kernel's own ratio), so
   nothing shifts when a figure mounts. Each figure sits in a framing measured
   from where it actually draws (every pose): --zoom magnifies the stage about
   its centre, --cut-t / --cut-b crop empty frame off the top and bottom, all
   as a percentage of the panel's width. A row of cards shares one framing. */
.lp-fig-stage {
  --zoom: 1;
  display: block;
  aspect-ratio: 5 / 4;
  inline-size: calc(100% * var(--zoom));
  margin-inline: calc((1 - var(--zoom)) * 50%);
  margin-block: calc(var(--cut-t, 0%) * -1) calc(var(--cut-b, 0%) * -1);
}

/* =========================================================================
   Features — five figure-led cards. Two wide (voice, share: figure beside the
   copy) over three narrow (figure over the copy). No grid-template-areas, so
   there is no RTL mirroring trap: DOM order IS reading order, and the grid
   mirrors with the document direction.
   ========================================================================= */
.lp-bento {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--lp-sp-16);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .lp-bento { grid-template-columns: repeat(6, 1fr); gap: var(--lp-sp-24); }
  .lp-card { grid-column: span 2; }
  .lp-card--voice,
  .lp-card--share { grid-column: span 3; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: center; }
}
@media (min-width: 560px) and (max-width: 899px) {
  .lp-card { grid-template-columns: minmax(0, 240px) minmax(0, 1fr); align-items: center; }
}

.lp-card {
  position: relative;
  overflow: hidden;
  display: grid;
  gap: var(--lp-sp-16) var(--lp-sp-24);
  align-content: start;
  padding: var(--lp-sp-24);
  border-radius: 16px;
  border: 1px solid var(--lp-edge);
  background: var(--d-side);
  transition: border-color .2s, transform .2s, background-color .2s;
}
.lp-card::after {
  content: '';
  position: absolute;
  inset-block-start: -40%;
  inset-inline-end: -30%;
  inline-size: 260px;
  block-size: 260px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--lp-accent) 16%, transparent), transparent 68%);
  pointer-events: none;
}
.lp-card > .lp-fig { position: relative; z-index: 1; }
.lp-card:hover {
  border-color: var(--lp-edge-hi);
  background: var(--d-hover);
  transform: translateY(-3px);
}
.lp-card-text { position: relative; z-index: 1; }
.lp-card h3 {
  margin: 0 0 var(--lp-sp-8);
  font-size: var(--lp-fs-heading);
  font-weight: 700;
  line-height: 1.35;
}
.lp-card p { margin: 0; color: var(--d-dim); line-height: 1.85; }

/* =========================================================================
   Why Circly — five reasons. Deliberately not a competitor table.
   ========================================================================= */
/* A spine with numbered nodes, and a card per reason carrying its own drawn
   scene. The spine is what makes five separate claims read as one argument. */
.lp-reasons {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--lp-sp-24);
  position: relative;
}
@media (min-width: 760px) {
  .lp-reasons { padding-inline-start: 76px; }
  /* The spine itself. Fades out at both ends so it never looks cut off. */
  .lp-reasons::before {
    content: '';
    position: absolute;
    inset-block: 26px;
    inset-inline-start: 27px;
    inline-size: 2px;
    background: linear-gradient(180deg, transparent, var(--lp-edge-hi) 12%, var(--lp-edge-hi) 88%, transparent);
  }
}

.lp-reason { position: relative; }
.lp-reason-node {
  display: none;
  position: absolute;
  inset-block-start: 22px;
  inset-inline-start: -76px;
  inline-size: 56px;
  block-size: 56px;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--lp-edge-hi);
  background: var(--d-main);
  font-size: 15px;
  font-weight: 700;
  color: var(--lp-accent-text);
  z-index: 1;
  transition: border-color .25s, color .25s, box-shadow .25s;
}
@media (min-width: 760px) { .lp-reason-node { display: grid; } }
.lp-reason:hover .lp-reason-node {
  border-color: var(--lp-accent-text);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--lp-accent) 10%, transparent);
}

.lp-reason-card {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--lp-sp-16);
  align-items: center;
  padding: var(--lp-sp-24);
  border-radius: 18px;
  border: 1px solid var(--lp-edge);
  background: var(--lp-glass);
  transition: border-color .2s, background-color .2s, transform .2s;
}
@media (min-width: 560px) {
  .lp-reason-card { grid-template-columns: minmax(200px, 260px) 1fr; gap: var(--lp-sp-24); }
  /* Alternate which edge the figure sits on, so five cards do not read as a
     list of five identical rows. */
  .lp-reason:nth-child(even) .lp-reason-card { grid-template-columns: 1fr minmax(200px, 260px); }
  .lp-reason:nth-child(even) .lp-fig { order: 2; }
}
/* Stacked, a figure is capped so it does not balloon on a wide phone. */
.lp-reason .lp-fig { inline-size: min(100%, 360px); justify-self: center; }
@media (min-width: 560px) { .lp-reason .lp-fig { inline-size: 100%; } }
.lp-reason:hover .lp-reason-card {
  border-color: var(--lp-edge-hi);
  background: var(--d-side);
  transform: translateY(-2px);
}

.lp-reason h3 { margin: 0 0 6px; font-size: var(--lp-fs-heading); font-weight: 700; line-height: 1.35; }
.lp-reason p { margin: 0; color: var(--d-dim); line-height: 1.85; max-inline-size: 62ch; }

/* =========================================================================
   Split sections (how-it-works, desktop). The second one flips so two split
   layouts in a row never read as one.
   ========================================================================= */
.lp-split { display: grid; gap: var(--lp-sp-48); align-items: center; }
@media (min-width: 900px) {
  .lp-split { grid-template-columns: 1fr 1fr; gap: var(--lp-sp-64); }
  .lp-split--flip .lp-split-text { order: -1; }
}
.lp-list { margin: 0 0 var(--lp-sp-24); padding: 0; list-style: none; display: grid; gap: 14px; }
.lp-list li {
  position: relative;
  padding-inline-start: 28px;
  color: var(--d-dim);
  line-height: 1.85;
}
.lp-list li::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .72em;
  inline-size: 8px;
  block-size: 8px;
  border-radius: 50%;
  background: var(--lp-grad);
}
/* --d-faint is 3.61:1 on --d-main — below the 4.5:1 floor for a real sentence.
   Notes use --d-dim (7.38:1) instead. */
.lp-note { margin: 0 0 var(--lp-sp-24); color: var(--d-dim); font-size: var(--lp-fs-label); }

.lp-keys {
  display: grid;
  gap: 12px;
  padding: var(--lp-sp-24);
  border-radius: 16px;
  border: 1px solid var(--lp-edge);
  background: var(--lp-glass);
}
.lp-key-row { display: flex; align-items: center; justify-content: space-between; gap: var(--lp-sp-16); }
.lp-key-row span { color: var(--d-dim); font-size: var(--lp-fs-label); }
.lp-key-row kbd {
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--lp-edge-hi);
  border-block-end-width: 2px;
  background: var(--d-rail);
  color: var(--d-text);
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 13px;
  white-space: nowrap;
}
.is-in .lp-key-row {
  animation: lp-press .3s var(--lp-ease) calc(var(--i) * 60ms + 200ms) both;
}
@keyframes lp-press {
  0% { transform: translateY(-3px); }
  60% { transform: translateY(1px); }
  100% { transform: none; }
}

/* The native-share settings, depicted (the desktop section's aside). The
   option labels are the share dialog's own; "source" and "60 fps" are shown
   selected because they are the defaults. Selected is a filled chip AND a dot,
   never colour alone. */
.lp-split-aside { display: grid; gap: var(--lp-sp-16); }
.lp-native {
  display: grid;
  gap: var(--lp-sp-16);
  padding: var(--lp-sp-24);
  border-radius: 16px;
  border: 1px solid var(--lp-edge);
  background: var(--lp-glass);
}
.lp-native-head { display: flex; align-items: center; justify-content: space-between; gap: var(--lp-sp-16); font-weight: 700; }
.lp-chip {
  padding: 3px 12px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--lp-accent) 45%, transparent);
  background: color-mix(in srgb, var(--lp-accent) 12%, transparent);
  color: var(--lp-accent-text);
  font-size: var(--lp-fs-label);
  font-weight: 700;
  letter-spacing: .04em;
}
.lp-opt-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--lp-sp-8); }
.lp-opt-lbl { flex: 0 0 5.5em; color: var(--d-dim); font-size: var(--lp-fs-label); }
.lp-opt {
  padding: 6px 12px;
  border-radius: var(--lp-radius-btn);
  border: 1px solid var(--lp-edge-hi);
  color: var(--d-dim);
  font-size: var(--lp-fs-label);
}
.lp-opt.is-on { border-color: transparent; background: var(--lp-grad); color: var(--lp-accent-fg); font-weight: 700; }
.lp-opt.is-on::before {
  content: '';
  display: inline-block;
  inline-size: 6px;
  block-size: 6px;
  margin-inline-end: 6px;
  border-radius: 50%;
  background: currentColor;
  vertical-align: middle;
}

/* How-it-works figure (the relay): one panel, capped so it stays a figure and
   not a hero. */
.lp-split-aside .lp-fig { inline-size: min(100%, 440px); margin-inline: auto; }

/* =========================================================================
   Pricing
   ========================================================================= */
/* Two plans, not three. Boost is not something you buy — it is what a Nitro
   account is given to spend — so it is not drawn as a plan at all. */
.lp-plans {
  display: grid;
  gap: var(--lp-sp-24);
  grid-template-columns: 1fr;
  max-inline-size: 780px;
  margin-inline: auto;
  margin-block-end: var(--lp-sp-48);
}
@media (min-width: 760px) { .lp-plans { grid-template-columns: repeat(2, 1fr); align-items: stretch; } }
.lp-plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--lp-sp-32) var(--lp-sp-24);
  border-radius: 18px;
  border: 1px solid var(--lp-edge);
  background: var(--d-side);
}
.lp-plan--hero {
  border-color: transparent;
  background:
    linear-gradient(var(--d-side), var(--d-side)) padding-box,
    var(--lp-grad) border-box;
  border: 1px solid transparent;
  box-shadow: 0 20px 60px color-mix(in srgb, var(--lp-accent) 18%, transparent);
}
.lp-plan-tag {
  position: absolute;
  inset-block-start: -11px;
  inset-inline-start: var(--lp-sp-24);
  padding: 3px 12px;
  border-radius: 999px;
  background: var(--lp-grad);
  color: var(--d-rail);
  font-size: 12px;
  font-weight: 700;
}
.lp-plan h3 { margin: 0 0 var(--lp-sp-8); font-size: var(--lp-fs-heading); font-weight: 700; }
.lp-price { margin: 0 0 4px; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.lp-price-n { font-size: clamp(2rem, 5vw, 2.75rem); font-weight: 700; line-height: 1; }
.lp-price-u { color: var(--d-dim); font-size: var(--lp-fs-label); }
.lp-plan-note { margin: 0 0 var(--lp-sp-24); color: var(--d-dim); font-size: var(--lp-fs-label); }
.lp-plan-list { list-style: none; margin: 0 0 var(--lp-sp-24); padding: 0; display: grid; gap: 10px; flex: 1; }
.lp-plan-list li {
  position: relative;
  padding-inline-start: 26px;
  color: var(--d-dim);
  font-size: 15px;
  line-height: 1.7;
}
.lp-plan-list li::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .5em;
  inline-size: 10px;
  block-size: 6px;
  border-inline-start: 2px solid var(--d-green);
  border-block-end: 2px solid var(--d-green);
  transform: rotate(-45deg);
}
.lp-plan-list b { color: var(--d-text); font-weight: 700; }
.lp-plan-list--gain li::before { border-color: var(--lp-accent-text); }
.lp-plan .lp-cta { inline-size: 100%; }

/* =========================================================================
   Steps — three figure-led cards on one track. Each card: its figure, a badge
   whose ring fills a little further than the last (the page's one recurring
   motif, --fill set inline), then the step's title and line. The dashed track
   runs through the three badges along the inline axis from 900px, and the
   cards are linked by a short vertical dash below that. Everything is
   logical, so it mirrors in LTR for free.
   ========================================================================= */
.lp-steps-sec { text-align: center; }
.lp-steps-sec .lp-h2,
.lp-steps-sec .lp-sub { margin-inline: auto; }
.lp-steps-sec .lp-eyebrow { justify-content: center; }

.lp-steps {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  display: grid;
  gap: var(--lp-sp-32);
  position: relative;
  text-align: center;
  max-inline-size: 460px;
}
@media (min-width: 900px) {
  .lp-steps { grid-template-columns: repeat(3, 1fr); gap: var(--lp-sp-24); max-inline-size: none; }
}

.lp-step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--lp-sp-16);
  padding: var(--lp-sp-16) var(--lp-sp-16) var(--lp-sp-24);
  border-radius: 18px;
  border: 1px solid var(--lp-edge);
  background: var(--lp-glass);
  transition: border-color .2s, background-color .2s, transform .2s;
}
.lp-step:hover { border-color: var(--lp-edge-hi); background: var(--d-side); transform: translateY(-3px); }

/* Below 900px: a short dashed link in the gap above every card but the first. */
.lp-step + .lp-step::before {
  content: '';
  position: absolute;
  inset-block-start: calc(var(--lp-sp-32) * -1);
  inset-inline-start: 50%;
  block-size: var(--lp-sp-32);
  border-inline-start: 2px dashed var(--lp-edge-hi);
}
@media (min-width: 900px) { .lp-step + .lp-step::before { display: none; } }

.lp-step-head { position: relative; display: flex; align-items: center; justify-content: center; }
/* The track: it overruns the card by half the grid gap on both sides so
   neighbours meet in the middle of the gap, and stops at the badge on the two
   outer cards. */
@media (min-width: 900px) {
  .lp-step-head::before {
    content: '';
    position: absolute;
    inset-block-start: 50%;
    inset-inline: calc((var(--lp-sp-16) + var(--lp-sp-8) + 5px) * -1);
    border-block-start: 2px dashed var(--lp-edge-hi);
  }
  .lp-step:first-child .lp-step-head::before { inset-inline-start: 50%; }
  .lp-step:last-child .lp-step-head::before { inset-inline-end: 50%; }
}
.lp-step-n {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 50%;
  background: var(--d-main);
}
.lp-step-n svg { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; transform: rotate(-90deg); }
.lp-step-n circle { fill: none; stroke-width: 2.5; }
.lp-step-bg { stroke: var(--lp-edge-hi); }
.lp-step-fg {
  stroke: var(--lp-accent-text);
  stroke-linecap: round;
  stroke-dasharray: 119.4;                       /* 2πr, r = 19 */
  stroke-dashoffset: calc(119.4 * (1 - var(--fill)));
}
.is-in .lp-step-fg { animation: lp-step-fill .9s var(--lp-ease) calc(var(--i) * 130ms + 200ms) backwards; }
@keyframes lp-step-fill { from { stroke-dashoffset: 119.4; } }
.lp-step-n b { font-size: var(--lp-fs-label); font-weight: 700; color: var(--d-text); }

.lp-steps h3 { margin: 0; font-size: var(--lp-fs-heading); font-weight: 700; }
.lp-steps p { margin: 0; color: var(--d-dim); line-height: 1.85; }
.lp-steps-cta { margin-block-start: var(--lp-sp-48); }

/* =========================================================================
   FAQ — <details> keeps working with JS off, which the requirements demand.
   The open/close height animates via grid-template-rows, not max-height.
   ========================================================================= */
/* Centred: the heading, the sub and the accordion column all sit on the page's
   midline. The questions themselves stay start-aligned — centred body text in
   a stack of accordions is unreadable. */
.lp-faq { text-align: center; }
.lp-faq .lp-eyebrow { justify-content: center; }
.lp-faq .lp-h2,
.lp-faq .lp-sub { margin-inline: auto; }
.lp-faq-list { display: grid; gap: 10px; max-inline-size: 800px; margin-inline: auto; text-align: start; }
.lp-faq details {
  border-radius: 14px;
  border: 1px solid var(--lp-edge);
  background: var(--d-side);
  overflow: hidden;
}
.lp-faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lp-sp-16);
  padding: var(--lp-sp-16) var(--lp-sp-24);
  min-block-size: 44px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.lp-faq summary::-webkit-details-marker { display: none; }
.lp-faq summary::after {
  content: '+';
  flex: none;
  color: var(--lp-accent-text);
  font-size: 20px;
  font-weight: 700;
  transition: transform .2s;
}
.lp-faq details[open] summary::after { content: '−'; }
.lp-faq summary:focus-visible { outline: 2px solid var(--lp-accent-text); outline-offset: -3px; }
.lp-faq details > div {
  display: grid;
  grid-template-rows: 1fr;
  padding-inline: var(--lp-sp-24);
  padding-block-end: var(--lp-sp-16);
}
.lp-faq details p { margin: 0; color: var(--d-dim); line-height: 1.9; min-block-size: 0; }

/* =========================================================================
   Closing + footer
   ========================================================================= */
.lp-closing {
  position: relative;
  isolation: isolate;
  text-align: center;
  padding-block: var(--lp-section);
  padding-inline: var(--lp-sp-24);
  overflow: hidden;
  /* A soft seam instead of a hard rule: the divider fades out at both ends. */
  background:
    linear-gradient(90deg, transparent, var(--lp-edge), transparent) top / 100% 1px no-repeat,
    radial-gradient(60% 60% at 50% 50%, color-mix(in srgb, var(--lp-accent) 7%, transparent), transparent 70%);
}
.lp-closing > *:not(.lp-aurora) { position: relative; z-index: 1; }
.lp-closing-mark {
  display: block;
  inline-size: 96px;
  block-size: auto;
  aspect-ratio: 340 / 374;
  margin: 0 auto var(--lp-sp-24);
  filter: drop-shadow(0 10px 30px color-mix(in srgb, var(--lp-accent) 40%, transparent));
}
.lp-closing .lp-h2 { margin-inline: auto; max-inline-size: 18ch; }
.lp-closing .lp-sub { margin-inline: auto; margin-block-end: var(--lp-sp-32); }

.lp-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--lp-sp-24);
  padding: var(--lp-sp-32) clamp(20px, 5vw, 48px);
  /* Fades up out of the page rather than starting at a hard rule. */
  background:
    linear-gradient(90deg, transparent, var(--lp-edge), transparent) top / 100% 1px no-repeat,
    linear-gradient(180deg, var(--d-main), var(--d-rail) 60%);
}
.lp-foot-brand { display: inline-flex; align-items: center; gap: var(--lp-sp-8); font-weight: 700; }
.lp-foot-links { display: flex; flex-wrap: wrap; gap: var(--lp-sp-16); }
.lp-foot-links a { color: var(--d-dim); font-size: var(--lp-fs-label); text-decoration: none; }
.lp-foot-links a:hover { color: var(--d-text); }
.lp-foot-note { margin: 0; color: var(--d-dim); font-size: var(--lp-fs-label); }

/* =========================================================================
   /changelog — its own sub-page, sharing this shell and these tokens so it
   can never drift from the landing page's look. A release history is a
   sequence, so it is drawn as one: a spine with a node per version, newest
   first, exactly the pattern the "why Circly" section uses.

   (These rules were lost in the redesign's first pass, which left the page
   unstyled — the guard suite checks changelog.html's structure and copy but
   has no way to notice missing CSS.)
   ========================================================================= */
.cl-head {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  text-align: center;
  padding-block: clamp(64px, 12vh, 128px) var(--lp-sp-48);
  padding-inline: clamp(20px, 5vw, 48px);
}
.cl-head > *:not(.lp-aurora) { position: relative; z-index: 1; }
.cl-head .lp-eyebrow { justify-content: center; }
.cl-title {
  font-size: clamp(2rem, 5vw, 3.25rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.015em;
  margin-block: 0 var(--lp-sp-16);
}
.cl-head .lp-sub { margin-inline: auto; margin-block-end: 0; }

.cl-main { padding-block-end: var(--lp-sp-64); }
.cl-list {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--lp-sp-24);
  max-inline-size: 860px;
  margin-inline: auto;
  padding-block: 0 var(--lp-sp-32);
  padding-inline: clamp(20px, 5vw, 48px);
}
@media (min-width: 760px) {
  .cl-list { padding-inline-start: 96px; }
  .cl-list::before {
    content: '';
    position: absolute;
    inset-block: 30px 60px;
    inset-inline-start: 47px;
    inline-size: 2px;
    background: linear-gradient(180deg, var(--lp-accent-text), var(--lp-edge-hi) 30%, transparent);
  }
}

.cl-entry {
  position: relative;
  background: var(--d-side);
  border: 1px solid var(--lp-edge);
  border-radius: 18px;
  padding: var(--lp-sp-24);
  transition: border-color .2s;
}
.cl-entry:hover { border-color: var(--lp-edge-hi); }
/* The node on the spine. */
@media (min-width: 760px) {
  .cl-entry::before {
    content: '';
    position: absolute;
    inset-block-start: 26px;
    inset-inline-start: -56px;
    inline-size: 18px;
    block-size: 18px;
    border-radius: 50%;
    border: 2px solid var(--lp-edge-hi);
    background: var(--d-main);
  }
  .cl-entry--latest::before { border-color: var(--lp-accent-text); box-shadow: 0 0 0 5px color-mix(in srgb, var(--lp-accent) 12%, transparent); }
}
/* Newest release gets the gradient edge, the same emphasis the Nitro plan and
   the top boost rank use. */
.cl-entry--latest {
  border-color: transparent;
  background:
    linear-gradient(var(--d-side), var(--d-side)) padding-box,
    var(--lp-grad) border-box;
  border: 1px solid transparent;
}

.cl-entry-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--lp-sp-8) var(--lp-sp-16);
  margin-block-end: var(--lp-sp-16);
  padding-block-end: var(--lp-sp-16);
  border-block-end: 1px solid var(--lp-edge);
}
.cl-version {
  margin: 0;
  font-size: var(--lp-fs-heading);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cl-date { color: var(--d-dim); font-size: var(--lp-fs-label); }
.cl-flag {
  padding: 3px 12px;
  border-radius: 999px;
  background: var(--lp-grad);
  color: var(--d-rail);
  font-size: 11.5px;
  font-weight: 700;
}
.cl-product {
  margin-inline-start: auto;
  padding: 2px 12px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--lp-accent) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--lp-accent) 28%, transparent);
  /* Sky as text on this ground is 8.93:1. */
  color: var(--lp-accent-text);
  font-size: var(--lp-fs-label);
  font-weight: 700;
}

.cl-group + .cl-group { margin-block-start: var(--lp-sp-24); }
.cl-group-h {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 var(--lp-sp-8);
  font-size: var(--lp-fs-label);
  font-weight: 700;
  color: var(--d-text);
}
/* Each kind gets its own dot colour, and its own bullet colour below, so the
   three groups are separable at a glance rather than by reading. Never colour
   alone: the group heading names the kind in words. */
.cl-group-h::before {
  content: '';
  inline-size: 9px;
  block-size: 9px;
  border-radius: 50%;
  background: var(--cl-kind, var(--d-dim));
}
.cl-group[data-kind="added"] { --cl-kind: var(--d-green); }
.cl-group[data-kind="fixed"] { --cl-kind: var(--d-amber); }
.cl-group[data-kind="changed"] { --cl-kind: var(--d-cyan); }

.cl-lines { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
.cl-lines li {
  position: relative;
  padding-inline-start: 20px;
  color: var(--d-dim);
  line-height: 1.85;
}
.cl-lines li::before {
  content: '';
  position: absolute;
  inset-inline-start: 4px;
  inset-block-start: .72em;
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: var(--cl-kind, var(--d-faint));
  opacity: .75;
}

.cl-back { display: flex; justify-content: center; padding-block-start: var(--lp-sp-32); }

/* Below-the-fold sections are skipped at first paint. contain-intrinsic-size
   keeps the scrollbar honest so this never causes a jump. */
.lp-section, .lp-closing {
  content-visibility: auto;
  contain-intrinsic-size: auto 600px;
}

/* =========================================================================
   Reduced motion. tokens.css already clamps every duration globally; this
   block adds INTENT on top — the aurora becomes a static gradient, reveals
   render visible rather than "instantly animated", and the sync demo shows
   its resolved state. Nothing is lost except movement.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .lp-card,
  .lp-reason,
  .lp-reason-card,
  .lp-reason-node,
  .lp-step,
  .lp-plan,
  .lp-topbar,
  .lp-cta,
  .lp-cta--ghost { transition: none; }

  .lp-rise,
  .is-in.lp-rise,
  .is-in .lp-rise { opacity: 1; transform: none; transition: none; }

  .lp-tagline .lp-word { opacity: 1; transform: none; animation: none; }

  .lp-aurora i,
  .lp-orbit,
  .lp-prog-fg { animation: none; }

  .lp-shot { animation: none; transform: none; }

  .is-in .lp-key-row,
  .is-in .lp-step-fg { animation: none; }
  .lp-reason:hover .lp-reason-card,
  .lp-step:hover { transform: none; }

  /* One settled mid-film frame, identical on all three screens: the argument
     survives, the movement does not. Beat 3 only. */
  .lp-sync { animation: none; --t: .6; }
  .lp-sync-cap[data-beat="1"],
  .lp-sync-cap[data-beat="2"] { display: none; }
  .lp-sync-cap[data-beat="3"] { opacity: 1; }
  .lp-cta:hover, .lp-card:hover, .lp-reason:hover { transform: none; }
}
