/* ipaside.com — no framework, no tracker, no third-party request.
   Every colour below is lifted from the app's own theme
   (src/iPASide.Flutter/lib/ui/theme/palette.dart), so the site and the product
   cannot drift into looking like two different things. */

/* ── Inter, self-hosted and subset to Latin ─────────────────────────────── */
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/Inter-Regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/Inter-Medium.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/Inter-SemiBold.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/Inter-Bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

/* ── Tokens ─────────────────────────────────────────────────────────────── */
:root {
  --bg0: #0b0b0d;
  --bg1: #121215;
  --bg2: #1a1a1f;
  --hairline: #26262c;
  --hairline-strong: #34343c;
  --card-border: #2c2c37;
  --card-border-hover: #3a3a46;

  --text: #ededef;
  --text-2: #9c9ca6;
  --text-3: #6b6b76;

  --accent: #5e6ad2;
  --accent-hover: #6d78db;
  --accent-from: #6672e6;
  --accent-to: #8c5cf0;
  --accent-subtle: rgba(94, 106, 210, .15);
  --focus: #7d88e0;

  --success: #4cc38a;
  --success-bg: rgba(76, 195, 138, .15);
  --warning: #f0b429;

  --card-from: #1b1b23;
  --card-to: #141419;
  --card-hover-from: #212129;
  --card-hover-to: #18181e;

  --wrap: 1120px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 22px;
  /* Buttons and small controls, matching the app's Radii.small. The site used
     10px, which on a control this size reads noticeably rounder than the app. */
  --r-btn: 6px;
  /* The app's Radii.tiny, for inline code chips, focus rings and logo masks. */
  --r-tiny: 4px;

  /* Type scale. The app defines six sizes and uses only those; this keeps its
     values where there is an equivalent and adds the three a page needs that a
     1120x720 window does not: a hero heading, a lead paragraph, and the large
     figures in Limits. Nothing should introduce a size outside this list. */
  --fs-caption: 11.5px;
  --fs-small: 12.5px;
  --fs-body: 14px;
  --fs-lead: 15px;
  --fs-lead-lg: 16.5px;
  --fs-title: 18px;
  --fs-stat: 21px;
  --fs-hero-sm: 31px;

  /* Tracking: tight for headings, snug for large body, wide for uppercase. */
  --ls-tight: -.02em;
  --ls-snug: -.01em;
  --ls-caps: .06em;

  --shadow: 0 4px 16px -4px rgba(0, 0, 0, .35), 0 12px 32px -12px rgba(0, 0, 0, .45);
  --glow: 0 8px 28px -10px rgba(108, 114, 230, .55);

  /* The app's curve, exactly: Flutter's Curves.easeOutCubic is Cubic(0.215, 0.61,
     0.355, 1). The site used to run easeOutQuint — nearly the same control points
     on x, but 1.0 instead of 0.61 on y, which snaps hard and then glides. Same
     family, different feel, and the difference is what made the page read as a
     separate product from the app it is selling. */
  --ease: cubic-bezier(.215, .61, .355, 1);

  /* Durations, from the app's Motion tokens. Anything slower than --t-page is a
     deliberate exception (a scroll reveal, an ambient drift), not a default. */
  --t-fast: .12s;
  --t-base: .18s;
  --t-entrance: .22s;
  --t-page: .26s;

  /* The app presses to 98.5% under the pointer. Undoing a hover lift is not the
     same gesture: one is the surface acknowledging you, the other is it giving way. */
  --press-scale: .985;
}

/* ── Base ───────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 84px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg0);
  color: var(--text);
  font: 400 16px/1.65 "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

a { color: var(--accent-hover); text-decoration: none; }
a:hover { color: #8b95ec; text-decoration: underline; text-underline-offset: 3px; }

code, kbd {
  font-family: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
}
code {
  font-size: .88em;
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--hairline);
  border-radius: var(--r-tiny);
  padding: .1em .38em;
  color: #c9c9d4;
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: var(--r-tiny);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 12px;
  z-index: 100;
  background: var(--bg2);
  border: 1px solid var(--card-border);
  border-radius: var(--r-sm);
  padding: 10px 16px;
  color: var(--text);
}
.skip:focus { left: 16px; }

.wrap { width: min(var(--wrap), calc(100% - 44px)); margin-inline: auto; }
.wrap.narrow { width: min(760px, calc(100% - 44px)); }
.wrap.center { text-align: center; }

/* ── Atmosphere ─────────────────────────────────────────────────────────── */
/* The glows are deliberately bigger than the screen and hang off both edges, so
   they are clipped here rather than by overflow-x on the body. Hiding overflow on
   the body makes it a scroll container, which is the classic way to break the
   position:sticky header above without noticing. */
.sky {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background:
    radial-gradient(1200px 600px at 72% -8%, rgba(38, 39, 80, .55), transparent 62%),
    linear-gradient(180deg, #0e0e13 0%, #08080a 100%);
}

.glow {
  position: absolute;
  border-radius: 50%;
  opacity: .5;
  will-change: transform;
}
.glow-a {
  width: 620px; height: 620px;
  top: -220px; right: -140px;
  background: radial-gradient(circle, rgba(102, 114, 230, .30), transparent 68%);
  animation: breathe 17s var(--ease) infinite;
}
.glow-b {
  width: 520px; height: 520px;
  top: 780px; left: -200px;
  background: radial-gradient(circle, rgba(140, 92, 240, .22), transparent 68%);
  animation: breathe 23s var(--ease) infinite reverse;
}
@keyframes breathe {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(0, 42px, 0) scale(1.11); }
}

.grid-lines {
  position: absolute;
  inset: 0;
  opacity: .32;
  background-image:
    linear-gradient(rgba(255, 255, 255, .022) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .022) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(1000px 700px at 50% 0%, #000 20%, transparent 78%);
}

/* ── Nav ────────────────────────────────────────────────────────────────── */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(11, 11, 13, .72);
  backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-page) var(--ease), background-color var(--t-page) var(--ease);
}
/* At the very top the bar should not look like a bar; the moment content passes
   under it, it earns its edge. */
.nav.stuck {
  border-bottom-color: var(--hairline);
  background: rgba(11, 11, 13, .86);
}
.nav-in {
  display: flex;
  align-items: center;
  gap: 26px;
  height: 62px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--text);
  font-weight: 600;
  font-size: var(--fs-lead-lg);
  letter-spacing: var(--ls-snug);
}
.brand:hover { text-decoration: none; color: var(--text); }
.brand img { border-radius: var(--r-btn); }

.links { display: flex; gap: 22px; margin-left: 8px; }
.links a {
  position: relative;
  color: var(--text-2);
  font-size: var(--fs-body);
  font-weight: 500;
  padding: 3px 0;
  transition: color var(--t-base) var(--ease);
}
.links a:hover { color: var(--text); text-decoration: none; }

/* Which section you are actually in. The underline is drawn with a transform so it
   wipes in from the left rather than appearing, and costs no layout. */
.links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1.5px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-from), var(--accent-to));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-page) var(--ease);
}
.links a.on { color: var(--text); }
.links a.on::after { transform: scaleX(1); }

.nav-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  --btn-bg: transparent;
  display: inline-flex;
  border-radius: var(--r-btn);
  border: 1px solid var(--card-border);
  background: var(--btn-bg);
  color: var(--text);
  font-weight: 600;
  font-size: var(--fs-body);
  line-height: 1;
  transition: transform var(--t-base) var(--ease), border-color var(--t-base) var(--ease),
              background-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
}
.btn:hover { text-decoration: none; color: var(--text); transform: translateY(-1px); }

/* Pressing scales down, the way the app's buttons do, rather than only dropping the
   hover lift. Undoing a lift reads as the surface losing interest; scaling reads as
   it taking the press. Faster than the lift, because a press should feel immediate. */
.btn:active {
  transform: translateY(0) scale(var(--press-scale));
  transition-duration: var(--t-fast);
}
.btn-in { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; }

.btn.small .btn-in { padding: 8px 13px; font-size: var(--fs-body); }
.btn.big .btn-in { padding: 14px 22px; font-size: var(--fs-lead); }

.btn.ghost { background: rgba(255, 255, 255, .03); }
.btn.ghost:hover { border-color: var(--card-border-hover); background: rgba(255, 255, 255, .06); }

.btn.primary {
  border-color: transparent;
  background: linear-gradient(135deg, var(--accent-from), var(--accent-to));
  color: #fff;
  box-shadow: var(--glow);
}
.btn.primary:hover {
  background: linear-gradient(135deg, #7883ef, #9c6dfb);
  box-shadow: 0 10px 34px -10px rgba(120, 131, 239, .7);
}

.gh-stars {
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
  font-weight: 500;
  padding-left: 8px;
  margin-left: 2px;
  border-left: 1px solid var(--hairline);
}

.vchip {
  font-size: var(--fs-caption);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  padding: 3px 7px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .17);
  color: rgba(255, 255, 255, .92);
}
.vchip:empty { display: none; }

/* ── Type ───────────────────────────────────────────────────────────────── */
h1 {
  margin: 14px 0 0;
  font-size: clamp(34px, 5.1vw, 58px);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: var(--ls-tight);
}
h2 {
  margin: 0 0 14px;
  font-size: clamp(27px, 3.5vw, 40px);
  font-weight: 700;
  line-height: 1.14;
  letter-spacing: var(--ls-tight);
}
h3 {
  margin: 0 0 8px;
  font-size: var(--fs-lead-lg);
  font-weight: 600;
  letter-spacing: var(--ls-snug);
}

.grad {
  background: linear-gradient(100deg, var(--accent-from), var(--accent-to));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.kicker {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: var(--ls-snug);
}
.kick-dash {
  width: 26px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent));
}

.lede {
  margin: 18px 0 0;
  max-width: 56ch;
  color: var(--text-2);
  font-size: var(--fs-lead-lg);
  line-height: 1.68;
}
.lede code { font-size: .84em; }

.section-sub {
  margin: 0 0 34px;
  max-width: 62ch;
  color: var(--text-2);
  font-size: var(--fs-lead-lg);
}
.center .section-sub,
.center .lede { margin-inline: auto; }
.center .kicker { justify-content: center; }

.fineprint {
  margin: 16px 0 0;
  color: var(--text-3);
  font-size: var(--fs-body);
}
.small-note {
  margin-top: 26px;
  color: var(--text-3);
  font-size: var(--fs-body);
  font-style: italic;
}

/* ── Layout ─────────────────────────────────────────────────────────────── */
.section { padding: clamp(64px, 9vw, 116px) 0; }

/* Headings are held to a readable measure, except in a centred block — where a
   max-width with no auto margin parks the text on the left while everything around
   it is centred, which is exactly the wrong half of centring. The `.center` rule has
   to out-specify the one above it, not merely follow it. */
.section > .wrap > h2 { max-width: 20ch; }
.section > .wrap.center > h2 { max-width: none; }

/* ── Hero ───────────────────────────────────────────────────────────────── */
.hero { padding: clamp(48px, 7vw, 96px) 0 0; }
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
}
.cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.center .cta { justify-content: center; }

/* ── Hero demo ──────────────────────────────────────────────────────────── */
.demo {
  border: 1px solid var(--card-border);
  border-radius: var(--r-xl);
  background: linear-gradient(180deg, var(--card-from), var(--card-to));
  box-shadow: var(--shadow);
  overflow: hidden;
}
.demo-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 15px;
  border-bottom: 1px solid var(--hairline);
  background: rgba(255, 255, 255, .022);
}
.demo-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: #2f2f38;
}
.demo-title {
  margin-left: 8px;
  color: var(--text-2);
  font-size: var(--fs-small);
  font-weight: 600;
}
.demo-live {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-weight: 500;
}
.pulse {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 0 rgba(76, 195, 138, .6);
  animation: pulse 2.1s ease-out infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(76, 195, 138, .55); }
  70%  { box-shadow: 0 0 0 7px rgba(76, 195, 138, 0); }
  100% { box-shadow: 0 0 0 0 rgba(76, 195, 138, 0); }
}

.demo-body { padding: 18px; }

.dropzone {
  position: relative;
  border: 1.5px dashed var(--hairline-strong);
  border-radius: var(--r-lg);
  min-height: 92px;
  display: grid;
  place-items: center;
  padding: 16px;
  transition: border-color var(--t-page) var(--ease), background-color var(--t-page) var(--ease);
}
.dropzone.filled {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent-subtle);
}
.dz-idle {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  color: var(--text-3);
  font-size: var(--fs-body);
  transition: opacity var(--t-page) var(--ease), transform var(--t-page) var(--ease);
}
.dropzone.filled .dz-idle { opacity: 0; transform: scale(.94); position: absolute; }

.dz-file {
  display: flex;
  align-items: center;
  gap: 13px;
  width: 100%;
  opacity: 0;
  transform: translateY(9px);
  transition: opacity .32s var(--ease), transform .32s var(--ease);
}
.dropzone.filled .dz-file { opacity: 1; transform: none; }

.dz-icon {
  width: 42px; height: 42px;
  flex: none;
  border-radius: var(--r-btn);
  background:
    radial-gradient(circle at 32% 28%, #ff5a8a, transparent 58%),
    radial-gradient(circle at 72% 76%, #7b3ff2, transparent 62%),
    linear-gradient(140deg, #f9a03f, #d6249f 58%, #4f5bd5);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .13);
}
.dz-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dz-meta strong { font-size: var(--fs-lead); font-weight: 600; }
.dz-meta span {
  color: var(--text-3);
  font-size: var(--fs-small);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dz-ok {
  margin-left: auto;
  flex: none;
  display: grid;
  place-items: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--success-bg);
  color: var(--success);
}

.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin: 18px 0 0;
  padding: 0;
  list-style: none;
}
.step {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 11px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-btn);
  background: rgba(255, 255, 255, .02);
  color: var(--text-3);
  font-size: var(--fs-small);
  font-weight: 500;
  transition: color var(--t-page) var(--ease), border-color var(--t-page) var(--ease),
              background-color var(--t-page) var(--ease);
}
.s-dot {
  width: 8px; height: 8px;
  flex: none;
  border-radius: 50%;
  background: #33333c;
  transition: background-color var(--t-page) var(--ease), box-shadow var(--t-page) var(--ease);
}
.step.on {
  color: var(--text);
  border-color: rgba(94, 106, 210, .5);
  background: var(--accent-subtle);
}
.step.on .s-dot {
  background: var(--accent-hover);
  box-shadow: 0 0 0 4px rgba(94, 106, 210, .18);
}
.step.ok { color: var(--text-2); border-color: rgba(76, 195, 138, .32); }
.step.ok .s-dot { background: var(--success); box-shadow: none; }

.prog { margin-top: 16px; }
.prog-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.prog-step {
  color: var(--text-2);
  font-size: var(--fs-small);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prog-pct {
  color: var(--text);
  font-size: var(--fs-small);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.bar {
  height: 6px;
  border-radius: 999px;
  background: #202027;
  overflow: hidden;
}
.bar > i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent-from), var(--accent-to));
  /* Shorter than the interval between updates (230ms during the upload), so each
     step actually arrives before the next one restarts it. A longer transition
     never reaches its target and the bar reads as permanently behind. Linear,
     because easing a progress bar makes steady work look like it is stalling. */
  transition: width var(--t-base) linear;
}

.demo-done {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 14px;
  padding: 10px 12px;
  border: 1px solid rgba(76, 195, 138, .3);
  border-radius: var(--r-btn);
  background: var(--success-bg);
  color: #b7e8ce;
  font-size: var(--fs-small);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--t-page) var(--ease), transform var(--t-page) var(--ease);
}
.demo-done.show { opacity: 1; transform: none; }
.demo-done svg { flex: none; color: var(--success); }
.demo-done em { color: #8fd9b4; font-style: normal; }

/* ── Screenshots ────────────────────────────────────────────────────────── */
.shot-sec { padding-top: clamp(52px, 7vw, 92px); }
.shot-frame {
  position: relative;
  border: 1px solid var(--card-border);
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--bg1);
  box-shadow: 0 24px 70px -28px rgba(0, 0, 0, .8);
}
.shot-edge {
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
}
.shot-cap {
  margin: 18px auto 0;
  max-width: 60ch;
  text-align: center;
  color: var(--text-3);
  font-size: var(--fs-body);
}

.shots-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
  margin-top: 46px;
}
.shots-row img {
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}

/* ── Cards ──────────────────────────────────────────────────────────────── */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
  gap: 18px;
}
.card {
  position: relative;
  padding: 24px 22px 22px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--card-from), var(--card-to));
  transition: border-color var(--t-entrance) var(--ease), transform var(--t-entrance) var(--ease),
              box-shadow var(--t-entrance) var(--ease), background-color var(--t-entrance) var(--ease);
}
.card:hover {
  border-color: var(--card-border-hover);
  /* -3px and a lighter gradient, both as the app's cards do. The site lifted and
     changed its border but left the surface itself alone, which is the difference
     between a card that responds and one that merely moves. */
  transform: translateY(-3px);
  background: linear-gradient(180deg, var(--card-hover-from), var(--card-hover-to));
  box-shadow: var(--shadow);
}
.card p { margin: 0; color: var(--text-2); font-size: var(--fs-lead); line-height: 1.68; }
.card h3 { margin-top: 14px; }
.card em { color: #b9b9c4; font-style: italic; }
.card strong { color: var(--text); font-weight: 600; }

.card-ico {
  display: block;
  width: 34px; height: 34px;
  border-radius: var(--r-sm);
  border: 1px solid rgba(94, 106, 210, .3);
  background: var(--accent-subtle) no-repeat center / 18px 18px;
}
/* Inline SVG as data URIs: one file fewer to fetch, and they inherit nothing so
   they cannot be recoloured by a stray rule. */
.i-sign    { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3l7 3v5c0 4.4-2.9 8.3-7 9.5C7.9 19.3 5 15.4 5 11V6l7-3z'/%3E%3Cpath d='M9.2 11.8l2 2 3.6-3.8'/%3E%3C/svg%3E"); }
.i-local   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='12' rx='2'/%3E%3Cpath d='M8 20h8M12 16v4'/%3E%3C/svg%3E"); }
.i-tweak   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 3l-6.5 6.5'/%3E%3Cpath d='M14.5 3H21v6.5'/%3E%3Cpath d='M10 6H5a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-5'/%3E%3C/svg%3E"); }
.i-clock   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5.2l3.4 2'/%3E%3C/svg%3E"); }
.i-device  { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='2.5' width='9' height='15' rx='2'/%3E%3Crect x='13' y='9' width='7' height='12.5' rx='1.8'/%3E%3C/svg%3E"); }
/* Two overlapping figures: more than one Apple ID signed in at the same time. */
.i-accounts{ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9.2' cy='8' r='3.2'/%3E%3Cpath d='M3.6 19.4c.5-3 2.8-4.7 5.6-4.7s5.1 1.7 5.6 4.7'/%3E%3Cpath d='M16.4 5.3a3.2 3.2 0 0 1 0 5.6'/%3E%3Cpath d='M17.6 14.9c1.9.5 3.3 2 3.7 4.5'/%3E%3C/svg%3E"); }
/* Stacked plates: many apps carried by the one the phone actually counts. */
.i-stack   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2.8 21 7.4l-9 4.6-9-4.6z'/%3E%3Cpath d='M3 12.2l9 4.6 9-4.6'/%3E%3Cpath d='M3 16.6l9 4.6 9-4.6'/%3E%3C/svg%3E"); }
/* A phone with a cycle arrow: the phone doing its own re-signing. */
.i-refresh { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b95ec' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='6' y='2.5' width='12' height='19' rx='2.4'/%3E%3Cpath d='M9.4 11.4a2.9 2.9 0 0 1 5-1.7l.9.9'/%3E%3Cpath d='M14.6 13.2a2.9 2.9 0 0 1-5 1.7l-.9-.9'/%3E%3Cpath d='M15.4 8.2v2.4H13'/%3E%3Cpath d='M8.6 16.4V14h2.4'/%3E%3C/svg%3E"); }

/* ── Timeline ───────────────────────────────────────────────────────────── */
/* The rail is placed against .tl, the dots against .tl-item whose left edge is this
   padding. Deriving both from these keeps them on one axis when a breakpoint changes
   the padding - which it does, and which used to put the dots 4px left of the line. */
.tl {
  --tl-pad: 26px;
  --tl-rail: 6px;
  --tl-dot: 12px;
  position: relative;
  margin-top: 34px;
  padding-left: var(--tl-pad);
}
.tl::before {
  content: "";
  position: absolute;
  left: calc(var(--tl-rail) - 1px); top: 8px; bottom: 8px;
  width: 2px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--accent), rgba(140, 92, 240, .18));
}
.tl-item { position: relative; padding-bottom: 20px; }
.tl-item:last-child { padding-bottom: 0; }
.tl-dot {
  position: absolute;
  /* Come back out of .tl's padding to the rail, then half a dot further. */
  left: calc(var(--tl-rail) - var(--tl-pad) - var(--tl-dot) / 2); top: 20px;
  width: var(--tl-dot); height: var(--tl-dot);
  border-radius: 50%;
  background: var(--bg2);
  border: 2px solid var(--accent);
}
.tl-dot.on {
  background: var(--accent);
  box-shadow: 0 0 0 5px rgba(94, 106, 210, .16);
}
.tl-card {
  padding: 18px 20px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--card-from), var(--card-to));
}
.tl-card.accent { border-color: rgba(94, 106, 210, .38); }
.tl-card p { margin: 0; color: var(--text-2); font-size: var(--fs-lead); }
.tl-card strong { color: var(--text); }

/* ── Tweaks + terminal ──────────────────────────────────────────────────── */
.tweaks-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(30px, 5vw, 58px);
  align-items: center;
}
.ticks { margin: 0; padding: 0; list-style: none; display: grid; gap: 13px; }
.ticks li {
  position: relative;
  padding-left: 28px;
  color: var(--text-2);
  font-size: var(--fs-lead);
  line-height: 1.62;
}
.ticks li::before {
  content: "";
  position: absolute;
  left: 0; top: .44em;
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--success-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234cc38a' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.5l5 5L20 6.5'/%3E%3C/svg%3E") no-repeat center / 9px 9px;
}

.term {
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  background: #0a0a0e;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.term-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--hairline);
  background: rgba(255, 255, 255, .022);
}
.term-title { margin-left: 8px; color: var(--text-3); font-size: var(--fs-small); }
.term-body {
  margin: 0;
  padding: 16px;
  /* Holds the complete six-line demo so typing never moves the page. */
  min-height: 210px;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
  font-size: var(--fs-small);
  line-height: 1.78;
  color: #a9b4c8;
}
.term-caret {
  display: inline-block;
  width: 7px;
  height: 14px;
  vertical-align: -2px;
  background: var(--accent-hover);
  animation: blink 1.1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* ── Limits ─────────────────────────────────────────────────────────────── */
/* Two by two rather than auto-fit: four cards in a 760px column pack as 3 + 1,
   which reads as a mistake rather than as a list. */
.limits {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin-top: 32px;
}
@media (max-width: 620px) {
  .limits { grid-template-columns: minmax(0, 1fr); }
}
.limit {
  padding: 20px;
  border: 1px solid var(--card-border);
  border-left: 2px solid var(--warning);
  border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--card-from), var(--card-to));
}
.limit-n {
  display: block;
  margin-bottom: 8px;
  color: var(--warning);
  font-size: var(--fs-stat);
  font-weight: 700;
  letter-spacing: var(--ls-tight);
}
.limit p { margin: 0; color: var(--text-2); font-size: var(--fs-body); line-height: 1.62; }

/* ── FAQ ────────────────────────────────────────────────────────────────── */
details {
  border-bottom: 1px solid var(--hairline);
  padding: 4px 0;
  /* Lets `height: auto` be animated to, which is what makes the open/close glide
     instead of jump. Browsers without it simply toggle instantly. */
  interpolate-size: allow-keywords;
}
details summary {
  cursor: pointer;
  list-style: none;
  padding: 16px 34px 16px 0;
  position: relative;
  color: var(--text);
  font-size: var(--fs-lead-lg);
  font-weight: 600;
  letter-spacing: var(--ls-snug);
  transition: color var(--t-base) var(--ease);
}
details summary::-webkit-details-marker { display: none; }
details summary:hover { color: var(--accent-hover); }
details summary::after {
  content: "";
  position: absolute;
  right: 4px; top: 50%;
  width: 9px; height: 9px;
  border-right: 2px solid var(--text-3);
  border-bottom: 2px solid var(--text-3);
  transform: translateY(-70%) rotate(45deg);
  transition: transform var(--t-page) var(--ease), border-color var(--t-base) var(--ease);
}
details summary:hover::after { border-color: var(--accent-hover); }
details[open] summary::after { transform: translateY(-30%) rotate(-135deg); }

/* The answer's own box animates open; the text inside fades up a beat later so the
   panel is already the right size by the time there is anything to read in it. */
details::details-content {
  block-size: 0;
  overflow-y: clip;
  transition: block-size .32s var(--ease), content-visibility .32s allow-discrete;
}
details[open]::details-content { block-size: auto; }

details p {
  margin: 0 0 18px;
  padding-right: 34px;
  color: var(--text-2);
  font-size: var(--fs-lead);
  line-height: 1.7;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity var(--t-page) var(--ease) var(--t-fast), transform var(--t-page) var(--ease) var(--t-fast);
}
details[open] p { opacity: 1; transform: none; }

/* ── Final CTA ──────────────────────────────────────────────────────────── */
.cta-final {
  border-top: 1px solid var(--hairline);
  background:
    radial-gradient(720px 300px at 50% 0%, rgba(94, 106, 210, .12), transparent 68%);
}
.cta-final h2 { margin-top: 16px; }

/* ── Footer ─────────────────────────────────────────────────────────────── */
.footer {
  border-top: 1px solid var(--hairline);
  padding: 34px 0 40px;
  background: rgba(0, 0, 0, .28);
}
.foot-in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 26px;
}
.foot-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text-3);
  font-size: var(--fs-body);
}
.foot-brand img { border-radius: var(--r-tiny); opacity: .85; }
.foot-links { display: flex; flex-wrap: wrap; gap: 20px; margin-left: auto; }
.foot-links a { color: var(--text-2); font-size: var(--fs-body); }
.foot-legal {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--hairline);
}
.foot-legal p {
  margin: 0;
  max-width: 92ch;
  color: var(--text-3);
  font-size: var(--fs-small);
  line-height: 1.66;
}
.foot-legal code { font-size: .92em; }

/* ── Reveals ────────────────────────────────────────────────────────────── */
.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .58s var(--ease), transform .58s var(--ease);
}
.js .reveal.in { opacity: 1; transform: none; }
.js .reveal:nth-child(2) { transition-delay: .05s; }
.js .reveal:nth-child(3) { transition-delay: .1s; }
.js .reveal:nth-child(4) { transition-delay: .15s; }
.js .reveal:nth-child(5) { transition-delay: .2s; }
.js .reveal:nth-child(6) { transition-delay: .25s; }

/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 980px) {
  .hero-grid, .tweaks-grid { grid-template-columns: minmax(0, 1fr); }
  .demo { max-width: 560px; }
  .links { display: none; }
}

/* ── Phones ──────────────────────────────────────────────────────────────────
   Below this width the page is one column. Lists lose their boxes and become rows,
   which is shorter and easier to skim with a thumb. */
@media (max-width: 760px) {
  .wrap, .wrap.narrow { width: calc(100% - 32px); }
  .hero { padding-top: 36px; }
  .section { padding: 58px 0; }

  /* Icon beside the heading rather than above it: a 34px block on its own line cost
     about 45px per card, and six of those is a screenful of nothing. */
  .card { display: grid; grid-template-columns: auto 1fr; column-gap: 12px; }
  .card-ico { grid-row: 1; width: 30px; height: 30px; background-size: 16px 16px; }
  .card h3 { grid-column: 2; margin: 0; align-self: center; }
  /* Full width rather than indented under the heading: the hanging indent looked
     tidy but cost ~45px of measure on a 390px screen, which is a wrapped word on
     every line. */
  .card p { grid-column: 1 / -1; margin-top: 11px; }

  /* The limits are four facts, not four cards. */
  .limits {
    display: block;
    margin-top: 24px;
    border-top: 1px solid var(--hairline);
  }
  /* Label above the text, not beside it, so every paragraph keeps the full width. */
  .limit {
    padding: 14px 2px;
    border: 0;
    border-bottom: 1px solid var(--hairline);
    border-radius: 0;
    background: none;
  }
  .limit-n { margin-bottom: 4px; font-size: var(--fs-lead); }
  .limit p { font-size: var(--fs-body); }

  /* Brand + GitHub + star count + Download does not fit a phone; the mark alone is
     recognisable enough, and the count is the part worth keeping. Dropped here rather
     than at 480 because this is the width where the row runs out of room. */
  .nav-in { gap: 12px; }
  .nav-actions { gap: 8px; flex-shrink: 0; }
  .gh-label { display: none; }
  .gh-stars { border-left: 0; padding-left: 0; }

  /* One button per row: a thumb is a blunter instrument than a cursor, and two
     side by side squeezed "Download for Windows" onto two lines. Centre the stack
     and cap the width so each one reads as a button, not a full-bleed bar touching
     both edges. */
  .cta { flex-direction: column; align-items: center; gap: 10px; }
  .cta .btn { flex: 0 0 auto; width: auto; max-width: 100%; }
  .cta .btn-in { justify-content: center; }

  .shots-row { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .steps { grid-template-columns: minmax(0, 1fr); }
  .foot-in { flex-direction: column; align-items: flex-start; gap: 18px; }
  .foot-links { margin-left: 0; gap: 14px 18px; }
  .foot-legal { margin-top: 16px; padding-top: 16px; }
  .tl { --tl-pad: 22px; }
  .demo-body { padding: 14px; }
  details summary { font-size: var(--fs-lead); padding-right: 30px; }

  .term-body { font-size: var(--fs-caption); padding: 14px; min-height: 220px; }
}

@media (max-width: 480px) {
  .wrap, .wrap.narrow { width: calc(100% - 24px); }
  h1 { font-size: var(--fs-hero-sm); letter-spacing: var(--ls-tight); }
  .lede { font-size: var(--fs-lead-lg); }
  .section { padding: 48px 0; }
  .section-sub { font-size: var(--fs-lead); margin-bottom: 26px; }
  .card { padding: 20px 18px 18px; }
  .limits { gap: 12px; }
  /* Two words on one line beats one word per line. */
  .limit-n { font-size: var(--fs-title); }
  .foot-legal p { font-size: var(--fs-caption); }
}

/* A little extra room for wrapping on the narrowest phones. */
@media (max-width: 440px) {
  .term-body { min-height: 230px; }
}

/* Touch: nothing is revealed by hover, and every target you are meant to hit is
   big enough for a fingertip. Links inside a sentence are left alone — WCAG exempts
   them, and padding them out would wreck the line spacing of the paragraph. */
@media (pointer: coarse) {
  .card:hover, .btn:hover { transform: none; }
  details summary { padding-top: 18px; padding-bottom: 18px; }
  .foot-links { gap: 4px 18px; }
  .foot-links a { padding: 10px 0; }
  .links a { padding: 10px 0; }
  .brand { padding: 6px 0; }
  /* Every button in the bar, by position rather than by a class name — an earlier
     version of this rule named .nav-cta, which does not exist in the markup, so the
     download button stayed at 32px while the rule looked like it was doing its job. */
  .nav-actions .btn .btn-in { padding-top: 11px; padding-bottom: 11px; }
}

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

/* ── LiveContainer + SideStore spotlight ─────────────────────────────── */
.lc-spot { padding-top: clamp(24px, 4vw, 48px); }
.lc-card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(24px, 4vw, 44px);
  align-items: center;
  padding: clamp(28px, 4vw, 44px);
  border-radius: 20px;
  border: 1px solid var(--card-border);
  background: linear-gradient(135deg, var(--card-from), var(--card-to));
  position: relative;
  overflow: hidden;
}
.lc-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(680px 360px at 6% -10%, var(--accent-subtle), transparent 68%);
  pointer-events: none;
}
.lc-icon {
  width: 96px;
  height: 96px;
  border-radius: 22px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .45);
  position: relative;
}
.lc-body { position: relative; }
.lc-eyebrow {
  display: inline-block;
  color: var(--accent-hover);
  font-weight: 600;
  font-size: .78rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.lc-body h2 {
  margin: 0 0 10px;
  font-size: clamp(1.5rem, 3.2vw, 2.1rem);
  line-height: 1.15;
}
.lc-body > p { color: var(--text-2); max-width: 62ch; margin: 0; }
.lc-points {
  list-style: none;
  padding: 0;
  margin: 18px 0 0;
  display: grid;
  gap: 10px;
}
.lc-points li { position: relative; padding-left: 26px; color: var(--text-2); }
.lc-points li strong { color: var(--text); }
.lc-points li::before {
  content: "\2713";
  position: absolute;
  left: 0;
  top: -1px;
  color: var(--accent-hover);
  font-weight: 700;
}
@media (max-width: 760px) {
  .lc-card { grid-template-columns: 1fr; text-align: center; }
  .lc-icon { justify-self: center; }
  .lc-body > p { margin-inline: auto; }
  .lc-points { text-align: left; max-width: 46ch; margin-inline: auto; }
}
