/* jinistickerbook — shared styles. Palette + display type mirror the app's DesignSystem.swift. */
@import url('https://fonts.googleapis.com/css2?family=Gaegu:wght@300;400;700&display=swap');

/* Phren Sans, self-hosted. Only the three weights the site uses. */
@font-face {
  font-family: 'Phren Sans';
  src: url('assets/fonts/PhrenSans-Rg.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Phren Sans';
  src: url('assets/fonts/PhrenSans-Md.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Phren Sans';
  src: url('assets/fonts/PhrenSans-Sm.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Surfaces, pulled from DesignSystem.swift. */
  --paper: #FBF8F2;
  --card: #FFFEF9;

  /* Text ink. Warm grays rather than neutral: the paper is a cream, and a
     pure-neutral gray reads faintly cold against it. These carry the same
     undertone, so the type sits in the page instead of on top of it. */
  --ink: #55504A;         /* body copy */
  --ink-strong: #35322D;  /* headings, and the darker step under body */
  --ink-soft: #7A736A;    /* muted captions, nav, footer */
  --ink-faint: #9A9289;   /* bullets, step numbers, de-emphasised labels */
  --line: #E2DDD0;
  /* Pressed/hover state of a filled button, and the tint of the screenshot shadow. */
  --ink-press: #211F1C;

  /* The hero lockup's slate, matching the jini_logo_3_ink_51555A asset. Sits
     outside the ink scale on purpose — it's the logo's colour, not a text step. */
  --brand-slate: #51555A;
  --shadow-rgb: 85, 80, 74;

  --display: 'Gaegu', 'Bradley Hand', cursive;
  --sans: 'Phren Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --max-width: 720px;   /* legal pages */
  --container: 1020px;  /* landing page */
}

/* Brand accent — #495C72, opted into per page.
   Deliberately NOT applied to body copy or headings. This page is a document
   people read at length, and neutral text reads better than tinted text; the
   blue is worth more as punctuation than as the colour of everything. It lands
   on links, buttons, eyebrows and step markers — small, structural, repeated —
   so it signals "brand" and points at the CTAs instead of becoming the page's
   default tone.

   The hero lockup is the one deliberate exception: the mark and the wordmark
   stay slate (#51555A), so the top of the page reads as ink and the blue is
   reserved for the things you can act on. */
.theme-ink {
  --accent: #495C72;        /* brand blue */
  --accent-soft: #54667B;   /* lighter step, for link hover */
  --accent-press: #3B4C60;  /* darker step, for filled-button hover */
}

/* Where the accent is allowed to land. Everything not listed here stays gray. */

/* Links — the blue marks them as interactive, which gray underlines do weakly. */
.theme-ink a { color: var(--accent); }
.theme-ink a:hover { color: var(--accent-soft); }
.theme-ink :focus-visible { outline-color: var(--accent); }

/* Section eyebrows (ABOUT / TERMS / FAQ). Small, repeated, structural — they
   read as brand marking the page's divisions rather than as coloured text. */
.theme-ink .eyebrow { color: var(--accent); }

/* Subheads inside a section: the "why list with us" reasons, the numbered
   feature titles, and the "how it works" steps. Short labels, not prose — the
   blue reads as marking the beat of a list rather than colouring text. The h2s
   above them and the body copy below them stay --ink-strong, so each block
   still runs gray → blue → gray. */
.theme-ink .reasons dt { color: var(--accent); }
.theme-ink .termlist dt { color: var(--accent); }
.theme-ink .feature h3 { color: var(--accent); }
.theme-ink .steps h3 { color: var(--accent); }

/* The "Hi, i'm James!" opener. A short greeting rather than prose — the accent
   marks it as the start of the about copy, the same way it marks a subhead. */
.theme-ink .greeting { color: var(--accent); }

/* Buttons: the primary CTA is the one thing on the page that should pull the
   eye, so it carries the brand colour as a solid fill. */
.theme-ink .btn {
  border-color: var(--accent);
  color: var(--accent);
}

.theme-ink .btn:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--card);
}

.theme-ink .btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--card);
}

.theme-ink .btn--primary:hover {
  background: var(--accent-press);
  border-color: var(--accent-press);
  color: var(--card);
}

/* Numbered step markers — the circles, not the text beside them. */
.theme-ink .steps li::before {
  border-color: var(--accent);
  color: var(--accent);
}

/* The 80/20 split bar, the page's one piece of data viz. */
.theme-ink .split__bar { border-color: var(--accent); }
.theme-ink .split__bar i:first-child { background: var(--accent); }
.theme-ink .split__you { color: var(--accent); }

/* Hero lockup — deliberately NOT the accent. The mark, the wordmark and the rule
   under them are one unit and stay slate, matching the jini_logo_3_ink_51555A
   asset above them. Keeping the blue off the top of the page leaves it meaning
   one thing only: this is something you can click. */
.theme-ink .hero h1 { color: var(--brand-slate); }
.theme-ink .hero__rule { color: var(--brand-slate); }

* { box-sizing: border-box; }

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

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

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

/* Terms, privacy, and artist terms are long documents people read straight
   through. Plain white gives the type maximum contrast and keeps the page from
   competing with the copy; the landing page keeps its cream --paper. */
.page-legal { background: #FFFFFF; }

::selection { background: var(--ink-strong); color: var(--card); }

/* ---------- Type ---------- */

h1, h2, h3, .display {
  font-family: var(--display);
  color: var(--ink-strong);
  font-weight: 700;
  letter-spacing: 0.01em;
}

h1 {
  font-size: clamp(38px, 5.4vw, 56px);
  line-height: 1.04;
  margin: 0 0 18px;
}

h2 {
  font-size: clamp(28px, 4vw, 36px);
  line-height: 1.1;
  margin: 0;
}

h3 {
  font-size: 21px;
  line-height: 1.2;
  margin: 0 0 5px;
}

p, li { margin: 0 0 12px; }
p:last-child, li:last-child { margin-bottom: 0; }
ul { padding-left: 20px; }
strong { color: var(--ink-strong); font-weight: 600; }

a {
  color: var(--ink-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

a:hover { color: var(--ink-soft); }

:focus-visible {
  outline: 2.5px solid var(--ink-strong);
  outline-offset: 3px;
  border-radius: 4px;
}

.eyebrow {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 12px;
}

.lede {
  font-size: clamp(18px, 2vw, 20px);
  line-height: 1.55;
  max-width: 46ch;
}

/* Starts a second block inside one section — enough air to read as its own
   beat, but less than the gap between two full sections. */
.eyebrow--restart { margin-top: clamp(48px, 6vw, 76px); }

.prose { max-width: 62ch; }
.prose p + p { margin-top: 14px; }
h2 + .prose { margin-top: 18px; }
.prose-center { margin-left: auto; margin-right: auto; }

/* The opening hello in the about copy. Carries the same weight as <strong>,
   which is the page's existing emphasis step for body text. */
.greeting { font-weight: 600; }

/* The "Your art, in everyday conversations." heading needs its own gap before
   the drawing + reasons block, so the two don't read as one run of text.
   Tightened on desktop (see the 860px block) — there the drawing sits in its
   own column, so less air is needed than in the stacked mobile layout. */
h2 + .split-drawing { margin-top: clamp(28px, 4vw, 44px); }

/* Stacked reasons under "Why list with us" — heading above, line below. */
.reasons {
  margin: 0;
  max-width: 42ch;
}

.reasons > div + div { margin-top: clamp(17px, 2.2vw, 23px); }

.reasons dt {
  font-family: var(--sans);
  font-size: clamp(18px, 2.1vw, 20px);
  font-weight: 600;
  color: var(--ink-strong);
  line-height: 1.25;
  margin: 0 0 4px;
}

.reasons dd {
  margin: 0;
  font-size: 16px;
  line-height: 1.5;
}

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

.container {
  width: min(var(--container), 100% - 40px);
  margin-inline: auto;
}

/* Same gutters as .container, so every section shares one left edge —
   the column inside is what narrows. */
.container--narrow > * { max-width: 700px; }

.section { padding: clamp(60px, 8vw, 100px) 0; }
.section--tight { padding: clamp(44px, 5vw, 68px) 0; }

/* Alternating band, one shade lighter than the page. */
.band {
  background: var(--card);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.section-head { margin-bottom: clamp(28px, 4vw, 44px); }

/* For heads that sit directly above a hairline-ruled list. */
.section-head--flush { margin-bottom: clamp(10px, 1.5vw, 18px); }

/* Dotted divider, echoes DottedDivider in the app. */
.dotted {
  border: none;
  border-top: 2.25px dotted var(--line);
  margin: 22px 0;
}

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

.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(249, 245, 237, 0.82);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s ease;
}

.topbar.is-stuck { border-bottom-color: var(--line); }

.topbar__inner {
  display: flex;
  align-items: center;
  justify-content: flex-end;   /* nav + CTA sit right; the brand lockup that
                                  used to hold the left edge is gone */
  gap: 20px;
  padding: 11px 0;
}


.topbar__nav {
  display: flex;
  align-items: center;
  gap: 26px;
  font-size: 15px;
}

.topbar__nav a { color: var(--ink-soft); text-decoration: none; }
.topbar__nav a:hover { color: var(--ink-strong); }

@media (max-width: 720px) {
  .topbar__nav { display: none; }
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  padding: 14px 22px;
  border: 1.5px solid var(--ink-strong);
  border-radius: 12px;
  background: transparent;
  color: var(--ink-strong);
  transition: background 0.16s ease, color 0.16s ease, border-color 0.16s ease;
}

.btn:hover {
  background: var(--ink-strong);
  border-color: var(--ink-strong);
  color: var(--card);
}

.btn--primary {
  background: var(--ink-strong);
  border-color: var(--ink-strong);
  color: var(--card);
}

.btn--primary:hover {
  background: var(--ink-press);
  border-color: var(--ink-press);
  color: var(--card);
}

.btn--sm { padding: 9px 15px; font-size: 14.5px; border-radius: 10px; }
.btn--lg { padding: 16px 28px; }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.btn-row--center { justify-content: center; }

@media (max-width: 460px) {
  .btn-row { display: grid; gap: 10px; }
  .btn-row .btn { width: 100%; }
}

/* ---------- App Store icon ---------- */

/* Block, not inline-block: as an inline-block the box picked up baseline slack
   from the line box, so its height differed between the flex .cta-row (desktop)
   and the grid one (<=460px). The hero drawing is positioned against this box,
   so that difference moved the drawing between the two layouts. Sized
   explicitly to the icon, it is the same 52px square in both. */
.store-badge {
  display: block;
  line-height: 0;
  width: var(--badge-size, 52px);
  height: var(--badge-size, 52px);
  flex: none;
}

/* Sized by class rather than by `.store-badge img`, which would also catch the
   hand-drawn ring and label inside the badge and squash them into 52px squares. */
.store-badge__icon {
  height: var(--badge-size, 52px);
  width: var(--badge-size, 52px);
  display: block;
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 13px 16px;
}

.cta-row .btn { padding: 16px 22px; }

/* Keep the badge at its native size, so the secondary CTA shouldn't stretch either. */
@media (max-width: 460px) {
  .cta-row { display: grid; justify-items: center; gap: 14px; }
  .cta-row .btn { width: auto; }
}

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

/* Fills the first screen. `min-height` rather than `height` so the hero can still
   grow past the viewport if the lockup needs the room on a short screen, instead
   of clipping. 100svh (small viewport height) keeps it from overflowing behind
   mobile browser chrome that expands and contracts on scroll; the plain 100vh
   above it is the fallback for browsers without svh.

   The topbar is sticky, so it takes real layout space above this section — its
   height comes off the total, otherwise header + hero would together run past
   one screen and the badge would sit below the fold. ~57px is the measured
   height: 11px padding twice, around a 35px small button. */

/* The lockup is centred in that box, but the extra bottom padding pulls the
   optical centre up a little — a dead-centre lockup reads low, and this leaves
   room under the badge that hints at the section below. */
.hero {
  --topbar-h: 57px;
  min-height: calc(100vh - var(--topbar-h));
  min-height: calc(100svh - var(--topbar-h));
  display: flex;
  align-items: center;
  padding: clamp(40px, 6vw, 72px) 0 clamp(96px, 14vw, 168px);
}

/* The flex child needs the full column width, since the parent is now a flex row. */
.hero__inner {
  text-align: center;
  width: 100%;
}

/* Mark above the wordmark at every width. Stacked reads as a lockup — the mark
   gets the full column and can carry real size, rather than being capped by the
   height of the headline sitting next to it. */
.hero__title {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: center;
  gap: clamp(24px, 2.6vw, 34px);
  margin-bottom: 20px;
}

/* The transparent mark, not the packed app icon — it sits directly on the
   paper, so it keeps its own proportions rather than filling a square. */
.hero__icon {
  flex: none;
  width: clamp(150px, 15vw, 200px);
  height: auto;
  display: block;
}

/* Stacked, the headline has the full column, so it can run larger than it could
   side by side without crowding the mark above it. */
.hero h1 { font-size: clamp(46px, 6.4vw, 72px); margin: 0; }
.hero .lede { margin: 0 auto 32px; }
.hero .cta-row { justify-content: center; }

/* Sits under the mark + wordmark in place of a lede. Sized to roughly the width
   of that pair rather than the full container, so it reads as underlining the
   title instead of dividing the page. A fixed width, deliberately: the rule is a
   piece of punctuation, so it holds one size at every viewport instead of
   tracking vw. max-width keeps it inside the gutters on a very narrow screen. */
.hero__rule {
  /* Temporarily hidden. `visibility` rather than `display: none` so the rule
     keeps holding the 34px gap between the wordmark and the CTA row — flip this
     back to `visible` to bring it back. */
  visibility: hidden;
  display: block;
  width: 280px;
  max-width: 100%;
  height: 6px;
  margin: 0 auto 34px;
  /* Ink comes from the theme block, alongside the wordmark's colour;
     this is the untinted fallback for a page without .theme-ink. */
  color: var(--ink-faint);
  overflow: visible;
}

/* The lockup is stacked at every width, so this only retunes the vw-based sizes
   for a narrower column — the layout itself no longer changes here. The vw
   coefficients are picked to meet the desktop values at 760px, so nothing jumps
   as the breakpoint is crossed. */
@media (max-width: 760px) {
  .hero__title { gap: clamp(24px, 5vw, 36px); }

  /* Holds at the size the desktop rule hands over at 760px, so the mark stays
     the anchor of the lockup as the column narrows rather than tracking vw down
     into a stamp. The 480px block takes over once that crowds the gutters. */
  .hero__icon { width: 150px; }

  .hero h1 { font-size: clamp(46px, 6.4vw, 62px); }
}

/* On a phone the mark shrinks further — the headline is the thing that should
   carry the hero, and a mark much past this starts eating the fold. */
@media (max-width: 480px) {
  .hero__icon { width: min(150px, 40vw); }
  /* No lower bound: "jini stickerbook" is a long string in a display face, and a
     floor here would push it past the gutters on a 320px screen. Capped at 46px
     to meet the value the wider rule hands over at 480px. */
  .hero h1 { font-size: min(12.5vw, 46px); }
}

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

/* The badge stays above the hand-drawn ring and keeps its own hit area.
   (position: relative comes from the .store-badge rule below, which makes it
   the positioning parent for the drawing.) */
.cta-row .store-badge { z-index: 2; }

/* The geometry both hero drawings are placed from. Set here, on the badge's
   parent, so the row can use the same numbers to reserve its own space.

   --art-px is one pixel of the source artwork, in CSS px. The ring and the
   label were exported from a single 2732x2048 canvas, so one shared scale
   reproduces the drawing exactly as it was made; every offset below is a
   measurement off that canvas, multiplied by this.

   --dl-scale shrinks the label only. It is the one knob the phone override
   turns; the ring ignores it.

   The label hangs below the badge, out of flow, so the row also has to reserve
   the room itself or the About section would run underneath it. That reserve is
   derived from the same constants that place the label — its bottom edge sits
   (113.5 + 425 x scale) art-px under the badge centre — less the badge's own
   lower half, plus 4px (10px of air, less the 6px optical nudge below). A
   smaller label on a phone therefore reclaims the space it no longer needs. */
.hero .cta-row {
  --art-px: calc(var(--badge-size, 52px) * 4.35 / 504);
  --dl-scale: 1;
  margin-bottom: calc(
    (113.5 + 425 * var(--dl-scale)) * var(--art-px)
    - var(--badge-size, 52px) / 2 + 4px);
}

/* The accent strokes were drawn to sit off the logo's top-right shoulder, so
   they hang off the mark rather than taking part in the stacked lockup. */
.hero__mark {
  position: relative;
  display: inline-block;
  line-height: 0;
}

.hero__accent {
  position: absolute;
  top: -6%;
  right: -26%;
  width: 28%;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

/* "download here" — a ring drawn to enclose the badge, and an arrow pointing
   up at it from the words below. The ring has to land ON the badge, not near
   it, so both pieces are anchored to the badge itself. */
.store-badge { position: relative; }

.hero__ring,
.hero__download {
  position: absolute;
  /* Origin is the badge's own centre — the badge is these elements'
     positioning parent, so nothing here can drift away from it. */
  top: 50%;
  left: 50%;
  /* Sizes are given explicitly, in absolute px derived from --art-px, so
     nothing depends on the image's load state and no percentage resolves
     against a box whose height isn't known yet. That was the old bug: a
     drawing that landed differently on desktop than on mobile. */
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  z-index: 1;
}

/* The badge is a fixed 52px square at every viewport, so the ring around it is
   a fixed multiple of it too — it never scales with the phone override. */
.hero__ring {
  width: calc(259 * var(--art-px));
  height: calc(251 * var(--art-px));
  /* Pull back by half the ring, so it is the ring's own centre that lands on
     the badge centre. The extra -6px is optical: the ink is heavier along the
     lower arc, so a geometrically centred ring reads as sitting slightly low
     around the icon. */
  transform: translate(
    calc(-129.5 * var(--art-px)),
    calc(-125.5 * var(--art-px) - 6px));
}

/* On the source canvas the arrow's tip is 118.5px left and 113.5px below the
   ring's centre, and sits 73px in from the label's own left edge. Anchoring
   the tip — subtracting that 73px AFTER scaling — means the label grows and
   shrinks about the point of the arrow, so the arrow keeps pointing at the
   same spot under the badge whatever size the label is. */
.hero__download {
  width: calc(504 * var(--art-px) * var(--dl-scale));
  height: calc(425 * var(--art-px) * var(--dl-scale));
  transform: translate(
    calc(-118.5 * var(--art-px) - 73 * var(--art-px) * var(--dl-scale)),
    calc(113.5 * var(--art-px) - 6px));
}

/* On a phone the label at full size dominates the fold — it ends up taller
   than the wordmark it sits under. The ring stays put (it belongs to the
   badge, which doesn't change size), so only the words and arrow come down. */
@media (max-width: 480px) {
  .hero .cta-row { --dl-scale: 0.7; }
}

/* ---------- Screenshot / video frames (hand-drawn) ---------- */

/* The app's own background is --paper, so a screenshot would otherwise
   dissolve into the page — the frame is what gives it an edge. Drawn in the
   same ink as the rest of the page, in place of the hairline rectangle and
   drop shadow that used to do this job: a machined edge around the artwork
   was the one thing on the page that didn't look handmade. */
/* The box is the screenshot itself. The frame hangs outside it, so the ink
   never covers any part of the shot. */
.shot {
  position: relative;
  width: 100%;
  max-width: 290px;
  aspect-ratio: 9 / 19.5;
}

/* Sized so the frame's OPENING lands on the shot's edge and the whole stroke
   sits outside it. In the art, the opening starts 17.5 of 535 units in from
   each edge, so the frame has to be 1.07x the shot and overhang it by 3.5% of
   the shot's width on every side.

   Horizontal and vertical insets are given separately because a percentage
   resolves against the box's width on the sides and its height on the ends —
   1.62% of the height is the same number of pixels as 3.5% of the width on a
   9/19.5 box, so the overhang comes out square. */
.shot::after {
  content: "";
  position: absolute;
  inset: -1.62% -3.5%;
  /* The art is 535x1119 against a 9/19.5 box: a 3% difference in proportion,
     which stretched to fit puts 0.2px of extra weight on the side strokes.
     Cheaper than cropping the screenshots to suit the frame. */
  background: url('assets/drawings/app_border.png') no-repeat center / 100% 100%;
  pointer-events: none;
}

.shot img,
.shot video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Matches the curve of the frame's opening — a radius of 27 units in art the
     frame renders 1.07x the size of this box. Same horizontal/vertical pairing
     as above, so the corner stays circular at any size. */
  border-radius: 5.4% / 2.5%;
}

/* ---------- Feature rows (copy one side, screenshot the other) ---------- */

.features {
  list-style: none;
  margin: 0;
  padding: 0;
}

.feature {
  margin: 0;
  padding: clamp(36px, 5vw, 60px) 0;
  border-top: 1px solid var(--line);
  display: grid;
  gap: clamp(28px, 4vw, 44px);
  align-items: center;
}

.feature:last-child { border-bottom: 1px solid var(--line); }

.feature__num {
  display: block;
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.14em;
  color: var(--ink-faint);
  margin-bottom: 14px;
}

.feature__copy h3 {
  font-size: clamp(24px, 2.8vw, 30px);
  line-height: 1.14;
  margin-bottom: 12px;
}

.feature__copy p {
  font-size: 16px;
  line-height: 1.65;
  max-width: 46ch;
}

/* Width lives on the grid item, so .shot's percentage width has something
   definite to resolve against. */
.feature__media {
  justify-self: center;
  width: 100%;
  max-width: 252px;
}

.feature__media .shot { max-width: none; }

@media (min-width: 820px) {
  /* Copy and screenshot sit next to each other with a fixed gap, and the row's
     spare width is pushed to the OUTSIDE by justify-content rather than left
     in a column between them. Sizing the copy column to max-content alone
     wasn't enough: the paragraph is capped at 46ch by .feature__copy p, so any
     leftover row width still opened up as a gap on whichever side the slack
     landed. */
  .feature {
    grid-template-columns: minmax(0, max-content) minmax(0, 252px);
    column-gap: clamp(76px, 8vw, 116px);
    justify-content: start;
  }

  .feature__copy { grid-column: 1; }
  .feature__media { grid-column: 2; }

  /* Even rows mirror, so the screenshots zig-zag down the page. The pair is
     pushed to the right edge so the screenshots still alternate sides.

     A much wider gap than the normal rows: on a flipped row the doodle hangs
     off the screenshot's RIGHT edge, i.e. straight into the copy column, so
     the gap has to clear the drawing rather than just separate two blocks. */
  .feature--flip {
    grid-template-columns: minmax(0, 252px) minmax(0, max-content);
    column-gap: clamp(124px, 13vw, 200px);
    justify-content: end;
  }

  .feature--flip .feature__media { grid-column: 1; grid-row: 1; }
  .feature--flip .feature__copy { grid-column: 2; grid-row: 1; }
}

/* ---------- Hand-drawn spot illustrations ----------

   Three placement patterns, all built on one base class:
     .drawing              — the image itself, never interactive, never selectable
     .drawing-aside        — sits beside a block on desktop, above it on mobile
     .drawing-mark         — small, rides alongside a section heading
     .feature__doodle      — absolutely positioned against a .shot

   Every drawing is decorative: alt="" so screen readers skip it, and
   aria-hidden on the wrappers that exist only to position one. */

.drawing {
  display: block;
  width: 100%;
  height: auto;
  /* The art is dark ink on transparent; on the light paper it needs no
     treatment, but it must never catch a click meant for the copy below. */
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

/* --- Pattern 1: drawing beside the section heading (about) ---

   The copy keeps its original full width; only the heading row is split, so
   the drawing sits to the right of "Built for artists." and the paragraphs
   below run the same measure they always did.

   Mobile: the drawing drops under the heading and above the copy. */

.head-drawn {
  display: grid;
  align-items: center;
  gap: clamp(10px, 2vw, 18px);
  /* Containing block for the absolutely-positioned drawing on desktop. */
  position: relative;
}

.head-drawn .drawing-aside {
  justify-self: center;
  width: 100%;
  max-width: var(--drawing-w, 210px);
}

@media (min-width: 860px) {
  /* The heading column is sized to its text (max-content) rather than 1fr, so
     the drawing sits immediately beside "Built for artists." instead of being
     pushed to the container's right edge by a stretched column. */
  .head-drawn {
    grid-template-columns: max-content minmax(0, var(--drawing-col, 250px));
    column-gap: clamp(24px, 4vw, 48px);
    justify-content: start;
  }

  /* The eyebrow and h2 stack in the left column, drawing spans both rows. */
  .head-drawn > :not(.drawing-aside) { grid-column: 1; }

  /* About's heading runs the full width of the narrow container, which would
     strand the drawing at the right edge. It keeps the mobile arrangement
     instead: one column, drawing under the heading. Back in flow, so it needs
     its own margins rather than the overhang the other sections rely on. */
  #about .head-drawn { grid-template-columns: minmax(0, 1fr); }

  #about .head-drawn .drawing-aside {
    position: static;
    grid-column: 1;
    grid-row: auto;
    justify-self: start;
    width: var(--drawing-w, 210px);
    margin-top: 6px;
    margin-bottom: 12px;
  }

  /* The drawing is taller than the eyebrow + h2 it sits beside. Left in flow it
     would set the row height and show up as padding above "About" and below the
     h2 — spacing that belongs to the drawing, not to the heading. Taking it out
     of flow removes it from the row's height calculation, so the heading block
     keeps its natural size and the drawing overhangs the copy below instead of
     pushing it down. */
  .head-drawn .drawing-aside {
    grid-column: 2;
    grid-row: 1 / span 2;
    justify-self: var(--drawing-justify, start);
    align-self: center;
    position: absolute;
    width: var(--drawing-w, 210px);
    max-width: none;
    /* Per-section vertical nudge, since the art's own balance point isn't
       always the centre of the heading block it sits beside. Done with
       margin-top rather than a transform (the reveal sets `transform: none`
       on [data-stagger] children once they animate in) and rather than `top`
       (a length there would cancel the align-self centring above). */
    margin-top: var(--drawing-shift, 0);
  }

  /* A small breath under the heading — not the large gap the out-of-flow
     drawing used to force, just enough to separate heading from copy. */
  .head-drawn + .prose { margin-top: clamp(8px, 1vw, 13px); }

  /* Terms: the jar is ~230px against a ~71px heading, so with the tightened
     gap below it crosses into the top of the list. It rides in front of
     everything it reaches — the hairline rules and the term text included —
     so the drawing reads as sitting on top of the page rather than being
     interrupted by it. */
  .head-drawn:has(+ .termlist) .drawing-aside { z-index: 2; }
}

/* --- Pattern 2: drawing left, list right (why list with us, terms) ---

   The section heading stays full-width above; below it the drawing takes the
   left column and the definition list the right.

   Mobile: heading, then drawing, then list — the requested order. */

.split-drawing { display: grid; gap: clamp(18px, 3vw, 28px); }

.split-drawing .drawing-aside {
  justify-self: center;
  width: 100%;
  max-width: var(--drawing-w, 230px);
}

@media (min-width: 860px) {
  .split-drawing {
    grid-template-columns: minmax(0, var(--drawing-col, 300px)) minmax(0, 1fr);
    column-gap: var(--split-gap, clamp(36px, 5vw, 72px));
    align-items: var(--split-align, center);
  }

  .split-drawing .drawing-aside {
    grid-column: 1;
    max-width: none;
  }

  .split-drawing > :not(.drawing-aside) { grid-column: 2; }

  /* In the split the list owns its column, so the standalone measure cap and
     the top margin that spaced it under a heading both come off. */
  .split-drawing .reasons { max-width: none; margin-top: 0; }

  /* A touch less air under the heading than the stacked mobile layout needs. */
  h2 + .split-drawing { margin-top: clamp(20px, 2.4vw, 30px); }
}

/* Mirrored: content left, drawing right (terms). */
@media (min-width: 860px) {
  .split-drawing--right {
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--drawing-col, 300px));
  }

  /* Both children are pinned to row 1. Without that, the drawing comes first
     in source and auto-places into row 1 of its column, pushing the list down
     into row 2 — the drawing ends up stacked above the list instead of beside
     it. Source order stays drawing-first so mobile still reads heading →
     drawing → list. */
  .split-drawing--right .drawing-aside { grid-column: 2; grid-row: 1; }
  .split-drawing--right > :not(.drawing-aside) { grid-column: 1; grid-row: 1; }

  /* The list lost width to the drawing column, so the term labels get a
     narrower gutter to keep the descriptions on sensible line lengths. */
  .split-drawing .termlist > div { grid-template-columns: 180px minmax(0, 1fr); }
  .split-drawing .termlist { margin-top: 0; }
}

/* --- Pattern 3: a mark riding alongside a heading (faq) --- */

.section-head--drawn { display: grid; align-items: center; }

/* The FAQ headline is meant to hold one line beside its drawing; the column
   is narrow, so the heading is allowed to overflow it rather than wrap. */
@media (min-width: 860px) {
  .section-head--nowrap h2 { white-space: nowrap; }
}

.section-head--drawn .drawing-mark {
  justify-self: center;
  width: 100%;
  max-width: var(--mark-w, 260px);
  margin-top: clamp(16px, 3vw, 24px);
}

@media (min-width: 860px) {
  .section-head--drawn {
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--mark-col, 300px));
    column-gap: clamp(28px, 4vw, 56px);
  }

  .section-head--drawn > :not(.drawing-mark) { grid-column: 1; }

  .section-head--drawn .drawing-mark {
    grid-column: 2;
    grid-row: 1 / span 2;
    justify-self: var(--mark-justify, center);
    /* Size and position are separate knobs. The mark's column (--mark-col) sets
       where it starts; without a cap of its own the image would simply fill
       that column, so widening the column to pull the drawing closer to the
       heading would also enlarge it. --mark-max caps the drawing independently,
       leaving --mark-col free to act as pure positioning. Defaults to none, so
       heads that don't set it behave as before. */
    max-width: var(--mark-max, none);
    /* The mark centers across the eyebrow + headline rows, which leaves it
       hanging below the headline. --mark-shift lifts it back into line.
       This has to be margin rather than a transform: the scroll-reveal sets
       `transform: none` on landing, which would wipe out a translate and drop
       the mark back down at the end of its animation. */
    margin-top: calc(-1 * var(--mark-shift, 0px));
  }
}

/* Mobile: the scissors sit under the section heading and above the steps, so
   the reading order is heading → drawing → steps. Centered in the column via
   the auto side margins. */
.steps-doodle {
  display: block;
  margin: clamp(18px, 2.6vw, 28px) auto clamp(24px, 3.4vw, 36px);
  width: 100%;
  max-width: clamp(320px, 42vw, 420px);
  /* Same reasoning as the desktop rule below — a large drawing needs more
     travel than the copy around it to read as moving at all. */
  --rev-y: 40px;
  --rev-dur: 0.85s;
  /* The blades and the dotted line are drawn a few degrees off level, so the
     artwork reads as slanted when laid out flat. This counter-rotation sets it
     back upright, and is applied in both orientations. */
  --doodle-tilt: -0.5deg;
}

/* The reveal drives `transform`, which is the same property carrying the tilt,
   so the two are composed here rather than left to the base .reveal rule —
   otherwise the drawing would animate to `transform: none` and land slanted.
   The translate goes first so it stays in screen axes. */
.steps-doodle.reveal {
  transform: translateY(var(--rev-y, 14px)) rotate(var(--doodle-tilt));
}

.steps-doodle.reveal.is-in {
  transform: translateY(0) rotate(var(--doodle-tilt));
}

/* Desktop: the scissors sit to the LEFT of the steps, in their own column.

   This is a real two-column grid rather than the absolutely-positioned pin the
   right-hand version used. Pinning worked there because the 700px content cap
   already left the right side of the container empty — the drawing dropped
   into space nothing else wanted. There is no such free space on the left, so
   the steps have to give up width for the drawing to sit beside them, and a
   grid is the honest way to express that. */
/* 1000px, matching the old right-hand placement: below this the two columns
   leave the copy too narrow, so the drawing stays stacked under the heading. */
@media (min-width: 1000px) {
  /* Opts OUT of the parent's 700px child cap so the wrapper spans the full
     container and both columns have room; the steps get their own cap from the
     grid track instead. */
  .container--narrow > .steps-doodle-wrap { max-width: none; }

  /* The drawing's column is sized to the scissors' rotated WIDTH (--doodle-size
     is the upright drawing's height, i.e. the unrotated long edge). Rotation
     does not change an element's box, so an img laid out at its full unrotated
     width would leave ~200px of dead space either side of the upright artwork.
     Instead the img's box is laid out NARROW — at the rotated width — and
     scaled back up to --doodle-size by the transform. Box and artwork then
     match, so there is no dead space and nothing overflows the container. */
  .steps-doodle-wrap {
    display: grid;
    grid-template-columns:
      calc(var(--doodle-size, 265px) / 3.43) minmax(0, 1fr);
    column-gap: var(--doodle-gap, clamp(24px, 3vw, 48px));
    align-items: center;
  }

  /* Source order is drawing-then-steps, which is also the column order, so
     neither child needs an explicit placement. */
  .steps-doodle {
    width: calc(var(--doodle-size, 265px) / 3.43);
    max-width: none;
    justify-self: center;
    margin: 0;
    /* Rotated so the blades point up rather than right — the column is tall and
       narrow, which suits the upright orientation. The quarter turn carries the
       same --doodle-tilt correction as the flat version. The scale compensates
       for the narrow layout box above: 3.43 (the drawing's aspect ratio) brings
       it back to --doodle-size on screen. */
    transform: rotate(calc(-90deg + var(--doodle-tilt))) scale(3.43);
  }

  /* The scroll reveal drives `transform`, which is the same property holding
     the rotation above — left alone it would animate to `transform: none` and
     drop the scissors flat and unscaled at the end of the reveal. So the
     reveal's offset is composed with the rotation here instead.

     The translate goes BEFORE the rotation so it stays in screen axes: written
     after, it would be rotated too, and a translateY would slide the scissors
     sideways rather than up. Transforms apply right-to-left, so the drawing is
     rotated and scaled first, then moved down the screen by --rev-travel and
     eased back to 0. */
  .steps-doodle.reveal {
    /* Travels further and slower than the steps beside it: it is a large
       standalone drawing, and at the copy's 22px the motion barely registers
       against its size. Closer to the showcase's 38px/0.85s, which is the
       page's setting for imagery rather than text. */
    --rev-travel: 40px;
    --rev-dur: 0.85s;
    transform: translateY(var(--rev-travel, 14px))
      rotate(calc(-90deg + var(--doodle-tilt))) scale(3.43);
  }

  .steps-doodle.reveal.is-in {
    transform: translateY(0) rotate(calc(-90deg + var(--doodle-tilt)))
      scale(3.43);
  }
}

/* --- Pattern 3: doodles overlapping the app screenshots --- */

/* Establishes the box the doodles position against. */
.feature__media { position: relative; }

.feature__doodle {
  position: absolute;
  width: var(--doodle-w, 40%);
  z-index: 2;
}

/* The screenshots are a fixed 252px at every width, so these percentages
   resolve to the same physical size on desktop and mobile alike — no
   per-breakpoint resizing needed. */

/* Paper plane, flying in over the top-right corner of screenshot 01. */
.feature__doodle--plane {
  --doodle-w: 174%;
  top: calc(-11% + 12px);
  right: calc(-50.6% + 2px);
}

/* Pointing hand, aimed at the sticker drawer in 02. Anchored bottom-right, so
   the pixel nudges push it down past the frame's bottom and out past its right
   edge. */
.feature__doodle--hand {
  --doodle-w: 84%;
  bottom: calc(22% - 30px);
  right: calc(-44% - 20px);
}

/* Small character peeking out from behind the left edge of screenshot 03.
   The width is 30% scaled by 217/201: the art was redrawn with the raised hand
   further out, which widened the file without moving anything else. Sizing to
   the new width keeps the ink at the size it was drawn, and since the piece is
   anchored by its left and bottom edges — the two the redraw left untouched —
   the character stays put and only the hand reaches further right. */
.feature__doodle--peek {
  --doodle-w: 32.39%;
  bottom: 16%;
  left: calc(-27% - 5px);
}

/* The drawings hang outside their media box — the plane's right edge sits
   ~126px past it — and the box ends flush with the container, so that overhang
   spills into the page margin. Above ~1272px the margin is wide enough on its
   own. Below that, the row is pulled in from the container's edge by exactly
   the shortfall, which buys the overhang its room without moving the drawing
   relative to the screenshot it annotates.

   Padding on the row rather than a negative margin on the drawing: the drawing
   is absolutely positioned against .feature__media, so shifting the media box
   moves screenshot and doodle together and the composition is preserved.

   126px is the plane's overhang (50.6% of the 252px media box, less the 2px
   nudge). It is the widest of the two that reach into the page margin — the
   peek needs 74px — so sizing to the plane covers both. The hand hangs 131px
   off its frame but its row is flipped, so that overhang goes inward, into the
   gap beside the copy. */
@media (min-width: 820px) {
  /* The screenshot sits at the row's right edge and the plane reaches ~126px
     past it, so the row is padded by that much: the media column moves left
     by the overhang and the drawing ends flush with the row instead of
     hanging outside it. Padding on the row (not a negative margin on the
     drawing) keeps screenshot and doodle moving together, since the doodle is
     positioned against .feature__media.

     A flat value rather than one derived from the viewport: the copy column is
     max-content, so the row's own edge is not a fixed distance from the page
     edge and a computed shortfall under-corrected in the 830-950px band. */
  .feature:not(.feature--flip) { padding-right: 126px; }

  /* Flipped rows put the screenshot on the left and the hand overhangs to its
     right — into the gap beside the copy, not the page margin — so the row
     needs no extra room. */
}

/* ---------- Mobile tuning for the drawings ----------

   Single-column territory: every drawing sits in the flow between its heading
   and the content below, so the adjustments here are all spacing and nudges.
   Scoped to <=859px, one below the point where the two-column drawing layouts
   engage, so none of it can reach the desktop composition. */
@media (max-width: 859px) {
  /* 1. Tighten ABOUT -> "Built for artists." */
  #about .head-drawn { gap: 4px; }

  /* 2. A little more air either side of the about-me drawing. */
  #about .head-drawn .drawing-aside {
    margin-top: 14px;
    margin-bottom: 18px;
  }

  /* 3. Separation between each screenshot and the copy above it. Row 1 needs
        the most: its plane hangs above the phone frame (top: -11%), so the gap
        has to clear the drawing rather than the screenshot. Rows 2 and 3 have
        their drawings low on the frame, so they need less. */
  .feature__media { margin-top: 26px; }
  .feature--flip .feature__media,
  .feature:nth-child(3) .feature__media { margin-top: 14px; }

  /* 4 & 5. See the single-column block below — those two live at a tighter
     breakpoint than the rest of this one. */

  /* 6. Scissors: slightly smaller, slightly more room beneath. */
  .steps-doodle {
    max-width: clamp(290px, 38vw, 380px);
    margin-bottom: clamp(32px, 4.2vw, 44px);
  }

  /* 7. A touch more air either side of the FAQ drawing. */
  .section-head--drawn .drawing-mark {
    margin-top: clamp(22px, 3.8vw, 30px);
    margin-bottom: clamp(8px, 1.6vw, 14px);
  }

  /* 8. The jar's ink sits right of its own centre, so centring the file leaves
        it looking pushed right under the heading. Nudged back with `left`, not
        a transform — the reveal clears transforms to `none` on arrival. */
  #deal .head-drawn .drawing-aside {
    position: relative;
    left: -18px;
  }
}

/* 4 & 5 of the tuning above. The screenshot centres in the column; these shift
   the whole media box (screenshot AND its doodle together) off centre, so the
   three stacked shots don't sit in a dead-straight line. Rows 1 and 2 move
   left, row 3 moves right.

   Offset with `left` rather than a transform: the scroll reveal animates
   `transform` and clears it to `none` on arrival, so a transform here would be
   overwritten — the box would slide sideways to centre as it came in instead of
   rising straight up like row 1, and the offset would be lost.

   Capped at 819px, not 859px like the rest of the tuning: the feature rows
   become two columns at 820px, where each shot has its own column and nudging
   it off centre only changes its distance from the copy beside it. */
@media (max-width: 819px) {
  .feature:first-child .feature__media { left: -15px; }
  .feature--flip .feature__media { left: -26px; }
  .feature:nth-child(3) .feature__media { left: 16px; }
}

/* The drawings keep their full desktop size and offsets at EVERY width — no
   mobile scaling. On a 390px phone the screenshot is a fixed 252px, leaving
   only ~69px of margin per side against the plane's 126px overhang, so a
   drawing that fits inside the viewport is necessarily a smaller drawing. The
   deliberate choice here is the other way round: keep the composition and let
   the artwork bleed off the page edge.

   The section clips instead of scrolling. `overflow-x: clip` rather than
   `hidden` because hidden would make the section a scroll container, which
   also breaks `position: sticky` on the topbar; clip just cuts the overflow.
   The x-only value leaves vertical overflow alone, so nothing interferes with
   the reveal transforms. */
#proof {
  overflow-x: clip;
}

/* Phones scale the whole unit — screenshot AND its drawing — down a little.
   Shrinking .feature__media is all it takes: the doodles are sized and offset
   in percentages OF that box, so they follow it exactly and the composition is
   preserved at the smaller size. The artwork still bleeds off the page edge,
   by design; this just takes the edge off how much. */
@media (max-width: 559px) {
  .feature__media { max-width: 224px; }
}

/* The pointing hand is the one drawing that gets shrunk further, and only from
   the width where it starts to run off the page. With the 224px media box above,
   the hand's right edge lands exactly on the viewport edge at 410px, so below
   that it overflows: on a 390px phone by about 10px, and by more the narrower
   the screen. 0.87 clears that with room to spare on a 390px phone and leaves a
   slight bleed on the narrowest ones. (Above 410px the drawing keeps its full
   size — there is margin enough for it.)

   Scaled about the fingertip: the whole point of the drawing is that it points
   at the sticker drawer in the screenshot, so that is the one part of it that
   must not move. 20% 38% is where the tip sits in the image file, measured from
   its top-left. */
@media (max-width: 409px) {
  .feature__doodle--hand {
    transform: scale(0.87);
    transform-origin: 20% 38%;
  }
}

/* ---------- The deal ---------- */

.deal { display: grid; gap: clamp(30px, 4vw, 40px); align-items: center; }

@media (min-width: 840px) {
  .deal { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); column-gap: clamp(40px, 6vw, 72px); }
}

.split__figures {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-family: var(--display);
  font-weight: 700;
  line-height: 1;
}

.split__you { font-size: clamp(62px, 9vw, 92px); color: var(--ink-strong); }
.split__slash { font-size: clamp(28px, 4.5vw, 40px); color: var(--line); }
.split__us { font-size: clamp(32px, 5.5vw, 48px); color: var(--ink-faint); }

.split__bar {
  display: flex;
  height: 12px;
  max-width: 340px;
  border: 1.5px solid var(--ink-strong);
  border-radius: 999px;
  overflow: hidden;
  margin: 22px 0 12px;
}

.split__bar i { display: block; }
.split__bar i:first-child { flex: 80; background: var(--ink); }
.split__bar i:last-child {
  flex: 20;
  background: repeating-linear-gradient(-45deg, var(--line) 0 4px, var(--card) 4px 8px);
}

.split__legend {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  max-width: 340px;
  font-size: 14px;
  color: var(--ink-soft);
}

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

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

.termlist { margin: clamp(40px, 5vw, 60px) 0 0; }

/* Following a drawn heading, the heading block already carries its own bottom
   margin, so the list's default top margin stacks into a gap far larger than
   either was meant to be. */
.head-drawn + .termlist { margin-top: clamp(20px, 2.5vw, 30px); }

.termlist > div {
  display: grid;
  gap: 2px 32px;
  padding: 15px 0;
  border-top: 1px solid var(--line);
}

.termlist > div:last-child { border-bottom: 1px solid var(--line); }

@media (min-width: 620px) {
  .termlist > div { grid-template-columns: 210px minmax(0, 1fr); align-items: baseline; }
}

.termlist dt {
  font-family: var(--display);
  font-size: 20px;
  font-weight: 700;
  color: var(--ink-strong);
  line-height: 1.25;
}

.termlist dd { margin: 0; font-size: 15.5px; line-height: 1.55; }

/* ---------- Steps ---------- */

.steps {
  list-style: none;
  counter-reset: step;
  padding: 0;
  margin: 0;
}

.steps li {
  counter-increment: step;
  position: relative;
  padding: 0 0 26px 50px;
  margin: 0;
}

.steps li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: -1px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1.5px solid var(--ink-strong);
  font-family: var(--display);
  font-size: 18px;
  font-weight: 700;
  color: var(--ink-strong);
  display: flex;
  align-items: center;
  justify-content: center;
}

.steps li::after {
  content: '';
  position: absolute;
  left: 15px;
  top: 38px;
  bottom: 4px;
  border-left: 2.25px dotted var(--line);
}

.steps li:last-child { padding-bottom: 0; }
.steps li:last-child::after { display: none; }

.steps p { font-size: 15.5px; }

/* Plain-spoken aside under a section. */
.note {
  margin: clamp(30px, 4vw, 44px) 0 0;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* ---------- FAQ ---------- */

.faq details { border-bottom: 1px solid var(--line); }
.faq details:first-of-type { border-top: 1px solid var(--line); }

.faq summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  padding: 18px 2px;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: 20px;
  font-weight: 700;
  color: var(--ink-strong);
  line-height: 1.25;
}

.faq summary::-webkit-details-marker { display: none; }

.faq summary::after {
  content: '';
  flex: none;
  width: 12px;
  height: 12px;
  margin-top: 7px;
  background:
    linear-gradient(var(--ink-soft), var(--ink-soft)) center/12px 1.5px no-repeat,
    linear-gradient(var(--ink-soft), var(--ink-soft)) center/1.5px 12px no-repeat;
  transition: transform 0.2s ease;
}

.faq details[open] summary::after {
  background: linear-gradient(var(--ink-soft), var(--ink-soft)) center/12px 1.5px no-repeat;
  transform: rotate(180deg);
}

.faq summary:hover { color: var(--ink); }

.faq__body {
  padding: 0 38px 20px 2px;
  font-size: 15.5px;
  line-height: 1.65;
}

/* ---------- Apply ---------- */

.apply { text-align: center; }
.apply h2 { margin-bottom: 14px; }

.apply__note {
  max-width: 46ch;
  margin: 0 auto 26px;
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--ink-soft);
  text-wrap: balance;
}

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

.footer {
  border-top: 1px solid var(--line);
  padding: 32px 0 40px;
  font-size: 14.5px;
  color: var(--ink-soft);
}

.footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  align-items: center;
  justify-content: space-between;
}

.footer p { margin: 0; }
.footer a { color: var(--ink-soft); }
.footer a:hover { color: var(--ink-strong); }
.footer nav { display: flex; flex-wrap: wrap; gap: 8px 18px; }

.footer__legal {
  margin-top: 20px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-faint);
}

/* ---------- Scroll reveal ----------
   .reveal animates as one block. [data-stagger] animates its direct children
   in sequence; the step between them is set per group in the page script.
   Distance, duration and direction are tunable through the --rev-* properties,
   which inherit down into a section. */

.reveal,
[data-stagger] > * {
  opacity: 0;
  transform: translate3d(var(--rev-x, 0px), var(--rev-y, 14px), 0);
  transition:
    opacity var(--rev-dur, 0.6s) cubic-bezier(0.22, 1, 0.36, 1),
    transform var(--rev-dur, 0.6s) cubic-bezier(0.22, 1, 0.36, 1);
}

.reveal.is-in,
[data-stagger] > .is-in { opacity: 1; transform: none; }

/* The screenshot showcase travels furthest — it's the one section where the
   motion is part of the point. */
#proof {
  --rev-y: 38px;
  --rev-dur: 0.85s;
}

/* The text sections sit between that and the quiet hero default. */
#how,
#deal,
#faq,
#apply {
  --rev-y: 22px;
  --rev-dur: 0.7s;
}

/* Screenshots come in sideways, from the outer edge of their own column. */
@media (min-width: 820px) {
  .feature__media { --rev-x: 52px; --rev-y: 0px; }
  .feature--flip .feature__media { --rev-x: -52px; }
}

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

@keyframes rise-in {
  from { opacity: 0; transform: translateY(14px); }
}

@keyframes fade-in {
  from { opacity: 0; }
}

@media (prefers-reduced-motion: no-preference) {
  .hero__icon,
  .hero__accent,
  .hero h1,
  .hero__rule,
  .hero .cta-row {
    animation: rise-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) backwards;
  }

  .hero__icon { animation-delay: 0.06s; }
  /* Just behind the mark it hangs off, so the strokes read as landing on the
     logo rather than arriving with it. */
  .hero__accent { animation-delay: 0.14s; }
  .hero h1 { animation-delay: 0.16s; }
  .hero__rule { animation-delay: 0.26s; }
  .hero .cta-row { animation-delay: 0.34s; }

  .faq details[open] .faq__body { animation: fade-in 0.3s ease; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal,
  [data-stagger] > * { opacity: 1; transform: none; transition: none; }
  .btn { transition: none; }
}

/* ---------- Legal pages (privacy.html, terms.html) ---------- */

.wrap {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 48px 18px 80px;
}

.wordmark {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  /* The mark is cropped tight to its artwork, so this gap is the whole optical
     gap; the old logo carried its own built-in whitespace on top of it. */
  gap: 4px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 30px;
  line-height: 1.05;
  letter-spacing: 0.08em;
  text-decoration: none;
  color: var(--ink-strong);
}

.wordmark img {
  width: 160px;
  max-width: 55vw;
  height: auto;
  display: block;
}

header.site { text-align: center; padding: 16px 0 44px; }

.wrap h2 { font-size: 25px; margin: 38px 0 8px; }
.wrap h3 { font-size: 20px; margin: 26px 0 4px; }

.meta { font-size: 15px; color: var(--ink-soft); margin-bottom: 30px; }
.center { text-align: center; }

footer.site {
  text-align: center;
  font-size: 14.5px;
  color: var(--ink-soft);
  padding: 40px 0 8px;
}

footer.site a { color: var(--ink-soft); }
