/* leyr.stream: product site and get.leyr.stream install page.
   One accent on neutral surfaces. It rests on Leyr green (the mark's
   colour); on the home page site.js retints it from the album in the
   now-playing chip, as the app does from the cover that is playing.
   Colours are defined once here as custom properties; rules use var(). */

/* The tint is registered so it can be transitioned: everything derived
   from it below (soft fills, lines, glow, ink) follows frame by frame.
   --tint is the bright accent for dark surfaces and carries near-black
   text; --tint-deep is the light theme's, and carries white text. */
@property --tint { syntax: "<color>"; inherits: true; initial-value: #1db954; }
@property --tint-deep { syntax: "<color>"; inherits: true; initial-value: #169443; }
/* How far the screenshots are pulled to the tint's hue: 0 while Leyr green
   plays (the screenshots already wear it), 1 for any other album. */
@property --recolor { syntax: "<number>"; inherits: true; initial-value: 0; }

@font-face {
  font-family: "Inter Variable";
  src: url("/brand/inter-latin-wght.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

:root {
  color-scheme: dark;
  /* Leyr green, shared with web/public/icons/leyr-mark.svg. */
  --tint: #1db954;
  --tint-deep: #169443;
  /* The app's own timing: its brand stops, wordmark and mark ease over 600 ms. */
  --tint-time: 600ms;
  --recolor: 0;
  transition: --tint var(--tint-time) ease, --tint-deep var(--tint-time) ease, --recolor var(--tint-time) ease;
  --accent: var(--tint);
  --accent-hi: color-mix(in oklab, var(--tint) 82%, white);
  --accent-ink: color-mix(in oklab, var(--tint) 78%, white);
  --on-accent: color-mix(in oklab, var(--tint) 10%, #030504);
  --accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
  --accent-line: color-mix(in srgb, var(--accent) 35%, transparent);
  --glow: color-mix(in srgb, var(--tint) 16%, transparent);

  --bg: #0a0a0b;
  --bg-2: #0e0f10;
  --surface: #131416;
  --surface-2: #191a1d;
  --line: rgb(255 255 255 / 0.07);
  --line-2: rgb(255 255 255 / 0.12);
  --fg: #ededef;
  --fg-2: #a3a3ab;
  --fg-3: #6e6e78;
  --shadow: 0 30px 80px -30px rgb(0 0 0 / 0.8);
  --frame-bar: #1a1b1e;
  --bad: #e8705f;

  --sans: "Inter Variable", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans", "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "JetBrains Mono", "SFMono-Regular", Menlo, Consolas, monospace;
  --r: 12px;
  --r-lg: 18px;
  --wrap: 1160px;
  --gutter: 20px;
  --ease: cubic-bezier(.2, .7, .2, 1);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --accent: var(--tint-deep); --accent-hi: color-mix(in oklab, var(--tint-deep) 85%, white);
    --accent-ink: color-mix(in oklab, var(--tint-deep) 82%, black); --on-accent: #ffffff;
    --accent-soft: color-mix(in srgb, var(--accent) 10%, transparent); --accent-line: color-mix(in srgb, var(--accent) 35%, transparent);
    --glow: color-mix(in srgb, var(--tint) 12%, transparent);
    --bg: #fafafa; --bg-2: #f3f3f4; --surface: #ffffff; --surface-2: #f6f6f7;
    --line: rgb(10 10 11 / 0.08); --line-2: rgb(10 10 11 / 0.14);
    --fg: #0d0d0f; --fg-2: #4b4b55; --fg-3: #7a7a85;
    --shadow: 0 30px 70px -36px rgb(10 10 11 / 0.35);
    --frame-bar: #ececee;
    --bad: #c2412f;
  }
}
:root[data-theme="light"] {
  color-scheme: light;
  --accent: var(--tint-deep); --accent-hi: color-mix(in oklab, var(--tint-deep) 85%, white);
  --accent-ink: color-mix(in oklab, var(--tint-deep) 82%, black); --on-accent: #ffffff;
  --accent-soft: color-mix(in srgb, var(--accent) 10%, transparent); --accent-line: color-mix(in srgb, var(--accent) 35%, transparent);
  --glow: color-mix(in srgb, var(--tint) 12%, transparent);
  --bg: #fafafa; --bg-2: #f3f3f4; --surface: #ffffff; --surface-2: #f6f6f7;
  --line: rgb(10 10 11 / 0.08); --line-2: rgb(10 10 11 / 0.14);
  --fg: #0d0d0f; --fg-2: #4b4b55; --fg-3: #7a7a85;
  --shadow: 0 30px 70px -36px rgb(10 10 11 / 0.35);
  --frame-bar: #ececee;
  --bad: #c2412f;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 72px; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font: 16px/1.6 var(--sans); letter-spacing: -0.006em;
  -webkit-font-smoothing: antialiased; overflow-x: hidden;
}
img, svg { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding-left: var(--gutter); padding-right: var(--gutter); }

/* ---------- Top bar ---------- */
.top {
  position: sticky; top: 0; z-index: 20; padding-top: env(safe-area-inset-top);
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: saturate(140%) blur(16px); -webkit-backdrop-filter: saturate(140%) blur(16px);
  border-bottom: 1px solid transparent; transition: border-color .3s var(--ease);
}
.top.scrolled { border-bottom-color: var(--line); }
.top .wrap { display: flex; align-items: center; gap: 12px; height: 64px; }
.logo { display: flex; align-items: center; gap: 10px; text-decoration: none; }
.logo .mark { width: 28px; height: 28px; }
.logo .word { height: 16px; width: auto; }
/* As in the app (BrandMark): only the rim turns, like a record label, while
   music plays. Always attached and paused when idle, so it stops where it is. */
.logo .rim { transform-box: view-box; transform-origin: 50% 50%; animation: brand-orbit 3.6s linear infinite paused; }
.is-playing .logo .rim { animation-play-state: running; }
@keyframes brand-orbit { to { transform: rotate(360deg); } }
.nav { margin-left: auto; display: flex; align-items: center; gap: 2px; }
.nav a:not(.btn) { text-decoration: none; color: var(--fg-2); font-size: 14.5px; font-weight: 500; padding: 10px 12px; border-radius: 8px; transition: color .2s; }
.nav a:not(.btn):hover { color: var(--fg); }
.nav .hide-sm { display: none; }
@media (min-width: 760px) { .nav .hide-sm { display: inline-block; } }
/* Cloud links carry the Leyr Cloud mark, so they read as part of Leyr. */
.btn-cloud .brand-tint { width: 20px; height: 20px; flex: none; }
.hero-note a, .closing .hero-note a { color: var(--accent-ink); }
/* Get Leyr: Cloud beside self-hosted. */
.ways { display: grid; gap: 16px; grid-template-columns: 1fr; max-width: 960px; margin: 0 auto; }
@media (min-width: 820px) { .ways { grid-template-columns: 1fr 1fr; } }
.way { position: relative; display: flex; flex-direction: column; padding: 32px; border-radius: var(--r-lg); border: 1px solid var(--line-2); background: var(--surface); min-width: 0; }
.way-cloud { border-color: var(--accent-line); background: radial-gradient(120% 60% at 50% 0%, var(--accent-soft), transparent 70%), var(--surface); }
.way .tag { position: absolute; top: -11px; left: 28px; margin: 0; padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; background: var(--accent); color: var(--on-accent); }
.way-head { display: flex; align-items: center; gap: 14px; margin-bottom: 22px; }
.way-head .brand-tint { width: 40px; height: 40px; flex: none; }
.way h3 { font-size: 24px; margin: 0; }
.way .who { margin: 2px 0 0; color: var(--fg-3); font-size: 15px; }
.way .checks { flex: 1; }
.way .price { margin: 24px 0 18px; padding-top: 18px; border-top: 1px solid var(--line); font-weight: 600; color: var(--fg-2); }
.way .price b { font-size: 28px; font-weight: 700; letter-spacing: -0.02em; color: var(--fg); }
.way .price span { display: block; margin-top: 2px; font-size: 13.5px; font-weight: 500; color: var(--fg-3); }
.way .cta { justify-content: flex-start; }
.nav-cloud { display: inline-flex; align-items: center; gap: 7px; }
.nav .nav-cloud.hide-sm { display: none; }
@media (min-width: 760px) { .nav .nav-cloud.hide-sm { display: inline-flex; } }
.nav-cloud .brand-tint { flex: none; width: 18px; height: 18px; }
footer .nav-cloud .brand-tint { width: 16px; height: 16px; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 44px; padding: 0 18px; border-radius: 10px;
  font: 600 15px/1 var(--sans); text-decoration: none; white-space: nowrap; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--fg);
  transition: transform .2s var(--ease), background-color .2s, border-color .2s, box-shadow .2s;
}
.btn:hover { transform: translateY(-1px); border-color: var(--fg-3); }
.btn.primary { background: var(--accent); border-color: transparent; color: var(--on-accent); box-shadow: 0 8px 24px -10px var(--accent); }
.btn.primary:hover { background: var(--accent-hi); }
.btn.sm { min-height: 36px; padding: 0 14px; font-size: 14px; }
.btn svg { width: 16px; height: 16px; }

/* ---------- Type ---------- */
.eyebrow { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; letter-spacing: .02em; color: var(--accent-ink); margin: 0 0 16px; }
.pill { padding: 6px 12px 6px 8px; border-radius: 999px; border: 1px solid var(--line-2); background: var(--surface); color: var(--fg-2); font-weight: 500; }
.pill b { color: var(--accent-ink); font-weight: 600; }
.pill .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* The app's live dot (chip-live) breathes while something is playing. */
.is-playing .pill .dot { animation: breathe 1.6s ease-in-out infinite; }
@keyframes breathe { 0%, 100% { opacity: .35; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.1); } }
h1, h2, h3 { margin: 0; font-weight: 680; letter-spacing: -0.035em; }
h1 { font-size: clamp(40px, 7vw, 76px); line-height: 1.02; }
h2 { font-size: clamp(30px, 4.4vw, 48px); line-height: 1.06; margin-bottom: 16px; }
h3 { font-size: 17px; letter-spacing: -0.015em; font-weight: 640; margin-bottom: 6px; }
.lede { font-size: clamp(17px, 2vw, 20px); line-height: 1.55; color: var(--fg-2); }
.accent { color: var(--accent-ink); }

/* ---------- Hero ---------- */
.hero { position: relative; padding-top: 72px; padding-bottom: 24px; text-align: center; }
.hero::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 640px; z-index: -1; pointer-events: none;
  /* The ellipse fades out inside the box, so no edge ever shows. */
  background: radial-gradient(42% 46% at 50% 46%, var(--glow), transparent 72%);
}
.hero.bloom::before { animation: bloom 1.6s var(--ease); }
@keyframes bloom { 0%, 100% { filter: none; transform: none; } 30% { filter: brightness(1.9) saturate(1.3); transform: scale(1.12); } }
/* The new colour washes out from the chip across the hero. */
.wash {
  position: absolute; z-index: -1; width: 1400px; height: 1400px; margin: -700px 0 0 -700px; border-radius: 50%;
  pointer-events: none; background: radial-gradient(closest-side, var(--c), transparent);
  animation: wash 1.8s var(--ease) forwards;
}
@keyframes wash { from { opacity: .55; transform: scale(.05); } to { opacity: 0; transform: scale(1); } }
.dots { width: min(280px, 60vw); margin: 0 auto 28px; }
.dots circle { fill: transparent; stroke: var(--accent); stroke-width: .1; stroke-opacity: .22; transition: fill .4s var(--ease), stroke-opacity .4s var(--ease); transform-box: fill-box; transform-origin: center; }
.dots circle.on { fill: var(--accent); stroke-opacity: 0; transition: stroke-opacity .4s var(--ease); }
/* A new album re-lights the wordmark left to right in its colour. */
.dots.wave circle.on { animation: dot-pop .7s var(--ease) both; animation-delay: calc(var(--x) * 28ms); }
@keyframes dot-pop {
  0% { transform: scale(.6); opacity: .25; }
  35% { transform: scale(1.45); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.hero h1 { max-width: 15ch; margin: 0 auto 20px; }
.hero .lede { max-width: 38rem; margin: 0 auto 32px; }
.cta { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.hero-note { margin-top: 18px; font-size: 13.5px; color: var(--fg-3); }

/* Product frame */
.stage { position: relative; max-width: 1080px; margin: 64px auto 0; }
.frame { border-radius: var(--r-lg); overflow: hidden; background: var(--surface); border: 1px solid var(--line-2); box-shadow: var(--shadow); }
/* Screenshots follow the playing album too, as the app's chrome does, and
   their album art stays as it is, as the art does in the app. A hue blend
   takes only the tint's hue and keeps each pixel's saturation and lightness,
   so greys, text and dark surfaces stay put and the app's green becomes the
   cover's. Each shot's mask (shots/<name>.mask.svg, written by
   screenshots/shoot.cjs) has holes over the artwork; site.js attaches it,
   and a shot without one is left alone. */
.frame, .phone { position: relative; isolation: isolate; }
.art-masked::after {
  content: ""; position: absolute; inset: var(--shot-top, 0px) 0 0 0; pointer-events: none;
  background: var(--tint); mix-blend-mode: hue; opacity: var(--recolor);
  -webkit-mask: var(--art-mask) 0 0 / 100% 100% no-repeat;
  mask: var(--art-mask) 0 0 / 100% 100% no-repeat;
}
.frame .bar { height: 34px; display: flex; align-items: center; gap: 7px; padding: 0 14px; background: var(--frame-bar); border-bottom: 1px solid var(--line); }
.frame .bar i { width: 10px; height: 10px; border-radius: 50%; background: var(--line-2); }
.frame .bar span { margin-left: 10px; font-size: 12px; color: var(--fg-3); }
.phone {
  position: absolute; right: -20px; bottom: -48px; width: 23%; min-width: 150px;
  border-radius: 30px; overflow: hidden; background: var(--surface);
  border: 1px solid var(--line-2); box-shadow: var(--shadow), 0 0 0 6px var(--bg);
}
@media (max-width: 720px) { .phone { display: none; } }

/* Now playing chip on the hero frame. On the home page it cycles through
   fictional albums and the page takes each cover's colour. */
.np {
  position: absolute; left: 24px; bottom: -30px; z-index: 2; display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px;
  width: 360px; padding: 10px 10px 12px; border-radius: 16px; background: color-mix(in srgb, var(--surface) 86%, transparent);
  border: 1px solid var(--line-2); box-shadow: var(--shadow), 0 18px 50px -24px var(--accent); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  font-size: 13px; text-align: left;
}
/* The Player's cover glow: the colour breathes behind the art. */
.np::before {
  content: ""; position: absolute; z-index: -1; left: 6px; top: 6px; width: 60px; height: 60px; border-radius: 50%;
  background: var(--accent); filter: blur(16px); opacity: .5; pointer-events: none;
}
.np.playing::before { animation: cover-glow 4.5s ease-in-out infinite; }
.np.paused::before { animation-play-state: paused; }
@keyframes cover-glow { 0%, 100% { opacity: .5; } 50% { opacity: .85; } }
.np .art { position: relative; width: 52px; height: 52px; border-radius: 9px; overflow: hidden; background: linear-gradient(135deg, var(--accent), var(--bg-2)); box-shadow: 0 6px 18px -8px var(--accent); }
.np .art svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.np .art .in { animation: cover-in .7s var(--ease) both; }
.np .art .out { animation: cover-out .5s var(--ease) forwards; }
@keyframes cover-in { from { opacity: 0; transform: scale(1.35) rotate(-8deg); } to { opacity: 1; transform: none; } }
@keyframes cover-out { to { opacity: 0; transform: scale(.7) rotate(6deg); } }
.np .meta { min-width: 0; }
.np .meta > * { animation: meta-in .55s var(--ease) both; }
.np .meta > :nth-child(2) { animation-delay: .06s; }
.np .meta > :nth-child(3) { animation-delay: .12s; }
@keyframes meta-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.np b { display: block; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np span { display: block; color: var(--fg-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np .hex { display: flex; align-items: center; gap: 6px; margin-top: 3px; font: 11px/1 var(--mono); color: var(--fg-3); }
.np .hex::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.np .ctl { display: flex; align-items: center; gap: 2px; }
.np button {
  display: grid; place-items: center; width: 30px; height: 30px; padding: 0; border: 0; border-radius: 50%;
  background: none; color: var(--fg-2); cursor: pointer; transition: color .2s, background-color .2s;
}
.np button:hover { color: var(--fg); background: var(--surface-2); }
.np button.pp { width: 34px; height: 34px; background: var(--accent); color: var(--on-accent); }
.np button.pp:hover { background: var(--accent-hi); }
.np button svg { width: 14px; height: 14px; }
.np button.pp svg { width: 15px; height: 15px; }
.np .pp .i-play, .np.paused .pp .i-pause { display: none; }
.np.paused .pp .i-play { display: block; }
.np .prog { position: absolute; left: 12px; right: 12px; bottom: 5px; height: 2px; border-radius: 2px; background: var(--line-2); overflow: hidden; }
.np .prog i { display: block; height: 100%; background: var(--accent); transform-origin: left; transform: scaleX(0); }
.np .prog i.run { animation: prog var(--dur, 7s) linear forwards; }
.np:not(.playing) .prog i, .np.paused .prog i { animation-play-state: paused; }
@keyframes prog { to { transform: scaleX(1); } }
.eq { display: flex; gap: 2px; align-items: flex-end; height: 14px; }
.np .eq { height: 12px; margin-right: 8px; }
.np .eq i { width: 2px; }
.eq i { width: 3px; height: 100%; border-radius: 2px; background: var(--accent); transform-origin: bottom; transform: scaleY(.4); }
/* The app's now-playing bars: one beat, and pausing freezes them mid-beat. */
.playing .eq i { animation: eq 1.1s ease-in-out infinite; }
.playing .eq i:nth-child(2) { animation-duration: .8s; animation-delay: -.3s; }
.playing .eq i:nth-child(3) { animation-duration: 1.3s; animation-delay: -.6s; }
.playing .eq i:nth-child(4) { animation-duration: .95s; animation-delay: -.2s; }
.paused .eq i { animation-play-state: paused; opacity: .55; }
@keyframes eq { 0%, 100% { transform: scaleY(.22); } 50% { transform: scaleY(1); } }
/* No room beside the frame on a phone: the chip sits under it instead. */
@media (max-width: 560px) {
  .np { position: relative; left: auto; bottom: auto; width: auto; max-width: 360px; margin: 16px auto 0; }
}
/* Pages without the hero chip keep an unseen one that only drives the
   colour. It stays rendered (off screen) so its progress bar still ticks. */
.np.unseen { position: fixed; left: -9999px; top: 0; width: 330px; visibility: hidden; pointer-events: none; }

/* ---------- Sections ---------- */
section { padding: 112px 0; }
.sec-head { max-width: 46rem; margin-bottom: 56px; }
.sec-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.sec-head p { margin: 0; }
.rule { border-top: 1px solid var(--line); }

/* Works-with strip */
.with { padding: 96px 0 0; text-align: center; }
.with p { font-size: 13.5px; color: var(--fg-3); margin: 0 0 18px; }
.with ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 28px; }
.with li { font-weight: 600; font-size: 15px; color: var(--fg-2); letter-spacing: -0.01em; }

/* Why Leyr: four statements in a grid. */
.values { display: grid; gap: 16px; grid-template-columns: 1fr; }
@media (min-width: 760px) { .values { grid-template-columns: 1fr 1fr; } }
.value { padding: 32px; border-radius: var(--r-lg); border: 1px solid var(--line-2); background: radial-gradient(90% 70% at 0% 0%, var(--accent-soft), transparent 60%), var(--surface); }
.value h3 { font-size: 22px; letter-spacing: -0.02em; margin-bottom: 10px; }
.value p { margin: 0; color: var(--fg-2); }

/* Feature rows */
.row { display: grid; gap: 36px; align-items: center; grid-template-columns: 1fr; }
.row + .row { margin-top: 112px; }
@media (min-width: 900px) {
  .row { grid-template-columns: 5fr 7fr; gap: 64px; }
  .row.flip { grid-template-columns: 7fr 5fr; }
  .row.flip > .copy { order: 2; }
}
.copy p { margin: 0 0 22px; }
.checks { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.checks li { position: relative; padding-left: 30px; color: var(--fg-2); }
.checks li::before, .checks li::after { content: ""; position: absolute; left: 0; top: 3px; width: 18px; height: 18px; }
.checks li::before { border-radius: 50%; background: var(--accent-soft); }
/* A mask, not a coloured data URI, so the tick follows the tint. */
.checks li::after {
  background: var(--accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 12.5l4 4 8-9'/%3E%3C/svg%3E") center / 12px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 12.5l4 4 8-9'/%3E%3C/svg%3E") center / 12px no-repeat;
}

/* Card grid */
.grid { display: grid; gap: 1px; grid-template-columns: 1fr; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
@media (min-width: 640px) { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .grid { grid-template-columns: repeat(3, 1fr); } }
.card { background: var(--surface); padding: 28px; min-width: 0; transition: background-color .25s; }
.card:hover { background: var(--surface-2); }
.card p { margin: 0; color: var(--fg-2); font-size: 15px; }
.ic { width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center; margin-bottom: 18px; background: var(--accent-soft); color: var(--accent-ink); border: 1px solid var(--accent-line); }
.ic svg { width: 18px; height: 18px; }

/* Gallery */
.gallery { display: grid; gap: 16px; grid-template-columns: 1fr; margin-top: 56px; }
@media (min-width: 760px) { .gallery { grid-template-columns: repeat(3, 1fr); } }
.gallery figure { margin: 0; }
.gallery figcaption { margin-top: 12px; font-size: 14px; color: var(--fg-2); }

/* Demo band */
.demo-band { display: grid; gap: 40px; align-items: center; grid-template-columns: 1fr; padding: 48px; border-radius: 24px; border: 1px solid var(--line-2); background: radial-gradient(70% 90% at 0% 0%, var(--glow), transparent 60%), var(--surface); }
@media (min-width: 900px) { .demo-band { grid-template-columns: 5fr 7fr; } }
@media (max-width: 560px) { .demo-band { padding: 28px 20px; } }
.demo-band .frame { box-shadow: none; }
.demo-band a.frame { display: block; text-decoration: none; transition: transform .3s var(--ease), border-color .3s; }
.demo-band a.frame:hover { transform: translateY(-3px); border-color: var(--accent-line); }

/* Self-host specs */
.specs { display: grid; gap: 40px 32px; grid-template-columns: 1fr; }
@media (min-width: 640px) { .specs { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .specs { grid-template-columns: repeat(4, 1fr); } }
.spec { border-top: 1px solid var(--line-2); padding-top: 20px; }
.spec b { display: block; font-size: 15px; font-weight: 640; margin-bottom: 6px; letter-spacing: -0.01em; }
.spec span { color: var(--fg-2); font-size: 15px; }

/* Closing */
.closing { text-align: center; }
.closing h2 { max-width: 16ch; margin-left: auto; margin-right: auto; }
.closing p { max-width: 34rem; margin: 0 auto 32px; }

footer { padding: 32px 0 calc(32px + env(safe-area-inset-bottom)); color: var(--fg-3); font-size: 14px; border-top: 1px solid var(--line); }
footer .wrap { display: flex; flex-wrap: wrap; gap: 12px 24px; align-items: center; }
footer .logo .word { height: 13px; }
footer nav { display: flex; gap: 20px; flex-wrap: wrap; margin-left: auto; }
footer a { text-decoration: none; }
footer a:hover { color: var(--fg); }

/* ---------- Install page ---------- */
.doc { max-width: 780px; }
.doc .hero { text-align: left; padding-bottom: 8px; }
.doc .hero::before { display: none; }
.doc .hero h1 { margin-left: 0; font-size: clamp(38px, 6vw, 60px); }
.doc .hero .lede { margin-left: 0; margin-bottom: 0; }
.doc section { padding: 56px 0 0; }
.doc section:last-of-type { padding-bottom: 96px; }
.doc h2 { font-size: clamp(24px, 3.4vw, 32px); }
.note { border: 1px solid var(--line-2); border-left: 3px solid var(--accent); background: var(--surface); border-radius: var(--r); padding: 16px 18px; color: var(--fg-2); margin: 28px 0 0; }
.note b { color: var(--fg); }
.req { display: grid; gap: 1px; grid-template-columns: 1fr; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
@media (min-width: 640px) { .req { grid-template-columns: 1fr 1fr; } }
.req > div { background: var(--surface); padding: 24px; min-width: 0; }
.req ul { margin: 10px 0 0; padding-left: 18px; color: var(--fg-2); }
.req li { margin: 4px 0; }
.steps { counter-reset: step; display: grid; }
.step { position: relative; padding: 0 0 36px 52px; min-width: 0; }
.step::before {
  counter-increment: step; content: counter(step);
  position: absolute; left: 0; top: -2px; width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; font: 600 14px var(--sans);
  background: var(--accent-soft); color: var(--accent-ink); border: 1px solid var(--accent-line);
}
.step::after { content: ""; position: absolute; left: 15px; top: 34px; bottom: 6px; width: 1px; background: var(--line-2); }
.step:last-child::after { display: none; }
.step p { margin: 0 0 10px; color: var(--fg-2); }
pre {
  margin: 12px 0 0; padding: 18px; border-radius: var(--r); background: var(--bg-2); border: 1px solid var(--line-2);
  font: 13.5px/1.65 var(--mono); color: var(--fg); overflow-x: auto; white-space: pre;
}
pre .c { color: var(--fg-3); }
code { font-family: var(--mono); font-size: .9em; padding: 1px 6px; border-radius: 6px; background: var(--surface-2); border: 1px solid var(--line); color: var(--fg); }
pre code { padding: 0; border: 0; background: none; }

/* ---------- Cloud page ---------- */
.plans { display: grid; gap: 16px; grid-template-columns: 1fr; }
@media (min-width: 640px) { .plans { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1040px) { .plans { grid-template-columns: repeat(4, 1fr); } }
.plan { position: relative; }
.plan.featured { border-color: var(--accent-line); background: radial-gradient(120% 60% at 50% 0%, var(--accent-soft), transparent 70%), var(--surface); }
.plan .tag { position: absolute; top: -11px; left: 24px; margin: 0; padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; background: var(--accent); color: var(--on-accent); }
/* Co-location: a wide band under the rented plans. */
.colo { display: grid; gap: 20px 40px; align-items: start; grid-template-columns: 1fr; margin-top: 16px; padding: 28px; border-radius: var(--r-lg); border: 1px solid var(--line-2); background: var(--surface); }
@media (min-width: 900px) { .colo { grid-template-columns: 6fr 5fr; } .colo .price { grid-column: 1 / -1; } }
.colo h3 { font-size: 22px; margin: 0 0 10px; }
.colo p { margin: 0; color: var(--fg-2); }
.colo .eyebrow { margin-bottom: 8px; }
.colo .price { margin: 0; padding-top: 18px; border-top: 1px solid var(--line); font-weight: 600; color: var(--fg-2); }
/* Plan comparison: scrolls sideways on a phone rather than squashing. */
.compare { margin-top: 40px; overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-lg); }
.compare:focus-visible { outline-offset: 2px; }
.compare table { width: 100%; min-width: 720px; border-collapse: collapse; font-size: 14.5px; }
.compare th, .compare td { padding: 12px 16px; text-align: left; border-bottom: 1px solid var(--line); }
.compare tbody tr:last-child th, .compare tbody tr:last-child td { border-bottom: 0; }
.compare thead th { font-size: 13px; font-weight: 640; color: var(--fg); background: var(--surface); }
.compare tbody th { font-weight: 500; color: var(--fg-2); white-space: nowrap; }
.compare td { color: var(--fg); }
.compare td:nth-child(3), .compare thead th:nth-child(3) { background: var(--accent-soft); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Add-ons */
.addons { margin-top: 40px; }
.addons h3 { margin-bottom: 14px; }
.addons ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; grid-template-columns: 1fr; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
@media (min-width: 640px) { .addons ul { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .addons ul { grid-template-columns: repeat(4, 1fr); } }
.addons li { background: var(--surface); padding: 20px; }
.addons b { display: block; font-weight: 640; margin-bottom: 4px; }
.addons span { color: var(--fg-2); font-size: 14.5px; }
.plan { display: flex; flex-direction: column; padding: 28px; border-radius: var(--r-lg); border: 1px solid var(--line-2); background: var(--surface); min-width: 0; }
.plan h3 { font-size: 22px; margin: 0; }
.plan .who { margin: 4px 0 22px; color: var(--fg-3); font-size: 15px; }
.plan .price { margin: 24px 0 0; padding-top: 18px; border-top: 1px solid var(--line); font-weight: 600; color: var(--fg-2); }
.plan .price b, .colo .price b { font-size: 28px; font-weight: 700; letter-spacing: -0.02em; color: var(--fg); }
.plan .price span, .colo .price span { display: block; margin-top: 2px; font-size: 13.5px; font-weight: 500; color: var(--fg-3); }
.plan .checks { flex: 1; }
.doc-narrow { max-width: 820px; }
.faq { display: grid; gap: 10px; }
.faq details { border: 1px solid var(--line-2); border-radius: var(--r); background: var(--surface); padding: 0 20px; }
.faq summary { cursor: pointer; padding: 18px 0; font-weight: 600; list-style: none; display: flex; justify-content: space-between; gap: 16px; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--accent-ink); font-weight: 500; transition: transform .2s var(--ease); }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq details p { margin: 0 0 18px; color: var(--fg-2); }
.join { display: grid; gap: 40px; grid-template-columns: 1fr; padding: 48px; border-radius: 24px; border: 1px solid var(--line-2); background: radial-gradient(70% 90% at 0% 0%, var(--glow), transparent 60%), var(--surface); }
@media (min-width: 900px) { .join { grid-template-columns: 5fr 6fr; align-items: start; } }
@media (max-width: 560px) { .join { padding: 28px 20px; } }
.join .lede { margin: 0; }
.form { display: grid; gap: 16px; min-width: 0; }
.form label { display: grid; gap: 6px; font-size: 14px; font-weight: 600; color: var(--fg); min-width: 0; }
.form .opt { font-weight: 400; color: var(--fg-3); }
.form .pair { display: grid; gap: 16px; grid-template-columns: 1fr; }
@media (min-width: 520px) { .form .pair { grid-template-columns: 1fr 1fr; } }
.form input, .form select, .form textarea {
  width: 100%; min-width: 0; min-height: 44px; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line-2); background: var(--bg-2); color: var(--fg);
  font: 400 16px/1.4 var(--sans); transition: border-color .2s, box-shadow .2s;
}
.form textarea { resize: vertical; }
.form input:focus, .form select:focus, .form textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.form .btn { justify-self: start; }
.form .btn[aria-busy="true"] { opacity: .6; cursor: progress; transform: none; }
.form .trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.form .status { margin: 0; min-height: 1.6em; font-size: 15px; color: var(--fg-2); }
.form .status.ok { color: var(--accent-ink); }
.form .status.bad { color: var(--bad); }

/* ---------- Motion ----------
   Quiet by design: content fades up once as it enters, the hero wordmark
   lights dot by dot once, and the equalizer moves only while in view. */
.js .reveal { opacity: 0; transform: translateY(14px); transition: opacity .7s var(--ease), transform .7s var(--ease); transition-delay: var(--d, 0s); }
.js .reveal.in { opacity: 1; transform: none; }
.hero-in { animation: rise .8s var(--ease) both; animation-delay: var(--d, 0s); }
@keyframes rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .js .reveal { opacity: 1; transform: none; }
}
