/* ==========================================================================
   AscendSAT — landing page + sign-in

   Its own world, scoped under .lp so none of it leaks into the product.

   THE IDEA
   Paper and light. The ground is white; behind the top of the page sits one
   very large, very soft bloom of colour that reads as light falling on
   paper rather than as a coloured block. Everything solid is white with a
   hairline edge and a long, low shadow. Brand blue appears only on things
   you are meant to press or read as "this one"; gold marks a single item
   per block. There is no saturated field anywhere, because a flat panel of
   brand colour is the fastest way to make a page look like a template.

   Scale does the rest. A page reads as expensive when it is confident about
   size and quiet about everything else, so: one enormous headline, one
   enormous product shot, full-width feature blocks instead of a grid of
   small cards, and a shadow scale where nothing floats at a height it did
   not earn.

   TYPE
   Inter Tight for display — neutral, authoritative, and it holds -0.045em
   tracking at 100px without falling apart. Space Grotesk for numerals only,
   where its tabular figures stop scores jittering as they count. One serif
   italic, reserved for the emphasised phrase in every heading and used
   nowhere else.
   ========================================================================== */

.lp {
  /* Paper */
  --paper:  #FFFFFF;
  --wash:   #F7F8FB;   /* section tint, barely there */
  --well:   #EEF1F7;   /* tracks, chips, insets */

  /* Light */
  --blue:      #2F6BFF;
  --blue-dk:   #1B47CC;
  --blue-hi:   #86A9FF;
  --blue-tint: #EDF2FF;
  --gold:      #A0740A;   /* text-safe amber — #F5B921 is unreadable on white */
  --gold-br:   #F5B921;   /* fills, dots, marks */
  --gold-tint: #FFF8E8;
  --green:     #0E9F6E;
  --green-tint:#E6F7F0;
  --red:       #D94A4A;
  --red-tint:  #FDEDED;

  /* Ink */
  --ink:   #08090C;
  --ink-2: #52596B;
  --ink-3: #878E9E;

  --line:   rgba(8, 9, 12, .08);
  --line-2: rgba(8, 9, 12, .15);

  /* One shadow scale. Long and low, never dark — on paper a heavy shadow
     reads as a sticker, not as depth. */
  --sh-1: 0 1px 2px rgba(8, 9, 12, .04);
  --sh-2: 0 1px 2px rgba(8, 9, 12, .04), 0 8px 18px -10px rgba(8, 9, 12, .14);
  --sh-3: 0 1px 3px rgba(8, 9, 12, .05), 0 18px 40px -18px rgba(8, 9, 12, .18);
  --sh-4: 0 2px 6px rgba(8, 9, 12, .05), 0 30px 60px -24px rgba(8, 9, 12, .2),
          0 80px 120px -60px rgba(8, 9, 12, .26);

  --f-display: "Inter Tight", Inter, -apple-system, sans-serif;
  --f-num:     "Space Grotesk", "Inter Tight", sans-serif;
  --f-serif:   "Instrument Serif", "Times New Roman", Georgia, serif;
  --f-ui:      Inter, -apple-system, sans-serif;

  --wrap: 1200px;
  --pad: clamp(20px, 4vw, 48px);
  --ease: cubic-bezier(.16, 1, .3, 1);
  --spring: cubic-bezier(.22, 1.4, .36, 1);

  position: relative;
  isolation: isolate;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-ui);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

body.landing { background: #FFFFFF; }
body.landing .sidebar,
body.landing .topbar { display: none; }
body.landing .main { margin-left: 0 !important; }
body.landing .outlet > .view { padding: 0; max-width: none; animation: none; }

.lp h1, .lp h2, .lp h3, .lp h4 {
  font-family: var(--f-display);
  font-weight: 700;
  letter-spacing: -.035em;
  color: var(--ink);
  margin: 0;
}

/* The one reserved gesture: the emphasised phrase in a heading is always
   serif italic, always ink. It carries emphasis by contrast of *form*, not
   by colour — a coloured phrase in every heading is a gradient effect with
   extra steps. */
.lp em {
  font-family: var(--f-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -.01em;
  /* Optical size: the serif runs small next to a 700-weight grotesque. */
  font-size: 1.08em;
}

.lp ::selection { background: rgba(47, 107, 255, .18); }
.lp :focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 8px; }

/* ==========================================================================
   Backdrop
   ========================================================================== */
/* Inset negative so the whole layer can drift with the cursor without ever
   pulling an edge into view. --mx/--my are the eased pointer position the
   pointer loop writes, in -0.5 … 0.5. */
.lp-bg {
  position: fixed; inset: -90px; z-index: -1;
  pointer-events: none; overflow: hidden;
  background: var(--paper);
  transform: translate3d(calc(var(--mx, 0) * 26px), calc(var(--my, 0) * 20px), 0);
}
/* Two blooms, both enormous and both nearly transparent. They read as light
   on the paper; anything more saturated reads as a coloured rectangle. */
.lp-bloom { position: absolute; border-radius: 50%; will-change: transform; }
.lp-bloom.cool {
  width: 120vw; height: 90vw; max-width: 1700px; max-height: 1200px;
  top: -46vw; left: 50%; margin-left: -60vw;
  background: radial-gradient(closest-side, rgba(47, 107, 255, .18), rgba(47, 107, 255, .05) 52%, transparent 76%);
  animation: lpBloomA 26s ease-in-out infinite;
}
.lp-bloom.warm {
  width: 80vw; height: 70vw; max-width: 1100px; max-height: 900px;
  top: -18vw; right: -22vw;
  background: radial-gradient(closest-side, rgba(245, 185, 33, .2), rgba(245, 185, 33, .05) 52%, transparent 76%);
  animation: lpBloomB 32s ease-in-out infinite;
}
@keyframes lpBloomA {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(-4vw, 2vh, 0) scale(1.08); }
}
@keyframes lpBloomB {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.04); }
  50%      { transform: translate3d(3vw, 3vh, 0) scale(.94); }
}
/* Hairline grid, masked to a soft pool so it never reaches an edge and
   turns into a visible rectangle. */
.lp-grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(8, 9, 12, .045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(8, 9, 12, .045) 1px, transparent 1px);
  background-size: 72px 72px;
  -webkit-mask-image: radial-gradient(ellipse 80% 46% at 50% 6%, #000 6%, transparent 72%);
          mask-image: radial-gradient(ellipse 80% 46% at 50% 6%, #000 6%, transparent 72%);
}

/* ==========================================================================
   Scroll rail
   ========================================================================== */
.lp-rail { position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 80; pointer-events: none; }
.lp-rail > i {
  position: relative; display: block; height: 100%;
  background: linear-gradient(90deg, var(--blue), var(--gold-br));
  transform: scaleX(var(--rs, 0)); transform-origin: 0 50%;
}
/* A head on the rail. Counter-scaled, because the bar it sits on is being
   stretched from nothing to full width and anything drawn inside it would
   otherwise be smeared across the whole page. */
.lp-rail > i::after {
  content: '';
  position: absolute; right: 0; top: -4px;
  width: 4px; height: 10px;
  border-radius: 999px;
  background: var(--gold-br);
  box-shadow: 0 0 12px 3px rgba(245, 185, 33, .7), 0 0 4px 1px rgba(245, 185, 33, .9);
  transform: scaleX(calc(1 / max(.02, var(--rs, 1))));
}

/* ==========================================================================
   Nav
   ========================================================================== */
.lp-nav {
  position: sticky; top: 0; z-index: 60;
  padding: 18px var(--pad) 0;
  transition: padding .45s var(--ease);
}
.lp-nav.stuck { padding-top: 10px; }

.lp-nav-in {
  display: flex; align-items: center; gap: 20px;
  /* Sections are `max-width: --wrap` with `--pad` of inner padding, so their
     text column is --wrap minus twice --pad. The bar matches that, not
     --wrap, or the logo hangs a full gutter left of the headline under it. */
  max-width: calc(var(--wrap) - var(--pad) * 2); margin: 0 auto;
  padding: 10px 0;
  border: 1px solid transparent; border-radius: 18px;
  transition: max-width .5s var(--ease), padding .45s var(--ease),
              background .35s ease, border-color .35s ease, box-shadow .35s ease;
}
.lp-nav.stuck .lp-nav-in {
  max-width: 940px;
  padding: 9px 9px 9px 16px;
  background: rgba(255, 255, 255, .82);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-color: var(--line);
  box-shadow: var(--sh-2);
}

.lp-logo { display: flex; align-items: center; gap: 11px; text-decoration: none; margin-right: auto; }
.lp-logo-mark {
  width: 34px; height: 34px; flex: none;
  transition: transform .45s var(--spring);
}
.lp-logo:hover .lp-logo-mark { transform: rotate(-8deg) scale(1.08); }
.lp-logo-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
.lp-logo-txt {
  font-family: var(--f-display); font-weight: 700; font-size: 19px;
  letter-spacing: -.035em; color: var(--ink);
}
.lp-logo-txt b { color: var(--blue); font-weight: 700; }

.lp-links { position: relative; display: flex; gap: 2px; }
.lp-links-ind {
  position: absolute; top: 2px; bottom: 2px; left: 0; width: 0;
  border-radius: 10px; background: var(--well);
  opacity: 0;
  transition: transform .42s var(--ease), width .42s var(--ease), opacity .3s ease;
}
.lp-link {
  position: relative; z-index: 1;
  padding: 8px 14px; border-radius: 10px;
  font-size: 14.5px; font-weight: 500; color: var(--ink-2);
  text-decoration: none;
  transition: color .22s ease;
}
.lp-link:hover, .lp-link.on { color: var(--ink); }

.lp-nav-end { display: flex; align-items: center; gap: 6px; }
.lp-textbtn {
  padding: 9px 12px; border: 0; border-radius: 10px; background: none;
  font: 500 14.5px var(--f-ui); color: var(--ink-2); cursor: pointer;
  transition: color .2s ease, background .2s ease;
}
.lp-textbtn:hover { color: var(--ink); background: var(--wash); }

.lp-burger {
  display: none;
  width: 40px; height: 40px; padding: 0;
  border: 1px solid var(--line); border-radius: 11px;
  background: #fff; cursor: pointer;
}
.lp-burger i {
  display: block; width: 16px; height: 1.5px; margin: 3.5px auto;
  background: var(--ink); border-radius: 2px;
  transition: transform .3s var(--ease);
}
.lp.menu-open .lp-burger i:first-child { transform: translateY(2.5px) rotate(45deg); }
.lp.menu-open .lp-burger i:last-child  { transform: translateY(-2.5px) rotate(-45deg); }

.lp-sheet {
  display: none;
  max-width: var(--wrap); margin: 8px auto 0;
  padding: 10px;
  border: 1px solid var(--line); border-radius: 18px;
  background: #fff;
  box-shadow: var(--sh-3);
}
.lp-sheet a {
  display: block; padding: 13px 14px; border-radius: 11px;
  color: var(--ink-2); text-decoration: none; font-size: 15.5px; font-weight: 500;
}
.lp-sheet a:hover { background: var(--wash); color: var(--ink); }
.lp-sheet .lp-btn { width: 100%; margin-top: 8px; }

/* ==========================================================================
   Buttons
   ========================================================================== */
.lp-btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px 24px;
  border: 0; border-radius: 12px;
  font: 600 15px/1 var(--f-ui);
  letter-spacing: -.012em;
  color: #fff; text-decoration: none; white-space: nowrap;
  cursor: pointer;
  overflow: hidden;
  /* Lift on hover, press on click, and a couple of pixels of lean toward the
     cursor. No rotation: turning the button to face the pointer looked
     clever and felt like the target was dodging. */
  transform: translate3d(var(--tx, 0px), calc(var(--ty, 0px) + var(--lift, 0px)), 0) scale(var(--press, 1));
  transition: transform .22s var(--ease), box-shadow .3s ease, background .25s ease;
}
.lp-btn:hover { --lift: -2px; }
.lp-btn:active { --lift: 0px; --press: .98; transition-duration: .07s; }
.lp-btn.tilting { transition: transform .14s ease-out, box-shadow .3s ease, background .25s ease; }
.lp-btn svg { width: 18px; height: 18px; transition: transform .4s var(--spring); }
/* The arrow leaves ahead of you. */
.lp-btn:hover svg:last-child { transform: translateX(4px); }

/* The label rolls over: the word you are reading leaves upward and an
   identical one arrives from below. The second copy is drawn from the data
   attribute, so there is one string and no way for the two to drift. */
.lp-btn-t {
  display: inline-grid;
  grid-template-areas: "t";
  overflow: hidden;
  /* Slack for descenders, given straight back so the button keeps its
     height and the label keeps its baseline. */
  padding: .18em 0 .22em; margin: -.18em 0 -.22em;
}
.lp-btn-t > span, .lp-btn-t::after {
  grid-area: t;
  transition: transform .48s var(--ease), opacity .3s ease;
}
.lp-btn-t::after { content: attr(data-t); transform: translateY(115%); opacity: 0; }
.lp-btn:hover .lp-btn-t > span { transform: translateY(-115%); opacity: 0; }
.lp-btn:hover .lp-btn-t::after { transform: translateY(0); opacity: 1; }
.lp-btn-lg { padding: 17px 30px; font-size: 16px; border-radius: 14px; }
.lp-btn-sm { padding: 10px 16px; font-size: 14px; border-radius: 10px; }
.lp-btn.static { pointer-events: none; }

.lp-btn-primary {
  background: var(--ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), var(--sh-2);
}
.lp-btn-primary:hover {
  background: #1B1D24;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .16), var(--sh-3),
              0 10px 34px -12px rgba(47, 107, 255, .55);
}

/* Sheen sweep — one pass on hover, not a loop. A button that shimmers
   forever is a distraction; one that answers a hover is a response. */
.lp-btn-primary::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 36%, rgba(255, 255, 255, .22) 50%, transparent 64%);
  transform: translateX(-130%);
  transition: transform .75s var(--ease);
}
.lp-btn-primary:hover::after { transform: translateX(130%); }

.lp-btn-ghost {
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--line-2);
  box-shadow: var(--sh-1);
}
.lp-btn-ghost:hover { background: var(--wash); border-color: var(--ink-3); }

/* ==========================================================================
   Hero
   ========================================================================== */
/* The hero leaves as the product arrives. --e is how far it has gone: it
   lifts a little, fades, and drifts out of focus, so the window standing up
   underneath reads as the thing being focused on rather than as the next row
   down the page. Everything is capped low — this is depth of field, not an
   exit animation. */
.lp-hero {
  max-width: 1080px; margin: 0 auto;
  padding: clamp(48px, 8vw, 104px) var(--pad) clamp(30px, 4vw, 52px);
  text-align: center;
  perspective: 1100px;
  transform: translate3d(0, calc(var(--e, 0) * -70px), 0);
  opacity: calc(1 - var(--e, 0) * .95);
  filter: blur(calc(var(--e, 0) * 5px));
  will-change: transform, opacity;
}

/* One plane, turning to face the cursor, with everything on it at its own
   depth. This is the whole reason the hero is a 3D scene: rotate the plane
   two degrees and the headline at 90px slides four times as far as the proof
   row at 20px. Five parallax layers out of one transform.

   --e also tips the plane away as it leaves, so the hero does not merely
   slide off the top — it falls back into the page while the product window
   comes up in front of it. */
/* No transition: this is written every scroll frame as well as every pointer
   frame, and an eased transform chasing the wheel makes the hero swim. */
.lp-hero-in {
  transform-style: preserve-3d;
  transform:
    rotateX(calc(var(--py, 0) * -3deg + var(--e, 0) * 12deg))
    rotateY(calc(var(--px, 0) * 4deg))
    translate3d(0, 0, calc(var(--e, 0) * -220px));
}
.lp-badge   { transform: translate3d(0, 0, 44px); }
.lp-h1      { transform: translate3d(0, 0, 92px); }
.lp-lede    { transform: translate3d(0, 0, 34px); }
.lp-cta-row { transform: translate3d(0, 0, 62px); }
.lp-proof   { transform: translate3d(0, 0, 18px); }

.lp-badge {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 7px 12px 7px 13px;
  border: 1px solid var(--line); border-radius: 999px;
  background: rgba(255, 255, 255, .8);
  backdrop-filter: blur(8px);
  box-shadow: var(--sh-1);
  font-size: 13px; font-weight: 500; color: var(--ink-2);
  text-decoration: none;
  transition: border-color .25s ease, color .25s ease, transform .25s var(--ease);
  animation: lpRise .9s var(--ease) backwards;
}
.lp-badge:hover { border-color: var(--line-2); color: var(--ink); transform: translate3d(0, -2px, 52px); }
.lp-badge svg { width: 14px; height: 14px; color: var(--ink-3); }
.lp-badge-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--green);
  box-shadow: 0 0 0 3px rgba(14, 159, 110, .16);
  animation: lpPulse 2.6s ease-in-out infinite;
}
@keyframes lpPulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(14, 159, 110, .16); }
  50%      { box-shadow: 0 0 0 8px rgba(14, 159, 110, 0); }
}

.lp-h1 {
  margin: clamp(26px, 3vw, 36px) 0 0;
  font-size: clamp(46px, 6.6vw, 96px);
  line-height: .95;
  letter-spacing: -.048em;
  font-weight: 700;
  text-wrap: balance;
  perspective: 900px;
}
/* Word by word, hinged up from below out of a blur. Each word owns a mask of
   its own so it can arrive on its own beat and still wrap wherever the line
   wants to break — one mask around the whole headline would only ever
   animate rectangles of text.

   The mask needs slack on three sides: overflow: hidden clips the serif
   italic's overhang and the descenders, so it is padded and the padding
   given straight back as negative margin. vertical-align keeps the masked
   boxes sitting on one line rather than on their own overflow baselines. */
.lp-wm {
  display: inline-block;
  overflow: hidden;
  padding: .1em .08em .16em;
  margin: -.1em -.08em -.16em;
  vertical-align: bottom;
}
.lp-w {
  display: inline-block;
  transform-origin: 50% 100%;
  opacity: 0;
  transform: translateY(96%) rotateX(-58deg);
  filter: blur(10px);
  animation: lpWordIn 1.05s var(--ease) forwards;
  animation-delay: calc(.12s + var(--i) * .075s);
}
@keyframes lpWordIn {
  60%  { filter: blur(0); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

.lp-lede {
  margin: clamp(20px, 2.4vw, 30px) auto 0; max-width: 34em;
  font-size: clamp(16px, 1.35vw, 19px); line-height: 1.58; color: var(--ink-2);
  text-wrap: pretty;
  animation: lpRise 1s var(--ease) .55s backwards;
}
.lp-cta-row {
  display: flex; gap: 12px; flex-wrap: wrap; justify-content: center;
  margin-top: clamp(26px, 3vw, 36px);
  animation: lpRise 1s var(--ease) .68s backwards;
}
.lp-proof {
  display: flex; gap: 8px 24px; flex-wrap: wrap; justify-content: center;
  margin: 24px 0 0; padding: 0; list-style: none;
  font-size: 13px; font-weight: 450; color: var(--ink-3);
  animation: lpRise 1s var(--ease) .8s backwards;
}
.lp-proof li { display: inline-flex; align-items: center; gap: 7px; }
.lp-proof svg { width: 14px; height: 14px; color: var(--green); }
@keyframes lpFadeUp { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
/* No `to`, and `backwards` rather than `both`: each of these ends on its own
   depth in the hero's 3D scene, and a keyframe that declared `transform:
   none` would keep applying it and flatten every layer the moment the
   entrance finished. */
@keyframes lpRise { from { opacity: 0; transform: translate3d(0, 22px, 0); } }

/* ==========================================================================
   The stage — the product, at full size

   The window starts tipped away and stands up as you scroll into it. --p is
   written by the scroll loop; everything the transform *is* stays here.
   ========================================================================== */
.lp-stage {
  max-width: calc(var(--wrap) + 80px); margin: 0 auto;
  padding: 0 var(--pad) clamp(20px, 3vw, 34px);
}
.lp-stage-persp { perspective: 2400px; perspective-origin: 50% 0%; }

/* The pointer's half of the window's motion, on its own element.
   Two transforms rather than one composed value, because the two want
   opposite timing: the pointer tilt eases back over half a second when the
   cursor leaves, and the scroll tilt must not be eased at all or it lags the
   wheel. preserve-3d keeps them in one 3D space — flatten this and the
   child's rotation stops being perspective and becomes a squash. */
.lp-stage-persp .lp-window-3d {
  transform: rotateX(calc(var(--rx, 0) * 1deg)) rotateY(calc(var(--ry, 0) * 1deg));
  transform-style: preserve-3d;
}

.lp-stage-persp .lp-window {
  --p: 0;
  position: relative;
  border: 1px solid var(--line); border-radius: 20px;
  background: #fff;
  overflow: hidden;
  transform-origin: 50% 0%;
  transform:
    rotateX(calc((1 - var(--p)) * 26deg))
    scale(calc(.9 + var(--p) * .1))
    translateY(calc((1 - var(--p)) * 30px));
  box-shadow:
    0 2px 6px rgba(8, 9, 12, .05),
    0 calc(20px + var(--p) * 30px) calc(40px + var(--p) * 40px) calc(-20px + var(--p) * -4px) rgba(8, 9, 12, .22),
    0 calc(50px + var(--p) * 60px) calc(90px + var(--p) * 60px) -60px rgba(8, 9, 12, .3);
  animation: lpStageIn 1.2s var(--ease) .45s both;
}
@keyframes lpStageIn { from { opacity: 0; } to { opacity: 1; } }

/* Light pooling on the glass where the cursor is. It inherits --gx/--gy from
   the wrapper the tilt is written on, and it lives here rather than there
   because this is the element with the rounded corners to clip to. */
.lp-window::before {
  content: '';
  position: absolute; inset: 0; z-index: 3;
  pointer-events: none;
  background: radial-gradient(420px circle at var(--gx, 50%) var(--gy, 50%),
              rgba(47, 107, 255, .09), rgba(47, 107, 255, .03) 40%, transparent 68%);
  opacity: 0;
  transition: opacity .45s ease;
}
.lp-window-3d:hover .lp-window::before { opacity: 1; }

/* One light crosses the glass the frame the window finishes standing up.
   Once, on a class the scroll loop sets a single time — a surface that
   shimmers on a loop is a banner ad, a surface that catches the light as it
   arrives is a surface. */
.lp-window::after {
  content: '';
  position: absolute; inset: -40% -60%; z-index: 4;
  pointer-events: none;
  background: linear-gradient(102deg,
              transparent 42%, rgba(255, 255, 255, .82) 50%, transparent 58%);
  opacity: 0;
}
.lp-window.landed::after { animation: lpSweep 1.5s var(--ease) .1s 1; }
@keyframes lpSweep {
  0%   { opacity: 0; transform: translate3d(-60%, 0, 0); }
  22%  { opacity: 1; }
  100% { opacity: 0; transform: translate3d(60%, 0, 0); }
}

.lp-win-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--wash);
}
.lp-win-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--line-2); }
.lp-win-dot.r { background: #FF5F57; } .lp-win-dot.y { background: #FEBC2E; } .lp-win-dot.g { background: #28C840; }
.lp-win-url {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0 auto; padding: 4px 14px;
  border-radius: 999px; background: #fff; border: 1px solid var(--line);
  font-size: 11.5px; font-weight: 500; color: var(--ink-3);
}
.lp-win-url svg { width: 11px; height: 11px; }

.lp-tabs {
  position: relative;
  display: flex; gap: 6px; justify-content: center; flex-wrap: wrap;
  margin-top: clamp(18px, 2.4vw, 28px);
}
/* The dark chip slides between the tabs rather than being repainted on each
   of them. One object moving is a mechanism; three objects changing colour
   is three objects changing colour. */
.lp-tabs-ind {
  position: absolute; top: 0; left: 0;
  border-radius: 11px; background: var(--ink);
  box-shadow: var(--sh-2);
  opacity: 0;
  transition: transform .5s var(--spring), width .5s var(--spring),
              height .3s ease, opacity .3s ease;
}
.lp-tab {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px;
  border: 1px solid var(--line); border-radius: 11px;
  background: #fff;
  font: 500 13.5px var(--f-ui); color: var(--ink-2);
  cursor: pointer;
  box-shadow: var(--sh-1);
  transition: background .3s ease, border-color .3s ease, color .3s ease, transform .25s var(--ease);
}
.lp-tab svg { width: 15px; height: 15px; }
.lp-tab:hover { color: var(--ink); border-color: var(--line-2); transform: translateY(-1px); }
/* Transparent, not dark: what you are seeing through it is the indicator. */
.lp-tab.on { background: transparent; border-color: transparent; color: #fff; box-shadow: none; transform: none; }

/* The screens are stacked so one can leave while the next arrives. Only the
   current one is in flow, so the window keeps the height of what is showing
   and never jolts to the tallest of the three. */
.lp-win-body { position: relative; perspective: 1600px; }
.lp-scr {
  position: absolute; top: 0; left: 0; width: 100%;
  opacity: 0; visibility: hidden; pointer-events: none;
}
.lp-scr.on {
  position: relative; opacity: 1; visibility: visible; pointer-events: auto;
  animation: lpScrIn .62s var(--ease) both;
}
.lp-scr.out { visibility: visible; animation: lpScrOut .44s var(--ease) both; }
@keyframes lpScrIn {
  from { opacity: 0; transform: translate3d(calc(var(--dir, 1) * 6%), 0, 0)
                                rotateY(calc(var(--dir, 1) * -8deg)) scale(.95); }
  to   { opacity: 1; transform: none; }
}
@keyframes lpScrOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translate3d(calc(var(--dir, 1) * -6%), 0, 0)
                                rotateY(calc(var(--dir, 1) * 8deg)) scale(.95); }
}

.lp-scr-in { padding: clamp(18px, 2.4vw, 30px); }
.lp-scr-in.split { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 0; padding: 0; }
.lp-scr-main { padding: clamp(18px, 2.4vw, 30px); }
.lp-scr-side { padding: clamp(18px, 2.4vw, 30px); background: var(--wash); border-left: 1px solid var(--line); }

.lp-scr-top { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; }
.lp-scr-time {
  display: inline-flex; align-items: center; gap: 6px; margin-left: auto;
  font-family: var(--f-num); font-size: 12px; font-weight: 500; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.lp-scr-time svg { width: 13px; height: 13px; }

.lp-tag {
  padding: 4px 10px; border-radius: 7px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
  background: var(--wash); color: var(--ink-2); border: 1px solid var(--line);
}
.lp-tag.hot   { background: var(--gold-tint); color: var(--gold); border-color: rgba(160, 116, 10, .22); }
.lp-tag.blue  { background: var(--blue-tint); color: var(--blue-dk); border-color: rgba(47, 107, 255, .24); }
.lp-tag.gold  { background: var(--gold-tint); color: var(--gold); border-color: rgba(160, 116, 10, .26); }
.lp-tag.green { background: var(--green-tint); color: var(--green); border-color: rgba(14, 159, 110, .26); }

.lp-stem { margin: 0 0 16px; font-size: 15px; line-height: 1.6; color: var(--ink); }

.lp-opt {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; margin-bottom: 8px;
  border: 1px solid var(--line); border-radius: 11px;
  background: #fff;
  font-size: 14px; color: var(--ink-2);
  transition: border-color .25s ease, background .25s ease;
}
.lp-opt b {
  display: grid; place-items: center;
  width: 23px; height: 23px; flex: none;
  border: 1px solid var(--line-2); border-radius: 50%;
  font: 700 11px var(--f-num); color: var(--ink-3);
}
.lp-opt.ok { border-color: rgba(14, 159, 110, .45); background: var(--green-tint); color: var(--ink); }
.lp-opt.ok b { border-color: var(--green); background: var(--green); color: #fff; }
.lp-scr.on .lp-opt.ok { animation: lpFlash 1.5s var(--ease) .9s both; }
@keyframes lpFlash {
  0%   { border-color: var(--line); background: #fff; }
  38%  { border-color: var(--green); background: #D2F1E3; }
  100% { border-color: rgba(14, 159, 110, .45); background: var(--green-tint); }
}
.lp-opt.picked { border-color: var(--blue); background: var(--blue-tint); color: var(--ink); }
.lp-opt.picked b { border-color: var(--blue); background: var(--blue); color: #fff; }

.lp-why {
  margin-top: 16px; padding: 14px 16px;
  border: 1px solid rgba(47, 107, 255, .2); border-radius: 12px;
  background: var(--blue-tint);
}
.lp-why-hd {
  display: flex; align-items: center; gap: 7px; margin-bottom: 6px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--blue-dk);
}
.lp-why-hd svg { width: 14px; height: 14px; }
.lp-why p { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--ink-2); }

.lp-scr-side-t {
  margin: 0 0 15px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-3);
}
.lp-mast { margin-bottom: 14px; }
.lp-mast-hd { display: flex; justify-content: space-between; font-size: 12.5px; margin-bottom: 6px; }
.lp-mast-hd span { color: var(--ink-2); }
.lp-mast-hd b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.lp-mast-bar { height: 6px; border-radius: 999px; background: var(--well); overflow: hidden; }
.lp-mast-bar i { display: block; height: 100%; width: 0; border-radius: 999px; background: var(--blue); }
.lp-scr.on .lp-mast-bar i {
  animation: lpGrow 1.1s var(--ease) both;
  animation-delay: calc(.25s + var(--i) * .11s);
}
.lp-mast.warn .lp-mast-bar i { background: var(--gold-br); }
@keyframes lpGrow { from { width: 0; } to { width: var(--w); } }

.lp-nudge {
  display: flex; gap: 10px; align-items: flex-start;
  margin-top: 20px; padding: 12px 14px;
  border: 1px solid rgba(160, 116, 10, .2); border-radius: 12px;
  background: var(--gold-tint);
  font-size: 12.5px; line-height: 1.5; color: var(--ink-2);
}
.lp-nudge svg { width: 15px; height: 15px; flex: none; color: var(--gold); margin-top: 1px; }
.lp-nudge b { color: var(--gold); font-weight: 700; }

.lp-sess { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.lp-sess-hd { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 9px; }
.lp-sess-hd span { font-size: 10.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }
.lp-sess-hd b { font: 700 13px var(--f-num); color: var(--ink); font-variant-numeric: tabular-nums; }
.lp-sess-dots { display: flex; gap: 5px; }
.lp-sess-dots i { flex: 1; height: 6px; border-radius: 999px; background: var(--well); }
.lp-sess-dots i.hit  { background: var(--blue); }
.lp-sess-dots i.miss { background: #EDA9A9; }
.lp-sess-xp { display: flex; align-items: center; gap: 7px; margin-top: 14px; font-size: 12.5px; color: var(--ink-3); }
.lp-sess-xp svg { width: 14px; height: 14px; color: var(--gold); }
.lp-sess-xp b { color: var(--gold); font: 700 13px var(--f-num); }

/* --- Mock exam screen ------------------------------------------------------ */
.lp-exam-bar {
  display: flex; align-items: center; gap: 14px;
  padding: 14px clamp(18px, 2.4vw, 30px);
  border-bottom: 1px dashed var(--line-2);
}
.lp-exam-bar > div:first-child b { display: block; font: 600 13.5px var(--f-display); letter-spacing: -.02em; color: var(--ink); }
.lp-exam-bar > div:first-child span { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }
.lp-exam-clock {
  display: inline-flex; align-items: center; gap: 7px; margin: 0 auto;
  padding: 6px 14px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--wash);
}
.lp-exam-clock svg { width: 14px; height: 14px; color: var(--ink-3); }
.lp-exam-clock b { font: 700 15px var(--f-num); letter-spacing: -.02em; color: var(--ink); font-variant-numeric: tabular-nums; }
.lp-exam-tools { display: flex; gap: 6px; }
.lp-tool {
  display: grid; place-items: center; width: 30px; height: 30px;
  border: 1px solid var(--line); border-radius: 9px; background: var(--wash); color: var(--ink-3);
}
.lp-tool svg { width: 15px; height: 15px; }

.lp-exam-body {
  display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
  gap: clamp(20px, 2.6vw, 36px);
  padding: clamp(20px, 2.6vw, 32px) clamp(18px, 2.4vw, 30px);
}
.lp-exam-opts { margin-top: 4px; }
.lp-exam-ref { border-left: 1px solid var(--line); padding-left: clamp(18px, 2.2vw, 28px); }
.lp-ref-card { border: 1px solid var(--line); border-radius: 13px; background: var(--wash); padding: 14px; }
.lp-parab { margin-bottom: 8px; }
.lp-parab svg { display: block; width: 100%; height: auto; }
.lp-ref-card p { margin: 0; font-size: 12px; line-height: 1.5; color: var(--ink-3); }

.lp-exam-foot {
  display: flex; align-items: center; gap: 16px;
  padding: 13px clamp(18px, 2.4vw, 30px);
  border-top: 1px solid var(--line);
  background: var(--wash);
}
.lp-exam-count { font-size: 12px; color: var(--ink-3); white-space: nowrap; }
.lp-exam-count b { color: var(--ink); font-weight: 700; font-family: var(--f-num); }
.lp-navdots { display: flex; gap: 4px; margin: 0 auto; flex-wrap: wrap; justify-content: center; }
.lp-navdot {
  display: grid; place-items: center;
  width: 21px; height: 21px; border-radius: 6px;
  border: 1px dashed var(--line-2); background: #fff;
  font: 500 10px var(--f-num); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.lp-navdot.done { border-style: solid; border-color: transparent; background: var(--blue-tint); color: var(--blue-dk); }
.lp-navdot.now  { border-style: solid; border-color: var(--blue); background: var(--blue); color: #fff; }
.lp-navdot.flag { border-style: solid; border-color: var(--gold-br); background: var(--gold-tint); color: var(--gold); }

/* --- Analytics screen ------------------------------------------------------ */
.lp-an-top {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(18px, 2.4vw, 34px);
  padding-bottom: 22px; margin-bottom: 22px;
  border-bottom: 1px solid var(--line);
}
.lp-an-big {
  display: flex; align-items: baseline; gap: 10px;
  font-family: var(--f-num); font-weight: 700; font-size: clamp(40px, 4.6vw, 56px);
  line-height: 1; letter-spacing: -.05em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.lp-an-big i {
  font-style: normal; font-size: 14px; font-weight: 700;
  padding: 4px 9px; border-radius: 999px;
  background: var(--green-tint); border: 1px solid rgba(14, 159, 110, .28); color: var(--green);
  letter-spacing: -.01em;
}
.lp-an-split { margin-top: 12px; display: flex; gap: 18px; flex-wrap: wrap; font-size: 12.5px; color: var(--ink-3); }
.lp-an-split b { color: var(--ink); font-family: var(--f-num); font-weight: 600; }

.lp-heat { display: grid; grid-template-columns: repeat(28, 1fr); gap: 3px; }
.lp-heat i { display: block; height: 34px; border-radius: 4px; background: var(--well); }
.lp-heat i[data-v="1"] { background: #C6D8FF; }
.lp-heat i[data-v="2"] { background: #7FA3FF; }
.lp-heat i[data-v="3"] { background: var(--blue); }
.lp-an-meta { margin-top: 12px; font-size: 12.5px; color: var(--ink-3); display: flex; align-items: center; gap: 7px; }
.lp-an-meta svg { width: 14px; height: 14px; color: var(--gold); }
.lp-an-meta b { color: var(--ink); font-weight: 600; }

.lp-an-bars { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px clamp(22px, 3vw, 44px); }
.lp-an-bars > .lp-scr-side-t { grid-column: 1 / -1; margin-bottom: 2px; }
.lp-an-row { display: grid; grid-template-columns: minmax(0, 158px) minmax(0, 1fr) 40px; align-items: center; gap: 12px; }
.lp-an-name { font-size: 12px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lp-an-track { height: 8px; border-radius: 999px; background: var(--well); overflow: hidden; }
.lp-an-track i { display: block; height: 100%; width: 0; border-radius: 999px; }
.lp-an-track i.ok  { background: var(--blue); }
.lp-an-track i.mid { background: var(--gold-br); }
.lp-an-track i.low { background: #E8734F; }
.lp-scr.on .lp-an-track i { animation: lpGrow 1s var(--ease) both; animation-delay: calc(.2s + var(--i) * .07s); }
.lp-an-pct { font: 600 12px var(--f-num); color: var(--ink); text-align: right; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   Ticker — quiet on purpose
   ========================================================================== */
.lp-tick {
  max-width: var(--wrap); margin: 0 auto;
  padding: clamp(30px, 4vw, 50px) 0 0;
}
.lp-tick-k {
  margin: 0 0 16px; text-align: center;
  font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.lp-tick-row {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.lp-tick-row + .lp-tick-row { margin-top: 8px; }
.lp-tick-track { display: flex; gap: 8px; width: max-content; animation: lpTick 80s linear infinite; }
/* The second row runs the other way, slower. Two rows pulling against each
   other read as a body of material; one row reads as a marquee. */
.lp-tick-row.rev .lp-tick-track { animation-duration: 104s; animation-direction: reverse; }
.lp-tick:hover .lp-tick-track { animation-play-state: paused; }
@keyframes lpTick { to { transform: translateX(-50%); } }
.lp-chip {
  display: inline-flex; align-items: center;
  padding: 7px 14px;
  border: 1px solid var(--line); border-radius: 999px;
  background: #fff;
  font-size: 12.5px; font-weight: 450; color: var(--ink-3);
  white-space: nowrap;
  transition: color .25s ease, border-color .25s ease, transform .3s var(--spring), box-shadow .25s ease;
}
.lp-chip:hover {
  color: var(--ink); border-color: var(--blue);
  transform: translateY(-2px); box-shadow: var(--sh-2);
}

/* ==========================================================================
   Figures
   ========================================================================== */
.lp-figs {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  max-width: var(--wrap); margin: 0 auto;
  padding: clamp(52px, 7vw, 96px) var(--pad);
  perspective: 700px;
}
.lp-fig { position: relative; padding: 4px 22px; }
/* The tallies stand up out of the page as you come to them and lie back down
   as you leave — the transform-origin is at the bottom, so the row hinges on
   its own baseline like four cards being dealt face up. */
.lp-fig-in {
  transform-origin: 50% 100%;
  transform:
    rotateX(calc(var(--c, 0) * 62deg))
    translate3d(0, calc(var(--c, 0) * -30px), calc(var(--ac, 0) * -130px));
  opacity: calc(1 - var(--ac, 0) * .8);
  will-change: transform;
}
.lp-fig + .lp-fig::before {
  content: ''; position: absolute; left: 0; top: 6%; bottom: 6%; width: 1px;
  background: linear-gradient(180deg, transparent, var(--line-2) 26%, var(--line-2) 74%, transparent);
}
.lp-fig-v {
  font-family: var(--f-num); font-weight: 700;
  font-size: clamp(36px, 4.4vw, 60px); line-height: 1;
  letter-spacing: -.05em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.lp-fig-v .lp-mln-i { display: flex; align-items: baseline; gap: 1px; }
.lp-fig-v i { font-style: normal; color: var(--ink-3); }
.lp-fig.gold .lp-fig-v { color: var(--gold); }
.lp-fig-k { margin-top: 12px; font-size: 13px; line-height: 1.45; color: var(--ink-3); max-width: 15em; }

/* ==========================================================================
   Sections and headings
   ========================================================================== */
.lp-sec { max-width: var(--wrap); margin: 0 auto; padding: clamp(70px, 9vw, 140px) var(--pad); }

/* Sized in px, not em: em here resolves against the wrapper's 16px, which
   left a 62px heading wrapping inside a 544px box and breaking every title
   into three ragged lines. */
.lp-head { max-width: 760px; margin-bottom: clamp(38px, 5vw, 66px); }
/* Headings lie back and come upright, hinged on their own baseline. Gentler
   than the panels because this is the type you are meant to be reading. */
.lp-sec { perspective: 1600px; }
.lp-head.js-3d {
  transform-origin: 50% 100%;
  transform: rotateX(calc(var(--c, 0) * 18deg)) translate3d(0, 0, calc(var(--ac, 0) * -70px));
  will-change: transform;
}
.lp-head.center { margin-inline: auto; text-align: center; }
.lp-head.center .lp-eyebrow { justify-content: center; }
.lp-head.center .lp-sub { margin-inline: auto; }
.lp-eyebrow {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 18px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
  color: var(--blue);
}
.lp-eyebrow i { width: 24px; height: 2px; flex: none; border-radius: 2px; background: var(--blue); opacity: .35; }
.lp-h2 { font-size: clamp(34px, 4.6vw, 62px); line-height: 1.02; letter-spacing: -.045em; }
/* Anything can ride up out of a mask, and several things do: every section
   heading, every feature title, and the tallies in the figures row. One
   gesture used for one kind of arrival is what makes a page feel authored
   rather than assembled.
   padding-bottom keeps the mask off the serif's descenders; the negative
   margin gives the space back so the element keeps its own baseline. */
.lp-mln { display: block; overflow: hidden; padding-bottom: .16em; margin-bottom: -.16em; }
.lp-mln-i {
  display: block; text-wrap: balance;
  transform: translateY(108%);
  transition: transform 1s var(--ease);
  transition-delay: var(--d, 0s);
}
.in .lp-mln-i, .in.lp-mln-i, .rv.in .lp-mln-i { transform: none; }
/* The parent only fades — the mask is already doing the movement. */
.lp-h2.rv { transform: none; }
.lp-sub {
  margin: 20px 0 0; max-width: 34em; text-wrap: pretty;
  font-size: clamp(15px, 1.3vw, 18px); line-height: 1.6; color: var(--ink-2);
}

/* ==========================================================================
   Feature blocks
   ========================================================================== */
.lp-features { display: grid; }
.lp-block {
  display: grid; grid-template-columns: minmax(0, .86fr) minmax(0, 1.14fr);
  align-items: center; gap: clamp(32px, 6vw, 90px);
  padding: clamp(40px, 6vw, 84px) 0;
}
.lp-block.flip > .lp-copy-w { order: 2; }
.lp-block-t { font-size: clamp(28px, 3.4vw, 44px); line-height: 1.06; letter-spacing: -.042em; margin: 0 0 18px; }
.lp-block-p { margin: 0; font-size: clamp(15px, 1.25vw, 17px); line-height: 1.62; color: var(--ink-2); max-width: 30em; }
.lp-block-list { list-style: none; padding: 0; margin: 24px 0 0; display: grid; gap: 12px; }
.lp-block-list li {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 14.5px; line-height: 1.5; color: var(--ink-2);
}
.lp-block-list svg { width: 16px; height: 16px; flex: none; margin-top: 1px; color: var(--blue); }
/* The panel is a plane at an angle to you, not a picture beside some text.

   Every .js-3d element is handed --c (-1 below the fold, 0 centred, +1 above
   it) and --ac (distance from centre) on every scroll frame, and each kind
   of element decides for itself what that means. Nothing here is a triggered
   animation: it runs off the wheel, both directions, continuously, which is
   the difference between a page that has been animated and a page that
   responds to you.

   Defaults matter: --c falls back to 0, which every rule below reads as
   "arrived and level", so if the loop never runs the page is simply correct.

   --dir is which side of the row a panel sits on, so it always turns away
   from its own edge. --vel is the page's scroll velocity, and a degree of
   skew into the direction of travel is what gives the page weight. */
.lp-block { perspective: 1400px; }
/* The copy turns the opposite way to the panel beside it, on the block's own
   long perspective — text has to stay readable the whole way through, so this
   is the one plane on the page that moves gently. */
.lp-copy-w {
  transform-origin: calc(50% - var(--dir, 1) * 40%) 50%;
  transform:
    translate3d(0, calc(var(--c, 0) * -26px), calc(var(--ac, 0) * -90px))
    rotateY(calc(var(--c, 0) * var(--dir, 1) * -13deg));
  opacity: calc(1 - var(--ac, 0) * .8);
  will-change: transform;
}
.lp-copy-w.flip { --dir: -1; }

/* The panel has its own, much shorter perspective: it is a slab swinging on
   the hinge of its outer edge, and at 800px that reads as a door rather than
   as a picture someone nudged. */
/* This column keeps .rv, but only as a trigger: the skill bars and the
   calendar inside the panel grow off .rv.in, and the scroll plane inside it
   is a different element doing a different job. Its own reveal transform is
   dropped so the two are not both moving the same pixels. */
.lp-block-vis { perspective: 800px; perspective-origin: 50% 50%; }
.lp-block-vis.rv, .lp-block-vis.rv.in { transform: none; opacity: 1; }
.lp-block-vis .js-3d {
  will-change: transform;
  transform-origin: calc(50% + var(--dir, 1) * 45%) 50%;
  transform:
    translate3d(0, calc(var(--c, 0) * -70px), calc(var(--ac, 0) * -220px))
    rotateX(calc(var(--c, 0) * 26deg))
    rotateY(calc(var(--c, 0) * var(--dir, 1) * 34deg))
    skewY(calc(var(--vel, 0) * 1.4deg));
  opacity: calc(1 - var(--ac, 0) * .7);
}

/* --- The shared panel the feature visuals are built from ------------------- */
.lp-panel {
  border: 1px solid var(--line); border-radius: 20px;
  background: #fff;
  box-shadow: var(--sh-3);
  overflow: hidden;
}
.lp-panel-hd {
  display: flex; align-items: center; gap: 12px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--wash);
}
.lp-panel-hd b { display: block; font: 700 15px var(--f-display); letter-spacing: -.025em; color: var(--ink); }
.lp-panel-hd span { display: block; font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.lp-panel-hd .lp-tag { margin-left: auto; flex: none; }
.lp-panel-body { padding: 20px; }
.lp-panel-foot {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 20px;
  border-top: 1px solid var(--line);
  background: var(--wash);
  font-size: 13px; line-height: 1.5; color: var(--ink-2);
}
.lp-panel-foot b { color: var(--ink); font-weight: 600; }
.lp-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.lp-dot.ok { background: var(--green); } .lp-dot.mid { background: var(--gold-br); } .lp-dot.low { background: #E8734F; }

.lp-srow { display: grid; grid-template-columns: minmax(0, 170px) minmax(0, 1fr) 44px; align-items: center; gap: 14px; padding: 9px 0; }
.lp-srow-n { font-size: 13.5px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lp-srow.flag .lp-srow-n { color: var(--ink); font-weight: 500; }
.lp-srow-track { height: 9px; border-radius: 999px; background: var(--well); overflow: hidden; }
.lp-srow-track i { display: block; height: 100%; width: 0; border-radius: 999px; }
.lp-srow-track i.ok  { background: var(--blue); }
.lp-srow-track i.mid { background: var(--gold-br); }
.lp-srow-track i.low { background: #E8734F; }
.rv.in .lp-srow-track i { animation: lpGrow 1.1s var(--ease) both; animation-delay: calc(.15s + var(--i) * .09s); }
.lp-srow-v { font: 700 14px var(--f-num); color: var(--ink); text-align: right; font-variant-numeric: tabular-nums; }

.lp-cal-hd { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 8px; }
.lp-cal-hd span { text-align: center; font: 600 11px var(--f-num); color: var(--ink-3); letter-spacing: .08em; }
.lp-cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 20px; }
.lp-cal i {
  display: block; aspect-ratio: 1; border-radius: 8px; background: var(--well);
  opacity: 0;
}
.lp-cal i[data-v="1"] { background: #D6E2FF; }
.lp-cal i[data-v="2"] { background: #9FBCFF; }
.lp-cal i[data-v="3"] { background: var(--blue); }
.lp-cal i.today { box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--gold-br); }
.rv.in .lp-cal i { animation: lpFadeIn .45s ease both; animation-delay: calc(.15s + var(--i) * .02s); }
@keyframes lpFadeIn { to { opacity: 1; } }
.lp-plan-rows { display: grid; gap: 8px; }
.lp-plan-row {
  display: flex; align-items: center; gap: 11px;
  padding: 12px 14px;
  border: 1px solid var(--line); border-radius: 11px; background: #fff;
  font-size: 13.5px; color: var(--ink-2);
}
.lp-plan-row b { margin-left: auto; font: 600 13px var(--f-num); color: var(--ink-3); }
.lp-plan-row.dim { opacity: .55; }

.lp-lad {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 13px; margin-bottom: 7px;
  border: 1px solid var(--line); border-radius: 12px; background: #fff;
  font-size: 13.5px; color: var(--ink-2);
}
.lp-lad-r { font: 700 12px var(--f-num); color: var(--ink-3); width: 14px; }
.lp-lad-av {
  width: 26px; height: 26px; border-radius: 9px; flex: none;
  background: #000 url("../assets/mascot.png") center/cover;
}
.lp-lad-n { flex: 1; }
.lp-lad-xp { font: 600 13px var(--f-num); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.lp-lad.gold { border-color: rgba(160, 116, 10, .3); background: var(--gold-tint); }
.lp-lad.gold .lp-lad-r, .lp-lad.gold .lp-lad-xp { color: var(--gold); }
.lp-lad.you { border-color: var(--blue); background: var(--blue-tint); color: var(--ink); }
.lp-lad.you .lp-lad-xp { color: var(--blue-dk); }
.lp-panel-foot.duel { gap: 8px; }
.lp-duel-av {
  width: 24px; height: 24px; border-radius: 8px; flex: none;
  background: #000 url("../assets/mascot.png") center/cover;
  box-shadow: 0 0 0 2px #fff;
}
.lp-duel-av.b { margin-left: -14px; }
.lp-panel-foot.duel > span:nth-child(3) { flex: 1; }
.lp-panel-foot .lp-btn { flex: none; }

/* ==========================================================================
   Planner section
   ========================================================================== */
.lp-plansec { background: linear-gradient(180deg, transparent, var(--wash) 22%, var(--wash) 78%, transparent); max-width: none; }
.lp-plansec > * { max-width: var(--wrap); margin-inline: auto; }
.lp-plansec-in {
  display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
  gap: clamp(30px, 5vw, 70px); align-items: center;
  perspective: 900px;
}
.lp-plansec-panel {
  transform-origin: 20% 50%;
  transform:
    translate3d(0, calc(var(--c, 0) * -56px), calc(var(--ac, 0) * -200px))
    rotateX(calc(var(--c, 0) * 24deg))
    rotateY(calc(var(--c, 0) * -26deg));
  opacity: calc(1 - var(--ac, 0) * .7);
  will-change: transform;
}
.lp-plansec-copy p { margin: 0 0 8px; font-size: clamp(15px, 1.25vw, 17px); line-height: 1.62; color: var(--ink-2); }

/* ==========================================================================
   Score planner
   ========================================================================== */
.pl {
  position: relative;
  color: var(--ink);
  padding: 22px 22px 20px;
  border: 1px solid var(--line); border-radius: 22px;
  background: #fff;
  box-shadow: var(--sh-4);
  overflow: hidden;
}

.pl-hd { display: flex; align-items: center; gap: 10px; padding: 2px 4px 14px; }
.pl-hd-t { font: 700 14px var(--f-display); letter-spacing: -.025em; color: var(--ink); }
.pl-hd-tag {
  margin-left: auto;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid rgba(14, 159, 110, .28); background: var(--green-tint);
  color: var(--green); font-size: 10.5px; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
}

.pl-chart-wrap { border-radius: 16px; background: var(--wash); border: 1px solid var(--line); padding: 6px 4px 0; }
.pl-chart { display: block; width: 100%; height: auto; }
.pl-grid line { stroke: rgba(8, 9, 12, .08); stroke-width: 1; }
.pl-drops line { stroke: rgba(8, 9, 12, .16); stroke-width: 1; stroke-dasharray: 2 5; }
.pl-axis { font-family: var(--f-num); font-size: 10px; font-weight: 500; fill: var(--ink-3); font-variant-numeric: tabular-nums; }
.pl-axis-x { font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; }
.pl-start circle { fill: var(--ink); }
.pl-end-halo { fill: rgba(245, 185, 33, .32); animation: lpHalo 2.8s ease-in-out infinite; }
.pl-end-dot { fill: var(--gold-br); stroke: #fff; stroke-width: 2.5; }
@keyframes lpHalo { 0%, 100% { r: 12; opacity: .9; } 50% { r: 17; opacity: .3; } }
.pl-chip rect { fill: var(--ink); stroke: none; }
.pl-chip-t { font-family: var(--f-num); font-size: 14px; font-weight: 700; fill: #fff; font-variant-numeric: tabular-nums; }

.pl-outs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; margin: 18px 0 0; }
.pl-out { position: relative; text-align: center; padding: 4px 6px; }
.pl-out + .pl-out::before { content: ''; position: absolute; left: 0; top: 14%; bottom: 14%; width: 1px; background: var(--line); }
.pl-out-v {
  display: block;
  font-family: var(--f-num); font-weight: 700; font-size: clamp(24px, 2.4vw, 30px);
  letter-spacing: -.04em; color: var(--ink); font-variant-numeric: tabular-nums;
}
.pl-out-v.gold { color: var(--gold); }
.pl-out span { display: block; margin-top: 4px; font-size: 12px; color: var(--ink-3); }

.pl-detail { margin: 16px 2px 0; font-size: 13px; line-height: 1.55; color: var(--ink-2); }
.pl-verdict {
  margin: 10px 0 0;
  padding: 11px 14px; border-radius: 11px;
  font-size: 13px; line-height: 1.45; font-weight: 500;
  border: 1px solid var(--line); background: var(--wash); color: var(--ink-2);
}
.pl-verdict.ok   { border-color: rgba(14, 159, 110, .26); background: var(--green-tint); color: #0A7A55; }
.pl-verdict.warm { border-color: rgba(160, 116, 10, .26); background: var(--gold-tint); color: var(--gold); }
.pl-verdict.hot  { border-color: rgba(217, 74, 74, .28);  background: var(--red-tint);  color: #B33A3A; }

.pl-ctl { margin-top: 20px; display: grid; gap: 15px; }
.pl-row { display: block; }
.pl-row-hd { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; }
.pl-row-hd > span:first-child { font-size: 13px; font-weight: 500; color: var(--ink-3); }
.pl-val { font-family: var(--f-num); font-weight: 700; font-size: 18px; letter-spacing: -.03em; color: var(--ink); font-variant-numeric: tabular-nums; }
.pl-val.gold { color: var(--gold); }

/* Range inputs, styled to the bone. Both vendor trees are needed: the
   pseudo-elements are not interchangeable and a shared rule is dropped
   whole by whichever engine does not recognise the other's selector. */
.pl-range { -webkit-appearance: none; appearance: none; display: block; width: 100%; height: 22px; background: transparent; cursor: pointer; }
.pl-range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px;
  background: linear-gradient(90deg, var(--blue) 0 var(--p, 50%), var(--well) var(--p, 50%) 100%);
}
.pl-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px; height: 20px; margin-top: -7px;
  border-radius: 50%; background: #fff; border: 2px solid var(--blue);
  box-shadow: var(--sh-2);
  transition: transform .16s ease;
}
.pl-range:hover::-webkit-slider-thumb  { transform: scale(1.1); }
.pl-range:active::-webkit-slider-thumb { transform: scale(1.2); }
.pl-range::-moz-range-track {
  height: 6px; border-radius: 999px;
  background: linear-gradient(90deg, var(--blue) 0 var(--p, 50%), var(--well) var(--p, 50%) 100%);
}
.pl-range::-moz-range-thumb { width: 20px; height: 20px; border: 2px solid var(--blue); border-radius: 50%; background: #fff; box-shadow: var(--sh-2); }
.pl-range.gold::-webkit-slider-runnable-track {
  background: linear-gradient(90deg, var(--gold-br) 0 var(--p, 50%), var(--well) var(--p, 50%) 100%);
}
.pl-range.gold::-moz-range-track {
  background: linear-gradient(90deg, var(--gold-br) 0 var(--p, 50%), var(--well) var(--p, 50%) 100%);
}
.pl-range.gold::-webkit-slider-thumb { border-color: #D69C08; }
.pl-range.gold::-moz-range-thumb     { border-color: #D69C08; }

.pl-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.pl-chip-btn {
  padding: 8px 13px;
  border: 1px solid var(--line); border-radius: 10px;
  background: #fff;
  font: 500 13px var(--f-ui); color: var(--ink-2);
  cursor: pointer;
  transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.pl-chip-btn:hover { color: var(--ink); border-color: var(--line-2); }
.pl-chip-btn[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: #fff; font-weight: 600; }
.pl-fine { margin: 16px 2px 0; font-size: 11.5px; line-height: 1.5; color: var(--ink-3); }

/* ==========================================================================
   The score climb
   ========================================================================== */
.lp-climb {
  position: relative; max-width: none;
  padding: clamp(60px, 7vw, 100px) 0 0;
  border-top: 1px solid var(--line);
}
.lp-climb > .lp-head {
  max-width: min(34em, calc(var(--wrap) - var(--pad) * 2));
  margin: 0 auto; padding-inline: var(--pad); text-align: center;
}
.lp-climb .lp-eyebrow { justify-content: center; }
.lp-climb .lp-sub { margin-inline: auto; }

/* The scroll runway. Its height is what the climb has to spend, and the
   pinned child eats one viewport of it — the same relationship the travel
   maths in landing-climb.js reads back out. */
.cl-body { position: relative; min-height: 320vh; }
.cl-pin {
  position: sticky; top: 0; height: 100vh;
  display: grid; place-items: center;
  padding: 92px var(--pad) 44px;
}
.cl-grid {
  display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  align-items: center; gap: clamp(28px, 4vw, 70px);
  width: 100%; max-width: calc(var(--wrap) - var(--pad) * 2);
}

.cl-pips { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 28px; }
.cl-pip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px 7px 11px;
  border: 1px solid var(--line); border-radius: 999px;
  background: #fff;
  font-size: 11.5px; font-weight: 600; color: var(--ink-3);
  transition: background .35s ease, border-color .35s ease, color .35s ease;
}
.cl-pip i { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--well); transition: background .35s ease; }
.cl-pip.done { color: var(--ink-2); }
.cl-pip.done i { background: var(--blue-hi); }
.cl-pip.on { background: var(--ink); border-color: var(--ink); color: #fff; }
.cl-pip.on i { background: var(--gold-br); }

.cl-stages { position: relative; min-height: 220px; }
.cl-stage {
  position: absolute; inset: 0;
  opacity: 0; transform: translateY(18px);
  transition: opacity .45s ease, transform .6s var(--ease);
  pointer-events: none;
}
.cl-stage.on { opacity: 1; transform: none; pointer-events: auto; }
.cl-stage-tag { display: inline-block; font-size: 11.5px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: var(--blue); }
.cl-stage-t { margin: 14px 0 0; font-size: clamp(28px, 3.2vw, 44px); line-height: 1.05; letter-spacing: -.045em; text-wrap: balance; }
.cl-stage-p { margin: 16px 0 0; font-size: 16px; line-height: 1.6; color: var(--ink-2); max-width: 26em; }

.cl-card { padding: clamp(20px, 2.6vw, 32px); border: 1px solid var(--line); border-radius: 24px; background: #fff; box-shadow: var(--sh-4); }
.cl-card-hd { display: flex; align-items: center; gap: 12px; padding-bottom: 18px; border-bottom: 1px solid var(--line); }
.cl-card-mark { width: 34px; height: 34px; flex: none; }
.cl-card-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
.cl-card-hd b { display: block; font: 700 15px var(--f-display); letter-spacing: -.025em; color: var(--ink); }
.cl-card-hd span { display: block; font-size: 12px; color: var(--ink-3); margin-top: 1px; }
.cl-card-tag {
  display: inline-flex; align-items: center; gap: 5px; margin-left: auto;
  padding: 5px 11px; border-radius: 999px;
  background: var(--green-tint); border: 1px solid rgba(14, 159, 110, .28);
  color: var(--green); font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
}
.cl-card-tag svg { width: 12px; height: 12px; }

.cl-total { padding: 22px 0 4px; }
.cl-total-k { margin: 0; font-size: 11px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-3); }
.cl-total-v {
  font-family: var(--f-num); font-weight: 700;
  font-size: clamp(60px, 7.6vw, 104px); line-height: 1;
  letter-spacing: -.06em; color: var(--ink);
  font-variant-numeric: tabular-nums; min-height: 1em;
}

/* The odometer.

   Four wheels behind a one-digit window. Every measurement is in em against
   the inherited display size, so the whole thing scales with the clamp above
   and nothing has to be kept in step by hand.

   Each wheel is eleven digits — 0 to 9 and then 0 again — because a wheel at
   9.6 has to have somewhere to roll to. Without the repeat it would snap
   backwards through eight digits to reach the next zero. */
.cl-od { --cell: 1.06em; display: flex; height: var(--cell); }
/* The fade is only wide enough to soften the two edges. A digit sits between
   16% and 84% of its cell, so anything past about 12% starts eating the
   glyph itself rather than the space around it. */
.cl-od-c {
  height: var(--cell); overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
}
/* The transition is the roll. A ten-point step moves the strip exactly one
   cell, and scrolling produces those steps faster than a quarter of a second
   apart, so the target keeps moving and the wheels read as turning
   continuously — while any position they are left in is a whole digit. */
/* font-style, because this is an <i>: the strip is a run of digits, and the
   tag's default italic would otherwise oblique the entire score.
   No will-change: each strip is fifty-three cells of display type, and four
   permanently promoted layers that tall is tens of megabytes of texture to
   save a promotion the transition does anyway. */
.cl-od-c > i {
  display: block;
  font-style: normal;
  transform: translate3d(0, calc(var(--n, 0) * var(--cell) * -1), 0);
  transition: transform .26s cubic-bezier(.22, .7, .28, 1);
}
/* line-height equal to the cell is what centres the glyph: half-leading
   splits the difference evenly above and below, so a digit at rest sits in
   the middle of its window instead of riding its own baseline. */
.cl-od-c > i > b {
  display: block;
  height: var(--cell); line-height: var(--cell);
  text-align: center; font-weight: inherit;
}

/* The wheels are two digits at once for most of their travel. The number a
   screen reader is given is the rounded one, announced politely so it is not
   read out on every ten-point step of a scroll. */
.cl-od-sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.cl-total-sub { margin: 10px 0 0; font-size: 12.5px; color: var(--ink-3); }
.cl-total-sub b { color: var(--ink-2); font-family: var(--f-num); font-weight: 600; }

.cl-scale { margin: 20px 0 26px; }
.cl-scale-track { position: relative; height: 10px; border-radius: 999px; background: var(--well); }
.cl-scale-fill { position: absolute; inset: 0 auto 0 0; width: 0; border-radius: 999px; background: linear-gradient(90deg, var(--blue-dk), var(--blue) 55%, var(--gold-br)); }
.cl-scale-dot { position: absolute; top: 50%; left: 0; width: 20px; height: 20px; margin: -10px 0 0 -10px; border-radius: 50%; background: #fff; border: 3px solid var(--ink); box-shadow: var(--sh-2); }
.cl-scale-ticks { display: flex; justify-content: space-between; margin-top: 10px; font: 500 11px var(--f-num); color: var(--ink-3); font-variant-numeric: tabular-nums; }

.cl-secs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.cl-sec-hd { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.cl-sec-hd span { font-size: 12.5px; color: var(--ink-2); }
.cl-sec-hd b { font: 700 17px var(--f-num); color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: -.03em; }
.cl-sec-bar { height: 6px; border-radius: 999px; background: var(--well); overflow: hidden; }
.cl-sec-bar i { display: block; height: 100%; width: 0; border-radius: 999px; background: var(--blue); }

.cl-foot { display: flex; align-items: baseline; gap: 9px; margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line); }
.cl-foot-k { font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }
.cl-foot-v { font: 700 21px var(--f-num); color: var(--gold); letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.cl-foot-n { font-size: 12px; color: var(--ink-3); margin-left: auto; }

/* ==========================================================================
   Extras
   ========================================================================== */
.lp-xgrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; perspective: 800px; }
/* Four cards coming forward off the page one after another. The stagger is
   free: they are at different heights, so they reach the middle of the
   screen at different moments and no delay has to be written down. */
.lp-xwrap {
  display: flex;
  transform-origin: 50% 100%;
  transform:
    translate3d(0, calc(var(--c, 0) * -46px), calc(var(--ac, 0) * -260px))
    rotateX(calc(var(--c, 0) * 44deg));
  opacity: calc(1 - var(--ac, 0) * .85);
  will-change: transform;
}
.lp-xcard {
  flex: 1;
  padding: 26px 24px;
  border: 1px solid var(--line); border-radius: 18px;
  background: #fff;
  box-shadow: var(--sh-1);
}
/* The lift is --lift on .js-tilt, not a transform here: a second transform
   rule at higher specificity would win and the card would stop tilting at
   exactly the moment you are hovering it. */
.lp-xcard:hover { box-shadow: var(--sh-3); border-color: var(--line-2); }
.lp-xic {
  display: grid; place-items: center;
  width: 42px; height: 42px; margin-bottom: 18px;
  border-radius: 13px; background: var(--blue-tint); color: var(--blue);
  transition: transform .45s var(--spring), background .3s ease, color .3s ease;
}
.lp-xcard:hover .lp-xic { transform: rotate(-7deg) scale(1.08); background: var(--blue); color: #fff; }
.lp-xic svg { width: 20px; height: 20px; }
.lp-xt { font-size: 16.5px; line-height: 1.3; letter-spacing: -.028em; margin: 0 0 8px; }
.lp-xp { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--ink-2); }

/* ==========================================================================
   Pricing
   ========================================================================== */
.lp-pers {
  display: flex; gap: 4px; flex-wrap: wrap; justify-content: center;
  margin: 0 auto clamp(30px, 3.4vw, 44px);
  padding: 5px;
  border: 1px solid var(--line); border-radius: 15px;
  background: var(--wash);
  width: fit-content;
}
.lp-per {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 18px;
  border: 0; border-radius: 11px; background: none;
  font: 600 14px var(--f-ui); color: var(--ink-2);
  cursor: pointer;
  transition: background .25s ease, color .25s ease, box-shadow .25s ease;
}
.lp-per:hover { color: var(--ink); }
.lp-per.on { background: #fff; color: var(--ink); box-shadow: var(--sh-1); }
.lp-per i {
  font-style: normal; font-size: 9.5px; font-weight: 800; letter-spacing: .08em;
  padding: 3px 7px; border-radius: 999px; background: var(--gold-br); color: #4A3200;
}

.lp-plans { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; perspective: 1100px; }
/* Three planes rather than three cards: the tilt already owns the card's
   transform, so the scroll needs an element of its own. The row fans in
   because the outer two are handed their own turn. */
.lp-plan-w {
  display: flex;
  transform-origin: 50% 100%;
  transform:
    translate3d(0, calc(var(--c, 0) * -40px), calc(var(--ac, 0) * -190px))
    rotateX(calc(var(--c, 0) * 30deg))
    rotateY(calc(var(--c, 0) * (var(--i, 1) - 1) * 16deg));
  opacity: calc(1 - var(--ac, 0) * .85);
  will-change: transform;
}
.lp-plan-w.feat { z-index: 1; }
.lp-plan-w > .lp-plan { flex: 1; }
.lp-plan {
  position: relative;
  display: flex; flex-direction: column;
  padding: 30px 28px;
  border: 1px solid var(--line); border-radius: 22px;
  background: #fff;
  box-shadow: var(--sh-1);
  /* backwards, not both: the fill must stop applying the instant it lands,
     or the animation's final transform would sit on top of the tilt for the
     rest of the page's life. */
  animation: lpPlanIn .7s var(--ease) backwards;
  animation-delay: calc(var(--i, 0) * .09s);
}
/* The function list matches .js-tilt's exactly, so the two interpolate
   per-function instead of being decomposed into matrices. */
@keyframes lpPlanIn {
  from { opacity: 0; transform: perspective(1100px) rotateX(9deg) rotateY(0deg) translate3d(0, 26px, 0); }
}
.lp-plan:hover { box-shadow: var(--sh-3); border-color: var(--line-2); }

/* The recommendation is made with weight and a rule, not a colour wash: a
   tinted card beside two white ones reads as "different", and the thing
   being said is "more". */
.lp-plan.featured { border-color: var(--ink); box-shadow: var(--sh-4); }
.lp-plan.featured:hover { box-shadow: var(--sh-4); border-color: var(--ink); }

/* A slow turn of brand light around the edge of the one card being
   recommended.

   The angle is a registered property so it can be animated at all — a plain
   custom property inside a gradient is a string, and strings do not
   interpolate. Browsers without @property get a still gradient, which is a
   perfectly good hairline.

   The ring is drawn as a masked box rather than a z-index: -1 layer. The
   card carries a transform, which makes it a stacking context, and inside
   one a negative-z child paints *after* the element's own background — so
   the obvious version puts the conic gradient over the whole white card
   instead of behind it. Two masks that cancel everywhere but the padding
   leave only the edge, above the background, which is where a border
   belongs anyway. */
@property --lp-a { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
.lp-plan.featured::before {
  content: '';
  position: absolute; inset: -2px;
  border-radius: inherit; padding: 2px;
  pointer-events: none;
  background: conic-gradient(from var(--lp-a),
              var(--blue), var(--gold-br) 25%, var(--blue) 50%, var(--gold-br) 75%, var(--blue));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  animation: lpRing 7s linear infinite;
}
@keyframes lpRing { to { --lp-a: 360deg; } }
.lp-plan-tag {
  position: absolute; top: -12px; left: 28px;
  padding: 5px 13px; border-radius: 999px;
  background: var(--ink); color: #fff;
  font-size: 10.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
}
.lp-plan-n {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--f-display); font-weight: 700; font-size: 20px;
  letter-spacing: -.035em; color: var(--ink);
}
.lp-plan-n i {
  font-style: normal; font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
  padding: 3px 8px; border-radius: 999px;
  background: var(--gold-tint); color: var(--gold); border: 1px solid rgba(160, 116, 10, .22);
}
.lp-plan-p { display: flex; align-items: baseline; gap: 8px; margin: 18px 0 0; font-family: var(--f-num); font-variant-numeric: tabular-nums; }
.lp-plan-p s { font-size: 22px; font-weight: 500; color: var(--ink-3); text-decoration-thickness: 2px; }
.lp-plan-p b { font-size: 46px; font-weight: 700; letter-spacing: -.055em; color: var(--ink); line-height: 1; }
.lp-plan-p span { font-family: var(--f-ui); font-size: 14px; font-weight: 500; color: var(--ink-3); }
.lp-plan-sub { margin: 12px 0 24px; font-size: 12.5px; color: var(--ink-3); }
.lp-plan-list { list-style: none; padding: 0; margin: 0 0 28px; display: grid; gap: 12px; }
.lp-plan-list li { display: flex; align-items: flex-start; gap: 10px; font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }
.lp-plan-list svg { width: 15px; height: 15px; flex: none; margin-top: 2px; color: var(--blue); }
.lp-plan.featured .lp-plan-list svg { color: var(--ink); }
.lp-plan .lp-btn { margin-top: auto; width: 100%; }

.lp-plans-note {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: 28px auto 0; max-width: 46em; text-align: center;
  font-size: 12.5px; line-height: 1.6; color: var(--ink-3);
}
.lp-plans-note svg { width: 14px; height: 14px; flex: none; }

/* ==========================================================================
   FAQ

   Buttons rather than <details>: a closed <details> sets its content to
   display:none, which no transition can animate out of. The grid-rows
   0fr → 1fr trick needs the content to stay in the box.
   ========================================================================== */
.lp-faq { max-width: 800px; margin: 0 auto; border-top: 1px solid var(--line); perspective: 1000px; }
.lp-faq-row.js-3d {
  transform-origin: 50% 50%;
  transform: rotateX(calc(var(--c, 0) * 22deg)) translate3d(0, 0, calc(var(--ac, 0) * -80px));
  opacity: calc(1 - var(--ac, 0) * .8);
  will-change: transform;
}
.lp-faq-row { border-bottom: 1px solid var(--line); transition: background .3s ease; }
.lp-faq-row:hover { background: var(--wash); }
.lp-faq-q {
  display: flex; align-items: center; gap: 18px; width: 100%;
  padding: 24px 10px;
  border: 0; background: none;
  font: 600 17px var(--f-display); color: var(--ink); text-align: left;
  letter-spacing: -.025em;
  cursor: pointer;
}
.lp-faq-t { flex: 1; }
/* A plus that becomes a minus: one bar rotates away. Cheaper and calmer
   than spinning a chevron a full half turn. */
.lp-faq-ic { position: relative; width: 15px; height: 15px; flex: none; }
.lp-faq-ic i {
  position: absolute; inset: 50% 0 auto; height: 2px; margin-top: -1px;
  background: var(--ink-3); border-radius: 2px;
  transition: transform .38s var(--ease), background .3s ease;
}
.lp-faq-ic i:last-child { transform: rotate(90deg); }
.lp-faq-row.open .lp-faq-ic i { background: var(--ink); }
.lp-faq-row.open .lp-faq-ic i:last-child { transform: rotate(180deg); }
.lp-faq-a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .42s var(--ease); }
.lp-faq-row.open .lp-faq-a { grid-template-rows: 1fr; }
.lp-faq-a > div { overflow: hidden; }
.lp-faq-a p { margin: 0; padding: 0 44px 26px 10px; font-size: 15px; line-height: 1.7; color: var(--ink-2); }

/* ==========================================================================
   Final CTA + footer
   ========================================================================== */
.lp-final { padding: 0 var(--pad) clamp(56px, 7vw, 90px); }
.lp-final-in {
  position: relative; overflow: hidden;
  max-width: calc(var(--wrap) - var(--pad) * 2); margin: 0 auto;
  padding: clamp(54px, 7vw, 96px) clamp(24px, 4vw, 56px);
  text-align: center;
  border-radius: 32px;
  background: var(--ink);
  color: #fff;
  box-shadow: var(--sh-4);
}
/* The one dark surface on the page, and the only place brand colour is
   allowed to bloom — after nine screens of paper it lands like a curtain.
   Inset past the edges so the whole aurora can drift without ever pulling a
   hard edge of gradient into the panel. */
.lp-final-in::before {
  content: '';
  position: absolute; inset: -25%; pointer-events: none;
  background:
    radial-gradient(ellipse 44% 52% at 30% 26%, rgba(47, 107, 255, .55), transparent 62%),
    radial-gradient(ellipse 38% 46% at 76% 78%, rgba(245, 185, 33, .3), transparent 62%);
  animation: lpAurora 18s ease-in-out infinite;
}
@keyframes lpAurora {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  33%      { transform: translate3d(4%, -3%, 0) scale(1.1); }
  66%      { transform: translate3d(-3%, 3%, 0) scale(1.04); }
}
/* And a light that follows the cursor. On paper this would be invisible;
   on the one dark panel it is the whole reason the panel is dark. */
.lp-final-in::after {
  content: '';
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(560px circle at var(--sx, 50%) var(--sy, 34%),
              rgba(255, 255, 255, .14), transparent 62%);
  opacity: 0;
  transition: opacity .5s ease;
}
.lp-final-in:hover::after { opacity: 1; }
.lp-final-in > * { position: relative; z-index: 1; }
.lp-final .lp-h2 { color: #fff; }
.lp-final .lp-sub { color: rgba(255, 255, 255, .76); margin-left: auto; margin-right: auto; }
.lp-final-mark {
  display: block; width: 70px; height: 70px; margin: 0 auto 24px;
  animation: lpBob 5s ease-in-out infinite;
}
.lp-final-mark img { width: 100%; height: 100%; object-fit: contain; display: block;
  filter: drop-shadow(0 14px 26px rgba(0, 0, 0, .55)); }
@keyframes lpBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
.lp-final .lp-btn { margin-top: 32px; }
.lp-final .lp-btn-primary { background: #fff; color: var(--ink); box-shadow: 0 12px 32px -10px rgba(0, 0, 0, .6); }
.lp-final .lp-btn-primary:hover { background: #F2F4F8; }
.lp-final .lp-btn-primary::after { background: linear-gradient(105deg, transparent 36%, rgba(8, 9, 12, .1) 50%, transparent 64%); }
.lp-final-note { margin: 20px 0 0; font-size: 12.5px; color: rgba(255, 255, 255, .6); }

.lp-foot { padding: 0 var(--pad) 48px; }
.lp-foot-in {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 34px;
  max-width: calc(var(--wrap) - var(--pad) * 2); margin: 0 auto;
  padding-top: 48px;
}
.lp-foot-brand .lp-logo { margin-right: 0; }
.lp-foot-note { margin: 16px 0 0; font-size: 12px; line-height: 1.65; color: var(--ink-3); max-width: 34em; }
.lp-foot-col { display: flex; flex-direction: column; gap: 10px; }
.lp-foot-h { margin: 0 0 4px; font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }
.lp-foot-col a { font-size: 13.5px; color: var(--ink-2); text-decoration: none; transition: color .2s ease; width: fit-content; }
.lp-foot-col a:hover { color: var(--ink); }
.lp-foot-rule { max-width: calc(var(--wrap) - var(--pad) * 2); margin: 36px auto 0; height: 1px; background: var(--line); }
.lp-foot-fine { max-width: calc(var(--wrap) - var(--pad) * 2); margin: 20px auto 0; font-size: 12px; color: var(--ink-3); }

/* ==========================================================================
   Motion primitives
   ========================================================================== */

/* Scroll reveal, and its variants. The default rises; a two-column row wants
   its halves to come in from their own sides, and a panel wants to come up
   off its back. .rv.in wins on source order — it is the same specificity as
   the modifiers and it is written last. */
.rv {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .8s var(--ease), transform .9s var(--ease), filter .8s var(--ease);
  transition-delay: var(--d, 0s);
}
.rv.rv-l  { transform: translate3d(-46px, 0, 0); }
.rv.rv-r  { transform: translate3d(46px, 0, 0); }
.rv.rv-up { transform: perspective(1200px) translate3d(0, 48px, 0) rotateX(8deg) scale(.965); }
.rv.in { opacity: 1; transform: none; }

/* The scroll-scrubbed planes have no equivalent of .rv.in, and they do not
   need one: every rule that reads --c falls back to 0, which means centred,
   upright and fully visible, and the loop never writes a value until the
   tree is really in the document. Doing nothing leaves the page correct. */

/* --------------------------------------------------------------------------
   Tilt — surfaces that turn to face the cursor

   The rotation is small on purpose. Past about six degrees a white card stops
   reading as paper catching the light and starts reading as a game menu, so
   the per-element cap lives in the markup and the default here is modest.

   The transition swap is what makes it feel physical: half a second is right
   for settling back to flat and far too slow to track a cursor, so the fast
   one is only in force while the pointer is actually on the surface.
   -------------------------------------------------------------------------- */
.js-tilt {
  transform:
    perspective(1100px)
    rotateX(calc(var(--rx, 0) * 1deg))
    rotateY(calc(var(--ry, 0) * 1deg))
    translate3d(0, var(--lift, 0px), 0);
  transition: transform .55s var(--ease), box-shadow .45s ease, border-color .45s ease;
}
.js-tilt.tilting { transition: transform .1s linear, box-shadow .45s ease, border-color .45s ease; }
.js-tilt:hover { --lift: -5px; }

/* A pool of light under the cursor. Blue rather than white, because white on
   white paper is nothing at all. */
.js-glare { position: relative; }
.js-glare::after {
  content: '';
  position: absolute; inset: 0; z-index: 0;
  border-radius: inherit; pointer-events: none;
  background: radial-gradient(320px circle at var(--gx, 50%) var(--gy, 50%),
              rgba(47, 107, 255, .11), transparent 62%);
  opacity: 0;
  transition: opacity .4s ease;
}
.js-glare:hover::after { opacity: 1; }

/* --------------------------------------------------------------------------
   Button ink

   Two things: a highlight that follows the cursor across the face, and one
   ripple node per press that removes itself when its animation ends.
   -------------------------------------------------------------------------- */
.js-magnetic::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit; pointer-events: none;
  background: radial-gradient(120px circle at var(--gx, 50%) var(--gy, 50%),
              rgba(255, 255, 255, .22), transparent 62%);
  opacity: 0;
  transition: opacity .35s ease;
}
.js-magnetic:hover::before { opacity: 1; }
.lp-btn-ghost.js-magnetic::before,
.lp-final .lp-btn-primary.js-magnetic::before {
  background: radial-gradient(120px circle at var(--gx, 50%) var(--gy, 50%),
              rgba(47, 107, 255, .18), transparent 62%);
}

.lp-ripple {
  position: absolute; border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .38), transparent 70%);
  transform: scale(0);
  animation: lpRipple .72s var(--ease) forwards;
}
.lp-btn-ghost .lp-ripple,
.lp-final .lp-btn-primary .lp-ripple {
  background: radial-gradient(closest-side, rgba(47, 107, 255, .3), transparent 70%);
}
@keyframes lpRipple {
  from { transform: scale(0); opacity: 1; }
  to   { transform: scale(1); opacity: 0; }
}

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 1080px) {
  .lp-links { display: none; }
  .lp-textbtn { display: none; }
  .lp-burger { display: block; }
  .lp.menu-open .lp-sheet { display: block; }
  .lp-block { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .lp-block.flip > .lp-copy-w { order: 0; }
  .lp-plansec-in { grid-template-columns: minmax(0, 1fr); }
  .lp-figs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 0; }
  .lp-fig:nth-child(3)::before { display: none; }
  .lp-xgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lp-plans { grid-template-columns: minmax(0, 1fr); max-width: 520px; margin-inline: auto; }
  .lp-plan-w.feat { order: -1; }
  /* Stacked, the pinned climb has nothing to pin to and the card would
     scroll away from its own caption. It becomes a plain sequence. */
  .cl-body { min-height: 0; }
  .cl-pin { position: static; height: auto; padding: 0; display: block; }
  .cl-grid { grid-template-columns: minmax(0, 1fr); max-width: 560px; margin: 0 auto; }
  .cl-left { order: 2; }
  .cl-stages { min-height: 200px; }
  /* A 26-degree tilt needs width to look like perspective rather than like
     a mistake, and the window is nearly viewport-wide down here. */
  .lp-stage-persp .lp-window { transform: scale(calc(.96 + var(--p) * .04)); }
  /* Nor is there room for a panel to turn away from an edge it no longer
     has: the blocks are stacked at this width, so a lift and a little tip
     is all that is left of the parallax. */
  .lp-block-vis .js-3d {
    transform:
      translate3d(0, calc(var(--c, 0) * -26px), 0)
      rotateX(calc(var(--c, 0) * 7deg))
      skewY(calc(var(--vel, 0) * .6deg));
    opacity: calc(1 - var(--ac, 0) * .4);
  }
}

@media (max-width: 900px) {
  .lp-scr-in.split { grid-template-columns: minmax(0, 1fr); }
  .lp-scr-side { border-left: 0; border-top: 1px solid var(--line); }
  .lp-exam-body { grid-template-columns: minmax(0, 1fr); }
  .lp-exam-ref { border-left: 0; border-top: 1px solid var(--line); padding-left: 0; padding-top: 18px; }
  .lp-exam-bar { flex-wrap: wrap; }
  .lp-exam-clock { margin: 0; order: 3; }
  .lp-an-top { grid-template-columns: minmax(0, 1fr); }
  .lp-an-bars { grid-template-columns: minmax(0, 1fr); }
  .lp-foot-in { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .lp-foot-brand { grid-column: span 2; }
}

@media (max-width: 620px) {
  /* Sideways entrances need a gutter to come in from. At this width there
     isn't one — the block is nearly the whole screen — so a 46px lateral
     offset is 46px of panel hanging off the edge until it lands. */
  .rv.rv-l, .rv.rv-r { transform: translate3d(0, 32px, 0); }
  /* The headline sits closest to the viewer in the hero's 3D scene, which
     scales it about nine per cent. On a phone that eats the gap under the
     badge, so the gap is given back. */
  .lp-h1 { margin-top: 34px; }
  .lp-figs { grid-template-columns: minmax(0, 1fr); }
  .lp-fig + .lp-fig::before { display: none; }
  .lp-fig { padding-left: 0; padding-right: 0; }
  .lp-xgrid { grid-template-columns: minmax(0, 1fr); }
  .lp-cta-row { flex-direction: column; align-items: stretch; }
  .lp-btn-lg { padding: 16px 24px; font-size: 15.5px; }
  .lp-badge { font-size: 11.5px; gap: 7px; padding: 6px 10px 6px 11px; }
  .lp-an-row { grid-template-columns: minmax(0, 110px) minmax(0, 1fr) 38px; gap: 9px; }
  .lp-srow { grid-template-columns: minmax(0, 120px) minmax(0, 1fr) 40px; gap: 10px; }
  .lp-navdots { display: none; }
  .lp-exam-count { margin-right: auto; }
  .lp-faq-q { font-size: 16px; padding: 20px 4px; gap: 14px; }
  .lp-faq-a p { padding: 0 30px 22px 4px; }
  .lp-pers { width: 100%; }
  .lp-per { flex: 1; justify-content: center; padding: 10px 8px; font-size: 13px; }
  .cl-secs { grid-template-columns: minmax(0, 1fr); }
  .lp-panel-foot.duel { flex-wrap: wrap; }
}

/* ==========================================================================
   Reduced motion

   Everything ambient stops. Everything that starts at opacity 0 is put back
   to visible rather than left mid-transition, because the reveal classes
   never arrive when the observer is bypassed.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .lp-bloom, .lp-tick-track, .lp-badge-dot, .lp-final-mark, .pl-end-halo,
  .lp-final-in::before, .lp-plan.featured::before { animation: none !important; }
  .rv, .rv.in, .rv.rv-l, .rv.rv-r, .rv.rv-up { opacity: 1; transform: none; transition: none; filter: none; }
  .lp-mln-i { transform: none; transition: none; }
  .lp-w, .lp-badge, .lp-lede, .lp-cta-row, .lp-proof, .lp-h1 { opacity: 1; transform: none; filter: none; animation: none; }
  .lp-wm { overflow: visible; }
  .lp-hero, .lp-hero-in { transform: none; opacity: 1; filter: none; }
  /* Every scroll-scrubbed plane goes flat and fully visible. --c is never
     written when reduced, but these all read it with a fallback and a page
     that depended on that fallback would be one bad default from invisible
     content — so they are pinned here as well. */
  .lp-block-vis .js-3d, .lp-copy-w, .lp-fig-in, .lp-xwrap,
  .lp-plansec-panel, .lp-plan-w, .lp-head.js-3d, .lp-faq-row.js-3d {
    transform: none !important; opacity: 1 !important;
  }
  .lp-btn-t > span, .lp-btn-t::after { transition: none; }
  .lp-btn:hover .lp-btn-t > span { transform: none; opacity: 1; }
  .lp-btn:hover .lp-btn-t::after { transform: translateY(115%); opacity: 0; }
  .lp-btn:hover svg:last-child { transform: none; }
  .lp-stage-persp .lp-window,
  .lp-stage-persp .lp-window-3d { transform: none; animation: none; }
  .lp-window::before, .lp-window::after { display: none; }
  .lp-plan { animation: none; }
  .js-tilt { transform: none !important; transition: none; }
  .js-glare::after, .js-magnetic::before, .lp-ripple { display: none; }
  .lp-scr.on, .lp-scr.out { animation: none; }
  .lp-scr.out { visibility: hidden; }
  .lp-tabs-ind { transition: opacity .2s ease; }
  .lp-chip:hover, .lp-xcard:hover .lp-xic { transform: none; }
  .cl-od-c > i { transition: none; }
  .lp-mast-bar i, .lp-an-track i, .lp-srow-track i { width: var(--w); animation: none !important; }
  .lp-cal i { opacity: 1; animation: none !important; }
  .js-parallax { transform: none !important; }
  /* The climb stops being a climb: the report shows its finished state and
     every caption is simply present, so nothing depends on scrolling. */
  .cl-body { min-height: 0; }
  .cl-pin { position: static; height: auto; padding: 0; display: block; }
  .cl-stages { min-height: 0; }
  .cl-stage { position: static; opacity: 1; transform: none; margin-bottom: 24px; }
}

/* ==========================================================================
   Sign in
   ========================================================================== */
.si { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 24px; }
.si-wrap { width: 100%; max-width: 420px; }

.si-back {
  position: fixed; top: 24px; left: 24px; z-index: 5;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 10px 16px 10px 12px;
  border: 1px solid var(--line); border-radius: 11px;
  background: #fff;
  box-shadow: var(--sh-1);
  color: var(--ink-2);
  font: 500 14px var(--f-ui); cursor: pointer;
  transition: color .2s ease, border-color .2s ease, background .2s ease;
}
.si-back:hover { color: var(--ink); border-color: var(--line-2); background: var(--wash); }
.si-back svg { width: 16px; height: 16px; }

.si-card {
  padding: clamp(32px, 5vw, 48px) clamp(24px, 4vw, 40px);
  text-align: center;
  border: 1px solid var(--line); border-radius: 24px;
  background: #fff;
  box-shadow: var(--sh-4);
  animation: lpFadeUp .9s var(--ease) both;
}
/* Brand lockup: the character on his own beside the wordmark. No tile behind
   him — that black rounded square belongs to the app icon, and reproducing it
   here made the header look like a screenshot of an app rather than a logo. */
.si-brand {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  margin-bottom: 20px;
}
.si-mark { display: block; width: 44px; height: 44px; flex: none; }
.si-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
.si-word {
  font-family: var(--f-display); font-weight: 700; font-size: 25px;
  letter-spacing: -.035em; color: var(--ink);
}
.si-word b { color: var(--blue); font-weight: 700; }

.si-h1 { font-size: clamp(24px, 3vw, 30px); margin: 0 0 22px; line-height: 1.12; letter-spacing: -.045em; }

/* --- Providers -----------------------------------------------------------
   Stacked full-width rows. Google's row is Google's own button, rendered by
   GSI at its own size and left alone — see the long note in signin.js for why
   nothing here tries to restyle it. Apple's is ours, matched to it as closely
   as a different vendor's button allows. */
.si-providers { display: grid; gap: 10px; }
.si-provider {
  display: flex; align-items: center; justify-content: center; gap: 11px;
  /* GSI renders its large button at a fixed 40px and won't be told otherwise,
     so Apple meets it near the middle rather than towering over it. */
  width: 100%; min-height: 44px;
  /* Fully rounded, to match the pill GSI renders next to it. */
  border-radius: 999px;
  font: 600 15px var(--f-ui);
  cursor: pointer;
  transition: transform .2s var(--ease), box-shadow .3s ease, background .2s ease;
}
.si-provider svg { width: 20px; height: 20px; flex: none; }
.si-provider:hover { transform: translateY(-2px); }
.si-provider:active { transform: translateY(0); }

.si-btn-apple { background: #000; color: #fff; border: 1px solid #000; box-shadow: var(--sh-2); }
.si-btn-apple:hover { background: #1A1A1A; box-shadow: var(--sh-3); }
.si-provider:disabled { opacity: .55; cursor: default; transform: none; }

/* Google's iframe brings its own frame and background, so this row is only a
   place to put it — no border, no hover lift of our own that would slide the
   button out from under the cursor mid-press.

   GSI renders its large button at a fixed 40px and offers no way to ask for
   more, which left it visibly shorter than the 44px Apple button beside it.
   So it is scaled the missing 10% instead. account.js renders it at
   width ÷ 1.1 so the scaled result lands back on the card's full width, and
   the row keeps Apple's height so the gap below stays even. Scaling does not
   cost the click — GSI only refuses when its button is hidden, not when it is
   resized. */
.si-provider-google {
  padding: 0; background: none;
  min-height: 44px;
  display: grid; place-items: center;
}
.si-provider-google:hover { transform: none; }
.si-gsi {
  display: flex; justify-content: center;
  transform: scale(1.1);
  transform-origin: center;
}
.si-provider-google.busy { opacity: .55; pointer-events: none; }
.si-provider-google.dead { opacity: .5; }

/* --- Divider -------------------------------------------------------------- */
.si-or {
  display: flex; align-items: center; gap: 14px;
  margin: 22px 0 18px;
  color: var(--ink-3); font-size: 13px;
}
.si-or::before, .si-or::after {
  content: ''; flex: 1; height: 1px; background: var(--line);
}

/* --- Email ---------------------------------------------------------------- */
.si-label {
  display: block; text-align: left;
  font: 600 13px var(--f-ui); color: var(--ink-2); margin-bottom: 7px;
}
.si-input {
  width: 100%; padding: 14px 18px;
  border: 1px solid transparent; border-radius: 999px;
  background: var(--wash);
  font: 500 15px var(--f-ui); color: var(--ink);
  transition: var(--t);
}
.si-input::placeholder { color: var(--ink-3); }
.si-input:focus {
  outline: none; background: #fff;
  border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0, 166, 255, .16);
}
.si-email-btn {
  width: 100%; margin-top: 12px; padding: 15px 20px;
  border: 0; border-radius: 999px;
  background: var(--ink); color: #fff;
  font: 600 15px var(--f-ui); cursor: pointer;
  transition: transform .2s var(--ease), background .2s ease, box-shadow .3s ease;
}
.si-email-btn:hover { transform: translateY(-2px); background: #1A1A1A; box-shadow: var(--sh-3); }
.si-email-btn:active { transform: translateY(0); }
.si-email-btn:disabled, .si-input:disabled { opacity: .55; cursor: default; transform: none; }

/* The code step. One field, six digits, spaced out so they can be read back
   off a phone screen without losing your place. */
/* `display: block` here would quietly beat the UA's `[hidden] { display:none }`
   — author styles win over the user-agent sheet — and both steps would show
   at once. Stated explicitly so hiding a step actually hides it. */
.si-step[hidden] { display: none; }
.si-sent {
  margin: 0 0 12px; font-size: 13.5px; line-height: 1.5; color: var(--ink-2);
  text-align: center;
}
.si-code {
  text-align: center;
  font: 700 22px var(--f-num, var(--f-ui));
  letter-spacing: .38em;
  text-indent: .38em;          /* re-centres text that letter-spacing pushes left */
  padding: 14px 16px;
}
.si-code::placeholder { color: var(--slate-300); letter-spacing: .38em; }
.si-resend-row {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  margin-top: 14px; flex-wrap: wrap;
}
.si-resend {
  border: 0; background: none; padding: 0;
  font: 600 13px var(--f-ui); color: var(--ink-2);
  cursor: pointer;
}
.si-resend:hover { color: var(--ink); text-decoration: underline; }
.si-resend-alt { color: var(--ink-3); }
.si-resend:disabled { opacity: .5; cursor: default; text-decoration: none; }

/* --- Switch between signing in and signing up ----------------------------- */
.si-switch { margin: 18px 0 0; font-size: 14px; color: var(--ink-2); }
.si-switch-link {
  border: 0; background: none; padding: 0;
  font: 700 14px var(--f-ui); color: var(--ink);
  cursor: pointer; text-decoration: none;
}
.si-switch-link:hover { text-decoration: underline; }

/* Sign-in failure. Sits between the controls and the fine print so the
   explanation appears where the click just happened, rather than as a toast
   that has vanished by the time it is read. */
.si-err {
  margin: 14px 0 0;
  padding: 11px 14px;
  border: 1px solid rgba(217, 74, 74, .32);
  border-radius: 11px;
  background: var(--red-tint);
  font-size: 13px; font-weight: 500; line-height: 1.5;
  color: #B33A3A;
  text-align: left;
}
/* The same box carries the good news after an email is sent — one place for
   "here is what just happened", whichever way it went. */
.si-err.ok {
  border-color: rgba(14, 159, 110, .32);
  background: var(--green-tint);
  color: var(--green);
}

.si-fine { margin: 22px 0 0; font-size: 12px; line-height: 1.6; color: var(--ink-3); }
