/* ============================================================================
   SOLASE :: SITE STYLESHEET
   ----------------------------------------------------------------------------
   Layout, utilities, and components. Every value here references a token from
   brand.css. If you find yourself typing a hex value or a px font-size in this
   file, add a token instead.

   Load order matters:  normalize.css  ->  brand.css  ->  site.css

   THE SURFACE MODEL
     Solase has three surfaces, not a light/dark pair. Every section picks one:
       .section-warm    the coral gradient field, white type
       .section-light   white, ink type   (the default)
       .section-ink     #200105, white type
     Buttons, cards, borders, and muted text all adapt to the surface they sit
     on, so a section can be reskinned by changing one class.

   Contents
     1. Reset and base
     2. Layout: container, surfaces, page wrapper
     3. Typography
     4. Buttons
     5. Navigation
     6. Hero
     7. Cards
     8. Accordion
     9. Footer
    10. Forms
    11. Misc UI
    12. Responsive
   ============================================================================ */


/* ==========================================================================
   1. RESET AND BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: var(--nav-height);
}

body {
  /* See the note in brand.css: pins Acumin's slant and width axes so no engine
     is free to pick its own. Inherited, so it covers every element. */
  font-variation-settings: "slnt" 0, "wdth" 100;
  font-family: var(--font--body);
  font-size: var(--type--body);
  font-weight: var(--weight--light);
  line-height: var(--leading--body);
  color: var(--text-color--text-primary);
  background: var(--background-color--background-primary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, video { max-width: 100%; display: block; }
ul, ol { list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

a {
  color: var(--link-color--link-primary);
  text-decoration: none;
  transition: color var(--transition);
}
a:hover { color: var(--link-color--link-hover); }

/* Inline prose links get the underline; structural links (nav, buttons,
   cards) opt out via .link-plain or their own component class. */
.prose a { text-decoration: underline; text-underline-offset: 2px; }

:focus-visible {
  outline: 2px solid var(--border-color--border-accent);
  outline-offset: 3px;
  border-radius: var(--radius-control);
}
/* The nav is outside <main>, so it misses the surface selectors below and
   would fall back to the ember ring, which is invisible on the coral field it
   floats over. It only ever sits on warm or ink, so it belongs in this list. */
.navbar       :focus-visible,
.section-warm :focus-visible,
.section-ink  :focus-visible { outline-color: var(--base-color-neutral--000); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; top: var(--space-xs); left: var(--space-xs);
  z-index: var(--z-modal);
  padding: var(--space-xs) var(--space-sm);
  background: var(--base-color-neutral--000);
  color: var(--base-color-brand--ink);
  border-radius: var(--radius-pill);
  transform: translateY(-200%);
  transition: transform var(--transition-fast);
}
.skip-link:focus { transform: translateY(0); }


/* ==========================================================================
   2. LAYOUT AND SURFACES
   ========================================================================== */

/* overflow-x: clip, NOT hidden. `hidden` on one axis forces the other axis to
   `auto`, which turns this element into a nested scroll container: the page
   scroll gets trapped and any position:sticky descendant stops working.
   `clip` contains the overflow without creating a scroll box. */
.page-wrapper { overflow-x: clip; }

.container {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--container-pad-x);
}
.container.is-narrow { max-width: 42rem; }
.container.is-wide   { max-width: var(--max-width-wide); }

/* --- The three surfaces --------------------------------------------------
   .section-warm is the signature field. It carries its own gradient, so it
   does not need a wrapper or an overlay element. The marketing gradient
   resolves to warm white at its final stop, which lets a white section sit
   directly beneath it with no visible seam. */
.section-warm {
  position: relative;
  background-image: var(--gradient--field-marketing);
  color: var(--text-color--text-on-warm);
}
/* Tall-section variant. Short warm bands keep the flat ramp, because spreading
   it over ~400px would land their white headings on the pale end. */
.section-warm.is-hero {
  background-image: var(--gradient--field-hero);
}
/* Full-viewport variant for auth screens, which run the whole spectrum. */
.section-warm.is-auth {
  background-image: var(--gradient--field-auth);
  min-height: 100vh;
  display: flex;
  align-items: center;
}

.section-light {
  background: var(--background-color--background-primary);
  color: var(--text-color--text-primary);
}
.section-sunken {
  background: var(--background-color--background-sunken);
  color: var(--text-color--text-primary);
}
.section-ink {
  background: var(--background-color--background-ink);
  color: var(--text-color--text-on-warm);
}

.section-pad { padding: var(--section-pad-y) 0; }
.section-pad.is-first-after-hero { padding-top: 60px; }

/* Grid */
.grid { display: grid; gap: var(--space-md); }
.grid.is-2 { grid-template-columns: repeat(2, 1fr); }
.grid.is-3 { grid-template-columns: repeat(3, 1fr); }
.grid.is-4 { grid-template-columns: repeat(4, 1fr); }


/* ==========================================================================
   3. TYPOGRAPHY

   The display treatment is weight 200 + tight leading + negative tracking.
   That combination IS the brand. Do not set a heading at a heavier weight or
   at default tracking.
   ========================================================================== */

h1, h2, h3, h4 {
  font-family: var(--font--display);
  font-weight: var(--weight--display);
  line-height: var(--leading--display);
  letter-spacing: var(--tracking--display);
}

h1 { font-size: var(--type--h1); }
h2 { font-size: var(--type--h2); }

/* h3 is a label, not a display size: it flips to semibold and normal metrics. */
h3 {
  font-size: var(--type--h3);
  font-weight: var(--weight--semibold);
  line-height: var(--leading--head);
  letter-spacing: normal;
}

.section-heading {
  text-wrap: balance;
  font-family: var(--font--display);
  font-weight: var(--weight--display);
  font-size: var(--type--h2);
  line-height: var(--leading--display);
  letter-spacing: var(--tracking--display);
  margin-bottom: var(--space-sm);
}
.section-subhead {
  font-size: var(--type--lead);
  font-weight: var(--weight--light);
  line-height: var(--leading--body);
  max-width: 38rem;
  margin-bottom: var(--space-xl);
  color: var(--text-color--text-secondary);
}

/* Eyebrow: small, uppercase, tracked out. */
.eyebrow {
  font-size: var(--type--xs);
  font-weight: var(--weight--semibold);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--base-color-neutral--500);
  margin-bottom: 22px;
}

/* Index numerals ("01", "02") are monospace and quiet by design. */
.index-num {
  font-family: var(--font--mono);
  font-size: var(--type--xs);
  font-weight: var(--weight--normal);
  color: var(--text-color--text-index);
  margin-bottom: var(--space-xs);
}

/* The wordmark is letterspaced display type, not an image. */
.wordmark {
  font-family: var(--font--display);
  font-weight: var(--weight--display);
  letter-spacing: var(--tracking--wordmark);
  text-transform: uppercase;
  line-height: 1;
}

/* The pronunciation line under the wordmark. */
.pronunciation {
  font-size: var(--type--small);
  font-weight: var(--weight--light);
  color: var(--text-color--text-on-warm-secondary);
}

.text-size-large  { font-size: var(--type--lead); line-height: var(--leading--body); }
.text-size-medium { font-size: var(--type--body); }
.text-size-small  { font-size: var(--type--small); }
.text-size-xs     { font-size: var(--type--xs); }

.text-weight-light    { font-weight: var(--weight--light); }
.text-weight-normal   { font-weight: var(--weight--normal); }
.text-weight-medium   { font-weight: var(--weight--medium); }
.text-weight-semibold { font-weight: var(--weight--semibold); }

.text-style-muted  { color: var(--text-color--text-secondary); }
.text-style-accent { color: var(--text-color--text-accent); }

/* Muted text on a warm or ink surface reads as translucent white, not grey. */
.section-warm .text-style-muted,
.section-warm .section-subhead,
.section-warm .eyebrow,
.section-ink  .text-style-muted,
.section-ink  .section-subhead,
.section-ink  .eyebrow { color: var(--text-color--text-on-warm-secondary); }

.section-warm .index-num,
.section-ink  .index-num { color: var(--text-color--text-on-warm-secondary); }

/* Links invert on warm and ink surfaces. */
.section-warm a, .section-ink a { color: var(--base-color-neutral--000); }
.section-warm a:hover, .section-ink a:hover { color: var(--base-color-brand--peach); }

.prose p + p { margin-top: var(--space-sm); }
.prose ul { margin: var(--space-sm) 0; }
.prose ul li {
  position: relative;
  padding-left: var(--space-md);
  margin-bottom: var(--space-xs);
}
.prose ul li::before {
  content: '';
  position: absolute;
  left: 0; top: 0.6em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--text-color--text-accent);
}


/* ==========================================================================
   4. BUTTONS

   Pill shape, 56px tall, semibold. The primary button is surface-aware:
   coral on a light surface, white on a warm or ink one.
   ========================================================================== */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  height: var(--control-height);
  padding: 0 var(--space-lg);
  font-family: var(--font--body);
  font-size: var(--type--body);
  font-weight: var(--weight--semibold);
  line-height: 1;
  white-space: nowrap;
  border: 1px solid var(--border-color--border-transparent);
  border-radius: var(--radius-pill);
  background: var(--button-color--primary-fill);
  color: var(--button-color--primary-text);
  transition: background-color var(--transition), border-color var(--transition),
              color var(--transition), transform var(--transition);
  cursor: pointer;
}
.button:hover { background: var(--button-color--primary-fill-hover); color: var(--button-color--primary-text); }

/* On warm and ink surfaces the primary button inverts to white on ink. */
.section-warm .button,
.section-ink  .button {
  background: var(--button-color--on-warm-fill);
  color: var(--button-color--on-warm-text);
}
.section-warm .button:hover,
.section-ink  .button:hover {
  background: var(--base-color-brand--blush);
  color: var(--button-color--on-warm-text);
}

/* Variants keep their own fill on every surface. Without this the
   .section-warm rule above would repaint them. */
.section-warm .button.is-gradient,
.section-ink  .button.is-gradient {
  background: var(--gradient--send);
  color: var(--base-color-neutral--000);
}
.section-warm .button.is-elevated,
.section-ink  .button.is-elevated {
  background: var(--base-color-neutral--000);
  color: var(--base-color-brand--ink);
}

/* Ghost: transparent with a hairline. The secondary action on any surface. */
.button.is-ghost {
  background: var(--base-color-neutral--transparent);
  color: var(--text-color--text-primary);
  border-color: var(--border-color--border-hairline);
}
.button.is-ghost:hover {
  background: var(--base-color-neutral--transparent);
  border-color: var(--text-color--text-primary);
}
.section-warm .button.is-ghost,
.section-ink  .button.is-ghost {
  color: var(--text-color--text-on-warm);
  border-color: var(--button-color--ghost-warm-border);
  background: var(--base-color-neutral--transparent);
}
.section-warm .button.is-ghost:hover,
.section-ink  .button.is-ghost:hover {
  background: var(--surface--glass-on-warm-strong);
  color: var(--text-color--text-on-warm);
}

/* Gradient: the primary CTA on the white reading surface. The design uses the
   send gradient here rather than a flat coral, so the button carries the same
   warm spectrum as the field above it. */
.button.is-gradient {
  background: var(--gradient--send);
  /* border-box, not the default padding-box. The button carries a 1px
     transparent border, so a gradient sized to the padding box gets clamped
     across that ring and draws a hard line along the top and bottom edges. */
  background-origin: border-box;
  color: var(--base-color-neutral--000);
  box-shadow: var(--shadow--warm);
  padding: 0 36px;
}
.button.is-gradient:hover {
  background: var(--gradient--send);
  color: var(--base-color-neutral--000);
  filter: brightness(1.06);
}

/* Elevated: white on the warm field, lifted off the gradient. */
.button.is-elevated {
  background: var(--base-color-neutral--000);
  color: var(--base-color-brand--ink);
  padding: 0 34px;
  box-shadow: 0 4px 24px rgb(0 0 0 / 0.12);
}
.button.is-elevated:hover {
  background: var(--base-color-brand--blush);
  color: var(--base-color-brand--ink);
}

/* Glass: the nav pill treatment, only legible on a warm or ink surface.
   The white wash is deliberate and is the look the brand wants. It does not
   meet the 4.5:1 body floor; see --surface--glass-on-warm-strong in brand.css
   for the measured figures and the decision. Do not "fix" it by darkening
   the fill, which is what it looked like on 2026-10-26 before it was put
   back. */
.button.is-glass {
  height: var(--control-height-sm);
  padding: 0 var(--space-md);
  font-size: var(--type--small);
  background: var(--surface--glass-on-warm-strong);
  color: var(--text-color--text-on-warm);
  box-shadow: inset 0 0 0 0.5px var(--surface--glass-on-warm-hairline);
  backdrop-filter: var(--blur--glass);
  -webkit-backdrop-filter: var(--blur--glass);
}
.button.is-glass:hover {
  background: var(--surface--glass-on-warm-hover);
  color: var(--text-color--text-on-warm);
}

/* Frost: the glass pill's light twin, for warm and ink surfaces only.
   .is-glass tints the field UP with a little white and keeps a white label,
   which only works where the field is still saturated. Frost fills with
   enough white to carry an INK label instead, which is what the pale end of
   a warm ramp needs. Over the coral it resolves to about #f7d4cf, within a
   hair of --base-color-brand--blush, so it reads as the app canvas rather
   than as a colour invented for the marketing site. Translucent on purpose:
   it picks up the gradient underneath instead of sitting on it as a flat
   patch. Defined after the .section-warm .button rule, which is what lets it
   keep its own fill there, the same way .is-glass does. */
.button.is-frost {
  background: var(--surface--glass-light);
  color: var(--text-color--text-primary);
  box-shadow: inset 0 0 0 0.5px var(--surface--glass-on-warm-hairline);
  backdrop-filter: var(--blur--glass);
  -webkit-backdrop-filter: var(--blur--glass);
}
.button.is-frost:hover {
  background: var(--surface--glass-light-strong);
  color: var(--text-color--text-primary);
}

/* Link style: no chrome. */
.button.is-link {
  height: auto; padding: 0;
  background: none; border: 0;
  color: var(--link-color--link-primary);
}
.button.is-link:hover { background: none; color: var(--link-color--link-hover); }

.button.is-small { height: var(--control-height-sm); padding: 0 var(--space-md); font-size: var(--type--small); }
.button.is-full  { width: 100%; }

.button-group { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.button-group.is-right  { justify-content: flex-end; }
.button-group.is-center { justify-content: center; }
/* Even: every button takes the width of the widest label, so a pair of
   buttons reads as one object. inline-grid shrink-wraps to the content, and
   1fr columns in an intrinsically sized grid all resolve to the widest
   track, which is the same result as a hardcoded min-width without having to
   pick the number or revisit it when a label changes. */
.button-group.is-even {
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}


/* ==========================================================================
   5. NAVIGATION

   The nav floats transparent over the hero field and only picks up a surface
   once the page scrolls.
   ========================================================================== */

.navbar {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: var(--z-nav);
  /* A scrim that fades out, not a bar with an edge. Against an unbroken coral
     field the invite prompt disappeared; darkening the top few pixels gives
     the white type something to sit against without drawing a band across the
     page. Taller than the nav so the fade completes past the content. */
  background: var(--scrim--nav);
  transition: background var(--transition), backdrop-filter var(--transition);
}
.navbar.is-fixed { position: fixed; }
.navbar.is-scrolled {
  position: fixed;
  background: var(--surface--nav-pinned);
  backdrop-filter: var(--blur--glass);
  -webkit-backdrop-filter: var(--blur--glass);
}

.navbar { padding-bottom: 28px; }
.navbar.is-scrolled { padding-bottom: 0; }

.navbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  height: var(--nav-height);
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--container-pad-x);
}

.navbar-brand { display: flex; align-items: center; gap: var(--space-xs); }
.navbar-brand img, .navbar-brand svg { height: 40px; width: 40px; }

.navbar-menu { display: flex; align-items: center; gap: var(--space-md); }
.navbar-link {
  font-size: var(--type--small);
  font-weight: var(--weight--semibold);
}
/* The mark ships in brand colour; the nav needs it white. */
.navbar-mark { filter: brightness(0) invert(1); }

.navbar-toggle { display: none; width: 24px; height: 18px; position: relative; }
.navbar-toggle span {
  position: absolute; left: 0;
  width: 100%; height: 2px;
  background: currentColor;
  transition: transform var(--transition), opacity var(--transition);
}
.navbar-toggle span:nth-child(1) { top: 0; }
.navbar-toggle span:nth-child(2) { top: 8px; }
.navbar-toggle span:nth-child(3) { top: 16px; }
.navbar-toggle.is-open span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.navbar-toggle.is-open span:nth-child(2) { opacity: 0; }
.navbar-toggle.is-open span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }


/* ==========================================================================
   6. HERO
   ========================================================================== */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  padding: var(--hero-pad-top) 0 var(--hero-pad-bottom);
  overflow: hidden;
}
.hero.is-full { min-height: 100vh; }
.hero.is-compact { min-height: auto; padding: 100px 0 60px; }

/* Centred hero, which is what the Solase homepage and auth screens use. */
.hero.is-centered { text-align: center; }
.hero.is-centered .hero-lead,
.hero.is-centered .hero-body { margin-left: auto; margin-right: auto; }
.hero.is-centered .hero-ctas { justify-content: center; }

.hero-grid {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xl);
  width: 100%;
}
.hero-text-col { flex: 1 1 auto; }
.hero-aside-col { flex: 0 0 auto; }

.hero h1 { max-width: 50rem; margin-bottom: var(--space-md); }
.hero.is-centered h1 { margin-left: auto; margin-right: auto; }
.hero.is-compact h1 { font-size: var(--type--h1-short); }

.hero-lead {
  font-size: var(--type--lead);
  font-weight: var(--weight--light);
  max-width: 38rem;
  margin-bottom: var(--space-sm);
}
.hero-body {
  font-size: var(--type--body);
  font-weight: var(--weight--light);
  line-height: var(--leading--loose);
  max-width: 34rem;
  color: var(--text-color--text-on-warm-secondary);
  margin-bottom: var(--space-lg);
}
.hero-ctas { display: flex; flex-wrap: wrap; gap: var(--space-sm); }

/* Brand lockup: mark, wordmark, pronunciation line. */
.hero-lockup { display: flex; flex-direction: column; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-xl); }
.hero-lockup .wordmark { font-size: clamp(2rem, 4vw, 2.75rem); }


/* ==========================================================================
   7. CARDS
   ========================================================================== */

.card {
  background: var(--surface--card-on-light);
  border: 1px solid var(--border-color--border-subtle);
  border-radius: var(--radius-panel);
  padding: var(--space-lg) var(--space-md);
  transition: border-color var(--transition), transform var(--transition);
}
.card.is-interactive:hover {
  border-color: var(--border-color--border-accent);
  transform: translateY(-2px);
}
.card-icon { width: 40px; height: 40px; margin-bottom: var(--space-sm); }
.card-title {
  font-size: var(--type--h3);
  font-weight: var(--weight--semibold);
  line-height: var(--leading--head);
  margin-bottom: var(--space-xs);
}
.card-body { font-size: var(--type--small); color: var(--text-color--text-secondary); }

/* On a warm or ink surface the card becomes glass. */
.section-warm .card,
.section-ink  .card {
  background: var(--surface--glass-on-warm);
  border-color: var(--border-color--border-on-warm);
  backdrop-filter: var(--blur--glass);
}
.section-warm .card-body,
.section-ink  .card-body { color: var(--text-color--text-on-warm-secondary); }

/* Plain feature block, no card chrome. Used for the numbered feature rows. */
.feature { }
.feature-title {
  font-size: var(--type--h3);
  font-weight: var(--weight--semibold);
  margin-bottom: var(--space-xs);
}
.feature-body { font-size: var(--type--small); color: var(--text-color--text-secondary); }
.section-warm .feature-body,
.section-ink  .feature-body { color: var(--text-color--text-on-warm-secondary); }

/* The product demo surface: a large glass panel floating on the warm field.
   Currently unused. Reserved for the live demo slated for the homepage hero;
   the placeholder that sat here was removed so the signup page does not ship
   with an empty box. */
.showcase {
  background: var(--surface--glass-on-warm);
  border: 1px solid var(--border-color--border-on-warm);
  border-radius: var(--radius-app);
  backdrop-filter: var(--blur--glass);
  box-shadow: var(--shadow--window);
  overflow: hidden;
}


/* ==========================================================================
   8. ACCORDION
   ========================================================================== */

.accordion { border-top: 1px solid var(--border-color--border-subtle); }
.accordion-item { border-bottom: 1px solid var(--border-color--border-subtle); }
.section-warm .accordion,
.section-warm .accordion-item,
.section-ink  .accordion,
.section-ink  .accordion-item { border-color: var(--border-color--border-on-warm); }

.accordion-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  width: 100%;
  padding: var(--space-md) 0;
  text-align: left;
  font-size: var(--type--body);
  font-weight: var(--weight--semibold);
}
.accordion-icon {
  flex-shrink: 0;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--text-color--text-accent);
  transition: transform var(--transition);
}
.section-warm .accordion-icon,
.section-ink  .accordion-icon { color: var(--text-color--text-on-warm); }
.accordion-item.is-open .accordion-icon { transform: rotate(45deg); }

.accordion-body {
  max-height: 0;
  overflow: hidden;
  transition: max-height var(--transition);
}
.accordion-body-inner {
  padding-bottom: var(--space-md);
  font-size: var(--type--small);
  color: var(--text-color--text-secondary);
}
.section-warm .accordion-body-inner,
.section-ink  .accordion-body-inner { color: var(--text-color--text-on-warm-secondary); }


/* ==========================================================================
   9. FOOTER
   ========================================================================== */

.footer {
  padding: var(--space-3xl) 0 var(--space-xl);
  background: var(--background-color--background-ink);
  color: var(--text-color--text-on-warm);
}
.footer-top {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-2xl);
  margin-bottom: var(--space-2xl);
}
.footer-statement {
  font-family: var(--font--body);
  font-size: var(--type--body);
  font-weight: var(--weight--light);
  line-height: var(--leading--loose);
  max-width: 30rem;
  color: var(--text-color--text-on-warm-secondary);
}
.footer-links { display: flex; flex-wrap: wrap; gap: var(--space-md); align-items: center; }
.footer-link {
  font-size: var(--type--body);
  font-weight: var(--weight--light);
  color: var(--text-color--text-on-warm-secondary);
}
.footer-link:hover { color: var(--base-color-neutral--000); }

.footer-bottom {
  padding-top: var(--space-md);
  border-top: 1px solid var(--border-color--border-on-warm);
  font-size: var(--type--small);
  color: var(--text-color--text-on-warm-secondary);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  justify-content: space-between;
}


/* ==========================================================================
   10. FORMS

   Two treatments. On a light surface the field is a hairline box; on the warm
   field it is glass. Auth screens use the warm variant.
   ========================================================================== */

.form-field { margin-bottom: var(--space-sm); text-align: left; }
.form-label {
  display: block;
  font-size: var(--type--small);
  font-weight: var(--weight--semibold);
  letter-spacing: var(--tracking--label);
  margin-bottom: var(--space-2xs);
}
.form-input, .form-select, .form-textarea {
  width: 100%;
  height: var(--control-height);
  padding: 0 var(--space-sm);
  font-family: var(--font--body);
  font-size: var(--type--body);
  font-weight: var(--weight--light);
  color: var(--text-color--text-primary);
  background: var(--base-color-neutral--000);
  border: 1px solid var(--border-color--border-hairline);
  border-radius: var(--radius-panel);
  transition: border-color var(--transition);
}
.form-textarea { height: auto; min-height: 8rem; padding: var(--space-sm); resize: vertical; }
.form-input:focus, .form-select:focus, .form-textarea:focus {
  border-color: var(--border-color--border-accent);
  outline: none;
}
.form-input::placeholder, .form-textarea::placeholder { color: var(--text-color--text-muted); }

/* Glass fields for the warm field, per the auth screens. */
.section-warm .form-input,
.section-warm .form-select,
.section-warm .form-textarea {
  background: var(--surface--glass-on-warm-strong);
  border-color: var(--border-color--border-transparent);
  box-shadow: inset 0 0 0 0.5px var(--surface--glass-on-warm-hairline);
  color: var(--text-color--text-on-warm);
  backdrop-filter: var(--blur--glass);
}
.section-warm .form-input::placeholder,
.section-warm .form-textarea::placeholder {
  color: var(--text-color--placeholder-on-warm);
}
.section-warm .form-input:focus,
.section-warm .form-textarea:focus {
  border-color: var(--base-color-neutral--000);
  box-shadow: inset 0 0 0 1px var(--base-color-neutral--000);
}

.form-error {
  display: none;
  margin-top: var(--space-2xs);
  font-size: var(--type--xs);
  color: var(--base-color-status--destructive);
}
.form-field.has-error .form-input { border-color: var(--base-color-status--destructive); }
.form-field.has-error .form-error { display: block; }
.form-note { font-size: var(--type--xs); color: var(--text-color--text-secondary); }
.section-warm .form-note { color: var(--text-color--text-on-warm-secondary); }

/* Auth card: the centred column the sign-in and create-account screens use. */
.auth-card { width: 100%; max-width: 24rem; margin: 0 auto; text-align: center; }
.auth-card .form-field { margin-bottom: var(--space-sm); }
.auth-links { margin-top: var(--space-lg); display: flex; flex-direction: column; gap: var(--space-xs); }
.auth-links a { font-weight: var(--weight--semibold); font-size: var(--type--small); }


/* ==========================================================================
   11. MISC UI
   ========================================================================== */

.divider {
  height: 1px;
  background: var(--border-color--border-subtle);
  margin: var(--space-xl) 0;
}
.section-warm .divider, .section-ink .divider { background: var(--border-color--border-on-warm); }

.sticky-cta {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: var(--z-sticky);
  padding: var(--space-xs) var(--space-sm);
  background: var(--surface--scrim-ink);
  backdrop-filter: var(--blur--glass);
  transform: translateY(100%);
  transition: transform var(--transition);
}
.sticky-cta.is-visible { transform: translateY(0); }

/* Tag / pill label, used on the warm field. */
.tag {
  display: inline-flex;
  align-items: center;
  height: 34px;
  padding: 0 var(--space-sm);
  border-radius: var(--radius-pill);
  background: var(--surface--glass-on-warm-strong);
  box-shadow: inset 0 0 0 0.5px var(--surface--glass-on-warm-hairline);
  backdrop-filter: blur(12px);
  font-size: var(--type--small);
  font-weight: var(--weight--semibold);
}


/* ==========================================================================
   MODAL

   Built on the native <dialog>. showModal() gives focus trapping, Escape to
   close, inertness of the page behind, and focus restore to the invoking
   button, all of which a hand-rolled modal has to reimplement and usually
   gets subtly wrong.

   The dialog element IS the scrim: it fills the viewport, paints the scrim
   itself, and centres the card. ::backdrop is left transparent, because
   custom properties do not reliably inherit into ::backdrop across browsers
   and this site has no literal colours to fall back on.
   ========================================================================== */

.modal {
  display: none;
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: var(--space-md);
  border: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface--scrim-ink);
  backdrop-filter: blur(6px);
  color: var(--text-color--text-primary);
}
.modal[open] { display: grid; place-items: center; }
.modal::backdrop { background: transparent; }

.modal-card {
  position: relative;
  width: 100%;
  max-width: 34rem;
  padding: var(--space-xl);
  background: var(--background-color--background-primary);
  border-radius: var(--radius-app);
  box-shadow: var(--shadow--window);
}

.modal-close {
  position: absolute;
  top: var(--space-md);
  right: var(--space-md);
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill);
  color: var(--text-color--text-secondary);
  transition: background-color var(--transition), color var(--transition);
}
.modal-close:hover {
  background: var(--background-color--background-sunken);
  color: var(--text-color--text-primary);
}
.modal-close svg { width: 20px; height: 20px; }

.modal-title {
  font-size: var(--type--h2);
  margin-bottom: var(--space-xs);
  padding-right: var(--space-xl);
}
.modal-intro { margin-bottom: var(--space-lg); }


/* ==========================================================================
   SIGNUP FORM
   Lives in the modal. Two columns, with the email field spanning both.
   ========================================================================== */

.signup-fields {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-sm);
}
.signup-fields .is-wide { grid-column: 1 / -1; }
.signup .button-group { margin-top: var(--space-md); }
.signup-note { margin-top: var(--space-sm); }
.signup-status {
  margin-top: var(--space-sm);
  font-size: var(--type--small);
  min-height: 1.4em;
}
.signup-status.is-error   { color: var(--base-color-status--destructive); }
/* Brand, not the stock semantic green. The success message only ever appears
   on a collapsed card with nothing else in it, and the error only ever appears
   with the fields still visible, so the two states cannot be confused despite
   both being warm. */
.signup-status.is-success {
  color: var(--text-color--text-accent);
  font-size: var(--type--body);
}

/* Success block. The headline is display type at heading size, which is how
   this brand does emphasis: weight 200 large, not a heavier weight small. */
.signup-success { display: none; }
.signup.is-done .signup-success { display: block; }
.signup-success-title {
  margin: 0 0 var(--space-xs);
  font-family: var(--font--display);
  font-weight: var(--weight--display);
  font-size: var(--type--h2);
  line-height: var(--leading--display);
  letter-spacing: var(--tracking--display);
  color: var(--base-color-brand--ink);
}
.signup-success-body {
  margin: 0;
  font-family: var(--font--reading);
  font-size: var(--type--lead);
  line-height: var(--leading--body);
  color: var(--text-color--text-secondary);
}

/* On success the card collapses to the confirmation alone: fields, submit,
   the privacy note, and the card's own heading and intro all go. */
.signup.is-done .signup-fields,
.signup.is-done .button-group,
.signup.is-done .signup-note { display: none; }
.modal-card.is-done .modal-title,
.modal-card.is-done .modal-intro { display: none; }
.modal-card.is-done { padding-top: var(--space-2xl); }
.signup.is-done .signup-status { display: none; }

@media (max-width: 768px) {
  .signup-fields { grid-template-columns: 1fr; }
  .modal { padding: 0; }
  .modal-card {
    max-width: 100%;
    min-height: 100dvh;
    border-radius: 0;
    padding: var(--space-2xl) var(--space-md) var(--space-xl);
  }
}


/* ==========================================================================
   HOMEPAGE BANDS
   Measurements taken from the Claude Design build so the two do not drift.
   ========================================================================== */

/* The stacked lockup is supplied master artwork. It is sized by the MARK's
   width, and the master is 254x276 with a 182px mark, so the image is drawn
   at mark-width x --lockup-ratio. Never re-set the wordmark as type. */
.lockup { height: auto; display: block; }

/* --- Hero ---------------------------------------------------------------- */
/* Symmetric, because every page using .hero now centres its content in a
   full-viewport panel. The old 104px/160px was asymmetric for two reasons that
   have both gone: the top cleared a fixed navbar, and the bottom gave the
   marketing ramp empty field to fade to white in before a white section. */
.hero {
  display: block;
  padding: var(--space-xl) 0;
  min-height: 0;
}
/* width:100% matters: .section-warm.is-auth makes the section a flex row, so
   without it this shrinks to its content and sits against the left edge. */
.hero-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xl);
  width: 100%;
  padding: 0 var(--container-pad-x);
  text-align: center;
}
.hero-lockup { display: flex; flex-direction: column; align-items: center; gap: var(--space-sm); margin: 0; }
/* The wordmark is the h1 on the splash. .hero h1's display size and leading
   would otherwise reserve a line box around an image that is already
   display:block, pushing the pronunciation away from the lockup. */
.lockup-heading { margin: 0; font-size: 0; line-height: 0; }

.hero h1 {
  margin: 0;
  max-width: 62rem;
  font-size: clamp(2.5rem, 4.5vw, 4.0625rem);
  line-height: 1.08;
  color: var(--text-color--text-on-warm);
  text-wrap: pretty;
}

/* Ink, not white. At 14px and 18px on the saturated top of the ramp, only ink
   clears 4.5:1. Ink on warm is the documented pairing. */
.pronunciation {
  margin: 0;
  font-family: var(--font--body);
  font-weight: var(--weight--normal);
  font-size: var(--type--small);
  letter-spacing: 0.01em;
  color: var(--base-color-brand--ink);
}
.pronunciation em {
  font-style: normal;
  font-variation-settings: "slnt" 12, "wdth" 100;
}

.hero-body {
  margin: 0;
  max-width: 40rem;
  font-family: var(--font--reading);
  font-size: 1.125rem;
  line-height: 1.55;
  color: var(--base-color-brand--ink);
}

/* --- Early access band --------------------------------------------------- */
.band-access { padding: 120px 0; }
.access-inner { max-width: 900px; margin: 0 auto; padding: 0 var(--container-pad-x); }
.access-head { text-align: center; }
.access-heading {
  margin: 0 0 18px;
  text-wrap: balance;
  font-size: clamp(2rem, 3.6vw, 2.875rem);
  line-height: 1.12;
  color: var(--base-color-brand--ink);
}
.access-sub {
  margin: 0 auto 44px;
  max-width: 620px;
  font-family: var(--font--reading);
  font-size: 1.125rem;
  line-height: 1.6;
  color: var(--text-color--text-secondary);
}
.access-cta { display: flex; justify-content: center; margin-bottom: 56px; }

/* The rule separates the promise from the proof; the numbering is a real
   sequence, not decoration. */
.proof-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
  border-top: 1px solid var(--base-color-neutral--200);
  padding-top: 34px;
}
.proof { display: flex; flex-direction: column; gap: 10px; }
.proof-title {
  margin: 0;
  text-wrap: balance;
  font-family: var(--font--body);
  font-weight: var(--weight--semibold);
  font-size: 1.125rem;
  letter-spacing: normal;
  color: var(--base-color-brand--ink);
}
.proof-body {
  margin: 0;
  font-family: var(--font--reading);
  font-size: var(--type--body);
  line-height: 1.5;
  color: var(--text-color--text-secondary);
}

/* --- Closing band -------------------------------------------------------- */
.band-closing {
  padding: 130px var(--container-pad-x) 110px;
  display: flex; flex-direction: column; align-items: center;
  gap: 42px; text-align: center;
}
.closing-heading {
  margin: 0; max-width: 760px;
  text-wrap: balance;
  font-size: clamp(2rem, 3.9vw, 3.125rem);
  line-height: 1.1;
  color: var(--text-color--text-on-warm);
}

/* --- Footer -------------------------------------------------------------- */
.footer { padding: 58px 0 32px; }
.footer-inner { max-width: 1220px; margin: 0 auto; padding: 0 var(--container-pad-x); }
.footer-top {
  display: flex; flex-wrap: wrap;
  gap: 56px; align-items: flex-start; justify-content: space-between;
  padding-bottom: 40px;
  margin-bottom: 0;
}
.footer-brand { display: flex; flex-direction: column; gap: 18px; max-width: 460px; }
.footer-statement {
  margin: 0;
  font-family: var(--font--reading);
  font-size: 1.125rem;
  line-height: 1.6;
  color: rgb(var(--base-color-neutral--000-rgb) / 0.7);
  max-width: none;
}
.footer-links { display: flex; flex-direction: column; gap: 13px; }
.footer-bottom {
  border-top: 1px solid rgb(var(--base-color-neutral--000-rgb) / 0.12);
  padding-top: 24px;
}
.footer-copy { display: flex; align-items: center; gap: 11px; font-size: var(--type--small); color: rgb(var(--base-color-neutral--000-rgb) / 0.6); }
.footer-icon { border-radius: 5px; display: block; }
.footer-link.is-small { font-size: var(--type--small); }


/* ==========================================================================
   LEGAL DOCUMENTS
   Long-form policy pages: terms, privacy. Built for sustained reading, so the
   measure is tighter than the marketing bands and the rhythm comes from the
   type rather than from surfaces or cards.
   ========================================================================== */

.legal-hero { text-align: center; }
.legal-hero h1 { margin: 0 0 var(--space-xs); }
.legal-updated {
  font-family: var(--font--body);
  font-size: var(--type--small);
  color: var(--base-color-brand--ink);
}

.legal-body {
  max-width: 44rem;          /* ~72 characters at this size */
  margin: 0 auto;
  font-family: var(--font--reading);
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--text-color--text-primary);
}
.legal-body > p { margin-bottom: var(--space-md); }

/* Section headings carry their own numbers, so they are not list markers. */
.legal-body h2 {
  margin: var(--space-2xl) 0 var(--space-sm);
  font-size: 1.5rem;
  line-height: 1.25;
  letter-spacing: normal;
  font-weight: var(--weight--semibold);
  font-family: var(--font--body);
  color: var(--base-color-brand--ink);
}
.legal-body h2:first-child { margin-top: 0; }

/* Sub-headings. The privacy policy nests one level; terms does not. */
.legal-body h3 {
  margin: var(--space-lg) 0 var(--space-xs);
  font-family: var(--font--body);
  font-size: 1.125rem;
  font-weight: var(--weight--semibold);
  line-height: 1.35;
  letter-spacing: normal;
  color: var(--base-color-brand--ink);
}

.legal-body ul { margin: 0 0 var(--space-md); }
.legal-body ul li {
  position: relative;
  padding-left: var(--space-md);
  margin-bottom: var(--space-xs);
}
.legal-body ul li::before {
  content: '';
  position: absolute;
  left: 2px; top: 0.72em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--base-color-brand--coral);
}

.legal-body a { text-decoration: underline; text-underline-offset: 2px; }

/* Statutory blocks are conventionally set in capitals. Capitals are hard to
   read in bulk, so give them extra leading and a touch of tracking, and hold
   them at full contrast rather than muting legally operative text. */
.legal-caps {
  text-transform: uppercase;
  letter-spacing: 0.01em;
}
/* Size and leading only when the whole paragraph is capitals. Applied to an
   inline span mid-sentence, a size change would break the line rhythm. */
p.legal-caps {
  font-size: 0.9375rem;
  line-height: 1.8;
}

.legal-contact {
  margin-top: var(--space-lg);
  padding: var(--space-md) var(--space-lg);
  background: var(--background-color--background-sunken);
  border-radius: var(--radius-panel);
  font-size: var(--type--body);
  line-height: 1.6;
}
.legal-contact p { margin: 0; }

@media (max-width: 768px) {
  .legal-body { font-size: 1rem; }
  .legal-body h2 { margin-top: var(--space-xl); font-size: 1.3125rem; }
}


/* ==========================================================================
   COOKIE CONSENT BANNER

   Built by js/consent-manager.js and appended to the body, so it is not in
   any page's markup. Ported from artisan-www; the chrome is rebuilt from this
   site's own .button classes on an ink surface so it cannot drift from the
   rest of the site.
   ========================================================================== */

#consent-banner {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: var(--z-consent);
  padding: 1.25rem var(--space-md);
  background: var(--surface--scrim-ink-strong);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--border-color--border-on-warm);
  color: var(--text-color--text-on-warm);
  transform: translateY(100%);
  opacity: 0;
  transition: transform var(--duration-slow) var(--ease-out-soft),
              opacity var(--duration-slow) var(--ease-out-soft);
}
#consent-banner.is-visible { transform: translateY(0); opacity: 1; }

.consent-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
}
.consent-text {
  margin: 0;
  font-family: var(--font--reading);
  font-size: var(--type--small);
  line-height: 1.5;
  color: var(--text-color--text-on-warm-secondary);
}
/* The policy link has to read against the muted body text it sits in, so it
   goes full white and underlined rather than inheriting the muted colour. */
.consent-text a {
  color: var(--text-color--text-on-warm);
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}
.consent-text a:hover { color: var(--base-color-brand--peach); }

.consent-buttons { display: flex; gap: 0.75rem; flex-shrink: 0; }

@media (max-width: 768px) {
  .consent-inner { flex-direction: column; text-align: center; }
  .consent-buttons { width: 100%; justify-content: center; }
  .consent-buttons .button { flex: 1 1 auto; }
  /* The sticky CTA is hidden above 768px anyway; below it, keep the banner
     clear of it so one does not cover the other. */
  .sticky-cta { bottom: auto; }
}


/* ==========================================================================
   12. RESPONSIVE
   Breakpoints: tablet 991px, mobile 768px.
   ========================================================================== */

@media (max-width: 991px) {
  .navbar-menu { gap: var(--space-sm); }
  .hero-grid { flex-direction: column; align-items: flex-start; }
  .hero.is-centered .hero-grid { align-items: center; }
  .grid.is-3, .grid.is-4 { grid-template-columns: repeat(2, 1fr); }
  .footer-top { grid-template-columns: 1fr; gap: var(--space-xl); }
}

@media (max-width: 768px) {
  .section-pad { padding: var(--section-pad-y-mobile) 0; }
  .section-pad.is-first-after-hero { padding-top: var(--space-xl); }

  .hero { padding: var(--hero-pad-top-mobile) 0 var(--hero-pad-bottom-mobile); }
  /* svh, not vh: vh on a phone measures the viewport with the address bar
     retracted, so a 100vh panel is taller than what is actually visible and
     centred content sits low until you scroll. svh measures the smallest
     visible viewport, which is what a splash panel wants. Collapsing this to
     auto also shortened the hero enough to push white type onto the pale end
     of the ramp: at 531px the h1 measured 2.83:1, under the 3:1 floor. */
  .hero.is-full { min-height: 100svh; }

  .grid.is-2, .grid.is-3, .grid.is-4 { grid-template-columns: 1fr; }
  .proof-grid { grid-template-columns: 1fr; gap: 28px; }
  .band-access { padding: 72px 0; }
  .band-closing { padding: 80px var(--container-pad-x) 72px; gap: 30px; }
  .hero { padding: var(--space-lg) 0; }
  .hero-inner { padding-top: 24px; gap: var(--space-lg); }
  .button-group { width: 100%; }
  .button-group .button { flex: 1 1 auto; }
  /* The grid pair stacks here like the flex one does, rather than squeezing
     two labels into 375px. */
  .button-group.is-even { display: grid; grid-auto-flow: row; }
  .footer-bottom { flex-direction: column; }
}

@media (min-width: 769px) {
  .sticky-cta { display: none; }
}
