/* E.N.D landing page.
   The palette is lifted straight from the bot's card renderer
   (src/utils/infoCard.js, cardKit.js) so the site and the images it
   shows read as one system: same background, same panels, same accent
   after readable() lifts it, same corner radii. Nothing is loaded from
   a third party, no font request, no analytics. */

:root {
  --bg: #16181d;
  --panel: #1e2126;
  --pill: #141619;
  --line: #2c2f36;
  --text: #ffffff;
  --body: #c5c8ce;
  --muted: #8a8e96;
  --accent: #5880ff;
  --green: #3a9d3a;
  /* The card canvas is 934px wide: the page shares its measure so a
     screenshot sits at its native size, unscaled. */
  --measure: 934px;
  --radius: 16px;
  --font: "Segoe UI", "DejaVu Sans", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--body);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { color: var(--text); line-height: 1.25; margin: 0; }
h1 { font-size: clamp(2rem, 5vw, 3rem); letter-spacing: -0.02em; }
h2 { font-size: 1.5rem; letter-spacing: -0.01em; }
h3 { font-size: 1rem; }
p { margin: 0; }
/* The UA gives <figure> 40px of side margin, which quietly shaved 80px
   off every card, on every screen size. */
figure { margin: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }

.wrap { width: 100%; max-width: var(--measure); margin: 0 auto; padding: 0 20px; }

/* ── Header ─────────────────────────────────────────────────── */
header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(22, 24, 29, 0.85);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.bar { display: flex; align-items: center; gap: 16px; height: 62px; }
.brand { color: var(--text); font-weight: 700; letter-spacing: 0.08em; font-size: 1rem; }
/* The 404 page uses the wordmark as a link home. Kept here rather than
   inline: the Content-Security-Policy in site/_headers forbids inline
   styles, and a policy you have to weaken for a decoration is not one. */
a.brand { text-decoration: none; }
a.brand:hover { color: var(--accent); }
.bar nav { margin-left: auto; display: flex; align-items: center; gap: 18px; }
.bar nav a { color: var(--muted); font-size: 0.9rem; }
.bar nav a:hover { color: var(--text); text-decoration: none; }

.langs { display: flex; gap: 4px; background: var(--pill); border: 1px solid var(--line); border-radius: 999px; padding: 3px; }
.langs button {
  border: 0; background: none; color: var(--muted); cursor: pointer;
  font: inherit; font-size: 0.78rem; padding: 3px 9px; border-radius: 999px;
}
.langs button[aria-pressed="true"] { background: var(--panel); color: var(--text); }

/* ── Buttons ────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 20px; border-radius: 12px;
  font-weight: 600; font-size: 0.95rem; white-space: nowrap;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); color: #0d1017; }
.btn-primary:hover { filter: brightness(1.08); }
.btn-ghost { background: var(--panel); color: var(--text); border: 1px solid var(--line); }
.btn-ghost:hover { border-color: var(--muted); }

/* ── Hero ───────────────────────────────────────────────────── */
.hero { padding: 80px 0 56px; text-align: center; position: relative; }
/* The cards carry a soft coloured band at the top; the page echoes it
   once, faintly, instead of decorating every section. */
.hero::before {
  content: "";
  position: absolute; inset: -120px 0 auto 0; height: 320px; z-index: -1;
  background: radial-gradient(60% 100% at 50% 0%, rgba(88, 128, 255, 0.14), transparent 70%);
}
.hero p.lead { font-size: 1.1rem; max-width: 620px; margin: 18px auto 0; }
.hero .cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 30px; }
.badges { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 26px; }
.badge {
  background: var(--pill); border: 1px solid var(--line); color: var(--muted);
  border-radius: 999px; padding: 5px 13px; font-size: 0.82rem;
}

/* ── Stat strip ─────────────────────────────────────────────── */
/* A <dl>: each figure is the term and its label the description, which
   is what a screen reader should hear. The numbers are in the markup at
   their final value, so the page without JavaScript is not a row of
   zeroes; the count-up only replaces text that is already correct. */
.stats {
  margin: 40px auto 0; padding: 0; max-width: 620px;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
}
.stat {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 8px;
}
.stat .num {
  color: var(--text); font-size: 1.6rem; font-weight: 700;
  letter-spacing: -0.02em; line-height: 1.1;
  /* The digits change width as they count; tabular figures stop the box
     from twitching on every frame. */
  font-variant-numeric: tabular-nums;
}
.stat dd { margin: 4px 0 0; color: var(--muted); font-size: 0.78rem; }

/* ── Sections ───────────────────────────────────────────────── */
section { padding: 56px 0; }
.head { margin-bottom: 28px; }
.head p { color: var(--muted); margin-top: 8px; }

.grid { display: grid; gap: 14px; grid-template-columns: repeat(3, 1fr); }
.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px;
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}
.card:hover {
  transform: translateY(-3px);
  border-color: rgba(88, 128, 255, 0.45);
  box-shadow: 0 14px 34px -18px rgba(0, 0, 0, 0.9);
}
/* The glyph is a block, so its box is as wide as the card while the
   emoji sits at the left edge of it. Scaling from the default centre
   therefore pushed the emoji left, out of the card's padding, which is
   the opposite of growing in place. Anchoring the origin to the left
   edge of the box, which is where the emoji actually is, keeps it put
   and costs no layout change. */
.card .glyph {
  font-size: 1.25rem; line-height: 1;
  transform-origin: left center;
  transition: transform 0.25s ease;
}
.card:hover .glyph { transform: scale(1.12); }
.card h3 { margin: 10px 0 6px; }
.card p { color: var(--muted); font-size: 0.9rem; }

/* ── Showcase ───────────────────────────────────────────────── */
/* minmax(0, 1fr) rather than a bare single column: an auto track sizes
   itself on the intrinsic width of the card inside it and ends up
   narrower than its container, leaving the figures floating short of
   the page measure. */
.shots { display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px; }
.shot { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; }
.shot img { border-radius: 10px; width: 100%; height: auto; }
.zoom { display: block; position: relative; }
.zoom::after {
  content: "⤢";
  position: absolute; right: 10px; bottom: 10px;
  width: 30px; height: 30px; border-radius: 8px;
  display: grid; place-items: center;
  background: rgba(20, 22, 25, 0.82); border: 1px solid var(--line);
  color: var(--body); font-size: 0.9rem;
  opacity: 0; transition: opacity 0.15s;
}
.zoom:hover::after, .zoom:focus-visible::after { opacity: 1; }
.shot figcaption { color: var(--muted); font-size: 0.85rem; margin-top: 12px; padding: 0 4px; }

/* ── Trust ──────────────────────────────────────────────────── */
.trust { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; }
.trust ul { margin: 18px 0 0; padding: 0; list-style: none; display: grid; gap: 14px; }
.trust li { display: flex; gap: 12px; align-items: flex-start; font-size: 0.95rem; }
.trust li span:first-child { color: var(--green); flex: 0 0 auto; }

/* ── Skip link ──────────────────────────────────────────────── */
/* Off-screen until it takes focus, which is the first thing a keyboard
   reader tabs into: it lets them past the header instead of walking the
   whole navigation on every page. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 20;
  background: var(--accent); color: #0d1017; font-weight: 600;
  padding: 10px 16px; border-radius: 0 0 12px 0;
}
.skip:focus { left: 0; text-decoration: none; }

/* A visible ring only for keyboard focus, so the mouse is not followed
   by outlines while the keyboard is never left guessing. */
a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px;
}

/* ── Commands page (generated) ──────────────────────────────── */
.commands { padding: 40px 20px 64px; }
.commands .head { margin-bottom: 34px; }
.commands h1 { font-size: 2rem; }
.commands .lead { font-size: 1.05rem; max-width: 620px; margin-top: 12px; }
.commands .note { color: var(--muted); font-size: 0.9rem; margin-top: 10px; }
.cmd-group { padding: 0 0 10px; }
.group-head {
  position: sticky; top: 62px; z-index: 5;
  background: var(--bg); padding: 14px 0 10px; margin: 0 0 12px;
  border-bottom: 1px solid var(--line);
}
.cmd-group h2 { display: flex; align-items: center; gap: 10px; }
.cmd-group h2 .glyph { font-size: 1.2rem; }

/* The category tiles, the same object as the module cards on the landing
   page because they do the same job. */
.cat-grid { margin-top: 4px; }
.cat-tile { display: block; color: inherit; }
.cat-tile:hover { text-decoration: none; }
.cat-tile h3 { color: var(--text); }
.tile-count {
  display: inline-block; margin-top: 12px;
  background: var(--pill); border: 1px solid var(--line); color: var(--muted);
  border-radius: 999px; padding: 3px 11px; font-size: 0.78rem;
}
.tile-count b { color: var(--text); }

/* Without JavaScript the back link is a link to nowhere, so it only
   exists once boot.js has proved there is JavaScript to go back with. */
.back { display: none; }
.anim .back {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--muted); font-size: 0.86rem; margin-bottom: 10px;
  background: none; border: 0; cursor: pointer; font-family: inherit;
}
.anim .back:hover { color: var(--text); text-decoration: none; }
.anim .back span[aria-hidden] { transition: transform 0.2s ease; }
.anim .back:hover span[aria-hidden] { transform: translateX(-3px); }

/* One category at a time, but only when there is JavaScript to switch
   between them: .anim comes from boot.js, and boot.js takes it back off
   if app.js never reports for duty, which turns the page back into the
   full list rather than leaving it empty. */
.anim body.cmds .cmd-group { display: none; }
.anim body.cmds .cmd-group.open { display: block; animation: group-in 0.4s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.anim body.cmds.viewing .cat-grid { display: none; }

@keyframes group-in {
  from { opacity: 0; transform: translate3d(0, 12px, 0); }
  to { opacity: 1; transform: none; }
}
/* The commands inside arrive just behind their section, in order. Eight
   steps is the whole of the largest category in under half a second. */
.anim body.cmds .cmd-group.open .cmd { animation: group-in 0.4s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.anim body.cmds .cmd-group.open .cmd:nth-child(2) { animation-delay: 0.03s; }
.anim body.cmds .cmd-group.open .cmd:nth-child(3) { animation-delay: 0.06s; }
.anim body.cmds .cmd-group.open .cmd:nth-child(4) { animation-delay: 0.09s; }
.anim body.cmds .cmd-group.open .cmd:nth-child(5) { animation-delay: 0.12s; }
.anim body.cmds .cmd-group.open .cmd:nth-child(6) { animation-delay: 0.15s; }
.anim body.cmds .cmd-group.open .cmd:nth-child(7) { animation-delay: 0.18s; }
.anim body.cmds .cmd-group.open .cmd:nth-child(n+8) { animation-delay: 0.21s; }
.cmd {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 10px;
}
.cmd h3 { display: flex; align-items: center; gap: 8px; font-size: 0.98rem; font-family: var(--font); }
.cmd h3 .glyph { font-size: 1.05rem; }
.cmd p { color: var(--muted); font-size: 0.9rem; margin-top: 6px; }
.subs { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 6px; }
.subs li {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: baseline;
  font-size: 0.86rem; color: var(--muted);
  border-top: 1px solid var(--line); padding-top: 6px;
}
.subs code {
  background: var(--pill); border: 1px solid var(--line); border-radius: 6px;
  padding: 1px 7px; color: var(--body); white-space: nowrap;
}

/* ── Premium page ───────────────────────────────────────────── */
.prem-head { text-align: center; max-width: 720px; margin: 0 auto 34px; }
.prem-head .lead { margin-left: auto; margin-right: auto; }
/* Says the shop is shut before anyone reads a price. Nobody likes
   finding that out at the end. */
.pill-soon {
  display: inline-block; margin-bottom: 14px;
  background: var(--pill); border: 1px solid var(--line); color: var(--muted);
  border-radius: 999px; padding: 5px 14px; font-size: 0.8rem;
}
.promise {
  display: flex; gap: 14px; text-align: left;
  background: var(--panel); border: 1px solid var(--line);
  border-left: 3px solid var(--green);
  border-radius: var(--radius); padding: 16px 18px; margin: 24px 0 0;
}
.promise p { color: var(--body); font-size: 0.9rem; }
.promise-mark { flex: 0 0 auto; font-size: 1.1rem; line-height: 1.5; }

/* Monthly / yearly. Both prices are in the markup and this only decides
   which one is visible, so nothing here can quote a wrong figure. */
.billing {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 26px;
  background: var(--pill); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px;
}
.billing button {
  border: 0; background: none; color: var(--muted); cursor: pointer;
  font: inherit; font-size: 0.86rem; padding: 7px 16px; border-radius: 999px;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.billing button[aria-pressed="true"] { background: var(--panel); color: var(--text); }
.billing button { display: inline-flex; align-items: center; gap: 8px; }
/* The discount rides on the button that gives it, so choosing yearly and
   reading why are the same glance. */
.billing .save {
  background: rgba(58, 157, 58, 0.16); color: var(--green);
  border-radius: 999px; padding: 2px 9px;
  font-size: 0.72rem; font-weight: 600; white-space: nowrap;
}
/* Monthly is what the markup shows on its own, so a reader without
   JavaScript gets a complete price list rather than two stacked ones. */
.on-yearly { display: none; }
body.yearly .on-monthly { display: none; }
body.yearly .on-yearly { display: inline; }

/* ── Comparison table (generated from the enforced limits) ───── */
.compare-note { margin-bottom: 14px; }
.compare { border-collapse: collapse; width: 100%; min-width: 520px; font-size: 0.9rem; }
.compare th, .compare td { padding: 11px 14px; border-bottom: 1px solid var(--line); }
.compare thead th {
  color: var(--text); background: var(--pill);
  text-align: center; white-space: nowrap; font-size: 0.85rem;
}
.compare thead th:first-child { text-align: left; }
.compare .col-silver { color: #c9d1d9; }
.compare .col-gold { color: #e3b341; }
.compare tbody th { text-align: left; color: var(--body); font-weight: 400; }
.compare td { text-align: center; }
.compare .yes { color: var(--green); font-weight: 700; }
.compare .no { color: var(--muted); }
.compare .num { color: var(--text); font-variant-numeric: tabular-nums; }
.compare .group-row th {
  background: var(--pill); color: var(--muted);
  font-size: 0.78rem; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 9px 14px;
}
.compare tbody tr:hover td, .compare tbody tr:hover th { background: rgba(255, 255, 255, 0.02); }
.compare .group-row:hover th { background: var(--pill); }

/* Screen-reader-only: the first header cell needs a name that a table
   reader can announce, without a visible label above the feature list. */
.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ── Premium tiers ──────────────────────────────────────────── */
/* stretch, not start: three columns of different heights read as three
   unfinished cards, and the call to action has to sit on the same line
   whichever one you are comparing. */
.tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: stretch; margin-bottom: 44px; }
.tier {
  display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 46px 22px 24px;
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}
/* Each tier gets its own light, from the top, in its own colour. It is
   the whole visual difference between the three and it costs one
   gradient: no images, nothing to load. */
.tier::before {
  content: ""; position: absolute; inset: 0; border-radius: var(--radius);
  background: radial-gradient(120% 60% at 50% 0%, rgba(88, 128, 255, 0.14), transparent 70%);
  pointer-events: none;
}
.tier { position: relative; overflow: hidden; }
.tier > * { position: relative; }
.tier:hover { transform: translateY(-3px); box-shadow: 0 18px 40px -24px #000; }

.tier-top { text-align: center; padding-bottom: 18px; border-bottom: 1px solid var(--line); }
.tier-desc { color: var(--muted); font-size: 0.86rem; margin-top: 6px; min-height: 2.6em; }
/* margin-top:auto pins it to the bottom of the card whatever the list
   above it does, so the three buttons line up across the three tiers. */
.tier-cta {
  display: block; margin-top: auto; text-align: center;
  background: var(--accent); color: #0d1017;
  border-radius: 12px; padding: 12px 16px;
  font-weight: 600; font-size: 0.92rem;
  transition: filter 0.15s ease, transform 0.15s ease, box-shadow 0.2s ease;
}
.tier-cta:hover { text-decoration: none; filter: brightness(1.08); transform: translateY(-1px); }
.cta-silver { background: #c9d1d9; }
.cta-gold { background: #e3b341; color: #17130a; }
.cta-silver:hover, .cta-gold:hover { box-shadow: 0 10px 26px -14px rgba(0, 0, 0, 0.9); }
/* The paid tiers carry a hairline of their own colour, which is the
   whole decoration: a page that shouts at a reader to pay is a page they
   leave. */
.tier.silver { border-color: #6d747d; }
.tier.silver::before { background: radial-gradient(120% 60% at 50% 0%, rgba(201, 209, 217, 0.13), transparent 70%); }
.tier.gold { border-color: #b8892b; }
.tier.gold::before { background: radial-gradient(120% 60% at 50% 0%, rgba(227, 179, 65, 0.16), transparent 70%); }
/* The gold card is the one being recommended, so it says why in a line
   rather than shouting "most popular" at a product nobody has bought
   yet. */
/* Inside the card, not hanging off its edge: the card clips its own
   gradient, so anything sitting outside the border would be cut. It is
   taken out of the flow and every card reserves the same room for it,
   which is what keeps the three headings on one line. */
.tier-flag {
  position: absolute; top: 14px; left: 50%; transform: translateX(-50%);
  background: rgba(227, 179, 65, 0.16); color: #e3b341;
  border: 1px solid rgba(227, 179, 65, 0.4);
  border-radius: 999px; padding: 3px 14px;
  font-size: 0.72rem; font-weight: 700; white-space: nowrap;
}
.tier h2 { font-size: 1.35rem; letter-spacing: -0.01em; }
.tier.silver h2 { color: #d7dee6; }
.tier.gold h2 { color: #e3b341; }

/* The price is the thing a reader came to see, so it is the largest
   type on the page. The currency sits small and raised beside it the way
   a price tag is read, not as another word in the sentence. */
.tier .price { margin-top: 16px; color: var(--muted); font-size: 0.9rem; line-height: 1.1; }
.tier .price b {
  color: var(--text); font-size: 2.6rem; font-weight: 700;
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.tier .price span span { font-size: 0.9rem; }
.tier-sub { color: var(--muted); font-size: 0.82rem; margin-top: 6px; min-height: 1.2em; }

.tier ul { list-style: none; margin: 18px 0 22px; padding: 0; display: grid; gap: 11px; }
.tier li {
  color: var(--body); font-size: 0.88rem; line-height: 1.5;
  padding-left: 28px; position: relative;
}
/* A tick on a disc rather than a bare character: at this size a plain
   glyph reads as punctuation, a disc reads as a list of things you get. */
.tier li::before {
  content: "✓";
  position: absolute; left: 0; top: 1px;
  width: 18px; height: 18px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(58, 157, 58, 0.16); color: var(--green);
  font-size: 0.7rem; font-weight: 700;
}
.tier.silver li::before { background: rgba(201, 209, 217, 0.14); color: #d7dee6; }
.tier.gold li::before { background: rgba(227, 179, 65, 0.16); color: #e3b341; }
.tier.gold li:first-child::before { content: "＋"; font-size: 0.8rem; }

/* ── Start in three steps ───────────────────────────────────── */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; counter-reset: step; }
.step {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px; position: relative;
}
.step::before {
  counter-increment: step; content: counter(step);
  display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 9px;
  background: var(--pill); border: 1px solid var(--line);
  color: var(--accent); font-weight: 700; font-size: 0.9rem;
}
.step h3 { margin: 12px 0 6px; }
.step p { color: var(--muted); font-size: 0.9rem; }
.step code {
  background: var(--pill); border: 1px solid var(--line); border-radius: 6px;
  padding: 1px 6px; font-size: 0.88em; color: var(--body);
}

/* ── FAQ ────────────────────────────────────────────────────── */
/* <details> rather than a scripted accordion: it opens without
   JavaScript, it is keyboard-operable for free, and the browser's own
   find-in-page can reach inside a closed one. */
.faq { display: grid; gap: 10px; }
.faq details {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 4px 16px;
}
.faq summary {
  cursor: pointer; list-style: none; padding: 12px 0;
  color: var(--text); font-weight: 600; font-size: 0.95rem;
  display: flex; align-items: center; gap: 10px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::before {
  content: "+"; color: var(--accent); font-weight: 700;
  width: 14px; flex: 0 0 auto; text-align: center;
}
.faq details[open] summary::before { content: "−"; }
.faq details p { color: var(--muted); font-size: 0.9rem; padding: 0 0 14px 24px; }

/* ── Reading progress and back to top ───────────────────────── */
/* Driven by the scroll position itself, not by JavaScript: no scroll
   handler, nothing written to a style attribute, and no work at all on
   a browser that does not support it, where the bar simply stays at
   zero width and is never seen. */
@keyframes fill-bar { to { transform: scaleX(1); } }
.progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 30;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  animation: fill-bar linear;
  animation-timeline: scroll(root block);
}
.totop {
  position: fixed; right: 18px; bottom: 18px; z-index: 20;
  width: 42px; height: 42px; border-radius: 12px;
  display: grid; place-items: center;
  background: var(--panel); border: 1px solid var(--line); color: var(--body);
  opacity: 0; pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease, border-color 0.2s ease;
}
.totop.shown { opacity: 1; pointer-events: auto; }
.totop:hover { border-color: var(--accent); transform: translateY(-2px); text-decoration: none; }

/* ── Legal pages (generated from the Markdown) ──────────────── */
/* Said in the reader's language, about a document that is not in it. */
.legal-lang {
  background: var(--pill); border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius); padding: 12px 16px; margin-bottom: 26px;
  color: var(--muted); font-size: 0.86rem;
}
.legal { padding: 40px 20px 64px; }
.legal h1 { font-size: 2rem; margin-bottom: 8px; }
.legal h2 { margin: 34px 0 10px; font-size: 1.2rem; }
.legal h3 { margin: 22px 0 8px; }
.legal p, .legal ul { margin: 10px 0; }
.legal ul { padding-left: 20px; }
.legal li { margin: 6px 0; }
.legal hr { border: 0; border-top: 1px solid var(--line); margin: 34px 0; }
.legal code { background: var(--pill); border: 1px solid var(--line); border-radius: 6px; padding: 1px 6px; font-size: 0.88em; }
.legal em { color: var(--muted); font-style: normal; }
/* A wide table must scroll inside its own box, never push the page. */
.table-wrap { overflow-x: auto; margin: 14px 0; border: 1px solid var(--line); border-radius: var(--radius); }
.legal table { border-collapse: collapse; width: 100%; min-width: 520px; font-size: 0.9rem; }
.legal th, .legal td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--line); vertical-align: top; }
.legal th { color: var(--text); background: var(--pill); white-space: nowrap; }
.legal tr:last-child td { border-bottom: 0; }

/* ── Footer ─────────────────────────────────────────────────── */
footer { border-top: 1px solid var(--line); padding: 32px 0 48px; color: var(--muted); font-size: 0.88rem; }
.foot { display: flex; gap: 18px; flex-wrap: wrap; align-items: center; }
.foot nav { display: flex; gap: 18px; flex-wrap: wrap; margin-left: auto; }
.foot a { color: var(--muted); }
.foot a:hover { color: var(--text); text-decoration: none; }

/* ── Motion ─────────────────────────────────────────────────── */
/* Everything here hangs off .anim, which app.js puts on <html> on its
   first line. Without JavaScript the class never lands, nothing is ever
   hidden, and the page reads exactly as it did before any of this: the
   reveal is decoration, never the thing standing between a reader and
   the text. */

/* The coloured band behind the hero drifts instead of sitting still.
   Only transform and opacity move, so it never triggers a relayout. */
@keyframes drift {
  0%, 100% { transform: translate3d(-4%, 0, 0) scale(1); opacity: 0.85; }
  50%      { transform: translate3d(4%, 12px, 0) scale(1.08); opacity: 1; }
}
.anim .hero::before { animation: drift 16s ease-in-out infinite; }

/* Hero: staggered on load. The delays live here rather than in inline
   styles because the Content-Security-Policy forbids those, and a
   policy you weaken for an animation is not a policy. */
@keyframes rise-in {
  from { opacity: 0; transform: translate3d(0, 16px, 0); }
  to   { opacity: 1; transform: none; }
}
.anim .rise { opacity: 0; }
.anim.ready .rise { animation: rise-in 0.7s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.anim.ready .hero .lead { animation-delay: 0.08s; }
.anim.ready .hero .cta { animation-delay: 0.16s; }
.anim.ready .hero .badges { animation-delay: 0.24s; }
.anim.ready .hero .stats { animation-delay: 0.32s; }

/* Sections: revealed as they come into view, once. */
.anim [data-reveal] {
  opacity: 0; transform: translate3d(0, 18px, 0);
  transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.anim [data-reveal].seen { opacity: 1; transform: none; }
/* A card should not wait on the one before it to finish, only to start:
   nine cards at 45ms each is under half a second for the whole grid. */
.grid [data-reveal]:nth-child(2), .shots [data-reveal]:nth-child(2) { transition-delay: 45ms; }
.grid [data-reveal]:nth-child(3), .shots [data-reveal]:nth-child(3) { transition-delay: 90ms; }
.grid [data-reveal]:nth-child(4), .shots [data-reveal]:nth-child(4) { transition-delay: 135ms; }
.grid [data-reveal]:nth-child(5) { transition-delay: 180ms; }
.grid [data-reveal]:nth-child(6) { transition-delay: 225ms; }
.grid [data-reveal]:nth-child(7) { transition-delay: 270ms; }
.grid [data-reveal]:nth-child(8) { transition-delay: 315ms; }
.grid [data-reveal]:nth-child(9) { transition-delay: 360ms; }

/* The header only earns its shadow once the page has moved. */
header { transition: background-color 0.25s ease, box-shadow 0.25s ease; }
header.scrolled {
  background: rgba(22, 24, 29, 0.94);
  box-shadow: 0 8px 24px -20px #000;
}
/* The nav link for the section being read. An underline that grows from
   the link rather than a colour swap alone, so it survives at a glance. */
.bar nav a[href^="#"] { position: relative; }
.bar nav a[href^="#"]::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -6px; height: 2px;
  background: var(--accent); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.25s ease;
}
.bar nav a[href^="#"].current { color: var(--text); }
.bar nav a[href^="#"].current::after { transform: scaleX(1); }

.btn { transition: transform 0.15s ease, filter 0.15s ease, border-color 0.2s ease, box-shadow 0.2s ease; }
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-primary:hover { box-shadow: 0 10px 26px -12px rgba(88, 128, 255, 0.8); }
/* The zoom has to clip: a scaled card would otherwise push its own
   square corners past the rounded ones underneath. */
.zoom { overflow: hidden; border-radius: 10px; }
.shot img { transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1); }
.zoom:hover img { transform: scale(1.012); }
.langs button { transition: background-color 0.2s ease, color 0.2s ease; }
.stat { transition: transform 0.25s ease, border-color 0.25s ease; }
.stat:hover { transform: translateY(-2px); border-color: rgba(88, 128, 255, 0.45); }

/* ── Small screens ──────────────────────────────────────────── */
@media (max-width: 860px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 700px) {
  .grid { grid-template-columns: 1fr; }
  .wrap { padding: 0 16px; }

  /* One row, always. The section anchors are dropped rather than
     wrapped: the page is short enough to scroll, and a three-line
     sticky header would eat a fifth of a phone screen. */
  .bar { height: 56px; }
  .bar nav a[href^="#"] { display: none; }
  .bar nav { gap: 12px; }

  /* Thumb-sized targets on the language switcher. */
  .langs button { padding: 7px 12px; font-size: 0.82rem; }

  h1 { font-size: 1.75rem; }
  .hero { padding: 40px 0 34px; }
  .hero p.lead { font-size: 1rem; }
  .hero .cta { flex-direction: column; align-items: stretch; margin-top: 24px; }
  .hero .cta .btn { justify-content: center; padding: 13px 20px; }
  .badges { gap: 6px; margin-top: 20px; }
  .badge { font-size: 0.76rem; padding: 4px 10px; }

  /* Four columns on a phone would give each figure 70px and break the
     labels over three lines. */
  .stats { grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 26px; }
  .stat { padding: 12px 6px; }
  .stat .num { font-size: 1.35rem; }

  section { padding: 34px 0; }
  .head { margin-bottom: 20px; }
  .card { padding: 16px; }

  /* A gradient that drifts forever keeps the compositor awake for a
     decoration nobody is looking at, and that is a phone's battery. */
  .anim .hero::before { animation: none; }

  /* Give the cards every pixel available, and keep the hint visible
     since there is no hover on a phone. */
  .shots { gap: 16px; }
  .shot { padding: 8px; }
  .shot figcaption { margin-top: 10px; font-size: 0.82rem; }
  .zoom::after { opacity: 1; }

  /* Three price columns on a phone would be three unreadable slivers. */
  .tiers { grid-template-columns: 1fr; }
  .prem-head { text-align: left; }
  .promise { padding: 14px; }
  .billing { width: 100%; justify-content: center; flex-wrap: wrap; }
  .billing .save { padding: 4px 10px 0; width: 100%; text-align: center; }

  /* The sticky category header has to sit exactly under the bar, which
     is 6px shorter here: at 62px a line of text shows through the gap. */
  .group-head { top: 56px; }
  .commands { padding: 26px 16px 48px; }
  .commands h1 { font-size: 1.6rem; }

  .trust { padding: 18px; }
  footer { padding: 26px 0 36px; }
  .foot nav { margin-left: 0; gap: 14px; }
}

/* A reader who asked their system for less motion gets the finished
   page, not a slower version of the animation: everything lands in its
   final state and nothing moves. app.js reads the same preference and
   skips the count-up. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .anim .hero::before { animation: none; }
  .anim .rise, .anim.ready .rise { opacity: 1; animation: none; }
  .anim [data-reveal] { opacity: 1; transform: none; transition: none; }
  .card:hover, .stat:hover, .btn:hover, .btn:active { transform: none; }
  .card:hover .glyph, .zoom:hover img { transform: none; }
  .anim body.cmds .cmd-group.open,
  .anim body.cmds .cmd-group.open .cmd { animation: none; }
  .anim .back:hover span[aria-hidden] { transform: none; }
  .bar nav a[href^="#"]::after { transition: none; }
}
