/* ============================================================================
   Now — product site
   Apple-style: system type, heavy negative tracking on display sizes, generous
   vertical rhythm, near-black on black, one accent gradient. Reveal-on-scroll is
   a single transition driven by an IntersectionObserver in main.js.
   ========================================================================== */

:root {
  --black: #000;
  /* Panels and hairlines carry a barely-there warm cast, so the surfaces belong to
     the same family as the accent instead of reading as cool grey with warm bits
     stuck on. At these values it is felt rather than seen. */
  --panel: #070605;
  --panel-2: #0f0d0c;
  --line: rgba(255, 242, 235, .1);
  --text: #f6f4f2;
  --dim: #8e8a86;
  /* Was #6e6e73, which measured 3.99:1 on the panels and missed AA for the 13px
     footnotes and captions it is used for. */
  --dim-2: #817c78;
  --radius: 18px;

  /* Related to the app icon, not copied from it. The icon's hues are used as-is (30.6°
     amber, 357.2° coral, measured off the plate as macOS composes it) but its chroma is
     pulled halfway back toward the older, paler palette: sampled straight, saturation
     lands near 0.60, and orange that saturated on pure black reads as neon. Sitting at
     ~0.52 keeps the family resemblance without the glare.
     If you re-sample the icon, take the mean of the opaque plate across the top and
     bottom thirds and skip the near-white bars. Do NOT sample the top or bottom edge:
     the composed icon has a specular highlight there that probes as almost white
     (#ffffbb), which is how you would accidentally derive a near-white brand colour. */
  --amber: #fcba75;
  --coral: #fc7f85;
  --accent: #fc9d7d;        /* midpoint — links, bullets, small marks */
  --accent-rgb: 252, 157, 125;
  --on-accent: #2a1206;     /* dark warm brown; the accent is far too light for white text */

  /* Measured off TIDAL for the app itself; reused here so the site's artwork
     behaves like the real thing. See FullScreenArtworkTilt.swift. */
  --tilt-max: 6deg;
  --tilt-lift: 9.5px;
  --sheen-opacity: .18;

  --ease: cubic-bezier(.22, 1, .36, 1);
  --wrap: 1120px;
  --wrap-narrow: 760px;
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* the sticky nav is 48px; keep anchored sections clear of it */
  scroll-padding-top: 72px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--black);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
               "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: 1.5;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }

/* The UA default is `margin: 1em 40px`, which was quietly insetting every screenshot
   by 40px on each side and making the wide container deliver less width than it
   claimed. Explicit margins are set per figure where they are wanted. */
figure { margin: 0; }

/* ═══════════════════════════ Liquid Glass ═══════════════════════════
 *
 * Ported from the momentum job tracker's `app/globals.css`. Apple's WWDC25 model
 * is three layers per surface, and all three are here:
 *
 *   1. the material    — backdrop-filter
 *   2. the highlights  — a ::before carrying the glint, the top arc band, and a
 *                        darker patch at the lower right
 *   3. the meniscus    — a box-shadow rim
 *
 * NOTHING HERE ACTUALLY REFRACTS. Worth stating plainly, because momentum's
 * comments describe this as "lensing" that "bends and concentrates light", and
 * that is intent rather than behaviour. `backdrop-filter: blur() saturate()
 * brightness() contrast()` blurs and colour-shifts the backdrop; it never
 * displaces it, which is what refraction means. The glint and the meniscus are
 * painted gradients and a shadow — they imitate what bent light would leave
 * behind rather than bending anything. Real displacement needs an SVG
 * feDisplacementMap referenced as `backdrop-filter: url(#lens)`; momentum's CSS
 * anticipates one ("lens-backed surfaces carry a url(#…) reference") but the repo
 * contains no such filter, so it does not refract either.
 *
 * What is genuinely doing the work is saturation. At 260% the colour behind the
 * bar reads through vividly, and that colour bleed is what looks like glass.
 *
 * Two deliberate differences from the source, both to fit this site:
 *
 *   • momentum ships light and dark; this site is dark only, so the `.dark`
 *     values are the defaults here rather than an override.
 *   • its ambient blooms are blue, violet and rose. Here they are amber and
 *     coral, sampled from the app icon, so the glass refracts the site's own
 *     colour instead of importing another product's.
 *
 * https://developer.apple.com/documentation/TechnologyOverviews/liquid-glass
 */

:root {
  --glass-blur: 18px;
  --glass-saturate: 220%;
  --glass-brightness: 1.12;
  --glass-contrast: 1.06;
}

.glass,
.glass-panel,
.glass-nav,
.glass-popover {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate))
    brightness(var(--glass-brightness)) contrast(var(--glass-contrast));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate))
    brightness(var(--glass-brightness)) contrast(var(--glass-contrast));
  /* backdrop-filter is deliberately NOT transitioned: filter lists cannot
     interpolate, so the browser jumps at 50% while still invalidating the
     expensive filtered region on every value change. */
  transition: box-shadow 200ms ease;
}

/* Tint darkened from momentum's `bg-white/[0.045]`, and this is a real departure.
   In momentum, `.glass` cards live in the app shell, which its CSS deliberately
   flattens to pure black — "flat background so glass never samples green body
   blooms" — while its marketing page uses only `.glass-bar`. Here the cards carry
   body text *and* sit over drifting blooms, and at 4.5% white the bloom washed
   through and cost the paragraphs their contrast: measurably so, since hiding the
   ambient layer restored them. Blur, saturation, rim and glint are untouched, so
   the material still lenses; only what it tints toward has changed. */
.glass {
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, .12);
  background: rgba(14, 11, 10, .44);
  box-shadow:
    inset 0 .75px 0 0 rgba(255, 255, 255, .18),
    inset .5px 0 0 0 rgba(255, 255, 255, .06),
    inset -.5px 0 0 0 rgba(255, 255, 255, .04),
    inset 0 -.5px 0 0 rgba(255, 255, 255, .04),
    0 18px 48px -22px rgba(0, 0, 0, .55);
  --glass-brightness: 1.18;
}

.glass-panel {
  border-radius: 24px;
  border: 1px solid rgba(255, 255, 255, .13);
  background: rgba(255, 255, 255, .055);
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, .2),
    inset .5px 0 0 0 rgba(255, 255, 255, .06),
    inset -.5px 0 0 0 rgba(255, 255, 255, .04),
    inset 0 -.75px 0 0 rgba(255, 255, 255, .05),
    0 28px 68px -26px rgba(0, 0, 0, .65);
  --glass-brightness: 1.18;
}

.glass-nav {
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .10);
  background: rgba(255, 255, 255, .045);
  box-shadow:
    inset 0 .75px 0 0 rgba(255, 255, 255, .16),
    inset 0 -.5px 0 0 rgba(255, 255, 255, .04),
    0 12px 38px -14px rgba(0, 0, 0, .5);
  --glass-brightness: 1.16;
}

/* Highlights layer. Sized in absolute units so the glint stays a corner detail
   on a large panel instead of flooding the surface. */
.glass::before,
.glass-panel::before,
.glass-nav::before {
  content: "";
  pointer-events: none;
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    radial-gradient(ellipse 220px 110px at 70px -10px,
      rgba(255, 255, 255, .18), transparent 70%),
    linear-gradient(180deg,
      rgba(255, 255, 255, .06) 0px, transparent 64px),
    radial-gradient(ellipse 200px 100px at calc(100% - 60px) calc(100% + 20px),
      rgba(255, 255, 255, .05), transparent 65%);
  opacity: .95;
  transition: opacity 200ms ease;
}

/* "The material illuminates from within as a form of feedback." */
.glass:hover,
.glass-panel:hover,
.glass-nav:hover { --glass-brightness: 1.26; }

.glass:hover::before,
.glass-panel:hover::before,
.glass-nav:hover::before { opacity: 1; }

/* The floating bar, plus Apple's Scroll Edge Effect: content dissolves into the
   background beneath it, lifting the glass visually above what is moving. */
.glass-bar {
  position: relative;
  /* Lensing, not frosting. At the shared 18px the bar was opaque enough that
     content passing beneath it lost its shape, which is the definition of frost —
     there was nothing left to refract. A shorter blur with the saturation pushed
     higher keeps the colour and edges of what is underneath legible through the
     glass, which is the whole effect. The tint drops with it, since a tint is the
     other thing that hides a backdrop. */
  --glass-blur: 6px;
  --glass-saturate: 260%;
  background: rgba(255, 255, 255, .014);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate))
    brightness(var(--glass-brightness)) contrast(var(--glass-contrast));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate))
    brightness(var(--glass-brightness)) contrast(var(--glass-contrast));
}
.glass-bar::after {
  content: "";
  position: absolute;
  inset: 100% 0 auto 0;
  height: 24px;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, 0) 100%);
}

/* ── real refraction, where the browser can actually do it ──
 *
 * These are second declarations of a property already set above, and that is the
 * fallback mechanism, not an oversight. A browser that cannot parse url() inside
 * backdrop-filter throws out just this declaration and keeps the blur-and-saturate
 * one, rather than dropping the property and leaving the surface with no glass at
 * all. Order matters: enhancement last.
 *
 * Only the unprefixed property is given a lens. -webkit-backdrop-filter is left
 * alone deliberately — WebKit is the engine being excluded, and the @supports
 * block near the end of this file strips the lens for Safari explicitly, because
 * Safari parses url() here happily enough and then renders nothing.
 */
.glass-bar {
  backdrop-filter: url(#now-lens-y) blur(var(--glass-blur)) saturate(var(--glass-saturate))
    brightness(var(--glass-brightness)) contrast(var(--glass-contrast));
}

/* The bar gets a lens and the cards do not, and that is a measured decision
   rather than an omission.
 *
 * Displacing a region where the backdrop is locally constant returns the same
 * pixels — mathematically it is the identity. Refraction is only visible where
 * what is behind has structure. The bar has real structure passing under it
 * (screenshots, text, the Dock) every time the page scrolls. The cards sit over
 * the ambient blooms, which are enormous soft gradients, so a lens there would
 * cost two displacement passes on each of twelve surfaces and change nothing a
 * person could see. They keep the blur and saturation.
 *
 * If content ever scrolls behind a card, add `url(#now-lens-xy)` to its
 * backdrop-filter and restore that filter in the markup. */

/* The filter definitions must be in the document but must never take up space or
   be announced. `display: none` would stop Chrome resolving the reference. */
.lens-defs {
  position: absolute;
  width: 0; height: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Screenshot and media frames. */
.liquid-glass-frame {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: 0;
  border-radius: 24px;
  border: 1px solid rgba(255, 255, 255, .13);
  background: rgba(255, 255, 255, .055);
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, .2),
    inset .5px 0 0 0 rgba(255, 255, 255, .06),
    inset 0 -.75px 0 0 rgba(255, 255, 255, .05),
    0 50px 120px -40px rgba(0, 0, 0, .85);
}
/* The image fills the frame, so the frame supplies the corner and the rim. */
.liquid-glass-frame img {
  display: block;
  width: 100%;
  border-radius: 0;
  box-shadow: none;
  margin: 0;
}

/* Pixel grain — the photographed feel, without noise. No mix-blend-mode: a blend
   mode forces this into its own compositing group on top of an already
   backdrop-filtered surface, costing a separate raster pass per card, and at 4%
   the blended and unblended results are indistinguishable. */
.grain::after {
  content: "";
  pointer-events: none;
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: .04;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.45'/%3E%3C/svg%3E");
}

/* Apple accessibility — frostier when transparency is reduced. */
@media (prefers-reduced-transparency: reduce) {
  .glass, .glass-panel, .glass-nav, .glass-popover {
    --glass-blur: 32px;
    --glass-saturate: 120%;
    background: rgba(255, 255, 255, .12);
  }
  .glass::before, .glass-panel::before, .glass-nav::before { opacity: .35; }
}

/* Safari-only tuning, carried over from momentum. WebKit re-rasterizes a
   backdrop-filter region every frame it is exposed, and the cost scales with the
   blur radius AND the number of chained filter functions; Chromium composites it
   far more cheaply. The @supports test matches Safari and not Chromium, because
   hanging-punctuation is WebKit-only. Two filter functions instead of four, and a
   denser tint on the bar so text contrast survives the weaker blur. */
@supports (hanging-punctuation: first) and (font: -apple-system-body) and (-webkit-appearance: none) {
  .glass, .glass-panel, .glass-nav, .glass-popover {
    -webkit-backdrop-filter: blur(8px) saturate(140%) !important;
    backdrop-filter: blur(8px) saturate(140%) !important;
    transition: box-shadow 200ms ease;
  }

  /* The Safari fallback for the lens. Safari parses `backdrop-filter: url(#…)`
     without complaint and then renders nothing through it, so the duplicate-
     declaration trick above does not save it — the bar would simply lose its
     material. Strip the reference here and Safari keeps the tuned blur and
     saturation it had before the lens existed. */
  .glass-bar {
    -webkit-backdrop-filter: blur(6px) saturate(260%) brightness(1.12) contrast(1.06) !important;
    backdrop-filter: blur(6px) saturate(260%) brightness(1.12) contrast(1.06) !important;
  }
  /* .glass-bar is deliberately left out of the override above, and momentum's
     dense `rgba(10,10,12,.72)` tint for it is dropped. Both existed because
     Safari's forced 8px blur was much weaker than the shared 18px, so the bar
     needed a heavy tint to keep its text readable. The bar now runs at 9px
     everywhere, so Safari no longer differs — and re-applying that tint here
     would make Safari's nav 72% opaque against Chrome's near-clear one. */
}

/* ── ambient blooms ──
   Glass has nothing to refract over a flat black page, so these sit behind
   everything and drift. Warm, per the note at the top of this section. */
.ambient {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.ambient i {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(64px);
}
.ambient i:nth-child(1) {
  left: -15%; top: -20%;
  width: 55vmax; height: 55vmax;
  opacity: .5;
  background: radial-gradient(closest-side, rgba(255, 173, 122, .5), transparent 70%);
  animation: bloom-float 18s ease-in-out infinite;
}
.ambient i:nth-child(2) {
  right: -15%; top: 10%;
  width: 60vmax; height: 60vmax;
  opacity: .4;
  background: radial-gradient(closest-side, rgba(255, 141, 138, .42), transparent 70%);
  animation: bloom-float-reverse 22s ease-in-out infinite;
}
.ambient i:nth-child(3) {
  right: 10%; bottom: 5%;
  width: 45vmax; height: 45vmax;
  opacity: .32;
  background: radial-gradient(closest-side, rgba(255, 201, 141, .3), transparent 70%);
  animation: bloom-float 18s ease-in-out infinite -7s;
}
/* keeps the footer clean */
.ambient .fade {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 0%, transparent 55%, var(--black) 100%);
}

@keyframes bloom-float {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(20px, -30px); }
}
@keyframes bloom-float-reverse {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(-30px, 40px); }
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ───────────────────────────── layout ───────────────────────────── */

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.wrap.narrow { max-width: var(--wrap-narrow); }
/* For full-bleed-ish screenshots that earn the extra width */
.wrap.wide { max-width: 1340px; }
.center { text-align: center; }

.band { padding: clamp(88px, 13vw, 168px) 0; position: relative; }
.band.alt { background: var(--panel); }

/* hairline between bands, the way Apple separates modules */
.band.alt::before,
.band.alt::after {
  content: "";
  position: absolute; left: 0; right: 0; height: 1px;
  background: var(--line);
}
.band.alt::before { top: 0; }
.band.alt::after { bottom: 0; }

/* ───────────────────────────── type ───────────────────────────── */

/* Sized so the longest line ("Right where you're working.") holds on one line
   inside the hero's measure. Bigger than this and the intended two-line break
   turns into four. */
.display {
  font-size: clamp(34px, 4.9vw, 64px);
  line-height: 1.06;
  letter-spacing: -.028em;
  font-weight: 600;
  margin: 0 0 18px;
  text-wrap: balance;
}
.display.sm { font-size: clamp(31px, 4.2vw, 52px); }

.title-2 {
  font-size: clamp(30px, 4.4vw, 52px);
  line-height: 1.1;
  letter-spacing: -.02em;
  font-weight: 600;
  margin: 0 0 20px;
}

.grad {
  background: linear-gradient(96deg, #ffd7a8 0%, var(--amber) 32%, #ffb0a0 70%, var(--coral) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.eyebrow {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 14px;
}

.lede {
  font-size: clamp(17px, 1.55vw, 21px);
  line-height: 1.5;
  color: var(--dim);
  margin: 0 auto 34px;
  max-width: 34em;
  letter-spacing: -.01em;
}

.body {
  font-size: 17px;
  line-height: 1.6;
  color: var(--dim);
  margin: 0 0 18px;
  letter-spacing: -.005em;
}
.center-body { max-width: 40em; margin-inline: auto; }

.meta { font-size: 13px; color: var(--dim-2); margin: 0; }
.meta.small { margin-top: 10px; }

.footnote {
  font-size: 13px;
  line-height: 1.55;
  color: var(--dim-2);
  max-width: 46em;
  margin: 26px auto 0;
  text-align: center;
}

kbd {
  font: inherit;
  font-size: .9em;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: 1px 6px;
  margin: 0 1px;
  background: rgba(255, 255, 255, .05);
  color: var(--text);
}

code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: .88em;
  background: rgba(255, 255, 255, .07);
  border-radius: 5px;
  padding: 2px 6px;
  color: #e6e6ea;
}

/* ───────────────────────────── nav ───────────────────────────── */

/* Material comes from .glass-bar; this only handles placement. */
.nav {
  position: sticky; top: 0; z-index: 50;
  border-bottom: 1px solid transparent;
  transition: border-color .3s ease;
}
.nav.stuck { border-bottom-color: var(--line); }

/* Legibility insurance for the near-clear bar. Real Liquid Glass darkens itself
   when what is behind it is bright — adaptive tinting, which CSS cannot do. The
   alternative was putting the tint back, which is exactly the frosting that was
   hiding the refraction. A shadow on the glyphs instead costs nothing over the
   dark page and rescues the case where a bright screenshot scrolls underneath. */
.nav-brand span,
.nav-links a { text-shadow: 0 1px 3px rgba(0, 0, 0, .55); }

.nav-inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 24px;
  height: 48px;
  display: flex;
  align-items: center;
  gap: 28px;
}

.nav-brand {
  display: flex; align-items: center; gap: 8px;
  color: var(--text); font-size: 15px; font-weight: 600; letter-spacing: -.01em;
}
.nav-brand:hover { text-decoration: none; }

.nav-links {
  display: flex; gap: 26px;
  list-style: none; margin: 0; padding: 0;
  margin-left: auto;
}
.nav-links a {
  color: var(--text); opacity: .8;
  font-size: 13px; letter-spacing: -.005em;
  transition: opacity .2s ease;
}
.nav-links a:hover { opacity: 1; text-decoration: none; }

.nav-cta {
  font-size: 13px; font-weight: 600;
  color: var(--on-accent);
  background: linear-gradient(180deg, var(--amber) 0%, var(--coral) 100%);
  padding: 5px 13px;
  border-radius: 980px;
  transition: filter .2s ease;
}
.nav-cta:hover { filter: brightness(1.1); text-decoration: none; }

@media (max-width: 700px) {
  .nav-links { display: none; }
  .nav-cta { margin-left: auto; }
}

/* ───────────────────────────── buttons ───────────────────────────── */

.cta-row {
  display: flex; flex-wrap: wrap; gap: 14px;
  justify-content: center; align-items: center;
  margin-bottom: 14px;
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font: inherit; font-size: 16px; font-weight: 500; letter-spacing: -.01em;
  padding: 13px 26px;
  border-radius: 980px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform .22s var(--ease), filter .22s ease, background .22s ease;
}
.btn:active { transform: scale(.975); }
.btn.lg { font-size: 18px; padding: 16px 34px; }

/* The icon's own gradient, running the same direction it does on the mark. Text is
   dark rather than white because the accent is a light pastel — white on it fails
   contrast badly. */
.btn-primary {
  background: linear-gradient(180deg, var(--amber) 0%, var(--coral) 100%);
  color: var(--on-accent);
  font-weight: 600;
}
.btn-primary:hover { filter: brightness(1.06) saturate(1.06); text-decoration: none; }
.btn-primary[disabled] { opacity: .55; cursor: progress; }

.btn-ghost {
  background: transparent; color: var(--accent);
  border-color: rgba(var(--accent-rgb), .42);
}
.btn-ghost:hover { background: rgba(var(--accent-rgb), .1); text-decoration: none; }

.apple { width: 18px; height: 18px; fill: currentColor; flex: none; margin-top: -2px; }
.btn.lg .apple { width: 20px; height: 20px; }

/* ───────────────────────────── hero ───────────────────────────── */

.hero {
  padding: clamp(56px, 9vw, 104px) 0 clamp(72px, 10vw, 128px);
  position: relative;
  overflow: hidden;
}
/* one soft light behind the headline, no more */
.hero::before {
  content: "";
  position: absolute;
  top: -18%; left: 50%;
  width: min(1100px, 130vw); aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle,
    rgba(255, 150, 115, .18) 0%,
    rgba(255, 150, 115, .06) 38%,
    transparent 68%);
  pointer-events: none;
}
.hero > * { position: relative; }

/* wider than the standard narrow column — display type needs the room */
.hero .wrap.narrow { max-width: 940px; }

/* The icon PNG carries its own squircle in the alpha channel, so no border-radius
   (it would cut into the artwork) and no box-shadow (it would trace the square box
   around a rounded mark). drop-shadow follows the alpha instead. */
.hero-icon {
  width: clamp(88px, 11vw, 120px); height: auto;
  margin: 0 auto 26px;
  filter: drop-shadow(0 18px 44px rgba(0, 0, 0, .65));
}

.hero-shot {
  margin: clamp(48px, 7vw, 84px) auto 0;
  max-width: 1180px;
  padding: 0 24px;
}
.hero-shot figcaption,
.framed figcaption {
  margin-top: 18px;
  text-align: center;
  font-size: 13px;
  color: var(--dim-2);
}

/* the tilt surface — perspective on the parent, rotation on the child, so the
   sheen can ride along inside the same 3D context */
/* Corner, rim and shadow come from .liquid-glass-frame — declaring them here too
   would beat the frame on source order and leave the hero the only screenshot
   without the meniscus. */
.shot-tilt {
  position: relative;
  transform-style: preserve-3d;
  will-change: transform;
  /* set by main.js */
  transform:
    perspective(1400px)
    rotateY(calc(var(--tx, 0) * var(--tilt-max)))
    rotateX(calc(var(--ty, 0) * var(--tilt-max) * -1))
    translateY(calc(var(--ty, 0) * var(--tilt-lift) * -1));
  transition: transform .40s var(--ease);
}
.shot-tilt.released { transition-duration: .56s; }

/* Deliberately the only cool colour on the page. This is the app's specular
   highlight, whose measured gain off TIDAL was R:G:B = 0.62 : 0.79 : 1.0 — an
   actually blue light. Warming it to match the palette would stop it matching the
   thing it is reproducing. */
.shot-tilt .sheen {
  position: absolute; inset: 0;
  pointer-events: none;
  mix-blend-mode: plus-lighter;
  opacity: var(--sheen, 0);
  transition: opacity .40s var(--ease);
  background: radial-gradient(
    35% 35% at calc(var(--lx, 50) * 1%) calc(var(--ly, 50) * 1%),
    rgba(158, 202, 255, var(--sheen-opacity)) 0%,
    rgba(158, 202, 255, calc(var(--sheen-opacity) * .45)) 42%,
    transparent 72%);
}

/* ───────────────────────────── split sections ───────────────────────────── */

.split {
  display: grid;
  grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
.split.reverse .split-text { order: 2; }
.split.reverse .split-shot { order: 1; }

.split-text .eyebrow { margin-bottom: 12px; }

/* .liquid-glass-frame img handles the image; the frame handles the corner. */

@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
  .split.reverse .split-text,
  .split.reverse .split-shot { order: initial; }
}

.ticks { list-style: none; margin: 22px 0 0; padding: 0; }
.ticks li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 11px;
  font-size: 15px;
  color: var(--dim);
  line-height: 1.55;
}
.ticks li::before {
  content: "";
  position: absolute; left: 4px; top: .52em;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--coral);
  box-shadow: 0 0 12px rgba(var(--accent-rgb), .65);
}

/* ───────────────────────────── feature grid ───────────────────────────── */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
  margin-top: clamp(36px, 5vw, 60px);
}

/* Surface comes from .glass. The opaque gradient this used to carry would have
   sat in front of the backdrop-filter and left nothing to refract. */
.card {
  padding: 30px 28px 32px;
  transition: transform .4s var(--ease), box-shadow 200ms ease;
}
.card:hover { transform: translateY(-4px); }

.card-ico {
  width: 40px; height: 40px;
  border-radius: 11px;
  display: grid; place-items: center;
  color: #ffdcc0;
  background: linear-gradient(160deg, rgba(var(--accent-rgb), .28), rgba(var(--accent-rgb), .07));
  border: 1px solid rgba(var(--accent-rgb), .25);
  margin-bottom: 18px;
}

/* Drawn icons rather than Unicode glyphs. The glyphs were whatever a font happened
   to contain — ✦ read as the generic AI sparkle and said nothing about artwork
   leaning under a pointer — and they shifted shape between fonts and platforms.
   One stroke weight, one grid, and each one depicts its own feature. */
.card-ico svg {
  width: 22px; height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;   /* the pointer in the first icon reaches past x=20 */
}
/* Filled accents inside an otherwise stroked icon: the pointer, the chosen preset
   tile, the keyhole. */
.card-ico svg .solid { fill: currentColor; stroke: none; }

.card h3 {
  font-size: 19px; font-weight: 600; letter-spacing: -.01em;
  margin: 0 0 10px;
}
.card p { font-size: 15px; line-height: 1.6; color: var(--dim); margin: 0; }

/* ───────────────────────────── service logos ───────────────────────────── */

.logos {
  list-style: none;
  margin: clamp(38px, 5vw, 58px) 0 clamp(44px, 6vw, 68px);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 30px 20px;
}
/* Seven sources. Left to auto-fit, the widest layouts take six and strand the
   seventh alone on a second row. Four across reads as a deliberate 4 + 3 block,
   and stays balanced whether the count is 7 or 8. */
@media (min-width: 860px) {
  .logos { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.logos li {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 4px;
  padding: 22px 12px 18px;
  transition: transform .4s var(--ease), box-shadow 200ms ease;
}
.logos li:hover { transform: translateY(-4px); }
.logos img {
  width: 72px; height: 72px;
  border-radius: 17px;
  margin-bottom: 10px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .55), 0 0 0 1px rgba(255, 255, 255, .07);
  transition: transform .4s var(--ease);
}
.logos li:hover img { transform: translateY(-5px) scale(1.04); }
.logos span { font-size: 14px; font-weight: 500; letter-spacing: -.01em; }
.logos em {
  font-style: normal;
  font-size: 12px;
  color: var(--dim-2);
}

/* The frame supplies the corner, rim and shadow — see .liquid-glass-frame. The
   figcaption sits outside it, so the caption rules below still apply. */
.framed > .liquid-glass-frame,
.split-shot.liquid-glass-frame { margin-inline: auto; }

/* ───────────────────────────── steps ───────────────────────────── */

.steps {
  list-style: none;
  counter-reset: none;
  margin: clamp(38px, 5vw, 58px) 0 0;
  padding: 0;
}
.steps li {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 20px;
  padding: 26px 0;
  border-top: 1px solid var(--line);
}
.steps li:last-child { border-bottom: 1px solid var(--line); }

.steps .n {
  width: 34px; height: 34px;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 15px; font-weight: 600;
  color: #ffdcc0;
  background: rgba(var(--accent-rgb), .15);
  border: 1px solid rgba(var(--accent-rgb), .32);
}

.steps h3 {
  font-size: 19px; font-weight: 600; letter-spacing: -.01em;
  margin: 4px 0 8px;
}
.steps p {
  font-size: 15px; line-height: 1.6; color: var(--dim);
  margin: 0 0 8px;
}
.steps p:last-child { margin-bottom: 0; }
.steps strong { color: var(--text); font-weight: 500; }

.steps .path {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: 13.5px;
  line-height: 1.5;
  color: #e6e6ea;
  background: rgba(255, 255, 255, .055);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 14px;
  margin: 10px 0;
  overflow-wrap: anywhere;
}
.steps .path strong { color: #fff; }
.steps .or { font-size: 13px; color: var(--dim-2); margin: 0 0 2px; }
.steps .hint { font-size: 13px; color: var(--dim-2); }

/* ───────────────────────────── download ───────────────────────────── */

.download {
  background:
    radial-gradient(80% 130% at 50% 0%, rgba(255, 150, 115, .17) 0%, transparent 62%),
    var(--black);
}
.download .display { margin-bottom: 14px; }

/* ───────────────────────────── footer ───────────────────────────── */

.foot {
  border-top: 1px solid var(--line);
  padding: 42px 0 56px;
  background: var(--panel);
}
.foot p {
  font-size: 12px;
  line-height: 1.7;
  color: var(--dim-2);
  margin: 0 0 10px;
  max-width: 60em;
}
.foot .dim { color: #4c4c50; }

/* ───────────────────────────── reveal on scroll ───────────────────────────── */

/* Scoped under .js, set by an inline script in <head>. If the stylesheet loads
   but main.js does not, every section stays visible instead of being permanently
   transparent with nothing to reveal it.

   --from is the direction the element travels in from, set by main.js: +1 when it
   is below the viewport, so it rises; -1 when it is above, so it descends. That
   way scrolling back up does not make content climb from the wrong side. */
.js .reveal {
  opacity: 0;
  transform: translateY(calc(var(--from, 1) * 42px));
  transition:
    opacity .9s var(--ease) var(--d, 0s),
    transform .9s var(--ease) var(--d, 0s);
}
.js .reveal.in { opacity: 1; transform: none; }

/* Re-arming happens off-screen, and the stagger delays are only wanted on the way
   in — without this, an element re-armed with --d:.3s keeps that delay and lags
   noticeably the next time it scrolls into view. */
.js .reveal.rearm { transition-delay: 0s; }

/* Never hide content when motion is unwelcome, or if JS fails to run. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .shot-tilt { transition: none; }
  .card:hover, .logos li:hover img { transform: none; }
}

/* ─────────────────── feature run (claim + recording) ─────────────────── */

/* One claim, then its recording, straight down the page. An earlier version alternated
   them left/right by assigning grid-column with :nth-of-type, which collided: the columns
   were pinned but the rows were left to auto-place, so figures landed beside the wrong
   card. A single column cannot get that wrong, and it is what the reference site does. */
.features-flow {
  display: grid;
  gap: clamp(28px, 4vw, 44px);
  margin: clamp(38px, 5vw, 58px) 0 0;
}

.feature-shot { margin: 0 0 clamp(20px, 3vw, 34px); }
.feature-shot video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;   /* reserve the space before metadata arrives, so nothing jumps */
  object-fit: cover;
  border-radius: calc(var(--radius) - 4px);
  background: #0b0b0c;
}
/* Only set when a clip genuinely failed to load; see the note in main.js. */
.feature-shot.missing { display: none; }

/* ─────────────────────────────── faq ─────────────────────────────── */

/* Native <details>, so it works with no JavaScript, is keyboard operable and reachable
   by find-in-page when closed on browsers that support that. An accordion built from
   divs and click handlers would have to reimplement all three. */
.faq-list {
  list-style: none;
  margin: clamp(38px, 5vw, 58px) 0 0;
  padding: 0;
  display: grid;
  gap: 12px;
}
.faq { border-radius: var(--radius); overflow: hidden; }
.faq summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 22px;
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -.01em;
  /* Safari still shows a disclosure triangle without this. */
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }

/* A drawn chevron rather than the native triangle, so it can rotate. */
.faq summary::after {
  content: "";
  flex: 0 0 auto;
  width: 9px; height: 9px;
  border-right: 1.5px solid var(--accent);
  border-bottom: 1.5px solid var(--accent);
  transform: rotate(45deg) translateY(-2px);
  transition: transform .28s var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg) translateY(-2px); }

.faq summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.faq p {
  margin: 0;
  padding: 0 22px 22px;
  color: var(--dim);
  font-size: 15px;
  line-height: 1.62;
  max-width: 62ch;
}
@media (prefers-reduced-motion: reduce) {
  .faq summary::after { transition: none; }
}
