/* ==========================================================================
   Site stylesheet — shared base, layout, and components for all pages.
   Every value references a token from tokens.css. Load order per page:
   tokens.css first, then site.css.
   ========================================================================== */

/* ----- Reset / base ----------------------------------------------------- */
/* Route the body font through next/font's self-hosted Hanken Grotesk (with its
   auto metric-adjusted fallback) instead of the bare 'Hanken Grotesk' name, so
   the fallback occupies the same space and titles don't re-wrap on font load.
   Site-only override (tokens.css/shared + the app demo keep the literal stack). */
:root { --font-sans: var(--font-hanken), -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif; }
*, *::before, *::after { box-sizing: border-box; }
/* scroll-padding-top keeps anchor targets (TOC jumps, #requirements, etc.) clear
   of the sticky header instead of landing behind it. ~80px clears the ~64-72px bar. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: var(--space-20); }
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text-primary);
  background: var(--color-bg-page);
  -webkit-font-smoothing: antialiased;
}
img, picture, svg, video { display: block; max-width: 100%; height: auto; }
a { color: var(--color-link); text-decoration: none; }
/* Generic text-link hover: just darken to near-black, no underline, no teal.
   Scoped off .btn / brand wordmarks so it never repaints those. */
a:not(.btn):not(.brand):not(.site-header__brand):hover { color: var(--color-text-primary); text-decoration: none; }
h1, h2, h3, h4 { margin: 0; font-weight: var(--weight-semibold); line-height: var(--leading-snug); }
p { margin: 0; }
:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; border-radius: var(--radius-sm); }

/* ----- Headings (type scale) ------------------------------------------- */
h1 { font-size: var(--text-5xl); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); font-weight: var(--weight-bold); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-xl); }
.lead { font-size: var(--text-lg); color: var(--color-text-secondary); max-width: var(--container-narrow); }

/* ----- Layout ----------------------------------------------------------- */
.container { width: 100%; max-width: var(--container-max); margin-inline: auto; padding-inline: var(--space-6); }
.section { padding-block: var(--space-24); }
.section + .section { border-top: 1px solid var(--color-divider); }
/* A continuation section (home: the plan-includes word-wheel right after the
   toolset) hugs the section above it — no top padding, no divider, pulled up into
   that section's bottom padding so the two read as one flow, not two blocks. */
.section--flush { padding-top: 0; margin-top: calc(-1 * var(--space-12)); }
.section + .section--flush { border-top: 0; }
/* No alternating section fills. The page is ONE unified background
   (--color-bg-page). Sections are separated by dividers, not color. */
.page-hero { padding-block: var(--space-24); }
/* Trim the half-leading above the first line so optical top spacing is even. */
.page-hero h1 { text-box-trim: trim-start; text-box-edge: cap alphabetic; }

/* Skip link for keyboard users. */
.skip-link { position: absolute; left: -9999px; top: var(--space-2); background: var(--color-bg-surface); color: var(--color-text-primary); padding: var(--space-2) var(--space-4); border-radius: var(--radius-md); box-shadow: var(--shadow-md); z-index: var(--z-toast); }
.skip-link:focus { left: var(--space-4); }

/* Placeholder marker — flags empty content areas in these skeleton pages. */
.placeholder {
  padding: var(--space-8);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  background: transparent;
}

/* ----- Header ----------------------------------------------------------- */
/* The header is always its own panel: the lighter chrome tint over the page,
   with a bottom divider. No scroll state (it does not change on scroll). */
.site-header {
  position: sticky; top: 0; z-index: var(--z-sticky);
  background: color-mix(in srgb, var(--color-bg-chrome) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(8px);
  -webkit-backdrop-filter: saturate(1.4) blur(8px);
  border-bottom: 1px solid var(--color-border);
}
.site-header__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-6); min-height: 64px; padding-block: var(--space-5); }
/* Brand lockup: logo mark before the wordmark (the wordmark keeps its accent-wipe). */
.site-header__brand { display: flex; align-items: center; gap: var(--space-2); text-decoration: none; }
/* Thin hairline so the logo's edge reads against the light chrome background;
   dropped in dark mode where the mark already separates from the dark surface. */
.site-header__logo { width: 28px; height: 28px; flex: none; border-radius: var(--radius-md); object-fit: cover; border: 1px solid var(--color-border); }
[data-theme="dark"] .site-header__logo { border-color: transparent; }
.brand { font-size: var(--text-xl); font-weight: var(--weight-bold); color: var(--color-text-primary); letter-spacing: var(--tracking-tight); }
.nav { display: flex; align-items: center; gap: var(--space-6); flex-wrap: wrap; }
/* Nav link styling targets text links only, never .btn anchors (those keep
   their button-token color in every state). */
.nav a:not(.btn) { color: var(--color-text-secondary); font-weight: var(--weight-medium); font-size: var(--text-base); }
.nav a:not(.btn):hover { color: var(--color-text-primary); text-decoration: none; }
.nav a:not(.btn)[aria-current="page"] { color: var(--color-text-primary); }
/* Sign in is a button (it opens the auth modal) but reads as a nav link. */
.nav__signin { border: none; background: none; padding: 0; cursor: pointer; font-family: inherit; color: var(--color-text-secondary); font-weight: var(--weight-medium); font-size: var(--text-base); }
.nav__signin:hover { color: var(--color-text-primary); }
/* The header primary button (Start today / Enter studio) is shorter vertically
   than the standard primary button; the header's own padding gives the bar its
   height. */
.nav .btn-primary { padding-block: var(--space-2); }

/* ----- Header auth controls (two states) -------------------------------- */
/* End of the nav: Sign in + Start today (logged out), or the account circle +
   Enter studio (logged in). While the session restores, a neutral skeleton holds
   the space so the logged-out controls never flash before the state is known. */
.nav__auth { display: inline-flex; align-items: center; gap: var(--space-4); }
.nav__auth-skeleton { display: inline-block; width: 8.5rem; height: 2.25rem; border-radius: var(--radius-pill); background: var(--color-bg-subtle); }
/* Remaining-images indicator in the logged-in header. */
.nav__usage { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-secondary); white-space: nowrap; }

/* Account circle + dropdown */
.acct { position: relative; display: inline-flex; }
.acct__circle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none; border-radius: var(--radius-pill);
  background: var(--color-bg-subtle); color: var(--color-text-secondary);
  border: 1px solid var(--color-border); cursor: pointer;
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
  transition: var(--transition-base);
}
.acct__circle:hover { color: var(--color-text-primary); border-color: var(--color-text-muted); }
.acct__menu {
  position: absolute; top: calc(100% + var(--space-2)); right: 0; z-index: var(--z-raised);
  min-width: 12rem; display: flex; flex-direction: column; gap: 2px;
  padding: var(--space-2);
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
}
.acct__item {
  display: block; width: 100%; text-align: left;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  /* The anchor items sit inside .nav, so `.nav a:not(.btn)` restyles them to
     text-base; the <button> is not an anchor and keeps this rule's value. Use
     text-base + inherit here so Sign out matches Dashboard/Billing exactly
     (font family the button would otherwise default away from, and size). */
  color: var(--color-text-secondary); font-size: var(--text-base); font-weight: var(--weight-medium);
  font-family: inherit;
  background: none; border: none; cursor: pointer; text-decoration: none;
}
.acct__item:hover { background: var(--color-bg-subtle); color: var(--color-text-primary); text-decoration: none; }

/* Header logo: accent wipe, played the moment the page is scrolled down (not on
   load). js/header.js adds .is-scrolled past a small threshold; that ONLY drives
   this wipe — the header's own background and divider are always on, independent
   of scroll. Adapted from a Uiverse effect by satyamchaudharydev (warm accent on
   the light bg). Scoped to the header wordmark link (.brand--logo) only; the
   footer's plain .brand span is untouched. The accent layer is an absolute
   overlay -> no layout shift. */
.brand--logo { --line-width: 6px; position: relative; display: inline-block; text-decoration: none; }
/* Base: solid wordmark in the primary text color. The accent overlay sweeps
   over it on scroll. Inherits the .brand font/size/weight/letter-spacing. */
.brand--logo .actual-text { color: var(--color-text-primary); }
/* Accent overlay clipped by width; its right border is the moving line.
   left/padding-left are equal so the fill text stays aligned with the base. */
.brand--logo .hover-text {
  position: absolute; inset: 0;
  left: -14px; padding-left: 14px; box-sizing: border-box;
  width: 0; overflow: hidden; white-space: nowrap;
  color: var(--color-accent);
  -webkit-text-stroke: 1px var(--color-accent);
  border-right: var(--line-width) solid transparent;
  transition: width 1.2s var(--ease-out);
  pointer-events: none;
}
/* Triggered: the line colorizes and the fill sweeps right, past the last letter.
   The line then holds for ~2s and fades over ~0.3s (the accent stays). Fires for
   the header on scroll, and for the footer wordmark when .is-wiped is added (the
   moment it fully enters the viewport — see FooterLogoWipe). */
.site-header.is-scrolled .brand--logo .hover-text,
.brand--logo.is-wiped .hover-text {
  width: calc(100% + 28px);
  border-right-color: var(--color-accent);
  animation: logo-line-out 3s var(--ease-out) forwards;
}
@keyframes logo-line-out {
  0%, 90% { border-right-color: var(--color-accent); }
  100%    { border-right-color: transparent; }
}

/* ----- Footer ----------------------------------------------------------- */
.site-footer { background: var(--color-bg-chrome); border-top: 1px solid var(--color-border); }
/* Brand fills the left; the four nav columns are content-width and packed
   against the right edge with a wide, even gap between them. */
/* Top block: brand + nav columns. Generous top padding, and a large gap below
   so the bottom bar sits well clear of the columns (no divider between them). */
.site-footer__inner { display: grid; grid-template-columns: 1fr repeat(4, max-content); gap: var(--space-24); padding-block: var(--space-20) var(--space-32); }
/* Brand row: logo mark before the wordmark. The explicit logo box overrides the
   global `img { height: auto }` so it stays a 28px rounded square. */
/* line-height: 1 tightens the wordmark's box so the icon centers on the text
   (default leading otherwise drops the text's optical center and floats the mark high). */
.site-footer__brand { display: flex; align-items: center; gap: var(--space-2); line-height: 1; }
/* The wordmark uses the header's line box (the row's line-height:1 would clip the
   bottom of the accent sweep line, which is sized to the line box). */
.site-footer__brand .brand--logo { line-height: var(--leading-normal); }
/* Thin hairline so the logo's edge reads against the light cream background.
   Dropped in dark mode, where the mark already separates from the dark surface. */
.site-footer__logo { width: 28px; height: 28px; flex: none; border-radius: var(--radius-md); object-fit: cover; border: 1px solid var(--color-border); }
[data-theme="dark"] .site-footer__logo { border-color: transparent; }
.site-footer__tag { margin-top: var(--space-3); color: var(--color-text-muted); font-size: var(--text-sm); }
.site-footer__col { display: flex; flex-direction: column; gap: var(--space-3); }
.site-footer__h { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-primary); margin-bottom: var(--space-1); }
.site-footer__col a { color: var(--color-text-secondary); font-size: var(--text-sm); }
/* Beat the global link-hover (which turns links teal + underlined): footer links
   just darken to near-black on hover, no underline. */
.site-footer__col a:not(.btn):not(.brand):hover { color: var(--color-text-primary); text-decoration: none; }
/* On hover, reveal the shared up-right arrow to the right of the link. No slide:
   the arrow's space is always reserved, so the text never moves. Same icon,
   currentColor, 1em — matches the buttons. */
.site-footer__col a::after {
  content: ""; display: inline-block; width: 1em; height: 1em; vertical-align: middle;
  margin-left: var(--space-2);
  background-color: currentColor;
  -webkit-mask: var(--icon-arrow-up-right) center / contain no-repeat;
  mask: var(--icon-arrow-up-right) center / contain no-repeat;
  opacity: 0; transition: opacity var(--duration-base) var(--ease-out);
}
.site-footer__col a:hover::after { opacity: 1; }
/* Bottom bar: copyright left, preferences right. No divider above it. */
.site-footer__bottom { display: flex; align-items: center; justify-content: space-between; gap: var(--space-6); flex-wrap: wrap; padding-block: 0 var(--space-20); color: var(--color-text-muted); font-size: var(--text-sm); }
.site-footer__copy { margin: 0; }

/* Footer preferences: theme switch + language picker, right-aligned on the
   copyright line. Design adapted from Cursor's footer (segmented theme control +
   language pill), rebuilt in our warm-light tokens. Presentational only — the
   theme buttons drive the radio's checked state (pure CSS, no script); applying
   an actual dark theme and real translations are not wired yet. */
.footer-prefs { display: flex; align-items: center; gap: var(--space-2); }

/* Compact theme switch: system / light / dark. Radio inputs hold the checked
   segment without JS; the labels are the icon buttons. Named .themesw so it does
   NOT collide with the calculator's separate text-based .seg toggle. Sized to sit
   about as tall as the copyright line it shares. */
.themesw { display: inline-flex; align-items: center; gap: var(--space-1); padding: 2px; border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-bg-page); }
.themesw__input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.themesw__opt { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-pill); color: var(--color-text-muted); cursor: pointer; transition: var(--transition-base); }
.themesw__opt:hover { color: var(--color-text-primary); }
.themesw__opt svg { width: 16px; height: 16px; }
.themesw__input:checked + .themesw__opt { background: var(--color-bg-surface); color: var(--color-text-primary); box-shadow: var(--shadow-xs); }
.themesw__input:focus-visible + .themesw__opt { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }

/* Language picker — a fully-rounded pill that opens a small menu (native
   <details>, no JS). Lists five languages; selecting one does not switch the
   site yet. Compact, roughly the height of the copyright line beside it. */
.lang { position: relative; display: inline-block; }
.lang__toggle { display: inline-flex; align-items: center; gap: var(--space-2); height: 28px; padding-inline: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-bg-page); color: var(--color-text-secondary); font-size: var(--text-sm); font-weight: var(--weight-medium); cursor: pointer; list-style: none; transition: var(--transition-base); }
.lang__toggle::-webkit-details-marker { display: none; }
.lang__toggle:hover { color: var(--color-text-primary); background: var(--color-bg-subtle); }
.lang__toggle svg { width: 14px; height: 14px; }
.lang__chev { color: var(--color-text-muted); transition: transform var(--duration-base) var(--ease-out); }
.lang[open] .lang__chev { transform: rotate(180deg); }
/* Menu opens upward — the picker sits at the very bottom of the page. */
.lang__menu { position: absolute; right: 0; bottom: calc(100% + var(--space-2)); z-index: var(--z-raised); min-width: 100%; margin: 0; padding: var(--space-1); list-style: none; background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); }
.lang__opt { display: block; width: 100%; text-align: left; padding: var(--space-2) var(--space-3); border: none; background: none; border-radius: var(--radius-sm); color: var(--color-text-secondary); font-family: var(--font-sans); font-size: var(--text-sm); white-space: nowrap; cursor: pointer; transition: var(--transition-base); }
.lang__opt:hover { background: var(--color-bg-subtle); color: var(--color-text-primary); }
.lang__opt[aria-current="true"] { color: var(--color-text-primary); font-weight: var(--weight-semibold); }

/* ----- Buttons (canonical, shared) -------------------------------------- */
.btn { position: relative; display: inline-flex; align-items: center; justify-content: center; font-family: var(--font-sans); font-size: var(--text-base); font-weight: var(--weight-semibold); border: none; cursor: pointer; text-decoration: none; transition: var(--transition-base); }
.btn:hover { text-decoration: none; }
.btn__label { display: inline-block; transition: transform var(--duration-base) var(--ease-out); }
.btn::after {
  content: ""; position: absolute; top: 50%; right: var(--btn-arrow-inset);
  width: 1em; height: 1em; background-color: currentColor;
  -webkit-mask: var(--icon-arrow-up-right) center / contain no-repeat;
  mask: var(--icon-arrow-up-right) center / contain no-repeat;
  opacity: 0; transform: translateY(-50%) translateX(-4px);
  transition: opacity var(--duration-base) var(--ease-out), transform var(--duration-base) var(--ease-out);
  pointer-events: none;
}
.btn:hover .btn__label, .btn:focus-visible .btn__label, .btn:active .btn__label { transform: translateX(calc(-1 * var(--btn-arrow-shift))); }
.btn:hover::after, .btn:focus-visible::after, .btn:active::after { opacity: 1; transform: translateY(-50%) translateX(2px); }
.btn:active { transform: scale(var(--btn-active-scale)); }
.btn-primary { background: var(--color-accent); color: var(--color-on-accent); padding: var(--space-3) var(--space-6); border-radius: var(--radius-pill); box-shadow: var(--shadow-accent); }
.btn-primary:hover { background: var(--color-accent-hover); }
.btn-primary:active { background: var(--color-accent-active); }
.btn-secondary { background: var(--color-bg-surface); color: var(--color-text-primary); border: 1px solid var(--color-border-strong); padding: var(--space-3) var(--space-6); border-radius: var(--radius-pill); }
.btn-secondary:hover { background: var(--color-bg-subtle); }
.btn-learn-more { background: none; border: none; color: var(--color-text-secondary); font-weight: var(--weight-medium); padding: var(--space-2) var(--btn-learn-arrow-room) var(--space-2) 0; border-radius: var(--radius-sm); }
.btn-learn-more:hover, .btn-learn-more:focus-visible { color: var(--color-text-primary); }

/* ----- Home hero (Linear-style composition, warm light theme) ----------- */
.hero { padding-top: var(--space-24); padding-bottom: var(--space-24); }
/* Divider between the hero (with the app cutout) and the first content section. */
.hero + .section { border-top: 1px solid var(--color-divider); }
.hero__title { font-size: var(--text-6xl); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); font-weight: var(--weight-bold); max-width: 30ch; text-wrap: balance; text-box-trim: trim-start; text-box-edge: cap alphabetic; }
.u { text-decoration: underline; text-decoration-thickness: 0.06em; text-underline-offset: 0.1em; }
.hero__sub { display: flex; align-items: last baseline; justify-content: space-between; gap: var(--space-8); flex-wrap: wrap; margin-top: var(--space-8); }
.hero__sub .lead { margin: 0; }
/* Feature link reuses the shared learn-more CTA (.btn-learn-more) but right-
   aligns flush to the container edge: text sits flush right at rest (no
   reserved padding), then on hover the label slides left and the up-right
   arrow reveals flush against the right edge. */
.hero__feature { white-space: nowrap; padding-right: 0; padding-block: 0; }
.hero__feature .tag { color: var(--color-text-primary); font-weight: var(--weight-semibold); }
.hero__feature::after { right: 0; }
.hero__feature:hover .btn__label,
.hero__feature:focus-visible .btn__label,
.hero__feature:active .btn__label { transform: translateX(calc(-1em - var(--space-2))); }
.hero__feature:hover::after,
.hero__feature:focus-visible::after,
.hero__feature:active::after { transform: translateY(-50%) translateX(0); }

/* App cutout — interactive product preview, a fully-rounded card anchored
   below the hero. Content is embedded (and stays interactive) from
   /assets/landing-page-app/. overflow:hidden clips the iframe to the radius;
   the box-shadow is unaffected and renders all around. */
.app-cutout {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-2xl);
  /* Page colour, not a surface white — the empty box blends into the page so the
     entrance reads as just the drawn outline; the app supplies its own colour. */
  background: var(--color-bg-page);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  transition: box-shadow 0.45s var(--ease-out, ease-out);
}
/* Tall enough to read as a full Mac screen (the app inside is laid out for that
   vertical room), capped so it never overruns the viewport on a laptop. */
.app-cutout__frame { display: block; width: 100%; height: calc(min(90vh, 940px) - 20px); border: 0; background: var(--color-bg-page); }

/* ===== Interactive demo entrance — hairline draw ==========================
   Dead simple: ONE line draws the whole rounded rectangle (from the top-left, all
   the way around), then the app fades in. Nothing of the frame pre-exists — the
   box is the page colour with no border/shadow while the line draws; on .is-done
   the static border + shadow are restored and the app fades in. Scoped to the demo
   (home + download). Tokens from shared; no layout shift (only stroke + opacity
   animate). Armed by .reveal-ready, so reduced-motion / no-JS shows it statically.
   JS (AppCutout) supplies the path geometry + pace (--draw-dur), plays once. */
.app-cutout-wrap {
  position: relative;
  margin-top: var(--space-16);
  /* The colour of the line as it draws — the normal hairline border colour. */
  --trace-line: var(--color-border);
}

/* This wrapper IS the demo's entrance, so opt it out of the section's fade-up
   reveal (the draw replaces it). Both placements: the home hero child and the
   download hero's demo column. */
.reveal-ready .reveal-group > .app-cutout-wrap,
.reveal-ready .reveal-group > .dl-hero__demo { opacity: 1; transform: none; transition: none; }

/* Nothing of the frame pre-exists while the line draws: the box is already the
   page colour, so just hide the border + shadow. On .is-done they return.
   Without .reveal-ready the full frame shows (no-JS / reduced motion). */
.reveal-ready .app-cutout-wrap:not(.is-done) .app-cutout { border-color: transparent; box-shadow: none; }

/* App hidden while the line draws, then fades in once the rectangle is complete. */
.reveal-ready .app-cutout__frame { opacity: 0; }
.app-cutout-wrap.is-done .app-cutout__frame {
  animation: ei-demo-fade 0.9s var(--ease-out, ease-out) forwards;
}

/* The trace overlay: above the iframe, never intercepts input; fades out once the
   draw is done, leaving only the cutout's restored hairline border. */
.app-cutout__trace {
  position: absolute; top: 0; left: 0; z-index: 2;
  pointer-events: none;
  opacity: 1; transition: opacity 0.45s var(--ease-out, ease-out);
}
.app-cutout-wrap.is-done .app-cutout__trace { opacity: 0; }

/* The line itself: draws the full rectangle from the top-left via stroke-dashoffset. */
.app-cutout__line {
  fill: none; stroke: var(--trace-line); stroke-width: 1;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 1; stroke-dashoffset: 1;
}
.app-cutout-wrap.is-revealing .app-cutout__line {
  animation: ei-demo-draw var(--draw-dur, 1.3s) linear forwards;
}

@keyframes ei-demo-draw { to { stroke-dashoffset: 0; } }
@keyframes ei-demo-fade { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .app-cutout__trace { display: none; }
  .reveal-ready .app-cutout__frame { opacity: 1; }
}

/* ----- "Team from" credibility strip ----------------------------------- */
/* Slim band framed by hairline borders. The affiliations are large, grey and
   truly centered across the band; "Team from" is a small grey label floating
   at the left (absolutely positioned) so it never pushes the centered group
   off-center. Gaps use --space-6 (24px), not the 96px section token. */
.teamfrom { padding-block: var(--space-10); border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border); }
.teamfrom__row { position: relative; display: flex; align-items: center; justify-content: center; }
.teamfrom__label {
  position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  font-size: var(--text-sm); font-weight: var(--weight-regular); color: var(--color-text-muted);
}
.teamfrom__list { display: flex; align-items: center; justify-content: center; gap: var(--space-10); flex-wrap: wrap; list-style: none; margin: 0; padding: 0; }
.teamfrom__list li { position: relative; font-size: var(--text-3xl); font-weight: var(--weight-medium); color: var(--color-text-secondary); line-height: var(--leading-snug); }
/* Thin vertical divider, shorter than the text, centered in the gap. */
.teamfrom__list li + li::before {
  content: ""; position: absolute; left: calc(var(--space-10) / -2); top: 50%;
  width: 1px; height: 0.75rem; transform: translateY(-50%); background: var(--color-border);
}
/* Narrow: stack the label above the centered group so centering is preserved. */
@media (max-width: 640px) {
  .teamfrom__row { flex-direction: column; gap: var(--space-3); }
  .teamfrom__label { position: static; transform: none; }
  .teamfrom__list li { font-size: var(--text-2xl); }
}
/* Very narrow: items may wrap, so drop the dividers. */
@media (max-width: 420px) {
  .teamfrom__list li + li::before { display: none; }
}

/* ----- Before/after comparison carousel -------------------------------- */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

.compare__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-8); flex-wrap: wrap; margin-bottom: calc(var(--space-3) + 5px); }
.compare__title { font-size: var(--text-4xl); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); font-weight: var(--weight-bold); max-width: 30ch; text-wrap: balance; margin: 0; }
/* Note stays in flow (so the head reserves its full height and the spacing
   below is unchanged), but is shifted up so its center sits on the header's
   centerline. -50% adapts to the note's own height; the added term is half the
   header's line height, so the header never moves at any viewport. */
.compare__note { font-size: var(--text-base); color: var(--color-text-secondary); max-width: 42ch; line-height: var(--leading-normal); transform: translateY(calc(-50% + var(--text-4xl) * var(--leading-tight) / 2)); }

/* Soft edge fade: the centered active slide (~20-80%) stays solid; the peek
   slides fade out toward the left and right edges into the page background. */
.compare__viewport {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
}
.compare__track { position: relative; display: flex; gap: var(--space-0); transition: transform var(--duration-slow) var(--ease-out); will-change: transform; }
.compare__slide { flex: 0 0 72%; opacity: 0.62; transition: opacity var(--duration-base) var(--ease-out); }
.compare__slide.is-active { opacity: 1; }

/* The before/after wipe widget */
.ba {
  --pos: 50%;
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: var(--radius-md); border: 1px solid var(--color-border);
  background: var(--color-bg-sunken); box-shadow: var(--shadow-md);
  touch-action: pan-y; user-select: none;
}
.compare__slide.is-active .ba { cursor: ew-resize; }
.compare__slide:not(.is-active) { cursor: pointer; }
.compare__slide:not(.is-active) .ba { pointer-events: none; }
.ba__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.ba__img--before { z-index: 1; clip-path: inset(0 calc(100% - var(--pos)) 0 0); }

.ba__label {
  position: absolute; top: var(--space-4); z-index: 3;
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill);
}
.ba__label--before { left: var(--space-4); background: var(--color-bg-surface); color: var(--color-text-primary); box-shadow: var(--shadow-sm); }
.ba__label--after { right: var(--space-4); background: var(--color-text-primary); color: var(--color-text-inverse); }
/* Each pill sits in a full-frame clip layer tied to its own image side, so the
   seam reveals/hides it as it scrolls over (Before pill belongs to the before
   image, After to the after). Clipping the pill directly would size the clip to
   the pill's own box, not the frame, so the layer (inset:0) is what gets clipped. */
.ba__pillclip { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.ba__pillclip--before { clip-path: inset(0 calc(100% - var(--pos)) 0 0); }
.ba__pillclip--after { clip-path: inset(0 0 0 var(--pos)); }

.ba__seam { position: absolute; top: 0; bottom: 0; left: var(--pos); width: 2px; transform: translateX(-50%); z-index: 2; background: var(--color-on-accent); }
.ba__handle {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 40px; height: 40px; border-radius: var(--radius-pill);
  /* Constant white chip + dark arrows in both themes (control sits on a photo). */
  background: var(--color-media-surface); color: var(--color-media-ink);
  border: none; box-shadow: var(--shadow-md);
  display: grid; place-items: center; cursor: ew-resize; padding: 0;
}
.ba__handle svg { width: 1.1em; height: 1.1em; }

/* Placeholder state until the photos are added */
.ba.is-empty .ba__img { opacity: 0; }
.ba.is-empty::after { content: "Before and after photos load here"; position: absolute; inset: 0; z-index: 0; display: grid; place-items: center; color: var(--color-text-muted); font-size: var(--text-sm); }

.compare__foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-6); margin-top: calc(var(--space-5) + 1px); flex-wrap: wrap; }
.compare__meta { display: flex; align-items: baseline; gap: var(--space-4); line-height: 1; }
.compare__count { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--color-text-muted); letter-spacing: var(--tracking-wide); }
.compare__name { font-weight: var(--weight-medium); color: var(--color-text-primary); }
.compare__controls { display: flex; align-items: center; gap: var(--space-6); }
.compare__dots { display: flex; align-items: center; gap: var(--space-2); }
.compare__dot { width: 8px; height: 8px; padding: 0; border: none; border-radius: var(--radius-pill); background: var(--color-border-strong); cursor: pointer; transition: background var(--duration-base) var(--ease-out), width var(--duration-base) var(--ease-out); }
.compare__dot.is-active { background: var(--color-accent); width: 22px; }
.compare__nav { display: flex; gap: var(--space-3); }
.compare__arrow { width: 44px; height: 44px; padding: 0; border-radius: var(--radius-pill); background: var(--color-bg-surface); border: 1px solid var(--color-border-strong); color: var(--color-text-primary); display: grid; place-items: center; cursor: pointer; transition: var(--transition-base); }
.compare__arrow:hover { background: var(--color-bg-subtle); }
.compare__arrow:active { transform: scale(var(--btn-active-scale)); }
.compare__arrow svg { width: 1.1em; height: 1.1em; }

/* Anti-highlight for this section's controls, in ONE place instead of repeated
   on each rule: never text-selectable or tap-highlighted. (The nav buttons also
   drop focus on mouse-click via Compare.tsx, so a click never leaves them looking
   highlighted; keyboard Tab focus still shows the ring.) */
.compare__arrow, .compare__dot, .ba__handle {
  user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
}

@media (max-width: 720px) {
  .compare__slide { flex-basis: 100%; }
  /* Full-width slide, no peeks: drop the edge fade so the active isn't clipped. */
  .compare__viewport { -webkit-mask-image: none; mask-image: none; }
  .compare__title { font-size: var(--text-3xl); }
  .compare__note { position: static; transform: none; max-width: 100%; }
}

/* ----- "What we provide" scroll-expand panel --------------------------- */
/* Base / fallback (no JS, reduced motion, small screens): an open, contained
   rounded card holding all the copy. Fully readable, normal flow. The signature
   scroll-expand is layered on top via .is-scroll (added by js/provide.js). */
.provide { padding-block: var(--space-24); border-top: 1px solid var(--color-divider); }
.provide + .section { border-top: 1px solid var(--color-divider); }
.provide__box {
  /* Match the container's content width (max-width minus its inline padding) so
     the card lines up with the rest of the page rather than running wider. */
  width: calc(100% - var(--space-6) * 2); max-width: calc(var(--container-max) - var(--space-6) * 2); margin-inline: auto;
  background: var(--color-bg-subtle); border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  position: relative;
  overflow: hidden; /* keeps the dot grid inside the box's rounded corners */
}
/* Faint dot-grid texture, this box only. Sits behind the copy (text is lifted
   with z-index). Uniform strength across the whole box — no fade. Offset by half
   a cell so the first row/column sit evenly inset from the top and left edges
   rather than hugging them. */
.provide__box > * { position: relative; z-index: 1; }
.provide__box::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(var(--provide-dot) 1px, transparent 1px);
  background-size: 22px 22px;
  background-position: 11px 11px;
}
.provide__inner { max-width: 80ch; margin-inline: auto; padding: var(--space-16) var(--space-12); }
.provide__title { font-size: var(--text-4xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); color: var(--color-text-primary); margin: 0 0 var(--space-8); }
.provide__body p { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--color-text-secondary); margin: var(--space-6) 0 0; }
.provide__body p:first-child { margin-top: 0; }
/* Emphasis on "own" — same color, underlined (not link styling). */
.provide__own { text-decoration: underline; text-decoration-thickness: 0.06em; text-underline-offset: 0.1em; }

/* Enhanced: a large centered card that expands to full-bleed as the user
   scrolls one viewport into the section. Paint-only via clip-path (the content
   is laid out once and never reflows), so it stays smooth and never hijacks
   scroll. --p (0..1) is driven by js/provide.js; --ch is the measured content
   height so the start card hugs the copy (no stranded lines, no empty chip). */
.provide.is-scroll { height: 170vh; padding-block: 0; }
/* The site header is sticky, so pin the stage BELOW it and size it to the area
   that remains visible (--header-h is measured in provide.js). The box then
   centers — and at the end fills — that visible area, not the full viewport, so
   it no longer locks too high under the header. */
.provide.is-scroll .provide__stage { position: sticky; top: var(--header-h, 0px); height: calc(100vh - var(--header-h, 0px)); display: grid; place-items: center; overflow: clip; }
.provide.is-scroll .provide__box {
  max-width: none; width: 100%; min-height: calc(100vh - var(--header-h, 0px)); margin: 0;
  display: grid; place-items: center; box-shadow: none;
  border-radius: 0; /* clip-path owns the rounding; element must be square */
  clip-path: inset(
    calc(max(0px, min(var(--space-24), (100vh - var(--header-h, 0px) - var(--ch, 70vh)) / 2)) * (1 - var(--p, 0)))
    calc((100% - min(var(--container-max), 100%) + var(--space-6) * 2) / 2 * (1 - var(--p, 0)))
    calc(max(0px, min(var(--space-24), (100vh - var(--header-h, 0px) - var(--ch, 70vh)) / 2)) * (1 - var(--p, 0)))
    calc((100% - min(var(--container-max), 100%) + var(--space-6) * 2) / 2 * (1 - var(--p, 0)))
    round calc(var(--radius-md) * (1 - var(--p, 0)))
  );
}

/* ----- Price-savings calculator ---------------------------------------- */
.calc__head { margin-bottom: var(--space-12); }
.calc__title { font-size: var(--text-4xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); text-wrap: balance; margin: 0; max-width: 24ch; }
.calc__grid {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  grid-template-areas:
    "inputs result"
    "note   cta";
  gap: var(--space-3) var(--space-12);
  align-items: start;
}
.calc__inputs { grid-area: inputs; }
.calc__note.calc__hint { grid-area: note; margin-top: 0; max-width: none; }
/* "Check our data" learn-more CTA: sits below the result box, flush right,
   top-aligned with the first line of the services note. Mirrors hero__feature. */
.calc__data-link { grid-area: cta; justify-self: end; align-self: center; white-space: nowrap; padding-right: 0; padding-block: 0; }
.calc__data-link::after { right: 0; }
.calc__data-link:hover .btn__label,
.calc__data-link:focus-visible .btn__label,
.calc__data-link:active .btn__label { transform: translateX(calc(-1em - var(--space-2))); }
.calc__data-link:hover::after,
.calc__data-link:focus-visible::after,
.calc__data-link:active::after { transform: translateY(-50%) translateX(0); }

.calc__group { border: none; padding: 0; margin: 0 0 var(--space-10); min-width: 0; }
.calc__group:last-child { margin-bottom: 0; }
.calc__label { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-primary); padding: 0; margin-bottom: var(--space-3); }
.calc__fields { display: flex; gap: var(--space-4); flex-wrap: wrap; margin-top: var(--space-4); }
.calc__fields[hidden] { display: none; }
.calc__fields .field { flex: 1 1 180px; }
.calc__hint { font-size: var(--text-sm); color: var(--color-text-muted); margin-top: var(--space-3); max-width: 52ch; }

/* Segmented toggle */
.seg { display: inline-flex; gap: var(--space-1); padding: var(--space-1); background: var(--color-bg-sunken); border: 1px solid var(--color-border); border-radius: var(--radius-pill); }
.seg__btn { border: none; background: none; cursor: pointer; font: inherit; font-weight: var(--weight-medium); color: var(--color-text-secondary); padding: var(--space-2) var(--space-5); border-radius: var(--radius-pill); transition: var(--transition-base); }
.seg__btn:hover { color: var(--color-text-primary); }
.seg__btn.is-active { background: var(--color-bg-surface); color: var(--color-text-primary); box-shadow: var(--shadow-sm); }

/* Service chips */
.calc__services { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-4); border: 1px solid var(--color-border-strong); border-radius: var(--radius-pill); cursor: pointer; font-size: var(--text-sm); color: var(--color-text-secondary); transition: var(--transition-base); }
.chip input { accent-color: var(--color-accent); margin: 0; cursor: pointer; }
.chip:has(input:checked) { border-color: var(--color-accent); background: var(--color-accent-tint); color: var(--color-text-primary); }
/* AI plans bundle everything: chips stay lit (checked) but dimmed and locked. */
.calc--ai .calc__services { opacity: 0.6; }
.calc--ai .chip, .calc--ai .chip input { cursor: not-allowed; }

/* Result panel */
.calc__result { grid-area: result; align-self: stretch; background: var(--color-bg-subtle); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-8); display: flex; flex-direction: column; gap: var(--space-6); }
.calc__result-label { display: block; font-size: var(--text-sm); color: var(--color-text-secondary); margin-bottom: var(--space-1); }
.calc__big { display: block; font-size: var(--text-5xl); font-weight: var(--weight-bold); color: var(--color-text-primary); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); font-variant-numeric: tabular-nums; }
.calc__ours-price { display: block; font-size: var(--text-2xl); font-weight: var(--weight-semibold); color: var(--color-accent); }
.calc__save-amt { display: block; font-size: var(--text-2xl); font-weight: var(--weight-semibold); color: var(--color-text-primary); font-variant-numeric: tabular-nums; }
.calc__breakeven { font-size: var(--text-base); font-weight: var(--weight-medium); color: var(--color-text-primary); border-top: 1px solid var(--color-divider); padding-top: var(--space-6); margin: auto 0 0; }

@media (max-width: 720px) {
  .calc__grid {
    grid-template-columns: 1fr;
    grid-template-areas: "inputs" "result" "note" "cta";
    gap: var(--space-8);
  }
  .calc__title { font-size: var(--text-3xl); }
}

/* ----- FAQ (two-column: standing label left, accordion list right) ----- */
.faq__grid { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: var(--space-16); align-items: start; }
/* Lock the moment the section's top divider reaches the header bottom: offset =
   header height (~80px, border-box) + the section's 96px top padding. */
.faq__intro { position: sticky; top: calc(var(--space-20) + var(--space-24)); }
.faq__title { font-size: var(--text-4xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); margin: 0; }
.faq__sub { font-size: var(--text-base); color: var(--color-text-secondary); max-width: 28ch; margin: var(--space-4) 0 0; }

/* Top hairline of the list. The list is pushed down by the height of the "FAQs"
   title plus its gap, so the first question's top line lines up with the top of
   the subheading on the left. */
.faq__list { position: relative; border-top: 1px solid var(--color-divider); margin-top: calc(var(--text-4xl) * var(--leading-tight) + var(--space-4)); }
/* Expand-all toggle: sits in the empty offset space above the questions, right
   aligned, positioned absolutely so it shifts nothing. Small, white, no arrow;
   keeps the shared button hover-darken and active-shrink. */
.faq__expand {
  position: absolute; right: 0;
  /* Offset up from the list top to the vertical center of the "FAQs" title. */
  top: calc(-1 * (var(--text-4xl) * var(--leading-tight) / 2 + var(--space-4)));
  transform: translateY(-50%);
  font-size: var(--text-sm); padding: var(--space-2) var(--space-4);
}
.faq__expand::after { content: none; }
/* Keep the centering offset while applying the shared active-shrink. */
.faq__expand:active { transform: translateY(-50%) scale(var(--btn-active-scale)); }
.faq__item { border-bottom: 1px solid var(--color-divider); }
.faq__q { margin: 0; font-weight: var(--weight-medium); }
.faq__trigger {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-6);
  width: 100%; padding: var(--space-6) 0; background: none; border: none; cursor: pointer;
  font: inherit; text-align: left; color: var(--color-text-primary);
}
.faq__q-text { font-size: var(--text-xl); font-weight: var(--weight-medium); line-height: var(--leading-snug); }
.faq__chevron { flex: none; display: grid; place-items: center; color: var(--color-text-muted); transition: transform var(--duration-base) var(--ease-out), color var(--duration-base) var(--ease-out); }
.faq__chevron svg { width: 1.25em; height: 1.25em; }
.faq__trigger:hover .faq__chevron, .faq__trigger:focus-visible .faq__chevron { color: var(--color-text-primary); }
.faq__item.is-open .faq__chevron { transform: rotate(180deg); color: var(--color-text-primary); }

/* Collapsed answers stay in the DOM (height 0 via grid), so they are read by
   search engines; expanding animates the row height smoothly. */
.faq__answer { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--duration-base) var(--ease-out); }
.faq__item.is-open .faq__answer { grid-template-rows: 1fr; }
.faq__answer-inner { overflow: hidden; }
.faq__answer-inner p { font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--color-text-secondary); max-width: 60ch; margin: 0; padding-bottom: var(--space-6); }

@media (max-width: 720px) {
  .faq__grid { grid-template-columns: 1fr; gap: var(--space-8); }
  .faq__intro { position: static; }
  /* Single column: no left/right alignment to honor, so drop the offset. */
  .faq__list { margin-top: 0; }
  /* No offset space to float into: place the toggle in flow, right aligned. */
  .faq__expand { position: static; transform: none; display: block; width: fit-content; margin: 0 0 var(--space-4) auto; }
  .faq__expand:active { transform: scale(var(--btn-active-scale)); }
}

/* ----- Ending CTA ------------------------------------------------------ */
/* The FAQ flows straight into the closing CTA: no divider. Deliberate extra
   room around the CTA — 150px above and below. Above = FAQ's 96px bottom padding
   + 54px here; below = 96px base + 54px (= 150px). */
.section + .cta { border-top: 0; }
.cta { padding-top: 54px; padding-bottom: 150px; }
.cta__inner { display: grid; justify-items: center; text-align: center; gap: var(--space-6); max-width: var(--container-narrow); margin-inline: auto; }
.cta__title { font-size: var(--text-5xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); text-wrap: balance; margin: 0; }
.cta__actions { display: flex; gap: var(--space-4); flex-wrap: wrap; justify-content: center; margin-top: var(--space-4); }
/* Larger download button for the closing CTA only. */
.cta__actions .btn-primary { font-size: var(--text-lg); padding: var(--space-4) var(--space-8); }

/* ----- Simple form (contact skeleton) ---------------------------------- */
.form { display: flex; flex-direction: column; gap: var(--space-5); max-width: var(--container-narrow); margin-top: var(--space-8); }
.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-secondary); }
.field input, .field textarea, .field select {
  font: inherit; color: var(--color-text-primary); background: var(--color-bg-surface);
  border: 1px solid var(--color-border-strong); border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  outline: none; transition: border-color var(--duration-base) var(--ease-out);
}
.field textarea { min-height: 140px; resize: vertical; }
/* Replace the native (browser-default) select arrow with the Lucide chevron,
   inset from the right edge to match the field's text padding. */
.field select {
  appearance: none; -webkit-appearance: none;
  background-image: var(--icon-chevron-down);
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  background-size: 1.15em;
  padding-right: calc(var(--space-4) + 1.15em + var(--space-2));
}
/* Focus recolors the existing 1px border in place — no outline, no outer shadow,
   so there's never a second parallel line and the box never shifts. */
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--color-accent);
}
.field [aria-invalid="true"] { border-color: var(--color-error); }

/* ----- Contact page ---------------------------------------------------- */
.contact__grid { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: var(--space-16); align-items: start; }
.contact__title { font-size: var(--text-5xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); margin: 0; }
.contact__lead { font-size: var(--text-lg); color: var(--color-text-secondary); line-height: var(--leading-normal); max-width: 45ch; margin: var(--space-5) 0 0; }
.contact__detail { margin-top: var(--space-10); }
.contact__detail-label { display: block; font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-primary); margin-bottom: var(--space-1); }
.contact__email { font-size: var(--text-lg); }
.contact__reply { font-size: var(--text-sm); color: var(--color-text-muted); margin: var(--space-6) 0 0; }
/* Drop the form so the "Name" LABEL (not the input box) lines up with the
   subheader on the left. Offset = title height + lead's top margin, plus the
   difference of the two text caps' half-leadings so the cap-tops match exactly. */
.contact__form { max-width: none; margin-top: calc(var(--text-5xl) * var(--leading-tight) + var(--space-5) + (var(--text-lg) - var(--text-sm)) * (var(--leading-normal) - 1) / 2); }
/* Local-only: this submit button is wide enough that the hover arrow has room,
   so keep the arrow but do not slide the label left (unlike the shared button). */
/* Wide buttons (full-width) keep the label put and reveal the arrow into its
   reserved space — the left-shift is only for buttons too narrow to fit it. */
.contact__submit:hover .btn__label,
.contact__submit:focus-visible .btn__label,
.contact__submit:active .btn__label,
.pricing-card__cta:hover .btn__label,
.pricing-card__cta:focus-visible .btn__label,
.pricing-card__cta:active .btn__label,
.auth__submit:hover .btn__label,
.auth__submit:focus-visible .btn__label,
.auth__submit:active .btn__label,
.btn-danger:hover .btn__label,
.btn-danger:focus-visible .btn__label,
.btn-danger:active .btn__label { transform: none; }
/* Submit confirmation / error banner. */
.form__status { font-size: var(--text-sm); margin: 0; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); border: 1px solid transparent; }
.form__status[hidden] { display: none; }
.form__status.is-success { color: var(--color-success); border-color: color-mix(in srgb, var(--color-success) 35%, transparent); background: color-mix(in srgb, var(--color-success) 10%, transparent); }
.form__status.is-error { color: var(--color-error); border-color: color-mix(in srgb, var(--color-error) 35%, transparent); background: color-mix(in srgb, var(--color-error) 10%, transparent); }
@media (max-width: 720px) {
  .contact__grid { grid-template-columns: 1fr; gap: var(--space-10); }
  /* Stacked: no left/right alignment to honor, so drop the offset. */
  .contact__form { margin-top: 0; }
}

/* ----- Download (product page) ----------------------------------------- */
/* Shared section heading + subnote. */
.dl-h2 { font-size: var(--text-4xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); text-wrap: balance; margin: 0; }

/* What you get: four offers, 4 across on wide, collapsing to 2 then 1. */
.dl-offers .dl-h2 { margin-bottom: var(--space-12); }
.dl-offers__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-10); list-style: none; margin: 0; padding: 0; align-items: start; }
.dl-offer__label { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--color-text-primary); line-height: var(--leading-snug); margin: 0 0 var(--space-2); }
.dl-offer__text { font-size: var(--text-base); color: var(--color-text-secondary); line-height: var(--leading-normal); margin: 0; }
/* Editorial numbered index above each benefit column — borrows the compare
   carousel's "01 / 06" marker: prominent accent numeral, smaller muted total,
   over a soft hairline that turns each column into an indexed panel. The number
   is the column's first child, so all four markers sit on one line regardless
   of heading length (reinforced by align-items: start on the grid above). */
.wyg-index {
  display: flex; align-items: baseline; gap: var(--space-2);
  margin-bottom: var(--space-4);
  font-variant-numeric: tabular-nums;
}
.wyg-num { font-size: var(--text-3xl); font-weight: var(--weight-bold); line-height: 1; letter-spacing: 0.01em; color: var(--color-accent); }
.wyg-total { font-size: var(--text-sm); font-weight: var(--weight-medium); line-height: 1; color: var(--color-text-muted); }
@media (max-width: 720px) { .dl-offers__grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-8); } }
@media (max-width: 440px) { .dl-offers__grid { grid-template-columns: 1fr; } }

/* Hero: asymmetric, edge-aligned (VanceAI style). Headline pinned left, download
   action pinned right, both vertically centered to a shared through-line. Flat
   warm background (one unified page background, no gradient). */
.dl-hero__inner { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-12); }
/* Gap between the hero row and the live demo is owned by .app-cutout-wrap's
   margin-top (the demo is wrapped by AppCutout for its entrance animation). */
.dl-hero__title { font-size: var(--text-6xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); text-wrap: balance; text-align: left; margin: 0; max-width: 16ch; }
/* Right side: button + fallback link bundled tight. */
.dl-hero__cta { display: grid; justify-items: center; gap: var(--space-2); flex: none; }
.dl-hero__actions { display: flex; justify-content: center; flex-wrap: wrap; gap: var(--space-4); }
.dl-hero__actions [hidden] { display: none; }
.dl-hero .btn-primary { font-size: var(--text-lg); padding: var(--space-4) var(--space-8); }
/* Secondary platform line: small muted text with the platform name as a link. */
.dl-alt { font-size: var(--text-sm); color: var(--color-text-muted); margin: 0; }
.dl-alt[hidden] { display: none; }
.dl-altlink { background: none; border: none; cursor: pointer; font: inherit; color: var(--color-text-secondary); text-decoration: underline; text-underline-offset: 0.15em; padding: 0; }
.dl-altlink:hover, .dl-altlink:focus-visible { color: var(--color-text-primary); }

@media (max-width: 720px) {
  .dl-hero__inner { flex-direction: column; align-items: flex-start; gap: var(--space-8); min-height: 0; }
  .dl-hero__cta { justify-items: start; }
  .dl-hero__title { font-size: var(--text-5xl); }
}

/* System requirements: Minimum / Recommended spec grid. Section padding and the
   top divider come from .section; the rules below are component-only, all tokens.
   The three columns are a single grid track shared by the header row and each
   data row via display:contents; on narrow screens each spec stacks into its own
   block, labelling values by tier with the data-tier attribute. */
.sysreq h2 { font-size: var(--text-4xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); color: var(--color-text-primary); margin: 0; }
.sysreq .intro { margin: var(--space-6) 0 0; max-width: 56ch; font-size: var(--text-lg); line-height: var(--leading-normal); color: var(--color-text-secondary); }
.sysreq .intro strong { color: var(--color-text-primary); font-weight: var(--weight-semibold); }

.sysreq .specs { margin-top: var(--space-16); display: grid; grid-template-columns: minmax(180px, 1.1fr) 1fr 1fr; column-gap: var(--space-12); }
.sysreq .col-head { display: contents; }
.sysreq .col-head .cell {
  padding: 0 0 var(--space-4); border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-text-muted);
}
.sysreq .col-head .cell.rec { color: var(--color-accent); }
.sysreq .col-head .cell.spacer { color: transparent; }

.sysreq .row { display: contents; }
.sysreq .row .cell { padding: var(--space-6) 0; border-bottom: 1px solid var(--color-divider); font-size: var(--text-base); line-height: var(--leading-normal); }
.sysreq .row .label { font-weight: var(--weight-semibold); color: var(--color-text-primary); }
.sysreq .row .val { color: var(--color-text-secondary); }
.sysreq .row .pending { color: var(--color-text-muted); font-style: italic; }

.sysreq .note { margin: var(--space-16) 0 0; font-size: var(--text-sm); color: var(--color-text-muted); }

@media (max-width: 720px) {
  .sysreq .specs { display: block; margin-top: var(--space-10); }
  .sysreq .col-head { display: none; }
  .sysreq .row { display: block; padding: var(--space-5) 0; border-bottom: 1px solid var(--color-divider); }
  .sysreq .row .cell { padding: 0; border: 0; }
  .sysreq .row .label { font-size: var(--text-lg); margin-bottom: var(--space-3); }
  .sysreq .row .val, .sysreq .row .pending {
    display: flex; justify-content: space-between; gap: var(--space-4);
    padding: var(--space-2) 0; font-size: var(--text-sm);
  }
  .sysreq .row .val::before, .sysreq .row .pending::before {
    content: attr(data-tier);
    color: var(--color-text-muted); font-style: normal; font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wide); text-transform: uppercase; font-size: var(--text-xs); flex: none;
  }
}

/* ----- Responsive ------------------------------------------------------- */
@media (max-width: 720px) {
  .site-header__inner { flex-wrap: wrap; gap: var(--space-4); }
  .nav { gap: var(--space-4); }
  .site-footer__inner { grid-template-columns: 1fr 1fr; gap: var(--space-8); }
  .hero__sub { flex-direction: column; align-items: flex-start; gap: var(--space-4); }
  .app-cutout__frame { height: 80vh; }
}

/* ----- Scroll reveal (IntersectionObserver, time-based) ----------------- */
/* Why not animation-timeline: view()? A scroll-linked timeline measures each
   element's OWN travel through the scrollport, so it stalls or misfires when the
   element is sticky/pinned (the FAQ header) or lives inside a transformed or
   clipped scroll container (the "What we provide" box). A time-based transition
   triggered by IntersectionObserver ignores all of that: it just plays once when
   the element crosses into view, regardless of how the element is wrapped.
   The hidden start state applies ONLY under .reveal-ready, which a tiny inline
   <head> script adds to <html> exclusively when IntersectionObserver exists AND
   motion is allowed. So no-JS and reduced-motion users never see a hidden/stuck
   state. js/reveal.js then adds .is-in to each element as it enters (one-shot:
   once and stay). Animate opacity/transform only; never layout properties. */
.reveal-ready .reveal,
.reveal-ready .reveal-group > * {
  opacity: 0;
  transform: translateY(56px);
  transition: opacity 1s var(--ease-out), transform 1s var(--ease-out);
}
/* Opacity-only variant: for elements where a transform would fight existing
   layout or scroll logic (sticky targets, transformed/clipped containers). */
.reveal-ready .reveal--fade { transform: none; }
/* Revealed end state — transform resolves to none so nothing lingers to create
   a containing block (which is what would otherwise break a sticky descendant). */
.reveal-ready .reveal.is-in,
.reveal-ready .reveal-group > .is-in { opacity: 1; transform: none; }
/* Cascade for grouped rows/grids that enter together. */
.reveal-ready .reveal-group > :nth-child(2) { transition-delay: 0.07s; }
.reveal-ready .reveal-group > :nth-child(3) { transition-delay: 0.14s; }
.reveal-ready .reveal-group > :nth-child(4) { transition-delay: 0.21s; }
.reveal-ready .reveal-group > :nth-child(5) { transition-delay: 0.28s; }
/* The model page's capabilities list has six items; extend the cascade by one. */
.reveal-ready .reveal-group > :nth-child(6) { transition-delay: 0.35s; }

/* Home hero only: fade the header + subheader up at half speed (slowed 50%,
   1s -> 2s). Scoped to the home-hero-only classes so no other reveal changes. */
.reveal-ready .hero__title,
.reveal-ready .hero__sub { transition-duration: 2s; }

/* ==========================================================================
   Model page (/pages/our-model.html) — model-card / technical-doc register.
   Shares the warm page background and single clay accent; the technical feel
   comes from monospace metadata, hairline rules and spec tables, and a faint
   blueprint grid behind the identity header. Reuses global tokens throughout
   (mono = --font-mono); only the patterns below are page-specific.
   ========================================================================== */

/* Bracket placeholders (mirrors the .sysreq .pending treatment). */
.model-page .pending { color: var(--color-text-muted); font-style: italic; }

/* Monospace numbered eyebrow above each section heading — the page's main
   "this is technical" signal. */
.model-page .eyebrow {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: 0.08em;
  color: var(--color-accent); margin: 0 0 var(--space-3);
}

/* ----- Identity header -------------------------------------------------- */
/* Faint blueprint grid, behind the identity header only. */
.grid-bg {
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: 32px 32px;
}
.model-head { border-bottom: 1px solid var(--color-border); }
.model-head__inner {
  max-width: var(--container-max); margin: 0 auto;
  padding: var(--space-24) var(--space-6);
}
.model-head h1 { font-size: var(--text-5xl); margin: 0; }
.model-head .lead {
  margin: var(--space-4) 0 0; max-width: 64ch;
  font-size: var(--text-xl); line-height: var(--leading-normal);
  color: var(--color-text-secondary);
}
/* Monospace metadata row. */
.meta {
  display: flex; flex-wrap: wrap; gap: var(--space-8);
  margin: var(--space-8) 0 0; font-family: var(--font-mono); font-size: var(--text-sm);
}
.meta div { margin: 0; }
.meta dt {
  margin: 0; color: var(--color-text-muted);
  letter-spacing: 0.04em;
}
.meta dd {
  margin: var(--space-1) 0 0; color: var(--color-text-primary);
  font-weight: var(--weight-semibold);
}

/* ----- Documentation layout: sticky TOC rail + content column ----------- */
.doc {
  display: grid; grid-template-columns: 200px 1fr; gap: var(--space-16);
  max-width: var(--container-max); margin: 0 auto;
  /* 96px top + bottom on the grid itself: the top step pushes BOTH columns down
     a standard step (so the rail and the article start aligned), and the bottom
     step is the page's closing gap + the sticky TOC's breathing room. Putting the
     top offset here (not as a margin on .toc) is what lets the rail stay pinned
     to the bottom: a margin on a sticky element is part of its box and would make
     it release ~96px early. Same idea as the FAQ section's padding. */
  padding: var(--space-24) var(--space-6);
}
.toc {
  /* Lock 96px below the header divider, not right under it: clear the sticky
     header (--space-20) plus one standard step (--space-24). Same offset the FAQ
     intro uses. No margin here on purpose — see .doc padding above. */
  position: sticky; top: calc(var(--space-20) + var(--space-24)); align-self: start;
  font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.9;
}
/* Identical to the rail links: inherits the mono font (Menlo), --text-sm size,
   and --color-text-muted grey from .toc. A faint divider sits below it with
   identical spacing above and below the line: --space-4 padding = --space-4 margin. */
.toc .toc__label {
  margin: 0 0 var(--space-4); padding-bottom: var(--space-4);
  /* Divider sits a touch wider than the label text, not the full rail width. */
  width: 72%; border-bottom: 1px solid var(--color-divider);
  font-size: var(--text-sm); line-height: 1.9;
  color: var(--color-text-muted); letter-spacing: 0;
}
.toc a { display: block; color: var(--color-text-muted); text-decoration: none; }
.toc a.active { color: var(--color-accent); text-decoration: none; }

/* Shared section rhythm in the content column. */
.doc section { padding: var(--space-16) 0; border-top: 1px solid var(--color-divider); }
/* The 96px gap below the divider now comes from .doc's top padding (which pushes
   both columns down equally), so the first section starts flush with the rail —
   no extra top padding here. */
.doc section:first-child { border-top: 0; padding-top: 0; }
.doc h2 {
  font-size: var(--text-3xl); letter-spacing: var(--tracking-tight);
  margin: 0 0 var(--space-5);
}
.doc p {
  font-size: var(--text-lg); line-height: var(--leading-relaxed);
  color: var(--color-text-primary); max-width: 80ch;
}
.doc p + p { margin-top: var(--space-4); }

/* ----- Architecture: monospace pipeline block --------------------------- */
.pipe {
  margin: var(--space-6) 0 0; font-family: var(--font-mono); font-size: var(--text-sm);
  line-height: var(--leading-relaxed); color: var(--color-text-primary);
  background: var(--color-bg-chrome); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); padding: var(--space-5) var(--space-6);
  overflow-x: auto;
}
.pipe .dim { color: var(--color-text-muted); }

/* ----- Capabilities: hairline-separated definition list ----------------- */
.caps { margin: var(--space-6) 0 0; }
.caps > div {
  display: grid; grid-template-columns: 220px 1fr; gap: var(--space-6);
  padding: var(--space-4) 0; border-top: 1px solid var(--color-divider);
}
.caps dt { font-weight: var(--weight-semibold); color: var(--color-text-primary); }
.caps dd { margin: 0; color: var(--color-text-secondary); }
/* Scoped under .doc so it beats `.doc p` (which would otherwise win on specificity). */
.doc .caps-note { margin-top: var(--space-5); color: var(--color-text-muted); font-size: var(--text-sm); max-width: 80ch; }

/* ----- Longevity: three compounding factors, monospace labels ----------- */
.compound { list-style: none; margin: var(--space-6) 0 0; padding: 0; max-width: 80ch; }
.compound li {
  padding: var(--space-5) 0; border-top: 1px solid var(--color-divider);
  color: var(--color-text-secondary); line-height: var(--leading-relaxed);
}
.compound .key {
  display: block; margin-bottom: var(--space-2);
  font-family: var(--font-mono); font-size: var(--text-sm); letter-spacing: 0.04em;
  color: var(--color-accent);
}

/* ----- Limitations: plain hairline rows --------------------------------- */
.limits { list-style: none; margin: var(--space-6) 0 0; padding: 0; max-width: 80ch; }
.limits li {
  padding: var(--space-4) 0; border-top: 1px solid var(--color-divider);
  color: var(--color-text-secondary); line-height: var(--leading-relaxed);
}

/* ----- Specifications: monospace spec table ----------------------------- */
.spec { display: grid; grid-template-columns: 180px 1fr; margin: var(--space-6) 0 0; }
.spec dt {
  font-family: var(--font-mono); font-size: var(--text-sm);
  letter-spacing: 0.04em; color: var(--color-text-muted);
  padding: var(--space-4) 0; border-top: 1px solid var(--color-divider);
}
.spec dd {
  margin: 0; padding: var(--space-4) 0; border-top: 1px solid var(--color-divider);
  font-size: var(--text-base); color: var(--color-text-primary);
}

/* ----- Version history: changelog rail ---------------------------------- */
.log { border-left: 2px solid var(--color-border); padding-left: var(--space-6); margin-top: var(--space-6); }
.log-entry { padding: var(--space-2) 0 var(--space-6); }
.log .ver { margin: 0 0 var(--space-2); font-family: var(--font-mono); font-weight: var(--weight-bold); color: var(--color-text-primary); }
.log time { margin-left: var(--space-2); font-family: var(--font-mono); font-weight: var(--weight-regular); color: var(--color-text-muted); font-size: var(--text-sm); }
.log-entry p:last-child { margin: 0; color: var(--color-text-secondary); max-width: 80ch; }

/* ----- Close ------------------------------------------------------------ */
/* Drop the last section's own bottom padding so the closing gap is exactly the
   doc's 96px, not 64px + 96px stacked. */
.doc .model-close { padding-bottom: 0; }
.model-close__links { display: flex; align-items: center; gap: var(--space-6); margin-top: var(--space-6); }
/* Match the header's shorter Download button (its padding gives the bar height). */
.model-close__links .btn-primary { padding-block: var(--space-2); }
/* "System requirements" is the shared small text CTA (.btn-learn-more: hover
   reveals the up-right arrow, no underline), kept in the page's mono register. */
.model-close__req { font-family: var(--font-mono); font-size: var(--text-sm); padding-right: 0; }
/* Arrow spacing modeled on the footer links: the arrow is inline and always
   reserves its space (so the label never moves), sits a --space-2 gap after the
   text, and just fades in on hover. Nothing slides. */
.model-close__req:hover .btn__label,
.model-close__req:focus-visible .btn__label,
.model-close__req:active .btn__label { transform: none; }
.model-close__req::after {
  position: static; top: auto; right: auto;
  margin-left: var(--space-2); transform: none;
}
.model-close__req:hover::after,
.model-close__req:focus-visible::after,
.model-close__req:active::after { opacity: 1; transform: none; }

/* ----- Mobile: single column, TOC hidden -------------------------------- */
@media (max-width: 880px) {
  .model-head__inner { padding: var(--space-16) var(--space-6) var(--space-12); }
  .doc { grid-template-columns: 1fr; gap: 0; padding: 0 var(--space-6); }
  .toc { display: none; }
  .caps > div { grid-template-columns: 1fr; gap: var(--space-1); }
  .spec { grid-template-columns: 1fr; }
  .spec dt { padding-bottom: 0; }
  .spec dd { padding-top: var(--space-2); border-top: 0; }
}

/* ==========================================================================
   About page (/about) — plain, conventional About Us page. A title and three
   paragraphs in a comfortable reading column (~70ch measure). No motion, no
   full-bleed, no banded sections, no dividers. Tokens only, so every value
   resolves in light and dark.
   ========================================================================== */
.about { max-width: var(--container-narrow); margin-inline: auto; padding: var(--space-24) var(--space-6); }
.about__title {
  margin: 0;
  font-size: var(--text-4xl); font-weight: var(--weight-bold);
  line-height: var(--leading-tight); letter-spacing: var(--tracking-tight);
  color: var(--color-text-primary);
}
.about__p {
  max-width: 70ch; margin: var(--space-6) 0 0;
  font-size: var(--text-lg); line-height: var(--leading-relaxed);
  color: var(--color-text-primary);
}

/* ----- Data / methodology page ------------------------------------------ */
/* Constrained reading column (same --container-narrow as the legal/prose pages):
   a title, one methodology paragraph, two quietly hairline-grouped company lists,
   then an "as of" footnote. No cards, no hype. */
.data-page { max-width: var(--container-narrow); margin-inline: auto; padding: var(--space-24) var(--space-6); }
.data-page__title { font-size: var(--text-4xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); color: var(--color-text-primary); margin: 0; }
.data-page__lead { font-size: var(--text-lg); color: var(--color-text-secondary); line-height: var(--leading-normal); margin: var(--space-6) 0 0; }

.data-page__lists { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-12); margin-top: var(--space-16); }
/* Heading in the small label register (sentence case), over a faint divider. */
.data-list__heading { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-muted); margin: 0 0 var(--space-4); padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-divider); }
.data-list ul { list-style: none; margin: 0; padding: 0; }
/* Company names in body weight, separated by hairlines rather than boxed cards. */
.data-list li { font-size: var(--text-base); color: var(--color-text-primary); padding: var(--space-3) 0; border-top: 1px solid var(--color-divider); }
.data-list li:first-child { border-top: 0; }

.data-page__footnote { font-size: var(--text-sm); color: var(--color-text-muted); line-height: var(--leading-normal); margin: var(--space-16) 0 0; }

@media (max-width: 720px) {
  .data-page__lists { grid-template-columns: 1fr; gap: var(--space-10); }
}

/* ----- "The toolset" bento grid (home, under the demo) ------------------ */
/* Five tools: one 2x2 anchor + four 1x1 supporting cells. Size encodes
   importance. All values from tokens; off-white/off-black surfaces (never pure),
   low-contrast hairline, one accent (chips + hover), consistent 16px gutter. */
.toolset__title { font-size: var(--text-4xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); color: var(--color-text-primary); margin: 0; }
.toolset__intro { font-size: var(--text-lg); color: var(--color-text-secondary); line-height: var(--leading-normal); max-width: 60ch; margin: var(--space-4) 0 var(--space-12); }

.toolset__grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 1fr; gap: var(--space-4); }

/* Full-width, thin free-tools strip below the bento grid. Same card surface as
   the cells, but compact (title + one-line description) so it reads as a slim
   band rather than another tall box. No image. */
.toolset__free {
  margin-top: var(--space-4);
  padding: var(--space-5) var(--space-6);
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.toolset__free-title { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--color-text-primary); line-height: var(--leading-snug); margin: 0; }
.toolset__free-desc { font-size: var(--text-base); color: var(--color-text-secondary); line-height: var(--leading-normal); margin: var(--space-2) 0 0; }
.toolset__cell {
  display: flex; flex-direction: column;
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  overflow: hidden;
}
.toolset__cell--anchor { grid-column: 1 / span 2; grid-row: 1 / span 2; }

.toolset__media { aspect-ratio: 3 / 2; margin-bottom: var(--space-4); border-radius: var(--radius-md); overflow: hidden; background: var(--color-bg-sunken); }
.toolset__cell--anchor .toolset__media { aspect-ratio: 16 / 10; }
.toolset__img { width: 100%; height: 100%; object-fit: cover; display: block; }

.toolset__name { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--color-text-primary); line-height: var(--leading-snug); margin: 0 0 var(--space-2); }
.toolset__cell--anchor .toolset__name { font-size: var(--text-2xl); }
.toolset__desc { font-size: var(--text-base); color: var(--color-text-secondary); line-height: var(--leading-normal); margin: 0; }

/* The anchor's extra height becomes breathing room + the full 16-style chip set
   at the bottom, not more copy. */
.toolset__chips { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; padding: 0; margin: var(--space-6) 0 0; }
.toolset__cell--anchor .toolset__chips { margin-top: auto; }
.toolset__chip { font-size: var(--text-xs); font-weight: var(--weight-medium); padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); background: var(--color-accent-tint); color: var(--color-accent); box-shadow: inset 0 0 0 1px var(--color-border); }

@media (prefers-reduced-motion: no-preference) {
  .toolset__cell, .toolset__free { transition: transform var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out); }
  .toolset__cell:hover, .toolset__free:hover { transform: translateY(-2px); border-color: var(--color-accent); box-shadow: var(--shadow-md); }
}

/* Tablet: 2-col; anchor spans the full row, the four supporting cells form a
   2x2 block below. */
@media (max-width: 1024px) {
  .toolset__grid { grid-template-columns: repeat(2, 1fr); }
  .toolset__cell--anchor { grid-column: 1 / span 2; grid-row: auto; }
  .toolset__cell--anchor .toolset__media { aspect-ratio: 5 / 2; }
}
/* Mobile: single column, stacked in importance order (DOM order already is). */
@media (max-width: 640px) {
  .toolset__grid { grid-template-columns: 1fr; }
  .toolset__cell--anchor { grid-column: 1; }
  .toolset__cell--anchor .toolset__media { aspect-ratio: 3 / 2; }
}

/* ----- Stub destinations (wired, built later) --------------------------- */
.stub { min-height: 60vh; display: grid; place-items: center; text-align: center; }
.stub__inner { max-width: 42ch; }
.stub__title { font-size: var(--text-4xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); margin: 0 0 var(--space-4); }
.stub__body { font-size: var(--text-lg); color: var(--color-text-secondary); line-height: var(--leading-relaxed); margin: 0; }

/* ----- Pricing page ----------------------------------------------------- */
.pricing__head { max-width: 56ch; margin-inline: auto; text-align: center; }
.pricing__title { font-size: var(--text-5xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); text-wrap: balance; margin: 0; }
.pricing__lead { margin: var(--space-5) auto 0; }
.pricing__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-5); margin-top: var(--space-16); align-items: stretch; }
.pricing-card { position: relative; display: flex; flex-direction: column; background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-6); }
.pricing-card--featured { border-color: var(--color-accent); box-shadow: var(--shadow-md); }
.pricing-card__badge { position: absolute; top: 0; right: var(--space-5); transform: translateY(-50%); background: var(--color-accent); color: var(--color-on-accent); font-size: var(--text-xs); font-weight: var(--weight-semibold); padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); }
.pricing-card__name { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--color-text-primary); margin: 0; }
.pricing-card__price { display: flex; align-items: baseline; gap: var(--space-2); margin: var(--space-4) 0 0; flex-wrap: wrap; }
.pricing-card__amount { font-size: var(--text-4xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--color-text-primary); }
.pricing-card__was { font-size: var(--text-base); color: var(--color-text-muted); text-decoration: line-through; margin-right: var(--space-2); }
.pricing-card__period { font-size: var(--text-sm); color: var(--color-text-muted); }
.pricing-card__cap { margin: var(--space-4) 0 0; font-size: var(--text-base); font-weight: var(--weight-medium); color: var(--color-text-primary); }
.pricing-card__cap-label { display: block; font-size: var(--text-xs); font-weight: var(--weight-regular); color: var(--color-text-muted); margin-bottom: var(--space-1); }
.pricing-card__blurb { margin: var(--space-4) 0 var(--space-6); font-size: var(--text-sm); color: var(--color-text-secondary); line-height: var(--leading-normal); }
.pricing-card__cta { margin-top: auto; width: 100%; }
/* The card for the signed-in user's current plan: a non-interactive marker, not
   a button. */
.pricing-card__cta--current { margin-top: auto; width: 100%; display: inline-flex; align-items: center; justify-content: center; padding: var(--space-3) var(--space-6); font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-muted); border: 1px dashed var(--color-border-strong); border-radius: var(--radius-pill); }
/* A tier beneath the user's current plan: same muted, dashed, non-actionable
   pill as "your current plan" (the label is the only difference). */
.pricing-card__cta--included { margin-top: auto; width: 100%; display: inline-flex; align-items: center; justify-content: center; padding: var(--space-3) var(--space-6); font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-muted); border: 1px dashed var(--color-border-strong); border-radius: var(--radius-pill); cursor: default; }
@media (max-width: 1000px) { .pricing__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .pricing__grid { grid-template-columns: 1fr; } }

/* ----- "Every plan includes" — animated word-wheel section --------------- */
/* Replaces the old static checklist. A slot-machine headline (RotatingWord) over
   four token-driven animated cards. One page background; accent appears only as
   the rotating word + the highlight note inside each card visual. Every value is
   a token so both themes and reduced motion resolve automatically. */
.plan-includes { margin-top: var(--space-20); padding-top: var(--space-16); border-top: 1px solid var(--color-divider); }
/* Left-aligned, single-line headline. white-space: nowrap keeps
   "The world's top <rotating> model." on one line while the wheel's width
   animates the trailing "model." horizontally; it wraps only on narrow screens. */
.plan-includes__head { max-width: none; }
.plan-includes__title { font-size: var(--text-5xl); font-weight: var(--weight-bold); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); white-space: nowrap; margin: 0; }
.plan-includes__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-5); margin-top: var(--space-12); align-items: stretch; }
/* Bottom note + real "Get in touch" button, left-aligned to match the header. */
.plan-includes__note { margin: var(--space-10) 0 0; display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; font-size: var(--text-sm); color: var(--color-text-muted); }
/* "Get in touch": a plain neutral text button, grey at rest and black on hover,
   with no arrow and no other hover effect. Built on the shared .btn base (so it
   stays unselectable, keyboard-focusable, and press-shrinks like every button),
   but with its own neutral ghost color and the two things every .btn otherwise
   adds on hover suppressed: the arrow (::after, as .faq__expand does) and the
   label nudge (as .contact__submit does). Grey -> black is the whole hover. */
.plan-includes__contact { background: none; border: none; color: var(--color-text-secondary); font-weight: var(--weight-regular); font-size: var(--text-sm); padding: var(--space-2) 0; border-radius: var(--radius-sm); }
.plan-includes__contact:hover, .plan-includes__contact:focus-visible { color: var(--color-text-primary); }
.plan-includes__contact::after { content: none; }
.plan-includes__contact:hover .btn__label,
.plan-includes__contact:focus-visible .btn__label,
.plan-includes__contact:active .btn__label { transform: none; }

.plan-card { display: flex; flex-direction: column; overflow: hidden; background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); transition: transform var(--duration-base) var(--ease-out), box-shadow var(--duration-base) var(--ease-out), border-color var(--duration-base) var(--ease-out); }
.plan-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--color-border-strong); }
.plan-card__stage { position: relative; height: 148px; overflow: hidden; border-bottom: 1px solid var(--color-border); background: linear-gradient(180deg, var(--color-bg-subtle), var(--color-bg-surface)); }
.plan-card__body { padding: var(--space-5); }
.plan-card__title { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--color-text-primary); margin: 0; }
.plan-card__desc { margin: var(--space-2) 0 0; font-size: var(--text-sm); color: var(--color-text-secondary); line-height: var(--leading-normal); }

/* Each visual centers itself in the stage; absolutely-positioned overlays
   (arcs, rings, the upload arrow) are centered by place-items and animate on top. */
.pi-viz { position: absolute; inset: 0; display: grid; place-items: center; }
.pi-glyph { position: relative; z-index: 1; }

/* Card 1 — all six tools: a 2x3 tile grid, an accent sweep travelling across the
   tiles so "six tools, chain or use one" reads at a glance. Fill-only, so smooth. */
.pi-suite { width: 52px; height: 52px; }
/* Slow, calm sweep to match the palette/cloud tempo (per-tile stagger set inline
   in SuiteGlyph). */
.pi-suite rect { fill: var(--color-border-strong); animation: pi-suite 5.2s var(--ease-out) infinite; }
@keyframes pi-suite {
  0%, 55%, 100% { fill: var(--color-border-strong); }
  22%, 34% { fill: var(--color-accent); }
}

/* Card 2 — every staging style: a Lucide palette swaying gently while its paint
   wells light to accent in sequence. */
.pi-viz--styles { color: var(--color-text-secondary); }
.pi-palette { width: 52px; height: 52px; transform-origin: 50% 64%; animation: pi-sway 4.6s ease-in-out infinite; }
.pi-palette .pi-well { stroke: none; fill: var(--color-text-muted); animation: pi-well 3.6s var(--ease-out) infinite; }
@keyframes pi-sway {
  0%, 100% { transform: rotate(-6deg); }
  50% { transform: rotate(6deg); }
}
@keyframes pi-well {
  0%, 55%, 100% { fill: var(--color-text-muted); }
  22% { fill: var(--color-accent); }
}

/* Card 3 — runs in the cloud: a Lucide cloud drifting gently while short wind
   streaks blow past beneath it. The streaks (muted accent) are this card's
   signature, so it no longer echoes the privacy card's concentric rings. */
.pi-viz--cloud { color: var(--color-text-secondary); }
.pi-cloud { width: 62px; height: 62px; animation: pi-cloud-drift 6s ease-in-out infinite; }
/* Streaks distributed all around the cloud (above, beside, below at varied
   heights) so the breeze reads as passing through the whole cloud, not just
   under it. They sit behind the cloud (default z below .pi-glyph) so some blow
   past behind it. */
.pi-wind { position: absolute; height: 2px; border-radius: var(--radius-pill); background: var(--color-accent); opacity: 0; }
.pi-wind--1 { width: 14px; top: 30%; left: 41%; animation: pi-wind 4.4s ease-in-out infinite; }
.pi-wind--2 { width: 20px; top: 42%; left: 29%; animation: pi-wind 4.4s ease-in-out infinite 0.9s; }
.pi-wind--3 { width: 12px; top: 53%; left: 57%; animation: pi-wind 4.4s ease-in-out infinite 1.8s; }
.pi-wind--4 { width: 18px; top: 65%; left: 33%; animation: pi-wind 4.4s ease-in-out infinite 0.45s; }
.pi-wind--5 { width: 14px; top: 75%; left: 46%; animation: pi-wind 4.4s ease-in-out infinite 1.35s; }
@keyframes pi-cloud-drift {
  0%, 100% { transform: translateX(-2.5px); }
  50% { transform: translateX(2.5px); }
}
@keyframes pi-wind {
  0% { transform: translateX(-9px); opacity: 0; }
  35% { opacity: 0.5; }
  65% { opacity: 0.5; }
  100% { transform: translateX(13px); opacity: 0; }
}

/* Card 4 — your images stay private: a Lucide lock inside two rings that breathe
   outward, the lock glowing softly on each beat. */
.pi-viz--privacy { color: var(--color-accent); }
/* Slow, calm breathing to match the palette/cloud tempo. */
.pi-lock { width: 46px; height: 46px; animation: pi-lock 5s var(--ease-out) infinite; }
.pi-ring { position: absolute; border-radius: var(--radius-pill); border: 1.5px solid var(--color-accent); opacity: 0.15; }
.pi-ring--1 { width: 78px; height: 78px; animation: pi-ring 5s var(--ease-out) infinite; }
.pi-ring--2 { width: 110px; height: 110px; animation: pi-ring 5s var(--ease-out) infinite 0.8s; }
@keyframes pi-ring {
  0%, 100% { transform: scale(0.85); opacity: 0.12; }
  50% { transform: scale(1.05); opacity: 0.45; }
}
@keyframes pi-lock {
  0%, 100% { filter: none; }
  50% { filter: drop-shadow(0 0 8px var(--color-focus-ring)); }
}

@media (prefers-reduced-motion: reduce) {
  .pi-suite rect, .pi-palette, .pi-palette .pi-well, .pi-cloud, .pi-wind, .pi-ring, .pi-lock { animation: none; }
  .pi-palette, .pi-cloud { transform: none; }
  .pi-ring { opacity: 0.3; }
  .pi-wind { opacity: 0.5; transform: none; }
}

@media (max-width: 1000px) { .plan-includes__grid { grid-template-columns: repeat(2, 1fr); } }
/* The one-line (nowrap) headline needs ~1032px of container width for the
   longest rotating word ("furniture removal"); below that let it wrap to two
   lines instead of overflowing the container. */
@media (max-width: 1040px) { .plan-includes__title { white-space: normal; } }
@media (max-width: 560px) { .plan-includes__grid { grid-template-columns: 1fr; } }

/* ----- Auth screens (sign in / up, password reset, verify) -------------- */
/* A single narrow card shared by every auth route + the modal. The card is a
   flex column with ONE rhythm token between every block (title, subtitle, form,
   helper row, footer), so every screen lines up identically — no per-element
   margins to drift out of sync. Reuses the canonical .form / .field /
   .form__status system. */
.auth { min-height: 70vh; display: grid; place-items: center; padding-block: var(--space-16); }
.auth__card { width: 100%; max-width: 30rem; display: flex; flex-direction: column; gap: var(--space-5); }
.auth__title { font-size: var(--text-3xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); margin: 0; }
/* The subtitle pairs tightly with its title, so it pulls up under the gap. */
.auth__subtitle { font-size: var(--text-base); color: var(--color-text-secondary); line-height: var(--leading-normal); margin: calc(-1 * var(--space-3)) 0 0; }
/* The form is itself a flex column on the same rhythm; drop .form's page margin
   + narrow cap inside the card. */
.auth__card .form { max-width: none; margin-top: 0; gap: var(--space-4); }
.auth__submit { align-self: stretch; margin-top: var(--space-1); }
/* Helper row under the password field: forgot-password left, remember-me right. */
.auth__helper-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); font-size: var(--text-sm); }
/* Remember-me: a real checkbox + label, accent-tinted to match the brand. */
.auth__remember { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--color-text-secondary); font-weight: var(--weight-medium); cursor: pointer; user-select: none; }
.auth__remember input { width: 1rem; height: 1rem; accent-color: var(--color-accent); cursor: pointer; }
/* Footer cross-link row. Centered single link by default (create-account /
   back-to-sign-in). */
.auth__links { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted); }
.auth__links a, .auth__link-btn { color: var(--color-text-secondary); font-weight: var(--weight-medium); }
.auth__links a:hover, .auth__link-btn:hover { color: var(--color-text-primary); }
/* Confirmation / status panel state (check-your-email, verifying, done). */
.auth__note { font-size: var(--text-base); color: var(--color-text-secondary); line-height: var(--leading-relaxed); margin: 0; }
.auth__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
/* A cross-link rendered as a button (modal mode) reads exactly like the link. */
.auth__link-btn { background: none; border: none; padding: 0; font: inherit; cursor: pointer; }

/* ----- Auth modal (centered popup over the current page) ----------------- */
/* Lock body scroll while a modal is open WITHOUT a layout shift: the gutter is
   always reserved so removing the scrollbar never reflows the page ~15px. */
html { scrollbar-gutter: stable; }
html.is-modal-open { overflow: hidden; }
/* Backdrop fills the viewport and centers the panel. */
.auth-modal { position: fixed; inset: 0; z-index: var(--z-modal); display: grid; place-items: center; padding: var(--space-6); background: color-mix(in srgb, var(--color-text-primary) 45%, transparent); }
/* The panel reuses the .auth__card system inside; this is just the surface. */
.auth-modal__panel { position: relative; width: 100%; max-width: 30rem; max-height: calc(100dvh - var(--space-12)); overflow-y: auto; background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-xl); padding: var(--space-8); }
.auth-modal__panel:focus { outline: none; }
.auth-modal__panel .auth__card { max-width: none; }
.auth-modal__close { position: absolute; top: var(--space-4); right: var(--space-4); display: inline-grid; place-items: center; width: 2rem; height: 2rem; border: none; border-radius: var(--radius-pill); background: none; color: var(--color-text-muted); cursor: pointer; transition: var(--transition-base); }
.auth-modal__close:hover { background: var(--color-bg-subtle); color: var(--color-text-primary); }
.auth-modal__close:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }

/* A narrower container variant for single-column pages (the dashboard). */
.container--narrow { max-width: var(--container-narrow); }

/* Destructive button: same shape as the others, error palette. */
.btn-danger { background: var(--color-error); color: #fff; padding: var(--space-3) var(--space-6); border-radius: var(--radius-pill); }
.btn-danger:hover { background: color-mix(in srgb, var(--color-error) 88%, black); }
.btn-danger[disabled], .btn-danger[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

/* ----- Account dashboard ------------------------------------------------- */
.dash { display: flex; flex-direction: column; gap: var(--space-8); padding-block: var(--space-8); }
.dash__title { font-size: var(--text-4xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); margin: 0; }
.dash__panel { border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-8); display: flex; flex-direction: column; gap: var(--space-4); }
.dash__h { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-muted); margin: 0; }
.dash__tier { font-size: var(--text-2xl); font-weight: var(--weight-semibold); margin: 0; }
.dash__usage { font-size: var(--text-lg); margin: 0; }
.dash__muted { font-size: var(--text-sm); color: var(--color-text-muted); margin: 0; }
.dash__hint { margin-top: calc(-1 * var(--space-2)); }
.dash__cap { margin-top: var(--space-2); }
/* Usage meter. */
.dash__bar { height: 8px; border-radius: var(--radius-pill); background: var(--color-bg-subtle); overflow: hidden; }
.dash__bar-fill { display: block; height: 100%; background: var(--color-accent); border-radius: var(--radius-pill); }
.dash__actions, .dash__settings-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-2); }
/* Billing history table. */
.dash__history { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.dash__history th { text-align: left; font-weight: var(--weight-medium); color: var(--color-text-muted); padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border); }
.dash__history th:last-child, .dash__history td:last-child { text-align: right; }
.dash__history td { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border); color: var(--color-text-primary); }
.dash__history tr:last-child td { border-bottom: 0; }
.dash__field { display: flex; flex-direction: column; gap: 2px; margin: 0; }
.dash__field-label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-secondary); }
.dash__field-value { font-size: var(--text-base); color: var(--color-text-primary); }
/* Danger zone. */
.dash__danger { border-color: color-mix(in srgb, var(--color-error) 40%, var(--color-border)); }
.dash__confirm { display: flex; flex-direction: column; gap: var(--space-4); margin-top: var(--space-2); }
.dash__confirm-title { font-size: var(--text-lg); font-weight: var(--weight-semibold); margin: 0; }
.dash__gate { padding-block: var(--space-16); display: flex; flex-direction: column; align-items: center; gap: var(--space-5); text-align: center; }
