/*
 * iFart — shared stylesheet for ifart.app
 *
 * The palette is taken from apps/mobile/tailwind.config.js so the site and the
 * app are recognisably the same product. Category and reaction colours are used
 * only where they encode that category or reaction — never as decoration.
 *
 * No webfonts: the display face is the monospace stack, set heavy and tight.
 * That is a deliberate choice, not a fallback — the product's voice is a
 * measurement readout, and a mono headline says so before a word is read.
 */

/* ---------------------------------------------------------------- tokens -- */

:root {
  color-scheme: light dark;

  /* Neutrals are biased toward the violet accent rather than pure grey. */
  --ground: #f6f5fb;
  --panel: #ffffff;
  --raised: #efedf9;
  --ink: #1a1a2e;
  --ink-dim: #55536e;
  --ink-faint: #8886a3;
  --accent: #7c3aed;
  --accent-strong: #6d28d9;
  --accent-wash: rgba(124, 58, 237, 0.08);
  /* The call to action is small bold uppercase, so it needs the 4.5:1 of
     normal text, not the 3:1 of large text. Deep violet under white clears
     it at 7.1:1. */
  --cta-bg: #6d28d9;
  --cta-bg-hover: #5b21b6;
  --cta-fg: #ffffff;
  --rule: rgba(26, 26, 46, 0.12);
  --rule-strong: rgba(26, 26, 46, 0.22);
  --shadow: 0 1px 2px rgba(26, 26, 46, 0.06), 0 8px 24px rgba(26, 26, 46, 0.06);

  /* Signal colours. Identical in both themes: they carry meaning, not mood. */
  --sig-silent: #6b7280;
  --sig-thunder: #f59e0b;
  --sig-squeaky: #ec4899;
  --sig-nuclear: #10b981;
  --sig-risky: #ef4444;

  --font-mono:
    ui-monospace, SFMono-Regular, 'SF Mono', 'Cascadia Mono', 'Segoe UI Mono',
    Menlo, Consolas, monospace;
  --font-sans:
    ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;

  --measure: 34rem;
  --gutter: clamp(1.25rem, 5vw, 3rem);
}

@media (prefers-color-scheme: dark) {
  :root {
    --ground: #1a1a2e;
    --panel: #16213e;
    --raised: #0f3460;
    --ink: #ececf6;
    --ink-dim: #a7a6c0;
    --ink-faint: #6e6d88;
    --accent: #a78bfa;
    --accent-strong: #8b5cf6;
    --accent-wash: rgba(167, 139, 250, 0.1);
    /* White on the dark theme's violet is only 4.23:1 — short of the mark.
       Inverting the button instead (near-black on bright violet) gets 6.3:1
       and hits harder on a dark ground. */
    --cta-bg: #a78bfa;
    --cta-bg-hover: #c4b5fd;
    --cta-fg: #14141f;
    --rule: rgba(167, 139, 250, 0.16);
    --rule-strong: rgba(167, 139, 250, 0.3);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.3);
  }
}

/* The viewer's own toggle must win over the OS preference, both ways. */
:root[data-theme='dark'] {
  --ground: #1a1a2e;
  --panel: #16213e;
  --raised: #0f3460;
  --ink: #ececf6;
  --ink-dim: #a7a6c0;
  --ink-faint: #6e6d88;
  --accent: #a78bfa;
  --accent-strong: #8b5cf6;
  --accent-wash: rgba(167, 139, 250, 0.1);
  --cta-bg: #a78bfa;
  --cta-bg-hover: #c4b5fd;
  --cta-fg: #14141f;
  --rule: rgba(167, 139, 250, 0.16);
  --rule-strong: rgba(167, 139, 250, 0.3);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.3);
}

:root[data-theme='light'] {
  --ground: #f6f5fb;
  --panel: #ffffff;
  --raised: #efedf9;
  --ink: #1a1a2e;
  --ink-dim: #55536e;
  --ink-faint: #8886a3;
  --accent: #7c3aed;
  --accent-strong: #6d28d9;
  --accent-wash: rgba(124, 58, 237, 0.08);
  /* The call to action is small bold uppercase, so it needs the 4.5:1 of
     normal text, not the 3:1 of large text. Deep violet under white clears
     it at 7.1:1. */
  --cta-bg: #6d28d9;
  --cta-bg-hover: #5b21b6;
  --cta-fg: #ffffff;
  --rule: rgba(26, 26, 46, 0.12);
  --rule-strong: rgba(26, 26, 46, 0.22);
  --shadow: 0 1px 2px rgba(26, 26, 46, 0.06), 0 8px 24px rgba(26, 26, 46, 0.06);
}

/* ------------------------------------------------------------------ base -- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* The masthead is sticky, so an anchored heading lands underneath it unless
   every target reserves the height back. `:where()` contributes no specificity,
   so this cannot outrank a rule that means to set scroll-margin itself. */
:where([id]) {
  scroll-margin-top: 5rem;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--accent);
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

a:hover {
  color: var(--accent-strong);
}

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

/* Off-screen until focused. First thing in the tab order, so a keyboard user
   is not walked through the masthead nav on every page. */
.skip {
  position: fixed;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 20;
  transform: translateY(-200%);
  padding: 0.7rem 1.1rem;
  border-radius: 8px;
  background: var(--cta-bg);
  color: var(--cta-fg);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
}

.skip:focus {
  transform: translateY(0);
}

h1,
h2,
h3 {
  text-wrap: balance;
  margin: 0;
}

/* The instrument voice: every label, readout and heading. */
.eyebrow,
.readout,
h1,
h2,
h3,
.wordmark,
th,
.clause-no {
  font-family: var(--font-mono);
}

.eyebrow {
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0;
}

.shell {
  width: 100%;
  max-width: 68rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ---------------------------------------------------------------- header -- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--rule);
}

.masthead-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 3.75rem;
}

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-decoration: none;
}

.wordmark::before {
  content: '';
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--sig-risky);
  transform: translateY(-0.05em);
}

.masthead nav {
  display: flex;
  gap: clamp(0.9rem, 3vw, 1.75rem);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.masthead nav a {
  color: var(--ink-dim);
  text-decoration: none;
}

.masthead nav a:hover,
.masthead nav a[aria-current='page'] {
  color: var(--ink);
}

.masthead-tools {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 3vw, 1.75rem);
}

/* Three links, a wordmark and the theme control do not quite fit across a
   narrow phone. The longest link drops rather than the whole nav, so the
   masthead keeps somewhere to go. */
@media (max-width: 47.99rem) {
  .masthead .nav-wide {
    display: none;
  }
}

/* The stylesheet has carried `[data-theme]` overrides since the first version,
   but nothing ever set the attribute. This is the control that does. It is
   useless without script, so it is only shown once script has run. */
.theme-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  flex: none;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--rule-strong);
  background: transparent;
  color: var(--ink-dim);
  cursor: pointer;
  transition:
    color 0.2s ease,
    border-color 0.2s ease;
}

.js .theme-toggle {
  display: inline-flex;
}

.theme-toggle:hover {
  color: var(--ink);
  border-color: var(--accent);
}

/* A half-filled disc: the one icon that means "contrast" without needing to
   decide whether it is currently a sun or a moon. */
.theme-icon {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
}

/* ------------------------------------------------------------- structure -- */

.section {
  padding-block: clamp(3rem, 8vw, 5.5rem);
  border-top: 1px solid var(--rule);
}

.section:first-of-type {
  border-top: 0;
}

.section-head {
  display: grid;
  gap: 0.75rem;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

.section-head h2 {
  font-size: clamp(1.375rem, 3.2vw, 1.875rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.section-head p {
  margin: 0;
  max-width: var(--measure);
  color: var(--ink-dim);
}

/* ------------------------------------------------------------------ hero -- */

.hero {
  padding-block: clamp(3rem, 9vw, 6rem) clamp(3rem, 8vw, 5rem);
}

.hero-grid {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
  align-items: center;
}

@media (min-width: 62rem) {
  .hero-grid {
    grid-template-columns: 1fr 26rem;
  }
}

/* The hero's type, ground and calls to action all live in the loud layer at
   the foot of this file — nothing element-scoped here, so those class-only
   selectors are not outranked. */

/* -------------------------------------------------------------- the rig --- */

.rig {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 1.25rem;
  box-shadow: var(--shadow);
  display: grid;
  gap: 1rem;
}

.rig-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.rig-head .eyebrow {
  color: var(--ink-dim);
}

/* Nothing is drawn into the canvas without a script, and an empty panel reads
   as a failed load rather than as a design. The meter, readout and verdict
   below still carry the whole point, so the canvas only appears with JS. */
.rig canvas {
  display: none;
  width: 100%;
  height: 132px;
  border-radius: 8px;
  background: var(--raised);
}

.js .rig canvas {
  display: block;
}

.readout {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.readout div {
  display: grid;
  gap: 0.25rem;
}

.readout dt,
.readout .k {
  color: var(--ink-faint);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: 0.625rem;
}

.readout .v {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* The score track. 0.00 at the left, 1.00 at the right, threshold at 0.70. */
.meter {
  display: grid;
  gap: 0.45rem;
}

.meter-track {
  position: relative;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--raised);
  overflow: hidden;
}

/* Rests at the settled value so the track agrees with the 0.71 printed in the
   markup when no script runs. It is only wound back to zero, to be animated
   up, once JS is known to be there. */
.meter-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 71%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-strong), var(--sig-nuclear));
  transition: width 1.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.js .meter-fill {
  width: 0;
}

.meter-threshold {
  position: absolute;
  top: -0.25rem;
  bottom: -0.25rem;
  left: 70%;
  width: 2px;
  background: var(--ink-faint);
}

.meter-scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.meter-scale .thresh {
  color: var(--ink-dim);
}

.verdict {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 0.9rem;
  border-radius: 8px;
  border: 1px dashed var(--rule-strong);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  transition: opacity 0.5s ease;
}

/* Only hidden-until-scored when a script is there to score it. Must precede
   `.verdict.on` — the two are the same specificity, so order decides. */
.js .verdict {
  opacity: 0;
}

.verdict.on {
  opacity: 1;
}

.verdict .stamp {
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sig-nuclear);
}

.verdict .why {
  color: var(--ink-faint);
  font-size: 0.6875rem;
}

/* ----------------------------------------------------------------- steps -- */

.steps {
  display: grid;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
}

@media (min-width: 48rem) {
  .steps {
    grid-template-columns: repeat(3, 1fr);
  }
}

.step {
  background: var(--panel);
  padding: 1.5rem;
  display: grid;
  gap: 0.5rem;
  align-content: start;
}

.step .n {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  color: var(--accent);
}

.step h3 {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.step p {
  margin: 0;
  color: var(--ink-dim);
  font-size: 0.9375rem;
}

/* ----------------------------------------------------------------- table -- */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--panel);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

caption {
  text-align: left;
  padding: 1rem 1.25rem 0;
  color: var(--ink-faint);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

th,
td {
  text-align: left;
  padding: 0.85rem 1.25rem;
  border-bottom: 1px solid var(--rule);
}

th {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

tbody tr:last-child td {
  border-bottom: 0;
}

/* ------------------------------------------------------------------ list -- */

.rules {
  display: grid;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
}

@media (min-width: 48rem) {
  .rules {
    grid-template-columns: repeat(2, 1fr);
  }
}

.rule-item {
  background: var(--panel);
  padding: 1.4rem 1.5rem;
  display: grid;
  gap: 0.4rem;
  align-content: start;
}

.rule-item h3 {
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.rule-item p {
  margin: 0;
  color: var(--ink-dim);
  font-size: 0.9375rem;
}

/* ---------------------------------------------------------------- footer -- */

.colophon {
  border-top: 1px solid var(--rule);
  padding-block: 2.5rem 3rem;
  color: var(--ink-faint);
  font-size: 0.875rem;
}

.colophon-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  align-items: baseline;
  justify-content: space-between;
}

.colophon nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.colophon nav a {
  color: var(--ink-dim);
  text-decoration: none;
}

.colophon nav a:hover {
  color: var(--ink);
}

/* ------------------------------------------------------------ legal docs -- */

.doc {
  padding-block: clamp(2.5rem, 6vw, 4rem);
}

.doc-head {
  display: grid;
  gap: 0.75rem;
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 2.5rem;
}

.doc-head h1 {
  font-size: clamp(1.75rem, 5vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  text-transform: uppercase;
}

.doc-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.doc-body {
  display: grid;
  gap: 2.5rem;
  max-width: 44rem;
}

.clause {
  display: grid;
  gap: 0.75rem;
}

.clause h2 {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.015em;
}

.clause-no {
  color: var(--accent);
  font-size: 0.8125rem;
  font-weight: 400;
  flex: none;
}

.clause p,
.clause li {
  margin: 0;
  max-width: var(--measure);
  color: var(--ink-dim);
}

.clause ul {
  margin: 0;
  padding-left: 1.1rem;
  display: grid;
  gap: 0.5rem;
}

.clause strong {
  color: var(--ink);
  font-weight: 600;
}

.callout {
  border-left: 3px solid var(--accent);
  background: var(--accent-wash);
  padding: 1rem 1.25rem;
  border-radius: 0 8px 8px 0;
  display: grid;
  gap: 0.5rem;
}

.callout p {
  color: var(--ink);
}

.toc {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 1.25rem 1.5rem;
  margin-bottom: 2.5rem;
}

.toc ol {
  margin: 0.75rem 0 0;
  padding-left: 1.4rem;
  columns: 2;
  column-gap: 2rem;
  font-size: 0.875rem;
}

.toc li {
  margin-bottom: 0.35rem;
  break-inside: avoid;
}

.toc a {
  text-decoration: none;
  color: var(--ink-dim);
}

.toc a:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* ========================================================================== *
 * Loud layer
 *
 * The substance stays the same — this is still a measurement readout played
 * straight. What changed is the volume, following what the best consumer app
 * sites are actually doing in 2026: oversized type carrying the hero instead
 * of an image, one saturated accent against a deep ground, CSS grain for
 * tactile depth, and the product itself shown at size.
 * ========================================================================== */

/* Grain. An SVG turbulence tile at low opacity, fixed over everything, so the
   flat ground reads as printed rather than as a filled rectangle. Cheap: one
   small tiled data URI, no WebGL, no repaint on scroll. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.36;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
}

:root[data-theme='light'] .grain,
html:not([data-theme='dark']) .grain {
  opacity: 0.2;
}

@media (prefers-color-scheme: dark) {
  html:not([data-theme='light']) .grain {
    opacity: 0.36;
  }
}

/* Content stacks above the grain. This deliberately does not set `position`:
   the previous form of this rule was `body > *:not(.grain)`, whose 0-1-1
   outranked `.masthead`'s 0-1-0 and silently reset the header's `sticky` to
   `relative` — it had stopped sticking. The masthead is excluded because it
   already establishes its own stacking at z-index 10, above the grain's 1. */
main,
.colophon {
  position: relative;
  z-index: 2;
}

/* -------------------------------------------------------------- big hero -- */

.hero-xl {
  padding-block: clamp(2.5rem, 7vw, 5rem) clamp(3rem, 8vw, 5rem);
  overflow: hidden;
}

.hero-xl .hero-grid {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4.5rem);
  align-items: center;
}

@media (min-width: 62rem) {
  .hero-xl .hero-grid {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  }
}

.headline {
  font-family: var(--font-mono);
  font-weight: 700;
  /* 13vw is the slope Yope's hero uses as well. The ceiling comes down from
     9.5rem to 6.5rem — Yope stops at 104px, and nothing measured went past
     it; at 152px this wrapped to three and four lines on a wide viewport. */
  font-size: clamp(3.25rem, 13vw, 6.5rem);
  line-height: 0.84;
  /* Was -0.055em, tighter than every site measured: NGL and Flighty sit at
     -0.02em, Partiful between -0.02em and -0.04em. */
  letter-spacing: -0.03em;
  text-transform: uppercase;
  margin: 0.5rem 0 0;
  text-wrap: balance;
}

.headline .l2 {
  display: block;
  color: var(--accent);
}

/* The one non-violet accent in the whole page, spent on a single character. */
.headline .stop {
  color: var(--sig-thunder);
}

.hero-sub {
  font-size: clamp(1.0625rem, 2vw, 1.3125rem);
  line-height: 1.5;
  color: var(--ink-dim);
  max-width: 30ch;
  margin: 1.5rem 0 0;
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 2.25rem;
}

/* 48px minimum, per the mobile-first benchmarks — these are thumb targets. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 3.25rem;
  padding: 0 1.6rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform 0.18s ease,
    background-color 0.18s ease,
    border-color 0.18s ease;
}

.btn-primary {
  background: var(--cta-bg);
  color: var(--cta-fg);
  box-shadow: 0 10px 30px -12px var(--cta-bg);
}

.btn-primary:hover {
  background: var(--cta-bg-hover);
  color: var(--cta-fg);
  transform: translateY(-2px);
}

/* ---------------------------------------------------------------- stores -- */

.stores {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.stores a {
  display: inline-flex;
  border-radius: 8px;
  transition: transform 0.18s ease;
}

.stores a:hover {
  transform: translateY(-2px);
}

/* Apple's SVG is cropped tight to the artwork, so the box height is the badge
   height. 48px holds the tap-target floor the rest of the page keeps to. */
.store-apple {
  height: 48px;
  width: auto;
}

/* Google ships its badge inside 41px of transparent margin on a 646x250
   canvas, which makes the file 1.4881x taller than the artwork in it. Setting
   both badges to the same height is the usual way this goes wrong — the Play
   badge comes out visibly smaller. At 71.4px the visible badge lands at the
   same 48px as Apple's, and the negative inline margin cancels the side
   padding so the optical gap matches the flex gap. Measured from the file's
   alpha channel rather than guessed, and neither asset is altered — both
   companies' brand guidelines require their artwork unmodified. */
.store-google {
  height: 71.4px;
  width: auto;
  margin-inline: -0.73rem;
}

/* ----------------------------------------------------------------- phone -- */

.phone {
  position: relative;
  width: min(20rem, 100%);
  margin-inline: auto;
  aspect-ratio: 9 / 18.5;
  border-radius: 2.4rem;
  padding: 0.6rem;
  background: linear-gradient(160deg, #2b2b45, #101019);
  box-shadow:
    0 2px 0 rgba(255, 255, 255, 0.08) inset,
    0 40px 80px -30px rgba(0, 0, 0, 0.7);
}

.phone-screen {
  height: 100%;
  border-radius: 1.9rem;
  background: #1a1a2e;
  overflow: hidden;
  display: grid;
  grid-template-rows: auto 1fr;
  color: #ececf6;
}

.phone-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1.1rem 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #6e6d88;
}

.phone-body {
  padding: 0.5rem 0.7rem 0.9rem;
  display: grid;
  gap: 0.6rem;
  align-content: start;
}

/* A replica of the app's own feed card, so the hero shows the actual product
   rather than a stock device mockup. */
.fart-card {
  background: #16213e;
  border-radius: 0.9rem;
  padding: 0.8rem;
  display: grid;
  gap: 0.65rem;
}

.fc-head {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.fc-avatar {
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: #38385c;
  display: grid;
  place-items: center;
  font-size: 0.75rem;
  font-weight: 700;
}

.fc-who {
  display: grid;
  line-height: 1.25;
}

.fc-who b {
  font-size: 0.75rem;
}

.fc-who span {
  font-size: 0.625rem;
  color: #6e6d88;
}

.fc-time {
  margin-left: auto;
  font-size: 0.625rem;
  color: #6e6d88;
}

.fc-title {
  font-size: 0.8125rem;
  font-weight: 600;
}

.fc-player {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.fc-play {
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  /* The phone is a fixed dark island showing the app's own palette, so its
     internals do not follow the site's theme tokens. */
  background: #8b5cf6;
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  flex: none;
}

.fc-wave {
  flex: 1;
  height: 1.8rem;
  display: flex;
  align-items: center;
  gap: 2px;
}

.fc-wave i {
  flex: 1;
  border-radius: 999px;
  background: #3a3a5c;
  min-height: 2px;
}

.fc-wave i.on {
  background: #a78bfa;
}

.fc-dur {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  color: #6e6d88;
}

.fc-tags {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.tag {
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  font-weight: 700;
}

.tag-verified {
  background: rgba(16, 185, 129, 0.16);
  color: #34d399;
}

.fc-reactions {
  display: flex;
  gap: 0.3rem;
  border-top: 1px solid rgba(167, 139, 250, 0.14);
  padding-top: 0.6rem;
}

.fc-reactions span {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  background: #1d2949;
  border-radius: 0.5rem;
  padding: 0.35rem 0;
  font-size: 0.6875rem;
  color: #a7a6c0;
  font-family: var(--font-mono);
}

.fc-reactions .picked {
  background: rgba(139, 92, 246, 0.22);
  color: #ececf6;
}

/* --------------------------------------------------------------- marquee -- */

.marquee {
  /* One gap value for the space between items, the space between the two
     tracks, and the distance the animation travels. They have to agree or the
     loop seam shows — see @keyframes slide. */
  --marq-gap: 2.5rem;

  border-block: 1px solid var(--rule);
  background: var(--panel);
  overflow: hidden;
  padding-block: 0.9rem;
  display: flex;
  gap: var(--marq-gap);
  white-space: nowrap;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
  mask-image: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
}

.marquee-track {
  display: flex;
  gap: var(--marq-gap);
  align-items: center;
  flex: none;
  animation: slide 38s linear infinite;
}

.marquee span {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.marquee span::before {
  content: '';
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--c, var(--accent));
}

/* A track travels its own width *plus the gap that follows it*, which lands the
   second track exactly where the first began. Stopping at -100% left the gap
   unaccounted for, so the loop jumped a gap's width every 38 seconds. */
@keyframes slide {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(-100% - var(--marq-gap)));
  }
}

/* ---------------------------------------------------------- weight cards -- */

.weights {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.weight {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 1.4rem 1.25rem;
  display: grid;
  gap: 0.35rem;
  transition:
    transform 0.2s ease,
    border-color 0.2s ease;
}

.weight:hover {
  transform: translateY(-3px);
  border-color: var(--rule-strong);
}

.weight .face {
  font-size: 2rem;
  line-height: 1;
}

.weight .mult {
  font-family: var(--font-mono);
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
}

.weight.hero-weight .mult {
  color: var(--sig-thunder);
}

.weight .who {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.weight .note {
  font-size: 0.8125rem;
  color: var(--ink-dim);
}

/* ---------------------------------------------------------------- reveal -- */

/* Gated on `.js`, which the document sets on itself before first paint. The
   class that reveals these is added by script, so an ungated `opacity: 0`
   leaves the page all but blank when the script does not run — every section
   head, the steps, the weight cards, the rig, the table and the ground rules
   carry `.reveal`. */
/* 0.3s, not the 0.65s this started at. Raycast uses .3s 97 times and Yope
   clusters at .25s–.3s; two thirds of a second read as sluggish beside them.
   The curve is unchanged — it is already Raycast's own. */
.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.js .reveal.in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  html {
    scroll-behavior: auto;
  }

  /* Reveals must not be left invisible when transitions are switched off. */
  .reveal {
    opacity: 1 !important;
    transform: none !important;
  }

  .marquee-track {
    animation: none !important;
  }
}

/* Pre-launch stand-in for the hidden store badges (index.html). */
/* display:flex on the containers would otherwise override the hidden attribute. */
.stores[hidden],
.cta-row[hidden] {
  display: none;
}

.stores-soon {
  margin-top: 1.5rem;
  font-weight: 600;
  opacity: 0.85;
}
