/* Garden — shared base styles for every page. */
/* Fonts are self-hosted (SIL OFL, licenses in assets/fonts/) rather than
   loaded from Google Fonts: no extra origins before first paint, and no
   visitor IPs sent to Google. Both are variable fonts, subset to latin and
   latin-ext; the browser fetches latin-ext only for characters that need it
   (some country names in the phone picker). Newsreader (display), Figtree (body). */
@font-face{font-family:'Figtree';font-style:normal;font-weight:400 600;font-display:swap;src:url(../assets/fonts/figtree-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Figtree';font-style:normal;font-weight:400 600;font-display:swap;src:url(../assets/fonts/figtree-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Newsreader';font-style:italic;font-weight:300 700;font-display:swap;src:url(../assets/fonts/newsreader-italic-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Newsreader';font-style:italic;font-weight:300 700;font-display:swap;src:url(../assets/fonts/newsreader-italic-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Newsreader';font-style:normal;font-weight:300 700;font-display:swap;src:url(../assets/fonts/newsreader-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Newsreader';font-style:normal;font-weight:300 700;font-display:swap;src:url(../assets/fonts/newsreader-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
:root{
  --ink:#141311;--ink-2:#333230;--ink-3:#45443f;--muted:#6a6964;--muted-2:#8e8d88;
  --rule:#e4e5e1;--field:#d4d5d0;--green:#1e2a24;--green-dark:#141d18;
  --band:var(--green);--band-text:#b9c2bc;--band-soft:#e3efe7;
  --serif:"Newsreader",Georgia,serif;--sans:"Figtree",system-ui,sans-serif;
  --max:1200px;--gutter:28px;--section-pad:176px;
  /* Space js/anchors.js leaves between the header (or the top of the screen)
     and the first text of whatever an anchor link scrolls to. */
  --anchor-gap:40px;
  /* Inset for desktop copy within the hero photo. */
  --edge:clamp(20px,5vw,72px);
}
*{box-sizing:border-box}
/* The hidden attribute is only display:none from the user-agent sheet, so any
   element we also give an explicit display to ignores it -- .waitlist-signup is
   a grid, and shipped visible despite [hidden] until this rule existed. The
   batch-state toggles all rely on [hidden], so it has to win. */
[hidden]{display:none !important}
html{scroll-behavior:smooth}
body{margin:0;background:#fff;color:var(--ink);font-family:var(--sans);-webkit-font-smoothing:antialiased;line-height:1.5}
img{display:block;max-width:100%}
h1,h2,h3,p{margin:0}
a{color:var(--ink)}a:hover{color:var(--green)}
input::placeholder{color:var(--muted-2)}
.wrap{max-width:var(--max);margin:0 auto;padding-left:var(--gutter);padding-right:var(--gutter)}
.serif{font-family:var(--serif)}

/* type scale */
.display{font-family:var(--serif);font-weight:400;font-size:clamp(48px,6vw,84px);line-height:.98;letter-spacing:-.025em;text-wrap:pretty}
.h2{font-family:var(--serif);font-weight:400;font-size:clamp(36px,4vw,56px);line-height:1.05;letter-spacing:-.02em;text-wrap:pretty}
.h2-sm{font-family:var(--serif);font-weight:400;font-size:clamp(34px,3.6vw,48px);line-height:1.08;letter-spacing:-.02em;text-wrap:pretty}
.h3{font-family:var(--serif);font-weight:400;font-size:clamp(28px,3vw,40px);line-height:1.1;letter-spacing:-.02em;text-wrap:pretty}
.h4{font-family:var(--serif);font-weight:500;font-size:28px;letter-spacing:-.01em}
.lede{font-size:20px;line-height:1.5;color:var(--ink-3);max-width:480px;text-wrap:pretty}
.body-lg{font-size:18px;line-height:1.6;color:var(--ink-3);text-wrap:pretty}
.body{font-size:16px;line-height:1.6;color:var(--ink-3);text-wrap:pretty}
/* Eyebrows stay on --green. Both darker tokens were tried here and neither
   reads as green at 13px uppercase: --band goes near-black, --green-dark is
   close behind. The label needs to carry color more than it needs to match the
   dark bands elsewhere on the page. */
.eyebrow{font-size:13px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--green)}
.accent{font-style:italic;color:var(--green)}

/* buttons */
.btn{display:inline-block;text-decoration:none;border:0;cursor:pointer;font-family:inherit;font-weight:600;font-size:16px;border-radius:999px;padding:16px 26px;color:#fff;background:var(--green);transition:background .15s}
.btn:hover{background:var(--green-dark);color:#fff}
.btn-sm{padding:9px 16px;font-size:14px;font-weight:500;background:transparent;color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink)}
/* --band is --green, so a default .btn on a band section is invisible against
   it. White matches the signup card, which is the other interactive surface
   these sections carry. */
.btn-on-band{background:#fff;color:var(--green)}
.btn-on-band:hover{background:var(--band-soft);color:var(--green)}
.btn-sm:hover{background:var(--ink);color:#fff}
.link-ul{text-decoration:none;color:var(--ink);padding:16px 8px;font-weight:500;font-size:16px;border-bottom:1px solid var(--ink)}

/* header */
.site-header{position:sticky;top:0;z-index:10;background:rgba(255,255,255,.88);backdrop-filter:blur(12px);border-bottom:1px solid transparent;transition:border-color .2s,box-shadow .2s}
.site-header.is-scrolled{border-bottom-color:var(--rule)}
.site-header.is-stuck{box-shadow:0 1px 2px rgba(20,29,24,.12)}
/* Animate only menu content; the translucent header surface stays stationary. */
@media(min-width:701px) and (prefers-reduced-motion:no-preference){
 .homepage .site-header>nav{animation:menu-dissolve 1.6s cubic-bezier(.22,1,.36,1) 2s backwards}
 .homepage .site-header:focus-within>nav,
 .homepage .site-header.menu-revealed>nav{animation:none}
}
@keyframes menu-dissolve{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}
.site-header nav{display:flex;align-items:center;justify-content:space-between;gap:24px;padding-top:18px;padding-bottom:18px}
.brand{text-decoration:none;font-family:var(--serif);font-size:28px;font-weight:500;letter-spacing:-.02em;display:flex;align-items:baseline;gap:10px;color:var(--ink)}
.nav-links{display:flex;gap:28px;align-items:center;font-size:14px;font-weight:500;flex-wrap:wrap;justify-content:flex-end}
.nav-links a:not(.btn){text-decoration:none;color:var(--ink-2)}

/* sections */
/* Section head stacks its intro under the heading and lets it run the full
   section width, so it wraps on the section's edges rather than stopping short
   of them. */
.section-head .body-lg{max-width:none}
.section .wrap{padding-top:var(--section-pad);padding-bottom:var(--section-pad)}
.grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,400px),1fr));gap:64px;align-items:center}
.grid-2.tight{gap:48px;align-items:end}
/* Both users of this put a split list or a card grid in the right column, so
   the column is subdivided again. A 380px minimum let that second split fall
   to ~175px around 900-1100px; hold out for 500px before going two-up. */
.grid-2.wide{grid-template-columns:repeat(auto-fit,minmax(min(100%,500px),1fr))}
.stack{display:flex;flex-direction:column}
.stack-4{gap:4px}.stack-12{gap:12px}.stack-16{gap:16px}.stack-18{gap:18px}.stack-20{gap:20px}.stack-22{gap:22px}.stack-28{gap:28px}.stack-32{gap:32px}.stack-56{gap:56px}
.photo{width:100%;object-fit:cover;border-radius:6px}
.photo-4x5{aspect-ratio:4/5}

/* The scroll cue occupies the existing space beneath the hero. */
.hero{position:relative}
.scroll-hint{position:absolute;bottom:4px;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;min-height:44px;padding:2px 12px;color:var(--muted);font-size:12px;letter-spacing:.03em;text-decoration:none;white-space:nowrap;transition:opacity .4s ease,visibility 0s}
.scroll-hint.has-scrolled{animation:none}
.scroll-hint.is-dismissed{opacity:0;visibility:hidden;pointer-events:none;transition:opacity .4s ease,visibility 0s .4s}
.scroll-hint svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round}
@media(max-width:1100px){.scroll-hint{display:none}}
@media(min-width:1101px){.scroll-hint{bottom:16px}}
@media(min-width:701px) and (prefers-reduced-motion:no-preference){
 .scroll-hint{animation:scroll-hint-appear 1.6s cubic-bezier(.22,1,.36,1) 2s backwards}
 .scroll-hint svg{animation:scroll-hint-nudge 1.6s ease-in-out 3.6s 3}
}
@keyframes scroll-hint-appear{from{opacity:0}to{opacity:1}}
@keyframes scroll-hint-nudge{0%,100%{transform:translateY(0)}50%{transform:translateY(4px)}}

/* hero — headline sits in the photo's negative space, at her eye line */
/* Explicit height keeps the image at the full content width while leaving
   enough vertical space for the overlaid copy. */
.hero-media{position:relative;overflow:hidden;width:100%;height:min(56.25vw,720px,84vh);background:#8d8d8a}
@media(min-width:701px){.hero-media{height:min(calc(100vh - 72px - 48px),780px);min-height:540px}}
.hero-photo{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:100% 28%}
/* Scrim carries the white copy. Stops are set so the dark coverage still holds
   at the right edge of the text block (~50% of the media), where her hair and
   the window blow out; the original 38%/66% stops dropped the lede's last
   lines under 4:1. */
.hero-media::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(20,19,17,.72) 0%,rgba(20,19,17,.56) 40%,rgba(20,19,17,0) 74%)}
.hero-copy{position:absolute;z-index:1;left:var(--edge);top:50%;transform:translateY(-50%);width:min(560px,44%);color:#fff;gap:28px}
.hero-copy .display{color:#fff}
.hero-copy .accent{color:#fff}
.hero-copy .lede{color:rgba(255,255,255,.9);max-width:480px;font-size:22px;line-height:1.5}
.hero-copy .link-ul{color:#fff;border-bottom-color:rgba(255,255,255,.7)}
.hero-copy .btn{background:#fff;color:var(--ink)}
.hero-copy .btn:hover{background:#e8e8e5;color:var(--ink)}
.hero-actions{display:flex;gap:20px;flex-wrap:wrap;align-items:center}
/* Build the message in three beats before the navigation finishes arriving. */
@media(min-width:701px) and (prefers-reduced-motion:no-preference){
 .hero-copy>h1{animation:hero-copy-arrive 1.2s cubic-bezier(.22,1,.36,1) .15s backwards}
 .hero-copy>.lede{animation:hero-copy-arrive 1.2s cubic-bezier(.22,1,.36,1) .55s backwards}
 .hero-copy>.hero-actions{animation:hero-copy-arrive 1.2s cubic-bezier(.22,1,.36,1) .95s backwards}
 .hero-copy:focus-within>*,.hero.hero-revealed .hero-copy>*{animation:none}
}
@keyframes hero-copy-arrive{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
/* The overlay holds as the window narrows rather than bailing to a stacked
   layout: the copy column takes a slightly larger share, moves closer to the
   edge, and the headline scales down, so it stays clear of her face. It only
   unwinds at 700px, where the photo genuinely can't host the copy. */
@media(max-width:1000px){
 /* copy runs to ~58% here rather than 50%, so the scrim has to reach further */
 .hero-media::after{background:linear-gradient(90deg,rgba(20,19,17,.78) 0%,rgba(20,19,17,.66) 46%,rgba(20,19,17,0) 88%)}
 .hero-copy{width:min(560px,50%);gap:20px}
 .hero-copy .display{font-size:clamp(32px,4.8vw,60px)}
 .hero-copy .lede{font-size:17px;max-width:none}
 .hero-actions{gap:14px}
}
@media(max-width:820px){
 /* narrowest overlay band: copy reaches ~58% and her hair is brightest here */
 .hero-media{height:min(66.67vw,720px,84vh)}
 .hero-media::after{background:linear-gradient(90deg,rgba(20,19,17,.84) 0%,rgba(20,19,17,.74) 54%,rgba(20,19,17,0) 96%)}
 .hero-copy{width:min(560px,54%)}
 .hero-copy .lede{font-size:16px}
}

/* Blend the cropped photo inside the rounded hero frame. */
@media(min-width:701px){
 :root{--hero-inset:56px;--col-left:calc(max((100vw - var(--max)) / 2, 0px) + var(--gutter));--frame-left:max(12px,calc(var(--col-left) - var(--hero-inset)))}
 .hero{padding-top:0}
 .hero .wrap{padding-bottom:48px;max-width:none;padding-left:var(--frame-left);padding-right:var(--frame-left)}
 .hero-copy{left:calc(var(--col-left) - var(--frame-left))}
 .hero-media{background:#243029;border-radius:24px}
 .hero-photo{object-position:88% 30%;left:5%;width:95%;mask-image:linear-gradient(90deg,transparent 4%,rgba(0,0,0,.18) 34%,rgba(0,0,0,.7) 52%,#000 66%,#000 92%,rgba(0,0,0,.6) 100%);-webkit-mask-image:linear-gradient(90deg,transparent 4%,rgba(0,0,0,.18) 34%,rgba(0,0,0,.7) 52%,#000 66%,#000 92%,rgba(0,0,0,.6) 100%)}
 .hero-media::after{display:none}
}

/* Center the hero itself; reserve room above it for the sticky menu. */
@media(min-width:1101px){
 .homepage{--desktop-hero-height:clamp(540px,calc(100svh - 158px),780px);padding-top:max(0px,calc((100svh - var(--desktop-hero-height))/2 - 79px))}
 .homepage .site-header{position:sticky;top:0;background:rgba(255,255,255,.82);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-bottom-color:transparent}
 .hero{padding:0 0 max(79px,calc((100svh - var(--desktop-hero-height))/2))}
 .hero .wrap{width:100%;padding-bottom:0}
 .hero-media{height:var(--desktop-hero-height)}
}

/* Keep overlaid copy legible as the photo and text converge on tablets. */
@media(min-width:701px) and (max-width:1000px){
 .hero-media::after{display:block;background:linear-gradient(90deg,rgba(20,19,17,.6) 0%,rgba(20,19,17,.5) 58%,transparent 90%)}
}

/* worry — copy left, a bare iMessage thread floating right. */
.worry .wrap{padding-top:var(--section-pad);padding-bottom:var(--section-pad)}
.worry .grid-2{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:start;gap:80px}
.worry .stack{max-width:560px}
.thread-col{display:flex;justify-content:center}
.thread{display:flex;flex-direction:column;width:min(100%,400px);font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","Helvetica Neue",var(--sans);}
.thread-day{margin:0;text-align:center;font-size:12px;font-weight:600;color:#8a8a8e;padding:22px 0 8px}
.thread-day:first-child{padding-top:0}
.thread-day span{font-weight:400}
.bubble{position:relative;max-width:82%;padding:10px 14px;border-radius:20px;font-size:17px;line-height:1.3;letter-spacing:-.01em;text-wrap:pretty}
.bubble+.bubble{margin-top:6px}
.bubble.me{align-self:flex-end;background:#0a84ff;color:#fff;border-bottom-right-radius:6px}
.bubble.them{align-self:flex-start;background:#e9e9eb;color:#141311;border-bottom-left-radius:6px;margin-top:32px}
.tapback{position:absolute;top:-24px;right:-22px;width:42px;height:44.4px;pointer-events:none}
.tapback svg{display:block;width:100%;height:100%}
.thread-status{margin:5px 6px 0 0;align-self:flex-end;font-size:12px;color:#8a8a8e}
/* Reserve the conversation's height while Tuesday's messages arrive once. */
@media(min-width:701px) and (prefers-reduced-motion:no-preference){
 .thread-animated [data-thread-reveal]{opacity:0;transform:translateY(8px)}
 .thread-animated.is-playing [data-thread-reveal]{animation:thread-arrive .36s ease-out var(--message-delay,0ms) both}
}
@keyframes thread-arrive{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
@media(max-width:1000px){.worry .grid-2{gap:48px}}

/* Alternatives: open layout with content on the shared column. */
#alternatives .wrap{padding-top:72px;padding-bottom:72px}
#alternatives .grid-2{align-items:start}
@media(min-width:801px){#alternatives .grid-2{grid-template-columns:minmax(0,1fr) minmax(0,2fr)}}
#alternatives .rows{margin-top:8px}
#alternatives .row:last-child{border-bottom:1px solid var(--rule)}
#system .system-head-wrap{padding-top:var(--section-pad);padding-bottom:0}
#system .section-head{max-width:none}
#system .system-scene-wrap{padding-top:48px;padding-bottom:0}
#system .system-routine-wrap{padding-top:88px;padding-bottom:var(--section-pad)}
#system .routine-layout>.stack .h3{font-size:clamp(26px,2.4vw,32px)}
#system .routine-layout>.stack .body{max-width:440px;color:var(--ink-3)}
/* system — one wide scene, same frame bleed as the hero. Captions float freely
   over the photo as cards; hairline leaders (SVG, % coords) run from each card
   to a dot on its device. Move a card with left/top below and update the
   matching polyline's points and .note-dot left/top in the markup. */
.scene{position:relative;margin:0;width:100%;aspect-ratio:3/2;border-radius:24px;overflow:hidden;background:#e9ece7}
.scene>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.scene-leaders{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.scene-leaders polyline{fill:none;stroke:#fff;stroke-width:1.5;stroke-linejoin:round;vector-effect:non-scaling-stroke;filter:drop-shadow(0 0 1px rgba(0,0,0,.35))}
.scene-tablet-leaders{display:none;pointer-events:none}
.scene-tablet-leaders ellipse{fill:#fff}
.note-dot{position:absolute;width:10px;height:10px;margin:-5px 0 0 -5px;border-radius:50%;background:#fff;box-shadow:0 0 0 3px rgba(255,255,255,.35),0 1px 3px rgba(0,0,0,.3)}
.scene-note{position:absolute;padding:20px 22px;border-radius:14px;background:rgba(255,255,255,.94);color:var(--ink);box-shadow:0 8px 30px rgba(20,26,22,.18);backdrop-filter:blur(6px)}
.note-hub{left:6%;top:64%;width:26%}
.note-sensor{left:56%;top:66%;width:28%}
.device-porthole{display:none}
.scene-note .h4{font-size:22px}
.scene-note .body{font-size:15px;line-height:1.5}
@media(min-width:701px){#system .system-scene-wrap{max-width:none;padding-left:var(--frame-left);padding-right:var(--frame-left)}}
/* Below 1000px the photo is too short to host the captions — they drop below
   the image onto the dark band. */
@media(max-width:1000px){
 .scene{aspect-ratio:auto;background:var(--band)}
 .scene>img{position:relative;aspect-ratio:3/2;display:block}
 .scene-leaders,.note-dot{display:none}
 .scene-notes{display:grid;grid-template-columns:1fr 1fr;gap:32px 40px;padding:40px 40px 48px;background:var(--band)}
 .scene-note{position:static;width:auto;padding:0;border-radius:0;background:none;box-shadow:none;backdrop-filter:none;color:#fff}
 .scene-note .h4{color:#fff}
 .scene-note .body{color:rgba(255,255,255,.9)}
}
@media(min-width:701px) and (max-width:1000px){
 .scene-tablet-leaders{display:block;height:auto;aspect-ratio:3/2}
 .scene-notes{position:relative}
 .scene-notes::before,.scene-notes::after{content:"";position:absolute;top:0;height:24px;width:1.5px;background:#fff;transform:translateX(-50%)}
 .scene-notes::before{left:25%}
 .scene-notes::after{left:75%}
}
@media(min-width:701px) and (max-width:1100px){
 #system .routine-layout{grid-template-columns:1fr;gap:32px}
 #system .routine-layout>.stack .body{max-width:none}
}
@media(max-width:700px){
 #system .system-routine-wrap{padding-top:56px}
 .scene{border-radius:0;background:none;overflow:visible}
 .scene>img{display:none}
 .scene-notes{grid-template-columns:1fr;padding:0;gap:32px;background:none}
 .scene-note{gap:0;background:var(--band);border-radius:20px;overflow:hidden}
 .scene-note .h4{color:#fff;margin:28px 20px 12px}
 .scene-note .body{color:rgba(255,255,255,.9);margin:0 20px 32px}
 .device-porthole{display:block;position:relative;width:100%;aspect-ratio:3/2;overflow:hidden;margin:0;background:#e9ece7}
 .device-porthole img{width:100%;height:100%;object-fit:cover}
 .porthole-hub img{object-position:50% 45%}
 .porthole-sensor img{object-position:50% 45%;transform:scale(1.4)}
}
@media(max-width:700px){#alternatives .wrap{padding-top:48px;padding-bottom:48px}}

/* phone bezel. Fixed padding: a percentage would resolve against the parent,
   so the bezel would thicken with the column. */
.phone{width:100%;max-width:260px;aspect-ratio:9/19.5;background:#2b2b2e;border-radius:15.5%/7.2%;padding:7px;position:relative;
  box-shadow:inset 0 0 0 1.5px #55565a,inset 0 0 0 3px #17171a,0 30px 60px -28px rgba(20,19,17,.45)}
.phone-screen{width:100%;height:100%;border-radius:13.5%/6.3%;overflow:hidden;background:#000;position:relative}
.phone-screen img{width:100%;height:100%;object-fit:cover;object-position:top}

/* lists with hairlines */
.rows{display:grid}
.row{display:grid;gap:24px;padding:22px 0;border-top:1px solid var(--rule)}
.row-alt{grid-template-columns:minmax(140px,200px) minmax(0,1fr)}
/* Lists that span the full content width cap their prose at a readable measure
   instead of letting it stretch to ~120 characters; the hairlines still run
   the full width. Capping the text rather than the grid track on purpose: a
   grid-template-columns override here would outrank the single-column mobile
   rule below and keep the row two-up on phones. */
.rows-wide .body{max-width:620px}
.row-alt .name{font-family:var(--serif);font-size:22px;text-decoration:line-through;text-decoration-color:rgba(30,42,36,.42);text-decoration-thickness:1px;color:var(--ink)}
#alternatives .row-alt .body{color:var(--ink-2)}
/* Numbered routine rows: editorial type and fine dividers. */
.routine-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.25fr);gap:72px;align-items:start}
.routine-list{list-style:none;margin:0;padding:0;counter-reset:routine}
.routine-item{counter-increment:routine;display:grid;grid-template-columns:40px minmax(0,1fr);gap:16px;padding:24px 0;border-top:1px solid var(--rule)}
.routine-list>.routine-item:last-child{border-bottom:1px solid var(--rule)}
.routine-item::before{content:counter(routine,decimal-leading-zero);font-family:var(--serif);font-size:20px;line-height:1.35;color:var(--green)}
.routine-copy{display:flex;flex-direction:column;gap:8px}
.routine-copy h3{font-family:var(--serif);font-weight:400;font-size:24px;line-height:1.2;letter-spacing:-.015em}
.routine-copy .body{font-size:16px;line-height:1.6;max-width:560px}
@media(max-width:1000px){.routine-layout{grid-template-columns:1fr;gap:32px}}

/* app */
/* Keep all three app screens together on tablet and desktop. */
.screens{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:32px}
@media(min-width:701px) and (max-width:1000px){.screens{gap:20px}}
@media(max-width:700px){.screens{grid-template-columns:1fr;gap:44px}}
/* Caption is capped to the phone's width and centred with it, so its left edge
   lines up with the screenshot instead of hanging off to the left. Both read
   one variable: the global mobile rule shrinks .phone to 220px, which would
   otherwise leave the caption wider than the screenshot it belongs to. */
.screens{--phone-w:260px}
.screens figure{margin:0;display:flex;flex-direction:column;gap:20px;align-items:center}
.screens .phone{max-width:var(--phone-w)}
.screens figcaption{display:flex;flex-direction:column;gap:6px;width:100%;max-width:var(--phone-w)}
.screens figcaption b{font-family:var(--serif);font-weight:500;font-size:22px;letter-spacing:-.01em}
.screens figcaption span{font-size:15px;line-height:1.5;color:var(--ink-3)}

/* Tablet response: full-width introduction, then steps beside the photo. */
@media(min-width:701px) and (max-width:1000px){
 #response .grid-2{grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:24px 32px;align-items:start}
 #response .grid-2>.stack{display:contents}
 #response .grid-2>.stack>.eyebrow,
 #response .grid-2>.stack>h2,
 #response .grid-2>.stack>.body-lg{grid-column:1/-1}
 #response .routine-list{grid-column:1;grid-row:4}
 #response .grid-2>img{grid-column:2;grid-row:4;align-self:start}
}

/* ---- buy.html -----------------------------------------------------------
   The paid call to action, which is its own page rather than a homepage
   section: #buy while the batch is open, #sold-out once it is not. .wrap, .grid-2,
   .stack, .eyebrow, .h3, .btn and .photo are reused as-is; only the patterns
   this file had no equivalent for live here. The heading shares the .waitlist
   .h3 scale step below rather than redeclaring the same clamp. */
.buy{background:#fff;color:var(--ink)}
/* height:auto is load-bearing, not tidying. The img carries width/height
   attributes to reserve layout space, and those presentational hints give it a
   used height, which makes the browser ignore .photo-4x5's aspect-ratio -- the
   photo rendered at its full 1536px intrinsic height. .testimonial-photo needs
   the same line for the same reason. */
.buy-photo{border-radius:18px;height:auto}

/* The copy column runs to roughly twice the photo's natural height, so a fixed
   4:5 crop leaves dead space whichever way the row is aligned: a gap underneath
   when top-aligned, two smaller gaps when centred. Where the grid genuinely has
   two columns, let the photo fill the taller one instead.

   920px is not a round number picked by eye, it is exactly where .grid-2 gains
   its second column: two 400px tracks + its 64px gap + two 28px .wrap gutters.
   The gate matters because below it the photo is alone in its row, where
   height:100% resolves against an indefinite row height, falls back to auto,
   and renders the image at its full 1536px intrinsic height all over again.
   min-height keeps the crop from collapsing if this copy is ever cut short. */
@media (min-width:920px){
  #buy .grid-2{align-items:stretch}
  .buy-photo{height:100%;min-height:520px;aspect-ratio:auto;object-position:52% 42%}
}
.buy-lede{font-size:clamp(18px,1.4vw,20px);line-height:1.6;text-wrap:pretty;color:var(--ink-3)}

/* The deposit terms, as a timeline. Same ruled-row construction as .buy-item
   above it, one size down, so the two blocks read as one column rather than as
   two unrelated lists. */
.buy-summary{font-size:clamp(20px,1.6vw,22px);line-height:1.4;font-weight:600;letter-spacing:-.01em;color:var(--ink);text-wrap:pretty}
.buy-terms{display:flex;flex-direction:column;margin:0}
.buy-term{display:flex;gap:20px;padding:14px 0;border-top:1px solid var(--rule)}
.buy-terms .buy-term:last-child{border-bottom:1px solid var(--rule)}
.buy-term-label{flex:none;width:110px;font-size:13px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);padding-top:4px}
.buy-term-copy{margin:0;font-size:17px;line-height:1.55;color:var(--ink-3);text-wrap:pretty}

.buy-included{display:flex;flex-direction:column}
.buy-included-label{font-size:13px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);padding-bottom:4px}
/* Rules between items and after the last one, so the list reads as a closed
   block. A trailing element in the markup would be a non-semantic spacer. */
.buy-item{display:flex;gap:20px;align-items:center;padding:20px 0;border-top:1px solid var(--rule)}
.buy-included .buy-item:last-of-type{border-bottom:1px solid var(--rule)}
.buy-item-name{font-family:var(--serif);font-weight:400;font-size:24px;line-height:1.2;letter-spacing:-.015em;margin:0}
.buy-item-copy{font-size:18px;line-height:1.5;color:var(--ink-3);text-wrap:pretty}

.buy-thumb{width:84px;height:84px;flex:none;border-radius:8px;object-fit:cover;object-position:50% 53%;display:block}
.buy-thumb-sensor{object-position:50% 45%}
/* The app thumb is a phone screenshot, not a crop: it sits small and top-aligned
   in a tinted well so the status bar and first card read at this size. */
.buy-thumb-app{overflow:hidden;background:var(--band-soft);display:flex;justify-content:center;padding-top:12px}
.buy-thumb-app img{width:46%;height:auto;align-self:flex-start;border-radius:5px;display:block}

/* Shared by three buttons: /buy's purchase button, the homepage panel's, and
   /buy's sold-out "Become a tester". Only the size is shared -- the shape below
   is keyed to [data-buy-cta], because only the first two are purchases. */
.buy-cta{font-size:18px;padding:18px 32px;align-self:flex-start}

/* The purchase button, on /buy and in the homepage panel. It fills its column
   rather than sizing to its own label -- it was label-width until 2026-10-30,
   which left the page's only purchase sitting small at the foot of a tall
   column -- and the squared corners follow from that: .btn's 999px radius is
   drawn for a pill sized to its label, and stretched this wide the ends stop
   reading as a rounded button and start reading as a lozenge.

   6px, not 8px, and not a new value: .card .btn, .card input and
   .prefix are already 6px, which is this site's radius for a control
   that fills its container. 8px would have been a third button shape competing
   with the signup card's button in the very same grid slot, and it is also the
   radius of .card and .buy-panel themselves, so the button would have shared a
   corner with the box around it instead of nesting inside it.

   Keyed to the attribute rather than .buy-cta because /buy's sold-out button
   carries that class too. It sits in a <p>, so align-self is inert there and it
   would have kept the squared corners at label width -- neither a pill nor a
   filled control. It stays a .btn pill, which is what a fallback should be. */
[data-buy-cta].buy-cta{align-self:stretch;text-align:center;border-radius:6px}

/* The sold-out state has no photo column, so it sets its own measure rather
   than filling the full content width at a readable line length. */
.buy-soldout{max-width:620px}

@media (max-width:700px){
  .buy-item{gap:16px}
  /* /buy's sold-out "Become a tester" keeps the pill, but it still fills the
     screen on a phone like every other full-width control here. It sits in a
     <p>, so align-self cannot do this for it -- width can. */
  .buy-cta{width:100%;text-align:center}
  /* A 110px label column plus a sentence does not fit a phone, so the label
     sits above its row rather than beside it. */
  .buy-term{flex-direction:column;gap:6px}
  .buy-term-label{width:auto;padding-top:0}
}

/* The early-access section, inline on the homepage: the copy on the left and,
   in the slot on the right, whichever of the two halves the batch calls for --
   the purchase panel while it is open, the signup form once it closes.

   The hairline is the join with the testimonial above it, which opens the same
   dark band; see the testimonial block at the foot of this file. */
.waitlist{background:var(--band);color:#fff}
.waitlist>.wrap{border-top:1px solid rgba(255,255,255,.14)}
.waitlist .grid-2{align-items:start}
/* Both halves stay top-aligned. Centring the copy against the purchase panel
   was tried and reverted: the panel runs roughly twice the copy's height, so
   centring moves the empty band from below the lede to above the eyebrow --
   between the section's own hairline and its first word, which is where the
   eye enters. Empty space under the last line of a column reads as margin;
   the same space above the heading reads as a mistake. Worst at ~960px, where
   the panel is at its narrowest and therefore its tallest. */
.waitlist .h3,.buy .h3{font-size:clamp(40px,4.5vw,64px);line-height:1.02}
.waitlist .body-lg{color:var(--band-soft)}
.waitlist-signup{display:grid;gap:32px;min-width:0}

/* The purchase panel: /buy's column, condensed to sit in that slot. It reuses
   that page's patterns wholesale -- .buy-included, .buy-item, .buy-cta,
   .buy-terms -- and only steps the sizes down, so a change to the shape of
   either one moves both and they cannot drift apart visually.

   White on the dark band rather than the band's own surface, matching the
   signup card it replaces: these are the two places on the page where a
   visitor acts, and both read as a panel laid on the band. */
/* max-width only bites between 701px and 919px, where .grid-2 has collapsed to
   one column but the panel has not yet been given the phone treatment: without
   it the panel runs the full ~845px content width and its 15px prose reaches
   nearly 90 characters a line, where the same copy on /buy is held to a ~560px
   grid track. Above 920px the track is narrower than this anyway. */
.buy-panel{background:#fff;color:var(--ink);border-radius:8px;padding:32px;display:flex;flex-direction:column;gap:24px;min-width:0;max-width:560px}
.buy-panel .buy-item{gap:16px;padding:14px 0}
.buy-panel .buy-thumb{width:60px;height:60px}
/* The photographic thumbs crop fine at any size; the app thumb is a whole-phone
   screenshot, so stepping the well down from /buy's 84px to 60px without
   widening the screenshot inside it would leave it at ~28px -- a light smudge
   rather than a phone. 62% holds it at roughly the pixel size it has on /buy. */
.buy-panel .buy-thumb-app{padding-top:8px}
.buy-panel .buy-thumb-app img{width:62%}
.buy-panel .buy-item-name{font-size:20px}
.buy-panel .buy-item-copy{font-size:15px;line-height:1.45}
/* Shape comes from [data-buy-cta].buy-cta above, which /buy's purchase button
   and this one share; only the size steps down. */
.buy-panel .buy-cta{font-size:17px;padding:16px 28px}
.buy-panel .buy-term{gap:14px;padding:12px 0}
/* 12px is the smallest size the site already uses (.scroll-hint, .thread-day,
   .footer-contact-label). 11px would have been a new floor, on the hardest
   combination to read small: uppercase, letter-spaced, in --muted. */
.buy-panel .buy-term-label{width:88px;font-size:12px;padding-top:4px}
.buy-panel .buy-term-copy{font-size:15px;line-height:1.5}
/* Stack the panel's terms below 1052px. That number is the panel's width, not
   the viewport's: .grid-2 goes two-up at 920px, so the panel is at its
   NARROWEST just above that (a ~400px track, ~234px left for the sentence once
   the 32px padding and the 88px label column are taken) and at its widest
   between 701px and 919px, where it is alone in a single-column grid. Keying
   this to max-width:700px alone would have left the squeeze untouched and
   fixed the width where there was none. 1052 is where the sentence clears
   300px: track >= 466, i.e. viewport >= (466 * 2) + 120.

   This also carries the phone case, so the panel needs no label rule in the
   block below -- it would have had to repeat itself there anyway, because the
   88px override above sits outside any query and outranks the bare
   .buy-term-label inside one. */
@media(max-width:1052px){
  .buy-panel .buy-term{flex-direction:column;gap:6px}
  .buy-panel .buy-term-label{width:auto;padding-top:0}
}
@media(max-width:700px){
  .buy-panel{padding:24px;gap:20px}
  .buy-panel .buy-item{padding:12px 0}
  .buy-panel .buy-thumb{width:52px;height:52px}
}
/* The default green eyebrow sits at roughly 1.5:1 on the dark band — illegible
   and a WCAG failure. Lift it onto the band's light token. */
.waitlist .eyebrow{color:var(--band-soft)}
.card{background:#fff;color:var(--ink);border-radius:8px;padding:36px;display:flex;flex-direction:column;gap:18px}
.card label{font-size:14px;font-weight:600;color:var(--ink-2)}
.field{display:flex;gap:10px}
.card input:not([type="checkbox"]){flex:1;min-width:0;padding:14px 16px;border:1px solid var(--field);border-radius:6px;font-size:16px;font-family:inherit;background:#fff;color:var(--ink);outline:none}
.card input:not([type="checkbox"]):focus{border-color:var(--green)}
.prefix{display:flex;align-items:center;padding:0 14px;border:1px solid var(--field);border-radius:6px;font-size:16px;color:var(--muted);background:#fff}
.card .field+.fine{margin-top:-8px}
/* The texting checkboxes (views/partials/sms_consent.html), on the homepage
   card and on /welcome. The whole label is the hit area. */
.sms-consent{display:flex;flex-direction:column;gap:10px}
.sms-consent .consent-choice{display:flex;align-items:flex-start;gap:10px;font-size:15px;font-weight:400;line-height:1.45;color:var(--ink);cursor:pointer}
.sms-consent input{flex:none;width:18px;height:18px;margin:2px 0 0;accent-color:var(--green)}
.sms-consent .fine a{color:inherit;text-decoration:underline}
.sms-consent input[aria-invalid="true"]{outline:2px solid #a12d25;outline-offset:2px}
.card .btn{border-radius:6px;padding:16px;background:var(--band)}
.card .btn:hover{background:var(--green-dark)}
.fine{font-size:13px;color:var(--muted);line-height:1.5}
.site-footer{background:var(--band);color:var(--band-text)}
.site-footer .wrap{padding:48px var(--gutter) 32px;border-top:1px solid rgba(255,255,255,.14);display:flex;flex-direction:column;gap:40px;font-size:14px}
.footer-top{display:flex;justify-content:space-between;align-items:flex-start;gap:40px 56px}
.footer-intro{display:grid;gap:8px;max-width:320px}
.footer-contact-label{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--muted-2)}
.footer-intro a{color:#fff;font-weight:600;width:fit-content}
.footer-intro a:hover{text-decoration:underline}
.footer-links{display:flex;flex-direction:column;gap:12px;text-align:right}
.footer-links a{font-size:15px;font-weight:500;transition:color .2s ease}
.footer-bottom{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:16px}
.site-footer .logo{font-family:var(--serif);font-size:24px;color:#fff}
.footer-copyright{font-size:13px;color:var(--muted-2)}
.site-footer a{text-decoration:none;color:var(--band-text)}.site-footer a:hover{color:#fff}

/* Production integration: form feedback, keyboard and mobile layouts. */
.nav-links a.btn{color:var(--ink)}.nav-links a.btn:hover{color:#fff}
.brand{flex-shrink:0}
.btn:disabled{opacity:.5;cursor:not-allowed}
.card[data-submitting="true"] .btn:disabled{cursor:wait}
.form-status{font-size:14px;line-height:1.5}
.form-status:empty{display:none}
/* The signup honeypot: off-screen, so people never see or tab into it. */
.hp{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}
.form-status[data-status="error"]{color:#a12d25}
.form-status[data-status="success"]{color:var(--green)}
a:focus-visible,button:focus-visible,input:focus-visible{outline:3px solid #b68b35;outline-offset:4px}
.skip-link{position:fixed;top:8px;left:8px;z-index:20;padding:12px;background:#fff;transform:translateY(-160%)}
.skip-link:focus{transform:translateY(0)}
@media(max-width:900px){
 .nav-links>a:not(.btn){display:none}
 .nav-links{gap:0;flex-wrap:nowrap}
}
/* ---- Mobile (≤700px) — from "Garden A - Mobile" design, Sept 2026 ---- */
@media(max-width:700px){
 /* Header, hero and sections share the mobile gutter. */
 :root{--gutter:20px;--section-pad:88px;--edge:20px}
 .section .wrap{padding-bottom:72px}
 .display{font-size:44px;line-height:1}
 .h2{font-size:34px}.h2-sm{font-size:30px}.h3{font-size:28px}.h4{font-size:24px}
 .lede{font-size:17px;max-width:none}.body-lg{font-size:16px}.body{font-size:15px;line-height:1.55}
 .grid-2,.grid-2.tight,.grid-2.wide{gap:28px;align-items:start}
 /* header: static (not sticky), brand + CTA only */
 .site-header{position:static;background:#fff;backdrop-filter:none}
 .site-header nav{gap:14px;padding-top:12px;padding-bottom:12px}
 .brand{font-size:26px}
 /* hero: too narrow to host the copy over the photo — unwind the overlay to
    photo first (4:3), copy below on white, full-width CTA */
 .hero{padding-top:16px}
 .hero .wrap{padding-bottom:48px}
 .hero-copy{padding:0}
 .hero-media{height:auto;overflow:visible;background:none;display:flex;flex-direction:column;gap:24px}
 .hero-media::after{display:none}
 .hero-photo{position:static;height:auto;aspect-ratio:4/3;border-radius:20px;object-position:80% 25%}
 .hero-copy{position:static;transform:none;left:auto;top:auto;width:auto;max-width:none;gap:24px}
 .hero-copy .display{color:var(--ink);font-size:44px}
 /* Accent and primary CTA take the header CTA's darker green (--band) rather
    than --green: on the stacked mobile hero they sit directly under the
    "Become a tester" pill, and the two greens read as a mismatch side by side. */
 .hero-copy .accent{color:var(--band)}
 .hero-copy .lede{color:var(--ink-3);font-size:17px;max-width:none}
 .hero-copy .link-ul{color:var(--ink);border-bottom-color:var(--ink)}
 .hero-copy .btn{background:var(--band);color:#fff}.hero-copy .btn:hover{background:var(--ink-2)}
 .hero-actions{flex-direction:column;align-items:center;gap:14px}
 .hero-actions .btn{width:100%;text-align:center}
 .hero-actions .link-ul{padding:4px 0;font-size:15px}
 /* worry: copy above the phone */
 .worry .wrap{padding-top:64px}
 .worry .grid-2{gap:32px;grid-template-columns:1fr}
 .worry .stack{max-width:none}
 .thread-col{order:2}
 .bubble{font-size:16px}
 .phone{max-width:220px}
 /* lists */
 .row-alt{grid-template-columns:1fr;gap:6px;padding:18px 0}
 .row-alt .name{font-size:20px}
 .routine-item{grid-template-columns:40px minmax(0,1fr);gap:14px;padding:22px 0}
 .routine-item::before{font-size:18px}
 .routine-copy{gap:10px}
 .routine-copy h3{font-size:21px}
 .routine-copy .body{font-size:15px;line-height:1.55}
 /* emergency: eyebrow → heading → intro → photo → steps.
    The stack is dissolved with display:contents, so its children become grid
    items and need explicit order. Without the eyebrow rule it would default to
    0 and render below its own heading. */
 #response .grid-2>img{order:0;aspect-ratio:4/3}
 #response .grid-2>.stack{display:contents}
 #response .grid-2>.stack>.eyebrow{order:-2}
 #response .grid-2>.stack>h2{order:-1}
 #response .grid-2>.stack>.routine-list{order:1}
 /* waitlist + footer */
 .waitlist .h3{font-size:38px}
 .card{padding:24px;gap:16px}
 .site-footer .wrap{gap:32px;padding:40px var(--gutter) 32px}
 .footer-top{flex-direction:column;gap:28px}
 /* Two columns filled top-to-bottom, not left-to-right. The nav is seven
    links, and row-flow put the seventh alone on a fourth row and split
    Privacy Policy from Terms of Service across rows. Column-flow fills four
    then three, which keeps the two legal links together at the foot of the
    second column and leaves no orphan. Row count is pinned to the roster
    like .team-grid's column count is: at seven links, four is the split that
    fills the first column. Revisit it if the nav grows. */
 .footer-links{display:grid;grid-template-columns:1fr 1fr;grid-auto-flow:column;grid-template-rows:repeat(4,auto);gap:12px 16px;text-align:left}
}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.btn,.scroll-hint{transition:none}}

/* The family testimonial opens the dark band that runs on through the
   early-access section to the footer. It used to sit the other way round, and
   with it the hairline that separates the two: whichever of the pair comes
   second carries the rule, and the first one carries the band's top padding. */
#testimonial{background:var(--band);color:#fff}
#testimonial .wrap{padding-bottom:calc(var(--section-pad) / 2)}
.testimonial{margin:0;align-items:center}
.testimonial-photo{object-position:50% 30%;height:auto}
.testimonial-quote{margin:0;text-indent:-.4em;color:#fff}
#testimonial .eyebrow{color:var(--band-soft)}
#testimonial .testimonial-name{font-weight:600;color:#fff}
@media(min-width:801px){.testimonial{grid-template-columns:minmax(0,5fr) minmax(0,7fr)}.testimonial-photo{max-width:400px}}
@media(min-width:701px) and (max-width:1100px){.testimonial{grid-template-columns:minmax(0,1fr) minmax(0,2fr);gap:32px;align-items:start}}
@media(max-width:700px){.testimonial-photo{width:200px;max-width:100%;aspect-ratio:4/3}}
