/* =========================================================================
   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 palette additions below are landing-only and exist for one reason:
   --d-accent #7c5cff is a fine FILL but only 4.32:1 as text on --d-main, and
   #fff on a #7c5cff fill is 4.35:1 — both under the 4.5:1 floor. Nothing in
   tokens.css changes; the landing just stops using them the wrong way.
   ========================================================================= */

.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);

  /* accessible derivatives of the shared palette (see header note) */
  --lp-accent-text: var(--d-accent-text);      /* 6.95:1 on --d-main ✓ */
  --lp-cta-fill: var(--d-accent-hover);         /* 5.46:1 under #fff ✓ */
  --lp-grad: linear-gradient(135deg, var(--d-accent) 0%, var(--d-cyan) 100%);
  --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: rgba(124, 92, 255, .38);
  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: rgba(62, 201, 255, .24);
  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: rgba(255, 92, 174, .16);
  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(--d-accent);
  color: var(--d-white);
  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-topcta {
  min-block-size: 36px;
  display: inline-flex;
  align-items: center;
  padding-inline: 14px;
  border-radius: var(--lp-radius-btn);
  border: 1px solid var(--lp-edge-hi);
  color: var(--d-text);
  font-weight: 700;
  transition: background-color .15s, border-color .15s;
}
.lp-topcta:hover { background: var(--lp-cta-fill); border-color: transparent; color: var(--d-white); }

/* 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 CTA and the toggle stay. */
@media (max-width: 720px) {
  .lp-topnav a:not(.lp-topcta) { display: none; }
}

/* =========================================================================
   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;
}
.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 rgba(124, 92, 255, .42));
}
.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(--d-cyan); 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);
  /* NOT --d-accent: #fff on #7c5cff is 4.35:1 and this label is 16px bold,
     which is not "large text" (that starts at 18.66px bold). #6a49f2 is
     5.46:1 under the same label. */
  background: var(--lp-cta-fill);
  color: var(--d-white);
  font-family: inherit;
  font-weight: 700;
  font-size: var(--lp-fs-body);
  text-decoration: none;
  box-shadow: 0 6px 24px rgba(106, 73, 242, .32);
  transition: background-color .15s, transform .15s, box-shadow .15s;
}
.lp-cta:hover {
  background: var(--d-accent);
  transform: translateY(-2px);
  box-shadow: 0 10px 30px rgba(106, 73, 242, .42);
}
.lp-cta:focus-visible { outline: 2px solid var(--lp-accent-text); 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: 500;
  border: 1px solid var(--lp-edge-hi);
  box-shadow: none;
}
.lp-cta--ghost:hover {
  border-color: var(--lp-accent-text);
  color: var(--d-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-text); outline-offset: 3px; }
.lp-cta:active, .lp-cta--ghost:active { 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%, rgba(124, 92, 255, .3), 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→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.
   ========================================================================= */
@supports (animation-timeline: view()) {
  @property --t { syntax: '<number>'; inherits: true; initial-value: 0; }
  .lp-sync {
    animation: lp-scrub linear both;
    animation-timeline: view();
    animation-range: contain 0% contain 100%;
  }
}
@keyframes lp-scrub { from { --t: 0; } to { --t: 1; } }

/* The well used to be a flat --d-rail block between two hard 1px rules, which
   read as a seam rather than a change of depth. It now 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: 260vh;
  padding-inline: clamp(20px, 5vw, 48px);
  background:
    radial-gradient(70% 40% at 50% 22%, rgba(124, 92, 255, .12), 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;
  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: 900px;
  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. */
.lp-players {
  direction: ltr;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(10px, 2vw, 20px);
  inline-size: min(560px, 100%);
  margin-block: var(--lp-sp-32);
}
.lp-pl {
  padding: 12px;
  border-radius: 12px;
  border: 1px solid var(--lp-edge);
  background: var(--lp-glass);
  /* How far out of phase this player starts. Decays to 0 at the seek. */
  --k: 0;
  transition: border-color .3s;
}
.lp-pl:nth-child(1) { --k: -9; }
.lp-pl:nth-child(2) { --k: 0; }
.lp-pl:nth-child(3) { --k: 11; }
.lp-pl-scr {
  display: block;
  block-size: 52px;
  border-radius: 6px;
  margin-block-end: 12px;
  background: linear-gradient(135deg, var(--d-hover), var(--d-active));
}
.lp-pl-track {
  position: relative;
  display: block;
  block-size: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .12);
}
.lp-pl-head {
  position: absolute;
  inset-block-start: -4px;
  inline-size: 12px;
  block-size: 12px;
  border-radius: 50%;
  background: var(--lp-accent-text);
  box-shadow: 0 0 14px rgba(124, 92, 255, .8);
  /* --spread collapses to 0 across the seek beat, which is the whole point:
     three drifting playheads become one. */
  --spread: calc(1 - clamp(0, (var(--t) - .34) / .18, 1));
  inset-inline-start: calc(3% + 86% * var(--t) + var(--spread) * var(--k) * 1%);
}
/* Locked: once the seek has happened the three agree, and they say so. */
.lp-sync .lp-pl { border-color: color-mix(in srgb, var(--d-green) calc(var(--t) * 55%), var(--lp-edge)); }

/* The three beats sit DIRECTLY under the players in a reserved box. They used
   to be pinned to the bottom of the viewport, far from the thing they describe,
   where they were read late or not at all. The box keeps its height whichever
   caption is showing, so nothing reflows as they cross-fade. */
.lp-sync-caps {
  position: relative;
  display: grid;
  place-items: center;
  min-block-size: 4.2em;
  inline-size: min(560px, 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) - .2) / .1, 1)); }
.lp-sync-cap[data-beat="2"] { opacity: calc(clamp(0, (var(--t) - .26) / .08, 1) - clamp(0, (var(--t) - .56) / .08, 1)); }
.lp-sync-cap[data-beat="3"] { opacity: calc(clamp(0, (var(--t) - .62) / .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: rgba(124, 92, 255, .16);
  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) {
  .lp-sync-sec { min-block-size: 200vh; }
  .lp-sync-cap { font-size: var(--lp-fs-body); }
  .lp-sync-caps { min-block-size: 5em; }
}

/* =========================================================================
   Features — asymmetric bento.

   grid-template-areas does NOT mirror on its own: the strings are read
   visually, start-to-end, in both directions. Without the :dir(rtl) variant
   below the big voice tile would land on the wrong edge in Persian, which is
   the primary direction. This is the single most likely RTL bug on the page.
   ========================================================================= */
.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(4, 1fr);
    grid-template-areas:
      'voice voice chat share'
      'friends admin chat share';
  }
  :dir(rtl) .lp-bento {
    grid-template-areas:
      'share chat voice voice'
      'share chat admin friends';
  }
  .lp-card--voice { grid-area: voice; }
  .lp-card--share { grid-area: share; }
  .lp-bento > li:nth-child(3) { grid-area: chat; }
  .lp-bento > li:nth-child(4) { grid-area: friends; }
  .lp-bento > li:nth-child(5) { grid-area: admin; }
}

.lp-card {
  position: relative;
  overflow: hidden;
  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, rgba(124, 92, 255, .16), transparent 68%);
  pointer-events: none;
}

/* Faded line art, one motif per card. Drawn rather than photographed: it costs
   nothing, scales to any size, and takes its colour from the theme. It sits
   UNDER the copy at low opacity and lifts slightly on hover, so the card has
   something to look at without competing with the words. */
.lp-card-art {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: -18px;
  inline-size: 190px;
  block-size: 190px;
  translate: 0 -50%;
  fill: none;
  stroke: var(--lp-accent-text);
  stroke-width: 3.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .1;
  pointer-events: none;
  transition: opacity .3s, scale .3s;
}
.lp-card:hover .lp-card-art { opacity: .17; scale: 1.05; }
/* The two wide tiles have room for a bigger, better-placed motif. */
.lp-card--voice .lp-card-art,
.lp-card--share .lp-card-art { inline-size: 250px; block-size: 250px; inset-inline-end: -34px; }
.lp-card--share .lp-card-art { inset-block-start: 62%; }
.lp-card:hover {
  border-color: var(--lp-edge-hi);
  background: var(--d-hover);
  transform: translateY(-3px);
}
.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; }
.lp-ic {
  display: inline-grid;
  place-items: center;
  inline-size: 42px;
  block-size: 42px;
  border-radius: 12px;
  margin-block-end: var(--lp-sp-16);
  background: rgba(124, 92, 255, .14);
  color: var(--lp-accent-text);
  border: 1px solid rgba(124, 92, 255, .24);
}
.lp-ic svg { inline-size: 22px; block-size: 22px; }

/* CSS-only "live" waveform on the voice tile. 24 spans, zero bytes. */
.lp-wave {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  block-size: 34px;
  margin-block-start: var(--lp-sp-24);
}
.lp-wave i {
  display: block;
  inline-size: 3px;
  block-size: 30%;
  border-radius: 2px;
  background: var(--lp-accent-text);
  opacity: .5;
  animation: lp-wave 1.2s ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * 40ms);
}
@keyframes lp-wave { to { block-size: 100%; opacity: 1; } }

/* =========================================================================
   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 rgba(124, 92, 255, .1);
}

.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: 120px 1fr; gap: var(--lp-sp-24); }
  /* Alternate which edge the art 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 120px; }
  .lp-reason:nth-child(even) .lp-reason-art { order: 2; }
}
.lp-reason:hover .lp-reason-card {
  border-color: var(--lp-edge-hi);
  background: var(--d-side);
  transform: translateY(-2px);
}

.lp-reason-art {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 14px;
  background:
    radial-gradient(70% 70% at 50% 30%, rgba(124, 92, 255, .16), transparent 70%),
    var(--d-rail);
  border: 1px solid var(--lp-edge);
}
.lp-reason-art svg { inline-size: 78%; block-size: 78%; fill: none; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.lp-reason-art .s1 { stroke: var(--lp-accent-text); }
.lp-reason-art .s2 { stroke: var(--d-cyan); }
.lp-reason-art .fill2 { fill: var(--d-cyan); stroke: none; }
.lp-reason-art .dash { stroke-dasharray: 7 9; opacity: .5; }

.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; }
}

/* How-it-works diagram */
.lp-diagram { inline-size: 100%; block-size: auto; max-inline-size: 420px; margin-inline: auto; display: block; }
.lp-dg-box { fill: var(--d-side); stroke: var(--lp-edge-hi); stroke-width: 1.5; }
.lp-dg-node { fill: var(--d-hover); stroke: var(--lp-edge-hi); stroke-width: 1.5; }
.lp-dg-node--src { fill: rgba(124, 92, 255, .18); stroke: var(--lp-accent-text); }
.lp-dg-cmd { fill: none; stroke: var(--d-faint); stroke-width: 1.5; stroke-dasharray: 4 4; }
.lp-dg-media { fill: none; stroke: var(--lp-accent-text); stroke-width: 2; stroke-dasharray: 260; stroke-dashoffset: 260; }
.is-in .lp-dg-media { animation: lp-draw .9s var(--lp-ease) .15s forwards; }
@keyframes lp-draw { to { stroke-dashoffset: 0; } }

/* =========================================================================
   Pricing
   ========================================================================= */
/* Two plans, not three. Boost is not something you buy — it is what a Nitro
   account is given to spend — so it lives with the ladder instead. */
.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 rgba(124, 92, 255, .18);
}
.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%; }

/* =========================================================================
   Boost ladder, as a progression rather than a table. Three ranks; each badge
   ring fills further than the last, each rank lists the rewards it unlocks,
   and the top one is flagged. The ring ties it to the page's circle motif and
   reads as a level-up track without inventing any number: every figure comes
   from plan.js.
   ========================================================================= */
.lp-ladder {
  padding: var(--lp-sp-32) var(--lp-sp-24);
  border-radius: 20px;
  border: 1px solid var(--lp-edge);
  background:
    radial-gradient(90% 120% at 50% 0%, rgba(124, 92, 255, .1), transparent 70%),
    var(--lp-glass);
}
.lp-ladder-head { text-align: center; margin-block-end: var(--lp-sp-32); }
.lp-ladder-t { margin: 0 0 6px; font-size: var(--lp-fs-heading); font-weight: 700; }
.lp-ladder-sub { margin: 0; color: var(--d-dim); font-size: var(--lp-fs-label); }

.lp-rungs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--lp-sp-16);
  grid-template-columns: 1fr;
  position: relative;
}
@media (min-width: 760px) {
  .lp-rungs { grid-template-columns: repeat(3, 1fr); gap: var(--lp-sp-24); }
  /* The track the three ranks sit on. */
  .lp-rungs::before {
    content: '';
    position: absolute;
    inset-block-start: 46px;
    inset-inline: 16%;
    block-size: 2px;
    background: linear-gradient(90deg, var(--lp-edge-hi), var(--lp-accent-text));
    opacity: .45;
  }
}

.lp-rung {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 6px;
  padding: var(--lp-sp-24) var(--lp-sp-16) var(--lp-sp-16);
  border-radius: 16px;
  background: var(--d-side);
  border: 1px solid var(--lp-edge);
  transition: border-color .25s, transform .25s;
}
.lp-rung:hover { border-color: var(--lp-edge-hi); transform: translateY(-3px); }
.is-in .lp-rung { animation: lp-rung-in .55s var(--lp-ease) calc(var(--i) * 130ms) both; }
@keyframes lp-rung-in { from { opacity: 0; transform: translateY(14px) scale(.97); } to { opacity: 1; transform: none; } }

/* Rank badge: a ring that fills further at each level. */
.lp-rung-badge {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 64px;
  block-size: 64px;
  margin-block-end: 6px;
}
.lp-rung-badge svg { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; transform: rotate(-90deg); }
.lp-rung-badge circle { fill: none; stroke-width: 4; }
.lp-rb-bg { stroke: rgba(255, 255, 255, .08); }
.lp-rb-fg {
  stroke: var(--lp-accent-text);
  stroke-linecap: round;
  stroke-dasharray: 169.6;                    /* 2πr, r = 27 */
  stroke-dashoffset: 169.6;
}
.is-in .lp-rb-fg { animation: lp-rb-fill .9s var(--lp-ease) calc(var(--i) * 130ms + 200ms) forwards; }
@keyframes lp-rb-fill { to { stroke-dashoffset: calc(169.6 * (1 - var(--fill))); } }
.lp-rung-badge b {
  font-size: 22px;
  font-weight: 700;
  color: var(--d-text);
}

.lp-rung-lv { font-weight: 700; font-size: var(--lp-fs-label); color: var(--d-text); }
.lp-rung-cost {
  padding: 3px 12px;
  border-radius: 999px;
  background: rgba(124, 92, 255, .14);
  border: 1px solid rgba(124, 92, 255, .28);
  color: var(--lp-accent-text);
  font-size: 13px;
  font-weight: 700;
}
.lp-rewards {
  list-style: none;
  margin: var(--lp-sp-8) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
}
.lp-rewards li {
  padding: 4px 10px;
  border-radius: 8px;
  background: var(--d-hover);
  border: 1px solid var(--lp-edge);
  color: var(--d-dim);
  font-size: 12.5px;
  white-space: nowrap;
}

/* Top rank: brighter ring, a gradient edge and a flag. */
.lp-rung--max {
  border-color: transparent;
  background:
    linear-gradient(var(--d-side), var(--d-side)) padding-box,
    var(--lp-grad) border-box;
  box-shadow: 0 14px 44px rgba(124, 92, 255, .16);
}
.lp-rung--max .lp-rb-fg { stroke: var(--d-cyan); }
.lp-rung--max .lp-rewards li { border-color: rgba(62, 201, 255, .3); color: var(--d-text); }
.lp-rung-flag {
  position: absolute;
  inset-block-start: -11px;
  padding: 3px 12px;
  border-radius: 999px;
  background: var(--lp-grad);
  color: var(--d-rail);
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
}

/* =========================================================================
   Steps
   ========================================================================= */
/* Three cards on one dashed track, each with its own icon and a numbered
   marker riding the track. It was three bare paragraphs before, which made the
   easiest part of the product look like the dullest. */
.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;
  padding: 0;
  display: grid;
  gap: var(--lp-sp-32);
  position: relative;
  text-align: center;
}
@media (min-width: 760px) {
  .lp-steps { grid-template-columns: repeat(3, 1fr); gap: var(--lp-sp-24); }
  /* The track, behind the numbered markers. */
  .lp-steps::before {
    content: '';
    position: absolute;
    inset-block-start: 21px;
    inset-inline: 18%;
    block-size: 2px;
    background-image: linear-gradient(90deg, var(--lp-edge-hi) 55%, transparent 0);
    background-size: 12px 2px;
    background-repeat: repeat-x;
  }
}

.lp-step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--lp-sp-24);
  padding-block-start: 46px;
  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); }

.lp-step-n {
  position: absolute;
  inset-block-start: -21px;
  display: inline-grid;
  place-items: center;
  inline-size: 42px;
  block-size: 42px;
  border-radius: 50%;
  border: 1px solid rgba(124, 92, 255, .4);
  background: var(--d-main);
  color: var(--lp-accent-text);
  font-weight: 700;
}
.lp-step-ic {
  display: inline-grid;
  place-items: center;
  inline-size: 54px;
  block-size: 54px;
  margin-block-end: var(--lp-sp-16);
  border-radius: 16px;
  background: rgba(124, 92, 255, .12);
  border: 1px solid rgba(124, 92, 255, .22);
  color: var(--lp-accent-text);
}
.lp-step-ic svg { inline-size: 26px; block-size: 26px; }
.lp-steps h3 { margin: 0 0 var(--lp-sp-8); 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%, rgba(124, 92, 255, .07), 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 rgba(124, 92, 255, .4));
}
.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 rgba(124, 92, 255, .12); }
}
/* 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: rgba(124, 92, 255, .16);
  border: 1px solid rgba(124, 92, 255, .28);
  /* --d-accent as text is 4.32:1; the lightened token is 6.95: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-card-art,
  .lp-reason,
  .lp-reason-card,
  .lp-reason-node,
  .lp-rung,
  .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-wave i,
  .lp-prog-fg { animation: none; }
  .lp-wave i { block-size: 60%; opacity: .7; }

  .lp-shot { animation: none; transform: none; }

  .is-in .lp-key-row,
  .is-in .lp-rung { animation: none; }
  .is-in .lp-dg-media { animation: none; stroke-dashoffset: 0; }
  /* The rank rings still show their level — they just arrive already filled. */
  .is-in .lp-rb-fg { animation: none; stroke-dashoffset: calc(169.6 * (1 - var(--fill))); }
  .lp-card:hover .lp-card-art { scale: 1; }
  .lp-reason:hover .lp-reason-card,
  .lp-rung:hover,
  .lp-step:hover { transform: none; }

  /* Beat 3 only, static: the argument survives, the movement does not. */
  .lp-sync { animation: none; --t: 1; }
  .lp-sync-cap[data-beat="1"],
  .lp-sync-cap[data-beat="2"] { display: none; }
  .lp-sync-cap[data-beat="3"] { opacity: 1; }
  .lp-pl-head { --spread: 0; }
  .lp-cta:hover, .lp-card:hover, .lp-reason:hover { transform: none; }
}
