/* Mushroom v2, one stylesheet for all ten pages.

   The live site splits this across tokens.css + components.css + legal.css plus a
   per-page inline <style> block, which is why the same .btn is defined in one place
   and used in ten. v2 keeps tokens.css separate (so the "never hardcode a hex" rule
   stays greppable) and puts everything else here. Ten pages, one file, one cache
   entry.

   Needs tokens.css loaded first. Never hardcode a hex value in this file. */

/* ---------- base ---------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* Terminus (TTF 4.49.3, SIL Open Font License 1.1, assets/fonts/OFL-Terminus.txt): the original files, unmodified, which is
   what lets them ship under the font's own name. A pixel font for a pixel pet. Its bitmaps are drawn for whole pixel
   sizes, so 16px body text is its sharpest. */
@font-face { font-family: "Terminus"; src: url("assets/fonts/TerminusTTF-4.49.3.ttf") format("truetype"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Terminus"; src: url("assets/fonts/TerminusTTF-Bold-4.49.3.ttf") format("truetype"); font-weight: 700 900; font-display: swap; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.65 "Terminus", ui-monospace, "SF Mono", Menlo, monospace;
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, h4 { line-height: 1.12; letter-spacing: 0; margin: 0; text-wrap: balance; font-weight: 700; }
h1 { font-size: clamp(2.1rem, 5.2vw, 3.35rem); font-weight: 800; }
h2 { font-size: clamp(1.6rem, 4vw, 2.25rem); font-weight: 800; }
h3 { font-size: 1.1rem; }
p { text-wrap: pretty; }
a { color: inherit; }
img, video { max-width: 100%; }
[id] { scroll-margin-top: 76px; }

:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 3px solid var(--ring);
  outline-offset: 3px;
  border-radius: 6px;
}

.wrap { width: min(100% - 2.5rem, 62rem); margin-inline: auto; }
.wrap--narrow { width: min(100% - 2.5rem, 44rem); margin-inline: auto; }
.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;
}

/* Tighter than the live site's clamp(3rem, 8vw, 5.5rem). Density is most of what
   reads as "professional" rather than "landing page". */
section { padding: clamp(2.5rem, 6vw, 4.5rem) 0; }
.band { background: var(--bg2); border-block: 1px solid color-mix(in srgb, var(--line2) 45%, transparent); }
.band--deep { background: var(--bg3); }

/* ---------- section vocabulary ---------- */
.eyebrow {
  display: inline-flex; align-items: center; gap: .55rem;
  text-transform: uppercase; letter-spacing: .12em; font-size: .76rem; font-weight: 700;
  color: var(--red); margin: 0 0 .75rem;
}
.eyebrow::before { content: "+"; font-size: 1.15em; font-weight: 700; line-height: 1; opacity: .85; }
.lede { color: var(--ink2); max-width: 40rem; margin: .85rem 0 0; font-size: 1.05rem; }
.center { text-align: center; }
.center .lede, .center .eyebrow { margin-inline: auto; }
.center .lede { max-width: 38rem; }
.more { margin: 2rem 0 0; font-size: .95rem; }
.more a { color: var(--red); font-weight: 600; text-decoration: none; }
.more a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid color-mix(in srgb, var(--line2) 45%, transparent);
}
.nav-inner { display: flex; align-items: center; justify-content: space-between; height: 56px; gap: 1rem; }
.brand {
  display: inline-flex; align-items: center; gap: .55rem;
  font-weight: 700; font-size: 1.05rem; letter-spacing: 0; text-decoration: none;
}
.brand img { border-radius: 8px; box-shadow: var(--shadow-sm); }
/* Never shrinks: brand is a nested flex container whose own min-content can compute to
   near-zero, which is how the wordmark ended up tucked under the toggle instead of the row
   simply overflowing. The .btn pills are left free to shrink a hair at the tightest widths -
   a couple of px off a pill's padding is invisible, unlike a squashed brand or toggle. */
.nav .brand { flex: none; }
.nav-links { display: flex; align-items: center; gap: 1.4rem; }
.theme-toggle { flex: none; }
.nav-links a { text-decoration: none; color: var(--ink2); font-size: .93rem; font-weight: 500; transition: color .12s; }
.nav-links a:hover, .nav-links a[aria-current="page"] { color: var(--ink); }
.nav-links a.btn { color: var(--red-ink); }
/* --red-ink is #fff in light mode - correct for the solid red "Download free" button, but
   .nav-links a.btn matches ANY .btn including a ghost one (the "App Store" link), whose own
   background is a near-white --card - white text on that reads as a blank button. Same bug,
   same fix as .prose a.btn--ghost below. */
.nav-links a.btn--ghost { color: var(--ink); }
/* The mobile row cannot hold brand + toggle + three pills: at 390px it needs even more than
   the ~424px of a 350px .wrap that two pills already overflowed. "Download free" and
   "Gumroad" are the two that go: /download serves a Mac or Windows desktop installer
   (worker.js) with no phone equivalent, and Gumroad is that same desktop purchase, so on a
   phone both are the wrong product. "App Store" is the universal listing that covers the
   Mac and the iPhone. The other two keep their full-size CTA in the hero and the footer on
   every viewport. */
/* The mirror added two links the source nav never had ($MUSHROOM, @mushroom), so the
   full row no longer fits between the mobile collapse point and a wide desktop. Drop the
   X handle first (it is in the footer too) and tighten the gaps, before the row overflows. */
@media (max-width: 66rem) {
  /* The mirror's two extra items ($MUSHROOM link, @mushroom) plus the two CTAs no longer
     fit between the mobile collapse point and a wide desktop. Below 66rem the token link
     and the ghost CTA step aside (both are still in the body and the footer), and the
     remaining button is not allowed to wrap onto two lines. */
  .nav-links .nav-x,
  .nav-links a[href="/#token"],
  .nav-links a.btn--ghost { display: none; }
  .nav-links { gap: .9rem; }
  .nav-links .btn { white-space: nowrap; }
}

@media (max-width: 46rem) {
  .nav-links a:not(.btn) { display: none; }
  .nav-links a[href="/download"] { display: none; }
  /* Even with only the toggle and one pill left, the smallest shipping iPhone (SE, 320px)
     still overflows .wrap by ~9px at the default 1.4rem gap - measured, not guessed, with a
     headless render. Tightened here rather than everywhere, since 1.4rem is fine wherever
     there's room for it. */
  .nav-links { gap: .6rem; }
}

/* ---------- announcement bar ---------- */
.announce {
  text-align: center; font-size: .88rem; font-weight: 500; padding: .55rem 1.25rem;
  color: var(--ink); background: color-mix(in srgb, var(--red) 8%, var(--bg));
  border-bottom: 1px solid color-mix(in srgb, var(--red) 15%, var(--line));
}
.announce b { color: var(--red); font-weight: 700; }
.announce a { color: var(--red); font-weight: 600; text-decoration: none; }
.announce a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  background: linear-gradient(180deg, color-mix(in srgb, var(--red) 88%, #fff), var(--red));
  color: var(--red-ink);
  border: 0; border-radius: var(--radius-pill);
  padding: .8rem 1.6rem;
  font: inherit; font-weight: 600; font-size: 1rem; line-height: 1.15; letter-spacing: 0;
  cursor: pointer; text-decoration: none;
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 30%, transparent),
              0 1px 2px var(--shadow),
              0 8px 20px color-mix(in srgb, var(--red) 22%, transparent);
  transition: transform .14s ease, box-shadow .14s ease, filter .14s ease;
}
.btn:hover {
  transform: translateY(-1px); filter: brightness(1.04);
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 30%, transparent),
              0 2px 5px var(--shadow),
              0 12px 28px color-mix(in srgb, var(--red) 30%, transparent);
}
.btn:active { transform: translateY(0); filter: brightness(.97); }
.btn--ghost {
  background: color-mix(in srgb, var(--card) 70%, transparent); color: var(--ink);
  border: 1px solid var(--line2);
  box-shadow: var(--shadow-sm); font-weight: 500;
}
.btn--ghost:hover { transform: translateY(-1px); filter: none; border-color: var(--ink2); background: var(--card); box-shadow: var(--shadow-sm); }
.btn.btn--sm {
  padding: .44rem 1.05rem; font-size: .88rem; font-weight: 600;
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 22%, transparent), 0 1px 2px var(--shadow);
}
.btn.btn--sm:hover { box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 22%, transparent), 0 3px 8px color-mix(in srgb, var(--red) 30%, transparent); }
.cta-row { display: flex; flex-wrap: wrap; gap: .85rem; align-items: center; margin-top: 1.9rem; }
.center .cta-row { justify-content: center; }

/* ---------- theme toggle ----------
   One icon, not a sun that swaps to a moon. Under light-dark() there is no selector for
   "currently dark": prefers-color-scheme still reports the SYSTEM, so a swap would show
   the wrong glyph to exactly the readers who used the button. The half-filled circle is
   the standard appearance mark and is true in both directions, which is also one SVG and
   no state to keep in sync. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; padding: 0; margin-right: -.2rem;
  color: var(--ink2); background: none;
  border: 1px solid transparent; border-radius: var(--radius-pill);
  cursor: pointer; transition: color .16s ease, background-color .16s ease;
}
.theme-toggle:hover { color: var(--ink); background: var(--bg2); }
.theme-toggle svg { display: block; width: 18px; height: 18px; }

/* ---------- hero ---------- */
header.hero { padding: clamp(3rem, 7vw, 5rem) 0 clamp(2.5rem, 5vw, 3.5rem); position: relative; overflow: hidden; }
/* The one tiled background on the site. DESIGN.md §8 records it as the standing
   exception: token-derived, faded out by mid-hero, reads as paper grain behind pixel
   art. Do not add a second, and do not extend this one past the hero. */
header.hero::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(color-mix(in srgb, var(--ink) 10%, transparent) 1px, transparent 1px);
  background-size: 22px 22px;
  -webkit-mask-image: radial-gradient(75% 55% at 50% 0%, #000, transparent 78%);
  mask-image: radial-gradient(75% 55% at 50% 0%, #000, transparent 78%);
  opacity: .45;
}
header.hero > * { position: relative; z-index: 1; }
.hero .sub {
  font-size: clamp(1.05rem, 2.2vw, 1.22rem); color: var(--ink2);
  max-width: 36rem; margin: 1.1rem auto 0;
}
.hero-for {
  margin: 1.1rem auto 0; max-width: 34rem;
  font-size: .92rem; color: var(--ink2);
}
.hero-for b { color: var(--ink); font-weight: 600; }
.hero-note { margin: 1rem 0 0; font-size: .85rem; color: var(--ink2); }

.ledge { display: flex; flex-direction: column; align-items: center; margin-bottom: 1.6rem; }
.ledge-line { width: min(15rem, 60%); height: 1px; background: linear-gradient(90deg, transparent, var(--line2), transparent); }

.trust {
  display: flex; flex-wrap: wrap; gap: .5rem 1.1rem; justify-content: center;
  margin-top: 1.6rem; color: var(--ink2); font-size: .85rem; font-weight: 500;
}
.trust span { display: inline-flex; align-items: center; gap: .4rem; }

/* ---------- macOS window frame ----------
   The component that does most of the "professional Mac app" work. Wrap any
   screenshot in it. Falls back to an empty frame with a caption when the shot does
   not exist yet, which is currently every one of them (see v2/README.md). */
.macwin {
  border: 1px solid var(--line2);
  border-radius: var(--radius-win);
  overflow: hidden;
  background: var(--card);
  box-shadow: var(--shadow-lg);
  margin: 2.2rem auto 0;
  max-width: 52rem;
}
.macwin-bar {
  display: flex; align-items: center; gap: .45rem;
  padding: .55rem .7rem;
  background: color-mix(in srgb, var(--ink) 5%, var(--card));
  border-bottom: 1px solid var(--line);
}
.macwin-bar i {
  width: 11px; height: 11px; border-radius: 50%;
  background: color-mix(in srgb, var(--ink) 20%, transparent);
  flex: none;
}
.macwin-title {
  margin-inline: auto; padding-right: 2.4rem;
  font-size: .78rem; font-weight: 500; color: var(--ink2);
}
.macwin img, .macwin video { display: block; width: 100%; height: auto; }
/* ---------- .shot: a screenshot that already has its own macOS chrome ----------
   Every real capture in assets/ contains traffic lights, a menu bar or the dock, so
   wrapping one in .macwin would draw a second titlebar over the app's own. .shot is
   just the frame: rounded, hairline, lifted. Use .macwin only for chrome-less content
   like the hero video. */
.shot {
  display: block; margin: 2.2rem auto 0;
  max-width: 46rem; width: 100%;
  border: 1px solid var(--line2); border-radius: var(--radius-win);
  box-shadow: var(--shadow-lg);
  overflow: hidden; background: var(--card);
}
.shot img { display: block; width: 100%; height: auto; }
/* Portrait captures need capping, and they do not all need the same cap: the chat
   panels are 700x1210 (aspect .58) and the app windows are around 870x1040 (aspect
   .84), so one max-width either towers or shrinks to nothing. Two steps covers both. */
.shot--tall { max-width: 21rem; }   /* chat panels */
.shot--mid  { max-width: 28rem; }   /* app windows: reminders, settings */
.shot--pair { display: grid; gap: 1.2rem; grid-template-columns: 1fr; margin-top: 2.2rem; }
@media (min-width: 46rem) {
  .shot--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; justify-items: center; }
  .shot--pair .shot { margin-top: 0; }
}
.shot-cap { margin: .7rem 0 0; font-size: .85rem; color: var(--ink2); text-align: center; }

/* placeholder body, used until real screenshots exist */
.macwin-todo {
  display: grid; place-items: center; gap: .4rem;
  min-height: 17rem; padding: 2rem;
  color: var(--ink2); font-size: .9rem; text-align: center;
  background:
    radial-gradient(60% 60% at 50% 40%, var(--tint), transparent 70%),
    var(--card);
}
.macwin-todo b { color: var(--ink); font-size: 1rem; }

/* ---------- cards ---------- */
/* text-align:left so a .grid inside a .center section keeps its cards left-ranged.
   .nudges sets its own centering and is unaffected. */
.grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); grid-auto-rows: 1fr; margin-top: 2.2rem; text-align: left; }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr)); }
.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-card); padding: 1.5rem;
  box-shadow: var(--shadow-sm);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: color-mix(in srgb, var(--red) 22%, var(--line)); }
.card h3 { margin-bottom: .35rem; }
.card p { margin: 0; color: var(--ink2); font-size: .95rem; }
.card--flat:hover { transform: none; box-shadow: var(--shadow-sm); border-color: var(--line); }

/* There was a .ico here: an emoji in a tinted rounded square, used fourteen times.
   Emoji share no stroke weight and no optical size, they are drawn by the OS rather
   than by us, and they were the loudest thing on a site whose whole identity is
   hand-drawn pixel art. The labels carry the meaning on their own. */

/* ---------- plain list, no card ----------
   Cards everywhere flattens the hierarchy: when every block is raised, none is.
   Used where the content is a list to read, not a set of tiles to scan. */
.stack { display: grid; margin-top: 2.2rem; text-align: left; }
@media (min-width: 52rem) {
  .stack--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 3rem; }
  .stack--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 2.5rem; }
}
/* top hairline only, never bottom: the same rule then reads correctly at one, two
   and three columns without a per-column :last-child exception. */
.stack > div { padding: 1.15rem 0; border-top: 1px solid var(--line2); }
.stack h3 { margin: 0 0 .3rem; font-size: 1rem; }
.stack p { margin: 0; color: var(--ink2); font-size: .95rem; }
.stack .more { margin-top: .55rem; font-size: .9rem; }
.stack--num > div { display: grid; grid-template-columns: 1.5rem minmax(0, 1fr); column-gap: .9rem; }
.stack--num .n { grid-row: span 2; font-weight: 700; color: var(--red); line-height: 1.62; }

/* six wellness nudges, no boxes, sized to their own text */
.nudges { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.7rem 1.2rem; margin-top: 2.2rem; text-align: center; }
@media (min-width: 52rem) { .nudges { grid-template-columns: repeat(3, 1fr); } }
.nudge h3 { font-size: 1rem; margin-bottom: .3rem; }
.nudge p { margin: 0; color: var(--ink2); font-size: .88rem; }

/* ---------- split sections ----------
   Every band on the homepage used to be the same shape: eyebrow, centred heading,
   centred lede, grid of cards. Two of them now put the copy on one side and a
   portrait capture on the other, which is also the only way those tall screenshots
   stop floating small in a lot of empty page. */
.split { display: grid; gap: 2rem 3rem; align-items: center; margin-top: 2.4rem; }
@media (min-width: 58rem) {
  .split { grid-template-columns: minmax(0, 1fr) 20rem; }
  .split--rev { grid-template-columns: 20rem minmax(0, 1fr); }  /* media first in the DOM */
}
.split .shot { margin-top: 0; max-width: 100%; }
.split .nudges, .split .stack { margin-top: 0; }
/* the left column is narrower than the section, so three across would not fit */
.split .nudges { grid-template-columns: repeat(2, 1fr); text-align: left; }

/* compact two-column list, used on /features */
.grid--compact { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 1.8rem; margin-top: 1.3rem; }
/* The 1.5rem gutter held an emoji, one of forty seven down this page, drawn by the
   reader's OS in whatever size and weight it felt like. Removed with the rest. */
.compact { padding: .8rem 0; border-top: 1px solid var(--line); }
.compact h3 { font-size: .97rem; margin: 0 0 .1rem; }
.compact p { margin: 0; color: var(--ink2); font-size: .88rem; }

/* stat row, used by Friends / Spore Storage on /features */
.specs { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center; margin-top: 2rem; }
.spec {
  display: flex; flex-direction: column; align-items: center; gap: .15rem;
  min-width: 7.5rem; padding: 1rem 1.2rem;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 16px; box-shadow: var(--shadow-sm);
}
.spec b { font-size: 1.4rem; font-weight: 800; line-height: 1.1; color: var(--red); font-variant-numeric: tabular-nums; }
.spec span { font-size: .82rem; color: var(--ink2); }

.reqs { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin-top: 1.5rem; }
.req { font-size: .85rem; color: var(--ink2); border: 1px solid var(--line2); border-radius: var(--radius-pill); padding: .35rem .9rem; }

/* ---------- the facts block ----------
   A <dl> of one unambiguous sentence per question. Serves humans, and is the single
   structure answer engines quote most reliably. See v2/README.md §LLMO. */
.facts {
  margin: 2rem 0 0; display: grid; gap: 0;
  border: 1px solid var(--line); border-radius: var(--radius-card);
  background: var(--card); box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.facts > div { display: grid; gap: .15rem .9rem; padding: .95rem 1.3rem; border-top: 1px solid var(--line); }
.facts > div:first-child { border-top: 0; }
.facts dt { font-weight: 600; font-size: .93rem; }
.facts dd { margin: 0; color: var(--ink2); font-size: .93rem; }
@media (min-width: 44rem) {
  .facts > div { grid-template-columns: 13rem 1fr; align-items: baseline; }
}

/* ---------- comparison table ---------- */
.compare-scroll { overflow-x: auto; margin-top: 2rem; -webkit-overflow-scrolling: touch; }
.compare {
  width: 100%; min-width: 34rem; border-collapse: collapse;
  font-size: .93rem; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius-card);
  overflow: hidden;
}
.compare th, .compare td { padding: .8rem 1rem; text-align: left; border-top: 1px solid var(--line); vertical-align: top; }
.compare thead th { border-top: 0; background: var(--tint); font-weight: 700; font-size: .88rem; }
.compare tbody th { font-weight: 600; color: var(--ink); width: 14rem; }
.compare td { color: var(--ink2); }
.compare .yes { color: var(--red); font-weight: 600; }

/* ---------- licence picker ---------- */
.picker {
  margin-top: 2.2rem;
  display: grid; gap: 1.2rem;
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) { .picker { grid-template-columns: 1fr 1fr; align-items: start; gap: 1.8rem; } }
.picker fieldset { border: 0; padding: 0; margin: 0 0 1.4rem; }
.picker legend { padding: 0; font-weight: 600; font-size: 1rem; margin-bottom: .6rem; }
.picker legend small { display: block; font-weight: 400; font-size: .85rem; color: var(--ink2); margin-top: .15rem; }
.opts { display: flex; flex-wrap: wrap; gap: .5rem; }
.opt {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .5rem 1rem; cursor: pointer;
  background: var(--card); border: 1px solid var(--line2); border-radius: var(--radius-pill);
  font-size: .92rem; color: var(--ink2);
  transition: border-color .14s ease, color .14s ease, background .14s ease;
}
.opt:hover { border-color: var(--ink2); color: var(--ink); }
.opt input { margin: 0; accent-color: var(--red); }
.opt:has(input:checked) { border-color: var(--red); color: var(--ink); background: var(--tint); font-weight: 600; }
.opt:has(input:focus-visible) { outline: 3px solid var(--ring); outline-offset: 3px; }
/* Text fields and dropdowns wear the .opt pill, so a form reads as one family with the
   price picker and the tools search. */
.field {
  padding: .5rem 1rem;
  background: var(--card); color: var(--ink);
  border: 1px solid var(--line2); border-radius: var(--radius-pill);
  font: inherit; font-size: .92rem;
  transition: border-color .14s ease;
}
.field:hover { border-color: var(--ink2); }
.field::placeholder { color: var(--ink2); }
/* appearance:none drops the native arrow, so the chevron is one conic-gradient triangle:
   tokens only, no hex, and it follows the theme. One layer, not the usual two
   linear-gradient halves, because those snap separately and show a seam at odd widths. */
select.field {
  appearance: none; padding-right: 2.4rem; cursor: pointer;
  background-image: conic-gradient(from -45deg at 50% 100%, var(--ink2) 90deg, transparent 0);
  background-size: .6rem .3rem;
  background-position: right 1rem center;
  background-repeat: no-repeat;
}

.result {
  position: sticky; top: 76px;
  background: var(--card); border: 1px solid var(--line2);
  border-radius: var(--radius-card); padding: 1.6rem;
  box-shadow: var(--shadow-md);
}
.result h3 { font-size: 1.3rem; }
.result .price-line { font-size: 2.1rem; font-weight: 800; letter-spacing: 0; margin: .5rem 0 .1rem; }
.result .price-note { margin: 0 0 1.1rem; font-size: .87rem; color: var(--ink2); }
.result .btn { width: 100%; }
.result ul { margin: 0 0 1.2rem; padding: 0; list-style: none; display: grid; gap: .45rem; font-size: .92rem; }
.result li { display: grid; grid-template-columns: 1.15rem 1fr; gap: .55rem; color: var(--ink2); }
.result li::before { content: "+"; color: var(--red); font-weight: 700; }
.result li.no::before { content: "-"; color: var(--ink2); }
.result .why { margin: 1rem 0 0; font-size: .85rem; color: var(--ink2); }
/* The "before you commit" box. This is the part that stops someone buying twice, so it
   sits above the button rather than under it. */
.result .heads-up {
  margin: 0 0 1.1rem; padding: .8rem 1rem;
  background: var(--tint); border: 1px solid color-mix(in srgb, var(--red) 20%, var(--line));
  border-radius: 12px;
}
.result .heads-up b { display: block; font-size: .85rem; margin-bottom: .3rem; }
.result .heads-up ul { margin: 0; gap: .35rem; }
.result .heads-up li { grid-template-columns: 1.15rem 1fr; font-size: .87rem; color: var(--ink); }
.result .heads-up li::before { content: "!"; color: var(--red); font-weight: 700; }
.result .runner-up { margin: 1rem 0 0; font-size: .85rem; color: var(--ink2); }
.result .runner-up a { color: var(--red); font-weight: 600; }
@media (max-width: 56rem) { .result { position: static; } }

/* ---------- pricing card ---------- */
.pay {
  position: relative; max-width: 30rem; margin: 2.4rem auto 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--spot) 6%, var(--card)), var(--card));
  border: 1px solid var(--line2);
  border-radius: 22px; padding: clamp(1.8rem, 4vw, 2.4rem);
  box-shadow: var(--shadow-lg);
  text-align: center;
}
.pay::after {
  content: ""; position: absolute; top: 0; left: 15%; right: 15%; height: 3px;
  background: linear-gradient(90deg, transparent, var(--red), transparent);
}
.price-big { font-size: 3rem; font-weight: 800; letter-spacing: 0; margin-top: .2rem; }
.excl { color: var(--ink2); font-size: .9rem; margin: .2rem 0 1.3rem; }
.pay .btn { width: 100%; }
.meta { margin: 1rem 0 0; font-size: .85rem; color: var(--ink2); }

/* ---------- FAQ / prose (help, legal, faq) ---------- */
.prose { max-width: 44rem; }
.prose h2 { margin: 2.6rem 0 .8rem; font-size: clamp(1.35rem, 3vw, 1.7rem); }
.prose h3 { margin: 1.8rem 0 .5rem; font-size: 1.08rem; }
.prose p, .prose li { color: var(--ink2); }
.prose p { margin: .7rem 0; }
.prose ul, .prose ol { margin: .7rem 0; padding-left: 1.3rem; }
.prose li { margin: .3rem 0; }
.prose a { color: var(--red); text-decoration: none; }
.prose a:hover { text-decoration: underline; text-underline-offset: 3px; }
/* .prose a is (0,1,1) and .btn is (0,1,0), so without this a button inside prose is
   painted red on red and the label vanishes. Same reason .nav-links a.btn exists. */
.prose a.btn { color: var(--red-ink); }
.prose a.btn:hover { text-decoration: none; }
.prose a.btn--ghost { color: var(--ink); }
.prose code, .prose pre {
  font-family: "Terminus", ui-monospace, "SF Mono", Menlo, monospace; font-size: .88em;
  background: var(--bg2); border: 1px solid var(--line); border-radius: 6px;
}
.prose code { padding: .1rem .35rem; }
.prose pre { padding: .9rem 1.1rem; overflow-x: auto; border-radius: 10px; }
.prose pre code { background: none; border: 0; padding: 0; }
.prose blockquote {
  margin: 1.2rem 0; padding: .8rem 1.2rem;
  border-left: 3px solid var(--red); background: var(--tint);
  border-radius: 0 10px 10px 0; color: var(--ink);
}
.page-head { padding: clamp(2.5rem, 6vw, 4rem) 0 0; }
.page-head h1 { font-size: clamp(1.9rem, 4.5vw, 2.7rem); }
.crumb { font-size: .87rem; color: var(--ink2); margin: 0 0 .8rem; }
.crumb a { color: var(--ink2); text-decoration: none; }
.crumb a:hover { color: var(--ink); text-decoration: underline; }
.toc { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1.6rem 0 0; }
.toc a {
  font-size: .87rem; text-decoration: none; color: var(--ink2);
  border: 1px solid var(--line2); border-radius: var(--radius-pill); padding: .32rem .85rem;
}
.toc a:hover { color: var(--ink); border-color: var(--ink2); }

/* ---------- footer ---------- */
footer { border-top: 1px solid var(--line); padding: 2.4rem 0 3rem; color: var(--ink2); font-size: .9rem; }
footer a { color: var(--red); text-decoration: none; }
footer a:hover { text-decoration: underline; }
footer a.btn { color: var(--red-ink); }
.foot-top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.foot-tagline { max-width: 30rem; margin: 1rem 0 1.5rem; font-size: .92rem; }
.foot-links { display: flex; flex-wrap: wrap; gap: .5rem 1.2rem; }
/* The version a download button hands this visitor, filled in by assets/download-version.js. */
.btn-ver { font-size: .8em; font-weight: 500; opacity: .72; }
.btn:has(.btn-ver) { align-items: baseline; }
.foot-badge { margin-top: 1.5rem; }
.foot-badge img { display: block; max-width: 100%; height: auto; }

/* ---------- the sprite ----------
   48x48 frames, nearest neighbour, integer scale only. DESIGN.md §4. */
.shroom {
  width: 96px; height: 96px;
  background-image: url("assets/cute mushroom walk.png");
  background-size: 384px 96px;
  background-repeat: no-repeat;
  image-rendering: pixelated;
  animation: walk .6s steps(4) infinite;
}
@keyframes walk { to { background-position: -384px 0; } }
.shroom--idle {
  background-image: url("assets/cute mushroom idle.png");
  background-size: 864px 96px;
  animation: idle 1.4s steps(9) infinite;
}
@keyframes idle { to { background-position: -864px 0; } }
/* A section divider the mushroom walks along, back and forth. The walk sheet is
   already loaded by the hero, so this costs one hairline and one keyframe set, and
   it is the only thing on the page that no other site can copy. `left` rather than
   translateX because scaleX is doing the turn and the two would fight over the same
   property. One element crawling a 26s linear path is not a paint problem. */
.walkline { position: relative; height: 48px; margin-top: 3rem; }
.walkline::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line2), transparent);
}
/* walk-sm, not walk: this shorthand sets animation-name, so it would otherwise put the
   96px keyframe back on a 48px sprite. */
.walkline .shroom { position: absolute; bottom: 1px; left: 0; animation: walk-sm .6s steps(4) infinite, stroll 26s linear infinite; }
@keyframes stroll {
  0%   { left: 0;                   transform: scaleX(1); }
  48%  { left: calc(100% - 48px);   transform: scaleX(1); }
  50%  { left: calc(100% - 48px);   transform: scaleX(-1); }
  98%  { left: 0;                   transform: scaleX(-1); }
  100% { left: 0;                   transform: scaleX(1); }
}

/* A keyframe travels the FULL rendered sheet width, so every background-size needs its
   own. Reuse one across two sizes and the tail frames land past the sheet, which with
   no-repeat paints nothing and the sprite blinks rather than walks. */
.shroom--sm { width: 48px; height: 48px; background-size: 192px 48px; animation-name: walk-sm; }
@keyframes walk-sm { to { background-position: -192px 0; } }
.shroom--sm.shroom--idle { background-size: 432px 48px; }
@keyframes idle-sm { to { background-position: -432px 0; } }
.shroom--sm.shroom--idle { animation-name: idle-sm; }

/* ---------- skins strip ----------
   Ten idle sheets, same 432x48 geometry, so the row never reflows by colour. Black and
   white are greyscale rather than hue rotations, and both keep the sprite's white outer
   outline, which is what stops either of them dissolving into the band behind it. */
/* A wrapping flex row fits as many as the width allows, which for ten put nine on one
   line and left the tenth alone underneath. Only 2, 5 and 10 divide ten evenly, so they
   are the only column counts with no orphan on the last row, and ten across needs a
   1,000px band. Hence a grid that steps 2 to 5, skipping the 3 and 4 a flex row picks. */
.skins {
  display: grid; grid-template-columns: repeat(2, 96px);
  gap: .9rem; justify-content: center; margin-top: 2rem;
}
/* 5 x 96px + 4 x .9rem = 537.6px of content, and .wrap gives the viewport less 2.5rem. */
@media (min-width: 40rem) { .skins { grid-template-columns: repeat(5, 96px); } }
.skin {
  width: 96px; height: 96px;
  background-size: 864px 96px; background-repeat: no-repeat;
  image-rendering: pixelated;
  animation: idle 1.4s steps(9) infinite;
}
.skin-red    { background-image: url("assets/skins/idle-red.png"); }
.skin-orange { background-image: url("assets/skins/idle-orange.png"); animation-delay: -.15s; }
.skin-yellow { background-image: url("assets/skins/idle-yellow.png"); animation-delay: -.3s; }
.skin-green  { background-image: url("assets/skins/idle-green.png"); animation-delay: -.45s; }
.skin-teal   { background-image: url("assets/skins/idle-teal.png"); animation-delay: -.6s; }
.skin-blue   { background-image: url("assets/skins/idle-blue.png"); animation-delay: -.75s; }
.skin-purple { background-image: url("assets/skins/idle-purple.png"); animation-delay: -.9s; }
.skin-pink   { background-image: url("assets/skins/idle-pink.png"); animation-delay: -1.05s; }
.skin-black  { background-image: url("assets/skins/idle-black.png"); animation-delay: -1.2s; }
.skin-white  { background-image: url("assets/skins/idle-white.png"); animation-delay: -1.35s; }

/* ---------- scroll reveal. Only hides once JS arms it, so no-JS shows everything. */
.js .rise { opacity: 0; transform: translateY(16px); transition: opacity .6s, transform .6s; }
.js .rise.in { opacity: 1; transform: none; }

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


/* ---------- highlights: two endless tapes under the hero (index.html #highlights) ----------
   Each tape holds two identical lists and moves by exactly one list's width, so the loop has no seam; the second
   tape runs the other way. A pixel mushroom sits between items, drawn crisp like every sprite on the site. */
#highlights h2 { margin-bottom: 0; }
.tape { display: grid; gap: .7rem; margin-top: 2rem; overflow: hidden; }
.tape-row {
  overflow: hidden; background: var(--card);
  border-block: 1px solid var(--line); box-shadow: var(--shadow-sm);
}
.tape-track { display: flex; width: max-content; animation: tape-roll 60s linear infinite; }
.tape-row--back .tape-track { animation-duration: 70s; animation-direction: reverse; }
.tape:hover .tape-track, .tape:focus-within .tape-track, .tape.is-paused .tape-track { animation-play-state: paused; }
@keyframes tape-roll { to { transform: translateX(-50%); } }
.tape-list { display: flex; align-items: center; margin: 0; padding: 0; list-style: none; }
.tape-item { display: flex; align-items: center; gap: .55rem; padding: .35rem 0; white-space: nowrap; font-size: .95rem; color: var(--ink2); }
.tape-item strong { color: var(--ink); font-weight: 650; }
/* The separator is the pet itself, idle, at 1x (the whole-number scale rule), in a different skin each time. */
.tape-sep { flex: none; margin-inline: 1.1rem 1rem; display: flex; }
.tape-sep .shroom { display: block; }
.tape-quote {
  quotes: "\201C" "\201D"; padding: .25rem .7rem; border-radius: 14px 14px 14px 5px;
  background: var(--red); color: var(--red-ink); font-size: .88rem;
}
.tape-new {
  font-size: .66rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--red); background: var(--tint); border-radius: var(--radius-pill); padding: .12rem .45rem;
}
.tape-toggle { margin-top: 1.2rem; font-size: .85rem; padding: .45rem 1rem; }

@media (prefers-reduced-motion: reduce) {
  /* Still, and yours to scroll: the second list in each tape only existed for the loop. */
  .tape-row { overflow-x: auto; }
  .tape-list[aria-hidden="true"], .tape-toggle { display: none; }
}

/* ---------- 8-bit layer: square corners, 2px pixel borders, hard shadows with no blur ----------
   One layer on top of everything above, so it can be tuned (or taken off) in one place. The palette is untouched:
   only the shapes change. */
:root {
  --px-line: light-dark(var(--ink), color-mix(in srgb, var(--ink) 55%, var(--bg)));
  /* Dark mode cannot use black: it vanishes on the near-black page. A dim ink reads as the same hard shadow. */
  --px-shadow: light-dark(color-mix(in srgb, var(--ink) 85%, transparent), color-mix(in srgb, var(--ink) 24%, var(--bg)));
  --radius-card: 0; --radius-win: 0; --radius-pill: 0;
  --shadow-sm: 3px 3px 0 var(--px-shadow);
  --shadow-md: 5px 5px 0 var(--px-shadow);
  --shadow-lg: 8px 8px 0 var(--px-shadow);
}
*, *::before, *::after { border-radius: 0 !important; }

/* Buttons: flat, outlined, lifting on hover and pressing into their shadow on click, like a game menu. */
.btn, .btn.btn--sm, .btn--ghost {
  background: var(--red); border: 2px solid var(--px-line);
  box-shadow: 3px 3px 0 var(--px-shadow); transition: transform .06s steps(2), box-shadow .06s steps(2);
}
.btn.btn--ghost { background: var(--card); color: var(--ink); }
.btn:hover, .btn.btn--sm:hover, .btn--ghost:hover {
  transform: translate(-1px, -1px); filter: none; box-shadow: 4px 4px 0 var(--px-shadow);
}
.btn:active, .btn--ghost:active { transform: translate(3px, 3px); box-shadow: 0 0 0 var(--px-shadow); }

/* Every framed thing gets the same 2px outline. */
.card, .compact-card, .macwin, .shot, .tape-row, .pay, .result, .faq details, .prose pre, .tape-quote, .tape-new, .chip {
  border: 2px solid var(--px-line);
}
.card:hover { transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--px-shadow); border-color: var(--px-line); }
.card--flat:hover { transform: none; box-shadow: var(--shadow-sm); }
.band { border-block: 2px solid var(--px-line); }
.tape-row { border-inline: 0; }

/* Headings in Press Start 2P (SIL Open Font License 1.1, assets/fonts/OFL-PressStart2P.txt), self-hosted, the original
   file. It is drawn on an 8px grid, so its sizes are whole multiples of 8 (anything else blurs), and it has one
   weight: a heading asking for bold would get a smeared fake one. Body text stays in Terminus. */
@font-face { font-family: "Press Start 2P"; src: url("assets/fonts/PressStart2P-Regular.ttf") format("truetype"); font-weight: 400; font-display: swap; }
h1, h2, .page-head h1, .prose h2 { font-family: "Press Start 2P", "Terminus", monospace; font-weight: 400; line-height: 1.5; letter-spacing: 0; }
h1, .page-head h1 { font-size: 24px; }
h2 { font-size: 16px; }
.prose h2 { font-size: 16px; margin: 2.6rem 0 1rem; }
@media (min-width: 700px) {
  h1, .page-head h1 { font-size: 32px; }
  h2 { font-size: 24px; }
}

/* Readable font: the "Aa" button in the nav (and the default for anyone whose system asks for more contrast) swaps
   both pixel fonts for the system font, for readers who find pixel type hard going. The 8-bit shapes stay. Set as
   data-font="readable" on <html> by the inline head script, before first paint, like the theme. */
:root[data-font="readable"] body, :root[data-font="readable"] h1, :root[data-font="readable"] h2,
:root[data-font="readable"] .page-head h1, :root[data-font="readable"] .prose h2 {
  font-family: -apple-system, "SF Pro Text", system-ui, "Segoe UI", sans-serif;
}
:root[data-font="readable"] body { line-height: 1.6; }
:root[data-font="readable"] :is(h1, h2, .page-head h1, .prose h2) { font-weight: 800; line-height: 1.12; }
:root[data-font="readable"] h1 { font-size: clamp(2.1rem, 5.2vw, 3.35rem); }
:root[data-font="readable"] h2 { font-size: clamp(1.6rem, 4vw, 2.25rem); }
:root[data-font="readable"] .page-head h1 { font-size: clamp(1.9rem, 4.5vw, 2.7rem); }
:root[data-font="readable"] .prose h2 { font-size: clamp(1.35rem, 3vw, 1.7rem); margin: 2.6rem 0 .8rem; }
.font-toggle { font: 700 15px/1 -apple-system, system-ui, "Segoe UI", sans-serif; }
.font-toggle[aria-pressed="true"] { color: var(--ink); background: var(--bg2); }

/* Cookie choice (consent.js): bottom of the screen, both answers the same size, nothing loads from Reddit before one. */
.consent {
  position: fixed; z-index: 1000; left: 16px; right: 16px; bottom: 16px;
  max-width: 640px; margin-inline: auto; padding: 14px 16px;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: var(--card); color: var(--ink);
  border: 2px solid var(--px-line); box-shadow: var(--shadow-md);
}
.consent[hidden] { display: none; }
.consent p { margin: 0; flex: 1 1 320px; font-size: .9rem; line-height: 1.5; }
.consent a { color: var(--red); }
.consent-actions { display: flex; gap: 10px; flex: none; }
