/* Mint — Vinyl Genius · mint-app.io
   Dark-first, editorial. Built by tools/website/build.py into one page per
   language; every page shares this file. Logical properties (inline-start /
   inline-end) keep the layout correct in Hebrew (dir="rtl"). */
:root {
  --ink: #0A0A0B;
  --ink-2: #111114;
  --ink-3: #18181C;
  --line: rgba(255,255,255,0.08);
  --line-strong: rgba(255,255,255,0.18);
  --fg: #F4F1EA;
  --fg-dim: rgba(244,241,234,0.68);
  --fg-faint: rgba(244,241,234,0.56);
  --accent: #3ADCE6;
  --accent-soft: rgba(58,220,230,0.12);
  --accent-ink: #041418;
  --radius: 14px;
  --maxw: 1240px;
  --gutter: clamp(16px, 4vw, 40px);
  --sans: "Inter Tight", "Inter", system-ui, -apple-system, "Segoe UI", "Noto Sans", "Hiragino Sans", "Apple SD Gothic Neo", sans-serif;
  --serif: "Instrument Serif", "Times New Roman", serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { scroll-behavior: smooth; scroll-padding-top: 80px; }
body {
  background: var(--ink);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: inherit; }
h1, h2, h3 { margin: 0; font-weight: 500; letter-spacing: -0.025em; line-height: 1.02; }
h2 { font-size: clamp(36px, 5.4vw, 68px); }
h3 { font-size: 22px; letter-spacing: -0.01em; line-height: 1.2; }
p { margin: 0; color: var(--fg-dim); }

.serif { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: -0.01em; }
.accent { color: var(--accent); }
.mono { font-family: var(--mono); }
/* Scripts Inter Tight lacks: name the right system font first so Chinese
   gets Traditional or Simplified glyph shapes (not the Japanese face in the
   default stack), and Thai gets Noto Sans Thai (loaded on the Thai pages
   only, see build.py). Menu links in another language pick up their own. */
:lang(zh-Hant) { --sans: "Inter Tight", "Inter", "PingFang TC", "Hiragino Sans CNS", "Microsoft JhengHei", "Noto Sans TC", "Noto Sans CJK TC", system-ui, -apple-system, sans-serif; }
:lang(zh-Hans) { --sans: "Inter Tight", "Inter", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", "Noto Sans CJK SC", system-ui, -apple-system, sans-serif; }
:lang(th) { --sans: "Inter Tight", "Inter", "Noto Sans Thai", "Thonburi", "Leelawadee UI", "Tahoma", system-ui, -apple-system, sans-serif; }
.lang-menu a[lang], .langs a[lang] { font-family: var(--sans); }

/* Instrument Serif is Latin-only; an italic fallback for Hebrew, Greek,
   Cyrillic, Thai and CJK is a fake oblique, so those keep the sans face in
   accent colour. */
:is(:lang(he), :lang(ja), :lang(ko), :lang(el), :lang(zh), :lang(th), :lang(uk)) .serif {
  font-family: var(--sans); font-style: normal; font-weight: 600; letter-spacing: -0.03em;
}
/* Thai and Chinese have no capitals and no glyphs in JetBrains Mono. */
:is(:lang(he), :lang(ja), :lang(ko), :lang(el), :lang(zh), :lang(th)) :is(.eyebrow, .kicker, .mode-tag, .price-row .k, .badge, .foot h4) {
  font-family: var(--sans); letter-spacing: 0; text-transform: none; font-weight: 500;
}
:is(:lang(he), :lang(ja), :lang(ko), :lang(el), :lang(zh), :lang(th)) :is(.eyebrow, .kicker, .badge) { font-size: 13px; }
/* Thai marks stack above and below the line; tight display leading clips them. */
html:lang(th) :is(h1, h2, h1 .serif, h2 .serif) { line-height: 1.22; letter-spacing: -0.01em; }
html:lang(th) h3 { line-height: 1.35; }

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
.skip { position: absolute; inset-inline-start: -999px; top: 8px; z-index: 100; background: var(--accent); color: var(--accent-ink); padding: 8px 12px; border-radius: 8px; }
.skip:focus { inset-inline-start: 8px; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

/* ---------- Top bar ---------- */
.topbar {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in oklab, var(--ink) 82%, transparent);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--line);
}
.topbar-inner {
  max-width: var(--maxw); margin: 0 auto;
  padding: 12px var(--gutter);
  display: flex; align-items: center; gap: 24px;
}
.brand img { height: 26px; width: auto; }
.nav { display: flex; gap: 26px; margin-inline-start: auto; }
.nav a { color: var(--fg-dim); text-decoration: none; font-size: 14px; transition: color .2s; }
.nav a:hover { color: var(--fg); }
.topbar-right { display: flex; align-items: center; gap: 10px; }

.lang { position: relative; }
.lang summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--fg-dim); padding: 9px 10px; border: 1px solid var(--line-strong); border-radius: 999px;
}
.lang summary::-webkit-details-marker { display: none; }
.lang summary:hover { color: var(--fg); border-color: var(--fg-faint); }
.lang svg { width: 14px; height: 14px; }
.lang-menu {
  position: absolute; inset-inline-end: 0; top: calc(100% + 8px);
  background: var(--ink-3); border: 1px solid var(--line-strong); border-radius: 14px;
  padding: 6px; width: min(340px, calc(100vw - 32px));
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px;
  box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
.lang-menu a {
  text-decoration: none; font-size: 14px; color: var(--fg-dim);
  padding: 8px 10px; border-radius: 8px;
}
.lang-menu a:hover { background: var(--accent-soft); color: var(--fg); }
.lang-menu a[aria-current="true"] { color: var(--accent); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 44px; padding: 10px 18px;
  font: 500 14px/1 var(--sans);
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: transparent; color: var(--fg); text-decoration: none; cursor: pointer;
  transition: border-color .2s, background .2s, transform .2s;
  white-space: nowrap;
}
.btn:hover { border-color: var(--fg); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 600; }
.btn-primary:hover { background: #6BE7EE; border-color: #6BE7EE; transform: translateY(-1px); }
.btn svg { width: 18px; height: 18px; flex: none; }
.btn-lg { min-height: 54px; padding: 14px 24px; font-size: 16px; }

/* ---------- Hero ---------- */
.hero { position: relative; padding: clamp(48px, 8vw, 104px) 0 clamp(48px, 6vw, 80px); overflow: hidden; }
.hero::before {
  content: ""; position: absolute; inset: -20% -10% auto auto; width: 70vw; height: 70vw; max-width: 900px; max-height: 900px;
  background: radial-gradient(closest-side, rgba(58,220,230,.16), transparent 70%);
  pointer-events: none;
}
[dir="rtl"] .hero::before { inset: -20% auto auto -10%; }
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 48px; align-items: center; position: relative; }
.eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--accent); background: var(--accent-soft); border: 1px solid rgba(58,220,230,.25);
  padding: 7px 12px; border-radius: 999px; margin-bottom: 28px;
}
.eyebrow .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 4px rgba(58,220,230,.18); }
.hero h1 { font-size: clamp(48px, 8.2vw, 112px); letter-spacing: -0.045em; line-height: .94; }
.hero h1 .serif { display: block; color: var(--accent); letter-spacing: -0.035em; }
.hero-sub { font-size: clamp(17px, 1.6vw, 20px); max-width: 540px; margin-top: 28px; }
.hero-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }
.hero-note { margin-top: 18px; font-size: 13px; color: var(--fg-faint); display: flex; flex-wrap: wrap; gap: 6px 18px; }
.hero-note span::before { content: "✓"; color: var(--accent); margin-inline-end: 6px; }

.phones { position: relative; height: clamp(440px, 52vw, 640px); }
.phone { position: absolute; width: 50%; }
.phone-a { inset-inline-start: 4%; top: 2%; transform: rotate(-4deg); z-index: 2; }
.phone-b { inset-inline-end: 4%; top: 12%; transform: rotate(5deg); width: 46%; }
@media (prefers-reduced-motion: no-preference) {
  .phone-a { animation: float-a 7s ease-in-out infinite; }
  .phone-b { animation: float-b 8s ease-in-out infinite; }
}
@keyframes float-a { 50% { transform: rotate(-4deg) translateY(-10px); } }
@keyframes float-b { 50% { transform: rotate(5deg) translateY(8px); } }

.facts {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--line); margin-top: clamp(48px, 6vw, 80px);
}
.fact { padding: 24px 24px 0 0; padding-inline: 0 24px; }
.fact + .fact { border-inline-start: 1px solid var(--line); padding-inline-start: 24px; }
.fact .n { font-size: clamp(30px, 3.4vw, 44px); letter-spacing: -0.03em; line-height: 1; font-weight: 500; }
.fact .l { font-size: 13px; color: var(--fg-faint); margin-top: 10px; }

/* ---------- Languages strip ---------- */
.langs { border-block: 1px solid var(--line); overflow: hidden; padding: 18px 0; }
.langs-track { display: flex; gap: 44px; width: max-content; font-size: 22px; color: var(--fg-faint); white-space: nowrap; }
.langs-track a { text-decoration: none; transition: color .2s; }
.langs-track a:hover, .langs-track a[aria-current="true"] { color: var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  .langs-track { animation: marquee 60s linear infinite; }
  .langs:hover .langs-track { animation-play-state: paused; }
  [dir="rtl"] .langs-track { animation-name: marquee-rtl; }
}
@keyframes marquee { to { transform: translateX(-50%); } }
@keyframes marquee-rtl { to { transform: translateX(50%); } }

/* ---------- Sections ---------- */
section { padding: clamp(72px, 10vw, 136px) 0; }
.kicker {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--fg-faint); margin-bottom: 28px;
}
.kicker b { color: var(--accent); font-weight: 500; }
.kicker::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.head { display: grid; grid-template-columns: 1.2fr .8fr; gap: 32px; align-items: end; margin-bottom: clamp(40px, 5vw, 64px); }
.head p { font-size: 17px; max-width: 440px; }

/* Modes */
.modes-list { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.modes-stage { display: none; }
.mode-shot .iphone { width: 100%; }
.mode {
  background: var(--ink-2); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px; display: flex; flex-direction: column; gap: 14px;
  transition: border-color .3s, transform .3s;
}
.mode:hover { border-color: rgba(58,220,230,.45); transform: translateY(-4px); }
.mode-shot {
  aspect-ratio: 4 / 5; overflow: hidden; padding: 6px 12% 0;
  -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent);
  mask-image: linear-gradient(to bottom, #000 72%, transparent);
}
.mode-tag { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); }
.mode p { font-size: 15px; }

/* Value */
.value { background: var(--ink-2); border-block: 1px solid var(--line); }
.value-grid { display: grid; grid-template-columns: .9fr 1.1fr; gap: clamp(32px, 6vw, 88px); align-items: center; }
.value-phone { width: min(300px, calc(78vh * .479)); margin-inline: auto; }
.price-rows { display: grid; gap: 0; margin: 36px 0 32px; border-top: 1px solid var(--line); }
.price-row { display: grid; grid-template-columns: auto 1fr; gap: 6px 20px; padding: 18px 0; border-bottom: 1px solid var(--line); }
.price-row .k { font-family: var(--mono); font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--accent); padding-top: 4px; min-width: 120px; }
.price-row .v { color: var(--fg); font-size: 17px; }
.price-row .v small { display: block; color: var(--fg-dim); font-size: 14px; margin-top: 2px; }
.pro-pill { display: inline-block; font-family: var(--mono); font-size: 10px; letter-spacing: .1em; color: var(--accent-ink); background: var(--accent); padding: 2px 7px; border-radius: 999px; vertical-align: 2px; margin-inline-start: 6px; }

/* Features */
.features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.feature { border: 1px solid var(--line); border-radius: var(--radius); padding: 28px; background: linear-gradient(180deg, var(--ink-2), var(--ink)); }
.feature .ic { width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); margin-bottom: 22px; }
.feature .ic svg { width: 20px; height: 20px; }
.feature h3 { margin-bottom: 10px; }
.feature p { font-size: 15px; }

.gallery { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-top: 56px; }
.gallery { padding-bottom: 24px; }

/* Pricing */
.billing { display: inline-flex; padding: 4px; border: 1px solid var(--line-strong); border-radius: 999px; gap: 4px; }
.billing button { all: unset; cursor: pointer; padding: 9px 16px; border-radius: 999px; font-size: 14px; color: var(--fg-dim); }
.billing button[aria-pressed="true"] { background: var(--fg); color: var(--ink); }
.billing button:focus-visible { outline: 2px solid var(--accent); }
.plans { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.plan { border: 1px solid var(--line); border-radius: 20px; padding: clamp(24px, 3vw, 40px); display: flex; flex-direction: column; background: var(--ink-2); }
.plan-pro { border-color: rgba(58,220,230,.5); background: radial-gradient(120% 80% at 100% 0%, rgba(58,220,230,.12), transparent 60%), var(--ink-2); }
.plan-top { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.plan-name { font-size: 28px; font-weight: 500; letter-spacing: -0.02em; }
.badge { font-family: var(--mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; padding: 5px 10px; border-radius: 999px; border: 1px solid var(--line-strong); color: var(--fg-dim); }
.plan-pro .badge { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.plan-price { margin: 22px 0 6px; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.plan-price strong { font-size: clamp(44px, 5vw, 60px); font-weight: 500; letter-spacing: -0.04em; line-height: 1; }
.plan-price span { color: var(--fg-dim); }
.plan-note { font-size: 13px; color: var(--fg-faint); min-height: 1.5em; }
.plan ul { list-style: none; padding: 0; margin: 28px 0 32px; display: grid; gap: 12px; flex: 1; }
.plan li { display: flex; gap: 12px; font-size: 15px; color: var(--fg); }
.plan li::before { content: ""; flex: none; width: 18px; height: 18px; margin-top: 2px; border-radius: 50%; background: var(--accent-soft) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233ADCE6' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5L20 7'/%3E%3C/svg%3E") center/11px no-repeat; }
.plan .btn { width: 100%; white-space: normal; text-align: center; line-height: 1.25; }
.plans > *, .hero-grid > *, .head > *, .value-grid > * { min-width: 0; }
.fine { font-size: 13px; color: var(--fg-faint); margin-top: 20px; text-align: center; }

/* FAQ */
.faq { max-width: 860px; margin: 0 auto; border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  list-style: none; cursor: pointer; padding: 24px 0;
  display: flex; align-items: center; gap: 20px; font-size: clamp(17px, 2vw, 20px); font-weight: 500;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; margin-inline-start: auto; font-family: var(--mono); font-size: 22px; color: var(--accent); transition: transform .25s; }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq details p { padding: 0 0 26px; max-width: 720px; font-size: 16px; }

/* CTA band */
.cta { text-align: center; }
.cta h2 { font-size: clamp(40px, 6.4vw, 88px); }
.cta p { margin: 20px auto 36px; max-width: 520px; font-size: 17px; }

/* Footer */
footer { border-top: 1px solid var(--line); padding: 56px 0 40px; }
.foot { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 32px; }
.foot h4 { margin: 0 0 14px; font-family: var(--mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--fg-faint); font-weight: 500; }
.foot a { display: block; text-decoration: none; color: var(--fg-dim); font-size: 14px; padding: 4px 0; }
.foot a:hover { color: var(--fg); }
.foot p { font-size: 14px; max-width: 320px; margin-top: 16px; }
.foot-bottom { margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--fg-faint); }

/* Reveal: only when JS has run, and never for the hero (it is the LCP). */
.js .reveal { opacity: 0; transform: translateY(24px); transition: opacity .9s cubic-bezier(.22,.61,.36,1), transform .9s cubic-bezier(.22,.61,.36,1); }
.js .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
}

/* ---------- Responsive ---------- */
@media (max-width: 1020px) {
  .nav { display: none; }
  .topbar-right { margin-inline-start: auto; }
  .modes-list { grid-template-columns: repeat(2, 1fr); }
  .features { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 820px) {
  .hero-grid, .head, .value-grid, .plans { grid-template-columns: 1fr; }
  .phones { height: auto; aspect-ratio: 1 / 1.05; max-width: 460px; width: 100%; margin: 8px auto 0; }
  .facts { grid-template-columns: 1fr 1fr; }
  .fact:nth-child(3) { border-inline-start: 0; padding-inline-start: 0; }
  .fact { padding-bottom: 20px; }
  .value-phone { width: min(250px, 62vw); }
  .gallery { grid-template-columns: 1fr 1fr; }
  .foot { grid-template-columns: 1fr 1fr; }
  .foot > div:first-child { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .topbar-right .btn-get span { display: none; }
  /* The menu is wider than the space left of the language button on a
     phone; anchor it to the (sticky, so positioned) top bar instead. */
  .lang { position: static; }
  .lang-menu { inset-inline: var(--gutter); top: calc(100% + 8px); width: auto; }
  .modes-list, .features { grid-template-columns: 1fr; }
  .hero-ctas .btn, .cta .btn { width: 100%; white-space: normal; text-align: center; line-height: 1.25; }
  .price-row { grid-template-columns: 1fr; }
}

/* ---------- Scroll choreography ----------
   Only with .fx (JS ran and the visitor allows motion). site.js publishes
   each [data-fx] element's scroll progress: --p (0 → 1 across the viewport,
   or while the hero scrolls away) and --e (0 → 1 while it enters). --dir
   mirrors every sideways turn for Hebrew. */
:root { --dir: 1; --amp: 1; }
/* 3D-turned phones must not widen the page; clip (not hidden) keeps the
   pinned scan-modes stage sticky. */
.fx main { overflow-x: clip; }
[dir="rtl"] { --dir: -1; }
/* On phone-sized screens a phone fills most of the view, so big turns read
   as the device falling over: every turn is scaled down there. */
@media (max-width: 820px) { :root { --amp: .55; } }

/* Hero: the phones arrive turned in 3D, then square up and lift away as the
   page scrolls while the copy drifts up and fades. */
.fx .phones { perspective: 1400px; }
.fx .phone { animation: none; will-change: transform; transform-style: preserve-3d; }
.fx .phone-a {
  transform:
    translate3d(0, calc(var(--p, 0) * -110px), 0)
    rotateX(calc((18deg - var(--p, 0) * 14deg) * var(--amp)))
    rotateY(calc((-42deg + var(--p, 0) * 54deg) * var(--dir) * var(--amp)))
    rotateZ(calc((-6deg + var(--p, 0) * 4deg) * var(--dir)))
    scale(calc(1 + var(--p, 0) * .08));
}
.fx .phone-b {
  transform:
    translate3d(calc(var(--p, 0) * 90px * var(--dir)), calc(var(--p, 0) * -40px), -60px)
    rotateX(calc((14deg - var(--p, 0) * 12deg) * var(--amp)))
    rotateY(calc((44deg - var(--p, 0) * 56deg) * var(--dir) * var(--amp)))
    rotateZ(calc((7deg - var(--p, 0) * 4deg) * var(--dir)));
}
.fx .phone .iphone { animation: phone-in 1.4s cubic-bezier(.16,1,.3,1) both; }
.fx .phone-b .iphone { animation-delay: .15s; }
@keyframes phone-in { from { opacity: 0; transform: translateY(80px) scale(.94); } }
.fx .hero-grid > div:first-child {
  transform: perspective(1000px) translate3d(0, calc(var(--p, 0) * -90px), 0) rotateX(calc(var(--p, 0) * 28deg)) scale(calc(1 - var(--p, 0) * .08));
  transform-origin: 50% 100%;
  opacity: calc(1 - var(--p, 0) * 1.3);
}

/* Headings light up word by word as they scroll in. */
.fx .w {
  display: inline-block; opacity: .08; transform-origin: 50% 100%;
  transform: perspective(700px) translateY(.45em) rotateX(62deg);
  filter: blur(6px);
  transition: opacity .7s ease, transform .9s cubic-bezier(.16,1,.3,1), filter .7s ease;
}
.fx .w.lit { opacity: 1; transform: none; filter: none; }

/* Reveals come up out of the page rather than just fading. */
.fx .reveal { transform: perspective(1100px) translateY(56px) rotateX(calc(22deg * var(--amp))) scale(.96); transform-origin: 50% 0; }
.fx .reveal.in { transform: none; }

/* Cards lean toward the pointer once they have revealed. */
.fx .tilt.in { transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); }
.fx .tilt.in.tilting { transition: transform .12s ease-out; }

/* Value: the phone stands up out of the page as it enters; each price row
   lights in turn. */
/* Value: the phone turns like on a turntable as the section crosses the
   screen, rising and squaring up a little as it enters. It used to lie back
   by up to 52°, which on a phone looked like it was falling over. */
.fx .value-phone {
  transform:
    perspective(1800px)
    translateY(calc((1 - var(--e, 1)) * 60px))
    rotateX(calc((1 - var(--e, 1)) * 12deg))
    rotateY(calc((var(--p, .5) - .5) * -70deg * var(--dir) * var(--amp)))
    scale(calc(.92 + var(--e, 1) * .08));
  transform-origin: 50% 50%;
  transform-style: preserve-3d;
  will-change: transform;
}
.fx .price-row { opacity: .28; transform: translateX(calc(-18px * var(--dir))); transition: opacity .7s ease, transform .7s cubic-bezier(.16,1,.3,1); }
.fx .price-row.lit { opacity: 1; transform: none; }

/* Gallery: the four phones fan in from 3D and drift at different speeds. */
.fx .gallery { perspective: 1400px; }
/* No opacity here: it would flatten the phones' 3D edge. */
.fx .gallery .iphone {
  transform:
    translateY(calc((.5 - var(--p, .5)) * var(--k) * 150px))
    rotateY(calc((var(--r) * (1 - var(--e, 1)) * 75deg + (.5 - var(--p, .5)) * 36deg) * var(--dir) * var(--amp)))
    scale(calc(.88 + var(--e, 1) * .12));
}
.fx .gallery .iphone:nth-child(1) { --k: 1;   --r: 1; }
.fx .gallery .iphone:nth-child(2) { --k: -.5; --r: .45; }
.fx .gallery .iphone:nth-child(3) { --k: .5;  --r: -.45; }
.fx .gallery .iphone:nth-child(4) { --k: -1;  --r: -1; }

/* Closing call to action grows into place. */
.fx .cta h2 { transform: scale(calc(.82 + var(--e, 1) * .18)); transform-origin: 50% 100%; }

/* Scan modes, desktop: one phone stays pinned while the four steps scroll
   past; each step turns the phone to its screen. */
@media (min-width: 1021px) {
  .fx .modes { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(40px, 6vw, 96px); align-items: start; }
  .fx .modes-stage {
    display: block; position: sticky; top: calc(50vh - min(36vh, 330px) + 30px);
    height: min(72vh, 660px); perspective: 1600px;
  }
  .fx .stage-phone {
    height: 100%; aspect-ratio: .479; margin-inline: auto;
    transform-style: preserve-3d;
    transform:
      rotateX(10deg)
      rotateY(calc((.5 - var(--p, 0)) * 90deg * var(--dir)))
      rotateZ(calc((.5 - var(--p, 0)) * -6deg * var(--dir)));
  }
  /* The phone turns as the steps scroll; its screen changes per step. */
  .fx .stage-phone .ip-screen img { opacity: 0; transform: scale(1.06); transition: opacity .6s ease, transform .9s cubic-bezier(.16,1,.3,1); }
  .fx .stage-phone .ip-screen img.is-active { opacity: 1; transform: none; }
  .fx .modes-list { display: block; }
  .fx .modes-list .mode {
    min-height: 72vh; justify-content: center; gap: 18px;
    background: none; border: 0; padding: 0;
  }
  .fx .modes-list .mode:not(.is-active) { opacity: .25; }
  .fx .modes-list .mode.in { transition: opacity .5s ease, transform .9s cubic-bezier(.22,.61,.36,1); }
  .fx .modes-list .mode:hover { transform: none; }
  .fx .mode-shot { display: none; }
  .fx .modes-list .mode h3 { font-size: clamp(34px, 3.6vw, 52px); letter-spacing: -0.03em; }
  .fx .modes-list .mode p { font-size: 19px; max-width: 440px; }
  .fx .modes-list .mode-tag { font-size: 13px; }
}

/* ---------- 3D iPhone ----------
   Markup from build.py's iphone(): a front (aluminium rim, bezel, screen,
   the smaller iPhone 18 Pro Dynamic Island, glass glare) with twelve
   slices stacked behind it as the rounded metal edge, plus the side
   buttons. Lengths are cqw (percent of the phone's own width), so every
   size shares one geometry. Without .fx nothing is turned, and the edge
   stays hidden behind the front. Never give an .iphone, or anything
   between it and its 3D parent, opacity or filter: both flatten 3D. */
.iphone {
  --hi: #c3c7cd; --mid: #5f646b; --lo: #1c1e22;   /* dark grey aluminium */
  --depth: 11cqw;   /* ~8.3 mm on a ~72 mm wide phone */
  container-type: inline-size;
  position: relative; width: 100%; aspect-ratio: .479;
  transform-style: preserve-3d;
}
.iphone--blue { --hi: #eef5fb; --mid: #a7c2d6; --lo: #4d6a80; }
.iphone--cherry { --hi: #d29aa4; --mid: #722a3a; --lo: #2b0c15; }
.ip-front, .ip-slice, .ip-shadow { position: absolute; inset: 0; border-radius: 16.5cqw; }
.ip-front {
  border: 1.2cqw solid transparent;
  box-shadow: inset 0 0 0 .3cqw rgba(255,255,255,.08);
  background:
    linear-gradient(#030304, #030304) padding-box,
    linear-gradient(135deg, var(--hi), var(--mid) 20%, var(--lo) 42%, var(--mid) 66%, var(--hi) 86%, var(--mid)) border-box;
}
.ip-screen, .ip-glass { position: absolute; inset: 2.1cqw; border-radius: 13.4cqw; }
.ip-screen { overflow: hidden; background: #000; }
.ip-screen img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top; }
/* Sized and placed over the island the screenshots already carry (31% of
   the 93.4cqw screen, centred 7.7% of its width down), in plain black so
   the two read as one capsule. */
.ip-island {
  position: absolute; top: 4.9cqw; left: 50%; width: 29.4cqw; height: 8.8cqw;
  transform: translateX(-50%); border-radius: 99cqw; background: #000;
}
.ip-glass {
  pointer-events: none;
  background: linear-gradient(115deg, transparent 36%, rgba(255,255,255,.12) 47%, rgba(255,255,255,.03) 53%, transparent 62%) 0 0 / 300% 100%;
  background-position: calc(90% - var(--p, .3) * 80%) 0;
}
/* Only a slice's outer rim ever shows (its middle is behind the front), so
   that rim is the metal side: lit from the upper left, still bright on the
   right, brightest half-way through the depth (--s from build.py). Darkening
   the rims, as this first did, hid the side and the phones looked flat. */
.ip-slice {
  background: linear-gradient(105deg,
    color-mix(in srgb, var(--hi) var(--s), var(--mid)) 0%,
    color-mix(in srgb, var(--hi) calc(var(--s) * .8), var(--mid)) 45%,
    color-mix(in srgb, var(--mid) var(--s), var(--lo)) 100%);
  transform: translateZ(calc(var(--i) * var(--depth) / -18));
}
.ip-shadow {
  inset: 5% 7%; background: rgba(0,0,0,.6);
  transform: translateZ(calc(var(--depth) * -1 - 2px));
  box-shadow: 0 6cqw 16cqw 4cqw rgba(0,0,0,.7);
}
/* Buttons stand on the side of the edge, half-way through its depth. */
.ip-btn {
  position: absolute; left: -.5cqw; width: calc(var(--depth) * .5); border-radius: 1cqw;
  background: linear-gradient(90deg, var(--lo), var(--hi) 50%, var(--lo));
  transform-origin: 0 50%;
  transform: translateZ(calc(var(--depth) * -.25)) rotateY(90deg);
}
.ip-action   { top: 18%;   height: 4.4%; }
.ip-vol-up   { top: 25.5%; height: 7.6%; }
.ip-vol-down { top: 34.5%; height: 7.6%; }
.ip-power, .ip-camera { left: auto; right: -.5cqw; transform-origin: 100% 50%; transform: translateZ(calc(var(--depth) * -.25)) rotateY(-90deg); }
.ip-power  { top: 27%; height: 11%; }
.ip-camera { top: 52%; height: 8%; background: linear-gradient(90deg, #111, #4a5260 50%, #111); }

/* ---------- Text choreography ----------
   Load: the hero headline's words flip up one after another (split by
   build.py, --wi = order), then the eyebrow slides in, the paragraph comes
   into focus and the buttons pop. Scroll: section words flip up as they
   light (above), paragraphs sharpen in after their heading, kicker rules
   draw across, facts count up, scan-mode steps roll through, the price
   turns over when the plan changes and FAQ answers drop in. */
.fx .hero h1 .hw {
  display: inline-block; transform-origin: 50% 100%;
  animation: word-up 1.1s cubic-bezier(.16,1,.3,1) both;
  animation-delay: calc(var(--wi) * 85ms + 150ms);
}
@keyframes word-up {
  from { opacity: 0; transform: perspective(700px) translateY(.6em) rotateX(80deg); filter: blur(10px); }
}
.fx .hero .eyebrow { animation: slide-in .9s cubic-bezier(.16,1,.3,1) both; }
@keyframes slide-in { from { opacity: 0; transform: translateX(calc(-40px * var(--dir))); filter: blur(6px); } }
.fx .hero-sub { animation: focus-up 1.1s cubic-bezier(.16,1,.3,1) .65s both; }
@keyframes focus-up { from { opacity: 0; transform: translateY(26px); filter: blur(12px); } }
.fx .hero-ctas .btn { animation: pop-in .8s cubic-bezier(.34,1.56,.64,1) both; animation-delay: .85s; }
.fx .hero-ctas .btn + .btn { animation-delay: .95s; }
@keyframes pop-in { from { opacity: 0; transform: scale(.82) translateY(14px); } }
.fx .hero-note { animation: focus-up 1s cubic-bezier(.16,1,.3,1) 1.1s both; }

/* Facts rise in turn and count up (site.js). */
.fx .fact { opacity: 0; transform: perspective(800px) translateY(36px) rotateX(-30deg); transition: opacity .8s ease, transform 1s cubic-bezier(.16,1,.3,1); }
.fx .facts.in .fact { opacity: 1; transform: none; }
.fx .facts.in .fact:nth-child(2) { transition-delay: .12s; }
.fx .facts.in .fact:nth-child(3) { transition-delay: .24s; }
.fx .facts.in .fact:nth-child(4) { transition-delay: .36s; }
.fx .fact .n { font-variant-numeric: tabular-nums; }

/* Paragraphs come into focus just after the heading above them. */
.fx .reveal > p { opacity: 0; transform: translateY(22px); filter: blur(10px); transition: opacity .9s ease .35s, transform 1.1s cubic-bezier(.16,1,.3,1) .35s, filter .9s ease .35s; }
.fx .reveal.in > p { opacity: 1; transform: none; filter: none; }

/* Kicker rules draw across; the number slides in ahead of the label. */
.fx .kicker::after { transform: scaleX(0); transform-origin: 0 50%; transition: transform 1.4s cubic-bezier(.16,1,.3,1) .25s; }
[dir="rtl"] .fx .kicker::after { transform-origin: 100% 50%; }
.fx .reveal.in .kicker::after, .fx .kicker.reveal.in::after { transform: scaleX(1); }
.fx .kicker b { display: inline-block; transform: translateX(calc(-18px * var(--dir))); opacity: 0; transition: transform .9s cubic-bezier(.16,1,.3,1) .15s, opacity .6s ease .15s; }
.fx .reveal.in .kicker b, .fx .kicker.reveal.in b { transform: none; opacity: 1; }

/* Price rows: the label slides in, then its text sharpens. */
.fx .price-row .v { filter: blur(4px); transition: filter .7s ease .1s; }
.fx .price-row.lit .v { filter: none; }

/* The price turns over when the billing period changes. */
.fx [data-price] { display: inline-block; transform-origin: 50% 60%; }
.fx [data-price].flip { animation: price-flip .7s cubic-bezier(.16,1,.3,1); }
@keyframes price-flip { from { opacity: 0; transform: perspective(500px) rotateX(-95deg) translateY(-10px); } }

/* FAQ answers drop in when opened. */
.fx .faq details[open] p { animation: drop-in .55s cubic-bezier(.16,1,.3,1); }
@keyframes drop-in { from { opacity: 0; transform: translateY(-12px); filter: blur(4px); } }

/* Scan-mode steps (desktop): the active step's title and text roll up into
   place; passed steps roll away upward, coming ones wait below. */
@media (min-width: 1021px) {
  .fx .modes-list .mode > * { transition: transform 1s cubic-bezier(.16,1,.3,1), filter .7s ease; transform-origin: 0 50%; }
  [dir="rtl"] .fx .modes-list .mode > * { transform-origin: 100% 50%; }
  .fx .modes-list .mode:not(.is-active) > * { transform: perspective(900px) translateY(36px) rotateX(-38deg); filter: blur(3px); }
  .fx .modes-list .mode.is-past > * { transform: perspective(900px) translateY(-36px) rotateX(38deg); }
  .fx .modes-list .mode.is-active h3 { transition-delay: .06s; }
  .fx .modes-list .mode.is-active p { transition-delay: .14s; }
}

/* The closing heading's words are lit by scroll like the others; its
   button pops once the block is in. */
.fx .cta .reveal .btn { transform: scale(.85); opacity: 0; transition: transform .8s cubic-bezier(.34,1.56,.64,1) .55s, opacity .5s ease .55s; }
.fx .cta .reveal.in .btn { transform: none; opacity: 1; }

/* ---------- WebGL phones (phone3d.js) ----------
   Each turning phone gets a canvas inside its .iphone, drawn by WebGL: the
   phone's box plus room on every side for the turn (55% of the width, 14%
   of the height, PAD_X / PAD_Y in phone3d.js). Being part of the page, it
   scrolls with it; one fixed canvas over the viewport, as before, tore into
   dark blocks and smeared tiles while iOS scrolled (2026-10-10). Once a
   phone's 3D twin is drawn the .iphone gets .is-gl (its CSS parts hide and
   only hold the place) and its turning element gets .gl-on:
   CSS keeps moving and scaling it, the 3D model does the turning.
   visibility, not just opacity: WebKit kept compositing stale tiles of the
   hidden preserve-3d edge slices, and the flat context drops those layers. */
.phone3d {
  position: absolute; left: -55%; top: -14%; width: 210%; height: 128%;
  max-width: none; pointer-events: none;
}
.iphone.is-gl { transform-style: flat; }
.iphone.is-gl > :not(.phone3d) { opacity: 0; visibility: hidden; }
.fx .phone-a.gl-on { transform: translate3d(0, calc(var(--p, 0) * -110px), 0) scale(calc(1 + var(--p, 0) * .08)); }
.fx .phone-b.gl-on { transform: translate3d(calc(var(--p, 0) * 90px * var(--dir)), calc(var(--p, 0) * -40px), 0); }
.fx .stage-phone.gl-on { transform: none; }
.fx .value-phone.gl-on { transform: translateY(calc((1 - var(--e, 1)) * 60px)) scale(calc(.92 + var(--e, 1) * .08)); }
.fx .gallery .iphone.gl-on { transform: translateY(calc((.5 - var(--p, .5)) * var(--k) * 150px)) scale(calc(.88 + var(--e, 1) * .12)); }

/* Cookie banner (Meta Pixel consent, site.js). */
.consent {
  position: fixed; z-index: 60; inset-inline: 16px; bottom: 16px;
  max-width: 560px; margin-inline: auto; padding: 16px 18px;
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: var(--ink-3); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 12px 40px rgba(0,0,0,.5);
}
.consent[hidden] { display: none; }
.consent p { flex: 1 1 260px; margin: 0; font-size: 14px; line-height: 1.45; color: var(--fg-dim); }
.consent p a { color: var(--fg); }
.consent-actions { display: flex; gap: 8px; margin-inline-start: auto; }
