@charset "UTF-8";
/* ============================================================================
   MARLUNE — SHARED DESIGN SYSTEM
   Plain static site. No build step. Every page links this file directly.

   Load order in <head>:
     <link rel="preconnect" href="https://fonts.googleapis.com">
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400..800;1,9..144,400..800&family=Plus+Jakarta+Sans:ital,wght@0,400..800;1,400..700&display=swap">
     <link rel="stylesheet" href="/assets/site.css">
   And before </body>:
     <script src="/assets/site.js" defer></script>

   CONTRAST: every value below was measured, not guessed. See DESIGN-SYSTEM.md
   for the full ratio table. Two rules matter most:
     - #F0803A and #D9722E are DECORATIVE ONLY. Max 3.28:1 on white. Never text.
     - On the brightest gradient stops (apricot #FFD3A8) the brief's #6E625A
       (4.25:1) and #9E4C14 (4.33:1) both fail AA. The semantic tokens
       --ink-muted and --accent-text therefore resolve to slightly deeper
       values that clear AA on EVERY surface in the system.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------ */
:root {
  /* Marlune ships one theme: a bright, sunny light theme. Declaring it here
     stops the UA auto-darkening form controls, scrollbars and canvases. */
  color-scheme: light;

  /* -- Raw palette (the brief's named colours, kept verbatim for reference) */
  --canvas:        #FFFCF8;
  --white:         #FFFFFF;

  --lilac:         #E9E0F7;
  --periwinkle:    #DCE4F7;
  --blush:         #FCE3E7;
  --peach:         #FFE2C9;
  --apricot:       #FFD3A8;
  --cream:         #FFF7ED;

  --ember-bright:  #F0803A;  /* DECORATIVE ONLY — 2.67:1 on white */
  --ember-mid:     #D9722E;  /* DECORATIVE ONLY — 3.28:1 on white */
  --ember-deep:    #9E4C14;  /* text on white/canvas/cream only (6.00:1) */

  --plum-bright:   #8B5478;
  --plum-deep:     #6E3F5F;
  --plum-soft:     #F6E9F3;

  --green:         #5C8A6A;  /* DECORATIVE ONLY — 3.96:1 on white */
  --green-deep:    #3F6B4E;
  --green-soft:    #E4F0E6;

  /* -- Gradient CANVAS stops.
        These are separate from the raw palette above on purpose. The raw
        palette is fixed (the phone mockup is a picture of the app and must
        stay bright in every scheme). These stops are scheme-aware, because
        a canvas painted in bright pastels under cream ink is unreadable.
        Always build .canvas-* backgrounds from these, never from --lilac
        and friends directly.

        Each stop has a matching *-0 zero-alpha twin. ALWAYS fade a radial
        stop to its own twin, never to the `transparent` keyword: bare
        `transparent` is rgba(0,0,0,0), so sRGB interpolation drags every
        midpoint toward grey and the whole canvas reads dusty. */
  --grad-lilac:      #E9E0F7;  --grad-lilac-0:      rgba(233, 224, 247, 0);
  --grad-periwinkle: #DCE4F7;  --grad-periwinkle-0: rgba(220, 228, 247, 0);
  --grad-blush:      #FCE3E7;  --grad-blush-0:      rgba(252, 227, 231, 0);
  --grad-peach:      #FFE2C9;  --grad-peach-0:      rgba(255, 226, 201, 0);
  --grad-apricot:    #FFD3A8;  --grad-apricot-0:    rgba(255, 211, 168, 0);
  --grad-cream:      #FFF7ED;
  --grad-base:       #FFFCF8;

  /* -- Semantic surfaces */
  --surface:            var(--canvas);
  --surface-card:       #FFFFFF;
  --surface-raised:     #FFFFFF;
  --surface-sunken:     #FFF7ED;
  --surface-contrast:   #2E2521;   /* the ONE dark band per page. Lightened from
                                      #241C19 to lift whole-page luminance on
                                      index (the site's darkest page) while
                                      still clearing AA for --ink-on-dark. */
  --surface-glass:      rgba(255, 255, 255, 0.66);
  --surface-glass-edge: rgba(255, 255, 255, 0.80);

  /* -- Semantic ink. AA or better on every surface token above. */
  --ink:            #241C19;  /* 16.36:1 on canvas, 12.06:1 on apricot  */
  --ink-secondary:  #4A403A;  /*  9.84:1 on canvas,  7.26:1 on apricot  */
  --ink-muted:      #5F544C;  /*  7.18:1 on canvas,  5.29:1 on apricot  */
  --ink-on-dark:    #F7F1EC;  /* 16.56:1 on --surface-contrast          */
  --ink-on-dark-mu: #B4A69E;  /*  7.85:1 on --surface-contrast          */

  /* -- Semantic accents for TEXT (all clear AA on every light surface) */
  --accent-text:    #8A4210;  /*  7.16:1 on canvas,  5.28:1 on apricot  */
  --plum-text:      #6E3F5F;  /*  8.09:1 on canvas,  5.96:1 on apricot  */
  --green-text:     #386146;  /*  6.92:1 on canvas,  5.10:1 on apricot  */

  /* -- Borders + focus */
  --line:          rgba(36, 28, 25, 0.10);
  --line-strong:   rgba(36, 28, 25, 0.18);
  --focus:         #241C19;   /* 16.36:1 on canvas, 12.06:1 on apricot */
  --focus-inner:   #FFFFFF;

  /* -- Warm shadows. Tinted with ember, never neutral grey. */
  --shadow-xs: 0 1px 2px rgba(122, 58, 15, 0.06);
  --shadow-sm: 0 2px 8px rgba(122, 58, 15, 0.07), 0 1px 2px rgba(122, 58, 15, 0.05);
  --shadow-md: 0 8px 24px rgba(122, 58, 15, 0.09), 0 2px 6px rgba(122, 58, 15, 0.05);
  --shadow-lg: 0 20px 48px rgba(122, 58, 15, 0.12), 0 4px 12px rgba(122, 58, 15, 0.06);
  --shadow-xl: 0 32px 80px rgba(122, 58, 15, 0.16), 0 8px 24px rgba(122, 58, 15, 0.07);

  /* -- Radii */
  --r-xs: 8px;
  --r-sm: 12px;
  --r-md: 18px;
  --r-lg: 26px;
  --r-xl: 36px;
  --r-pill: 999px;

  /* -- Type families */
  --font-display: "Fraunces", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --font-body: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system,
               "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* -- Fluid type scale. 320px floor, 1440px ceiling. */
  /* Capped at 6rem so the hero headline and the phone mockup below it share
     one screen on a standard laptop. Bigger than this pushed the payoff
     element under the fold at 1440 x 900. */
  --t-display-1: clamp(2.65rem, 1.30rem + 6.75vw, 6.00rem);
  --t-display-2: clamp(2.40rem, 1.35rem + 5.25vw, 5.90rem);
  --t-display-3: clamp(2.00rem, 1.32rem + 3.40vw, 4.25rem);
  --t-h2:        clamp(1.75rem, 1.28rem + 2.35vw, 3.30rem);
  --t-h3:        clamp(1.35rem, 1.14rem + 1.05vw, 2.05rem);
  --t-h4:        clamp(1.15rem, 1.05rem + 0.50vw, 1.50rem);
  --t-lead:      clamp(1.10rem, 1.00rem + 0.50vw, 1.45rem);
  --t-body:      clamp(1.00rem, 0.96rem + 0.20vw, 1.13rem);
  --t-sm:        0.94rem;
  --t-xs:        0.82rem;
  --t-eyebrow:   0.78rem;

  /* -- Spacing */
  --s-1: 0.25rem;  --s-2: 0.5rem;   --s-3: 0.75rem;  --s-4: 1rem;
  --s-5: 1.5rem;   --s-6: 2rem;     --s-7: 3rem;     --s-8: 4rem;
  --s-9: 6rem;     --s-10: 8rem;

  /* One rhythm token for every section on every page. Resolves to --s-7 at
     the 320 floor and --s-9 at the 1440 ceiling, so section padding always
     lands on the spacing scale instead of on an arbitrary clamp value. */
  --section-y: clamp(3rem, 2rem + 4vw, 6rem);
  /* Heroes get one shared token too. Before this, hero band heights ranged
     from 375px (privacy) to 1902px (pricing) across the seven pages. */
  --hero-y:    clamp(2.5rem, 1.6rem + 3vw, 4.5rem);
  --gutter:    clamp(1.15rem, 0.55rem + 3vw, 2.75rem);

  /* -- ARC. The vertical radius of every tinted section's curved edge, and
        the length of its alpha fade. Marlune has no hard horizontal edges:
        a tinted band is a shallow lens, not a rectangle. Never raise this
        above 6rem or the curve reads as a novelty shape rather than light. */
  --arc: clamp(2rem, 1rem + 2.5vw, 4.5rem);

  /* -- Layout widths */
  --w-prose: 68ch;
  --w-narrow: 46rem;
  --w-page:  75rem;
  --w-wide:  86rem;

  /* -- Header. The masthead is flush to the top of the viewport and is ONE
        row at every width, so --header-block is a single value. It is read
        by scroll-padding-top and by every sticky offset on the site, so any
        change to the bar's height must be mirrored here. */
  --header-top:   0rem;
  --header-block: 4.25rem;
  --sticky-offset: calc(var(--header-block) + var(--s-5));

  /* -- Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft: cubic-bezier(0.33, 0.9, 0.35, 1);
  --dur-fast: 160ms;
  --dur: 280ms;
  --dur-slow: 620ms;

  /* -- Grain: a bounded, tileable feTurbulence texture as a data URI.
        Applied per-section via .grain, never as a page-height fixed layer.

        PERFORMANCE: the tint is baked into the SVG (feColorMatrix maps the
        noise luminance straight into the ALPHA channel, giving black specks
        on transparent) so the overlay composites with plain alpha and needs
        NO mix-blend-mode. A blend mode here forces the whole section into a
        non-accelerated compositing pass and pins the main thread on scroll,
        which measurably froze the page. Do not reintroduce one. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
  /* White specks, for dark surfaces. */
  --grain-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
  /* Mean alpha of the noise is ~0.5, so the effective veil is roughly half
     this number. Keep it low: grain should be felt, not seen. */
  --grain-opacity: 0.085;
}

/* -- Dark mode. Deliberately warm, never blue-black. Ratios measured. */


/* ---------------------------------------------------------------------------
   2. RESET + BASE
   ------------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Tracks the REAL masthead box rather than a hand-tuned number. The old
     fixed 7rem was measured against the desktop nav and parked anchor
     targets 14px underneath the wrapped mobile nav. */
  scroll-padding-top: calc(var(--header-top) + var(--header-block) + var(--s-4));
}

/* ---------------------------------------------------------------------------
   THE MOONRISE — one document-level light source
   --------------------------------------------------------------------------
   Every hard horizontal seam this site ever had came from painting a wash
   onto a SECTION box: the box has edges, the gradient stops were still
   saturated when it hit them, and the sticky header sat above the box in
   plain cream. There is no box here. This layer is position:fixed, so it is
   viewport sized, seamless at every scroll position, and there is nothing
   above or below it to cut against.

   The warm stops are centred BELOW the viewport (118% and 96%), so only
   their bright upper edge lands on screen: warmth rising from under the
   fold. Lavender is demoted to a single cool counterweight off the top
   right corner. Ember leads, cool seasons. Every fade goes to its own
   zero-alpha twin, never to the `transparent` keyword.

   LIGHT ONLY. There is no dark theme and no prefers-color-scheme block
   anywhere in this file. Do not add one.
   ------------------------------------------------------------------------ */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background-color: var(--grad-base);
  background-image:
    radial-gradient(120% 90% at 50% 118%, var(--grad-apricot) 0%, var(--grad-apricot) 18%, var(--grad-apricot-0) 72%),
    radial-gradient(90% 70% at 82% 96%,   var(--grad-peach) 0%,   var(--grad-peach) 14%,   var(--grad-peach-0) 68%),
    radial-gradient(70% 55% at 14% 104%,  var(--grad-blush) 0%,   var(--grad-blush-0) 66%),
    radial-gradient(85% 60% at 96% -6%,   var(--grad-lilac) 0%,   var(--grad-lilac-0) 70%),
    linear-gradient(180deg, var(--grad-cream) 0%, var(--grad-base) 46%, var(--grad-cream) 100%);
}

body {
  margin: 0;
  /* overflow-x hidden is a safety net, not the fix. Components must not
     overflow on their own at 320 / 375 / 768 / 1440. */
  overflow-x: hidden;
  background-color: var(--grad-base);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.65;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img, svg, video, canvas { display: block; max-width: 100%; }
img, video { height: auto; }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; }

button, input, select, textarea { font: inherit; color: inherit; }

a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.18em; }

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: var(--s-7) 0;
}

/* -- Focus. Always visible, never removed. Double ring so it reads on both
      light gradients and the dark contrast band. */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
.btn:focus-visible,
.nav__link:focus-visible,
.pill:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px var(--focus-inner);
}

::selection { background: var(--peach); color: #241C19; }

/* -- Skip link */
.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -120%);
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--ink);
  color: var(--canvas);
  border-radius: 0 0 var(--r-md) var(--r-md);
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--dur) var(--ease-out);
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

/* -- Screen-reader only */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------
   3. TYPOGRAPHY
   ------------------------------------------------------------------------ */
.display-1, .display-2, .display-3,
h1, h2, h3 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.028em;
  text-wrap: balance;
  color: var(--ink);
}

/* Large Fraunces wants LOWER weight and tighter tracking than text sizes.
   Heavy Fraunces at display size is exactly what made this page read as a
   generic template; the face is an optical-size serif and should be allowed
   to behave like one. `opsz` is driven by font-optical-sizing above, so only
   SOFT is pinned here. */
.display-1, .display-2, .display-3, h1 {
  font-weight: 520;
  font-variation-settings: "SOFT" 0;
}
.display-1 { font-size: var(--t-display-1); line-height: 0.98; letter-spacing: -0.032em; }
.display-2 { font-size: var(--t-display-2); line-height: 1.02; letter-spacing: -0.028em; }
.display-3 { font-size: var(--t-display-3); line-height: 1.06; letter-spacing: -0.024em; }

h1 { font-size: var(--t-display-2); line-height: 1.04; letter-spacing: -0.026em; }
h2 { font-size: var(--t-h2); line-height: 1.08; }
h3 { font-size: var(--t-h3); line-height: 1.18; letter-spacing: -0.018em; }

h4, .h4 {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--t-h4);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.012em;
  color: var(--ink);
}

.lead {
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--ink-secondary);
  text-wrap: pretty;
}

.body-sm { font-size: var(--t-sm); line-height: 1.6; }
.body-xs { font-size: var(--t-xs); line-height: 1.55; }

.muted { color: var(--ink-muted); }
.secondary { color: var(--ink-secondary); }

/* Accent text tokens. Never use --ember-bright / --ember-mid for text. */
.accent { color: var(--accent-text); }
.accent-plum { color: var(--plum-text); }
.accent-green { color: var(--green-text); }

/* Italic Fraunces, the wordmark voice. Use sparingly, for emphasis words. */
.serif-italic {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 600;
}

/* Gradient display text. Decorative fill is fine here because the ember
   gradient is only ever the FILL of very large text; a solid AA fallback
   colour is set first so unsupported browsers still read correctly. */
.text-gradient {
  color: var(--accent-text);
  background-image: linear-gradient(96deg, var(--ember-deep), var(--plum-deep));
  -webkit-background-clip: text;
  background-clip: text;
}
@supports (-webkit-text-fill-color: transparent) {
  .text-gradient { -webkit-text-fill-color: transparent; }
}


/* -- Eyebrow label. The house editorial device: a short solid ember rule,
      then uppercase Jakarta, aligned to the same left rule as the heading
      below it. One treatment everywhere, so left alignment reads as a
      decision rather than an accident. The rule is DECORATIVE (ember at
      3.28:1); the label text is --accent-text at 7.16:1 and carries the
      meaning on its own. */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.65em;
  margin: 0 0 var(--s-4);
  font-family: var(--font-body);
  font-size: var(--t-eyebrow);
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent-text);
}
.eyebrow::before {
  content: "";
  flex: 0 0 auto;
  width: 1.75rem;
  height: 2px;
  background: var(--ember-mid);
}
.eyebrow--plum::before  { background: var(--plum-bright); }
.eyebrow--green::before { background: var(--green); }


/* Inside a centred head the rule would dangle off the left of the label. */
.section__head--center .eyebrow,
.center .eyebrow { justify-content: center; }
.eyebrow--plum { color: var(--plum-text); }
.eyebrow--green { color: var(--green-text); }

/* -- Prose block for legal / article pages */
.prose { max-width: var(--w-prose); }
.prose > * + * { margin-top: 1.1em; }
.prose h2 { margin-top: 2em; }
.prose h3 { margin-top: 1.6em; }
.prose ul, .prose ol { padding-left: 1.3em; }
.prose li { margin-top: 0.45em; }
.prose li::marker { color: var(--accent-text); }
.prose a { color: var(--accent-text); text-decoration: underline; }
.prose strong { font-weight: 700; color: var(--ink); }

/* ---------------------------------------------------------------------------
   4. LAYOUT
   ------------------------------------------------------------------------ */
.wrap {
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--narrow { max-width: var(--w-narrow); }
.wrap--wide   { max-width: var(--w-wide); }
.wrap--full   { max-width: none; }

.section { position: relative; padding-block: var(--section-y); }
.section--tight { padding-block: clamp(2.25rem, 1.5rem + 3.5vw, 4.5rem); }
.section--flush-top { padding-top: 0; }
.section--flush-bottom { padding-bottom: 0; }

/* Section heads range LEFT by default and sit on the same rule as the body
   below them. Centring is still available but it is now a deliberate
   emphasis used at most once per page, not the default reach. */
.section__head {
  max-width: 38rem;
  margin-inline: 0;
  margin-bottom: clamp(2rem, 1.4rem + 2.6vw, 3.75rem);
}
.section__head--center { margin-inline: auto; text-align: center; max-width: 44rem; }
.section__head > .lead { margin-top: var(--s-4); }

/* ---------------------------------------------------------------------------
   PAGE HERO — asymmetric editorial
   --------------------------------------------------------------------------
   One shared hero on all seven pages: copy ranged left at a 26rem measure
   with a ragged right edge, eyebrow rule, headline, lead and actions all
   aligned to one visible left rule. On index and features a device or a
   visual sits right, off the centre axis. Under 860px it becomes a single
   column and any rotation drops to zero.
   ------------------------------------------------------------------------ */
/* --hero-min stops the two legal heroes rendering as a 375px washed strip
   while index's ran to 1317px. One hero shape on all seven pages. */
.page-hero {
  padding-block: var(--hero-y) var(--section-y);
  min-height: var(--hero-min, clamp(16rem, 28vh, 24rem));
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* A TINTED hero still needs the fade allowance in its padding, or the first
   line of the eyebrow sits inside the arc's alpha ramp. */
.page-hero.canvas-soft,
.page-hero.canvas-warm,
.page-hero.canvas-cool,
.page-hero.canvas-sunken,
.page-hero.canvas-contrast {
  padding-block: calc(var(--hero-y) + var(--arc) * 0.8) calc(var(--section-y) + var(--arc) * 0.8);
}

.hero__inner {
  display: grid;
  gap: clamp(2rem, 1.2rem + 3vw, 4rem);
  align-items: center;
}
@media (min-width: 861px) {
  .hero__inner--split { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
}

/* Five of the seven heroes carry copy only, with no art and no grid to hold
   the right side. Against the 1200px page wrap that reserved 548px of bare
   canvas at 1440. The wrap itself is capped instead, so the band is sized to
   its content rather than leaving a hole. NOT re-centred: left-ranged is the
   house rhythm and the thing that separates this from the reference site. */
.page-hero--text > .wrap {
  max-width: 52rem;
  /* Capping the width alone re-CENTRES the wrap, which pushes the hero copy
     184px right of the left rail every other section sits on and puts a jog
     in the page. The start margin therefore reproduces the page wrap's own
     centring offset, so the hero is narrower but starts on exactly the same
     rail. Below --w-page the offset resolves to 0 and nothing moves. */
  margin-inline-start: max(0px, calc((100% - var(--w-page)) / 2));
  margin-inline-end: auto;
}

.hero__copy { max-width: 32rem; margin-inline: 0; text-align: left; }
.hero__copy--wide { max-width: 38rem; }
.hero__sub { max-width: 27rem; margin-inline: 0; }
.hero__copy--wide .hero__sub { max-width: 32rem; }

/* --t-display-1 tops out at 6rem, which was tuned for a 56rem CENTRED
   block. Dropped into a 32rem editorial column it sets six lines of two
   words each. The hero headline is therefore capped separately: this is a
   measure problem, not a scale problem, so the global token is untouched. */
.hero__copy h1,
.hero__copy .display-1,
.hero__copy .display-2 { font-size: clamp(2.5rem, 1.55rem + 4.4vw, 4.75rem); }
.hero__copy--wide h1,
.hero__copy--wide .display-1,
.hero__copy--wide .display-2 { font-size: clamp(2.5rem, 1.5rem + 5vw, 5.5rem); }

/* ---------------------------------------------------------------------------
   PULL QUOTE — one per page, never a testimonial
   --------------------------------------------------------------------------
   Marlune is unreleased, so this can only ever carry a product statement or
   a reassurance line in Marlune's own voice. No quotation marks, no
   attribution, no name, no rating. Never use it for anything that could be
   read as a review.
   ------------------------------------------------------------------------ */
.pull-quote {
  max-width: 30rem;
  margin-inline: 0;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.5rem, 1.1rem + 1.9vw, 2.6rem);
  line-height: 1.18;
  letter-spacing: -0.022em;
  color: var(--ink);
  text-wrap: pretty;
}
.pull-quote::before {
  content: "";
  display: block;
  width: 3rem;
  height: 2px;
  margin-bottom: var(--s-5);
  background: var(--ember-mid);
}

/* ---------------------------------------------------------------------------
   PHASE TRACK — wayfinding, not ornament
   --------------------------------------------------------------------------
   A row of arcs waxing from thin crescent to full, marking an ORDERED
   sequence. It is a legend for a progression, so it carries information.
   ONE instance per page maximum. Never as bullets, never as decoration,
   and never a literal moon icon: the name is felt in the geometry and is
   never explained. aria-hidden in markup; the steps themselves are the
   accessible content.
   ------------------------------------------------------------------------ */
.phase-track { display: flex; align-items: center; gap: 0.5rem; }
.phase-track > i {
  display: block;
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  border: 1.5px solid var(--ember-mid);
  opacity: 0.65;
  background: linear-gradient(90deg, transparent 50%, var(--ember-mid) 50%);
}
.phase-track > i:nth-child(1) { background: none; }
.phase-track > i:nth-child(2) { background-image: linear-gradient(90deg, transparent 76%, var(--ember-mid) 76%); }
.phase-track > i:nth-child(3) { background-image: linear-gradient(90deg, transparent 60%, var(--ember-mid) 60%); }
.phase-track > i:nth-child(4) { background-image: linear-gradient(90deg, transparent 50%, var(--ember-mid) 50%); }
.phase-track > i:nth-child(5) { background-image: linear-gradient(90deg, transparent 28%, var(--ember-mid) 28%); }
.phase-track > i:nth-child(6) { background: var(--ember-mid); opacity: 0.8; }

.stack > * + * { margin-top: var(--s-4); }
.stack-lg > * + * { margin-top: var(--s-6); }
.stack-sm > * + * { margin-top: var(--s-2); }

.center { text-align: center; }
.center-x { margin-inline: auto; }

.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
}
.cluster--center { justify-content: center; }

/* NOTE ON NAMING: these are auto-fit grids, so the number in the class is a
   MAXIMUM, not a guarantee. .grid-2 used to floor at 20rem, which fits three
   times in the 1112px page wrap, so every four-item ".grid-2" rendered as a
   3 + 1 orphan row. The floors below are chosen so the resolved column count
   actually matches the name at 1024 and 1440.
   Before adding a set, check `items % resolvedCols` at 375/768/1024/1440. */
.grid { display: grid; gap: clamp(1rem, 0.7rem + 1.4vw, 1.85rem); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 16.5rem), 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }

/* A THREE-item .grid-3 resolves to two tracks between 620 and 999px and
   renders a half-width orphan on row two. Add .grid-3--balance to any
   three-item set: the third card spans the full row instead, so the block
   still reads as a finished shape. Three narrow columns were tried first
   and are far too tight at 620. */
@media (min-width: 620px) and (max-width: 999px) {
  .grid-3--balance > :last-child { grid-column: 1 / -1; }
  .grid-4--balance { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Split: copy one side, visual the other. Stacks under 900px. */
.split {
  display: grid;
  gap: clamp(2rem, 1.2rem + 4vw, 4.5rem);
  align-items: center;
}
@media (min-width: 900px) {
  .split { grid-template-columns: 1fr 1fr; }
  .split--copy-wide { grid-template-columns: 1.15fr 0.85fr; }
  .split--visual-wide { grid-template-columns: 0.85fr 1.15fr; }
  .split--reverse > :first-child { order: 2; }
}

/* ---------------------------------------------------------------------------
   5. GRADIENT CANVAS + GRAIN
   ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
   HOW TINTED SECTIONS WORK NOW
   --------------------------------------------------------------------------
   A tinted section NEVER paints a rectangle. Its tint lives on a ::before
   layer that is:
     1. clipped to a shallow lens with `border-radius: 50% / var(--arc)`,
        so the top and bottom edges are wide arcs, not lines; and
     2. alpha-masked to nothing over the first and last --arc of its height,
        so even the tangent point at the centre of the arc fades instead of
        cutting.
   Between the two there is no adjacent-row colour delta anywhere on the
   page above about 3/255. The seam is not patched, it is structurally
   impossible.

   Section padding adds 0.8 x --arc top and bottom so no content ever sits
   inside the fade zone, which is what keeps text contrast honest.

   .canvas-gradient is now a NO-OP. The page wash is the fixed body::before
   moonrise layer; heroes no longer own a background at all. The class is
   kept so the existing markup keeps validating, and so `.canvas-gradient
   .btn-note` and friends still resolve.
   ------------------------------------------------------------------------ */
.canvas-gradient {
  position: relative;
  isolation: isolate;
  background: none;
}

.canvas-soft,
.canvas-warm,
.canvas-cool,
.canvas-sunken,
.canvas-contrast {
  position: relative;
  isolation: isolate;
  background: none;
  /* --arc-fade is deliberately LONGER than --arc. The border-radius clips
     the tint away at the corners; the mask fades it out vertically. If the
     two are the same length they fight: at the far left and right margins
     the corner ellipse bottoms out at exactly y = --arc, where a mask of
     the same length has already reached full opacity, so the tint appears
     at full strength on a single row. That is a seam, reintroduced at the
     margins by geometry. Making the fade 2.4x the radius means the tint is
     only ~40% opaque where the clip lands, so the flank is soft too. */
  --arc-fade: calc(var(--arc) * 2.4);
  padding-block: calc(var(--section-y) + var(--arc) * 0.8);
}
.canvas-soft::before,
.canvas-warm::before,
.canvas-cool::before,
.canvas-sunken::before,
.canvas-contrast::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* Horizontal radius 50%, vertical radius --arc: a wide shallow dome on
     the top edge and a mirrored one on the bottom. Roughly a 2 to 4 degree
     rise at 1440. */
  border-radius: 50% / var(--arc);
  -webkit-mask-image: linear-gradient(180deg,
      rgba(0, 0, 0, 0) 0,
      #000 var(--arc-fade),
      #000 calc(100% - var(--arc-fade)),
      rgba(0, 0, 0, 0) 100%);
          mask-image: linear-gradient(180deg,
      rgba(0, 0, 0, 0) 0,
      #000 var(--arc-fade),
      #000 calc(100% - var(--arc-fade)),
      rgba(0, 0, 0, 0) 100%);
}
/* The dark band is the one place a long fade COSTS something: light text on
   a half-faded dark band loses contrast. Its fade is shorter and its
   padding is correspondingly larger, so every line of type sits on the
   solid part of the band and nothing near the edge is ever read against a
   half-strength surface. */
.canvas-contrast {
  --arc-fade: calc(var(--arc) * 1.5);
  padding-block: calc(var(--section-y) + var(--arc) * 1.6);
}

/* A section flush against the footer or the top of the document has nothing
   to arc into on that side. */
.canvas-flush-bottom::before { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }

/* Soft: the cool counterweight, used for mid-page reading sections. */
.canvas-soft::before {
  background-color: var(--grad-cream);
  background-image:
    radial-gradient(100% 80% at 84% 0%,   var(--grad-lilac) 0%, var(--grad-lilac-0) 62%),
    radial-gradient(100% 80% at 12% 100%, var(--grad-peach) 0%, var(--grad-peach-0) 64%);
}
/* Warm: ember light, the house tint. */
.canvas-warm::before {
  background-color: var(--grad-cream);
  background-image:
    radial-gradient(110% 90% at 50% 108%, var(--grad-apricot) 0%, var(--grad-apricot-0) 64%),
    radial-gradient(80% 70% at 8% 0%,     var(--grad-peach) 0%,   var(--grad-peach-0) 62%);
}
/* Cool: the one lavender-led band, kept for the two legal page titles. */
.canvas-cool::before {
  background-color: var(--grad-base);
  background-image:
    radial-gradient(95% 80% at 88% 0%,  var(--grad-lilac) 0%,      var(--grad-lilac-0) 62%),
    radial-gradient(95% 80% at 10% 100%, var(--grad-periwinkle) 0%, var(--grad-periwinkle-0) 62%);
}
/* Sunken: plain warm paper, no radials. */
.canvas-sunken::before { background-color: var(--surface-sunken); }

/* Plain sections show the moonrise straight through. They must NOT paint a
   fill of their own: an opaque cream section over a fixed wash is exactly
   the pasted-rectangle problem this rewrite removes. */
.canvas-plain { background: none; position: relative; }

/* THE one dark band. Use at most once per page, never for a whole page.
   It arcs like every other tinted section, so the page still has no hard
   horizontal edge, but it does not fade: text sits on it. */
.canvas-contrast::before {
  background-color: var(--surface-contrast);
  background-image:
    /* Alphas are capped at 0.26 / 0.22 on purpose. Higher values lighten the
       band enough that .muted and .accent fall below AA where the two
       radials overlap. Measured worst-case blend is #613B31. */
    radial-gradient(90% 70% at 15% 0%,   rgba(139, 84, 120, 0.26) 0%, rgba(139, 84, 120, 0) 62%),
    radial-gradient(90% 70% at 88% 100%, rgba(217, 114, 46, 0.22) 0%, rgba(217, 114, 46, 0) 60%);
}
.canvas-contrast { color: #F7F1EC; }
.canvas-contrast h1, .canvas-contrast h2, .canvas-contrast h3,
.canvas-contrast h4, .canvas-contrast .h4 { color: #F7F1EC; }
.canvas-contrast .lead,
.canvas-contrast .secondary { color: #D8CCC5; }
/* #C4B8B0 not #B4A69E: on the blended band the darker grey is only 4.08:1. */
.canvas-contrast .muted { color: #C4B8B0; }
.canvas-contrast .eyebrow { color: #FFB07A; }
.canvas-contrast .accent { color: #FFB07A; }
.canvas-contrast .accent-plum { color: #E3A8CE; }
.canvas-contrast .accent-green { color: #9FD0AE; }
.canvas-contrast { --line: rgba(247,241,236,0.14); --line-strong: rgba(247,241,236,0.26); }
.canvas-contrast :focus-visible { outline-color: #FFB07A; }


/* -- GRAIN OVERLAY -----------------------------------------------------------
   Bounded to its own section box. `contain: paint` keeps the texture from
   becoming a full-page composited layer, and pointer-events:none keeps it
   inert. Add .grain to any .canvas-* element. */
.grain { position: relative; }
.grain::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: var(--grain);
  background-repeat: repeat;
  background-size: 160px 160px;
  opacity: var(--grain-opacity);
  /* layout+paint containment only. `strict` adds SIZE containment, which
     fights the inset:0 sizing this overlay depends on. */
  contain: layout paint style;
}

/* Grain must follow the arc, or a faint rectangular ghost shows in the two
   corners the tint has curved away from. */
.canvas-soft.grain::after,
.canvas-warm.grain::after,
.canvas-cool.grain::after,
.canvas-sunken.grain::after,
.canvas-contrast.grain::after {
  border-radius: 50% / var(--arc);
  -webkit-mask-image: linear-gradient(180deg,
      rgba(0, 0, 0, 0) 0, #000 var(--arc-fade), #000 calc(100% - var(--arc-fade)), rgba(0, 0, 0, 0) 100%);
          mask-image: linear-gradient(180deg,
      rgba(0, 0, 0, 0) 0, #000 var(--arc-fade), #000 calc(100% - var(--arc-fade)), rgba(0, 0, 0, 0) 100%);
}
.canvas-flush-bottom.grain::after { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }

/* The dark contrast band is dark in LIGHT mode, so it wants light specks. */
.canvas-contrast.grain::after { background-image: var(--grain-light); }

.grain--strong { --grain-opacity: 0.20; }
.grain--soft   { --grain-opacity: 0.07; }

/* Anything inside a grain section must sit above the texture. */
.grain > * { position: relative; z-index: 1; }

/* DECORATIVE BLOBS ARE RETIRED.
   Drifting pastel blobs behind a hero are the reference site's ambient
   decoration, and ours were also a real defect: the ember blob measured
   144px past the right viewport edge at 1440 and was sliced flat by the
   hero's `overflow: clip`, landing exactly on the bottom seam and making it
   more conspicuous. The light now comes from the canvas (body::before),
   not from floating shapes. The rule is kept as a hard off switch so any
   blob left in old markup cannot reintroduce the overflow. */
.blob { display: none !important; }

/* ---------------------------------------------------------------------------
   6. HEADER — flush masthead
   --------------------------------------------------------------------------
   Deliberately NOT a floating glassmorphic pill. A pill that hovers over a
   pastel wash is the single most recognisable borrowed element in this kind
   of layout, and on mobile it wrapped to two rows and became a 116px slab
   sitting over a flat cream strip. This is a magazine masthead: full width,
   flush to the top, on the canvas rather than above it, one row at every
   width, and invisible at rest apart from the wordmark and the links.

   HEIGHT IS A CONTRACT. The bar is --header-block tall at every breakpoint,
   and scroll-padding-top plus every sticky offset on the site are derived
   from that token. If you change the padding here, change the token.
   ------------------------------------------------------------------------ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  padding-inline: var(--gutter);
  background-color: rgba(255, 252, 248, 0);
  border-bottom: 1px solid transparent;
  transition: background-color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}
/* .is-stuck is added by site.js once the page scrolls past the header.
   A hairline warm rule and a barely-there cream tint, nothing more. No
   shadow, ever: the bar sits ON the paper, it does not float above it. */
/* OPAQUE, never translucent, and NO backdrop-filter. A translucent bar
   samples whatever is beneath it: over the one dark band it composited to a
   muddy grey-taupe slab (0.72*255 + 0.28*36 = 194) that terminated in a
   hard full-width horizontal cut. That was the owner's original complaint
   reintroduced at greater magnitude. Opaque paper cannot do that. */
.site-header.is-stuck {
  background-color: #FFFCF8;
  border-bottom-color: transparent;
}
/* A cream bar is still a hard edge when the DARK band runs beneath it, so
   while the band is under the header the bar adopts the band's own colour
   and light ink. The masthead then reads as part of the band: no seam at
   all, and the link contrast rises instead of falling. Set by site.js. */
.site-header.is-stuck.is-over-contrast {
  background-color: var(--surface-contrast);
  border-bottom-color: transparent;
}
.site-header.is-over-contrast .brand { color: var(--ink-on-dark); }
.site-header.is-over-contrast .nav__link { color: var(--ink-on-dark-mu); }
.site-header.is-over-contrast .nav__link:hover {
  color: var(--ink-on-dark);
  box-shadow: inset 0 -2px 0 rgba(247, 241, 236, 0.4);
}
.site-header.is-over-contrast .nav__link[aria-current="page"] {
  color: var(--ink-on-dark);
  box-shadow: inset 0 -2px 0 #FFB07A;
}
.site-header.is-over-contrast .btn--primary { background: #F7F1EC; color: #241C19; }
.site-header.is-over-contrast :focus-visible { outline-color: #FFB07A; }
/* Soft lower terminus so even the cream state fades into the page rather
   than ruling a line across it. */
.site-header.is-stuck::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 100%;
  height: var(--s-5);
  pointer-events: none;
  background: linear-gradient(to bottom, #FFFCF8, rgba(255, 252, 248, 0));
}
.site-header.is-stuck.is-over-contrast::after {
  background: linear-gradient(to bottom,
    var(--surface-contrast), rgba(46, 37, 33, 0));
}

.nav {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  width: 100%;
  max-width: var(--w-page);
  min-height: var(--header-block);
  margin-inline: auto;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}

/* -- Wordmark */
.brand {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  gap: 0.55rem;
  flex: 0 0 auto;
  text-decoration: none;
  color: var(--ink);
}
.brand__mark { width: 1.75rem; height: 1.75rem; flex: 0 0 auto; }
.brand__name {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 600;
  font-size: 1.32rem;
  letter-spacing: -0.02em;
  line-height: 1;
}

/* -- Links. Ranged RIGHT against the CTA, not centred: masthead, not pill.
      Always visible at every width, never behind a hamburger. */
.nav__links {
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-end;
  align-items: center;
  gap: 0.1rem;
  flex: 1 1 auto;
  min-width: 0;
  list-style: none;
}
.nav__link {
  /* min-height 44px: WCAG 2.5.8 target size, and this audience is 40 to 58. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.45rem 0.7rem;
  border-radius: var(--r-xs);
  font-size: 0.94rem;
  font-weight: 600;
  color: var(--ink-secondary);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.nav__link:hover { color: var(--ink); box-shadow: inset 0 -2px 0 var(--line-strong); }
/* The current page is marked with an ember underline, not a white pill.
   The rule is decorative (3.28:1) and never the only signal: aria-current
   carries the meaning, and the ink colour darkens too. */
.nav__link[aria-current="page"] {
  color: var(--ink);
  box-shadow: inset 0 -2px 0 var(--ember-mid);
}

/* -- Right side CTA */
.nav__cta { flex: 0 0 auto; margin-left: var(--s-2); }

/* -- The old "More links" overflow disclosure has been REMOVED.
      It held Privacy and Terms only, it shipped aria-expanded="true" in the
      HTML against a display:none panel (so the no-JS state was a lie), and
      it did not earn a control in a masthead this small. Both links live in
      the footer of every page, which is now the only path to them.
      site.js tolerates the button being absent.

   -- Small screens. ONE row at every width, so --header-block stays true.
      Below 560px the wordmark drops to the flame mark alone and the CTA
      shortens, which buys back enough room that the links never wrap. */
@media (max-width: 900px) {
  .nav { gap: var(--s-3); }
  .nav__link { padding: 0.45rem 0.5rem; font-size: 0.9rem; }
}
@media (max-width: 700px) {
  .nav__link { padding: 0.45rem 0.38rem; font-size: 0.85rem; }
  .nav__cta { margin-left: var(--s-1); }
  .site-header .btn--sm { padding: 0.55em 0.85em; font-size: 0.85rem; }
}
/* Below 560px the header CTA is dropped. Pricing is already the second
   primary link, one tap away and never hidden, so nothing becomes
   unreachable. This is what keeps the bar to ONE row down to 320px. */
@media (max-width: 560px) {
  /* Visually hidden, NOT display:none. The adjacent flame SVG is
     aria-hidden, so removing this from the accessibility tree left the
     header and footer home links with no accessible name at all: a WCAG
     Level A failure (2.4.4, 4.1.2) on all seven pages at mobile widths. */
  .brand__name {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  /* Scoped to .site-header so it outranks `.btn { display: inline-flex }`,
     which is declared later in this file and otherwise wins the cascade. */
  .site-header .nav__cta { display: none; }
  .nav__link { padding: 0.45rem 0.42rem; font-size: 0.88rem; }
}
@media (max-width: 400px) {
  .nav__link { padding: 0.45rem 0.28rem; font-size: 0.82rem; }
}
@media (max-width: 340px) {
  .nav__link { padding: 0.45rem 0.2rem; font-size: 0.78rem; }
}

/* ---------------------------------------------------------------------------
   7. BUTTONS
   ------------------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.82em 1.5em;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

/* Primary: dark pill. White on #241C19 = 16.73:1. */
.btn--primary {
  background: #241C19;
  color: #FFFCF8;
  box-shadow: var(--shadow-md);
}
.btn--primary:hover { background: #3A2D28; box-shadow: var(--shadow-lg); }

/* Secondary: glass pill. Ink on translucent white over any gradient stop
   is at worst 12.06:1 (over apricot). */
.btn--secondary {
  background: rgba(255, 255, 255, 0.72);
  border-color: var(--surface-glass-edge);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .btn--secondary {
    -webkit-backdrop-filter: blur(14px) saturate(1.5);
    backdrop-filter: blur(14px) saturate(1.5);
  }
}
.btn--secondary:hover { background: rgba(255, 255, 255, 0.95); box-shadow: var(--shadow-md); }

/* Ember solid. Uses the DEEP ember so white text clears AA (7.16:1). */
.btn--ember {
  background: var(--accent-text);
  color: #FFFFFF;
  box-shadow: var(--shadow-md);
}
.btn--ember:hover { background: #7A3A0F; box-shadow: var(--shadow-lg); }

/* Ghost / text button */
.btn--ghost {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn--ghost:hover { background: rgba(255, 255, 255, 0.6); border-color: var(--ink); }

/* On the dark contrast band, invert primary so it stays visible. */
.canvas-contrast .btn--primary { background: #F7F1EC; color: #241C19; }
.canvas-contrast .btn--primary:hover { background: #FFFFFF; }
.canvas-contrast .btn--secondary {
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.30);
  color: #F7F1EC;
}
.canvas-contrast .btn--secondary:hover { background: rgba(255, 255, 255, 0.18); }
.canvas-contrast .btn--ghost { border-color: rgba(255,255,255,0.32); color: #F7F1EC; }


.btn--lg { padding: 1em 1.9em; font-size: var(--t-lead); }
.btn--sm { padding: 0.6em 1.1em; font-size: var(--t-sm); }

/* Stacked mobile CTAs share one width. Two buttons sitting directly above
   one another at 213px and 165px read as a ragged, off-axis pair. */
@media (max-width: 520px) {
  .cluster > .btn { flex: 1 1 100%; }
  .cluster--center { justify-content: stretch; }
}
/* Header CTA is a small button but still a primary target. */
.site-header .btn--sm { min-height: 44px; }
.btn--block { display: flex; width: 100%; }

/* Sub-label under a CTA cluster, e.g. "7 day free trial. Cancel anytime." */
.btn-note {
  margin-top: var(--s-3);
  font-size: var(--t-sm);
  color: var(--ink-muted);
}
/* On the dark contrast band, and on any gradient section where a blurred blob
   can darken the backdrop, the muted token falls under AA. Reuse the values
   already vetted for .muted on those same surfaces. */
.canvas-contrast .btn-note { color: #C4B8B0; }
.canvas-gradient .btn-note { color: var(--ink-secondary); }

/* ---------------------------------------------------------------------------
   8. PILLS + BADGES
   ------------------------------------------------------------------------ */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.42em 0.9em;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.7);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--ink-secondary);
  text-decoration: none;
  white-space: nowrap;
}
.pill--ember { background: var(--peach); border-color: rgba(154, 76, 20, 0.20); color: var(--accent-text); }
.pill--plum  { background: var(--plum-soft); border-color: rgba(110, 63, 95, 0.20); color: var(--plum-text); }
.pill--green { background: var(--green-soft); border-color: rgba(63, 107, 78, 0.20); color: var(--green-text); }
.pill--solid { background: #241C19; border-color: #241C19; color: #FFFCF8; }

/* Small status dot. Decorative colour is fine; never the only signal. */
.pill__dot { width: 0.5em; height: 0.5em; border-radius: 50%; background: currentColor; flex: 0 0 auto; }



/* ---------------------------------------------------------------------------
   9. CARDS
   ------------------------------------------------------------------------ */
/* PAPER, not glass. Separation comes from a hairline warm rule and a warm
   cream tint, not from elevation. The old glossy translucent card with a
   drop shadow is the reference site's surface language; this one reads as
   a sheet of warm paper laid on the canvas. Grain stays: grain on paper is
   the whole point. */
.card {
  position: relative;
  padding: clamp(1.25rem, 1rem + 1.1vw, 2rem);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--grad-cream) 58%, #FFFFFF);
  box-shadow: 0 1px 2px rgba(36, 28, 25, 0.04);
  transition: transform var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}
/* Fallback for engines without color-mix. Declared first-wins order matters:
   the @supports block re-applies the mix so it always wins where supported. */
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .card { background: #FFFBF4; }
}
.card > * + * { margin-top: var(--s-3); }

.card--lift:hover {
  transform: translateY(-3px);
  border-color: var(--line-strong);
  box-shadow: var(--shadow-sm);
}
.card--glass {
  background: rgba(255, 255, 255, 0.62);
  border-color: var(--surface-glass-edge);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card--glass { -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); }
}
.card--flat { box-shadow: none; }
.card--pad-lg { padding: clamp(1.6rem, 1.2rem + 2vw, 3rem); }
.card--tint-ember { background: linear-gradient(160deg, var(--cream), var(--peach)); border-color: rgba(154,76,20,0.14); }
.card--tint-plum  { background: linear-gradient(160deg, #FFFFFF, var(--plum-soft)); border-color: rgba(110,63,95,0.14); }
.card--tint-green { background: linear-gradient(160deg, #FFFFFF, var(--green-soft)); border-color: rgba(63,107,78,0.14); }
.card--tint-cool  { background: linear-gradient(160deg, #FFFFFF, var(--periwinkle)); border-color: rgba(60,80,140,0.12); }


/* Card icon chip */
.card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.85rem;
  height: 2.85rem;
  border-radius: var(--r-md);
  background: linear-gradient(150deg, var(--ember-bright), var(--ember-mid));
  color: #FFFFFF;
  box-shadow: var(--shadow-sm);
}
.card__icon svg { width: 1.5rem; height: 1.5rem; }
.card__icon--plum  { background: linear-gradient(150deg, var(--plum-bright), var(--plum-deep)); }
.card__icon--green { background: linear-gradient(150deg, var(--green), var(--green-deep)); }
.card__icon--cool  { background: linear-gradient(150deg, #8FA6E0, #5E76B8); }

/* balance / pretty are applied at the COMPONENT level, not sprinkled as
   utilities, so no card title can ship with a one-word last line by
   omission. Same for every lead and every heading in the base styles. */
.card__title {
  font-size: var(--t-h4);
  font-weight: 700;
  letter-spacing: -0.012em;
  color: var(--ink);
  text-wrap: balance;
}
.card__body { color: var(--ink-secondary); text-wrap: pretty; }

/* Numbered step card */
.card__step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.3rem;
  height: 2.3rem;
  border-radius: 50%;
  border: 1px solid rgba(154, 76, 20, 0.22);
  background: var(--peach);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--accent-text);
}


/* ---------------------------------------------------------------------------
   10. ACCORDION (FAQ)
   ------------------------------------------------------------------------ */
.accordion { border-top: 1px solid var(--line); }

.accordion__item { border-bottom: 1px solid var(--line); }

.accordion__trigger {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  width: 100%;
  padding: clamp(1rem, 0.85rem + 0.6vw, 1.5rem) 0;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: var(--t-h4);
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -0.012em;
  text-align: left;
  color: var(--ink);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out);
}
.accordion__trigger:hover { color: var(--accent-text); }

.accordion__icon {
  position: relative;
  flex: 0 0 auto;
  width: 1.4rem;
  height: 1.4rem;
  margin-top: 0.15em;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  transition: background-color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}
.accordion__icon::before,
.accordion__icon::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.7rem;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transform: translate(-50%, -50%);
  transition: transform var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out);
}
.accordion__icon::after { transform: translate(-50%, -50%) rotate(90deg); }
.accordion__trigger[aria-expanded="true"] .accordion__icon { background: var(--peach); border-color: rgba(154,76,20,0.3); color: #241C19; }

.accordion__trigger[aria-expanded="true"] .accordion__icon::after { transform: translate(-50%, -50%) rotate(0deg); opacity: 0; }

/* Closed state uses [hidden], so content is genuinely removed from the a11y
   tree and the tab order. No JS-dependent visibility trickery. */
.accordion__panel { padding: 0 0 clamp(1rem, 0.85rem + 0.6vw, 1.5rem); }
.accordion__panel[hidden] { display: none; }
.accordion__panel > * + * { margin-top: var(--s-3); }
.accordion__panel p { color: var(--ink-secondary); max-width: var(--w-prose); }
.accordion__panel a { color: var(--accent-text); text-decoration: underline; }

/* Grouped FAQ headings on the dedicated FAQ page */
.faq-group + .faq-group { margin-top: clamp(2.5rem, 2rem + 2vw, 4rem); }
.faq-group__title { margin-bottom: var(--s-4); font-size: var(--t-h3); }

/* ---------------------------------------------------------------------------
   11. TABLES
   ------------------------------------------------------------------------ */
/* SCROLLABLE REGION. Below ~700px the table is wider than its container.
   Two things are therefore required, not optional:
     1. tabindex="0" + role="region" + aria-label IN THE MARKUP, so keyboard
        users can reach the clipped columns at all (WCAG 2.1.1). Without it
        the right-hand plan column is simply unreachable.
     2. A visible scroll cue. The two edge shadows below are painted with
        background-attachment: local/scroll so they appear only on the side
        that still has content off-screen, and vanish at each end. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background-color: color-mix(in srgb, var(--grad-cream) 58%, #FFFFFF);
  /* Four layers. The two "cover" layers are painted in the card colour and
     scroll WITH the content (background-attachment: local), so at each end
     of the scroll they slide over the shadow beneath and hide it. The two
     shadow layers are pinned to the border box (scroll). Net effect: an
     edge shadow appears only on a side that still has content off-screen. */
  background-image:
    linear-gradient(to right, #FFFBF4, rgba(255, 251, 244, 0)),
    linear-gradient(to left,  #FFFBF4, rgba(255, 251, 244, 0)),
    linear-gradient(to right, rgba(36, 28, 25, 0.14), rgba(46, 37, 33, 0)),
    linear-gradient(to left,  rgba(36, 28, 25, 0.14), rgba(46, 37, 33, 0));
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-size: 30px 100%, 30px 100%, 22px 100%, 22px 100%;
  background-repeat: no-repeat;
  background-attachment: local, local, scroll, scroll;
  box-shadow: 0 1px 2px rgba(36, 28, 25, 0.04);
  -webkit-overflow-scrolling: touch;
}
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .table-wrap { background-color: #FFFBF4; }
}
.table-wrap:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.table {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  font-size: var(--t-sm);
}
.table caption {
  padding: var(--s-4) var(--s-5) 0;
  text-align: left;
  font-weight: 700;
  color: var(--ink);
}
.table th, .table td {
  padding: 0.9rem 1.1rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
}
.table thead th {
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  background: var(--surface-sunken);
  white-space: nowrap;
}
.table tbody tr:last-child th,
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody th { font-weight: 700; color: var(--ink); }
.table td { color: var(--ink-secondary); }
.table__yes { color: var(--green-text); font-weight: 700; }
.table__no  { color: var(--ink-muted); }

/* ---------------------------------------------------------------------------
   12. PRICING
   ------------------------------------------------------------------------ */
.price-grid {
  display: grid;
  gap: clamp(1rem, 0.7rem + 1.4vw, 1.75rem);
  align-items: start;
}
/* 900, not 760. At 768 two 341px columns force the yearly plan's
   equivalence line to four lines against the monthly plan's two, which no
   min-height can reconcile without leaving a visible hole in one card.
   Full-width stacked cards at tablet read better and align trivially. */
@media (min-width: 900px) { .price-grid { grid-template-columns: 1fr 1fr; } }

/* The two plans are a MATCHED SET, so their internal rows must line up.
   As flex columns they did not: the yearly card's equivalence line wraps to
   two lines and pushed price, trial pill and feature list 12 to 37px out of
   step with the monthly card. A shared row grid bands them instead: term,
   amount, equivalence, pill, list and CTA each occupy the same track in both
   cards. Keep the row count in sync with the markup if you add a row. */
.price-card { position: relative; display: flex; flex-direction: column; height: 100%; }
/* Two SEPARATE grids cannot share row heights, so a row grid here would not
   actually align the pair (that needs subgrid, which the rest of this file
   does not depend on). Reserving the tallest possible height for the two
   rows that differ does the job with no layout risk: the yearly card's
   equivalence line wraps to two lines while the monthly card's fits on one,
   which is what pushed price, trial pill and feature list 12 to 37px out of
   step between the cards. */
@media (min-width: 900px) {
  .price-card__intro { min-height: 4.6em; }
  .price-card__equiv { min-height: 3.4em; }
}
/* The ribbon is the featured card's first child and is absolutely
   positioned, but it still counts for `.card > * + *`, so the plan name
   underneath it picked up a 12px top margin that the unribboned card did
   not have. That was the last of the two cards' misalignment. */
.price-card > .price-card__flag + * { margin-top: 0; }
.price-card--featured {
  border-color: rgba(154, 76, 20, 0.32);
  background: color-mix(in srgb, var(--peach) 26%, #FFFFFF);
  box-shadow: 0 1px 2px rgba(36, 28, 25, 0.05);
}
/* Centred on the card, not pinned to a corner. Pinned top-right it floated
   detached over empty gradient 146px away from the plan name it qualifies. */
.price-card__flag {
  position: absolute;
  top: 0;
  left: 50%;
  right: auto;
  transform: translate(-50%, -50%);
}
.price-card__term { font-size: var(--t-h4); font-weight: 700; color: var(--ink); }
.price-card__amount {
  display: flex;
  align-items: baseline;
  gap: 0.3em;
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 1.9rem + 2.2vw, 3.6rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
}
/* letter-spacing is inherited as a RESOLVED LENGTH, so the parent's
   -0.03em (about -1.7px at display size) would follow this small text down
   and swallow its word spaces. Always reset tracking on small text nested
   inside display type. See .u-tracking-normal. */
.price-card__period {
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 600;
  letter-spacing: normal;
  color: var(--ink-muted);
}
.price-card__equiv { font-size: var(--t-sm); color: var(--ink-secondary); }
.price-card__list { list-style: none; }
.price-card__list li {
  display: flex;
  gap: 0.6em;
  padding: 0.4rem 0;
  color: var(--ink-secondary);
}
/* The tick is DRAWN. This shipped for a while as an empty green disc,
   twelve times over, on the primary conversion element. The glyph is an
   inline SVG data URI (no external asset, no icon font) stroked in
   --green-text #386146, which is 4.9:1 on --green-soft. */
.price-card__list li::before {
  content: "";
  flex: 0 0 auto;
  width: 1.2em;
  height: 1.2em;
  margin-top: 0.26em;
  border-radius: 50%;
  background-color: var(--green-soft);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23386146' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 0.72em 0.72em;
  box-shadow: inset 0 0 0 1px rgba(63, 107, 78, 0.28);
}
.price-card__cta { margin-top: auto; padding-top: var(--s-5); }

/* Legally required pricing disclosure. NEVER give this a reveal class. */
.price-disclosure {
  margin-top: var(--s-5);
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: var(--w-prose);
}

/* ---------------------------------------------------------------------------
   13. NOTICES — medical, safety, privacy
   ------------------------------------------------------------------------ */
/* These carry legally and clinically important content. They are ALWAYS
   plainly visible. Never attach .reveal or any animation class to them. */
.notice {
  display: flex;
  gap: var(--s-4);
  padding: clamp(1rem, 0.85rem + 0.7vw, 1.5rem);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-card);
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--ink-secondary);
}
.notice__title { display: block; margin-bottom: 0.35rem; font-weight: 700; color: var(--ink); }
.notice a { color: var(--accent-text); text-decoration: underline; }
.notice--urgent { border-color: rgba(154, 76, 20, 0.35); background: var(--cream); }
.notice--plum   { border-color: rgba(110, 63, 95, 0.28); background: var(--plum-soft); }
.notice--green  { border-color: rgba(63, 107, 78, 0.28); background: var(--green-soft); }


/* ---------------------------------------------------------------------------
   14. PHONE MOCKUP SYSTEM
   --------------------------------------------------------------------------
   INSIDE .phone, 1em == 1 iOS point. A single font-size on .phone therefore
   scales an entire screen design: 16em == 16pt for ANY property (width,
   height, padding, gap, border-radius, box-shadow offsets).

   TWO RULES KEEP THIS TRUE. Both matter; the second is the one people get
   wrong.

   RULE 1 — containers do not set font-size.
   font-size is the one property that compounds through em inheritance. If a
   container sets it, every em on its descendants is silently multiplied:

     ok    .ph-card { padding: 16em }  .ph-card__title { font-size: 17em }
     WRONG .ph-tab { font-size: 11em } .ph-tab__glyph { width: 20em }
                                       ^ 20 x 11 = 220pt, not 20pt

   RULE 2 — if an element sets its OWN font-size and also needs a box metric
   (width, height, padding, margin, gap, border-radius), that metric must
   NOT use em. em on such an element resolves against its own new font-size,
   so `font-size: 15em; width: 32em` is 32 x 15 = 480pt wide. Use the --u
   token instead: it is a real px LENGTH, so it is completely immune to
   font-size inheritance.

     WRONG .ph-row__icon { font-size: 15em; width: 32em }
     ok    .ph-row__icon { font-size: 15em; width: calc(var(--u) * 32) }

   In short: plain `em` for containers, `calc(var(--u) * N)` for any element
   that also sets font-size. Both mean "N iOS points".

   Frame is iPhone 15 logical size: 393 x 852 pt.
   Override the scale per instance with `style="--phone-fs: 0.8px"`.        */

.phone {
  /* One iOS point as a real length. Immune to font-size inheritance. */
  --u: var(--phone-fs, clamp(0.62px, 0.01875vw + 0.63px, 0.92px));
  /* 1em = 1 iOS point. Frame spans about 271px at 320 up to 362px at 1440. */
  font-size: var(--u);
  position: relative;
  width: 393em;
  height: 852em;
  flex: 0 0 auto;
  margin-inline: auto;
  padding: 12em;
  border-radius: 62em;
  background: linear-gradient(155deg, #3A3033, #171214 45%, #2B2326);
  box-shadow:
    var(--shadow-xl),
    inset 0 0 0 1.5em rgba(255, 255, 255, 0.16),
    inset 0 0 0 3em rgba(0, 0, 0, 0.55);
  /* Font tokens, resolved against the .phone root so they never compound. */
  --fs-lg-title: 34em;
  --fs-title-1: 28em;
  --fs-title-2: 22em;
  --fs-title-3: 20em;
  --fs-headline: 17em;
  --fs-body: 17em;
  --fs-callout: 16em;
  --fs-subhead: 15em;
  --fs-footnote: 13em;
  --fs-caption: 12em;
  --fs-caption-2: 11em;
}

.phone__screen,
.phone-screen {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  border-radius: 50em;
  background: var(--canvas);
  background-image: linear-gradient(180deg, var(--cream), var(--canvas) 40%, var(--blush));
  color: #241C19;
  font-family: var(--font-body);
  line-height: 1.35;
  letter-spacing: -0.01em;
  /* Screens never inherit dark mode; a phone screenshot is a picture of the
     app, and the app screenshot always renders in its light theme. */
  color-scheme: light;
}
.phone-screen--warm { background-image: linear-gradient(180deg, var(--cream), var(--peach)); }
.phone-screen--cool { background-image: linear-gradient(180deg, var(--lilac), var(--canvas) 45%, var(--periwinkle)); }
.phone-screen--plum { background-image: linear-gradient(180deg, var(--plum-soft), var(--canvas)); }

/* Dynamic island */
.phone__island {
  position: absolute;
  top: 23em;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  width: 122em;
  height: 35em;
  border-radius: 20em;
  background: #050405;
  pointer-events: none;
}

/* -- Status bar.
   NOTE: font-size lives on the LEAF (.ph-status__time), never on the
   container, so sibling elements sized in em still resolve against the
   .phone root. See the "only leaves set font-size" rule above. */
.ph-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: 0 0 auto;
  height: 54em;
  padding: 14em 30em 0;
  color: #241C19;
}
.ph-status__time { display: block;
  font-size: var(--fs-footnote);
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1;
}
.ph-status__right { display: flex; align-items: center; gap: 5em; }
.ph-status__batt {
  width: 25em; height: 12em;
  border: 1.5em solid currentColor;
  border-radius: 4em;
  padding: 2em;
  opacity: 0.9;
}
.ph-status__batt i { display: block; height: 100%; width: 72%; border-radius: 1.5em; background: currentColor; }
.ph-status__wifi {
  width: 15em; height: 11em;
  background: currentColor;
  opacity: 0.9;
  clip-path: polygon(50% 100%, 0 38%, 12% 26%, 50% 60%, 88% 26%, 100% 38%);
}

/* -- App header inside the screen */
.ph-header {
  flex: 0 0 auto;
  padding: 14em 22em 10em;
}
.ph-header__row { display: flex; align-items: center; justify-content: space-between; gap: 10em; }
.ph-header__title { display: block;
  font-family: var(--font-display);
  font-size: var(--fs-title-1);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.1;
  color: #241C19;
}
.ph-header__sub { display: block; margin-top: calc(var(--u) * 3); font-size: var(--fs-subhead); color: #5F544C; }
.ph-header__avatar {
  width: 34em; height: 34em;
  border-radius: 50%;
  background: linear-gradient(150deg, var(--ember-bright), var(--plum-bright));
  flex: 0 0 auto;
}

/* -- Scrollable body region */
.ph-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  padding: 4em 22em 14em;
  display: flex;
  flex-direction: column;
  gap: 12em;
}

/* -- Cards inside the phone */
.ph-card {
  padding: 16em;
  border-radius: 22em;
  background: #FFFFFF;
  box-shadow: 0 4em 14em rgba(122, 58, 15, 0.10);
}
.ph-card--tint { background: linear-gradient(150deg, #FFFFFF, var(--peach)); }
.ph-card--plum { background: linear-gradient(150deg, #FFFFFF, var(--plum-soft)); }
.ph-card--ember {
  background: linear-gradient(150deg, var(--ember-mid), #B95C1E);
  color: #FFFFFF;
}
.ph-card__label { display: block;
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #8A4210;
}
.ph-card--ember .ph-card__label { color: rgba(255,255,255,0.86); }
.ph-card__title {
  display: block;
  margin-top: calc(var(--u) * 5);
  font-size: var(--fs-headline);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: #241C19;
}
.ph-card--ember .ph-card__title { color: #FFFFFF; }
.ph-card__text { display: block; margin-top: calc(var(--u) * 5); font-size: var(--fs-subhead); color: #5F544C; }
.ph-card--ember .ph-card__text { color: rgba(255,255,255,0.92); }

/* -- Progress ring. Pure CSS conic gradient, no SVG needed.
      Set the value with style="--ring: 68". */
.ph-ring {
  position: relative;
  width: 96em;
  height: 96em;
  flex: 0 0 auto;
  border-radius: 50%;
  background:
    conic-gradient(var(--ember-mid) calc(var(--ring, 65) * 1%), rgba(36, 28, 25, 0.09) 0);
  display: grid;
  place-items: center;
}
.ph-ring::after {
  content: "";
  position: absolute;
  inset: 11em;
  border-radius: 50%;
  background: #FFFFFF;
}
.ph-ring__value {
  position: relative;
  z-index: 1;
  font-family: var(--font-display);
  font-size: var(--fs-title-2);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: #241C19;
}
.ph-ring--plum { background: conic-gradient(var(--plum-bright) calc(var(--ring, 65) * 1%), rgba(36,28,25,0.09) 0); }
.ph-ring--green { background: conic-gradient(var(--green) calc(var(--ring, 65) * 1%), rgba(36,28,25,0.09) 0); }

.ph-ring-row { display: flex; align-items: center; gap: 16em; }

/* -- List rows */
.ph-list { display: flex; flex-direction: column; gap: 8em; list-style: none; }
.ph-row {
  display: flex;
  align-items: center;
  gap: 12em;
  padding: 12em 14em;
  border-radius: 18em;
  background: #FFFFFF;
  box-shadow: 0 2em 8em rgba(122, 58, 15, 0.07);
}
.ph-row__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  /* sets its own font-size, so box metrics use --u (see RULE 2) */
  width: calc(var(--u) * 32);
  height: calc(var(--u) * 32);
  border-radius: calc(var(--u) * 11);
  background: var(--peach);
  font-size: var(--fs-subhead);
}
.ph-row__icon--plum { background: var(--plum-soft); }
.ph-row__icon--green { background: var(--green-soft); }
.ph-row__icon--cool { background: var(--periwinkle); }
.ph-row__main { flex: 1 1 auto; min-width: 0; }
.ph-row__title { display: block; font-size: var(--fs-subhead); font-weight: 700; color: #241C19; }
.ph-row__meta { display: block; margin-top: calc(var(--u) * 2); font-size: var(--fs-caption); color: #5F544C; }
.ph-row__trail { flex: 0 0 auto; font-size: var(--fs-caption); font-weight: 700; color: #8A4210; }

/* -- Chat bubbles, for the Juno screen */
.ph-chat { display: flex; flex-direction: column; gap: 8em; }
.ph-bubble {
  max-width: 78%;
  /* sets its own font-size, so box metrics use --u (see RULE 2) */
  padding: calc(var(--u) * 11) calc(var(--u) * 14);
  border-radius: calc(var(--u) * 20);
  font-size: var(--fs-subhead);
  line-height: 1.4;
}
.ph-bubble--them {
  align-self: flex-start;
  border-bottom-left-radius: calc(var(--u) * 7);
  background: #FFFFFF;
  color: #241C19;
  box-shadow: 0 2em 8em rgba(122, 58, 15, 0.08);
}
.ph-bubble--me {
  align-self: flex-end;
  border-bottom-right-radius: calc(var(--u) * 7);
  background: linear-gradient(140deg, var(--plum-bright), var(--plum-deep));
  color: #FFFFFF;
}

/* -- Segmented control / chips */
.ph-chips { display: flex; flex-wrap: wrap; gap: 6em; }
.ph-chip {
  /* sets its own font-size, so box metrics use --u (see RULE 2) */
  padding: calc(var(--u) * 6) calc(var(--u) * 12);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.85);
  font-size: var(--fs-caption);
  font-weight: 700;
  color: #4A403A;
  box-shadow: inset 0 0 0 var(--u) rgba(36, 28, 25, 0.09);
}
.ph-chip--on { background: #241C19; color: #FFFCF8; box-shadow: none; }

/* -- Bar chart, for the insights screen */
.ph-bars { display: flex; align-items: flex-end; gap: 7em; height: 74em; }
.ph-bars__bar {
  flex: 1 1 0;
  border-radius: 6em 6em 3em 3em;
  background: linear-gradient(180deg, var(--ember-bright), var(--ember-mid));
  height: calc(var(--h, 50) * 1%);
  min-height: 6em;
}
.ph-bars__bar--plum { background: linear-gradient(180deg, var(--plum-bright), var(--plum-deep)); }
.ph-bars__bar--muted { background: rgba(36, 28, 25, 0.12); }

/* -- Tab bar */
.ph-tabbar {
  display: flex;
  align-items: center;
  justify-content: space-around;
  flex: 0 0 auto;
  height: 76em;
  padding: 8em 10em 22em;
  /* Deliberately NOT backdrop-filter. A blur inside the phone buys almost
     nothing visually at this scale and costs a compositing pass per mockup,
     and the showcase stacks several mockups at once. */
  background: rgba(255, 255, 255, 0.94);
  border-top: 1em solid rgba(36, 28, 25, 0.07);
}
.ph-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3em;
  color: #5F544C;
}
.ph-tab__glyph {
  width: 20em; height: 20em;
  border-radius: 7em;
  background: currentColor;
  opacity: 0.55;
}
/* font-size on the leaf only, so .ph-tab__glyph's em sizing stays true */
.ph-tab__label { display: block;
  font-size: var(--fs-caption-2);
  font-weight: 600;
  line-height: 1;
}
.ph-tab--on { color: #8A4210; }
.ph-tab--on .ph-tab__glyph { opacity: 1; }

/* -- Home indicator */
.ph-home {
  position: absolute;
  bottom: 9em;
  left: 50%;
  transform: translateX(-50%);
  width: 140em;
  height: 5em;
  border-radius: 3em;
  background: rgba(36, 28, 25, 0.30);
  pointer-events: none;
}

/* Optional soft glow behind a hero phone */
.phone-halo { position: relative; display: flex; justify-content: center; }
.phone-halo::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 8% 6% 4%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(240, 128, 58, 0.45), rgba(240, 128, 58, 0) 72%);
  filter: blur(48px);
  pointer-events: none;
}
.phone-halo > .phone { position: relative; z-index: 1; }

/* ---------------------------------------------------------------------------
   15. STICKY SCROLL SHOWCASE
   --------------------------------------------------------------------------
   Copy scrolls on one side, a phone stays pinned on the other and swaps its
   screen per step. CRITICAL: every screen is present in the DOM and readable.
   The inactive state is opacity + a small transform only, and under
   prefers-reduced-motion the screens simply stack with all copy visible. */

.showcase { position: relative; }

.showcase__grid { display: grid; gap: clamp(2rem, 1.2rem + 3vw, 4rem); }
@media (min-width: 960px) {
  .showcase__grid { grid-template-columns: 1fr minmax(18rem, 24rem); align-items: start; }
  .showcase--visual-left .showcase__media { order: -1; }
}

.showcase__media { position: relative; }
@media (min-width: 960px) {
  /* The pinned phone must never slide under the masthead. It used to: a
     700px phone was centred in a 608px sticky box with overflow visible, so
     it overhung 46px top and bottom and the top of the frame was covered by
     the nav. The box now starts below the real header and the phone is
     capped against the box height, with padding-block as a second guard. */
  .showcase__media {
    position: sticky;
    top: var(--sticky-offset);
    height: min(72vh, 42rem);
    padding-block: var(--s-4);
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .showcase__media .phone {
    /* 852em tall frame. 0.0745vh keeps it inside 72vh minus the padding;
       the 0.75px ceiling keeps it inside the 42rem ceiling on tall screens. */
    --phone-fs: min(clamp(0.62px, 0.01875vw + 0.63px, 0.92px), 0.0745vh, 0.75px);
  }
  /* Stack every screen in the same box so they cross-fade in place. */
  .showcase__media .phone { position: absolute; }
  .showcase__phone { position: absolute; inset: 0; display: grid; place-items: center; }
  .showcase__phone[data-active="false"] { opacity: 0; visibility: hidden; }
  .showcase__phone[data-active="true"] { opacity: 1; visibility: visible; }
  .showcase__phone {
    transition: opacity 420ms var(--ease-soft), transform 420ms var(--ease-soft);
    transform: scale(0.985);
  }
  .showcase__phone[data-active="true"] { transform: scale(1); }
}
/* Below 960px there is no pinning. Show ONE phone (the first) and let the
   steps read as a normal vertical list. Extra phones are hidden to avoid a
   wall of duplicate mockups on mobile. */
@media (max-width: 959px) {
  .showcase__phone { display: none; }
  .showcase__phone:first-child { display: block; margin-bottom: var(--s-6); }
  /* The screens do not change on scroll here, so the instruction that says
     they do is hidden rather than left to mislead. */
  .showcase__hint { display: none; }
}

.showcase__steps { display: flex; flex-direction: column; }
.showcase__step {
  padding-block: clamp(2rem, 1.5rem + 4vw, 6rem);
  /* Fully legible at all times. data-active only shifts emphasis. */
  color: var(--ink);
}
@media (min-width: 960px) {
  .showcase__step { min-height: 62vh; display: flex; flex-direction: column; justify-content: center; }
  .showcase__step[data-active="false"] { opacity: 0.55; }
  .showcase__step { transition: opacity 380ms var(--ease-soft); }
}
.showcase__step + .showcase__step { border-top: 1px solid var(--line); }
@media (min-width: 960px) { .showcase__step + .showcase__step { border-top: 0; } }

.showcase__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem; height: 2.1rem;
  margin-bottom: var(--s-4);
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  font-size: var(--t-sm);
  font-weight: 700;
  color: var(--accent-text);
}
.showcase__step[data-active="true"] .showcase__num {
  background: var(--peach);
  border-color: rgba(154, 76, 20, 0.3);
  color: #8A4210;
}

.showcase__title { font-size: var(--t-display-3); }
.showcase__body { margin-top: var(--s-4); max-width: 34rem; }

/* ---------------------------------------------------------------------------
   16. FOOTER
   ------------------------------------------------------------------------ */
/* NO border-top. The hairline read as a seam and, worse, as a luminance
   inversion: cream above, a darker 1px rule, then a footer top BRIGHTER
   than the section above it before darkening again to peach. The gradient
   now starts fully transparent so the footer emerges out of whatever sits
   above it over the first 5rem, and it arcs like every other tinted band. */
.site-footer {
  position: relative;
  isolation: isolate;
  padding-block: clamp(3.5rem, 2.6rem + 3.5vw, 6rem) clamp(2rem, 1.6rem + 1.6vw, 3rem);
  background: none;
  border-top: 0;
}
.site-footer::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: 50% 50% 0 0 / var(--arc) var(--arc) 0 0;
  background-image: linear-gradient(180deg,
      rgba(255, 226, 201, 0) 0%,
      rgba(255, 226, 201, 0.45) 34%,
      var(--peach) 100%);
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,0) 0, #000 calc(var(--arc) * 2.4), #000 100%);
          mask-image: linear-gradient(180deg, rgba(0,0,0,0) 0, #000 calc(var(--arc) * 2.4), #000 100%);
}


.footer__top {
  display: grid;
  gap: clamp(2rem, 1.4rem + 2.5vw, 3.5rem);
  padding-bottom: clamp(2rem, 1.6rem + 2vw, 3rem);
}
@media (min-width: 720px) { .footer__top { grid-template-columns: 1.4fr 1fr 1fr 1fr; } }

.footer__brand { max-width: 22rem; }
.footer__tagline { margin-top: var(--s-3); font-size: var(--t-sm); color: var(--ink-secondary); }

.footer__col-title {
  margin-bottom: var(--s-3);
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.footer__list { list-style: none; }
.footer__list li + li { margin-top: 0.15rem; }
.footer__link {
  /* padding-block lifts the hit area to 44px without opening up the rhythm;
     the list gap above is reduced by the same amount. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-block: 0.35rem;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--ink-secondary);
  text-decoration: none;
}
.footer__link:hover { color: var(--ink); text-decoration: underline; }
/* Privacy and Terms live only in the footer, so the current-page affordance
   has to live there too. Same ember underline as the masthead. The colour
   shift is a second signal; aria-current carries the meaning. */
.footer__link[aria-current="page"] {
  color: var(--ink);
  font-weight: 700;
  box-shadow: inset 0 -2px 0 var(--ember-mid);
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  align-items: center;
  justify-content: space-between;
  padding-top: clamp(1.25rem, 1rem + 1vw, 2rem);
  border-top: 1px solid var(--line);
  font-size: var(--t-xs);
  color: var(--ink-muted);
}
.footer__legal-block { max-width: 62ch; }
.footer__legal { line-height: 1.6; }
.footer__legal + .footer__legal { margin-top: 0.55rem; }
.footer__legal a { color: var(--accent-text); text-decoration: underline; }

/* ---------------------------------------------------------------------------
   17. ANIMATION UTILITIES
   --------------------------------------------------------------------------
   THE RULE, learned from a real shipped bug:
   A scroll or JS animation must NEVER be the thing that makes content
   visible. Every animated element defines its VISIBLE END STATE as the
   default. site.js applies `.js-anim` to <html> only when it has a working
   IntersectionObserver, and only then does the hidden start state apply.
   If the script fails to load, throws, or the observer never fires, all
   content is already on screen.

   Legally required content (pricing disclosure, medical notice, terms,
   privacy) must carry NO reveal class at all. Not even a safe one.        */

/* Default = visible end state. Always. */
.reveal {
  opacity: 1;
  transform: none;
}

/* Hidden start state applies ONLY when the script proved an observer exists. */
.js-anim .reveal:not(.is-in) {
  opacity: 0;
  transform: translateY(18px);
}
.js-anim .reveal {
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
/* will-change ONLY while an element is still waiting. Applying it to every
   .reveal promotes the whole page to compositor layers at once. */
.js-anim .reveal:not(.is-in) { will-change: opacity, transform; }
.js-anim .reveal.is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Directional variants */
.js-anim .reveal--left:not(.is-in)  { transform: translateX(-22px); }
.js-anim .reveal--right:not(.is-in) { transform: translateX(22px); }
.js-anim .reveal--scale:not(.is-in) { transform: scale(0.965); }
.js-anim .reveal--fade:not(.is-in)  { transform: none; }

/* Stagger. Put .stagger on a PARENT; its .reveal children step in.
   Delays are pure CSS so a missing script cannot strand a child. */
.stagger > .reveal:nth-child(1) { --reveal-delay: 0ms; }
.stagger > .reveal:nth-child(2) { --reveal-delay: 70ms; }
.stagger > .reveal:nth-child(3) { --reveal-delay: 140ms; }
.stagger > .reveal:nth-child(4) { --reveal-delay: 210ms; }
.stagger > .reveal:nth-child(5) { --reveal-delay: 280ms; }
.stagger > .reveal:nth-child(6) { --reveal-delay: 350ms; }
.stagger > .reveal:nth-child(7) { --reveal-delay: 420ms; }
.stagger > .reveal:nth-child(8) { --reveal-delay: 490ms; }
.stagger > .reveal:nth-child(n+9) { --reveal-delay: 560ms; }

/* Gentle float. Decorative only. Never applied to text content. */
@keyframes marlune-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}
.float { animation: marlune-float 7s var(--ease-soft) infinite; }
.float--slow { animation-duration: 11s; }
.float--delay { animation-delay: -3.5s; }

/* Gradient drift. Animates background-position only, which the compositor
   handles cheaply, and the element is legible at every frame. */
@keyframes marlune-drift {
  0%   { background-position: 0% 40%; }
  50%  { background-position: 100% 60%; }
  100% { background-position: 0% 40%; }
}
.drift {
  /* 200% blew the gradient up to four times the visible area, so only a
     quarter of the composition was ever on screen and the warm stops panned
     off entirely. 118% keeps the composition intact and still drifts. */
  background-size: 118% 118%;
  animation: marlune-drift 22s ease-in-out infinite;
}

/* Soft pulse for a decorative dot */
@keyframes marlune-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.55; transform: scale(0.88); }
}
.pulse { animation: marlune-pulse 2.8s var(--ease-soft) infinite; }

/* -- REDUCED MOTION -----------------------------------------------------
   Everything resolves to the visible end state instantly. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  /* Force-reveal regardless of what the script did or did not do. */
  .js-anim .reveal,
  .js-anim .reveal:not(.is-in),
  .reveal {
    opacity: 1 !important;
    transform: none !important;
  }

  .float, .drift, .pulse { animation: none !important; }

  /* Keep the LAYOUT, remove only the motion. Statically positioning
     .showcase__media alone used to destroy this section: .showcase__phone is
     `position:absolute; inset:0`, so removing the parent's containing block
     pushed every phone up the tree, stretched all six to full section height
     and stacked them at one offset on top of the body copy. The sticky
     cross-fade is kept; it simply swaps instantly instead of animating. */
  .showcase__phone,
  .showcase__step {
    transition: none !important;
    transform: none !important;
  }
  .showcase__step[data-active="false"] { opacity: 1 !important; }
  /* Reduced motion pins the first screen and never swaps it, so the scroll
     instruction does not apply here either. */
  .showcase__hint { display: none !important; }
}

/* Print: flatten everything, drop decoration. */
@media print {
  .site-header, .nav__toggle, .blob, .grain::after, .phone-halo::before { display: none !important; }
  .reveal { opacity: 1 !important; transform: none !important; }
  body { background: #FFFFFF; color: #000000; }
  .canvas-gradient, .canvas-soft, .canvas-warm, .canvas-cool, .canvas-contrast {
    background: none !important; color: #000000 !important;
  }
}

/* ---------------------------------------------------------------------------
   18. SMALL UTILITIES
   ------------------------------------------------------------------------ */
.u-hide { display: none !important; }
.u-mt-0 { margin-top: 0 !important; }
.u-mt-4 { margin-top: var(--s-4) !important; }
.u-mt-6 { margin-top: var(--s-6) !important; }
.u-mt-7 { margin-top: var(--s-7) !important; }
.u-mb-0 { margin-bottom: 0 !important; }
.u-maxw-prose { max-width: var(--w-prose); }
.u-maxw-narrow { max-width: var(--w-narrow); }
.u-nowrap { white-space: nowrap; }
/* Put this on any small text nested inside a display heading or price.
   letter-spacing inherits as a resolved length, not as em, so tight display
   tracking otherwise collapses the word spaces of small nested text. */
.u-tracking-normal { letter-spacing: normal; }
.u-balance { text-wrap: balance; }
.u-pretty { text-wrap: pretty; }
.u-relative { position: relative; z-index: 1; }

@media (max-width: 639px) { .u-hide-sm { display: none !important; } }
@media (min-width: 640px) { .u-only-sm { display: none !important; } }


/* ── REAL SCREENSHOTS ───────────────────────────────────────────────────────
   The phone frame is still CSS; only the screen inside it is now a real capture.
   aspect-ratio + explicit width/height on the tag keep layout stable while the
   image loads, so the hero never shifts (CLS). */
.phone-shot{
  display:block; width:100%; height:auto;
  aspect-ratio: 552 / 1200;
  border-radius: inherit;
}
.proof{ display:grid; gap: var(--s-7); align-items:center; }
@media (min-width: 900px){
  .proof{ grid-template-columns: 1fr 1fr; gap: var(--s-9); }
  .proof--flip .proof__shot{ order: 2; }
}
.proof__shot{ margin-inline:auto; max-width: 300px; width:100%; }
.proof__shot img{
  display:block; width:100%; height:auto;
  aspect-ratio: 552 / 1200;
  border-radius: 28px;
  border: 1px solid var(--line);
  box-shadow: 0 24px 60px -28px rgba(44,35,32,.38);
}

.hero__aside{ margin-top: var(--s-4); font-size: .95rem; }
.link-quiet{ color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
.link-quiet:hover{ color: var(--ink); }
