/* == fonts: generated by `npm run fonts` (sites/tools/fonts.mjs), do not edit by hand == */
/* Self-hosted from Google Fonts. To change the faces, edit the URL below and
   re-run `npm run fonts`; it reads the URL back from here, and the preload
   list too (PAGE.md, "Preload what paints first").
   source: https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600&family=Inter:ital,wght@0,400;0,600;0,700;1,400;1,600&display=swap
   preload: Inter:400,Fraunces:600
*/
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/fraunces-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/fraunces-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/fraunces-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/fraunces-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/inter-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* == end fonts == */

/* ===========================================================================
   Healing Nomad

   WHERE THIS DESIGN COMES FROM, because it is not the usual answer.

   Angela did not pick one of the three concept directions. She had already
   designed the site herself in Canva and then sent an eleven-part written
   specification instead -- copy, the whole treatment menu with prices, the
   compliance blocks, and layout instructions down to the divider rules. Her
   spec is in claude/projects/healing-nomad/source/ in the platform repo, and
   it is the authority for STRUCTURE and CONTENT.

   It also fixes the visual ground, twice and explicitly: "blends smoothly into
   our dark background" (phase 1) and "integrate natively into our dark neutral
   template" (phases 5 and 6). So the site is dark because she said so.

   AND THEN BLACK, 21 Sep 2026. Her changelog, Part 1: "Completely remove the
   'perceived' dark green background color across the entire site. Replace it
   with a premium, solid matte black background (#000000)". The near-black
   teal from the Clinical After Dark mockup is gone, and so is the teal cast
   it gave every grey: the greys below are neutral so nothing reads green.

   THE ACCENTS ARE SAMPLED FROM HER OWN LOGO, not from the concept she turned
   down: #FF0069 and #16DADE are read straight out of IMG_8456.PNG, the master
   file she attached to phase 8, which she describes as "vibrant Neon Turquoise
   and Neon Pink". The near-black ground is the one place the Clinical After
   Dark mockup is used, because it is the only dark value anyone approved and
   it sits correctly under her two accents.

   AND THEN A STYLE GUIDE, 22 Sep 2026. Jacob made two renders of the home and
   treatments pages -- design/mockup/ -- and they ARE measured: the grounds,
   the card fill and hairline, the two-column hero, the heading rows, the glow
   band and the menu card's price rail all trace to design/SPEC.md, "Measured:
   the 22 Sep 2026 style mockups", at 887 x 1.4425. They are style only. Jacob:
   "These are just style guides.. dont chyange a word or an image file. just
   redesign, and reorient", so every word and every image is still hers, and
   the renders' own invented packages, prices and rewritten disclaimers are not
   built. Her spec's numbers -- 10px or 11px footer text, a 768px breakpoint,
   four equal columns, two columns with the introductory rate on the left --
   are still tokens and rules below, commented with the phase they came from.
   =========================================================================== */

:root {
  /* --- Colour ------------------------------------------------------------
     Her logo, sampled: the pink and turquoise outlines of the hand mark, and
     the teal of the script inside it. The grounds are her #000000 (21 Sep),
     with cards and hairlines lifted just off it in plain grey. */
  --brand-pink: #ff0069;        /* logo, outer hand outline */
  --brand-cyan: #16dade;        /* logo, inner outline and script */
  --brand-cyan-soft: #7febee;   /* lifted for text on near-black, for contrast */

  --ground: #000000;            /* page: her "solid matte black" (21 Sep, Part 1) */
  --ground-2: #060607;          /* alternating band, sampled off the 22 Sep render */
  --card: #0e1011;              /* card and panel fill, sampled */
  --line: #1d1e21;              /* hairline: her "border-top: 1px solid", sampled */

  --ink: #f2f2f2;               /* body text on black */
  --ink-dim: #b0b0b0;           /* secondary copy, 9.6:1 on black */
  --ink-faint: #8c8c8c;         /* her "subtle, low-contrast gray" (phase 1), 6.1:1 */

  /* --- Layout ----------------------------------------------------------- */
  --wrap: 1140px;
  --gut: 24px;
  --radius: 14px;

  /* --- Type -------------------------------------------------------------
     One family, because she asked every new block to "inherit our site's
     existing global font-family stack" (phase 4). */
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;

  --f-h1: clamp(2.1rem, 1.45rem + 2.5vw, 3.2rem);   /* 51px at 1280: the 22 Sep render's h1, 118px of ink over three lines at 887 */
  --f-h2: clamp(1.65rem, 1.2rem + 1.9vw, 2.5rem);
  --f-h3: clamp(1.1rem, 0.98rem + 0.5vw, 1.3rem);
  --f-body: clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);
  --f-small: 0.875rem;
  --f-eyebrow: 0.72rem;
  --f-legal: 11px;              /* phase 1: "10px or 11px font size" */

  /* --- Rhythm ----------------------------------------------------------- */
  --sec-pt: clamp(56px, 7vw, 104px);
  --sec-pb: clamp(56px, 7vw, 104px);
  --gap-head-body: 20px;
}

/* A minimal reset. Everything else belongs to the design. */
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; }
img, picture, svg, video { display: block; max-width: 100%; height: auto; }
h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; }
button { font: inherit; color: inherit; }

/* NO GLOBAL SMOOTH SCROLL, deliberately, and it is worth saying why because it
   looks like a free nicety and gets added back.

   Nothing here needs it: the nav goes to other pages and the only in-document
   jump is the skip link, where a reader who has just pressed Tab wants to
   arrive, not to travel. What it costs is real. `scroll-behavior: smooth`
   makes every programmatic `scrollTo` an animation, so anything that scrolls
   and then measures reads the page mid-flight: `npm run check:layout` reported
   headings on four pages as "covered by the site header", the offenders moved
   between runs, and nothing was covering anything. The platform repo lists the
   same trap in claude/11-site-construction.md.

   `scroll-padding-top` is the part that must stay. The header is sticky, so an
   anchored jump would otherwise land its target underneath it. */
html { scroll-padding-top: 84px; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body {
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--f-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gut); }
.wrap--narrow { max-width: 780px; }

section { padding-block: var(--sec-pt) var(--sec-pb); }
.band { background: var(--ground-2); }

h1, h2 { font-family: var(--font-display); font-weight: 600; line-height: 1.12; letter-spacing: -0.015em; }
h1 { font-size: var(--f-h1); }
h2 { font-size: var(--f-h2); }
h3 { font-size: var(--f-h3); font-family: var(--font); font-weight: 600; letter-spacing: 0.01em; line-height: 1.3; }

/* Her "Sub-Header / Category Branding" line, which recurs in phases 3, 4, 6
   and 7 as a small tracked caps label under a title. */
.eyebrow {
  font-family: var(--font);
  font-size: var(--f-eyebrow);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand-cyan-soft);
}
.eyebrow--pink { color: var(--brand-pink); }

.lede { font-size: 1.125rem; color: var(--ink-dim); max-width: 62ch; }
p + p { margin-top: 1em; }
.muted { color: var(--ink-dim); }
.stack { display: grid; gap: var(--gap-head-body); }
.stack--lg { display: grid; gap: 34px; }

/* Her divider, named once. Phases 4, 6 and 7 each ask for the same thing:
   "a subtle top border divider line (border-top: 1px solid) with adequate
   padding", separating a notice from what it qualifies. */
.rule-note {
  border-top: 1px solid var(--line);
  margin-top: 24px;
  padding-top: 16px;
}

/* Her clinical notices: an italic note, and a smaller light-grey italic
   regulatory line. Both wordings are hers, verbatim, in the markup. */
.notice { font-size: var(--f-small); font-style: italic; color: var(--ink-dim); }
.notice--reg { font-size: 0.8125rem; color: var(--ink-faint); font-style: italic; }
/* Her notices are italic and their labels are bold, so the label needs a real
   BOLD ITALIC face. Inter ships 600 italic here and not 700, and <b> defaults
   to 700 -- which the browser would synthesise by slanting the upright. 600 is
   the weight that exists. */
.notice b, .notice--reg b { font-weight: 600; }

/* -------------------------------------------------------------- buttons --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  /* Her CTA label is thirty characters ("CLICK HERE TO TEXT TO BOOK NOW",
     phase 11) and the words are hers, so the button gives way instead. Type
     and padding RAMP with the viewport rather than stepping at a breakpoint:
     the first version of this stepped 12.5px -> 15.2px at 421px, which
     `npm run sweep` correctly called a size-jump with no structural change
     behind it. A button whose label wraps reads as a broken control, and on a
     phone this is the only booking action there is. */
  /* 62px tall and 293 wide in the 22 Sep render (43 x 203 at 887 x 1.4425).
     The floor stays 48, the touch target, for the narrowest phones. */
  padding: clamp(14px, 10px + 0.9vw, 19px) clamp(16px, 8px + 2.5vw, 28px);
  border-radius: 999px; border: 1px solid transparent;
  font-weight: 600; font-size: clamp(0.78rem, 0.481rem + 1.5vw, 0.95rem); letter-spacing: 0.02em;
  text-decoration: none; cursor: pointer; min-height: 48px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.btn--primary { background: var(--brand-cyan); color: #03161b; }
.btn--primary:hover { background: var(--brand-cyan-soft); }
.btn--ghost { border-color: var(--line); color: var(--ink); }
/* The render puts an arrow inside every pill. Decoration: the label is the
   link's text, and the glyph is aria-hidden in the markup. */
.btn svg { width: 15px; height: 15px; fill: currentColor; flex: none; }
.btn--ghost:hover { border-color: var(--brand-cyan); }
.btn:focus-visible, a:focus-visible, button:focus-visible {
  outline: 2px solid var(--brand-cyan); outline-offset: 3px;
}

/* ------------------------------------------------- the text-to-book CTA ---
   Phases 2 and 11 specify this exactly: the sms: link below 768px, and above
   768px the button is hidden and replaced by a line of static text, because a
   desktop cannot send a text.

   THIS LEAVES DESKTOP WITH NO CLICKABLE ACTION, which is an open ask on the
   build card rather than something to quietly fix here. Built as she wrote it.
   Both forms are real content rather than one being decoration, so whichever
   a reader meets says the same thing. */
.sms-cta { display: inline-flex; }
.sms-desktop, .desktop-cta { display: none; }
@media (min-width: 768px) {
  .sms-cta { display: none; }
  /* Above 768 the same pill, same label, goes to /contact instead, which
     carries her line, her consent paragraph and the number as text. So the
     sms: link never reaches a machine that cannot send one, and the band
     still has something to click (Jacob, 22 Sep). */
  .desktop-cta { display: inline-flex; }
  .sms-desktop { display: block; font-size: 1.0625rem; color: var(--ink); max-width: 48ch; }
  .sms-desktop strong { color: var(--brand-cyan-soft); font-weight: 600; }
}

/* --------------------------------------------------------------- header --- */
.site-header {
  position: sticky; top: 0; z-index: 40;
  background: rgba(0, 0, 0, 0.94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.site-header__inner { display: flex; align-items: center; gap: 18px; min-height: 68px; position: relative; }
.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; margin-right: auto; }
.brand img { width: 38px; height: auto; }
.brand__name { font-family: var(--font-display); font-size: 1.12rem; font-weight: 600; letter-spacing: -0.01em; white-space: nowrap; }

.nav { display: flex; gap: 24px; }
.nav a { text-decoration: none; font-size: 0.95rem; color: var(--ink-dim); }
.nav a:hover, .nav a[aria-current="page"] { color: var(--brand-cyan-soft); }

/* Phase 9: "a small, minimal, clickable phone icon and an Instagram icon in
   the top right utility margin of every page". */
.utility { display: flex; align-items: center; gap: 10px; }
.utility a { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--line); color: var(--ink-dim); }
.utility a:hover { border-color: var(--brand-cyan); color: var(--brand-cyan-soft); }
.utility svg { width: 17px; height: 17px; fill: currentColor; }

.nav-toggle { display: none; background: none; border: 1px solid var(--line); border-radius: 10px; width: 44px; height: 44px; cursor: pointer; }
.nav-toggle svg { width: 20px; height: 20px; margin-inline: auto; fill: currentColor; }

@media (max-width: 900px) {
  .nav-toggle { display: block; }
  .nav {
    /* inset-inline: 0, NOT a negative gutter. The containing block is
       .site-header__inner, which is a .wrap, and a .wrap's padding box already
       spans the full viewport below its max-width: the gutter is inside its
       width, not outside it. Pulling the panel out by -24px therefore did not
       bleed it to the edges, it pushed it 24px off-screen on each side and
       left every link sitting flush at x=0 with no left spacing at all.
       check:widths never caught it because the panel is closed when the page
       loads, so no automated width pass has ever seen it open. */
    position: absolute; inset-inline: 0; top: 100%;
    flex-direction: column; gap: 0;
    background: var(--ground-2); border-bottom: 1px solid var(--line);
    padding: 4px var(--gut) 18px;
  }
  .nav[hidden] { display: none; }
  .nav a { padding: 14px 0; border-bottom: 1px solid var(--line); font-size: 1.05rem; }
  .nav a:last-child { border-bottom: 0; }
}

/* ----------------------------------------------------------------- hero ---
   21 Sep, Part 1: her photograph is out of the hero and the logo is the
   anchor. It was centred above the copy until the 22 Sep style render put it
   in its own column beside the headline, which is what this builds (Jacob's
   call, 22 Sep: "Build the mockup's layout"). Below 900 it stacks, logo
   first, so the anchor still leads.

   Measured off the render at 887 x 1.4425: copy column 490 wide, logo 425,
   gap 104. */
.hero { padding-block: clamp(36px, 5vw, 63px) clamp(44px, 6vw, 80px); }
.hero__inner { display: grid; gap: clamp(28px, 4vw, 52px); justify-items: center; }
.hero__copy { display: grid; gap: 20px; justify-items: center; text-align: center; }
.hero__copy .lede { margin-inline: auto; }
.hero__logo { width: min(425px, 72vw); order: -1; }
/* The treatments hero draws it smaller than the home one: 251 wide at 887,
   362 at 1.4425, against the home hero's 425. */
.hero__logo--sm { width: min(270px, 56vw); }
/* At 270 the hero lockup's own tracking broke "Integrative Wellness" onto two
   lines, the same way the 160px footer one did. Tighter and smaller here. */
.hero__logo--sm .logo-lockup__sub { font-size: clamp(0.6rem, 0.5rem + 0.35vw, 0.78rem); letter-spacing: 0.22em; padding-left: 0.22em; white-space: nowrap; }

/* An inner page's hero carries a title, a line and a pill, not a headline and
   a screening disclosure, so it gets about half the home hero's air: Jacob,
   22 Sep, "this hero section has way too much space above and below the hero
   header... we can shrink the logo a bit to fit". The logo is 300 rather than
   362 for the same reason - it was setting the band's height on its own. */
.hero--page { padding-block: clamp(20px, 2.4vw, 32px) clamp(24px, 3vw, 40px); }
.hero--page .hero__inner { row-gap: clamp(20px, 2.6vw, 34px); }
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; }
@media (min-width: 900px) {
  .hero__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 0.86fr); align-items: center; column-gap: clamp(48px, 7vw, 104px); }
  .hero__copy { justify-items: start; text-align: left; }
  .hero__copy .lede { margin-inline: 0; }
  .hero__actions { justify-content: flex-start; }
  .hero__logo { order: 0; width: min(425px, 34vw); }
  .hero__logo--sm { width: min(270px, 22vw); }
  .hero__inner .tcpa { margin-inline: 0; }
}

/* The full logo with her new subtext (21 Sep, Part 1). The master artwork is
   420 x 611 and its last line, OZONE | VITAMINS, starts at row 581; the
   artwork proper ends at row 531. The frame is cut to 420:532 so that line
   never shows, without editing her file, and "Integrative Wellness" is set
   beneath it in the same spaced light-grey caps the artwork uses. */
.logo-lockup { display: grid; justify-items: center; margin-inline: auto; }
.logo-lockup__art { display: block; width: 100%; aspect-ratio: 420 / 532; overflow: hidden; }
.logo-lockup__art img { width: 100%; }
.logo-lockup__sub {
  margin-top: 0.6em; font-size: clamp(0.72rem, 0.6rem + 0.6vw, 1rem);
  letter-spacing: 0.32em; text-transform: uppercase; color: #d9d9d9;
  padding-left: 0.32em; /* the tracking trails the last letter; this re-centres it */
}

/* Part 2, item 2: her TCPA disclosure, "in small, clean print directly
   underneath the texting call-to-action line". */
.tcpa { font-size: 0.75rem; line-height: 1.6; color: var(--ink-faint); max-width: 62ch; }
.tcpa a { color: var(--ink-dim); }
.hero__inner .tcpa { margin-inline: auto; }

/* .section-head, the homepage menu preview's title row, went with the
   preview on 2 Oct 2026. */

/* Part 2, item 5: "Drastically increase the font size of the header to create
   a clean, bold, high-luxury gateway directly to our options". The treatments
   h1 and the homepage h2 share it, so the menu is announced the same way
   wherever it starts. */
.menu-title { font-size: clamp(2.3rem, 1.6rem + 2.6vw, 3.6rem); line-height: 1.05; letter-spacing: -0.02em; }
/* No nowrap here: at 63px the title is 668px of ink, which fits the 1092
   column beside its pill on the home page and must WRAP in the treatments
   hero, where its column is half that. Forcing one line pushed the hero
   title off the left of the page (caught in the render pass, 22 Sep). */

/* A band lit from two corners: her turquoise from the top left, her pink from
   the bottom right, over black. Sampled off the 22 Sep render, which reads
   #003a47 at the left edge, #72063b at the bottom right and #050708 through
   the middle - two radial glows, not a left-to-right ramp. */
.band--glow {
  background:
    radial-gradient(60% 120% at 0% 0%, rgba(22, 218, 222, 0.22), transparent 60%),
    radial-gradient(60% 120% at 100% 100%, rgba(255, 0, 105, 0.26), transparent 60%),
    #050607;
}

/* ---------------------------------------------------------------- cards --- */
.grid { display: grid; gap: 20px; }
.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 26px 24px; display: flex; flex-direction: column; gap: 12px;
}
/* Fraunces is loaded at 500 and 600 only. Anything set in the display face
   must name one of them: inheriting 400 makes the browser invent a face, which
   `npm run qa` catches as synthesised type and which renders differently on
   every machine. */
.card__price { font-family: var(--font-display); font-weight: 500; font-size: 1.45rem; color: var(--brand-cyan-soft); }
.card__best { font-size: var(--f-small); color: var(--ink-dim); }
.card__best b { color: var(--ink); font-weight: 600; }

/* Phase 4: "please lay out four equal visual columns... do not apply any
   highlighted frames or asymmetrical styling. Every card must look
   identical." Hence one class, no featured modifier anywhere. */
.grid--4 { grid-template-columns: repeat(2, 1fr); }
@media (min-width: 900px) { .grid--4 { grid-template-columns: repeat(4, 1fr); } }

/* Phase 6: "exactly two equal visual columns (which must scale into a single
   responsive vertical row on mobile smartphone breakpoints)... the
   introductory rate is positioned in the left container so it displays first
   to the user." Source order puts it first, so both agree at every width. */
.grid--2 { grid-template-columns: 1fr; }
@media (min-width: 700px) { .grid--2 { grid-template-columns: 1fr 1fr; } }

/* .grid--3 was the homepage's three-card menu preview, removed 2 Oct 2026. */

/* A package card, on the menu (1 Oct 2026): label, name,
   price, her three-sentence summary, and a link to the package's own page,
   which carries the long copy and the formulation. The 22 Sep render's
   two-up menu card with its price rail held all of that and is gone with it;
    The link is pinned to the foot so a
   row of cards lines its buttons up whatever each summary's length. */
.card--pkg h3 a { color: inherit; text-decoration: none; }
.card--pkg h3 a:hover { color: var(--brand-cyan-soft); }
.card__more { margin-top: auto; align-self: flex-start; }
/* The menu's eleven cards, two up at most (Jacob, 1 Oct 2026: "a 2 column
   grid max"). A summary card has no rail to make room for, so it needs no
   later break. */
.grid--pkgs { grid-template-columns: 1fr; }
@media (min-width: 700px) { .grid--pkgs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* The package page: her full description at a reading measure. */
.pkg-detail .formula-list { margin-top: 4px; }

.dose { text-align: center; gap: 6px; }
.dose__amt { font-size: 1.05rem; font-weight: 600; }
.dose__label { font-size: var(--f-small); color: var(--ink-dim); }

/* Phase 7: "please display these 5 booster options using a clean, symmetrical
   layout stack. Every option must look identical in typography and spacing." */
.booster { display: grid; gap: 8px; padding: 20px 0; border-bottom: 1px solid var(--line); }
.booster:last-of-type { border-bottom: 0; }
.booster__top { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: baseline; justify-content: space-between; }
.booster__name { font-size: 1.05rem; font-weight: 600; }
.booster__price { font-family: var(--font-display); font-weight: 500; font-size: 1.15rem; color: var(--brand-cyan-soft); }

/* ---------------------------------------------- the ingredient dictionary --
   Phase 3, and the one thing she singled out from her own Canva layout: tap an
   ingredient and read what it is. Each package lists its formulation as
   buttons, and the dialog carries every definition in that blend.
   <dialog> so the modal is the platform's: focus trap, Esc and inertness all
   come free and none of them are reimplemented here. */
.formula-list { display: flex; flex-wrap: wrap; gap: 8px; }
/* 21 Sep, Part 1: the listed vitamins and minerals in "our brand's signature
   Neon Pink so they stand out with high contrast against the new solid black
   background". #ff0069 on black is 5.5:1. */
.chip {
  background: rgba(255, 0, 105, 0.1); border: 1px solid rgba(255, 0, 105, 0.45);
  color: var(--brand-pink); border-radius: 999px;
  padding: 6px 13px; font-size: 0.8rem; cursor: pointer; min-height: 32px;
}
.chip:hover { border-color: var(--brand-pink); background: rgba(255, 0, 105, 0.2); }
.chip--static { cursor: default; color: var(--ink-dim); background: none; border-color: var(--line); }

/* Immunity Reinforcement's "Included Clinical Booster (Administered
   Separately)", listed apart from what is in the bag (21 Sep, Part 2). */
.booster-note { display: grid; gap: 8px; }
.booster-note__head { font-size: var(--f-small); font-weight: 600; color: var(--ink); }
/* A few of her formulation entries are a phrase rather than a word, e.g.
   "Enhanced-Dose Vitamin C, Glutathione, Zinc & B12". Wrapping one inside a
   pill reads as a broken button, so the generator tags it and it takes a row
   of its own with square corners. Tagged by length in build-pages.mjs, because
   CSS cannot measure text. */
.formula-list li.is-wide { flex-basis: 100%; }
.chip--wide { border-radius: 10px; text-align: left; display: block; }

dialog.sheet {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--ground-2); color: var(--ink);
  padding: 0; width: min(560px, calc(100vw - 32px)); max-height: 82vh;
}
dialog.sheet::backdrop { background: rgba(0, 0, 0, 0.8); }
.sheet__head { display: flex; align-items: flex-start; gap: 16px; padding: 22px 24px 14px; border-bottom: 1px solid var(--line); }
.sheet__head h2 { flex: 1; font-size: 1.25rem; }
.sheet__close { background: none; border: 1px solid var(--line); border-radius: 50%; width: 36px; height: 36px; cursor: pointer; flex: none; }
.sheet__close:hover { border-color: var(--brand-cyan); }
.sheet__body { padding: 4px 24px 24px; overflow-y: auto; }
.sheet__body dt { font-size: 0.78rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--brand-cyan-soft); margin-top: 22px; }
.sheet__body .cls { font-size: 0.66rem; letter-spacing: 0.14em; color: var(--ink-faint); text-transform: uppercase; margin-top: 2px; }
.sheet__body dd { font-size: 0.95rem; color: var(--ink-dim); margin-top: 6px; }

/* ------------------------------------------------- panels (22 Sep render) ---
   The About render sets the founder's story in one bordered box split by a
   vertical hairline, a short column against a long one. Measured at 887: the
   box spans the content column, its divider sits at x=338 of 76..810, so 36%,
   and both are 1.4425 from the site's own numbers. Below 880 the divider
   becomes a horizontal one, because a 36% column of prose is a ladder. */
.panel {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(22px, 2.4vw, 34px);
}
.panel--split { display: grid; gap: clamp(22px, 2.6vw, 34px); }
/* A grid's auto rows STRETCH when its column is shorter than its neighbour,
   which opened a 150px hole under "Our Story & Truth" (render pass, 22 Sep).
   Both columns pack from the top instead. */
.panel__side, .panel__main { align-content: start; }
.panel__figure img { border-radius: 10px; border: 1px solid var(--line); width: 100%; }
@media (min-width: 880px) {
  .panel--split { grid-template-columns: minmax(0, 0.56fr) minmax(0, 1fr); column-gap: clamp(28px, 3.4vw, 46px); }
  .panel__main { border-left: 1px solid var(--line); padding-left: clamp(28px, 3.4vw, 46px); }
}

/* Her contact lines as the render's details card, beside her own copy. The
   form the render draws on the left is not built: phase 11 bans it. */
.contact-grid { display: grid; gap: clamp(28px, 3.4vw, 48px); align-items: start; }
@media (min-width: 900px) {
  .contact-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr); }
}
.detail-card { display: grid; gap: 10px; align-content: start; }
.detail-card__name { font-size: 1.05rem; }
.detail-list { display: grid; gap: 14px; margin-top: 8px; }
.detail-list li { display: flex; align-items: center; gap: 12px; font-size: 1.05rem; }
.detail-list a { color: var(--brand-cyan-soft); }
/* The ring the render draws around each icon. */
.detail-list svg {
  width: 38px; height: 38px; flex: none; padding: 10px; border-radius: 50%;
  border: 1px solid var(--line); fill: var(--brand-cyan-soft); box-sizing: border-box;
}

/* A centred stack, for the lit closing bands. */
.stack--center { justify-items: center; text-align: center; }
.stack--center .lede, .stack--center .tcpa { margin-inline: auto; }

/* ------------------------------------------------------------------ about --- */
/* .split and .split--about drew the movement section and its Pogo Ball
   portrait, removed whole on 2 Oct 2026. */
/* blockquote.callout was her About callout, set as a pink-ruled pull quote. The
   22 Sep render opens the page on a hero instead, where the same sentence is
   the lede, so the rule had nothing left to draw (check:css, same commit). */

/* Phase 10's Journey Timeline slider (.rail) was here. The section came out
   on the 1 Oct 2026 call, so the rules went with it. */

/* --------------------------------------------------------------- contact ---
   .contact-meta held her provider name, email and phone as a plain stack. The
   22 Sep render sets them in a bordered card with a ringed icon per row, which
   is .detail-card above, so the old rule went with it. */
.sysnotice {
  font-size: var(--f-eyebrow); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint); border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 16px; display: inline-block; line-height: 1.5;
}

/* ---------------------------------------------------------------- footer ---
   Phase 1 sets the type here, not taste: "a small, clean sans-serif font (10px
   or 11px font size) using a subtle, low-contrast gray color that blends
   smoothly into our dark background". Quiet by instruction, and on every page
   by instruction. */
.site-footer { background: var(--ground-2); border-top: 1px solid var(--line); padding-block: 54px 40px; }
/* Phase 8: "The Global Footer Baseline: Position it cleanly directly above our
   professional regulatory compliance disclaimers block." */
.site-footer__logo { width: min(160px, 40vw); }
/* At 160px the hero's tracking breaks "Integrative Wellness" onto two lines;
   the footer's lockup sets it smaller and tighter so it holds one. */
.site-footer__logo .logo-lockup__sub { font-size: 0.6rem; letter-spacing: 0.2em; padding-left: 0.2em; white-space: nowrap; }
.legal { margin-top: 32px; font-size: var(--f-legal); line-height: 1.8; color: var(--ink-faint); }
.legal h2 { font-family: var(--font); font-size: var(--f-legal); font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-dim); line-height: 1.8; }
.legal p { margin-top: 10px; }
.legal b { color: var(--ink-dim); font-weight: 600; }
/* Centred under the disclaimers in the 22 Sep render, with the logo above
   them, which is where phase 8 already put it. */
.legal-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 22px; margin-top: 22px; font-size: var(--f-legal); }
.legal-links a { color: var(--ink-dim); }
.legal-links a:hover { color: var(--brand-cyan-soft); }

/* Phase 9: "Position our social media icon row directly beneath our legal
   compliance disclaimers and privacy link rows." */
.social { display: flex; gap: 14px; justify-content: center; margin-top: 30px; }
.social a { display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%; border: 1px solid var(--line); color: var(--ink-dim); }
.social a:hover { border-color: var(--brand-cyan); color: var(--brand-cyan-soft); }
.social svg { width: 18px; height: 18px; fill: currentColor; }
.colophon { margin-top: 26px; text-align: center; font-size: var(--f-legal); color: var(--ink-faint); }
/* The LocalForge credit, About only (scripts/build-pages.mjs). */
.colophon .credit { white-space: nowrap; }
.colophon .credit a { color: inherit; text-decoration: none; }
/* Where the line has no room left it would add one; it sits out instead,
   so the footer never grows (measured 10 Oct 2026). */
@media (max-width: 328px), (min-width: 470px) and (max-width: 596px) { .colophon .credit { display: none; } }

/* The three legal pages (/privacy, /hipaa, /terms). No mockup draws them, so
   they take the site's own tokens: body size and colour, the h3 scale for
   section heads, the hairline above each. */
.policy h1 { margin-bottom: 14px; }
.policy__meta { color: var(--ink-dim); font-size: var(--f-small); }
.policy__banner { font-weight: 600; letter-spacing: 0.02em; border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px; background: var(--card); }
.policy h2 { font-family: var(--font); font-size: var(--f-h3); font-weight: 600; line-height: 1.3; letter-spacing: 0.01em; margin-top: 38px; padding-top: 24px; border-top: 1px solid var(--line); }
.policy p, .policy ul { margin-top: 14px; color: var(--ink-dim); line-height: 1.7; }
.policy ul { list-style: disc; padding-left: 1.3em; display: grid; gap: 10px; }
.policy li::marker { color: var(--brand-pink); }
.policy b { color: var(--ink); font-weight: 600; }

.skip-link {
  position: absolute; left: -9999px; top: 8px;
  background: var(--brand-cyan); color: #03161b; padding: 10px 18px; border-radius: 8px; z-index: 100;
}
.skip-link:focus { left: 16px; }
