/* redo that. — marketing site
   One stylesheet, system fonts, no build step. Tokens mirror src/lib/theme.ts.
   Restraint is the brand: two neutrals, one warm accent, no gradients. */

:root {
  /* Brand */
  --ink: #141210;
  --ink-soft: #221f1b;
  --paper: #faf7f2;
  --sand: #f0eae0;
  --line: #e3dcd1;
  --ember: #c8683c;

  /* Applied roles (light) */
  --bg: var(--paper);
  --bg-alt: var(--sand);
  --fg: #1c1916;
  /* Deeper than brand `stone` (#8A8378, 3.4:1) so muted copy clears AA. */
  --fg-muted: #6b645a;
  /* Ember itself is only 3.6:1 on paper — fine for rules and dots, not for
     text, so small accent type uses a deepened variant. */
  --accent-text: #a9552e;
  --rule: var(--line);
  --frame: #e8e1d6;
  /* The one inverted block; flips with the scheme so it always stands out. */
  --invert-bg: var(--ink);
  --invert-fg: var(--paper);
  --invert-muted: rgba(250, 247, 242, 0.64);
  --invert-rule: rgba(250, 247, 242, 0.16);
  --chrome: rgba(250, 247, 242, 0.78);
  --shadow: 0 1px 2px rgba(20, 18, 16, 0.05), 0 12px 32px rgba(20, 18, 16, 0.08);

  --gutter: 1.25rem;
  --measure: 34rem;
  --radius: 14px;
  /* Vertical rhythm is the page-length budget. Four to five screens total, so
     sections breathe on a laptop without turning a phone into a staircase. */
  --section: clamp(2.75rem, 6vw, 4.5rem);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: var(--ink);
    --bg-alt: var(--ink-soft);
    --fg: var(--paper);
    --fg-muted: rgba(250, 247, 242, 0.64);
    --accent-text: var(--ember);
    --rule: rgba(250, 247, 242, 0.14);
    --frame: #2b2721;
    --invert-bg: var(--paper);
    --invert-fg: var(--ink);
    --invert-muted: #6b645a;
    --invert-rule: #e3dcd1;
    --chrome: rgba(20, 18, 16, 0.78);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 12px 32px rgba(0, 0, 0, 0.35);
  }
}

/* Explicit choice wins in both directions (media queries can't be overridden
   by a later selector, so the dark case is repeated outside the query). */
:root[data-theme='dark'] {
  --bg: var(--ink);
  --bg-alt: var(--ink-soft);
  --fg: var(--paper);
  --fg-muted: rgba(250, 247, 242, 0.64);
  --accent-text: var(--ember);
  --rule: rgba(250, 247, 242, 0.14);
  --frame: #2b2721;
  --invert-bg: var(--paper);
  --invert-fg: var(--ink);
  --invert-muted: #6b645a;
  --invert-rule: #e3dcd1;
  --chrome: rgba(20, 18, 16, 0.78);
}

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
    'Noto Sans', sans-serif;
  font-size: 1.0625rem;
  line-height: 1.6;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

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

/* ---- Type -------------------------------------------------------------- */
/* Tracking is size-specific: display tightens, body sits near zero. */

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

h1 {
  font-size: clamp(2.375rem, 8.5vw, 4.25rem);
  line-height: 1.02;
  letter-spacing: -0.038em;
}

h2 {
  font-size: clamp(1.75rem, 5vw, 2.625rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
}

h3 {
  font-size: 1.1875rem;
  line-height: 1.35;
  letter-spacing: -0.016em;
}

p {
  margin: 0;
}

a {
  color: inherit;
}

.lede {
  font-size: clamp(1.125rem, 2.4vw, 1.375rem);
  line-height: 1.5;
  letter-spacing: -0.011em;
  color: var(--fg-muted);
  max-width: var(--measure);
}

.muted {
  color: var(--fg-muted);
}

.eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* ---- Layout ------------------------------------------------------------ */

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

section {
  padding-block: var(--section);
}

/* The header is sticky, so an anchor jump would otherwise park the eyebrow
   underneath it. */
section[id] {
  scroll-margin-top: 3.75rem;
}

.band {
  background: var(--bg-alt);
}

.stack > * + * {
  margin-top: 1rem;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--invert-bg);
  color: var(--invert-fg);
  padding: 0.75rem 1rem;
  border-radius: 0 0 var(--radius) 0;
  z-index: 20;
}

.skip:focus {
  left: 0;
}

/* ---- Scroll reveals ------------------------------------------------------
   The default state is visible. `.anim` on <html> — set by the head script
   only when JS runs, IntersectionObserver exists and reduced motion is off —
   is what hides a block until it scrolls in, so nothing is ever hidden from a
   crawler or a visitor with JS off. Transform and opacity only; entry eases
   out, never in. */

.anim [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 620ms cubic-bezier(0.23, 1, 0.32, 1),
    transform 620ms cubic-bezier(0.23, 1, 0.32, 1);
  transition-delay: var(--reveal-delay, 0ms);
}

.anim [data-reveal].in-view {
  opacity: 1;
  transform: none;
}

/* ---- Focus ------------------------------------------------------------- */

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

/* ---- Header ------------------------------------------------------------ */

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--chrome);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border-bottom: 1px solid var(--rule);
}

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

.wordmark {
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.028em;
  text-decoration: none;
  white-space: nowrap;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  font-size: 0.9375rem;
}

.site-nav a {
  color: var(--fg-muted);
  text-decoration: none;
  padding-block: 0.5rem;
}

.site-nav a:hover {
  color: var(--fg);
}

/* ---- Hero -------------------------------------------------------------- */

.hero {
  padding-top: clamp(2.25rem, 6vw, 3.5rem);
  padding-bottom: clamp(1.75rem, 4vw, 2.5rem);
}

.hero h1 {
  max-width: 15ch;
}

.hero .lede {
  margin-top: 1rem;
}

/* ---- Buttons + pills --------------------------------------------------- */

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0 1.5rem;
  border: 0;
  border-radius: 999px;
  background: var(--invert-bg);
  color: var(--invert-fg);
  font: inherit;
  font-weight: 600;
  letter-spacing: -0.012em;
  text-decoration: none;
  cursor: pointer;
  transition: transform 120ms ease-out, opacity 120ms ease-out;
}

.btn:hover {
  opacity: 0.88;
}

.btn:active {
  transform: scale(0.98);
}

.btn-quiet {
  background: transparent;
  color: var(--fg);
  border: 1px solid var(--rule);
}

.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
  margin-top: 1.5rem;
  padding: 0;
  list-style: none;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0 1.125rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-size: 0.9375rem;
  color: var(--fg-muted);
}

.pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ember);
  flex: none;
}

/* ---- Before / after pairs ---------------------------------------------- */

.pair {
  margin: 0;
}

.frames {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
}

.frame {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--frame);
  aspect-ratio: 3 / 2;
}

.frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tag {
  position: absolute;
  left: 0.625rem;
  bottom: 0.625rem;
  padding: 0.25rem 0.625rem;
  border-radius: 999px;
  background: rgba(20, 18, 16, 0.62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #faf7f2;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.pair figcaption {
  margin-top: 0.875rem;
  font-size: 0.9375rem;
  color: var(--fg-muted);
}

.hero-pair {
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
}

/* ---- Steps + phone frames ---------------------------------------------- */

.steps {
  display: grid;
  gap: clamp(1.75rem, 4vw, 2.25rem);
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  padding: 0;
  list-style: none;
}

/* On a phone the screenshot sits beside its caption rather than under it —
   stacking the two was what made this section two screens tall by itself. */
.step {
  display: flex;
  align-items: flex-start;
  gap: 1.25rem;
}

.step-body {
  flex: 1 1 auto;
  min-width: 0;
}

.step-num {
  display: inline-block;
  font-variant-numeric: tabular-nums;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--accent-text);
}

.step h3 {
  margin-top: 0.25rem;
}

.step p {
  color: var(--fg-muted);
  max-width: 30rem;
  font-size: 0.9375rem;
}

.phone {
  flex: none;
  width: 9rem;
  padding: 0.375rem;
  border-radius: 1.5rem;
  background: var(--ink);
  box-shadow: var(--shadow);
}

.phone img {
  width: 100%;
  border-radius: 1.2rem;
  aspect-ratio: 620 / 1343;
  object-fit: cover;
}

/* ---- Rails --------------------------------------------------------------
   Swipe on a phone, click through on a desktop. Native scroll-snap does the
   work; the script only syncs the dots and arrows, so a rail still scrolls
   with JS off. The inline padding lines the first card up with the text
   column above it while the rail itself runs full bleed.

   There are two on the home page and they must not read as one component:
   `--wide` is the showcase — image-led, about twice as wide, no card chrome,
   the photograph is the card. `--feat` is the feature list — a small panel
   with a picture, three words and a line. Same mechanics, different object. */

.rail-shell {
  position: relative;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  --rail-inset: max(var(--gutter), calc((100% - 68rem) / 2 + var(--gutter)));
}

.rail {
  display: flex;
  gap: 1rem;
  margin: 0;
  padding: 0.25rem var(--rail-inset) 1.25rem;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline-start: var(--rail-inset);
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.rail::-webkit-scrollbar {
  display: none;
}

.rail-card {
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  transition: transform 320ms cubic-bezier(0.23, 1, 0.32, 1),
    box-shadow 320ms cubic-bezier(0.23, 1, 0.32, 1);
}

/* Showcase rail — the picture is the card. */
.rail-shell--wide .rail {
  gap: 1.25rem;
}

.rail-shell--wide .rail-card {
  flex: 0 0 min(86vw, 44rem);
  border-radius: var(--radius);
}

.rail-shell--wide .pair {
  width: 100%;
}

.rail-shell--wide figcaption {
  margin-top: 0.75rem;
}

/* Feature rail — a small panel. */
.rail-shell--feat .rail-card {
  flex: 0 0 min(78vw, 19.5rem);
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: 18px;
  background: var(--bg);
}

.rail-shell--feat .rail-card img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  /* A hairline keeps the media edge readable when the picture is as pale as
     the card under it. */
  border-bottom: 1px solid var(--rule);
  background: var(--frame);
}

.rail-body {
  padding: 1.125rem 1.25rem 1.375rem;
}

.rail-body p {
  margin-top: 0.375rem;
  font-size: 0.9375rem;
  color: var(--fg-muted);
}

@media (hover: hover) {
  .rail-shell--feat .rail-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow);
  }
}

/* Dots: hidden until the script turns them on, since they do nothing without
   it. The hit area is 1.5rem; the dot inside is 7px. */
.dots {
  display: flex;
  gap: 0.375rem;
  margin-left: -0.375rem;
}

.dot {
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.dot::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--rule);
  transition: transform 260ms cubic-bezier(0.23, 1, 0.32, 1), background-color 260ms ease-out;
}

.dot[aria-current='true']::before {
  background: var(--ember);
  transform: scale(1.4);
}

/* Arrows are a desktop affordance only, and only on hover — the rail is a
   swipe everywhere else. */
.rail-arrow {
  display: none;
}

@media (hover: hover) and (min-width: 56em) {
  .rail-arrow {
    position: absolute;
    top: 30%;
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: 1px solid var(--rule);
    border-radius: 50%;
    background: var(--bg);
    color: var(--fg);
    box-shadow: var(--shadow);
    cursor: pointer;
    opacity: 0;
    transition: opacity 220ms ease-out, transform 220ms cubic-bezier(0.23, 1, 0.32, 1);
  }

  /* The showcase cards are short and wide, so a flat 30 % would drop these
     onto the caption instead of the picture. */
  .rail-shell--wide .rail-arrow {
    top: 36%;
  }

  .rail-prev {
    left: 1rem;
  }

  .rail-next {
    right: 1rem;
  }

  .rail-shell:hover .rail-arrow,
  .rail-arrow:focus-visible {
    opacity: 1;
  }

  .rail-arrow:hover {
    transform: scale(1.06);
  }

  .rail-arrow[disabled] {
    opacity: 0;
    pointer-events: none;
  }
}

/* ---- Closing call ------------------------------------------------------- */

.call {
  background: var(--invert-bg);
  color: var(--invert-fg);
}

.call .lede,
.call .muted,
.call .pill {
  color: var(--invert-muted);
}

.call .pill {
  border-color: var(--invert-rule);
}

.call .btn {
  background: var(--invert-fg);
  color: var(--invert-bg);
}

/* ---- Long-form pages ---------------------------------------------------- */

.doc {
  max-width: 44rem;
  padding-block: clamp(2.5rem, 6vw, 4rem) var(--section);
}

.doc h1 {
  font-size: clamp(2rem, 6vw, 3rem);
}

.doc h2 {
  font-size: 1.375rem;
  letter-spacing: -0.02em;
  margin-top: 2.75rem;
}

.doc h3 {
  font-size: 1.0625rem;
  margin-top: 1.75rem;
}

.doc p,
.doc ul,
.doc ol {
  margin-top: 0.875rem;
}

.doc ul,
.doc ol {
  padding-left: 1.25rem;
}

.doc li + li {
  margin-top: 0.5rem;
}

.doc a {
  color: var(--fg);
  text-decoration-color: var(--ember);
  text-underline-offset: 3px;
}

.doc .updated {
  margin-top: 1rem;
  font-size: 0.9375rem;
  color: var(--fg-muted);
}

.doc table {
  width: 100%;
  margin-top: 1rem;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.doc th,
.doc td {
  text-align: left;
  vertical-align: top;
  padding: 0.625rem 0.75rem 0.625rem 0;
  border-bottom: 1px solid var(--rule);
}

.doc th {
  font-weight: 600;
  white-space: nowrap;
}

.scroll-x {
  overflow-x: auto;
}

/* ---- Referral ----------------------------------------------------------- */

.code-card {
  margin-top: 2rem;
  padding: clamp(1.5rem, 5vw, 2.5rem);
  border: 1px solid var(--rule);
  border-radius: 20px;
  background: var(--bg-alt);
  text-align: center;
}

.code {
  display: block;
  margin: 0.75rem 0 0;
  font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
  font-size: clamp(2.25rem, 12vw, 3.75rem);
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.1;
  text-indent: 0.12em;
  word-break: break-all;
  /* A long-press or double-click grabs the whole code, not one character. */
  -webkit-user-select: all;
  user-select: all;
}

.copy-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.625rem;
  margin-top: 1.5rem;
}

.copy-status {
  min-height: 1.25rem;
  font-size: 0.875rem;
  color: var(--fg-muted);
}

.howto {
  counter-reset: howto;
  margin-top: 2.5rem;
  padding: 0;
  list-style: none;
}

.howto li {
  position: relative;
  padding-left: 2.25rem;
  margin-top: 1rem;
}

.howto li::before {
  counter-increment: howto;
  content: counter(howto);
  position: absolute;
  left: 0;
  top: 0.1rem;
  width: 1.625rem;
  height: 1.625rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--rule);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fg-muted);
}

/* ---- Footer ------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--rule);
  padding-block: 2rem 2.5rem;
  font-size: 0.9375rem;
  color: var(--fg-muted);
}

.site-footer .wrap {
  display: grid;
  gap: 1.25rem;
}

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.site-footer a {
  color: var(--fg-muted);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--fg);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.legal {
  font-size: 0.875rem;
  line-height: 1.5;
}

/* ---- Wider viewports ---------------------------------------------------- */

@media (min-width: 40em) {
  :root {
    --gutter: 2rem;
  }

  .frames {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 56em) {
  /* Three abreast, back to a column; `margin-top: auto` lands every phone on
     one baseline however long the copy above it runs. */
  .steps {
    grid-template-columns: repeat(3, 1fr);
    gap: 2.25rem;
  }

  .step {
    flex-direction: column;
    gap: 1.25rem;
  }

  .step p {
    font-size: 1rem;
  }

  .step .phone {
    margin-top: auto;
    width: 100%;
    max-width: 13rem;
    padding: 0.5rem;
    border-radius: 2rem;
  }

  .step .phone img {
    border-radius: 1.6rem;
  }

  /* Three cards and a peek of the fourth on a laptop — enough overflow that
     the rail reads as a rail and the arrows have somewhere to go. */
  .rail-shell--feat .rail-card {
    flex-basis: 21rem;
  }

  .site-footer .wrap {
    grid-template-columns: 1fr auto;
    align-items: end;
  }
}

/* ---- User preferences --------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }

  /* Belt and braces: the head script already skips `.anim` under reduced
     motion, but if the preference changes after load nothing may stay hidden. */
  .anim [data-reveal] {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .site-header,
  .tag {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .site-header {
    background: var(--bg);
  }

  .tag {
    background: #141210;
  }
}

@media (prefers-contrast: more) {
  :root {
    --fg-muted: var(--fg);
    --rule: currentColor;
  }
}
