/* ============================================================
   SAAGA — shared stylesheet for every page on the site.

   Linked by saaga-website.html, for-women.html and for-practitioners.html.
   It used to live inline in the homepage; three pages each carrying their own
   copy would drift the moment a token changed, which is the whole reason this
   is a file. Change a value here and all three pages follow.

   No build step. To port to Wix / Webflow / Framer, paste this once into the
   site-wide custom CSS rather than into each page.
   ============================================================ */
:root{
  --white:#ffffff;
  /* THE WARM FILTER. Every photograph and the film carry the same slight warm
     cast, so they sit in the page's light rather than in a studio's. Sepia at
     this strength tints without yellowing; the saturation lift keeps skin from
     going flat under it. Was sepia(.07); the founder asked for a bit more. */
  --warm-photo:sepia(.16) saturate(1.06);
  --paper:#FCFBF8;      /* large blocks only, never the page ground */
  --paper-2:#EFE9E1;    /* second block tone, warmer stone */
  --paper-3:#F9F7F2;    /* third block tone */
  /* ============ ACCENT — Clay · ACTIVE ============
     The apricot went. It was the yellowest thing on a page already leaning
     yellow, and it belonged to nothing: no screen in either product used it.
     The replacement is not a new colour — it is the product's own clay-pink,
     #C9927F, one of the five category colours the member app has always drawn
     with. Warm, unmistakably women's health without being pink-pink, and it
     ties the site to the thing it is selling.

     #C9927F itself is 2.7:1 behind white, so it stays decorative. --accent is
     the same hue taken down to 4.9:1, which is what buttons and links use.

     Still STRICTLY an accent: the nav CTA, primary buttons on a light ground,
     links, hover, the focus ring. It never fills a section, never carries
     meaning, never codes a status or a category.

       --accent        primary buttons on light grounds, the nav CTA.
                       #BD7251 is 3.7:1 behind white text, matching Perelel rather than AA.
       --accent-dark   hover and links. 6.59:1 on white.
       --accent-light  the product's clay-pink itself. DECORATIVE ONLY at
                       2.66:1 — a mark, a rule, a dot. Never behind text.
       --accent-pale   deliberately NOT tinted. The slot exists for a section
                       fill, and a whole orange section is not an accent, so
                       it holds a warm paper instead. Tint it only if the
                       "one section per page" rule is reinstated.

     Buttons sitting on photography stay white — the hero and the close — since
     white reads harder on a dark film than the accent does, and it keeps the
     accent rare.

     Before shipping any other season, re-run both checks:
       white text on --accent      >= 4.5:1
       --accent-dark on white      >= 4.5:1
     ------------------------------------------------------------------- */
  --accent-pale:#F1DFD8;    /* the one large tinted block per page */
  --accent-light:#C9927F;   /* the product's own clay-pink. Decorative only at 2.7:1 */
  --accent:#BD7251;         /* Perelel's #C07859, two points darker. 3.7:1 behind white — same as theirs, under AA */
  --accent-ink:#ffffff;     /* what goes ON the accent. 4.9:1 */
  --accent-dark:#945438;    /* rim, hover, links, small labels, focus. 5.86:1 */

  --acc:var(--accent);        /* primary action, the vivid step */
  --acc-deep:#3B362F;
  --stone:#635A52;
  /* --clay carries real text: pricing notes, captions and the legal line.
     The old #a89f8d sat at 2.7:1 on white, which is not readable. This clears
     5.07:1 on white and 4.53:1 on paper. */
  --clay:#7A6B5E;
  /* On the beige, --stone drops to 4.2:1 and --clay to 3.3:1. These are the
     same tones taken one step darker so body copy and captions still clear
     4.5:1 when a section is filled with the brand colour. */
  --stone-deep:#575049;
  --clay-deep:#5D5347;
  --ink:#3A342E;              /* warm dark grey — never pure black (brand rule) */
  --line:#E6DED4;   /* the one place a little more warmth is welcome */
  --sans:'Poppins',-apple-system,BlinkMacSystemFont,sans-serif;
  --serif:'Playfair Display',Georgia,serif;  /* wordmark only */
  /* 100vw counts the scrollbar; the layout wants the width the content
     actually gets. saaga.js overwrites this with documentElement.clientWidth,
     and 100vw is the fallback if the script never runs — a few px out at some
     widths, which is what it was before, rather than broken. */
  --vw:100vw;
  --pad:clamp(18px,4vw,56px);
  --maxw:1240px;
  /* ============ CANVAS ============
     Every shape on the page shares one gutter and one corner radius.
     Change these two values and the whole page re-proportions. */
  --gap:clamp(14px,1.7vw,26px);
  --r:clamp(22px,2.5vw,38px);
  /* ============ THE BRAND COLOUR ============
     #d9d0c1 is SAAGA's beige. It is the ground the whole site sits on and
     one full-width block mid-page, so it reads as the brand colour rather
     than as a background tint. Large text on it clears 7.6:1 against --ink;
     body copy in --stone only reaches 4.2:1, so never set small grey text
     directly on the beige — put it in a white shape. */
  --brand:#F5F3EC;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
/* ============ THE GROUND ============
   Fixed to the viewport, so it never scrolls. Everything else is a shape
   that slides over it. The strip of ground showing in the gutters is the
   page — this is why nothing is allowed to touch the screen edge. */
html{background:var(--brand)}
body{background:transparent;color:var(--stone);font-family:var(--sans);font-weight:300;
  font-size:clamp(15px,1rem,16px);line-height:1.7;-webkit-font-smoothing:antialiased}
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  /* A lit wall, not a flat tint. Three layers, in order: a wide shaft of
     daylight crossing on the diagonal, a warm bloom where the light enters,
     and a soft falloff opposite it. All of it is fixed to the viewport, so
     the light stays put while the page moves over it — which is what makes
     it read as a room rather than as a gradient. Keep the shaft WIDE and
     low-contrast; the hard-edged version is .s-shaft, and one hard beam per
     page is the limit. */
  /* FLATTER. The diagonal shaft and the dark falloff are gone; one warm
     bloom where the light enters is all that is left, and it is faint. The
     page had too much going on behind the content — a lit wall, a hard beam,
     tinted blocks — and the founder asked for it fresher. A lighter sand with
     less painted on it is most of that. */
  background:
    radial-gradient(64% 56% at 12% 4%, rgba(255,246,228,.78) 0%, rgba(255,246,228,0) 60%),
    radial-gradient(58% 52% at 90% 84%, rgba(232,214,188,.55) 0%, rgba(232,214,188,0) 64%),
    var(--brand);
}

/* ============ SECTION FILLS ============
   Shapes alternate white and the brand beige down the page. The old paper
   tones sat within 3% of white, so section-to-section reads as one continuous
   surface — this is the value step that was missing. Text tones step down with
   it, because --stone does not clear 4.5:1 on the beige. */
/* Exactly the ground colour, and no lightening wash. These sections merge into
   the ground, so the page reads as white panels with open beige air between
   them — that alternation is the rhythm. Tinting them even slightly turns them
   back into near-white panels and the rhythm disappears, which is what happened
   the first time. A step DOWN from the ground is not an option either: it gains
   almost no value separation (1.1:1 vs white's 1.5:1) and drops body copy below
   4.5:1. */
/* .shape sets a white fill and is declared after this block, so this needs the
   extra specificity to win — a bare .beige loses the cascade and renders white. */
.shape.beige,.beige{background:transparent}
.beige p,.beige li,.beige dd{color:var(--stone-deep)}
.beige .note,.beige .g-cap,.beige cite,.beige .mock-cap,.beige .path-sub{color:var(--clay-deep)}
/* --line is lighter than the beige, so rules drawn in it disappear */
.beige .rows,.beige .row,.beige .numbered .col{border-color:rgba(90,83,70,.24)}

/* ============ SHAPES ============
   One rule governs every block on the page: same gutter, same radius.
   A shape's own fill is set by .block / .block-2 / .block-accent below,
   which are declared after this and therefore win. */
.shape{position:relative;margin:0 var(--gap) var(--gap);border-radius:var(--r);
  overflow:clip;background:var(--paper)}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{transition-duration:.01ms!important}}
.wrap{max-width:var(--maxw);margin:0 auto;padding-left:var(--pad);padding-right:var(--pad)}

/* ============ PAPER GRAIN ============
   Fixed film grain over the whole page. Tune with --grain (0 = off).
   Sits above content but ignores pointer events, so nothing breaks. */
:root{--grain:.38}
body::after{
  content:"";position:fixed;inset:0;pointer-events:none;z-index:200;
  opacity:var(--grain);mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23p)' opacity='.55'/%3E%3C/svg%3E");
}
@media print{body::after{display:none}}

/* ============ THE HIGHLIGHT ============
   Poppins carries every headline. Playfair italic marks ONE word inside it —
   the word the sentence turns on. It is an accent, not a second headline
   face, which is why it only ever appears mid-sentence and never alone.

   Rules, so it stays an accent:
     · At most one .hl per headline. Two highlights is no highlight.
     · Only where a single word carries the argument. Functional titles
       (the FAQ, the app, what we track) take none.
     · Never a whole phrase, never the entire headline.

   Playfair sets narrower and needs air, so it takes a nudge in size and a
   much looser track than the -.035em the surrounding Poppins runs at. */
.hl{font-family:var(--serif);font-style:italic;font-weight:400;
    font-size:1.03em;letter-spacing:-.008em}

/* TYPE — sans led, like the deck */
h1,h2,h3,h4{font-family:var(--sans);font-weight:300;color:var(--ink);letter-spacing:-.035em;line-height:1.02}
/* text-wrap:balance on every heading, not just the statements. Without it a
   heading breaks wherever the measure runs out, which left "Everything a
   women's health practice runs / on" — a two-letter last line. Balance splits
   the lines evenly instead, so no heading can strand its final word. */
h1{font-size:clamp(1.95rem,6vw,4.8rem);text-wrap:balance}
/* A step down from 48px. The hero's h1 and the two statements keep their
   scale; every section title under them was competing with them. */
h2{font-size:clamp(1.45rem,3.2vw,2.25rem);line-height:1.1;text-wrap:balance}
/* Display sizes keep the light 300 — at that scale it has presence. Sub-heads
   do not: at 1rem a 300 weight reads as body copy, which is why the column
   and row headings had no hierarchy against the paragraphs under them. */
h3{font-size:clamp(1.08rem,1.9vw,1.3rem);line-height:1.2;letter-spacing:-.02em;font-weight:500;text-wrap:balance}
h4{font-size:1rem;font-weight:500;letter-spacing:-.01em;line-height:1.3}
p{max-width:58ch}
a{color:inherit}

/* NAV */
/* A bar, not a lozenge. Full width, no radius, and see-through enough that the
   page runs underneath it — the faint blur is only there so type stays legible
   over busy footage. The tone flips with what is behind it: .over-dark for the
   film hero, plain for everything below. */
/* Blur only — no tint in either state. A paper-coloured plate made it a strip
   fastened to the top of the page; the blur alone lets the page run underneath
   while keeping type off busy footage. Legibility comes from the weight below,
   not from a panel behind it. And no rule underneath. */
nav{position:sticky;top:0;z-index:80;margin:0;border-radius:0;background:transparent;
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  transition:color .3s ease}
nav.over-dark .logo{color:#fff;filter:drop-shadow(0 1px 12px rgba(30,26,22,.45))}
nav.over-dark .nav-links a{color:#fff;text-shadow:0 1px 12px rgba(30,26,22,.45)}
nav.over-dark .nav-links a:hover{color:#fff}
/* ...but NOT the links inside the dropdown. That panel is white whatever is
   behind the bar, so turning its links white made them invisible on the film
   hero. Only what sits directly on the photograph flips. */
nav.over-dark .ddown-menu a{color:var(--ink);text-shadow:none}
nav.over-dark .ddown-menu a:hover{color:var(--ink)}
nav.over-dark .ddown > summary{color:var(--accent-ink)}
.nav-in{display:flex;align-items:center;justify-content:space-between;gap:20px;
  max-width:none;height:clamp(56px,4.6vw,64px);
  padding-left:clamp(20px,3.4vw,48px);padding-right:clamp(20px,3.4vw,48px)}
/* LOGO SLOT — replace this <a> content with your SVG lockup */
.logo{display:flex;align-items:center;gap:9px;text-decoration:none;color:var(--ink)}
.logo-icon{width:25px;height:25px;flex:none}
.logo-word{width:80px;height:20px}
/* Shown from 620px up, not 960px. The old rule hid these below 960 with no menu
   behind them, so on any window narrower than a large laptop the nav was a logo
   and a CTA — the two audience pages had no link in it at all. They shrink to
   fit rather than disappearing. */
/* The current page used to be marked with style="color:var(--ink)" on the
   anchor. An inline declaration cannot be overridden, so over the film hero the
   bar turned white and that one link stayed dark and unreadable. */
.nav-links a[aria-current="page"]{color:var(--ink)}
nav.over-dark .nav-links a[aria-current="page"]{color:#fff}

.nav-links{display:flex;gap:clamp(16px,2.4vw,34px);font-size:clamp(.76rem,1.05vw,.84rem)}
.nav-links a{text-decoration:none;color:var(--ink);font-weight:500;letter-spacing:-.005em;
  transition:color .2s;white-space:nowrap}
.nav-links a:hover{color:var(--clay-deep)}
/* Measured, not guessed: with two links at these lengths the row needs about
   600px before the page overflows. Hidden below 660 for slack. A third link
   pushed that to 668 — re-measure if one comes back. */
@media(max-width:659px){.nav-links{display:none}}
.nav-cta{font-size:.76rem;letter-spacing:.02em;text-decoration:none;color:var(--accent-ink);background:var(--accent);border:1px solid var(--accent);font-weight:500;
  padding:11px 22px;border-radius:100px;white-space:nowrap;transition:background .25s,color .25s}
.nav-cta:hover{background:var(--accent-dark);color:var(--white)}

/* --- the Get started menu ---
   A native disclosure, so it opens and closes with no script at all and the
   keyboard gets it free. saaga.js only adds the manners: Escape, and clicking
   away. The marker is suppressed because the button already reads as one. */
.ddown{position:relative}
.ddown > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:.5em}
.ddown > summary::-webkit-details-marker{display:none}
/* On a phone this button is the only navigation there is, and "Get started"
   reads as a call to action, not as a way to reach the other pages — nobody
   opens it looking for them. A burger says menu; the label returns as soon as
   the bar can show the links itself. */
.nav-burger{display:none;width:18px;height:13px;flex:none}
@media(max-width:659px){
  .nav-burger{display:block}
  .nav-cta-label{display:none}
  .ddown > summary{padding-left:16px;padding-right:16px}
  .ddown > summary::after{display:none}
}
.ddown > summary::after{content:"";width:.4em;height:.4em;flex:none;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:translateY(-.12em) rotate(45deg);transition:transform .2s ease}
.ddown[open] > summary::after{transform:translateY(.08em) rotate(-135deg)}
.ddown-menu{position:absolute;right:0;top:calc(100% + 10px);z-index:90;
  min-width:max(262px,100%);display:flex;flex-direction:column;
  background:var(--white);border:1px solid rgba(90,83,70,.10);border-radius:18px;padding:7px;
  box-shadow:0 24px 48px -24px rgba(46,42,37,.34),0 3px 10px -7px rgba(46,42,37,.26)}
.ddown-menu a{display:flex;align-items:center;gap:11px;text-decoration:none;color:var(--ink);
  font-size:.86rem;line-height:1.3;padding:10px 12px;border-radius:11px;
  transition:background .15s}
.ddown-menu a:hover,.ddown-menu a:focus-visible{background:var(--paper-3)}
.ddm-ico{width:16px;height:16px;flex:none;color:var(--clay-deep)}
/* The group labels and the page rows only exist while the bar cannot show the
   page links itself — above 660px this collapses back to three actions.
   Scoped to .ddown-menu because `.ddown-menu a` (0,1,1) sets display:flex and
   would otherwise outrank a bare `.ddm-page` (0,1,0), leaving the page links
   duplicated in the desktop menu right under the nav bar showing the same two. */
.ddm-h{display:none}
.ddown-menu .ddm-page{display:none}

@media(max-width:659px){
  /* a sheet, not a popover: pinned to the canvas gutter on both sides so it
     lines up with every other .shape on the page, and wide enough that the
     longest label wraps instead of forcing the panel off-screen */
  .ddown-menu{position:fixed;left:var(--gap);right:var(--gap);
    top:calc(clamp(56px,4.6vw,64px) + 4px);min-width:0;padding:9px;border-radius:20px;
    animation:ddm-in .2s cubic-bezier(.2,.7,.3,1) both}
  .ddm-h{display:block;margin:9px 12px 3px;font-size:.6rem;letter-spacing:.15em;
    text-transform:uppercase;color:var(--clay)}
  .ddm-h2{margin-top:12px;padding-top:11px;border-top:1px solid var(--line)}
  .ddown-menu a{font-size:.98rem;padding:12px;min-height:46px}
  .ddown-menu .ddm-page{display:flex;font-weight:500}
  .ddown-menu .ddm-page::after{content:"";margin-left:auto;flex:none;width:.4em;height:.4em;
    border-top:1.6px solid var(--clay);border-right:1.6px solid var(--clay);
    transform:rotate(45deg)}
}
@keyframes ddm-in{from{opacity:0;transform:translateY(-7px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.ddown-menu{animation:none}}

/* the menu is wider than the pill it hangs from, so it must not be clipped */
nav,.nav-in{overflow:visible}

/* BUTTONS */
.btn{display:inline-flex;align-items:center;justify-content:center;font-size:.82rem;letter-spacing:.01em;
  text-decoration:none;cursor:pointer;font-family:var(--sans);font-weight:400;padding:16px 34px;border-radius:100px;
  /* The bright accent cannot carry white text at any size — see the brand doc —
     so the label is the deep ink, set at 500 rather than 400. The weight is doing
     real work here: the fill separates from the page at only 2.9:1, under the 3:1
     a control boundary wants, and a bolder label is what keeps the pill reading
     as a control now that it has no rim. Do not drop it back to 400.
     The border is kept but tinted to the fill, so the metrics stay put. */
  background:var(--accent);color:var(--accent-ink);border:1px solid var(--accent);
  font-weight:500;transition:background .3s,color .3s,border-color .3s}
.btn:hover{background:var(--accent-dark);color:var(--white);border-color:var(--accent-dark)}
/* .btn-alt overrides the weight back down — it is an outline button on a light
   ground and does not need the extra push. */
.btn-alt{font-weight:400}
.btn-alt{background:var(--paper);color:var(--ink);border-color:var(--paper)}
.btn-alt:hover{background:var(--ink);color:var(--white);border-color:var(--ink)}
.block .btn-alt,.block-2 .btn-alt,.block-blush .btn-alt{background:var(--white);border-color:var(--white)}
.block .btn-alt:hover,.block-2 .btn-alt:hover,.block-blush .btn-alt:hover{background:var(--ink);border-color:var(--ink)}
.btns{display:flex;flex-wrap:wrap;gap:12px}
/* On a phone these wrapped onto a line each and went nearly full width, which
   read as two stacked banners rather than as a primary and a secondary. They
   share the row instead, and the labels shrink rather than the row breaking. */
/* Sharing the row is fine; being FORCED to share it is not. flex:1 1 0 with
   nowrap gave both buttons exactly half the width whatever their label said, so
   "Book a practitioner demo" broke onto three lines and the 100px radius turned
   a three-line button into an oval blob. Labels stay on one line and the row is
   allowed to wrap instead: two short buttons sit side by side, a long pair takes
   a line each at full width, and the height never changes either way. */
/* Perelel's buttons on a phone are pills at their own width, centred — not
   bars edge to edge. flex:1 1 auto was stretching ours to fill the row, so a
   lone button became a banner. They keep their natural width now, sit centred
   in the row, and only wrap when two will not fit side by side. */
@media(max-width:560px){
  .btns{flex-wrap:wrap;gap:10px;justify-content:center}
  .btns > .btn{flex:0 1 auto;min-width:0;justify-content:center;white-space:nowrap;
    padding:14px 26px;font-size:.8rem}
}
:focus-visible{outline:2px solid var(--accent-dark);outline-offset:3px}

/* ============ HERO ============
   The film is the whole surface and the title sits on it. Until hero.mp4
   lands, the poster frame shows and nothing else about the layout changes. */
.hero{padding:0;min-height:clamp(620px,96vh,1240px);display:flex;align-items:flex-end;isolation:isolate}
/* --- full-bleed hero ---
   The canvas system gives every block a gutter and a rounded corner, which is
   right for a section and wrong for the front door: boxed in, the film reads as
   a card on a page rather than as the page opening. So this one block leaves
   the system — edge to edge, square corners — and rises far enough to sit
   BEHIND the nav pill, which stays a light translucent lozenge floating on the
   footage. Everything below it keeps the gutter.

   The negative top margin is the nav's own height plus the two gaps that would
   otherwise sit above and below it. If the nav height changes, this changes. */
.hero-bleed{margin:calc(-1 * clamp(56px,4.6vw,64px)) 0 var(--gap);border-radius:0}
.hero-bleed .hero-copy{padding-top:clamp(56px,4.6vw,64px)}
.hero-film{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;
  background:#3a352f}
.hero::after{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(96deg, rgba(38,33,28,.62) 0%, rgba(38,33,28,.34) 42%, rgba(38,33,28,.06) 78%),
  linear-gradient(180deg, rgba(38,33,28,.38) 0%, rgba(38,33,28,.06) 34%, rgba(38,33,28,.46) 72%, rgba(38,33,28,.74) 100%)}
.hero-copy{width:100%;padding-top:clamp(70px,11vw,130px);padding-bottom:clamp(38px,5vw,74px)}
.hero h1{color:#fff;max-width:19ch;margin-bottom:clamp(18px,2.4vw,26px);
  text-shadow:0 1px 40px rgba(38,33,28,.35)}
.hero-sub{font-size:clamp(1rem,1.75vw,1.18rem);line-height:1.55;color:rgba(255,255,255,.86);max-width:46ch}
.hero .btns{margin-top:clamp(26px,3.4vw,38px)}
.hero .btn{background:#fff;color:var(--ink);border-color:#fff}
.hero .btn:hover{background:var(--paper);border-color:var(--paper)}
.hero .btn-alt{background:transparent;color:#fff;border-color:rgba(255,255,255,.5)}
.hero .btn-alt:hover{background:#fff;color:var(--ink);border-color:#fff}

/* FULL BLEED IMAGE */
/* width:auto, not 100% — .shape adds side margins, and a 100% width on top of
   them makes this the one section wider than every other and off-centre. */
.bleed{width:auto;overflow:hidden;position:relative;background:#cfc9c2}
.bleed img{width:100%;height:100%;object-fit:cover;display:block}
.b-16{aspect-ratio:16/7}
@media(max-width:760px){.b-16{aspect-ratio:4/5}}
.b-21{aspect-ratio:21/9}
@media(max-width:760px){.b-21{aspect-ratio:3/2}}
.imgph{display:flex;align-items:flex-end;padding:clamp(18px,3vw,34px);
  background:linear-gradient(150deg,#d8d2ca 0%,#b9b1a8 55%,#8f877f 100%)}
.imgph>span{font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.9);max-width:44ch;line-height:1.6}
.bleed-quote{position:absolute;left:0;bottom:0;padding:clamp(26px,5vw,68px);max-width:min(92%,780px);z-index:2}
.bleed-quote p{max-width:15em}
.bleed-quote p{font-size:clamp(1.5rem,3.6vw,3rem);line-height:1.12;color:#fff;letter-spacing:-.035em;font-weight:300}

/* BLOCKS — where #f5f3ec lives.
   Layered gradients give the block uneven pigment, like limewash,
   rather than a flat fill. Colour is unchanged. */
.block{background:
  radial-gradient(62% 52% at 16% 12%, rgba(255,255,255,.85) 0%, rgba(255,255,255,0) 62%),
  radial-gradient(52% 46% at 86% 78%, rgba(120,112,98,.09) 0%, rgba(120,112,98,0) 64%),
  radial-gradient(70% 58% at 58% 0%, rgba(214,206,192,.42) 0%, rgba(214,206,192,0) 66%),
  var(--paper)}
/* The brand beige, at full width. The only text sitting directly on it is the
   section heading, which is large enough to clear contrast; everything else in
   here lives inside white cards. */
.block-2{background:var(--brand)}

/* ============ LIGHT SHAFT ============
   A hard bar of daylight falling across a beige wall, the way it does in the
   brand photography. Two pieces make it read as light rather than as a stripe:
   a narrow bright core with a soft warm bloom either side of it, and a faint
   warm shadow on the far side of the beam.

   It is a surface, so it goes on a shape and the shape needs `position:relative`
   (every .shape already has it). Text sits above it — the pseudo-element is
   behind the content and ignores the pointer.

   Use it sparingly. It is a lighting effect, and two lit surfaces on one page
   read as a mistake rather than as weather. */
.s-shaft::before{
  content:"";position:absolute;top:0;bottom:0;left:-25%;right:-25%;pointer-events:none;z-index:0;
  animation:sun-drift 130s ease-in-out infinite alternate;
  /* Turned well down and the shadow band dropped: at full strength it was the
     loudest thing on the page. It is weather now, not a spotlight. */
  background:
    linear-gradient(101deg,
      rgba(255,249,236,0)   34%,
      rgba(255,249,236,.12) 41.5%,
      rgba(255,253,247,.34) 45%,
      rgba(255,253,247,.38) 47%,
      rgba(255,249,236,.14) 51%,
      rgba(255,249,236,0)   58%);
}
.s-shaft>*{position:relative;z-index:1}
@media(prefers-reduced-motion:no-preference){}
.block-accent{background:
  radial-gradient(60% 52% at 20% 16%, rgba(255,255,255,.82) 0%, rgba(255,255,255,0) 62%),
  radial-gradient(56% 48% at 84% 82%, rgba(0,0,0,.05) 0%, rgba(0,0,0,0) 64%),
  var(--accent-pale)}
/* accent-pale appears here and nowhere else on the page */
/* 132px top AND bottom put 264px of nothing between two sections that both
   sit transparent on the ground, which reads as a hole rather than as room. */
section{padding:clamp(40px,5.2vw,84px) 0}
/* a rail already ends in its own scroll padding */
section:has(.rail){padding-bottom:clamp(26px,3.4vw,56px)}
.lead{margin-bottom:clamp(30px,4vw,54px)}
/* max-width in em, so it scales with the HEADING size (a ch value here is
   measured in the small body font and crushes titles into a narrow column). */
.lead h2{max-width:20em}
.lead p{font-size:clamp(1rem,1.9vw,1.12rem);margin-top:20px;max-width:52ch;color:var(--stone)}
.lead p+p{margin-top:14px}
/* "For practitioners:" — the page addresses the woman throughout, so where a
   paragraph switches audience it has to say so. The label carries the switch. */
.lead p b{color:var(--ink);font-weight:500}
/* Title and intro both sit on the left margin. An intro pushed to the right of
   its own title reads as a stray column rather than as part of the heading. */

/* COLUMN SETS */
.cols{display:grid;gap:34px}
@media(min-width:760px){.cols-3{grid-template-columns:repeat(3,1fr);gap:48px}.cols-2{grid-template-columns:repeat(2,1fr);gap:60px}}
.col h3{margin-bottom:12px}
.col p{font-size:.92rem;line-height:1.62}

/* SIGNAL ROWS */
.rows{border-top:1px solid var(--line)}
.row{display:grid;gap:6px;padding:clamp(20px,2.6vw,28px) 0;border-bottom:1px solid var(--line)}
@media(min-width:760px){.row{grid-template-columns:34px minmax(0,17ch) 1fr;gap:28px;align-items:baseline}}
.row svg{width:26px;height:26px;color:var(--stone);position:relative;top:5px}
.row h4{color:var(--ink)}
.row p{font-size:.9rem;line-height:1.6}

/* BIG NUMBER */
.big{font-size:clamp(3.2rem,9vw,6.4rem);line-height:.9;letter-spacing:-.04em;color:var(--ink);font-weight:300;display:block}
.big-sub{font-size:clamp(.95rem,1.9vw,1.1rem);max-width:40ch;margin-top:24px}

/* AUDIENCE */
.aud{display:grid;gap:16px}
@media(min-width:900px){.aud{grid-template-columns:1fr 1fr;gap:20px}}
.card{background:var(--white);border-radius:20px;padding:clamp(28px,3.6vw,48px);display:flex;flex-direction:column}
.card h3{margin-bottom:14px}
.card>p{font-size:.93rem;line-height:1.62;margin-bottom:26px;max-width:34ch;flex:1}
.card .btns{margin-bottom:12px}
.note{font-size:.79rem;color:var(--clay)}
.more[hidden]{display:none}
.more{margin-top:28px;padding-top:26px;border-top:1px solid var(--line)}
.more dl{display:grid;gap:18px;margin-bottom:24px}
.more dt{font-size:.87rem;color:var(--ink);font-weight:400;margin-bottom:3px}
.more dd{font-size:.85rem;line-height:1.6}
.link{background:none;border:none;padding:0;font-family:var(--sans);font-size:.82rem;color:var(--ink);
  cursor:pointer;text-decoration:underline;text-underline-offset:5px;text-decoration-color:var(--clay)}
.link:hover{text-decoration-color:var(--acc)}
.shots{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:24px}
.shot{aspect-ratio:9/16;border-radius:12px;background:linear-gradient(160deg,#d8d2ca,#8f877f);
  display:flex;align-items:flex-end;padding:10px}
.shot span{font-size:.54rem;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.85)}

/* QUOTES */

/* FAQ */
.faq details{border-bottom:1px solid var(--line)}
.faq details:first-of-type{border-top:1px solid var(--line)}
.beige.faq details{border-color:rgba(90,83,70,.24)}
.beige .faq summary,.beige.faq summary{color:var(--ink)}
/* Denser closed: 26px of padding a side put ~72px between questions, so six
   of them were a screen of air. 16px reads as a list. */
.faq summary{padding:16px 0;font-size:.98rem;color:var(--ink);cursor:pointer;list-style:none;letter-spacing:-.02em;
  display:flex;justify-content:space-between;gap:26px;align-items:baseline}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";color:var(--clay);font-size:1.2rem;flex:none;font-weight:300}
.faq details[open] summary::after{content:"–"}
.faq details>p{font-size:.92rem;line-height:1.7;padding-bottom:20px;max-width:none}
.faq details>p+p{margin-top:-12px;padding-top:12px}
/* a link inside an answer inherits the answer's colour, so an underline was the
   only thing marking it. Same treatment as every other link on the site. */
.faq details>p a{color:var(--accent-dark);text-underline-offset:2px}
.faq details>p a:hover{color:var(--ink)}

/* a photograph on its own — no scrim, since there is no text to keep legible */
.photoband{position:relative;overflow:hidden}
.photoband img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center 40%}

/* ============ COLLABORATION ============
   One statement, set large, with the body copy beneath at reading size. No stat
   row: the reference layout ends on figures, and we have none we can stand
   behind. */
.collab h2{max-width:14ch;margin-bottom:clamp(22px,2.6vw,32px)}
.collab-body{max-width:56ch;font-size:clamp(1.02rem,1.4vw,1.16rem);line-height:1.62;
  color:var(--stone);margin-bottom:1em}
.collab-body b{font-weight:400;color:var(--accent-dark)}
.collab .btns{margin-top:clamp(24px,2.8vw,34px)}
/* .btn-alt is tuned for the film hero, where it sits on dark. On paper it needs
   its own border and ink, or it reads as unstyled text. */
.collab .btn-alt{border-color:rgba(65,58,48,.3);color:var(--ink);background:transparent}
.collab .btn-alt:hover{background:var(--ink);color:var(--white);border-color:var(--ink)}

/* ============ ACCESS REQUEST FORM ============ */
.leadform{margin-top:clamp(26px,3.2vw,42px);max-width:760px}
.lf-row{display:grid;gap:clamp(14px,1.8vw,22px);margin-bottom:clamp(14px,1.8vw,22px)}
@media(min-width:660px){.lf-row{grid-template-columns:1fr 1fr}}
.leadform label{display:block;font-size:.8rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--clay)}
.lf-full{margin-bottom:clamp(14px,1.8vw,22px)}
.leadform input,.leadform select,.leadform textarea{
  display:block;width:100%;margin-top:.55em;
  font-family:var(--sans);font-weight:300;font-size:1rem;color:var(--ink);
  letter-spacing:normal;text-transform:none;
  background:var(--white);border:1px solid var(--line);border-radius:.6em;
  padding:.72em .85em;transition:border-color .18s ease}
.leadform textarea{resize:vertical;min-height:5em}
.leadform input:focus,.leadform select:focus,.leadform textarea:focus{
  outline:none;border-color:var(--accent)}
.beige .leadform input,.beige .leadform select,.beige .leadform textarea{
  border-color:rgba(90,83,70,.24)}
.lf-send{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(14px,2vw,26px)}
.lf-note{font-size:.84rem;color:var(--stone);margin:0;max-width:40ch}
.lf-note a{color:var(--accent-dark)}
/* the validation message lives in the page, not in a bubble that disappears */
/* the thank-you, once the endpoint has taken the submission. It replaces the
   form rather than sitting under it: there is nothing left to fill in. */
.leadform[data-done] > *{display:none}
.leadform[data-done]::after{content:attr(data-done);display:block;
  font-size:clamp(1rem,1.5vw,1.1rem);color:var(--ink);padding:clamp(20px,2.4vw,30px) 0}
.leadform button[data-busy]{opacity:.6;cursor:progress}
.leadform[data-error]::after{content:attr(data-error);display:block;
  margin-top:1em;font-size:.86rem;color:var(--accent-dark)}

/* ============ TOUCH TARGETS ============
   Inline links that sit alone in a line were 19–26px high. On a pointer that
   is fine; on a thumb it is a miss. Padding only, so nothing moves visually
   beyond the extra room around it. */
@media(max-width:820px){
  .more-link,.link-arrow,.card-link{display:inline-block;padding:13px 0}
  .btn,.nav-cta{min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  .ddown > summary{min-height:44px}
  .whocard summary{padding:20px 0}
  .faq summary{padding:15px 0}
}

/* ============ WHO IT IS FOR ============
   A grid of <details>. Native disclosure rather than a JS tab set, for three
   reasons: the answer text is in the DOM whether or not it is open, so search
   and answer engines read all of it; it works with the script disabled; and a
   keyboard gets it for free. Every entry names a real title or condition,
   because those are the words people actually search for. */
/* --- message + voice, inside the app mock ---
   Sized in em so they scale with .ui's own container-query font size, like
   every other piece of the mock. Anything in px here would blow up the moment
   the phone is rendered small. */
.ui-msg{max-width:86%;padding:.62em .8em;border-radius:1.1em;margin:.34em 0;
  font-size:.94em;line-height:1.4}
.ui-msg.in{background:#f1ece2;color:var(--ink);border-bottom-left-radius:.35em}
.ui-msg.out{background:#6b6455;color:#f7f4ee;margin-left:auto;
  border-bottom-right-radius:.35em}
.ui-mic{display:flex;align-items:center;gap:.6em;margin-top:.6em;
  padding:.55em .5em .55em .9em;border-radius:2em;background:var(--paper);
  border:1px solid var(--line);color:var(--clay);font-size:.92em}
.ui-mic i{margin-left:auto;flex:none;width:1.9em;height:1.9em;border-radius:50%;
  background:var(--accent);position:relative}
.ui-mic i::after{content:"";position:absolute;left:50%;top:50%;
  width:.42em;height:.72em;margin:-.36em 0 0 -.21em;border-radius:.3em;background:#fff}
.ui-mic.listening{border-color:var(--accent);color:var(--ink)}
.ui-chips{display:flex;flex-wrap:wrap;gap:.35em;margin-top:.45em}
.ui-chips span{font-size:.88em;padding:.34em .7em;border-radius:2em;
  border:1px solid var(--line);color:var(--stone)}
.ui-chips span.on{background:var(--ink);border-color:var(--ink);color:#fff}

/* --- a rail that stays horizontal at every width ---
   The pile is right for cards you read; it is wrong for a row of phones, which
   are objects you compare side by side. This keeps the desktop rail's scroll
   and its arrows and simply narrows the items on a phone. */
@media(max-width:999px){
  .rail.rail-flat,.patient-view.rail.rail-flat{display:flex;flex-wrap:nowrap;
    overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;
    gap:12px;scrollbar-width:none;-ms-overflow-style:none}
  .rail.rail-flat::-webkit-scrollbar{display:none}
  .rail.rail-flat > *{position:static;top:auto;flex:0 0 62%;scroll-snap-align:start;
    box-shadow:none}
}
@media(min-width:1000px){
  .rail.rail-flat > *{flex:0 0 clamp(220px,22%,268px)}
}
.patient-view .phone{max-width:none;width:100%;margin:0 auto}

/* --- the Without/With turn, on a photograph ---
   Same component as the practitioner page; the ground it turns is the image
   rather than a flat colour. On the without the photograph is desaturated and
   sits under a colder, heavier scrim, so the turn happens to the picture as
   well as to the words. The scrim is not optional here: this photograph used
   to carry no text and needed none. */
.diff-photo{position:relative;isolation:isolate;
  padding:clamp(46px,6vw,88px) 0 clamp(50px,6.4vw,92px)}
.dp-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;
  filter:grayscale(.85) contrast(.92) sepia(.16);transition:filter 1.1s ease}
.diff-photo::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(28,25,22,.80) 0%,rgba(28,25,22,.62) 45%,rgba(28,25,22,.78) 100%);
  transition:background 1.1s ease}
.diff-photo .wrap{position:relative;z-index:1}
.diff-photo h2{color:#fff}
.diff-photo .diff-row{border-color:rgba(255,255,255,.20)}
.diff-photo .diff-row h3{color:rgba(255,255,255,.62)}
.diff-photo .diff-row p{color:rgba(255,255,255,.44)}
.diff-photo .diff-head{color:rgba(255,255,255,.55)}
.diff-photo .diff-switch{background:rgba(255,255,255,.14)}
.diff-photo .diff-tab{color:rgba(255,255,255,.72)}
.diff-photo .diff-tab.on{background:rgba(255,255,255,.92);color:var(--ink);box-shadow:none}

/* the turn itself: colour returns to the photograph, the scrim warms, the type
   comes up to full white and the accent lights */
.diff-photo[data-side="b"] .dp-img{filter:var(--warm-photo)}
.diff-photo[data-side="b"]::after{
  background:linear-gradient(180deg,rgba(46,32,24,.72) 0%,rgba(58,40,28,.48) 45%,rgba(40,29,22,.72) 100%)}
.diff-photo[data-side="b"] .diff-row h3{color:#fff}
.diff-photo[data-side="b"] .diff-row p{color:rgba(255,255,255,.76)}
/* the flat-colour rules from the practitioner page must not repaint this one */
.diff-photo.has-switch[data-side="a"],
.diff-photo.has-switch[data-side="b"]{background-color:transparent}
.diff-photo.has-switch[data-side="a"] .diff-row{border-color:rgba(255,255,255,.18)}
.diff-photo.has-switch[data-side="a"] .diff-a h3{color:rgba(255,255,255,.62)}
.diff-photo.has-switch[data-side="a"] .diff-a p{color:rgba(255,255,255,.44)}
.diff-photo.has-switch[data-side="b"] .diff-b h3{color:#fff}
.diff-photo.has-switch[data-side="b"] .diff-b p{color:rgba(255,255,255,.76)}
.diff-photo.has-switch .diff-row h3::before{background:rgba(255,255,255,.38)}
.diff-photo.has-switch[data-side="b"] .diff-row h3::before{background:var(--accent)}

/* --- screens in the rail, at a size worth looking at ---
   .sc-media .phone caps at 142px, which was right when these cards were two
   columns and the phone had half a card to live in. In the rail the card is
   ~400px and the phone had been sitting in the middle of it at a third of the
   width, with a 5.7px screen font — a thumbnail of an interface rather than an
   interface. At 286px the same screen renders at ~12px and can actually be
   read, which is the whole reason it is on the page. */
/* The interface goes at the TOP of the card and loses its phone: no bezel, no
   notch, no wordmark, no tab bar. Those are chrome, and chrome is what makes a
   product shot read as "here is a screenshot" rather than as the thing itself.

   ONE GROUND, though. Giving the picture its own background colour cut the card
   in half — a tinted block sitting on a white block, with a hard seam between
   them. The card carries a single soft wash top to bottom and the interface
   FLOATS on it, inset on all sides with its own corners and shadow, so the
   panel reads as an object lying on the card rather than as the card's top half.

   Losing the frame is also what makes it large: .ui sizes itself in cqi against
   .screen, so widening that container from a 286px phone to most of the card
   raises the type with it — no scaling, the same rule given more room. */
/* align-CONTENT, not just align-items. The rail stretches every card to the
   tallest, and a grid with auto rows hands that leftover space to the rows —
   so each card padded its picture row by a different amount and the headings
   landed on six different lines. Packing the rows to the top puts the slack at
   the bottom of the card, where it belongs. */
.rail .stackcard{padding:0;overflow:hidden;align-items:start;align-content:start;gap:0;
  background:linear-gradient(168deg,var(--paper-3) 0%,#fbf9f5 46%,var(--white) 100%);
  border:1px solid rgba(90,83,70,.09)}
.rail .stackcard > div:not(.sc-media){padding:clamp(20px,2.2vw,28px)}
/* A FIXED height, not a max: the media is what sets where the copy starts, and
   letting each card's picture end wherever its content happened to fall left
   every title on a different line. Same height everywhere, so the headings and
   the paragraphs under them align straight across the rail. */
.rail .stackcard .sc-media{order:-1;margin:0;border-radius:0;background:transparent;
  align-items:flex-start;justify-content:center;overflow:hidden;
  padding:clamp(18px,2vw,26px) clamp(18px,2vw,26px) 0;
  height:clamp(198px,21vw,262px)}
/* And the panel stays phone-width. Stretched to the full card, .ui-row's
   space-between pushed every label and its value to opposite ends and the
   interface read as something dragged out of shape rather than as itself. */
.rail .stackcard .sc-media .phone{max-width:300px;width:100%;margin:0 auto;flex:none;
  aspect-ratio:auto;background:none;padding:0;box-shadow:none;border-radius:0}
.rail .stackcard .sc-media .notch{display:none}
/* the floating panel: its own corners and lift, and a mask rather than an
   overlay at the bottom, so it fades into whatever the card's wash is doing
   there instead of into one hard-coded colour */
.rail .stackcard .sc-media .screen{height:auto;background:var(--white);
  border-radius:14px;overflow:hidden;
  box-shadow:0 20px 38px -24px rgba(46,42,37,.42),0 2px 6px -3px rgba(46,42,37,.16)}
/* THE FADE BELONGS TO THE BOX, NOT TO THE PANEL.
   It was on .screen, whose height is its content's — so the gradient started at
   68% of the PANEL and a tall panel was still four-fifths opaque where the
   fixed 262px box clipped it. That is what the cut edges were: a fade that
   finished below the crop. On .sc-media it always lands on the bottom edge,
   whatever the panel inside happens to measure. */
.rail .stackcard .sc-media{
  -webkit-mask-image:linear-gradient(to bottom,#000 0,#000 78%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 0,#000 78%,transparent 100%)}
/* The drawn record panel is the same object as the phone panels beside it, so
   it gets the same width, the same lift and the same top alignment rather than
   floating loose and full-bleed in its card. */
.rail .stackcard .sc-media .bro-soldraw{max-width:300px;width:100%;margin:0 auto;
  border-radius:14px;padding:12px;
  box-shadow:0 20px 38px -24px rgba(46,42,37,.42),0 2px 6px -3px rgba(46,42,37,.16)}
/* One line per area, at 300px. Wrapped, the day strip and five areas ran past
   the bottom of the card and Health admin fell off it — and that is the row
   that proves the record is not just cycle tracking. */
.rail .stackcard .sc-media .bro-recrow{grid-template-columns:4.5rem 1fr;gap:0 8px;padding:5px 8px}
.rail .stackcard .sc-media .bro-recrow em{font-size:.5rem;letter-spacing:.02em}
.rail .stackcard .sc-media .bro-recrow span{font-size:.63rem;line-height:1.25;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rail .stackcard .sc-media .bro-recdays span{font-size:.53rem;padding:3px 0}
.rail .stackcard .sc-media .ui{position:static;inset:auto;background:transparent}
.rail .stackcard .sc-media .ui-top,
.rail .stackcard .sc-media .ui-nav{display:none}
.rail .stackcard .sc-media .ui-body{padding-top:clamp(12px,1.4vw,16px)}

/* Two lines of heading everywhere, so the paragraph beneath starts on the same
   line across the rail whether the title wraps or not. */
/* THREE lines reserved, not two. Two meant any heading over ~44 characters
   took a third line at 1280 and pushed that card's paragraph out of line with
   the rest of the row — which had copy being cut to fit the box four times
   running. The box fits the copy instead. Short headings simply carry more air
   beneath them, identically on every card, so it reads as spacing rather than
   as a gap. */
.rail .stackcard h3{min-height:3.45em;margin-bottom:10px}
/* The cards are a heading and one sentence now, no bullet list under them.
   Three lines of paragraph keeps the card bottoms level where the sentence
   wraps differently. */
.rail .stackcard > div:not(.sc-media) > p{min-height:4.8em;margin-bottom:0}

/* --- the flowline ---
   One curve of the homepage's contour, in the gap between two sections so that
   gap is doing something rather than being nothing. No markers on it: dots
   riding a line is someone else's idiom, and the curve says it on its own.

   The movement is two paths drifting against each other on different, very
   long, prime-ish durations, so they never quite repeat the same shape at the
   same time. Slow enough that you would not catch it looking, which is the
   point — it should register as the page breathing, not as an animation. */
/* A section that opens with the flowline gives up most of its top padding: the
   line IS the space between the two sections, and stacking the section's own
   padding on top of it left a hole with a thread across the middle. */
section:has(> .flowline){padding-top:clamp(12px,1.6vw,26px)}
.flowline{display:block;width:100%;height:clamp(48px,5.6vw,84px);
  margin:calc(-1 * clamp(18px,2.4vw,36px)) 0 clamp(4px,0.8vw,12px);
  overflow:visible;pointer-events:none}
.flowline path{fill:none;stroke:#a99f8e;stroke-width:1.1;
  vector-effect:non-scaling-stroke;opacity:.42;
  animation:flow-a 96s cubic-bezier(.45,0,.55,1) infinite alternate}
.flowline .fl-2{opacity:.22;
  animation:flow-b 131s cubic-bezier(.45,0,.55,1) infinite alternate}
@keyframes flow-a{from{transform:translate3d(-1.6%,4px,0)}
                  to{transform:translate3d(1.8%,-5px,0)}}
@keyframes flow-b{from{transform:translate3d(1.4%,-3px,0)}
                  to{transform:translate3d(-2%,6px,0)}}
@media(prefers-reduced-motion:reduce){
  .flowline path,.flowline .fl-2{animation:none}
}

/* a fortnight of one metric as bars — small enough to sit under a label and
   still show a shape, which is what "all your data" has to look like */
.ui-spark{display:flex;align-items:flex-end;gap:.16em;height:2.4em;margin:.45em 0 .1em}
.ui-spark i{flex:1;min-height:12%;border-radius:.14em;background:var(--dim,#b57a66);opacity:.9}
.ui-k .ui-kb{float:right;font-weight:500;letter-spacing:0;text-transform:none;color:var(--ink)}
/* the day's progress, so "3 of 5 done" is visible and not only stated */
.ui-prog{height:.42em;border-radius:2em;background:var(--line);overflow:hidden;margin-top:.5em}
.ui-prog i{display:block;height:100%;border-radius:2em;background:var(--accent)}

/* one row per area: the colour dot, what it is, and the number. Used where a
   card claims to cover all five and has to show all five to be believed. */
.ui-ar{display:flex;align-items:center;gap:.62em;padding:.5em 0;font-size:.95em;
  border-top:1px solid var(--line)}
.ui-ar:first-child{border-top:0}
.ui-ar i{flex:none;width:.62em;height:.62em;border-radius:50%;background:var(--dim)}
.ui-ar span{color:var(--stone)}
.ui-ar b{margin-left:auto;font-weight:500;color:var(--ink);white-space:nowrap}

/* --- the trio ---
   Not a rail. The features above it are already a horizontal scroller, and two
   scrollers in a row read as the same section twice. Three phones, staged: the
   middle one forward and larger, the outer two set back and dropped, so the
   group reads as one composition rather than as a row of equal thumbnails. */
/* two phones rather than three when only two are worth showing */
.patient-view.trio:has(> :nth-child(2):last-child){grid-template-columns:repeat(2,1fr);
  max-width:760px;margin-inline:auto}
@media(min-width:820px){
  .patient-view.trio:has(> :nth-child(2):last-child) > :nth-child(1),
  .patient-view.trio:has(> :nth-child(2):last-child) > :nth-child(2){transform:none}
}
.patient-view.trio{display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(18px,3vw,46px);align-items:start;
  margin-top:clamp(26px,3.4vw,46px)}
@media(min-width:820px){
  .patient-view.trio > *{transition:transform .4s ease}
  .patient-view.trio > :nth-child(1){transform:translateY(34px) scale(.9);transform-origin:top right}
  .patient-view.trio > :nth-child(3){transform:translateY(34px) scale(.9);transform-origin:top left}
  .patient-view.trio > :nth-child(2){position:relative;z-index:2}
  /* 250px put the app's own type at 10.6px on a 1280 screen, which reads as
     texture rather than as a screen anyone could use — and this section's whole
     claim is that she enjoys using it. 300 takes it to about 12.7px, and three
     of them still sit inside a 1134px section with room to spare. */
  .patient-view.trio .phone{max-width:278px}
}
/* --- the phones are cut, not scaled ---
   A whole phone at this size leaves the bottom third empty or, if it is filled,
   cuts a card in half at the bezel. So the device itself ends early and fades
   out: the screen carries on past the crop the way it does in the hand, and
   there is no bottom edge for content to collide with. The app's own nav bar
   goes with it, since it would otherwise sit in the middle of the screen. */
/* CUT, not rounded off. The phone kept its bottom corners inside the crop, so
   what faded out was a complete, rounded-bottom device — which reads as a
   tablet, not as a phone continuing past the edge. The frame's bottom corners
   are square now and the screen inside is the full 2050 tall, so the crop
   line falls across straight bezel sides and an unfinished screen; the fade
   only softens the last stretch. */
.patient-view.trio .phone{aspect-ratio:1000/1560;overflow:hidden;
  border-bottom-left-radius:0;border-bottom-right-radius:0;
  -webkit-mask-image:linear-gradient(to bottom,#000 80%,rgba(0,0,0,.4) 93%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 80%,rgba(0,0,0,.4) 93%,transparent 100%)}
.patient-view.trio .phone .screen{height:calc(100% * 2050 / 1560)}
.patient-view.trio .phone .ui-nav{display:none}

@media(max-width:819px){
  .patient-view.trio{display:flex;flex-wrap:nowrap;overflow-x:auto;
    overscroll-behavior-x:contain;scroll-snap-type:x mandatory;gap:12px;
    scrollbar-width:none;-ms-overflow-style:none}
  .patient-view.trio::-webkit-scrollbar{display:none}
  .patient-view.trio > *{flex:0 0 64%;scroll-snap-align:start}
}

/* --- the assistant bubbles, inside a phone ---
   The section that used to hold this is gone; the screen is a card in the
   rail now. These stay because the bubbles are still rendered inside .ui,
   and .aimsg was drawn for a 620px card — its px values are nonsense at
   phone scale, so everything here is re-set in em. */
.ui .aidemo{padding:.7em .75em}
.ui .aihead{gap:.5em;padding-bottom:.6em;margin-bottom:.5em}
.ui .aihead .dot{width:.42em;height:.42em}
.ui .aihead span{font-size:.78em;letter-spacing:.12em}
.ui .aithread{gap:.5em}
.ui .aimsg{max-width:90%;border-radius:1.05em;padding:.6em .78em;
  font-size:.94em;line-height:1.42}
.ui .aimsg.you{border-bottom-right-radius:.34em}
.ui .aimsg.saaga{border-bottom-left-radius:.34em}
.ui .aimsg .caret{width:.09em;height:.9em}
.ui .aidots i{width:.28em;height:.28em}


/* This lead runs to two paragraphs — it is the page's why-we-exist, and one
   sentence cannot hold both the gap and the answer to it. The measure stays
   tight so it reads as an argument rather than as a wall. */
#who-for .lead p{max-width:62ch}
#who-for .lead p + p{margin-top:.9em}

/* --- the chapter you are in ---
   The heading opens a line and this finishes it, one chapter at a time, typed.

   Every chapter is in the markup. With no script they simply read as a list —
   that is what the ", " separator is for. With the script, they all stack into
   ONE grid cell and go invisible, which is what reserves the width of the
   longest chapter: the typed line then has a fixed left edge and the caret
   travels right, instead of the whole sentence sliding as it grows. */
#who-for.mid{text-align:center}
#who-for.mid .lead h2,#who-for.mid .lead p{margin-left:auto;margin-right:auto}
#who-for.mid .lead p{max-width:56ch}
#who-for.mid .wholist{justify-content:center;max-width:56em;margin-inline:auto}

/* The global p{max-width:58ch} is a measure for prose, and a centred line that
   keeps it is centred inside a box narrower than the section — which reads as
   off-centre. These two are not prose, so they drop it. */
#who-for.mid .chapters,#who-for.mid .who-k{max-width:none;margin-inline:auto}
.chapters{margin-top:clamp(34px,4.4vw,58px)}
.chapters-k{display:block;font-size:clamp(.95rem,1.6vw,1.05rem);color:var(--stone-deep);
  margin-bottom:.5em}
/* The chapter itself carries the line, so it is set at statement size — the
   kicker above it is only the setup. */
.chapter-now{font-size:clamp(1.55rem,3.4vw,2.25rem);font-weight:300;line-height:1.15;
  letter-spacing:-.03em;color:var(--ink);text-align:center}
.chapter-now .w + .w::before{content:", "}
html.js .chapter-now{display:inline-grid;justify-items:center;vertical-align:bottom}
html.js .chapter-now .w{grid-area:1/1;white-space:nowrap;visibility:hidden}
html.js .chapter-now .w + .w::before{content:none}
.chapter-typed{grid-area:1/1;white-space:pre}
.chapter-typed::after{content:"";display:inline-block;width:2px;height:.92em;
  background:var(--accent);margin-left:3px;vertical-align:-.1em;
  animation:caret-blink 1.1s steps(1) infinite}
/* Narrow screens: let the longest chapter wrap rather than overflow. Every
   chapter shares the one grid cell, so the cell already holds the tallest of
   them and the line below never jumps as they change. */
@media(max-width:560px){
  html.js .chapter-now .w{white-space:normal}
  html.js .chapter-now{max-width:11em}
}

/* --- who it is for, as names rather than accordions ---
   Twelve <details> nobody opened one at a time, each hiding a sentence that
   said what the one above it said. The names ARE the point — a practitioner
   scans for their own — so they are just names now, and the argument that used
   to be a section of its own leads the section instead. */
.who-k{font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;color:var(--clay);
  margin-top:clamp(30px,3.6vw,48px);margin-bottom:14px}
.wholist{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.wholist li{font-size:.86rem;line-height:1.3;color:var(--stone-deep);
  padding:9px 15px;border-radius:100px;background:rgba(255,255,255,.62);
  border:1px solid rgba(90,83,70,.14)}

.whogrid{display:grid;gap:0;margin-top:clamp(28px,3.4vw,46px);
  border-top:1px solid var(--line)}
@media(min-width:820px){
  .whogrid{grid-template-columns:1fr 1fr;column-gap:clamp(34px,4vw,68px)}
}
.beige .whogrid,.beige .whocard{border-color:rgba(90,83,70,.24)}
.whocard{border-bottom:1px solid var(--line)}
.whocard summary{list-style:none;cursor:pointer;display:flex;gap:18px;
  align-items:baseline;justify-content:space-between;
  padding:18px 0;font-size:clamp(.98rem,1.25vw,1.08rem);color:var(--ink);
  letter-spacing:-.015em}
.whocard summary::-webkit-details-marker{display:none}
.whocard summary::after{content:"+";flex:none;color:var(--clay);font-weight:300;font-size:1.15rem}
.whocard[open] summary::after{content:"\2013"}
.whocard summary:hover{color:var(--accent-dark)}
.whocard > p{font-size:.92rem;line-height:1.65;color:var(--stone);
  padding:0 0 20px;max-width:52ch;margin:0}

/* CLOSE */
.close h2{max-width:14ch;margin-bottom:36px}

/* FOOTER */
footer.beige{padding:clamp(52px,7vw,90px) 0 44px;background:var(--paper)}
.foot{display:grid;gap:34px}
/* Solutions, Legal, Contact. "Learn" went first — it pointed at condition pages
   that were never built — and "Explore" after it: every row in it was a jump to
   a section of the page the reader is already on. */
@media(min-width:820px){.foot{grid-template-columns:1.6fr 1fr 1fr 1fr}}
/* Between the phone layout and that one there was no rule at all, so from 660
   to 819px the four groups stacked into a single column and Contact sat on a
   row of its own. The three link groups share a row here too; the brand takes
   the full width above them. */
@media(min-width:660px) and (max-width:819px){
  .foot{grid-template-columns:repeat(3,1fr);gap:28px 20px}
  .foot > :first-child{grid-column:1 / -1}
}
/* On a phone the three link groups stacked into 13 rows of 45px — 585px of
   footer, 1.5 screens for 83 words. Side by side in two columns they cost half
   that, and the touch targets stay the size they need to be. */
@media(max-width:659px){
  .foot{grid-template-columns:1fr 1fr;gap:26px 18px}
  .foot > :first-child{grid-column:1 / -1}
  footer.beige{padding-top:38px;padding-bottom:30px}
  footer.beige a{padding:9px 0}
  footer.beige h4{margin-bottom:10px}
}
/* It is an <a> to the homepage now. footer.beige a (0,1,2) outweighs a bare
   .foot-logo, so the mark would go display:block and pick up the link padding
   unless the rule carries the same weight. */
footer.beige a.foot-logo{display:flex;align-items:center;gap:8px;margin-bottom:16px;
  padding:0;color:var(--ink);width:max-content}
footer.beige a.foot-logo:hover{opacity:.72}
.foot-logo .logo-icon{width:22px;height:22px;flex:none}
.foot-logo .logo-word{width:70px;height:18px}
/* --clay measures 3.76:1 against this ground, and these are 0.66rem uppercase
   — small text, so the bar is 4.5:1, not 3:1. --clay-deep is 5.20:1. */
footer.beige h4{font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:var(--clay-deep);margin-bottom:16px;font-weight:400}
/* 13 links at 23px high is a thumb-sized problem on a phone. Padding rather
   than a bigger font — the size is right, the target was not. */
footer.beige a{display:block;padding:11px 0;margin-bottom:0;font-size:.85rem;
  text-decoration:none;color:var(--stone)}
footer.beige a:hover{color:var(--ink)}
.legal{margin-top:52px;padding-top:26px;border-top:1px solid var(--line);font-size:.73rem;color:var(--clay-deep);line-height:1.65}
.legal p{max-width:76ch;margin-top:10px}

/* ============================================================
   SURFACES — brand materials from saaga-surfaces.html, live in CSS/SVG,
   no image assets. Warmth and depth without photography.
   ============================================================ */

/* Stone wash — overlapping warm-neutral gradients + grain. Reads as light
   falling across stone. Replaces flat photo bands. */
.s-wash{background:
  radial-gradient(58% 62% at 22% 30%, #e6e2d5 0%, rgba(230,226,213,0) 68%),
  radial-gradient(52% 58% at 80% 24%, #f3f0e7 0%, rgba(243,240,231,0) 66%),
  radial-gradient(66% 72% at 64% 92%, #c6c0af 0%, rgba(198,192,175,0) 72%),
  linear-gradient(158deg,#f4f2ea,#dcd7c9)}
.s-wash::before{content:"";position:absolute;inset:0;opacity:.30;mix-blend-mode:multiply;pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='k'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23k)' opacity='.5'/%3E%3C/svg%3E")}

/* Warm duotone — for framing a mockup or carrying a quote. Deeper stone. */
.s-duo{background:linear-gradient(152deg,#b7afa4 0%,#7c746a 68%,#5c554c 100%)}
.s-duo::before{content:"";position:absolute;inset:0;background:linear-gradient(152deg,rgba(99,97,90,.35),rgba(46,42,37,.5));mix-blend-mode:multiply;pointer-events:none}
.s-duo::after{content:"";position:absolute;inset:0;opacity:.4;mix-blend-mode:overlay;pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='d'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23d)' opacity='.55'/%3E%3C/svg%3E")}

/* Cycle contour — the sine wave from the cycle mark, repeated and fading.
   A topographic map of one cycle. The one ownable texture (it IS the mark). */
.contour{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.contour path{fill:none;stroke:#8f887c;stroke-width:1.1;vector-effect:non-scaling-stroke}

/* Signal field — a month of tracked days as soft bars. Reads clinical in a
   good way; used on the practitioner side. */
.field{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.field rect{fill:#8f887c}

/* ============================================================
   DEVICE MOCKUPS — SAAGA app + portal, rendered in CSS/SVG to match the
   real product. Warm grounds, rounded cards, the signal marks.
   ============================================================ */
/* Everything about this frame is a PROPORTION of its width, not a pixel count.
   It used to be a flat 34px radius on a 7px bezel, which is about right at the
   250px this was drawn at and badly wrong anywhere else — at the 137px the
   homepage duo renders it, 34px is a quarter of the width and the phone reads
   as a rounded blob with a fat black border. A real handset's corner is ~13% of
   its width; the paired percentage keeps that corner circular against the
   1000/2050 body instead of stretching it into an oval. */
.phone{position:relative;border-radius:13% / 6.34%;background:#26231f;padding:2.8%;
  box-shadow:0 30px 60px -28px rgba(46,42,37,.5),0 8px 20px -12px rgba(46,42,37,.35);
  width:100%;max-width:250px;aspect-ratio:1000/2050}
.phone .screen{position:relative;height:100%;border-radius:10.8% / 5.1%;overflow:hidden;
  background:#fbfaf6;display:flex;flex-direction:column}
/* A real screenshot rather than a rebuilt screen. The captures are 1206x2622,
   almost exactly the frame's ratio, so cover crops only a few pixels; anchored
   to the top so the wordmark and the first card are always whole. */
/* contain, not cover. The captures are 1206x2622 and the frame's screen is a
   slightly wider ratio, so cover was scaling to fill the width and cutting the
   app's own bottom bar off — which reads as the screenshot running out of the
   phone. Contain shows the whole capture, on the app's own background. */
.phone .screen .app-shot{width:100%;height:100%;object-fit:contain;
  object-position:center;display:block;background:#fbfaf6}
/* aspect-ratio rather than a height, so the speaker slot scales with the body */
.phone .notch{position:absolute;top:1.4%;left:50%;transform:translateX(-50%);
  width:34%;aspect-ratio:17;height:auto;border-radius:100px;background:#26231f;z-index:6}
.scr{flex:1;overflow:hidden;padding:26px 15px 12px;display:flex;flex-direction:column;gap:11px}
.scr-top{display:flex;align-items:center;justify-content:space-between}
.scr-word{width:46px;height:12px;color:var(--ink)}
.scr-eye{font-size:.42rem;letter-spacing:.16em;text-transform:uppercase;color:var(--clay)}
.scr h5{font-family:var(--sans);font-weight:300;font-size:1.02rem;letter-spacing:-.03em;color:var(--ink);line-height:1.05}
.mcard{background:#fff;border:1px solid var(--line);border-radius:15px;padding:12px 13px;
  box-shadow:0 1px 0 rgba(255,255,255,.9) inset,0 10px 20px -16px rgba(168,159,141,.5)}
.mcard.tint{background:linear-gradient(158deg,#fdfcf9,#f1ede3)}
.m-lab{font-size:.44rem;letter-spacing:.16em;text-transform:uppercase;color:var(--clay);display:block}
.m-line{font-size:.62rem;line-height:1.32;color:var(--stone)}
.m-line b{color:var(--ink);font-weight:400}
.m-pill{display:inline-flex;align-items:center;justify-content:center;background:var(--ink);color:#fff;font-size:.52rem;padding:7px 0;border-radius:100px;width:100%;letter-spacing:.02em;margin-top:9px}
.m-chips{display:flex;gap:6px;flex-wrap:wrap;margin-top:4px}
.m-chip{border:1px solid var(--line);border-radius:100px;padding:5px 9px;font-size:.5rem;color:var(--stone);display:inline-flex;gap:4px;align-items:center;background:#fff}
.m-chip svg{width:9px;height:9px;color:var(--stone)}
.m-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}
.m-stat{background:#fff;border:1px solid var(--line);border-radius:12px;padding:9px 8px;text-align:center}
.m-stat b{display:block;font-family:var(--sans);font-weight:300;font-size:.92rem;color:var(--ink);letter-spacing:-.02em;line-height:1}
.m-stat span{font-size:.4rem;letter-spacing:.12em;text-transform:uppercase;color:var(--clay);display:block;margin-top:4px}
.m-bar{height:5px;border-radius:100px;background:var(--paper-2);overflow:hidden;margin-top:7px}
.m-bar i{display:block;height:100%;background:var(--acc);border-radius:100px}
.m-nav{display:flex;justify-content:space-around;align-items:center;padding:9px 0 12px;border-top:1px solid var(--line);background:#fff}
.m-nav s{width:15px;height:15px;border-radius:5px;background:var(--paper-2);display:block;text-decoration:none}
.m-nav s.on{background:var(--ink)}
.m-row{display:flex;align-items:center;gap:8px}
.m-mark{width:15px;height:15px;color:var(--stone);flex:none}
/* mini insight chart */
.m-chart{height:52px;display:flex;align-items:flex-end;gap:3px;margin-top:8px}
.m-chart s{flex:1;background:var(--paper-2);border-radius:2px;display:block}
.m-chart s.hi{background:var(--stone)}
/* mini month calendar */
.m-cal{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;margin-top:8px}
.m-cal s{aspect-ratio:1;border-radius:50%;background:var(--paper);display:flex;align-items:center;justify-content:center;font-size:.42rem;color:var(--clay)}
.m-cal s.p{background:#d8cfc0;color:var(--ink)}
.m-cal s.f{outline:1px solid var(--clay);outline-offset:-1px}
.m-cal s.o{background:var(--ink);color:#fff}
.m-cal s.t{border:1px solid var(--ink);color:var(--ink)}

/* Browser frame — practitioner portal, the outcome view. */
.browser{position:relative;border-radius:14px;overflow:hidden;background:#fff;border:1px solid var(--line);
  box-shadow:0 30px 60px -30px rgba(46,42,37,.45),0 10px 22px -14px rgba(46,42,37,.3);width:100%}
.br-bar{display:flex;align-items:center;gap:6px;padding:11px 14px;background:#f4f2ea;border-bottom:1px solid var(--line)}
.br-bar s{width:9px;height:9px;border-radius:50%;background:#d8d2c4;display:block}
.br-url{margin-left:10px;font-size:.6rem;color:var(--clay);background:#fff;border:1px solid var(--line);border-radius:100px;padding:4px 12px}
.br-body{display:grid;grid-template-columns:118px 1fr;min-height:210px}
.br-side{background:#faf8f3;border-right:1px solid var(--line);padding:16px 13px;display:flex;flex-direction:column;gap:9px}
.br-side .s-item{font-size:.62rem;color:var(--stone)}
.br-side .s-item.on{color:var(--ink);font-weight:400}
.br-main{padding:18px}
.br-h{font-family:var(--sans);font-weight:300;font-size:1.1rem;color:var(--ink);letter-spacing:-.03em}
.br-sub{font-size:.6rem;color:var(--clay);letter-spacing:.02em;margin-top:2px}
.adh{margin-top:16px;display:grid;gap:11px}
.adh-row{display:grid;grid-template-columns:98px 1fr 34px;gap:12px;align-items:center}
.adh-row .a-lab{font-size:.66rem;color:var(--ink)}
.adh-row .a-track{height:7px;border-radius:100px;background:var(--paper-2);overflow:hidden}
.adh-row .a-track i{display:block;height:100%;background:var(--stone);border-radius:100px}
.adh-row .a-pct{font-size:.62rem;color:var(--clay);text-align:right}
.mock-cap{font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;color:var(--clay);margin-top:16px;text-align:center}

/* Frameless mini app-screens for the three-up shots row */
.shots .shot{aspect-ratio:9/17;background:linear-gradient(160deg,#fdfcf9,#f1ede3);border:1px solid var(--line);
  border-radius:14px;padding:11px 9px 9px;display:flex;flex-direction:column;gap:6px;overflow:hidden;
  box-shadow:0 12px 22px -18px rgba(168,159,141,.7)}
.shots .s-eye{font-size:.4rem;letter-spacing:.14em;text-transform:uppercase;color:var(--clay);display:block}
.shots .s-h{font-size:.66rem;color:var(--ink);letter-spacing:-.02em;line-height:1.1;margin-top:1px}
.shots .s-mini{background:#fff;border:1px solid var(--line);border-radius:9px;padding:7px 8px}
.shots .s-mini .t{font-size:.46rem;line-height:1.35;color:var(--stone)}
.shots .s-mini .t b{color:var(--ink);font-weight:400}
.shots .s-row{display:flex;align-items:center;gap:5px}
.shots .s-row svg{width:11px;height:11px;color:var(--stone);flex:none}
.shots .s-3{display:grid;grid-template-columns:repeat(3,1fr);gap:4px}
.shots .s-3 span{background:#fff;border:1px solid var(--line);border-radius:7px;padding:5px 2px;text-align:center;font-size:.55rem;color:var(--ink)}
.shots .s-3 small{display:block;font-size:.34rem;letter-spacing:.08em;text-transform:uppercase;color:var(--clay);margin-top:1px}
.shots .s-chart{height:34px;display:flex;align-items:flex-end;gap:2px}
.shots .s-chart s{flex:1;background:var(--paper-2);border-radius:1.5px;display:block}
.shots .s-chart s.hi{background:var(--stone)}
.shots .s-cal{display:grid;grid-template-columns:repeat(7,1fr);gap:3px;margin-top:2px}
.shots .s-cal s{aspect-ratio:1;border-radius:50%;background:var(--paper);display:block}
.shots .s-cal s.p{background:#d8cfc0}
.shots .s-cal s.o{background:var(--ink)}
.shots .s-cal s.f{outline:1px solid var(--clay);outline-offset:-1px}
.shots .s-pill{margin-top:auto;background:var(--ink);color:#fff;font-size:.46rem;text-align:center;padding:5px 0;border-radius:100px}

/* ============================================================
   AUDIENCE PATHS — two large boxes, one per audience, distinct CTAs.
   ============================================================ */
/* Two large white cards on a paper block — they separate by FILL, no borders
   (brand rule). Bigger audience labels so the two paths read clearly. */
/* ============ SWIPE ROWS (phones only) ============
   Some sets are a column on a phone purely because a grid collapses to one —
   three phone mocks stacked was 1523px of #patient-view, and two audience cards
   stacked was 1735px of #who. Neither is a list you read top to bottom; they are
   alternatives you compare. So on a phone they become one horizontal row you
   swipe, which costs the height of ONE item instead of all of them.

   The peek is the whole affordance: items are sized under 100% so the next one
   shows at the edge and the row reads as scrollable without a control to say so.
   Native scroll-snap, so there is no script and the keyboard and screen readers
   get it for free. It bleeds to the screen edge by cancelling .wrap's padding,
   or the peek would sit inside a margin and look like a mistake. */
@media(max-width:659px){
  /* compounded on purpose: the sets this is applied to set their own display
     (.aud2 is a grid, .patient-view is a grid) in rules that come later, and a
     bare .swipe at the same weight loses to both. */
  .swipe,.aud2.swipe,.patient-view.swipe{
    display:flex;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;scroll-padding-left:var(--pad);
    gap:12px;margin-left:calc(-1 * var(--pad));margin-right:calc(-1 * var(--pad));
    padding-left:var(--pad);padding-right:var(--pad);
    scrollbar-width:none;-ms-overflow-style:none}
  .swipe::-webkit-scrollbar{display:none}
  .swipe > *{flex:0 0 auto;scroll-snap-align:start}
  /* two big cards: nearly full width, a thumb's worth of the next one showing */
  .aud2.swipe > *{width:90%}
  /* three phones: narrower, so two neighbours are visible at rest */
  .patient-view.swipe > *{width:62%;max-width:none}
  .patient-view.swipe .phone{max-width:none}
}

.aud2{display:grid;gap:18px;margin-top:clamp(30px,4vw,52px)}
@media(min-width:860px){.aud2{grid-template-columns:1fr 1fr;gap:24px}}
/* The photograph is an image band at the top of the card, at full strength.
   It used to sit behind the copy under a 74–98% wash, which meant the card
   carried a photograph nobody could see and the page lost its only mid-page
   contrast. Copy sits below it on a solid fill, so nothing has to be scrimmed. */
.pathcard{position:relative;overflow:hidden;border-radius:var(--r);
  display:flex;flex-direction:column;color:var(--ink);background:var(--white);
  box-shadow:0 46px 84px -52px rgba(46,42,37,.32)}
.pathcard .pc-media{display:block;width:100%;aspect-ratio:16/10;object-fit:cover}
.pc-body{padding:clamp(28px,3.4vw,46px);display:flex;flex-direction:column;flex:1}
.path-h{font-size:clamp(1.35rem,2.4vw,1.7rem);letter-spacing:-.03em;color:var(--ink);font-weight:300;line-height:1.08}
.path-sub{font-size:clamp(1.02rem,1.7vw,1.2rem);color:var(--stone);letter-spacing:-.01em;margin:9px 0 24px}
.pathcard .lede{font-size:.95rem;line-height:1.55;color:var(--stone);margin-bottom:26px;max-width:40ch}
.pathcard ul{list-style:none;margin:0 0 32px;display:grid;gap:13px}
.pathcard li{font-size:.9rem;color:var(--stone);padding-left:22px;position:relative;line-height:1.5;max-width:42ch}
.pathcard li b{color:var(--ink);font-weight:400}
.pathcard li::before{content:"";position:absolute;left:2px;top:8px;width:7px;height:7px;border-radius:50%;background:var(--clay)}
.pathcard .cta-row{margin-top:auto;display:flex;flex-wrap:wrap;gap:12px;align-items:center;position:relative;z-index:2}

/* ============ THE WHOLE CARD IS A LINK ============
   Anchors cannot nest, and these cards contain their own links, so the card is
   NOT wrapped in an <a>. Instead the heading's link stretches a transparent
   pseudo-element over the whole card. Everything the visitor might click for a
   different destination — the CTA button and the arrow link — sits in .cta-row,
   which is raised above that overlay and keeps its own target.

   Keep the link on the heading: its text ("For women") is what a screen reader
   announces for the whole card, so it has to read as a destination on its own. */
.pathcard .card-link{color:inherit;text-decoration:none}
.pathcard .card-link::after{content:"";position:absolute;inset:0;z-index:1}
.pathcard{transition:transform .3s ease, box-shadow .3s ease}
.pathcard:hover{transform:translateY(-4px);
  box-shadow:0 58px 96px -48px rgba(46,42,37,.44)}
.pathcard .pc-media{transition:transform .6s ease}
.pathcard:hover .pc-media{transform:scale(1.035)}
/* the overlay swallows the link's own outline, so the focus ring goes on the card */
.pathcard:has(.card-link:focus-visible){outline:2px solid var(--accent);outline-offset:4px}
@media (prefers-reduced-motion:reduce){
  .pathcard:hover{transform:none}
  .pathcard:hover .pc-media{transform:none}
}
.pathcard .note{font-size:.8rem;color:var(--stone);margin-top:14px;font-weight:400}

/* The routine section: a full-strength photograph beside the steps. The middle
   third of the page ran from the audience cards to the closing image with no
   dark element in it at all, which is most of what made the page feel flat. */
.rt-split{display:grid;gap:clamp(20px,3vw,40px);margin-top:clamp(30px,4vw,52px)}
@media(min-width:900px){.rt-split{grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);align-items:stretch}}
.rt-photo{width:100%;height:100%;min-height:clamp(300px,36vw,460px);object-fit:cover;
  object-position:center 45%;border-radius:var(--r);display:block}
.rt-steps{display:grid;gap:clamp(20px,2.6vw,32px);align-content:center}

/* Fewer symbols — the signal-mark icons come off the content rows (kept only
   inside the product mockups, where they read as app UI). */
.row svg{display:none}
@media(min-width:760px){.row{grid-template-columns:minmax(0,18ch) 1fr;gap:40px}}

/* Each of the five carries two lines: what it covers, then why it matters.
   The "what" is set in ink so the eye can skim the five definitions without
   reading the reasoning; the "why" sits back a step for whoever wants it. */
.what-why{display:grid;gap:7px}
.what-why .what{color:var(--ink)}
.what-why .why{color:var(--stone)}
.beige .what-why .why{color:var(--stone-deep)}
@media(min-width:760px){.dims .row{align-items:start}.dims .row .dico{margin-top:2px}}

/* Five dimensions: bring the signal marks back, one per dimension, each in a
   soft tint of that dimension's brand colour (the same palette the app uses). */
.dims .row{align-items:center}
.dims .dico{width:42px;height:42px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;
  background:color-mix(in srgb, var(--dim) 22%, #ffffff)}
.dims .dico svg{display:block;width:21px;height:21px;color:var(--dim);position:static;top:auto}
@media(min-width:760px){.dims .row{grid-template-columns:42px minmax(0,14ch) minmax(0,1fr);gap:28px}}

/* Five stages, set large. These were five rows of small text carrying five
   words of real content — the names are the content, so they get display size
   and the description sits beside them. This is where the page's scale contrast
   comes from: nothing else in the middle of the page is set this big. */
.stages{margin-top:clamp(28px,3.6vw,48px)}
.stage{padding:clamp(20px,2.6vw,30px) 0;border-top:1px solid var(--line);display:grid;gap:10px}
.stage:last-child{border-bottom:1px solid var(--line)}
@media(min-width:900px){
  .stage{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
         gap:clamp(28px,4vw,72px);align-items:baseline}
}
.stage h3{font-size:clamp(1.55rem,3.6vw,2.7rem);font-weight:300;letter-spacing:-.035em;line-height:1.03}
.stage p{font-size:.92rem;line-height:1.6}
.beige .stage{border-color:rgba(90,83,70,.24)}

/* Numbered steps — used where columns are a real sequence (How it works). */
.numbered{counter-reset:step}
.numbered .col{counter-increment:step;position:relative;padding-top:26px;border-top:1px solid var(--line)}
/* The step number sits on the rule, so it needs to knock a hole in it — the
   background must match whatever the section is filled with, not a fixed tint. */
.numbered .col::before{content:counter(step,decimal-leading-zero);position:absolute;top:0;left:0;
  transform:translateY(-50%);background:var(--white);padding:0 10px 0 0;
  font-size:.72rem;letter-spacing:.14em;color:var(--accent-dark)}
.beige .numbered .col::before{background:var(--brand)}
.numbered .col h3{margin:8px 0 12px}
@media(min-width:760px){.numbered.cols-3{gap:clamp(30px,4vw,56px)}}

/* The app screens as proof inside another section: a rule and a sub-head set
   them apart from the claim above without making them a section of their own. */
.proof{margin-top:clamp(44px,6vw,86px);padding-top:clamp(30px,4vw,48px);border-top:1px solid var(--line)}
.beige .proof{border-top-color:rgba(90,83,70,.24)}
.proof h3{margin-bottom:10px}
.proof>p{max-width:52ch}

/* ============ CROSS-PAGE LINKS ============
   The homepage carries one proof of each side and hands off to the two
   point-of-view pages for depth. These are the hand-offs. */
/* Deliberately NOT --accent-dark. These are quiet "read more" links inside
   cards, and in the accent they read as warnings — the only red text on an
   otherwise warm neutral page. --clay-deep is the page's own brown, so they
   sit in the palette instead of shouting, and they stop changing meaning every
   time the accent does. 6.4:1 on paper. */
.more-link,.link-arrow{display:inline-block;font-size:.85rem;color:var(--clay-deep);
  text-decoration:none;border-bottom:1px solid rgba(125,109,81,.34);padding-bottom:2px;
  transition:color .2s,border-color .2s}
.more-link:hover,.link-arrow:hover{color:var(--ink);border-bottom-color:var(--ink)}
.link-arrow{font-size:.82rem;border-bottom:0}
.link-arrow:hover{text-decoration:underline;text-underline-offset:4px}
.cta-row{flex-wrap:wrap;gap:14px 20px}

/* A single app screen, where the homepage only needs to prove the app exists */
.proof-one{display:flex;flex-direction:column;align-items:center;gap:18px;
  margin-top:clamp(26px,3.4vw,44px)}
.proof-one .phone{max-width:230px;width:100%}
.proof-one p{margin:0}

/* App gallery — a row of real current-app screenshots in phone frames */
.gallery{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,2.5vw,26px);margin-top:clamp(26px,3.4vw,44px);align-items:start}
.gallery .phone{max-width:230px;width:100%;margin:0 auto}
.gallery .phone .screen{background:#fbfaf6}
.g-cap{text-align:center;font-size:clamp(.86rem,1.15vw,.95rem);line-height:1.45;
  letter-spacing:-.01em;color:var(--stone-deep);margin-top:22px;max-width:26ch;
  margin-left:auto;margin-right:auto}
@media(max-width:620px){.gallery{grid-template-columns:1fr;max-width:280px;margin-left:auto;margin-right:auto;gap:34px}}

/* Framed product screenshot (portal) — a real screenshot, softly framed */
.shot-frame{border-radius:16px;overflow:hidden;margin-top:clamp(30px,4vw,52px);
  box-shadow:0 50px 90px -50px rgba(46,42,37,.4),0 12px 26px -16px rgba(46,42,37,.28);background:#fff}
.shot-frame img{width:100%;height:auto;display:block}

/* Closing CTA on real brand photography */
.close-photo{position:relative;overflow:hidden;padding:clamp(84px,15vw,190px) 0;isolation:isolate;background:#8f877f}
.close-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 52%;z-index:-2}
.close-tint{position:absolute;inset:0;z-index:-1;background:linear-gradient(180deg,rgba(46,42,37,.46),rgba(46,42,37,.72))}
.close-photo h2{color:#fff;max-width:15ch;margin-bottom:clamp(30px,4vw,40px)}
.close-photo .btn{background:#fff;color:var(--ink);border-color:#fff}
.close-photo .btn:hover{background:var(--paper);border-color:var(--paper)}
.close-photo .btn-alt{background:transparent;color:#fff;border-color:rgba(255,255,255,.55)}
.close-photo .btn-alt:hover{background:#fff;color:var(--ink);border-color:#fff}
.close-note{margin-top:22px;font-size:.85rem;color:rgba(255,255,255,.7)}

/* ============================================================
   MOTION
   One system, three jobs: content arrives, ambient surfaces drift,
   and one element demonstrates a claim instead of asserting it.

   All of it is gated behind html.js, and the inline script in each page
   only adds that class when the visitor has NOT asked for reduced motion.
   So "prefers-reduced-motion: reduce" turns the whole system off in one
   place, and a visitor with JS disabled sees a fully static page with
   nothing hidden.
   ============================================================ */

/* --- content arrives --------------------------------------------------
   A single gesture, used everywhere: 16px up, over 0.85s, on an ease-out
   curve. Resist adding a second gesture — the restraint is what makes it
   read as the page settling rather than as effects firing. */
/* The hidden state is wrapped in :where() so it contributes NO specificity.
   Without that, `html.js .rows > .row` (0,3,1) outranks `html.js .in` (0,2,1)
   and those elements can never reveal — they stay invisible forever while
   single-class targets like .lead reveal normally, which looks like a timing
   bug and is not one. Keep :where() here if you add selectors. */
html.js :where(
  .lead,
  .cols > .col,
  .rows > .row,
  .stage,
  .pathcard,
  .proof,
  .proof-one,
  .gallery > div,
  .shot-frame,
  .rt-photo,
  .rt-steps > .col,
  .step,
  .scard,
  .tstop,
  .bcard,
  .phase,
  .chatline){
  opacity:0;transform:translateY(16px);
  transition:opacity .85s cubic-bezier(.22,.61,.36,1),transform .85s cubic-bezier(.22,.61,.36,1)}
html.js .in{opacity:1;transform:none}

/* --- ambient drift ----------------------------------------------------
   The cycle contour is the brand mark, so drifting it is the one piece of
   motion nobody else can copy. Each line runs at a different duration, so
   they slide past each other and never resolve into a repeating pattern.
   Minutes, not seconds — it should never be caught moving. */
.contour path{animation:contour-drift 52s ease-in-out infinite alternate}
.contour path:nth-child(2){animation-duration:61s}
.contour path:nth-child(3){animation-duration:47s}
.contour path:nth-child(4){animation-duration:69s}
.contour path:nth-child(5){animation-duration:56s}
@keyframes contour-drift{from{transform:translate3d(0,0,0)}to{transform:translate3d(-24px,7px,0)}}

/* the shaft of daylight crosses the beige the way the sun actually moves */
@keyframes sun-drift{from{transform:translateX(-3%)}to{transform:translateX(7%)}}

@media (prefers-reduced-motion:reduce){
  .contour path,.s-shaft::before{animation:none}
}

/* --- the chat line ----------------------------------------------------
   "Logging takes seconds, not a form" is the one claim on the page that can
   be demonstrated rather than stated, so it is. The line types what a member
   would actually say, and the five phrases are one per tracked area — cycle,
   nutrition, movement, sleep, labs — so it doubles as proof that all five
   are logged the same way. The markup carries a real first phrase, so with
   JS off it is simply a static example. */
.chatline{max-width:470px;margin:0 auto clamp(22px,3vw,34px);
  display:flex;align-items:center;gap:13px;background:#fff;
  border:1px solid var(--line);border-radius:100px;padding:15px 22px;
  box-shadow:0 16px 34px -24px rgba(46,42,37,.45)}
.beige .chatline{border-color:rgba(90,83,70,.16)}
.chatline .dot{width:7px;height:7px;border-radius:50%;background:var(--accent);flex:none}
.chatline .txt{font-size:.93rem;color:var(--ink);line-height:1.4;min-height:1.4em}
.chatline .caret{display:inline-block;width:1.5px;height:1em;background:var(--accent);
  margin-left:3px;vertical-align:-.14em}
html.js .chatline .caret{animation:caret-blink 1.1s steps(1) infinite}
@keyframes caret-blink{50%{opacity:0}}

/* ============================================================
   PAGE-SPECIFIC LAYOUTS

   The two point-of-view pages must not look like each other. They carry
   different arguments to different readers, and a shared layout makes the
   site feel like one page with the nouns swapped.

     for-women.html      spacious and image-led — a walkthrough. Steps
                         alternate sides, each with the screen it describes.
     for-practitioners   dense and list-led — a briefing. Phases sit in
                         parallel columns with what each one contains.

   Keep that contrast if you add sections.
   ============================================================ */

/* --- WALKTHROUGH (for-women) — steps alternate sides down the page --- */
.steps{display:grid;gap:clamp(46px,6.5vw,96px);margin-top:clamp(34px,4.5vw,62px);counter-reset:step}
.step{display:grid;gap:clamp(22px,3vw,48px);align-items:center;counter-increment:step}
@media(min-width:900px){
  .step{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .step:nth-child(even) .step-media{order:2}
}
.step-media{display:flex;flex-direction:column;align-items:center;gap:clamp(16px,2vw,24px)}
.step-media .phone{max-width:248px;width:100%}
.step-media .chatline{margin:0;max-width:330px}
.step-copy{max-width:46ch}
.step-copy .n{display:block;font-size:.72rem;letter-spacing:.18em;color:var(--accent-dark);margin-bottom:15px}
.step-copy .n::before{content:counter(step,decimal-leading-zero)}
.step-copy h3{font-size:clamp(1.45rem,3vw,2.1rem);font-weight:300;letter-spacing:-.035em;line-height:1.06;margin-bottom:13px}
.step-copy ul{list-style:none;margin:20px 0 0;display:grid;gap:11px}
.step-copy li{font-size:.9rem;line-height:1.55;padding-left:21px;position:relative}
.step-copy li::before{content:"";position:absolute;left:2px;top:8px;width:6px;height:6px;border-radius:50%;background:var(--clay)}

/* --- BENEFIT CARDS (for-women) — soft, roomy, three across --- */
.bene{display:grid;gap:14px;margin-top:clamp(30px,4vw,54px)}
@media(min-width:700px){.bene{grid-template-columns:repeat(2,1fr);gap:16px}}
@media(min-width:1040px){.bene{grid-template-columns:repeat(3,1fr)}}
.bcard{background:var(--white);border-radius:var(--r);padding:clamp(24px,2.8vw,36px);
  box-shadow:0 22px 48px -38px rgba(46,42,37,.42)}
.bcard h3{font-size:1.05rem;margin-bottom:10px}
.bcard p{font-size:.9rem;line-height:1.6}

/* --- PHASES (for-practitioners) — parallel columns, each with its contents --- */
.phases{display:grid;gap:clamp(28px,3.2vw,44px);margin-top:clamp(30px,4vw,54px);counter-reset:ph}
@media(min-width:820px){.phases{grid-template-columns:repeat(3,1fr)}}
.phase{counter-increment:ph;border-top:1px solid var(--line);padding-top:24px}
.beige .phase{border-top-color:rgba(90,83,70,.24)}
.phase .n{display:block;font-size:.68rem;letter-spacing:.18em;color:var(--accent-dark);margin-bottom:13px}
.phase .n::before{content:"PHASE " counter(ph)}
.phase ul{list-style:none;margin:15px 0 0;display:grid;gap:10px}
.phase li{font-size:.86rem;line-height:1.5;padding-left:19px;position:relative}
.phase li::before{content:"";position:absolute;left:0;top:8px;width:5px;height:5px;border-radius:50%;
  background:var(--accent);opacity:.55}

/* --- TESTIMONIALS --- */
/* A card still waiting for a real quote. It is styled exactly like a live one so
   the section can be judged on its design — but the COPY inside it is bracketed,
   and must stay bracketed. That is the only thing stopping a placeholder from
   shipping as a testimonial, which is not a mistake we get to make twice. */

/* ============ MEDIA WARMTH ============
   A slight warm grade on the photography so the images sit in the same light
   as the page. Deliberately NOT applied to app or portal screenshots — tinting
   product UI misrepresents what it looks like. Keep it subtle; this is a grade,
   not a filter effect. */
.hero-film,.pc-media,.rt-photo,.close-bg,.bleed img{
  filter:var(--warm-photo);
}
@media (prefers-reduced-motion:no-preference){}

/* ============ WHERE THE ORANGE LANDS ============
   Widened deliberately, but only onto marks and small dark-step text — the
   bright accent still never sits behind a word. Orange carries no meaning
   anywhere: no status, no category, no ranking. */
.faq summary::after{color:var(--accent-dark)}
.step-copy li::before{background:var(--accent)}
.pathcard li::before{background:var(--accent)}
.stage h3 .mark,.lead .rule{display:block;width:34px;height:2px;background:var(--accent);
  border-radius:2px;margin-bottom:18px}
.g-cap{color:var(--accent-dark)}

/* ============ THE ONE APRICOT BLOCK ============
   Both reference sites give their brand colour a third to a half of the page as
   large tinted blocks, and put only a small amount of it on the buttons. Ours
   cannot follow that literally — apricot and beige are neighbours on the wheel,
   so a pale tint reads as a slightly different beige rather than as a colour.
   This tint is therefore stronger than a wash, and it appears EXACTLY ONCE per
   page. Two of them and the page stops having a ground.

   Small grey text does not go on it: --clay only reaches 3.8:1 here. Use --ink
   or --stone. */
/* Mixed toward --paper, the same treatment the deep-dive heroes get. Neat
   --accent-pale is a full stop against the paper panels either side of it —
   the same red, but 22 lower on green and 29 on blue — so a block set in it
   read as a different material rather than as the page warmed at one corner.
   Only one apricot in the system now; the hero adds its light pool on top. */
/* NO PINK. The founder looked at the block set in --accent-pale and said not
   to use that colour. The section is the paper, with the same light pool the
   other panels carry, and nothing tinted. */
.apricot{background:
  radial-gradient(58% 56% at 14% 8%, rgba(255,250,243,.5) 0%, rgba(255,250,243,0) 62%),
  var(--paper)}
.apricot .note,.apricot .g-cap,.apricot cite{color:var(--stone)}
.apricot .rows,.apricot .row,.apricot .phase,.apricot .stage{border-color:rgba(140,90,50,.22)}

/* ============ WITHOUT / WITH ============
   Problem on the left, answer on the right. The pair only makes sense read
   across, so the column headings appear only when the two actually sit side by
   side; stacked, each half labels itself instead. */
.diff{margin-top:clamp(28px,3.4vw,46px)}
.diff-head{display:none}
.diff-row{display:grid;gap:clamp(14px,2vw,38px);
  padding:clamp(20px,2.4vw,30px) 0;border-top:1px solid var(--line)}
@media(min-width:860px){
  .diff-head{display:grid;grid-template-columns:1fr 1fr;gap:clamp(20px,2.6vw,38px);
    font-size:.74rem;letter-spacing:.15em;text-transform:uppercase;color:var(--clay);
    padding-bottom:.9em}
  .diff-row{grid-template-columns:1fr 1fr}
}
@media(max-width:859px){
  .diff-a::before{content:"Without SAAGA"}
  .diff-b::before{content:"With SAAGA"}
  .diff-a::before,.diff-b::before{display:block;font-size:.7rem;letter-spacing:.15em;
    text-transform:uppercase;color:var(--clay);margin-bottom:.6em}
}
/* text-wrap:balance is right for a long display heading and wrong for these.
   The switch's headings are two or three words in a half-width column, and
   balance was evening them into "One / timeline" and "Read against your /
   phase" — two short lines where one full one was available. */
/* `wrap`, NOT `normal`. text-wrap takes wrap | nowrap | balance | pretty |
   stable — `normal` is not one of them, so the declaration was thrown away and
   the h3 rule's balance kept applying. It looked fixed in a headless check and
   was still splitting in a real browser. */
.diff-row h3{text-wrap:wrap}

/* --- the Without / With switch ---
   Added by the script; without it none of this matches and the section stays
   the two-column table in the markup. The state lives on the SECTION so the
   ground, the type and the copy can all turn together: the point of the section
   is the turn, so it has to be felt and not just read. */
.has-switch{transition:background-color .9s ease}
/* background-COLOR, not the `background` shorthand. A var() inside the shorthand
   is kept as a pending substitution rather than resolved to a colour, and a
   pending substitution will not interpolate against a transitioning
   background-color — the section stayed frozen on the grey through the whole
   transition, with the type and the accent turning around it. */
.has-switch[data-side="a"]{background-color:#eae8e4}      /* cool, flat, dull */
.has-switch[data-side="b"]{background-color:var(--paper)} /* SAAGA's own beige */

.diff-switch{display:flex;width:max-content;gap:4px;padding:4px;margin:clamp(22px,2.6vw,32px) auto 0;
  border-radius:100px;background:rgba(90,83,70,.09);transition:background .9s ease}
.diff-tab{font:inherit;font-size:.78rem;letter-spacing:.01em;font-weight:500;
  padding:9px 18px;border:0;border-radius:100px;background:transparent;
  color:var(--stone-deep);cursor:pointer;white-space:nowrap;
  transition:background .3s ease,color .3s ease,box-shadow .3s ease}
.diff-tab.on{background:var(--white);color:var(--ink);
  box-shadow:0 4px 12px -6px rgba(46,42,37,.4)}
.has-switch[data-side="a"] .diff-tab.on{background:#f6f5f4;color:#6f6c67;
  box-shadow:none}

.diff.is-switch{margin-top:clamp(18px,2.2vw,26px)}
/* The script sets [hidden] on the head, which is not enough on its own: the
   860px rule below gives .diff-head display:grid, and a class beats the [hidden]
   attribute at equal weight — so the old column labels kept rendering AND kept
   the grid's first cell, which pushed every statement into the wrong row. */
.diff.is-switch .diff-head{display:none}
.diff.is-switch .diff-row{grid-template-columns:1fr;padding:clamp(16px,1.9vw,22px) 0;
  border-color:rgba(90,83,70,.16);transition:border-color .9s ease}
.has-switch[data-side="a"] .diff-row{border-color:rgba(120,118,114,.22)}
.diff.is-switch .diff-row{display:grid;grid-template-columns:minmax(0,1fr)}
.diff.is-switch .diff-row > .diff-a,.diff.is-switch .diff-row > .diff-b{grid-area:1/1}
.diff.is-switch[data-side="a"] .diff-b,
.diff.is-switch[data-side="b"] .diff-a,
.has-switch[data-side="a"] .diff-b,
.has-switch[data-side="b"] .diff-a{visibility:hidden;pointer-events:none}
/* the switch names the side now, so the per-cell labels would say it twice */
.diff.is-switch .diff-a::before,.diff.is-switch .diff-b::before{content:none}

/* the type carries the turn as much as the ground does */
.has-switch .diff-row h3{transition:color .9s ease}
.has-switch .diff-row p{transition:color .9s ease}
.has-switch[data-side="a"] .diff-a h3{color:#7e7b76;font-weight:300}
.has-switch[data-side="a"] .diff-a p{color:#94918c}
.has-switch[data-side="b"] .diff-b h3{color:var(--ink)}
.has-switch[data-side="b"] .diff-b p{color:var(--stone-deep)}
/* No mark before the titles. There was a dot, grey on the without and the
   accent on the with; the founder said it looked bad. The turn is carried by
   the ground, the type and the words. */
.has-switch .diff-row h3::before{content:none}

@media(min-width:860px){
  .diff.is-switch{display:grid;grid-template-columns:1fr 1fr;
    column-gap:clamp(28px,3.4vw,58px);align-items:start}
  .diff.is-switch .diff-row:nth-child(-n+3){border-top:0}
  .diff.is-switch .diff-row:nth-child(n+4){border-top:1px solid}
}

/* The turn is a CURTAIN, not a fade: each statement is revealed left to right
   by an animated clip-path, staggered so the set rewrites itself top to bottom.
   A light sweep runs across the whole block at the same time, which is what
   makes it read as one gesture rather than four separate reveals. */
.diff.is-switch{position:relative}
.diff.is-switch.swap .diff-row > div{animation:diffWipe .62s cubic-bezier(.3,.72,.22,1) both}
.has-switch[data-dir="back"] .diff.is-switch.swap .diff-row > div{animation-name:diffWipeBack}
.diff.is-switch.swap .diff-row:nth-child(3) > div{animation-delay:.07s}
.diff.is-switch.swap .diff-row:nth-child(4) > div{animation-delay:.14s}
.diff.is-switch.swap .diff-row:nth-child(5) > div{animation-delay:.21s}
@keyframes diffWipe{
  from{clip-path:inset(0 100% 0 0);opacity:.25}
  to{clip-path:inset(0 0 0 0);opacity:1}}
@keyframes diffWipeBack{
  from{clip-path:inset(0 0 0 100%);opacity:.25}
  to{clip-path:inset(0 0 0 0);opacity:1}}
/* position:absolute keeps this out of flow — an in-flow ::after on a grid
   container becomes a grid ITEM and would sit in the layout as a fifth cell */
.diff.is-switch.swap::after{content:"";position:absolute;top:-6px;bottom:-6px;left:0;
  width:38%;pointer-events:none;z-index:2;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.34) 50%,transparent);
  animation:diffSweep .85s cubic-bezier(.36,.6,.28,1) both}
.diff-photo .diff.is-switch.swap::after{
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.20) 50%,transparent)}
@keyframes diffSweep{from{transform:translateX(-120%)}to{transform:translateX(300%)}}
@media(prefers-reduced-motion:reduce){
  .diff.is-switch.swap .diff-row > div{animation:none}
  .diff.is-switch.swap::after{display:none}
  .has-switch,.has-switch .diff-row h3,.has-switch .diff-row p{transition:none}
}


.diff h3{font-size:clamp(1.05rem,1.45vw,1.2rem);margin-bottom:.45em}
.diff p{font-size:.98rem;line-height:1.6;color:var(--stone);max-width:42ch}
.diff-a h3{font-weight:300;color:var(--stone)}
/* the answer side carries the accent rule, so a glance lands on it first */
.diff-b{border-left:2px solid var(--accent);padding-left:clamp(14px,1.6vw,22px)}
.diff-b h3{font-weight:400;color:var(--ink)}

/* ============ FEATURE TABS ============
   Names on the left, the chosen one on the right. Replaces a scroll-driven card
   stack: the reader decides what to look at and when, and nothing moves while
   they are reading it. */
.tabs{display:grid;gap:clamp(26px,3.4vw,44px);margin-top:clamp(28px,3.6vw,48px)}
@media(min-width:900px){
  .tabs{grid-template-columns:minmax(0,.5fr) minmax(0,1.5fr);
    gap:clamp(30px,3.6vw,58px);align-items:start}
  .tab-side{position:sticky;top:calc(var(--gap) + 104px)}
}
.tab-list{display:flex;flex-direction:column}
.tab-list button{appearance:none;background:none;border:0;cursor:pointer;
  font-family:var(--sans);font-weight:300;color:var(--stone);
  font-size:clamp(.95rem,1.12vw,1.08rem);letter-spacing:-.01em;line-height:1.3;
  text-align:left;padding:.7em 0 .7em .95em;
  border-left:2px solid var(--line);transition:color .18s ease,border-color .18s ease}
.tab-list button:hover{color:var(--ink)}
/* selected state is carried by the rule and the weight, not a fill — a filled
   pill would read as a button to press rather than as the current section */
.tab-list button[aria-selected="true"]{color:var(--ink);font-weight:400;
  border-left-color:var(--accent)}
.tab-side .btns{margin-top:clamp(24px,2.8vw,34px)}

.tab-panel{display:grid;gap:clamp(20px,2.6vw,34px)}
/* The UA rule is [hidden]{display:none} at (0,1,0) — the same specificity as
   .tab-panel — and author styles win ties, so display:grid silently kept every
   panel visible however many times the script set .hidden = true. */
.tab-panel[hidden]{display:none}
@media(min-width:700px){
  /* start, not center. Centred, the copy floated down the middle of the tall
     phone while the tab list sat at the top, so the three columns each began at
     a different height and nothing lined up across the row. */
  .tab-panel{grid-template-columns:minmax(0,1fr) minmax(0,1.08fr);align-items:start}
}
.tab-copy h3{font-size:clamp(1.45rem,2.3vw,2rem);margin-bottom:.55em}
.tab-copy p{color:var(--stone);font-size:clamp(1rem,1.2vw,1.1rem);line-height:1.6;margin-bottom:1.05em}
.tab-copy ul{list-style:none;padding:0;margin:0}
.tab-copy li{position:relative;padding-left:1.2em;margin-bottom:.55em;
  font-size:1rem;color:var(--stone)}
.tab-copy li::before{content:"";position:absolute;left:0;top:.62em;
  width:.4em;height:.4em;border-radius:50%;background:var(--accent)}
.tab-panel .sc-media{margin:0}
/* .sc-media .phone{max-width:142px} is the same specificity and sits LATER in
   the file, so it won every tie. Match one level deeper to actually take. */
.tab-panel .sc-media .phone{max-width:272px;width:100%;margin:0 auto}
.tab-panel .sc-media{padding:26px 0 0}
.tab-panel .sc-media.sc-flat{padding:22px}

/* ============ SCROLLING CARD RAIL ============
   A horizontal rail for "how it works" on both point-of-view pages. Native
   overflow scrolling with snap — no JS, so it works with the script disabled
   and it keeps momentum scrolling on touch.

   The negative margin pulls the rail out to the edge of the shape while the
   padding puts the first card back on the text margin, so cards run off the
   side rather than stopping short. It needs tabindex="0" in the markup: a
   scroll container that keyboard users cannot reach is a trap. */
.scroller{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(266px,332px);
  gap:clamp(12px,1.4vw,18px);
  overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x proximity;
  margin:clamp(28px,3.6vw,48px) calc(var(--pad) * -1) 0;
  padding:2px var(--pad) 18px}
.scroller:focus-visible{outline:2px solid var(--accent-dark);outline-offset:4px}
.scroller::-webkit-scrollbar{height:6px}
.scroller::-webkit-scrollbar-track{background:transparent}
.scroller::-webkit-scrollbar-thumb{background:rgba(65,58,48,.20);border-radius:100px}
.scroller::-webkit-scrollbar-thumb:hover{background:rgba(65,58,48,.34)}

.scard{scroll-snap-align:start;background:var(--white);border-radius:var(--r);
  padding:clamp(22px,2.4vw,30px);display:flex;flex-direction:column;
  box-shadow:0 22px 48px -38px rgba(46,42,37,.42)}
.scard .n{display:block;font-size:.7rem;letter-spacing:.18em;color:var(--accent-dark);margin-bottom:13px}
.scard h3{font-size:1.08rem;margin-bottom:9px}
.scard p{font-size:.9rem;line-height:1.6}
.scard ul{list-style:none;margin:15px 0 0;display:grid;gap:8px}
.scard li{font-size:.84rem;line-height:1.5;padding-left:17px;position:relative}
.scard li::before{content:"";position:absolute;left:0;top:8px;width:5px;height:5px;
  border-radius:50%;background:var(--accent)}
/* a screen inside the card, for the consumer rail only */
.scard-media{background:var(--paper);border-radius:calc(var(--r) - 12px);
  margin-bottom:18px;padding:18px 0 0;display:flex;justify-content:center;overflow:hidden}
.scard-media .phone{max-width:148px;width:100%}
.scard-media .chatline{margin:0 14px 18px;max-width:none;padding:11px 16px}
.scard-media .chatline .txt{font-size:.8rem}

/* ============ THE FIVE AREAS ============
   Cards rather than rows, with a real hierarchy: the cycle spans the full width
   because the copy says the other four are read against it, and the layout
   should say the same thing. Each card carries its pillar colour on the top
   edge and in the icon tint — the same values the app uses.

   They arrive staggered on scroll (see the motion section). The rise is a
   little further and the scale a little deeper than the page default, because
   this is the one section that should feel like it assembles. */
.areas{display:grid;gap:14px;margin-top:clamp(30px,4vw,54px)}
@media(min-width:700px){.areas{grid-template-columns:repeat(2,1fr);gap:16px}}
@media(min-width:1080px){.areas{grid-template-columns:repeat(4,1fr)}}
/* Plain white, no rule and no shadow. The coloured top edge and the drop shadow
   were doing decoration rather than work — the pillar colour is already carried
   by the icon tint, which is where it means something.

   This only reads because the section behind is the beige ground: white on the
   paper panel separates at 1.12:1 and the cards would all but disappear. If the
   fill of #tracks changes, these need a shadow back. */
.acard{background:var(--white);border-radius:var(--r);padding:clamp(24px,2.6vw,34px);
  display:flex;flex-direction:column}
/* ============ CARD RAIL ============
   One component for the three card sets that do the same job on three pages —
   the five areas on the homepage, "everything in one place" on for-women, and
   the practitioner features. They were three different layouts saying the same
   thing, so they are one now, and it changes shape by device rather than
   shrinking:

     phone  — the cards PILE. Each one sticks a little lower than the last, so
              the set stays on screen while you move through it and you read one
              card at a time instead of scrolling past five.
     desktop— ONE ROW you scroll sideways, snapped, with the next card showing
              at the edge.

   The two halves must never both apply, and not only for looks: a horizontal
   scroll container is exactly the ancestor that kills position:sticky. Same
   reason .acard is no longer in the scroll-reveal list — that animation ends on
   a transform, and a transformed ancestor stops sticky resolving against the
   viewport. Keep both away from these cards. */
@media(max-width:999px){
  .rail,.areas.rail,.stack.rail{display:grid;gap:clamp(14px,2vw,20px)}
  .rail > *{position:sticky}
  /* clears the sticky nav, then steps down so each landed card still shows a
     sliver of the one beneath it */
  .rail > :nth-child(1){top:calc(var(--gap) + 80px)}
  .rail > :nth-child(2){top:calc(var(--gap) + 96px)}
  .rail > :nth-child(3){top:calc(var(--gap) + 112px)}
  .rail > :nth-child(4){top:calc(var(--gap) + 128px)}
  .rail > :nth-child(5){top:calc(var(--gap) + 144px)}
  .rail > :nth-child(6){top:calc(var(--gap) + 160px)}
  /* a pile needs edges: white cards landing on white cards on a light ground */
  .rail > *{box-shadow:0 -1px 0 rgba(90,83,70,.13),0 26px 48px -34px rgba(46,42,37,.45)}
}
@media(min-width:1000px){
  /* compounded: .areas and .stack both declare display:grid further down the
     file, and a bare .rail at equal weight loses to them */
  /* The rail breaks OUT of .wrap to the section's own edges. It was sitting in
     a 1128px column inside a 1391px section — 132px of margin doing nothing on
     each side — so fewer cards were in view than there was room for. The bleed
     is what .wrap takes off: its padding, plus half of whatever max-width is
     holding it in. The same figure comes back as padding, so the first card
     still lines up with the heading above it and only the far edge moves. */
  .rail,.areas.rail,.stack.rail,.patient-view.rail{
    /* No percentage in here on purpose. 100% resolved against the containing
       block differently for margin than for padding, so the rail moved left by
       the wrap's centring offset but the padding did not put the first card
       back — it sat 76px left of its own heading. This is all viewport and
       token units: the section's inner width, less .wrap's content width,
       halved. It equals --pad exactly whenever max-width is not biting. */
    --bleed:calc(((var(--vw) - 2 * var(--gap))
      - (min(var(--maxw), var(--vw) - 2 * var(--gap)) - 2 * var(--pad))) / 2);
    display:flex;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;gap:clamp(16px,1.6vw,22px);
    margin-left:calc(-1 * var(--bleed));
    margin-right:calc(-1 * var(--bleed));
    /* The inset is --pad, not the full bleed. Matching the heading meant the
       first card sat ~132px in while cards ran off the right edge with nothing
       — a deep indent on one side and a bleed on the other, which reads as
       lopsided the moment you land on the section. Same gutter both ends now:
       the row looks even at rest, and even again when it is scrolled out. */
    padding-left:var(--pad);
    padding-right:var(--pad);
    scroll-padding-left:var(--pad);
    padding-bottom:16px;align-items:stretch}
  .rail > *{flex:0 0 clamp(320px,32%,420px);scroll-snap-align:start;position:static;top:auto}
  /* a real, quiet scrollbar — the row has to look scrollable when it is */
  .rail{scrollbar-width:thin;scrollbar-color:rgba(90,83,70,.32) transparent}
  .rail::-webkit-scrollbar{height:6px}
  .rail::-webkit-scrollbar-thumb{background:rgba(90,83,70,.32);border-radius:99px}
  .rail::-webkit-scrollbar-track{background:transparent}
  /* the cards inside carry their own two-column layouts at this width; in a
     392px rail item those have to fold back to one */
  .rail .stackcard{grid-template-columns:1fr}
  .rail .acard.acard-lead{display:flex;grid-column:auto}
}

/* --- the rail's arrows ---
   Only on the width where the rail actually scrolls sideways. Each button is
   hidden at the end it cannot travel any further towards, so which arrows are
   showing IS the position indicator — no dots needed. .rail-wrap is created by
   the script and is position:relative only: give it an overflow or a transform
   and the cards stop sticking when this is a pile on a phone. */
.rail-wrap{position:relative}
.rail-arrow{display:none}
@media(min-width:1000px){
  .rail-arrow{display:grid;place-items:center;position:absolute;top:50%;
    width:42px;height:42px;margin-top:-21px;padding:0;border-radius:50%;
    background:rgba(255,255,255,.94);border:1px solid rgba(90,83,70,.16);
    box-shadow:0 12px 26px -16px rgba(46,42,37,.5);color:var(--ink);
    cursor:pointer;z-index:4;
    opacity:0;pointer-events:none;
    transition:opacity .28s ease,transform .2s ease,background .2s ease}
  .rail-arrow.on{opacity:1;pointer-events:auto}
  .rail-arrow:hover{background:#fff;transform:scale(1.07)}
  .rail-arrow svg{width:14px;height:14px}
  .rail-prev{left:4px}
  .rail-next{right:4px}
}
@media(prefers-reduced-motion:reduce){
  .rail-arrow{transition:opacity .28s ease}
  .rail-arrow:hover{transform:none}
}

.acard .aico{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;margin-bottom:16px;
  background:color-mix(in srgb, var(--dim) 20%, #ffffff)}
.acard .aico svg{width:22px;height:22px;color:var(--dim)}
.acard h3{font-size:1.05rem;margin-bottom:9px}
.acard .what{color:var(--ink);font-size:.9rem;line-height:1.55}
.acard .why{color:var(--stone);font-size:.86rem;line-height:1.6;margin-top:9px}

/* the cycle is the clock the others are read against, so it spans */
.acard.acard-lead{grid-column:1 / -1}
@media(min-width:700px){
  .acard.acard-lead{display:grid;grid-template-columns:auto minmax(0,1fr) minmax(0,1.15fr);
    gap:clamp(20px,2.6vw,36px);align-items:start}
  .acard.acard-lead .aico{margin-bottom:0}
  .acard.acard-lead .why{margin-top:0}
}

/* ============ THE NEWSLETTER BAND ============
   One row on a desktop, stacked on a phone. The label is real rather than a
   placeholder standing in for one: a placeholder disappears the moment someone
   types, which leaves a screen reader and a distracted reader with a bare box.

   The input and the button share a row down to 480px, where the button takes
   the full width instead of squeezing the field below a readable length. */
.news{padding-top:clamp(30px,3.6vw,50px);padding-bottom:clamp(30px,3.6vw,50px)}
/* One column now that the block is the form alone: centred, and no wider than
   the field needs to stay a comfortable length. */
.news-in{display:grid;gap:clamp(20px,2.6vw,34px);align-items:center;
  max-width:540px;margin-inline:auto}
.news-form label{text-align:left}
.news-copy h2{font-size:clamp(1.45rem,2.6vw,1.95rem);margin-bottom:.5em}
.news-copy p{font-size:clamp(.94rem,1.4vw,1.02rem);color:var(--stone-deep);max-width:46ch;margin:0}
.news-form label{display:block;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--clay-deep);margin-bottom:9px}
.news-form{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px}
.news-form label{grid-column:1 / -1;margin-bottom:0}
.news-form input{width:100%;background:var(--white);border:1px solid rgba(90,83,70,.22);
  border-radius:100px;padding:15px 20px;font-family:var(--sans);font-weight:300;
  font-size:1rem;color:var(--ink)}
.news-form input::placeholder{color:var(--clay)}
.news-form input:focus{outline:none;border-color:var(--accent-dark);
  box-shadow:0 0 0 3px rgba(154,58,18,.14)}
.news-form .btn{white-space:nowrap}
.news-note{grid-column:1 / -1;font-size:.78rem;color:var(--clay-deep);margin:2px 0 0}
@media(max-width:479px){
  .news-form{grid-template-columns:minmax(0,1fr)}
}
/* --- the signup, on the closing photograph ---
   Everything here is set against a dark tint rather than paper: a white field,
   a label that reads as an offer rather than a form heading, and a width that
   keeps the field at a comfortable length inside a centred block. */
.news-form.on-photo{max-width:440px;margin:clamp(26px,3.4vw,40px) auto 0;text-align:left}
.news-form.on-photo label{color:rgba(255,255,255,.82);font-size:.75rem}
.news-form.on-photo input{background:rgba(255,255,255,.94);border-color:transparent}
.news-form.on-photo input:focus{border-color:#fff;box-shadow:0 0 0 3px rgba(255,255,255,.28)}
.news-form.on-photo .news-note{color:rgba(255,255,255,.7)}
.news-form.on-photo[data-error]::after{color:#ffd9c9}
.news-form.on-photo[data-done]::after{color:#fff}

/* the states the script writes */
.news-form[data-error] input{border-color:var(--accent-dark)}
.news-form[data-error]::after{content:attr(data-error);grid-column:1 / -1;
  font-size:.8rem;color:var(--accent-dark);margin-top:2px}
.news-form[data-done] > *{display:none}
.news-form[data-done]::after{content:attr(data-done);grid-column:1 / -1;
  font-size:.95rem;color:var(--ink)}

/* A width/height pair on an <img> is a presentational hint: with width:100% and
   no height rule, the height attribute still applies and the picture renders at
   its attribute height, stretched and clipped by the card. Both flat shots in
   the feature rail carry those attributes for CLS, so both need this. */
.sc-media img{height:auto}
/* A wide screenshot in a 262px slot leaves a band of nothing under it. The two
   flat cards centre theirs so the card reads as composed rather than as a
   picture that fell to the top. */
.rail .stackcard .sc-media.sc-flat{justify-content:center;align-items:center}

/* ============ THE LEGAL PAGES ============
   terms.html and privacy.html, generated from the app's own markdown. Long-form
   reading, so: one column at a comfortable measure, numbered headings that carry
   their own space, and rules doing the section breaks the markdown marks with
   ---. Nothing here is decorative. */
.legal-doc{padding-top:clamp(30px,4vw,60px);padding-bottom:clamp(40px,5vw,80px)}
.legal-body{max-width:70ch;margin:0 auto}
.legal-body h1{font-size:clamp(1.9rem,4vw,2.9rem);letter-spacing:-.035em;margin-bottom:.35em}
.legal-body h1 + p em{font-style:normal;font-size:.8rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--clay-deep)}
/* the scope line, directly under the date: which product these cover */
.legal-body h1 + p + p em{font-style:normal;display:block;margin-top:.2em;
  font-size:.95rem;letter-spacing:0;text-transform:none;color:var(--ink);
  padding:.7em .9em;background:var(--paper-3);border-radius:10px}
.legal-body h2{font-size:clamp(1.1rem,1.9vw,1.32rem);letter-spacing:-.02em;
  margin:2.4em 0 .7em}
.legal-body h2:first-of-type{margin-top:1.8em}
.legal-body p{font-size:clamp(.95rem,1.35vw,1.02rem);line-height:1.75;
  color:var(--stone-deep);margin-bottom:1em;max-width:none}
.legal-body strong{color:var(--ink);font-weight:500}
.legal-body ul{list-style:none;margin:0 0 1.2em;padding:0}
.legal-body li{position:relative;padding-left:1.15em;margin-bottom:.6em;
  font-size:clamp(.95rem,1.35vw,1.02rem);line-height:1.7;color:var(--stone-deep)}
.legal-body li::before{content:"";position:absolute;left:0;top:.72em;
  width:.32em;height:.32em;border-radius:50%;background:var(--accent);opacity:.7}
.legal-body a{color:var(--accent-dark);text-underline-offset:2px}
.legal-body a:hover{color:var(--ink)}
/* the markdown's --- rules: a section break, not a divider under every heading */
.legal-body hr{border:0;border-top:1px solid var(--line);margin:2.2em 0 0}
.legal-body hr + h2{margin-top:1.8em}
/* the address block at the end runs as consecutive one-line paragraphs */
.legal-body h2:last-of-type ~ p{margin-bottom:.15em}

/* ============ THE TIMELINE ============
   The stages told as one continuous example rather than as a list of
   conditions. The connecting rule is the argument: it is the same record
   running under all of them, so the rule must not break between stops.

   The dot's ring has to match whatever the section is filled with, or it
   punches a hole in the wrong colour — hence the .beige and .apricot cases. */
.timeline{display:grid;gap:26px;margin-top:clamp(30px,4vw,54px);position:relative}
@media(min-width:900px){
  .timeline{grid-template-columns:repeat(5,1fr);gap:clamp(16px,2vw,28px)}
}
/* The connector is a wave, not a rule. Absolutely positioned so it stays out of
   the grid flow, and sized so the curve's baseline (y=20 of 40) sits at 7px —
   the centre of the dots. non-scaling-stroke because preserveAspectRatio="none"
   would otherwise squash the line thinner vertically than horizontally. */
.twave{display:none}
@media(min-width:900px){
  /* The box runs from the FIRST dot's centre to the LAST one's, not edge to
     edge, so the curve's four crossings land exactly on the five dots whatever
     the gap resolves to. That span is 0.8 x width + 0.8 x gap, and the gap is
     clamp(16px,2vw,28px) — hence the 0.8 of it below.

     Width must also be stated outright: an absolutely positioned SVG with
     width:auto takes its intrinsic size (height x the viewBox ratio) and
     ignores `right`, which stopped the wave less than half way across. */
  .twave{display:block;position:absolute;left:7px;
    width:calc(80% + clamp(12.8px,1.6vw,22.4px));
    top:-3px;height:20px;overflow:visible;pointer-events:none}
}
.tstop{position:relative;padding-left:30px}
@media(min-width:900px){.tstop{padding-left:0;padding-top:30px}}
.tstop::before{content:"";position:absolute;left:0;top:2px;width:14px;height:14px;
  border-radius:50%;background:var(--accent);box-shadow:0 0 0 5px var(--paper)}
@media(min-width:900px){.tstop::before{top:0}}
.beige .tstop::before{box-shadow:0 0 0 5px var(--brand)}
.apricot .tstop::before{box-shadow:0 0 0 5px var(--accent-pale)}
/* the vertical rule for the stacked layout */
@media(max-width:899px){
  .timeline::before{content:"";position:absolute;left:6px;top:6px;bottom:6px;width:1px;
    background:rgba(120,100,74,.30)}
}
.tstop h3{font-size:1rem;margin-bottom:8px}
.tstop p{font-size:.86rem;line-height:1.55}

/* ============ SPLIT HERO (both point-of-view pages) ============
   The homepage opens on a full-bleed film with the headline over it. Both deep
   dives deliberately do not: someone deciding whether to use a product should
   see the product. Copy on the left, the thing itself on the right, on the
   apricot.

   The split hero IS each page's one apricot block, so no other section on
   for-women.html or for-practitioners.html may take .apricot. */
.hero-panel{min-height:0;display:block;isolation:auto;
  padding:clamp(52px,7vw,104px) 0 clamp(52px,7vw,100px)}
.hero-panel::after{display:none}
/* Hero headlines are set here rather than inheriting the global h1, so the three
   pages stay within a few px of each other. They were 76.8 / 76.8 / 50.4 — a
   third apart — because the practitioner headline names its audience in full. */
.hero h1,.hero-panel h1{font-size:clamp(1.95rem,5.6vw,4rem)}
.hero-panel h1{color:var(--ink);max-width:17ch;text-shadow:none;margin-bottom:clamp(20px,2.6vw,30px)}
/* This headline names its audience in full — 65 characters against the consumer
   hero's 35 — so it takes a smaller size to land in four lines rather than
   eight. The measure is irrelevant here: the grid column is the real limit. */
.hero-grid:has(.deskout) h1{max-width:none}
.hero-panel .hero-sub{color:var(--stone);max-width:44ch}
.hero-panel .btns{margin-top:clamp(22px,2.6vw,32px)}
.hero-grid{display:grid;gap:clamp(30px,4vw,54px);align-items:center}
/* On a phone the product should come before the ask. The copy column and the
   screen are siblings, so the CTA cannot simply move — .hero-text goes
   display:contents and its children become items of the grid itself, which lets
   the screen sit between the sub-line and the buttons. Reordering only: the DOM
   still reads headline, sub, buttons, price, so nothing changes for a reader who
   is not looking at a phone. */
@media(max-width:999px){
  /* align-items:stretch is not optional here. .hero-grid sets align-items:center
     for its two-column desktop layout, and in a flex COLUMN that shrink-wraps
     every item to its content instead of stretching it — which collapsed the
     portal to zero width, because it clips its own overflow and so has no
     min-content to hold it open. */
  .hero-grid:has(.hero-media){display:flex;flex-direction:column;gap:0;
    align-items:stretch}
  .hero-grid:has(.hero-media) .hero-text{display:contents}
  .hero-grid:has(.hero-media) h1{order:1}
  .hero-grid:has(.hero-media) .hero-sub{order:2}
  .hero-grid:has(.hero-media) .hero-media{order:3;margin-top:clamp(26px,4.5vw,38px)}
  .hero-grid:has(.hero-media) .stores,
  .hero-grid:has(.hero-media) .btns{order:4;margin-top:clamp(24px,4vw,32px)}
  .hero-grid:has(.hero-media) .price{order:5}
}

@media(min-width:1000px){
  .hero-grid{grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);gap:clamp(34px,4.5vw,68px)}
}
.hero-panel .btn-alt{background:transparent;color:var(--ink);border-color:rgba(65,58,48,.32)}
.hero-panel .btn-alt:hover{background:var(--ink);color:var(--white);border-color:var(--ink)}
/* the line that says who it was built with — it earns a rule of its own */
.built{margin-top:clamp(24px,2.8vw,34px);padding-top:17px;max-width:42ch;
  border-top:1px solid rgba(154,58,18,.26);font-size:.85rem;color:var(--accent-dark)}
/* The apricot is the loudest block on either page, and at full strength across
   the whole panel it swamps the beige that is meant to be the brand colour. So
   pool light under the product shot — the screens then sit on something quiet
   — and keep the colour where the headline actually needs it, on the left. */
/* Mixed toward --paper rather than starting at full --accent-pale. Against the
   paper panels below it (#f8f2e5) the neat token is 22 lower on green and 29 on
   blue — enough that the hero read as a different material rather than as the
   same page warmed at one corner. color-mix keeps it tied to the tokens, so a
   palette change carries through instead of stranding a hex here. */
.hero-panel.apricot{background:
  radial-gradient(82% 94% at 76% 46%, rgba(255,253,250,.97) 0%, rgba(255,253,250,.5) 40%, rgba(255,253,250,0) 76%),
  var(--paper)}
/* the product runs off the right edge, so the screen reads as bigger than the page */
.hero-media{position:relative}
@media(min-width:1000px){.hero-media{margin-right:calc(var(--pad) * -1)}}
.hero-shot{display:block;width:100%;border-radius:calc(var(--r) - 8px);overflow:hidden;
  box-shadow:0 60px 104px -52px rgba(46,42,37,.52),0 16px 34px -20px rgba(46,42,37,.30)}
.hero-shot img{width:100%;height:auto;display:block}

/* the member-app row on the practitioner page — phones on a paper shelf */
.patient-view{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,2.2vw,26px);
  margin-top:clamp(30px,4vw,52px);align-items:start}
.patient-view .phone{max-width:212px;width:100%;margin:0 auto}
@media(min-width:660px) and (max-width:820px){
  .patient-view{grid-template-columns:1fr;max-width:280px;margin-inline:auto;gap:30px}}

/* ============ STACKING FEATURE CARDS ============
   Two columns: the argument and an image stay put on the left while the cards
   pile up on the right. Each card sticks a little lower than the one before, so
   the set stays on screen while you move through it instead of scrolling past.

   These are FEATURES, not steps — no numbering. If it reads as a process, it is
   in the wrong component; the ordered version is the rail on the homepage.

   Two things this depends on, both easy to break by accident:

   1. NO SCROLL CONTAINER ABOVE IT. `.shape` uses `overflow:clip`, which does not
      establish one, so sticky survives. Change any ancestor to `overflow:hidden`
      or `auto` and every card silently stops sticking.
   2. NO TRANSFORM ON THE CARDS. A transformed ancestor becomes the containing
      block and sticky stops resolving against the viewport — which is why
      .stackcard must never be added to the scroll-reveal selector list.

   Top offsets clear the sticky nav (66px plus its gutters), then step down so
   each landed card still shows the heading of the one beneath it. */
.stackwrap{display:grid;gap:clamp(28px,3.4vw,52px);margin-top:clamp(30px,4vw,54px);
  align-items:start}
/* .lead already carries a margin-bottom of the same size, so a lead directly
   above this put ~100px between the heading and the cards. One gap, not two. */
.lead + .stackwrap{margin-top:0}
/* and when the heading is the only thing in the lead, its own bottom margin
   is a third gap on top of the lead's — the lead is already the spacer */
.lead > h2:only-child{margin-bottom:0}
/* The two-column version — argument pinned on the left, cards climbing on the
   right — is gone. The cards are a horizontal rail at this width now, and a
   rail inside a 55% column shows a card and a half. Intro above, row beneath,
   full width, which is also what the other two sets do. */
@media(min-width:1000px){
  .stackwrap{grid-template-columns:1fr;gap:clamp(26px,3vw,40px)}
}

.stack{display:grid;gap:clamp(16px,2vw,26px)}
.stackcard{background:var(--white);border-radius:var(--r);
  padding:clamp(24px,2.8vw,38px);box-shadow:0 30px 62px -46px rgba(46,42,37,.5);
  display:grid;gap:clamp(18px,2.4vw,32px);align-items:center}
@media(min-width:760px){.stackcard{grid-template-columns:minmax(0,1fr) minmax(0,.78fr)}}
/* sticky offsets live on .rail now, so all three sets step identically */
.stackcard h3{font-size:clamp(1.12rem,1.9vw,1.32rem);font-weight:300;letter-spacing:-.03em;
  line-height:1.1;margin-bottom:11px}
.stackcard p{font-size:.92rem;line-height:1.6}
.stackcard ul{list-style:none;margin:14px 0 0;display:grid;gap:9px}
.stackcard li{font-size:.86rem;line-height:1.5;padding-left:18px;position:relative}
.stackcard li::before{content:"";position:absolute;left:0;top:8px;width:5px;height:5px;
  border-radius:50%;background:var(--accent)}
.sc-media{display:flex;justify-content:center;align-items:center;
  background:var(--paper);border-radius:calc(var(--r) - 12px);padding:16px 0 0;overflow:hidden}
.sc-media .phone{max-width:142px;width:100%}
.sc-media.sc-flat{padding:18px;background:var(--paper-3)}
.sc-media .chatline{margin:0;max-width:none;width:100%;padding:12px 16px}
.sc-media .chatline .txt{font-size:.82rem}
@media(prefers-reduced-motion:reduce){.stackcard{position:static}}

/* ============ THE STATEMENT ============
   A single large centred line directly under the hero, before any feature does
   any work. It is the page's point of view rather than a description — the one
   sentence you would say if you only got one.

   Keep it to roughly two lines at display size. It stops being a statement and
   starts being a paragraph somewhere around the third line, and the supporting
   sentence underneath exists so the big line does not have to carry detail. */
.statement{text-align:center}
/* text-wrap:balance evens the lines out so a short closing word cannot be left
   stranded on its own. It degrades to normal wrapping where unsupported, which
   is why the measure is still set rather than left to the balancer alone. */
.statement p{font-size:clamp(1.35rem,4.2vw,2.95rem);font-weight:300;letter-spacing:-.034em;
  line-height:1.12;color:var(--ink);max-width:30ch;margin:0 auto;text-wrap:balance}
.statement .sub{font-size:clamp(.95rem,1.6vw,1.06rem);letter-spacing:0;line-height:1.62;
  color:var(--stone);max-width:52ch;margin:clamp(20px,2.4vw,30px) auto 0;font-weight:300;
  text-wrap:pretty}

/* ============ THE ASSISTANT DEMO ============
   A live conversation rather than a screenshot: the question types itself, the
   assistant thinks, the answer arrives. It demonstrates the one claim on this
   page that a still image cannot.

   The answers are deliberately DATA SUMMARIES — her own numbers, read back —
   and never advice, a diagnosis or a recommendation. SAAGA is not a regulated
   medical device (see the footer), and a marketing page is the last place to
   blur that. If you edit the script in saaga.js, keep every answer to something
   the app could literally compute from what she logged. */
.aidemo{background:var(--white);border-radius:var(--r);max-width:620px;margin:clamp(30px,4vw,52px) auto 0;
  padding:clamp(22px,2.6vw,32px);box-shadow:0 30px 62px -46px rgba(46,42,37,.5);
  display:flex;flex-direction:column;gap:12px;min-height:290px}
.aihead{display:flex;align-items:center;gap:10px;padding-bottom:14px;margin-bottom:2px;
  border-bottom:1px solid var(--line)}
/* the bubbles live in .aithread, so the flex column has to be here — on .aidemo
   it has nothing to act on and every bubble stretches to full width */
.aithread{display:flex;flex-direction:column;gap:12px;align-items:flex-start}
.aihead .dot{width:7px;height:7px;border-radius:50%;background:var(--accent);flex:none}
.aihead span{font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;color:var(--clay)}
.aimsg{max-width:88%;border-radius:18px;padding:12px 16px;font-size:.9rem;line-height:1.55;
  opacity:0;transform:translateY(6px);transition:opacity .35s ease,transform .35s ease}
.aimsg.show{opacity:1;transform:none}
/* The same two bubbles the messaging screen uses: hers dark and right, the
   answer light and left. They were peach-on-cream, which read as two shades of
   the same thing rather than as two people talking. */
.aimsg.you{align-self:flex-end;background:#6b6455;color:#f7f4ee;
  border-bottom-right-radius:6px}
.aimsg.saaga{align-self:flex-start;background:#f1ece2;color:var(--ink);
  border-bottom-left-radius:6px}
.aimsg .caret{background:currentColor}
/* the ghost holds the finished sentence's box open; the typed text lies over
   it, inheriting the same padding so the two line up exactly */
.aimsg.you{position:relative}
.aimsg .ghost{visibility:hidden}
.aimsg .typed{position:absolute;left:0;top:0;right:0;bottom:0;padding:inherit}
.aimsg .caret{display:inline-block;width:1.5px;height:.95em;background:var(--accent);
  margin-left:2px;vertical-align:-.12em;animation:caret-blink 1.1s steps(1) infinite}
.aidots{display:inline-flex;gap:4px;align-items:center;padding:3px 0}
.aidots i{width:5px;height:5px;border-radius:50%;background:var(--clay);display:block;
  animation:aidot 1.25s ease-in-out infinite}
.aidots i:nth-child(2){animation-delay:.16s}
.aidots i:nth-child(3){animation-delay:.32s}
@keyframes aidot{0%,60%,100%{opacity:.25;transform:translateY(0)}30%{opacity:.9;transform:translateY(-3px)}}
@media (prefers-reduced-motion:reduce){
  .aimsg{opacity:1;transform:none}
  .aidots i{animation:none;opacity:.5}
}

/* ============ WHAT IT IS ============
   The plain description on the left, both surfaces on the right. A visitor
   reads "an app and a portal" from the picture before they reach the sentence
   that says it, which is the point of showing them together.

   The pair sits in a column rather than across the full width, which is what
   keeps the portal at a readable size instead of dominating the section. */
.explain{display:grid;gap:clamp(30px,4vw,52px)}
@media(min-width:1000px){
  /* start, not center: the screens are tall, and centring a short text block
     against them left the headline floating in the middle of the column with
     the paragraph stranded below the fold of the image. Both now begin on the
     image's top edge. The paragraph also has to live in the SAME grid item as
     the headline — as a third child it auto-placed into a second row and sat
     half a screen under the thing it describes. */
  .explain{grid-template-columns:minmax(0,.88fr) minmax(0,1.12fr);gap:clamp(34px,4.4vw,72px);
    align-items:start}
}
/* On a phone the screens come between the headline and the paragraph, so the
   product is seen before it is explained. */
@media(max-width:999px){
  .explain{align-items:stretch}
  .explain-text{display:contents}
  .explain h2{order:1}
  .explain .duo{order:2}
  .explain-lede{order:3}
  /* .explain-text is display:contents here, so a child with no order of its own
     would fall to 0 and jump above the headline. */
  .explain-close{order:4}
}
/* the line that lands the paragraph, on a row of its own */
.explain-close{margin-top:.9em;color:var(--ink)}
.explain h2{margin-bottom:clamp(16px,2vw,22px)}

/* .explain p and .explain p + p lived here. They styled no real paragraph once
   the standfirst came out, and reached six of them inside the mocked screens
   instead — see the guard beside .ui-p for why that wins. */

/* the phone overlaps the portal's lower right, inside the section bounds —
   `.shape` uses overflow:clip, so anything hanging outside is simply cut */
.duo{position:relative;padding-right:clamp(38px,5vw,84px);padding-bottom:clamp(14px,2vw,30px)}
.duo-desk{border-radius:calc(var(--r) - 12px);overflow:hidden;display:block;
  box-shadow:0 44px 84px -50px rgba(46,42,37,.5),0 12px 26px -16px rgba(46,42,37,.26)}
.duo-desk img{width:100%;height:auto;display:block}
/* the rebuilt portal, not a screenshot — container-type on the PARENT, because
   .pui sizes its own type in cqi and an element cannot query itself */
.duo-desk:has(.pui){container-type:inline-size}
.duo-phone .screen{container-type:inline-size}
/* The floor was 88px, and 11vw only reaches 148 at 1345px wide. Between roughly
   760 and 1200 the phone collapsed to 88–132px and the screen inside it fell to
   3.4–5.4px type — a laptop at 1024 got 4.5px. It is a whole app screen in
   there; below ~150px it cannot be read at any viewport. */
.duo-phone{position:absolute;right:0;bottom:0;width:clamp(152px,13vw,176px)}
.duo-phone .phone{width:100%;max-width:none}
/* Below 1000 the duo gets .explain's full row to itself. It used to STACK
   there — portal, then a centred phone under it — and the two never balanced:
   a phone is roughly 1:2 and a portal 16:10, so at 390px the phone came out
   1.85x the portal's height and the pair read as two slabs, 558px of them.

   So it keeps the desktop composition instead: the phone hangs off the
   portal's lower right and the two overlap into one shape. The numbers below
   are not guesses — with W the row width, the portal is .625W tall (16/10) and
   the phone is width x 2.05, so to land the phone's top at 46% of the portal's
   height the row needs padding-bottom = (phoneW x 2.05 + .2875W) - .625W.
   Percentage padding resolves against WIDTH, so this holds at every size.
   Change a phone width here and recompute the padding underneath it. */
@media(max-width:999px){
  .duo{padding-right:0;padding-bottom:23.7%}          /* for a 28% phone */
  .duo-phone{position:absolute;right:0;bottom:0;width:28%;max-width:none;margin:0}
}
@media(max-width:820px){
  /* The crop that used to live here showed a 1020px-wide portal inside a 326px
     frame, so a phone got the sidebar and two words of a task at desk scale — a
     wall of giant text with no screen around it. On a phone the portal is not
     trying to be legible: it reads as a small, whole object you recognise as a
     dashboard, with the phone beside it doing the legible work. */
  .duo-desk .pui{width:100%;max-width:none;font-size:clamp(2.6px,1.12cqi,11px)}
  .duo-desk{max-height:none}
}
@media(max-width:620px){
  /* 28% of a 326px row is a 91px phone — past the point where its screen is
     anything at all. It goes back up to 42%, and the padding with it. */
  .duo{padding-bottom:52.4%}
  .duo-phone{width:42%}
}

/* ============ FAQ LAYOUT ============
   Title on the left, questions on the right. Stacked full-width the FAQ was the
   tallest section on every page while carrying the least — this halves it.

   Nothing is open by default. An open first answer pushes every other question
   below the fold and quietly implies it is the one most people ask, which is a
   claim we have not earned. Let the reader choose. */
.faq-grid{display:grid;gap:clamp(24px,3vw,40px)}
@media(min-width:1000px){
  .faq-grid{grid-template-columns:minmax(0,.72fr) minmax(0,1.28fr);
    gap:clamp(34px,4.4vw,76px);align-items:start}
  .faq .faq-grid > .lead{position:sticky;top:calc(var(--gap) + 104px);margin-bottom:0}
}
.faq-list details:first-of-type{border-top:1px solid var(--line)}
.beige.faq .faq-list details{border-color:rgba(90,83,70,.24)}

/* A statement with nothing under it. With no supporting line to lean on, the
   sentence has to carry the whole section, so it goes up a size and the
   section gets more air around it. Use this when the line is the argument
   rather than the introduction to one. */
.statement-bare p{font-size:clamp(1.5rem,5.2vw,3.6rem);line-height:1.08;max-width:22ch}
/* 150px above AND below left the line floating in the middle of an empty
   block. A statement wants air, not a field. */
.statement-bare{padding-top:clamp(48px,6.4vw,96px);padding-bottom:clamp(48px,6.4vw,96px)}

/* two phones on the consumer hero, the second dropped so they read as a pair
   rather than as one screenshot duplicated */
.hero-phones{display:flex;justify-content:center;align-items:flex-start;
  gap:clamp(12px,1.8vw,24px)}
.hero-phones .phone{max-width:206px;width:100%}
.hero-phones .phone:nth-child(2){margin-top:clamp(22px,4vw,58px)}
@media(max-width:520px){.hero-phones .phone:nth-child(2){display:none}}

/* ============================================================
   THE APP, REBUILT IN CSS

   These replace the PNG screenshots inside the phone frames. Screenshots are
   1206px wide and were being shown at 140-210px, where nothing is legible —
   the best line in the product ("Dr. Elena Rossi, ND's protocol is guiding
   this") was invisible on every page it appeared on.

   RULE: every label and number here is lifted from a real capture in this
   folder, except where the capture showed a broken demo state — the calendar
   read "TODAY, CYCLE DAY 52" over "Nothing tracked for the day", which is a
   stalled seed rather than the product. That screen shows a healthy state and
   is marked below. Check it against a real seeded account before launch.

   Everything sizes in em against a container-query font-size, so one markup
   works at any phone width. Do not put px sizes inside .ui.
   ============================================================ */
.phone .screen{container-type:inline-size}
.ui{position:absolute;inset:0;background:#fbfaf6;display:flex;flex-direction:column;
  font-family:var(--sans);font-weight:300;color:var(--ink);
  font-size:clamp(2.6px,4.6cqi,13px);line-height:1.35;overflow:hidden;text-align:left}
.ui-top{display:flex;align-items:center;justify-content:center;padding:1.7em 0 .85em;flex:none}
/* the actual mark, not Playfair with letter-spacing standing in for it — the
   real logo has its own drawing and the fake read as a different brand */
.ui-top .wm{width:4.9em;height:1.25em;display:block;color:var(--ink)}
.ui-body{flex:1;padding:0 .8em;display:flex;flex-direction:column;gap:.45em;overflow:hidden}
/* flex:none — .ui-body is a flex column, so once the screen's content is taller
   than the phone every card shrinks instead of overflowing, and the tiles lose
   their values while keeping their labels. A real screen scrolls; this one
   clips at the fold, which is what flex:none gives. */
.ui-card{background:#fff;border-radius:.9em;padding:.68em .8em;flex:none}
.ui-card.flat{background:#f2efe8}
.ui-h{font-weight:500;font-size:1em;margin-bottom:.35em}
/* Written .ui .ui-p, not .ui-p. A mocked screen sizes everything from its own
   root in em, but a section rule like `.explain p` or `.col p` is a descendant
   selector at (0,1,1) and beats a lone class at (0,1,0) — so body copy meant
   for the page leaks into the phone and blows one line up to 17px inside a
   7.5px screen. Two classes puts these out of reach. */
/* Deliberately a scoped class, not `.explain p`: the mock app screens inside
   this same section are built from real <p>s, and a descendant selector here
   beats their own font-size and blows the fake UI up to body-copy scale. */
/* Sits AFTER the two screens now, not between the headline and them: the
   product is the argument, and on a phone a paragraph in front of it pushed
   the screens most of a screen down. */
.explain-lede{max-width:46ch;margin-top:clamp(16px,1.8vw,22px);
  font-size:clamp(.98rem,1.6vw,1.12rem);line-height:1.6;color:var(--stone)}

.ui .ui-p{color:var(--stone);font-size:.84em;line-height:1.38}
.ui-sec{display:flex;align-items:center;justify-content:center;gap:.5em;margin-bottom:.6em}
.ui-sec i{width:1.55em;height:1.55em;border-radius:50%;display:block;flex:none;
  background:color-mix(in srgb, var(--dim,#c9927f) 22%, #fff)}
.ui-sec span{font-size:.76em;letter-spacing:.16em;text-transform:uppercase;color:var(--stone)}
.ui-pill{display:inline-block;background:var(--accent-pale);color:var(--accent-dark);
  border-radius:2em;padding:.3em .7em;font-size:.76em;font-weight:400;margin-bottom:.5em}
.ui-row{display:flex;gap:.7em;justify-content:space-between;align-items:baseline;
  padding:.5em 0;font-size:.84em}
.ui-row + .ui-row{border-top:1px solid var(--line)}
.ui-row b{font-weight:400;color:var(--stone);text-align:right;white-space:nowrap}
/* --- home screen ----------------------------------------------------------
   Rebuilt rather than screenshotted. The real capture is a self-serve member's
   home, but the seeded day is empty ("No logs", "0m", "No activity yet") and it
   carries a practitioner card, which does not belong on the consumer page. */
.ui-k{font-size:.68em;letter-spacing:.15em;text-transform:uppercase;color:var(--clay);
  line-height:1.3;margin-bottom:.5em}
.ui-k.mid{text-align:center}
.ui-hi{font-weight:500;font-size:1.32em;letter-spacing:-.015em;margin-bottom:.4em}
.ui-cta{background:var(--brand);color:var(--ink);border-radius:2em;text-align:center;
  padding:.5em 0;font-size:.78em;letter-spacing:.13em;text-transform:uppercase}
.ui-more{margin-top:.5em;padding-top:.5em;border-top:1px solid var(--line);
  text-align:center;font-size:.72em;letter-spacing:.13em;text-transform:uppercase;
  color:var(--stone)}
/* the home hormone chart, rebuilt from SimplifiedHormoneChart: four stacked
   area curves (estrogen rose, LH gold, progesterone olive, FSH grey) under a
   dashed "today" line, over a -5 / today / +5 axis. Colours are the app's
   COLORS.chart values, not approximations. */
/* explicit height, not the viewBox ratio: at natural aspect the chart alone
   eats the room the Feeling-today chips need, and they fall below the fold.
   preserveAspectRatio="none" lets it compress without distorting the read. */
.ui-horm{display:block;width:100%;height:3.1em;margin:.05em 0}
.ui-hax{display:flex;justify-content:space-between;font-size:.62em;
  letter-spacing:.06em;color:var(--stone);margin-bottom:.55em}
/* four glance tiles where three fit: the fourth clips at the card edge exactly
   as it does in the app, where the row scrolls sideways. */
.ui-card.clip{overflow:hidden;
  /* The fourth tile is cut on purpose, as it is in the app. Without a fade the
     cut lands mid-word and reads as a rendering fault rather than as a row that
     carries on, which is what it is. */
  -webkit-mask-image:linear-gradient(to right,#000 82%,transparent 99%);
  mask-image:linear-gradient(to right,#000 82%,transparent 99%)}
.ui-tiles.four{grid-template-columns:repeat(4,1fr);width:124%}
/* the Cycle / Feeling-today pair, mirroring the app's two home area cards:
   a big day number over its label, then the symptom chips underneath */
.ui-cyc{text-align:center;margin:.1em 0 .25em}
.ui-cyc b{display:block;font-weight:500;font-size:1.72em;line-height:1;letter-spacing:-.02em}
.ui-cyc span{display:block;font-size:.7em;letter-spacing:.08em;color:var(--stone);margin-top:.25em}
.ui-chips{display:flex;flex-wrap:wrap;gap:.35em;justify-content:center}
.ui-chips s{text-decoration:none;background:#fff;border-radius:2em;padding:.3em .65em;
  font-size:.72em;color:var(--ink)}
.ui-chips s.add{background:transparent;color:var(--stone);
  box-shadow:inset 0 0 0 1px var(--line)}
.ui-tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:.4em}
.ui-tile{background:#fff;border-radius:.6em;padding:.55em .5em}
.ui-tile em{font-style:normal;display:block;font-size:.66em;letter-spacing:.1em;
  text-transform:uppercase;color:var(--clay);line-height:1.3}
.ui-tile b{display:block;font-weight:400;font-size:1.15em;margin:.25em 0 .1em;letter-spacing:-.02em}
.ui-tile span{display:block;font-size:.68em;color:var(--stone);line-height:1.3}
.ui-nav{flex:none;display:flex;justify-content:space-around;align-items:center;
  padding:.6em 0 .8em;border-top:1px solid var(--line);background:#fff}
.ui-nav s{text-decoration:none;font-size:.68em;color:var(--clay);display:flex;
  flex-direction:column;align-items:center;gap:.3em}
.ui-nav s svg{width:1.45em;height:1.45em;display:block}
.ui-nav s.on{color:var(--ink)}
/* the centre chat button — a filled brand disc that overlaps the bar's top edge,
   the way it does in the app */
.ui-navmark{flex:none;width:2.6em;height:2.6em;border-radius:50%;background:var(--brand);
  display:grid;place-items:center;margin-top:-1.1em;color:var(--ink)}
.ui-navmark svg{width:1.3em;height:1.3em;display:block}
/* calendar */
.ui-cal{display:grid;grid-template-columns:repeat(7,1fr);gap:.22em;margin-top:.5em}
.ui-cal s{aspect-ratio:1;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:.72em;color:var(--stone);text-decoration:none}
.ui-cal s.p{background:#e2d3c2;color:var(--ink)}
.ui-cal s.t{outline:1px solid var(--ink);outline-offset:-1px;color:var(--ink)}
.ui-cal s.d{position:relative}
.ui-cal s.d::after{content:"";position:absolute;bottom:.05em;width:.2em;height:.2em;
  border-radius:50%;background:var(--accent)}
.ui-cal em{font-style:normal;font-size:.66em;color:var(--clay);text-align:center;display:block}
.ui-day{text-align:center;font-size:.76em;letter-spacing:.12em;text-transform:uppercase;
  color:var(--stone);margin:.7em 0 .1em}

/* ============ POP-OUT ============
   One card lifted out of the phone and shown at a size you can actually read.
   The phone carries "this is an app"; the pop-out carries the claim. Because
   the UI is CSS rather than a screenshot, the card is the same markup at a
   different size — nothing is redrawn and nothing can drift out of sync.

   The pop-out sets its own font-size: it sits outside the phone's container
   query, so it does not inherit the phone's scaling. */
/* Sized for a hero media column. It needs roughly 380px of width to work —
   do NOT put it inside a stack card, whose media slot is about 280px and which
   the pop-out escapes. */
/* inline-flex so the container hugs the phone plus its padding. Stretched to
   the full column, a percentage offset lands past the phone's edge and the card
   sits beside it instead of on it. */
.hero-media{display:flex;justify-content:center}
/* --- the hero pop-outs -----------------------------------------------------
   Three snippets lifted off the phone rather than one, so the hero shows the
   product's range at a glance: the greeting, one protocol area, one trend. They
   are absolutely placed against .popout, whose padding is what reserves the
   room they need on BOTH sides — without it they overhang the hero's rounded
   corner and get clipped. Percentage padding on a shrink-to-fit box resolves
   against the containing block, not the box itself, so these track the column
   width rather than feeding back on themselves. */
.popout{position:relative;display:inline-flex;
  padding:clamp(14px,3%,34px) clamp(84px,22%,166px)
          clamp(26px,6%,56px)  clamp(70px,19%,142px)}
/* an explicit width, not 100% — inside a shrink-to-fit container there is
   nothing for a percentage to resolve against and the phone collapses */
.popout .phone{width:clamp(158px,19vw,244px);max-width:none;flex:none}
/* every card OVERLAPS the phone. Placed clear of it they read as three
   unrelated boxes rather than as pieces lifted out of the screen. */
.pop{position:absolute;z-index:3;
  background:#fff;border-radius:14px;padding:12px 14px;
  box-shadow:0 28px 56px -30px rgba(46,42,37,.5),0 6px 16px -10px rgba(46,42,37,.3);
  font-family:var(--sans);font-weight:300;color:var(--ink);
  font-size:clamp(8.5px,.95vw,11.5px);line-height:1.4;text-align:left}
/* Four cards down one phone. They alternate sides and never share a vertical
   band, otherwise two of them collide at narrow widths and the composition
   reads as a pile rather than as pieces lifted out of the screen. pop-a stays
   narrow so its right edge stops short of the screenshot's centred wordmark —
   wider and it slices SAAGA in half, which looks like a rendering fault. */
/* Narrower cards, wider gutters: four of them at the previous widths buried the
   phone entirely, and the screen behind them is half the point of the picture.
   Each now clips the bezel by roughly 40px instead of eating a third of it. */
/* Three cards, not four: the whole routine is one block on the left, with the
   trend under it and the assistant opposite. Each clips the bezel by roughly
   40px — the screen behind them is half the point of the picture. */
/* The routine is the tall one, so it centres on the phone and the other two sit
   above and below it on the opposite side. None of them touches the top or
   bottom edge of the composition — pinned to the extremes they read as pushed
   out of the frame rather than lifted off the screen. */
.pop-a{right:0;top:50%;transform:translateY(-50%);width:min(54%,206px)}
.pop-c{left:3%;top:12%;width:min(46%,180px)}
/* the assistant sits low, beside the tab bar it is reached from */
.pop-d{left:5%;bottom:7%;width:min(56%,222px);display:flex;gap:.7em;align-items:flex-start}
.pop-ico{flex:none;width:2.5em;height:2.5em;border-radius:50%;background:var(--brand);
  display:grid;place-items:center}
.pop-ico svg{width:1.35em;height:1.35em;color:var(--ink)}
.pop-say{margin:0;font-size:.98em;line-height:1.45}
/* the real capture sits flush in the bezel; top-anchored so the greeting is
   what survives the crop rather than the middle of the scroll */
.phone .shot{width:100%;height:100%;object-fit:cover;object-position:top;display:block}
.pop .ui-sec{margin-bottom:.6em}
.pop .ui-row{font-size:.92em}
.pop .ui-tiles{gap:.35em}
/* the greeting card — the only one that is not a slice of a list */
.pop-hi{font-size:1.22em;font-weight:300;letter-spacing:-.01em;margin:0 0 .25em}
.pop-sub{color:var(--stone);font-size:.94em;margin:0}
/* the trend card. Bar heights come from --v so the markup carries the data. */
.pop-val{font-size:1.34em;font-weight:400;letter-spacing:-.01em;display:block}
.pop-note{color:var(--stone);font-size:.9em}
.popbars{display:flex;align-items:flex-end;gap:.26em;height:2.9em;margin-top:.7em}
.popbars i{flex:1;height:var(--v);border-radius:2px 2px 0 0;
  background:color-mix(in srgb, var(--dim,#8a9db5) 46%, #fff)}
.popbars i.on{background:var(--dim,#8a9db5)}
/* Below this the column is too narrow for three cards to overlap the phone
   without covering it. Show the phone alone rather than a stack of fragments. */
@media(max-width:820px){
  .popout{padding:0}
  /* scoped to .popout — a bare .pop also hid the practitioner hero's cards,
     which live in .deskout and share this stylesheet */
  .popout .pop{display:none}
}

/* ============ WHAT WE TRACK — the hero ticker ============
   A slow marquee of everything SAAGA covers. It says "all five areas, in real
   detail" faster than a paragraph can, and it gives the hero one moving thing
   that is not the video.

   The track holds the list TWICE and travels exactly -50%: at that distance the
   second copy lands precisely where the first began, so the loop is seamless.
   Any other distance — or a single copy — visibly jumps. Duration is set long
   on purpose; a ticker that outpaces reading is decoration, not information. */
/* the story block — one prose column, set wider than a lead paragraph but well
   short of full width, so it reads as writing rather than as a layout */
/* No heading — the quote is the section. Set larger than body copy so it reads
   as something said rather than something explained. */
/* An explicit width, not ch: the quote sets its own font-size on the <p>, so a
   ch measure on the wrapper resolves against the inherited 16px and comes out
   less than half the intended column. */
/* The marks are typed into the copy, not generated by `quotes`, so they survive
   being selected and copied — and quotes:none stays to make sure the two cannot
   both appear. The opening mark hangs into the left margin so the first line
   still aligns optically with the ones under it. */
.story{max-width:min(100%,720px);margin:0 auto;text-align:center;quotes:none;
  text-indent:-.42em}
.story p{font-size:clamp(1.35rem,3.2vw,2.15rem);line-height:1.32;
  letter-spacing:-.025em;color:var(--ink);font-weight:300;text-wrap:balance}

/* the sign-off — Playfair italic at signature scale, then the role beneath */
.story .sign{max-width:min(100%,270px);font-style:normal;
  margin:clamp(26px,3vw,38px) auto 0;padding-top:clamp(20px,2.2vw,26px);
  border-top:1px solid var(--line)}
.sign em{display:block;white-space:nowrap;font-family:var(--serif);font-style:italic;
  font-size:clamp(1.5rem,2.4vw,2rem);line-height:1;color:var(--ink);letter-spacing:-.01em}
.sign span{display:block;margin-top:.55em;font-size:.86rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--clay)}

/* ============ THE PORTAL HOME, REBUILT ============
   The same treatment the member app screens get: CSS rather than a screenshot,
   so it stays legible at hero size and can show the layout we want. Two
   departures from today's portal, both deliberate:
     - tasks sit BESIDE events rather than stacked above them
     - unread messages appear on the home screen itself
   Both are worth making in the portal too; noted in the README.
   Scales off container-query units like .ui does, so one rule fits every size. */
/* aspect-ratio, not height: a rebuilt screen is a DIV, and unlike an <img> it
   carries no intrinsic size — without this the frame collapses to a sliver and
   every percentage-positioned card piles up in a column. */
/* container-type goes on the PARENT. An element cannot query itself, so with it
   on .pui the cqi below silently resolved against the viewport instead — 1cqi of
   1440px, clamped to the 10px max, which is why the screen read as zoomed in.
   (.ui gets this right by accident of nesting: its container is .phone .screen.) */
.hero-shot:has(.pui){container-type:inline-size}
.pui{position:relative;display:flex;aspect-ratio:16/10;background:#faf9f7;
  border-radius:inherit;overflow:hidden;
  font-family:var(--sans);font-weight:400;color:var(--ink);text-align:left;
  font-size:clamp(2.8px,1.12cqi,11px);line-height:1.34;
  -webkit-font-smoothing:antialiased}
.pui-side{flex:none;width:15.5%;background:#6b6455;color:#efeae1;padding:2.1em 1.6em}
.pui-logo{display:block;font-family:var(--serif);font-size:1.5em;letter-spacing:.06em;
  color:#fff;line-height:1}
.pui-logo em{display:block;font-style:normal;font-family:var(--sans);font-size:.44em;
  letter-spacing:.1em;opacity:.8;margin-top:.5em}
/* Icons, counts and Help, as the real sidebar has them. Contrast matters even
   in a mock: at opacity .82 the label blended into #6b6455 at 3.6:1 and read
   as unfinished rather than as chrome. */
.pui-side s{display:flex;align-items:center;gap:.7em;text-decoration:none;
  font-size:.95em;margin-top:.55em;padding:.5em .7em;border-radius:.5em;
  color:rgba(239,234,225,.9)}
.pui-side s svg{width:1.15em;height:1.15em;flex:none}
.pui-side s.on{background:rgba(255,255,255,.13);color:#fff;font-weight:400}
/* unread count on Messages; plain figure on Clients, matching the portal */
.pui-side u{margin-left:auto;text-decoration:none;font-size:.76em;line-height:1;
  background:var(--accent);color:#fff;border-radius:2em;padding:.3em .5em;min-width:1.5em;
  text-align:center}
.pui-side u.q{background:none;color:rgba(239,234,225,.66);padding:0;font-size:.78em}
/* --- Active clients table (portal home) ---------------------------------
   Four columns, exactly as HomeDashboardView renders them. Two details worth
   keeping if this gets touched again:
     - flag pills are SOLID in the flag's colour, not tinted — tagFill() hands
       the raw hex straight to `background`, so a pale pill would be wrong;
     - there is NO activity / last-seen column, and adding one would be a claim
       the product deliberately does not make (members never consented to share
       app-usage with their practitioner). */
.pcl{margin-top:.55em;font-size:.82em}
.pclh,.pclr{display:grid;grid-template-columns:.9fr 1.1fr 1.2fr .95fr 1.05fr;
  /* the table is capped short of the card edge on purpose: the protocol
     overlay sits over the right of the frame, and Flags is the column this
     screenshot exists to show, so it must land clear of it. */
  max-width:62%;
  gap:.7em;align-items:center;padding:.42em 0;border-bottom:1px solid var(--line)}
.pclh{font-size:.82em;letter-spacing:.07em;text-transform:uppercase;
  color:var(--clay);border-bottom-color:var(--line)}
.pclr:last-child{border-bottom:0}
.pclr > span:first-child{font-weight:500;color:var(--ink)}
.pclr > span:nth-child(4){color:var(--stone)}
/* Next up: soonest appointment, then the soonest pending task. An overdue
   task is tinted and labelled, exactly as NextUpCell renders it. */
.pcl-nu{display:flex;flex-direction:column;gap:.15em;min-width:0}
.pu{font-style:normal;color:var(--ink);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;font-size:.95em}
.pu-t{color:var(--stone)}
.pu-od{color:#b57a66;font-weight:500}
.pcl-none{color:var(--clay)}
.pn,.pf{display:inline-flex;align-items:center;font-style:normal;line-height:1;
  border-radius:2em;white-space:nowrap;margin:.12em .25em .12em 0}
.pn{gap:.3em;padding:.16em .2em .16em .45em;background:#f6f5f5;
  border:1px solid var(--line);color:var(--ink);font-weight:500;font-size:.92em}
.pn u{text-decoration:none;display:inline-flex;align-items:center;justify-content:center;
  min-width:1.15em;height:1.15em;border-radius:50%;background:#fff;
  border:1px solid var(--line);font-size:.88em}
.pf{padding:.3em .62em;color:#fff;font-weight:500}
.pf-n{background:#626059}          /* needs_attention — charcoal */
.pf-a{background:#b57a66}          /* anomaly — terracotta */
.pf-r{background:#6b8f71}          /* review — success green */

.pui-main{flex:1;padding:2em 2.3em;min-width:0}
.pui-date{font-size:.9em;color:var(--stone)}
.pui-hi{font-size:1.75em;font-weight:400;letter-spacing:-.02em;margin:.2em 0 .9em}
.pui-card{background:#fff;border:1px solid var(--line);border-radius:.85em;
  padding:.85em 1em;margin-bottom:.7em}
.pui-week{display:grid;grid-template-columns:repeat(7,1fr);gap:.3em;margin:.6em 0 .9em;
  text-align:center}
.pui-week s{text-decoration:none;font-size:.85em;color:var(--stone);display:block;
  padding:.45em 0;border-radius:2em}
.pui-week s.on{background:var(--ink);color:#fff}
.pui-week s em{display:block;font-style:normal;font-size:.78em;color:var(--clay);margin-bottom:.3em}
.pui-week s.on em{color:var(--clay)}
/* tasks and events share the row — stacked, the events list pushed everything
   else off the fold and the two never read as one day */
.pui-split{display:grid;grid-template-columns:.85fr 1.15fr;gap:1.4em;
  padding-top:.85em;border-top:1px solid var(--line)}
.pui-task{display:flex;gap:.5em;align-items:flex-start;font-size:.92em;padding:.3em 0}
.pui-task::before{content:"";flex:none;width:.85em;height:.85em;border-radius:.2em;
  border:1px solid var(--clay);margin-top:.12em}
.pui-ev{display:flex;gap:.7em;padding:.34em 0}
.pui-ev b{flex:none;width:4.4em;font-weight:300;font-size:.82em;color:var(--stone)}
.pui-ev span{display:block;border-left:2px solid #c9927f;padding-left:.6em;font-size:.92em;font-weight:400}
.pui-ev em{display:block;font-style:normal;font-weight:300;font-size:.85em;color:var(--stone)}
.pui-msg{display:flex;gap:.6em;align-items:baseline;padding:.4em 0;font-size:.9em}
.pui-msg + .pui-msg{border-top:1px solid var(--line)}
.pui-msg b{flex:none;font-weight:400}
.pui-msg span{flex:1;color:var(--stone);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pui-msg i{flex:none;font-style:normal;font-size:.85em;color:var(--clay)}
.pui-dot{display:inline-block;width:.5em;height:.5em;border-radius:50%;background:var(--accent);
  margin-right:.4em}

/* ============ THE PRACTITIONER HERO POP-OUTS ============
   The desktop twin of .popout. Same idea, same .pop card styling — only the
   frame is wide instead of tall, so the cards clip its left and right edges
   rather than stacking down one side. Padding reserves the room they need;
   without it they overhang the hero's rounded corner and get clipped. */
/* A little more of the row than the consumer hero gets — a desktop shot plus
   four cards needs the width — but only a little. Pushed further, the text
   column starves and the headline wraps to eight lines. */
@media(min-width:1000px){
  .hero-grid:has(.deskout){grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr)}
}
/* The shot runs off the right edge of the panel — .shape clips it at the rounded
   corner — so it renders far larger than the column and stays legible with cards
   on top of it. Boxed inside the column it was small AND covered. */
/* width:100%, because .hero-media is a flex container and .deskout is therefore
   a shrink-to-fit item. That was harmless while the shot was an <img> with an
   intrinsic width to size to; with a rebuilt screen inside there is nothing to
   measure and the whole frame collapses to a sliver. */
.deskout{position:relative;width:100%;
  padding:clamp(12px,3%,32px) clamp(8px,1.6%,18px) clamp(22px,5%,48px)}
.deskout .hero-shot{width:100%;border-radius:calc(var(--r) - 10px)}
/* The left card sits LOW. Higher up it covers the day's tasks and appointments
   — the "a lot going on" the shot is there to show in the first place. */
/* Four cards around a wide shot: two down each side, the screenshot reading
   through the middle. The protocol card is the widest because its whole point
   is the column count. */
/* Corners, not the middle. The screenshot's own content sits centre-left, so
   cards parked there erase the thing they are supposed to be zooming into. */
/* Cards hug the left half; the shot's right half — which now runs past the page
   edge — stays clear, so the portal is readable behind them. */
/* Three cards now the thread lives in the screen itself. They sit at the top and
   bottom edges, clear of the middle band where the tasks and appointments are. */
/* All three start clear of the sidebar: it is the portal's identity — logo,
   nav, unread counts — and a card parked on top of it hides exactly what the
   shot is there to establish. */
/* The protocol card is the tallest, so it owns the right-hand side and runs the
   full height there. The three short ones sit along the bottom, where they clip
   the frame's edge rather than covering the tasks and appointments above. */
/* It hangs off the frame's right edge, but only just — at -15% it ran past the
   section's own rounded shape and sat on the page ground. The roster table it
   used to cover is capped at 81% of its card, so this no longer has to clear
   the full width to keep the Flags column readable. */
/* A PERCENTAGE offset here scales with the frame, so a value that hung the card
   just past the edge at 1440 threw it clean outside the section's shape at 1200.
   A fixed overhang behaves the same at every width. */
.dpop-1{right:0;top:3%;width:min(33%,218px)}
/* The three short cards share one flex row so they cannot collide — and the row
   stops short of .dpop-1's column, which hand-set percentages kept running
   into. Bottom-aligned, so their lower edges line up along the frame. */
.dpop-3{left:19%;top:-6%;width:min(28%,184px)}
.dpop-row{position:absolute;left:0;right:31%;bottom:-7%;z-index:3;
  display:flex;align-items:flex-end;gap:.6rem}
.dpop-row .pop{position:static;width:auto;flex:1 1 0;min-width:0}
/* the dashboard snippet: two counts, then one metric with its trend */
.dsh{display:flex;gap:1.1em;margin-bottom:.55em}
.dsh span{display:block;font-size:.78em;letter-spacing:.06em;text-transform:uppercase;color:var(--clay)}
.dsh b{display:block;font-weight:400;font-size:1.5em;letter-spacing:-.02em;color:var(--ink);
  text-transform:none;letter-spacing:-.02em}
.dshm{font-size:.78em;letter-spacing:.08em;text-transform:uppercase;color:var(--clay);
  padding-top:.5em;border-top:1px solid var(--line)}
.popbars.solid i{background:var(--dim)}
/* temperature and ovulation, in the portal's own reading: period bands, an
   ovulation marker, and the basal temperature stepping up behind it */
.bbt{display:block;width:100%;height:3.4em;margin:.2em 0 .5em;overflow:visible}
.bbt-p{fill:#e2d3c2}
.bbt-ov{stroke:#c9927f;stroke-width:.8;stroke-dasharray:2 2}
.bbt-l{fill:none;stroke:var(--ink);stroke-width:1.1;stroke-linejoin:round;
  stroke-linecap:round;vector-effect:non-scaling-stroke}
.bbt-key{display:flex;gap:.7em;font-size:.72em;color:var(--stone);margin-bottom:.5em}
.bbt-key s{text-decoration:none;display:flex;align-items:center;gap:.3em}
.bbt-key s::before{content:"";width:.5em;height:.5em;border-radius:1px;background:#e2d3c2}
.bbt-key s.o::before{background:#c9927f;border-radius:50%}
.bbt-key s.t::before{background:var(--ink)}

/* the line-item editor, cut down to the columns that carry the argument */
.ptab{font-size:.8em}
.pth,.ptr{display:grid;grid-template-columns:1.1fr .95fr 1fr .9fr;gap:.35em;
  padding:.32em 0;align-items:baseline}
.pth{font-size:.78em;letter-spacing:.06em;text-transform:uppercase;color:var(--clay)}
/* the area a run of lines belongs to */
.pgr{font-size:.76em;letter-spacing:.08em;text-transform:uppercase;color:var(--clay-deep);
  padding:.5em 0 .1em;border-top:1px solid var(--line)}
.pgr:first-of-type{border-top:0}
.ptr{border-top:1px solid var(--line)}
.ptr span:not(:first-child){color:var(--stone)}
.ptr b{font-weight:400;color:var(--accent-dark)}
/* the same table inside a phone: cadence drops, three columns fit, and the
   type comes up from .8em (9.5px in a 278px phone) to something readable */
.ptab-3{font-size:.92em}
.ptab-3 .pth,.ptab-3 .ptr{grid-template-columns:1.25fr .8fr .95fr}

/* nutrition: one stacked bar per logged day, then that day's split */
/* One stacked bar per logged day. The three segments are ONE gradient with hard
   stops — pseudo-elements can only add two layers, and a stack needs three.
   --h is the bar's height in the track; --m/--d are stops within the bar. */
.nbars{display:flex;align-items:flex-end;gap:.24em;height:3em;margin:.1em 0 .5em}
.nbars i{flex:1;height:var(--h);border-radius:2px 2px 0 0;
  background:linear-gradient(to top,
    #d4b76a 0 var(--m),
    #cbbfa6 var(--m) var(--d),
    #a89f91 var(--d) 100%)}
.nleg{display:flex;gap:.6em;font-size:.74em;color:var(--stone);margin-bottom:.55em}
.nleg s{text-decoration:none;display:flex;align-items:center;gap:.28em}
.nleg s::before{content:"";width:.5em;height:.5em;border-radius:1px;background:#d4b76a}
.nleg s.d::before{background:#cbbfa6}
.nleg s.s::before{background:#a89f91}
.nday{font-size:.78em;letter-spacing:.06em;text-transform:uppercase;color:var(--clay);
  padding-top:.45em;border-top:1px solid var(--line);margin-bottom:.4em}
.nsplit{display:grid;grid-template-columns:1fr 1fr;gap:.2em .7em;font-size:.86em;color:var(--stone)}
.nsplit span{display:flex;justify-content:space-between;gap:.5em}
.nsplit b{font-weight:400;color:var(--ink)}

/* adherence, in the portal's own shape: rule, hit-rate line, then the bar */
.ad2{margin-top:.5em}
.ad2 + .ad2{padding-top:.5em;border-top:1px solid var(--line)}
.ad2h{display:flex;align-items:center;gap:.4em;font-size:.88em}
.ad2h em{width:.45em;height:.45em;border-radius:50%;background:var(--dim);flex:none}
.ad2h b{margin-left:auto;font-weight:400;font-size:.86em;color:var(--accent-dark)}
.ad2s{font-size:.8em;color:var(--stone);margin:.15em 0 .25em}
.ad2b{display:flex;align-items:center;gap:.45em;font-size:.8em;color:var(--stone)}
.ad2b i{flex:1;height:.34em;border-radius:2em;background:var(--line);position:relative}
.ad2b i::after{content:"";position:absolute;top:0;bottom:0;left:0;width:var(--v);
  border-radius:2em;background:var(--dim)}
.ad2b b{font-weight:400;color:var(--ink)}
/* a message thread lifted out of the portal: client left, practitioner right */
.msg{border-radius:.9em;padding:.5em .72em;font-size:.92em;line-height:1.4;
  margin-top:.45em;max-width:92%}
.msg.them{background:var(--paper-2);color:var(--ink)}
.msg.you{background:var(--brand);color:var(--ink);margin-left:auto}
/* the stat tiles default to white, which is invisible on a white pop card */
.pop .ui-tile{background:var(--paper-2)}
/* the flag pills, in the portal's own two tones */
.fpill{display:inline-block;border-radius:2em;padding:.34em .72em;margin:0 .28em .3em 0;
  font-size:.82em;line-height:1.25;color:#fff;background:#7d7462}
.fpill.ok{background:#6f8a63}
/* protocol adherence — a labelled bar per area, in that area's colour */
.adh{display:flex;align-items:center;gap:.55em;padding:.36em 0;font-size:.88em}
.adh + .adh{border-top:1px solid var(--line)}
.adh span{flex:none}
.adh i{flex:1;height:.4em;border-radius:2em;background:var(--line);position:relative;min-width:1.6em}
.adh i::after{content:"";position:absolute;top:0;bottom:0;left:0;width:var(--v);
  border-radius:2em;background:var(--dim,#c9927f)}
.adh b{font-weight:400;color:var(--stone);min-width:2.5em;text-align:right}
/* On a phone this hero used to HIDE the portal and let the three snippet cards
   stack full width instead — so the page sold a practitioner portal without
   showing one, and three unrelated white slabs stood where a composition had
   been. The shot comes back, whole and small: the same treatment the homepage
   duo gets, where a 1440px screen rendered at 326 reads as an object you
   recognise as a dashboard rather than as text you are meant to read.

   The cards become one row you swipe, so all three are still there at the size
   they were drawn for and the hero is a picture again rather than a pile. */
.deskout-cards{display:contents}          /* desktop: the cards position against .deskout */
/* 999, not 820: the hero stacks below 1000, and between 820 and 999 the
   lifted-out cards were still floating at desktop offsets — hanging off the
   bottom of the shot and over the buttons. Same range as the stack. */
@media(max-width:999px){
  /* min-width:auto is the default on grid and flex items, and it resolves to
     MIN-CONTENT — so the portal mock's client table, five columns of words that
     will not wrap, set a 418px floor on a 362px column. The grid then sized its
     one column to 418 and every child of the hero, headline included, was cut
     off at the right edge. Nothing here can shrink unless the whole chain is
     allowed to; .pui already clips its own overflow. */
  .hero-grid{grid-template-columns:minmax(0,1fr)}
  .hero-media,.deskout,.deskout .hero-shot,.deskout .pui{min-width:0;max-width:100%}
  .deskout{padding:0;display:flex;flex-direction:column;gap:14px}
  .deskout .hero-shot{display:block;width:100%}
  .deskout .pui{width:100%;max-width:none;font-size:clamp(2.6px,1.12cqi,11px)}

  /* NO bleed margins here. .deskout is a flex column inside the hero, so a
     child made wider than its container grows the hero's intrinsic width and
     pushes the headline, sub and buttons off the right edge — which is exactly
     what a negative margin did. It stays inside its box; the 78% items give the
     peek on their own. min-width:0 so the row can actually shrink to fit. */
  /* The three lifted-out snippets were drawn to float over a desk-width screen.
     At phone scale they are cards of 10px tables with no screen behind them —
     they read as clutter whether they stack or swipe. The portal home already
     carries the argument on its own, so on a phone it is the only thing here. */
  .deskout-cards{display:none}
}

/* ============ STORE BADGES + PRICING ============
   Hand-drawn stand-ins for the official badge artwork. Both Apple and Google
   require their OWN supplied assets and forbid redrawn marks, so these must be
   swapped for the downloaded SVGs before launch — the shape is right, the
   licence is not. */
.stores{display:flex;flex-wrap:wrap;align-items:center;gap:.7rem;
  margin-top:clamp(22px,2.6vw,32px)}
/* Two badges at their natural width plus the gap come to ~341px, which is 15px
   more than a 390 screen has — so they wrapped to a line each and the hero
   grew a stacked pair of black bars. Tightened just enough to hold one row. */
@media(max-width:560px){
  /* Wrap, NOT nowrap. The homepage hero puts a third button in this row and the
     deep-dive pages do not — forcing one line meant that third item took its
     100% basis out of the same row and squeezed both badges to nothing, text
     spilling out of two empty pills. Wrapping lets the badges share row one and
     the button take row two on its own. */
  .stores{flex-wrap:wrap;gap:.5rem}
  .stores .store{flex:1 1 auto;min-width:0;padding-left:.75em;padding-right:.75em}
  /* the two-line label is what breaks the row: "Download on the" wraps before
     the badge does, so the badge grows taller and shoves the pair onto separate
     lines. Hold both lines on one line each and let the type shrink instead. */
  /* Clipping a label is worse than shrinking it: overflow:hidden here turned
     the badges into "DOWNLOAD ON T" and "Google Pla". They size to their own
     content and the type comes down instead, which fits both on one row. */
  .stores .store span{min-width:0;white-space:nowrap;font-size:.86rem}
  .stores .store span em{white-space:nowrap;font-size:.53rem}
  .stores .btn-alt{flex:1 0 100%;margin-top:.2rem;justify-content:center}
}
.store{display:inline-flex;align-items:center;gap:.6em;text-decoration:none;
  background:var(--ink);color:#fff;border-radius:.72em;padding:.5em .95em .55em;
  line-height:1.05;transition:background .18s ease}
.store:hover,.store:focus-visible{background:#2b2720}
/* On the film hero the ink pill would vanish into the footage, so the badges
   invert — white plate, dark mark — the way the official dark-background
   artwork does. The Play triangle keeps its own colours either way. */
.hero .store{background:#fff;color:var(--ink)}
.hero .store:hover,.hero .store:focus-visible{background:var(--paper)}
.hero .stores{margin-top:clamp(26px,3.4vw,38px);align-items:center}
.store-ico{width:1.6em;height:1.6em;flex:none}
.store span{display:block;font-size:1rem;letter-spacing:-.01em}
.store em{display:block;font-style:normal;font-size:.6rem;letter-spacing:.07em;
  text-transform:uppercase;opacity:.8;margin-bottom:.1em}
.price{margin-top:clamp(13px,1.5vw,18px);font-size:.88rem;color:var(--stone);max-width:48ch}
.price b{font-weight:500;color:var(--ink)}
/* the ticker occupies the panel's bottom padding, so the panel gives some back */
.hero-panel.has-ticker{padding-bottom:clamp(26px,3vw,44px)}
.ticker{position:relative;margin-top:clamp(30px,4.4vw,58px);overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 11%,#000 89%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 11%,#000 89%,transparent 100%)}
.ticker-track{display:flex;width:max-content;animation:ticker-run 86s linear infinite}
/* Perelel's strip, not a row of pills: small capitals, letterspaced, a dot
   between each item, nothing behind the words. The founder pointed at theirs. */
.ticker-run{display:flex;align-items:center;gap:0}
.ticker s{text-decoration:none;white-space:nowrap;display:inline-flex;align-items:center;
  color:var(--clay-deep);text-transform:uppercase;letter-spacing:.14em;font-weight:500;
  font-size:clamp(.66rem,.8vw,.74rem);line-height:1.2;padding:.5em 0}
.ticker s::after{content:"";display:inline-block;width:4px;height:4px;border-radius:50%;
  background:var(--accent);opacity:.7;margin:0 1.4rem}
@keyframes ticker-run{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.ticker:hover .ticker-track{animation-play-state:paused}
/* honour the same preference the rest of the page does */
@media(prefers-reduced-motion:reduce){.ticker-track{animation:none}}


/* ============================================================
   PANELS LIFTED FROM THE BROCHURE (2026-09-10)

   Three of the practitioner page's cards showed a captured screenshot of the
   portal or the app, shrunk into a card. A 2400px dashboard at card width is a
   smear of bars with unreadable labels, and a crop of the app's home screen
   shows a third of one area — the founder read them side by side with the
   brochure's and said so.

   The brochure draws those three instead, at the size a card actually shows
   them, and these are those rules verbatim. Same class names, so the two stay
   diff-able; same tokens, which both stylesheets already define.
   ============================================================ */
/* The mount the three panels sit on, and the base size everything inside them
   is relative to. Slightly tighter here than in the brochure: this page gives a
   card 262px of media where the brochure gives it up to 282, and the record's
   closing line was falling off the bottom. */
.bro-soldraw{width:100%;background:var(--white);border-radius:9px;
  padding:12px 13px;font-size:.7rem}

/* her whole record: a day off the strip, and what each area filed under it */
.bro-recdays{display:flex;gap:5px;margin-top:7px}
.bro-recdays span{flex:1;text-align:center;border:1px solid var(--line);border-radius:8px;
  padding:4px 0;font-size:.58rem;color:var(--stone-deep);white-space:nowrap}
.bro-recdays span.is-on{background:var(--ink);border-color:var(--ink);color:#fff}
.bro-rec{margin-top:7px;border:1px solid var(--line);border-radius:10px;overflow:hidden}
/* The area and what it filed sit on ONE line each. Stacked, five areas plus the
   day strip ran past the bottom of the card and Health admin fell off it —
   which is the one row that proves the record is not just cycle tracking. */
.bro-recrow{display:grid;grid-template-columns:5.6rem 1fr;gap:0 10px;align-items:center;
  padding:6px 10px;background:var(--paper-3)}
.bro-recrow + .bro-recrow{border-top:1px solid var(--line)}
.bro-recrow em{display:flex;align-items:center;gap:5px;font-style:normal;font-size:.53rem;
  letter-spacing:.08em;line-height:1.25;text-transform:uppercase;color:var(--clay)}
.bro-recrow em i{width:6px;height:6px;border-radius:50%;flex:none}
.bro-recrow span{font-size:.72rem;line-height:1.3;color:var(--ink)}
.bro-recfoot{margin-top:6px;text-align:center;font-size:.6rem;color:var(--stone-deep)}

/* her day as four tiles and one flat button, the way the app stacks its areas */
.bro-adaygrid{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:7px}
.bro-aday{background:var(--paper-3);border-radius:10px;padding:9px 10px 10px;min-width:0}
.bro-adayk{display:flex;align-items:center;gap:6px;font-size:.56rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--clay);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.bro-adayk i{width:7px;height:7px;border-radius:50%;flex:none}
.bro-aday p{margin:5px 0 0;font-size:.73rem;line-height:1.32;color:var(--ink)}
.bro-adaybar{height:5px;border-radius:99px;background:rgba(120,110,98,.16);margin:7px 0 4px}
.bro-adaybar u{display:block;height:100%;border-radius:99px;text-decoration:none}
.bro-aday span{display:block;font-size:.64rem;color:var(--stone-deep);margin-top:5px}
.bro-aday .bro-adaybar + span{margin-top:0}
.bro-adaycta{margin-top:7px;text-align:center;border:1px solid var(--line);border-radius:10px;
  padding:8px 0;font-size:.62rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--stone-deep)}

/* the dashboard metric, drawn rather than captured, so the bars read at the
   size a card actually shows them */
.bro-dashn{font-size:1.9rem;font-weight:400;color:var(--ink);line-height:1;margin:8px 0 5px}
.bro-dashs{font-size:.76rem;color:var(--ink)}
.bro-dasht{font-size:.74rem;color:var(--stone-deep);margin-top:3px}
.bro-dasht i{font-style:normal;color:var(--ink);margin-right:3px}
.bro-dasht b{font-weight:500;color:var(--ink)}
.bro-dashc{display:block;width:100%;height:auto;margin-top:10px}
.bro-dashax text{font-size:7px;fill:#a89f8d;font-family:'Poppins',sans-serif}

/* the named capabilities, as tablets under the sentence */
.bro-solfeats{list-style:none;display:flex;flex-wrap:wrap;gap:8px;margin:16px 0 0;padding:0}
.bro-solfeats li{font-size:.88rem;line-height:1.3;color:var(--ink);
  background:var(--paper-3);border:1px solid rgba(120,110,98,.16);
  border-radius:999px;padding:7px 14px;white-space:nowrap}
.bro-solcard p{margin-bottom:0}
/* the metric headline carries its own unit line on the adherence card */
.bro-dashn em{font-style:normal;font-size:.76rem;color:var(--stone-deep);margin-left:8px}

/* On a phone the card gives 198px of media and these panels are px-padded, so
   type alone does not shrink them: the record lost its Health admin row, which
   is the one that proves this is not just cycle tracking. Tighten the rows
   there instead of cropping them away. */
@media(max-width:700px){
  .bro-soldraw{padding:10px 11px;font-size:.66rem}
  /* the day strip earns its space on a laptop and costs a row on a phone, where
     what matters is that five areas filed under one day */
  .bro-recdays{display:none}
  .bro-recrow{grid-template-columns:4.6rem 1fr;gap:0 8px;padding:5px 8px}
  /* one line per area, cut where it runs out: five areas that fit beats four
     that wrap and a fifth that falls off the card */
  .bro-recrow span{font-size:.66rem;line-height:1.25;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .bro-recrow em{font-size:.5rem}
  .bro-adaygrid{gap:5px;margin-top:5px}
  .bro-aday{padding:7px 8px 8px}
  .bro-aday p{font-size:.68rem;margin-top:4px;
    display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
  .bro-adayk{font-size:.5rem}
  .bro-adaybar{margin:5px 0 3px}
  .bro-aday span{font-size:.58rem;margin-top:3px}
}

/* ============ THE PHONE, BALANCED ============
   Three things the founder saw on a small screen, fixed together and kept at
   the end of the sheet so they win.

   1. CENTRED WHEN STACKED. Every two-column section — copy beside a screen —
      folds to one column on a phone, and the copy stayed left-aligned over a
      centred picture: a heading pinned to the edge, a paragraph pinned to the
      edge, and the product floating in the middle under them. Once there is
      no second column, there is nothing for the copy to be aligned against.
      It centres, and so do the buttons, the pills and the small lines.

   2. THE RAIL SWIPES. The eight cards piled into a 3,400px stack on a phone,
      the height of the whole rest of the page. They are a row you flick
      through now, the way the phone rail already behaved and the way a page
      like Perelel's does it — one screen, not nine.

   3. THE TYPE COMES DOWN A STEP. The display sizes were tuned for a laptop
      and their minimums were still large on 390px: a 31px headline over a
      16px paragraph in a 350px column. Headline 28, section head 23, card
      head 20, body 15. Still light, still airy, no longer shouting. */
@media(max-width:999px){
  /* 1 — centred */
  .hero-grid:has(.hero-media) h1,
  .hero-grid:has(.hero-media) .hero-sub,
  .hero-grid:has(.hero-media) .price,
  .hero-grid:has(.hero-media) .built{text-align:center;margin-left:auto;margin-right:auto}
  .hero-grid:has(.hero-media) .btns,
  .hero-grid:has(.hero-media) .stores{justify-content:center}
  .hero-grid:has(.hero-media) .built{border-top:0;padding-top:0}
  .hero-grid:has(.hero-media) .tagrow,
  .hero-grid:has(.hero-media) .chips,
  .hero-grid:has(.hero-media) .pills{justify-content:center}
  .explain h2,.explain-lede,.explain-close{text-align:center;margin-left:auto;margin-right:auto}
  .lead{text-align:center}
  .lead h2,.lead p{margin-left:auto;margin-right:auto}
  .rt-split > *:first-child,.aud > *:first-child{text-align:center}
  /* the section leads on the deep-dive pages carry a heading and one or two
     paragraphs and nothing else; centred, the measure has to stay readable */
  .lead p{max-width:36em}

  /* 2 — the rail is a row */
  /* A grid item sizes to its content's max-content unless told otherwise,
     and a row of eight cards has a max-content width of eight cards. On the
     women's page .rail-wrap sits in a grid and grew to 786px on a 390px
     phone — one card filling twice the screen, its paragraph running off the
     right edge. min-width:0 is what lets it shrink to the column. */
  .stackwrap{grid-template-columns:minmax(0,1fr)}
  .rail-wrap{min-width:0;max-width:100%}
  .rail,.areas.rail,.stack.rail{display:flex;flex-wrap:nowrap;gap:12px;
    overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;
    padding-bottom:10px;scrollbar-width:none;-ms-overflow-style:none;
    /* the row runs to the section's edge so the next card is cut by the
       screen, not by a margin — the cut IS the cue that there is more */
    margin-right:calc(-1 * var(--pad,18px));padding-right:var(--pad,18px);
    scroll-padding-left:0}
  .rail::-webkit-scrollbar{display:none}
  .rail > *{flex:0 0 78%;scroll-snap-align:start;position:static;top:auto;
    box-shadow:0 18px 40px -30px rgba(46,42,37,.4)}
  .rail > :nth-child(n){top:auto}
  .rail .stackcard{grid-template-columns:1fr}
  /* Arrae's cue: a small round arrow on the right edge, over the card. It
     goes when the row is scrolled to its end, which the desktop script
     already toggles on .rail-next — the phone just gets to see it. */
  .rail-arrow.rail-next{display:grid;place-items:center;position:absolute;
    right:6px;top:38%;width:38px;height:38px;padding:0;border-radius:50%;
    background:rgba(58,53,47,.82);border:0;color:#fff;cursor:pointer;z-index:4;
    opacity:0;pointer-events:none;transition:opacity .25s ease}
  .rail-arrow.rail-next.on{opacity:1;pointer-events:auto}
  .rail-arrow.rail-next svg{width:14px;height:14px}
  .rail-arrow.rail-prev{display:none}

  /* THE THREE PHONES, on a phone. They were a swipe of bezelled devices, each
     fading out through its own black frame — which read as a broken phone
     shape rather than a cut one. Now three rows that fit one screen: the
     screen on the left, cut clean at the bottom with no frame, the line
     about it on the right. */
  /* an older rule caps .patient-view at 280px and centres it on small screens —
     right for a single phone, wrong for a row of screen + caption, which
     it shoved into a 280px column on the right-hand side of a tablet */
  .patient-view.trio{display:grid;grid-template-columns:1fr;gap:14px;overflow:visible;
    max-width:none;margin-inline:0;margin-right:0;padding-right:0;scroll-snap-type:none}
  .patient-view.trio > *{display:grid;grid-template-columns:44% minmax(0,1fr);gap:18px;width:100%;
    align-items:center;flex:none;position:static;z-index:auto}
  .patient-view.trio .phone{max-width:none;width:100%;aspect-ratio:auto;height:196px;
    overflow:hidden;background:none;padding:0;box-shadow:none;border-radius:0;margin:0;
    -webkit-mask-image:linear-gradient(to bottom,#000 0,#000 70%,transparent 100%);
    mask-image:linear-gradient(to bottom,#000 0,#000 70%,transparent 100%)}
  .patient-view.trio .notch{display:none}
  .patient-view.trio .screen{height:auto;border-radius:12px;background:var(--white);
    box-shadow:0 14px 30px -20px rgba(46,42,37,.4)}
  .patient-view.trio .g-cap{text-align:left;font-size:1rem;line-height:1.4;color:var(--ink);margin:0;max-width:none}
  /* .ui is absolutely positioned inside the phone frame; with the frame gone
     it has to flow, or the screen has no height and the phone is nothing */
  .patient-view.trio .ui{position:static;inset:auto;background:transparent}
  .patient-view.trio .ui-top,.patient-view.trio .ui-nav{display:none}
  .patient-view.trio .ui-body{padding-top:10px}

  /* the film hero on the homepage: same treatment, centred over the picture */
  .hero .hero-copy{text-align:center}
  .hero h1,.hero .hero-sub{margin-left:auto;margin-right:auto}
  .hero .stores,.hero .btns{justify-content:center}
}
@media(max-width:700px){
  /* 3 — the type */
  h1{font-size:clamp(1.75rem,7.2vw,2.2rem)}
  h2{font-size:clamp(1.35rem,5vw,1.6rem)}
  .lead p,.hero-sub,.explain-lede,.explain-close,
  .stackcard p,.acard p,.aud2 p,.pathcard p,.bene p,.whocard p,.faq p{font-size:.94rem;line-height:1.6}
  .aud2 h3,.pathcard h3,.path-h{font-size:1.25rem}
  .stackcard h3,.acard h3,.bene h3{font-size:1.08rem}
  .story p{font-size:1.18rem;line-height:1.4}
  .rail .stackcard > div:not(.sc-media){padding:18px}
}

/* the practitioner-type list is the same strip, sitting under its label */
.ticker.ticker-who{margin-top:10px}
.ticker.ticker-who .ticker-track{animation-duration:110s}

/* ============ THE WITHOUT / WITH, ON A PHONE ============
   Four statements stacked under the switch made this the tallest thing on the
   phone page. They are a row you flick through now, one statement per card,
   the switch still turning all four at once. The section's photograph stays
   behind them; the cards carry a faint wash so the text has a ground. */
@media(max-width:859px){
  .diff.is-switch{display:flex;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;gap:12px;scrollbar-width:none;-ms-overflow-style:none;
    margin-left:calc(-1 * var(--pad));margin-right:calc(-1 * var(--pad));
    padding:0 var(--pad) 6px;scroll-padding-left:var(--pad)}
  .diff.is-switch::-webkit-scrollbar{display:none}
  .diff.is-switch .diff-row{flex:0 0 82%;scroll-snap-align:start;border-top:0;
    padding:18px 18px 22px;border-radius:14px;background:rgba(255,255,255,.07);
    border:1px solid rgba(255,255,255,.14)}
  .diff-photo.has-switch[data-side="b"] .diff.is-switch .diff-row{background:rgba(255,255,255,.1)}
  .diff.is-switch .diff-row h3{font-size:1.05rem}
  .diff.is-switch .diff-row p{font-size:.9rem;line-height:1.55}
}
@media(max-width:999px){
  /* the cue sits on a photograph here, so it goes light */
  .diff-photo .rail-arrow.rail-next{background:rgba(255,255,255,.92);color:var(--ink);top:auto;bottom:34px}
}
/* the first of the three phones is a capture, not a drawn screen: it fills
   the frame from the top and is cut by the same fade as its neighbours */
.patient-view.trio .phone .screen .app-shot{object-fit:cover;object-position:top}
@media(max-width:819px){
  .patient-view.trio .phone .screen .app-shot{height:auto;display:block}
}
