
/* ============ SECTION ORDER: nav, hero, after-hero (plan, ambassadors),
   industries, testimonials, dfy (Done for you: the white-water chapter),
   site (The AI Visibility Website: isometric stack), founder, faq, proof,
   footer. ============ */
/* ============ GLOBAL TOKENS (variant palette declaration: warm-neutral charcoal
   scale #131312 / #161615 / #1B1B19 and true black #000000 at the deepest end
   on dark; paper-white scale on light (the working theme); ink-scale type
   family. Periwinkle is the single accent. The budget is relaxed on the light
   theme: periwinkle may appear in more places, but always as motion or state
   (pulse, swipe, active, rotating word), never as static decoration.
   Deployments: swarm convergence lines (pulsing after the settle), the
   rotating word in the services intro, the button swipe sheet, the lit
   industry's glow in the industries bar, the demo panel (count, active
   question number, active tab underline, timing rule, capture dot,
   ghost-slot ring), the services pour's category eyebrows and the page
   ending's lava-lamp field under the footer. Ending-field tones
   (three tones of the one hue, used nowhere else; round-14 dark triad,
   confirmed by the round-20 single-hue ruling): #416CD7 deeper, #5C90FF
   base, #ADC6FF paler; zero navy, zero cream, zero gold. Fonts: Switzer only (display surfaces at
   600, everything else 400/500). ============ */
:root{
  --r-card:14px;   /* the one card radius (round 38 token): dfy cards + expansions, the proof stage */
  --field:#131312; --field-2:#161615; --field-3:#1B1B19; --field-deep:#000000;
  --lt:#F2F1EC; --lt-2:#C7C5BE; --lt-3:#918F87;
  --hair:rgba(242,241,236,0.09); --hair-strong:rgba(242,241,236,0.2);
  --ink-rgb:242,241,236;   /* the "ink" pole: what text is made of */
  --paper-rgb:19,19,18;    /* the "paper" pole: what the field is made of */
  --ink-filter:none;       /* baked-light assets (marks, atom, lockup) invert where ink is dark */
  --peri:#5C90FF; --peri-soft:rgba(92,144,255,0.55);
  --peri-dark: var(--peri); /* ROUND 20 (Mark's escalation): the old base hue read purple on light fields too, so the hue itself is rejected. One blue, #5C90FF, on both grounds. --peri-dark survives as a var alias (a sanctioned one-off indirection: both tokens are theme-invariant and declared only here, so the no-token-references-a-token palette rule's re-resolution hazard cannot occur) so any future divergence is a one-line change. Dial: if the blue reads too electric, walk toward #6693FF. */
  /* keep --peri, --peri-soft and --peri-dark in sync with site/site.css's token block */
  --navy:#0B1B3F;   /* theme-invariant: the nav bar after the tide, the dfy card surfaces */
  color-scheme:dark;
  --ease:cubic-bezier(0.16,1,0.3,1);
  --ease-soft:cubic-bezier(0.22,1,0.36,1);
  --font:'Switzer',Arial,sans-serif;
  /* display register: Switzer 600. The token keeps its historical name. */
  --serif:'Switzer',Arial,sans-serif;
  --t-hero:clamp(2.7rem,4.6vw,4.5rem);
  --t-disp2:clamp(2.1rem,4vw,3.5rem);
  --t-quote:clamp(1.5rem,2.4vw,2.25rem);
  --t-ask:clamp(1.35rem,2.4vw,2.05rem);
  --t-lede:1.1rem;
  --t-lede-lg:clamp(1.3rem,1.55vw,1.55rem);
  --t-body:1rem;
  --t-small:0.85rem;
  --t-label:0.72rem;
  --t-link:0.85rem;
  --t-idx:0.85rem;
  --t-quiet:0.95rem;
  --t-entity:0.95rem;
  --w-4:400; --w-5:500; --w-6:600;
  --lh-disp:1.02; --lh-head:1.15; --lh-sub:1.3; --lh-body:1.65; --lh-solid:1;
  --track:0.22em; --track-serif:-0.025em; --track-h3:-0.01em;
  --gutter:5vw;
  --w-max:1400px;
  --sec-pad:8rem;
}
/* THEMING. Every color resolves through the tokens above. data-theme on
   <html> sets the page; data-theme on any <section>/<footer> re-themes that
   section (custom properties inherit, so everything inside re-resolves).
   --peri, --peri-soft and --peri-dark are theme-invariant; shadows stay
   black. ROUND-14 RULE (founder perception ruling): periwinkle has two
   homes: dark grounds always use --peri-dark, light fields keep --peri. */
[data-theme="dark"]{
  --field:#131312; --field-2:#161615; --field-3:#1B1B19; --field-deep:#000000;
  --lt:#F2F1EC; --lt-2:#C7C5BE; --lt-3:#918F87;
  --hair:rgba(242,241,236,0.09); --hair-strong:rgba(242,241,236,0.2);
  --ink-rgb:242,241,236;
  --paper-rgb:19,19,18;
  --ink-filter:none;
  --navy:#0B1B3F;
  color-scheme:dark;
}
[data-theme="light"]{
  --field:#F4F3EF; --field-2:#FFFFFF; --field-3:#ECEBE6; --field-deep:#FFFFFF;
  --lt:#141413; --lt-2:#3A3A37; --lt-3:#6B6B66;
  --hair:rgba(20,20,19,0.10); --hair-strong:rgba(20,20,19,0.22);
  --ink-rgb:20,20,19;
  --paper-rgb:244,243,239;
  --ink-filter:invert(1) hue-rotate(180deg);
  --navy:#0B1B3F;
  color-scheme:light;
}
/* a themed section restarts color inheritance from its own tokens */
[data-theme]{color:var(--lt)}
*{margin:0;padding:0;box-sizing:border-box}
/* Webflow-proof list reset (round 28, the staging industries wrap): on a
   published Webflow page the base sheet styles ul,ol (padding-left:40px;
   margin-bottom:10px) at type specificity 0,0,1, which outranks the
   universal reset above no matter the order - 27 of home's 30 lists
   rendered with that padding on staging, and the stolen 40px is what
   wrapped the industries row. html ul is 0,0,2 and wins by specificity,
   not order; locally a no-op. Keep in sync with site/site.css. */
html ul,html ol{margin:0;padding:0}
/* Webflow-proof element defaults (round 30, the full base-sheet exposure
   sweep): the round-28 mechanism applied to every remaining exposure
   measured live-vs-source across all 28 poured pages at 1440 under
   fonts.ready. Webflow's published-page base sheet styles bare elements at
   type specificity (0,0,1), outranking the universal reset (0,0,0)
   regardless of order; every declaration below restates the reset, the UA
   default, or an inert value at 0,0,2+ so it is a LOCAL NO-OP that wins on
   the published page, and any class rule (0,1,0+) still overrides. The two
   deliberate value pins are marked. Keep in sync with site/site.css. */
html h1,html h2,html h3,html h4,html h5,html h6,html p{margin:0}   /* Webflow: heading margin-top 20/10px + margin-bottom 10px; p margin-bottom 10px - the systemic theft under every unclassed heading/paragraph (960+ p's, 340+ h2/h3's measured) */
html h1{font-size:2em}html h2{font-size:1.5em}html h3{font-size:1.17em}html h4{font-size:1em}html h5{font-size:.83em}html h6{font-size:.67em}   /* UA values; Webflow pins px sizes (its h1 38px hit the home hero's bare h1 wrapper) */
html h4,html h5,html h6{line-height:inherit}   /* Webflow 24/20/18px (hit websites' rj-footer h4); inherit - NOT normal - restores natural inheritance exactly (rj-footer's number line-height flows in), so it is a true local no-op; h1-h3 keep the global --lh-head rule, which beats Webflow's same-specificity line-height by order */
html blockquote{margin:0;padding:0;border-left:0;font-size:inherit;line-height:inherit}   /* Webflow: 5px #e2e2e2 bar + 10px 20px padding + margin-bottom 10px + 18px/22px type - the founder-quote gray bar; the 18px also inflated em-based widths (cs-quote max-width 44em) */
html img{vertical-align:baseline}   /* Webflow: middle; inert on display:block imgs, pinned for computed parity */
html button,html [type="button"],html [type="reset"]{appearance:auto}   /* Webflow: -webkit-appearance:button on button (0,0,1) AND on [type=button]/[type=reset] (0,1,0), so the guard needs both forms (0,0,2 / 0,1,1) - every chrome/faq/quiz button carries type="button". Rendering-inert under the button reset. (Webflow's html input[type=button] is 0,1,2 and would still win on an input[type=button]; none rendered.) */
html pre{overflow:visible}   /* Webflow: auto - a nested-scrollbar risk (hit websites' x-ray code panel); .post-code pre keeps its own overflow-x:auto at 0,1,1 */
/* NOTE, not a rule here: Webflow's svg:not(:root){overflow:hidden} (0,1,1) matches the UA default, so plain svgs are fine - but it BEATS any 0,1,0 class that sets overflow:visible on an svg (hit websites' .aml-overlay; guarded in websites.html with html svg.aml-overlay). A blanket svg neutralization is wrong: it would flip every plain svg's UA hidden to visible locally. */
html table{border-spacing:0}   /* VALUE PIN: local computed goes 2px->0 on the three table pages, inert because every rendered table sets border-collapse:collapse */
html body{min-height:auto}   /* Webflow: 100% */
:root{height:auto;font-family:var(--font);-webkit-text-size-adjust:100%;text-size-adjust:100%}   /* Webflow html: height 100%, sans-serif, text-size-adjust 100%. height and font-family restored to source semantics; text-size-adjust is the second VALUE PIN - Webflow's 100% is the normalize-standard value live users have had since launch, inert under the viewport meta on every page */
html{scroll-behavior:smooth;overflow-x:hidden}   /* belt against horizontal overflow (on html only: on body too it would make body a scroll container and break the sticky pins) */
@media (prefers-reduced-motion: reduce){html{scroll-behavior:auto}}
[id]{scroll-margin-top:calc(87px + 1.4rem)}   /* anchor targets clear the fixed nav (87px rendered .nav-bar height) with breathing room; round 16, keep in sync with site/site.css */
body{font-family:var(--font);font-size:var(--t-body);font-weight:var(--w-4);line-height:var(--lh-body);color:var(--lt);background:var(--field)}
img,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;background:none;border:0;cursor:pointer;color:inherit}
h1,h2,h3{line-height:var(--lh-head);text-wrap:balance}
:focus-visible{outline:2px solid var(--peri);outline-offset:3px}   /* keyboard focus only; there is no :focus outline anywhere, so a click never draws a box */
/* the two-home periwinkle rule applied to focus: dark scopes take the
   on-dark variant; a light panel nested INSIDE a dark scope (the mega, the
   narrow menu) restores the base accent via the higher-specificity nested
   rule (the page root is data-theme="light", so a bare light rule would
   outrank the dark one everywhere; cause on record, round 14) */
[data-theme="dark"] :focus-visible{outline-color:var(--peri-dark)}
[data-theme="dark"] [data-theme="light"] :focus-visible{outline-color:var(--peri)}
.wrap{max-width:var(--w-max);margin:0 auto;padding-left:var(--gutter);padding-right:var(--gutter)}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* quiet section label: the steno register's minimal h2 - body-scale, sentence
   case, never letterspaced uppercase (spends no eyebrow budget) */
.quiet-h2{font-size:var(--t-quiet);font-weight:var(--w-5);letter-spacing:0;color:var(--lt-3)}
.lede{font-size:var(--t-lede);color:var(--lt-2);max-width:34em}
/* eyebrow rule (in force): an eyebrow renders only when it adds information
   its heading does not carry (a category, a number, an orientation cue);
   one that restates its heading is deleted. Uniform treatment when present. */
.eyebrow{font-size:var(--t-small);letter-spacing:0.12em;text-transform:uppercase;color:var(--peri);margin-bottom:1rem}
[data-theme="dark"] .eyebrow{color:var(--peri-dark)}   /* the two-home periwinkle rule (the site section's "The product" rides this) */
/* engine marks: plain img elements from the pre-tinted LIGHT-glyph PNG set
   (every surface here is on the charcoal scale). Scale floor: 20px labels,
   26px in the hero swarm (modest featured scale per directive). Sanctioned
   hover bounce with focus parity, none under reduced motion. */
.eng-mark{display:inline-block;flex:none;width:20px;height:20px;object-fit:contain}
@keyframes mark-bounce{0%{transform:none}40%{transform:translateY(-5px)}70%{transform:translateY(1px)}100%{transform:none}}
@media (hover:hover){.eng-mark:hover{animation:mark-bounce 0.5s var(--ease)}}
a:focus-visible .eng-mark,button:focus-visible .eng-mark,[tabindex]:focus-visible .eng-mark{animation:mark-bounce 0.5s var(--ease)}
@media (prefers-reduced-motion: reduce){
  .eng-mark:hover,a:focus-visible .eng-mark,button:focus-visible .eng-mark,[tabindex]:focus-visible .eng-mark{animation:none}
}
/* buttons + typeset links. Buttons are pills, solid, with a non-animated
   hover state (round 35, Max's verdict: the diagonal paper wipe is retired
   site-wide; the paper/ink literal palette exception retired with it).
   Solid buttons dim toward the ground on hover; bordered variants
   strengthen their border instead. No transition on either, so reduced
   motion needs no carve-out. (Keep in sync with site/site.css.) */
.btn{display:inline-block;background:var(--lt);color:var(--field);font-size:var(--t-label);font-weight:var(--w-6);letter-spacing:var(--track);text-transform:uppercase;padding:0.95rem 1.7rem;border-radius:999px;white-space:nowrap}   /* round-11 arrow rule (keep in sync with site/site.css) */
.btn:hover,.btn:focus-visible{opacity:0.85}
.btn--outline{background:transparent;color:var(--lt);border:1px solid var(--hair-strong)}
.btn--outline:hover,.btn--outline:focus-visible{opacity:1;border-color:rgba(var(--ink-rgb),0.9)}
.tlink{display:inline-flex;align-items:center;gap:0.7rem;font-size:var(--t-link);font-weight:var(--w-6);letter-spacing:var(--track);text-transform:uppercase;color:var(--lt);position:relative;padding-bottom:0.5rem}
.tlink::before{content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;background:var(--hair)}
.tlink::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;background:var(--lt);transform:scaleX(0);transform-origin:right;transition:transform 0.5s var(--ease)}
.tlink:hover::after,.tlink:focus-visible::after{transform:scaleX(1);transform-origin:left}
.tlink .arr{display:inline-block;transition:transform 0.4s var(--ease)}
.tlink:hover .arr,.tlink:focus-visible .arr{transform:translateX(6px)}
/* reveal system (sparse). Round-11 fail-open: an unrevealed .rv fades in
   on its own at 1.5s (keep in sync with site/site.css). */
body.js .rv{opacity:0;transform:translateY(18px);transition:opacity 0.8s var(--ease),transform 0.8s var(--ease);animation:rv-failopen 0.6s ease 1.5s forwards}
body.js .rv.is-in{opacity:1;transform:none}
@keyframes rv-failopen{to{opacity:1;transform:none}}
body.js .hero-stagger{opacity:0;transform:translateY(26px);transition:opacity 1.5s var(--ease-soft),transform 1.5s var(--ease-soft)}
body.js.loaded .hero-stagger{opacity:1;transform:none}
/* hero title: JS splits the h1 into per-character spans (source text
   untouched; a visually hidden copy carries it for AT). Each character
   rises, fades in and collapses from loose tracking to the display
   token, so the line reads as words assembling. Reduced motion and
   no-JS: the plain heading, nothing split. */
.hero-display .split-w{display:inline-block;white-space:nowrap}
body.js .is-split .split-c{display:inline-block;opacity:0;transform:translateY(0.45em);letter-spacing:0.16em;transition:opacity 0.7s var(--ease-soft),transform 0.7s var(--ease-soft),letter-spacing 0.7s var(--ease-soft)}
body.js.loaded .is-split .split-c{opacity:1;transform:none;letter-spacing:var(--track-serif)}
@media (prefers-reduced-motion: reduce){
  body.js .rv{opacity:1;transform:none;transition:none;animation:none}
  body.js .hero-stagger{opacity:1;transform:none;transition:none}
}

/* ============ NAV (mega-menu bar over the dark hero) ============ */
/* Logo left; Solutions (mega panel), Pricing, Case Studies, Resources
   (narrow dropdown) and the See your plan CTA right. The bar is fixed over
   the dark water: until scrolled it is transparent and themed dark (paper
   type), and the scroll sync swaps the theme off as it turns solid paper
   with ink type. The mega and the narrow menu are ALWAYS light panels
   (data-theme="light" in markup) regardless of the bar's theme. Panels
   anchor to the bar (position:relative on .nav-bar); the mega spans the
   full bar width, the narrow menu sits under its trigger (.has-drop).
   Under 1280px the links collapse into the paper overlay and the triggers
   become accordion headers with the panels in flow; under 768px the CTA
   moves into the overlay too, pinned to the bottom. */
.nav{position:fixed;top:0;left:0;right:0;z-index:50}
.nav-bar{position:relative;display:flex;align-items:center;gap:2.4rem;padding:1.3rem var(--gutter);background:transparent;transition:background 0.4s var(--ease),box-shadow 0.4s var(--ease)}
/* navy state: from the moment the arriving block covers the water (driven
   by the hero's chased vis) the bar is solid navy with paper type (the nav
   keeps data-theme="dark" in both states); the white hairline literal is
   part of the navy surface, not the theme */
.nav.is-navy .nav-bar{background:var(--navy);box-shadow:0 1px 0 rgba(255,255,255,0.12)}
.nav-logo img{height:24px;width:auto}
.nav-logo img,.foot-row img,.trail-echo,.eng-mark{filter:var(--ink-filter)}
.nav-links{display:flex;align-items:center;gap:2.2rem;list-style:none;margin-left:auto}
.nav-links>li>a,.nav-trigger{display:inline-block;font-size:var(--t-label);font-weight:var(--w-6);letter-spacing:var(--track);text-transform:uppercase;color:var(--lt);position:relative;padding:0 0 0.3rem;white-space:nowrap}
.nav-links>li>a::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;background:var(--lt);transform:scaleX(0);transform-origin:right;transition:transform 0.45s var(--ease)}
.nav-links>li>a:hover::after,.nav-links>li>a:focus-visible::after{transform:scaleX(1);transform-origin:left}
/* trigger chevron: a 6px rotated-square border corner in currentColor */
.chev{display:inline-block;width:6px;height:6px;border-right:1px solid currentColor;border-bottom:1px solid currentColor;transform:rotate(45deg);margin-left:0.45rem;vertical-align:0.15em}
/* panel anchoring: the mega spans the bar (its li stays static so the
   absolute panel resolves against .nav-bar); the narrow menu's li carries
   .has-drop and positions itself */
.nav-item.has-menu{position:static}
.nav-item.has-drop{position:relative}
.mega{position:absolute;left:0;right:0;top:100%;background:var(--field-2);color:var(--lt);border-top:1px solid var(--hair);box-shadow:0 30px 60px rgba(0,0,0,0.12)}
.menu{position:absolute;left:0;top:100%;min-width:220px;padding:0.8rem 0;background:var(--field-2);color:var(--lt);border-top:1px solid var(--hair);box-shadow:0 30px 60px rgba(0,0,0,0.12)}
.menu a{display:block;padding:0.7rem 1.4rem;font-size:var(--t-body);font-weight:var(--w-5);color:var(--lt);white-space:nowrap;transition:color 0.3s var(--ease)}
.menu a:hover,.menu a:focus-visible{color:var(--peri)}
.mega-cols{display:grid;grid-template-columns:repeat(4,1fr);max-width:var(--w-max);margin:0 auto;padding:2.6rem var(--gutter) 2.4rem}
.mega-col+.mega-col{border-left:1px solid var(--hair);padding-left:2.4rem}
.mega-col{padding-right:2.4rem}
.mega-h{font-size:var(--t-label);font-weight:var(--w-6);letter-spacing:var(--track);text-transform:uppercase;color:var(--lt)}
.mega-tag{margin-top:0.4rem;font-size:var(--t-body);color:var(--lt-3);margin-bottom:1.3rem}
.mega-col a{display:block;font-size:1.15rem;font-weight:var(--w-5);color:var(--lt);transition:color 0.3s var(--ease)}
.mega-col a+a{margin-top:0.9rem}
.mega-col a:hover,.mega-col a:focus-visible{color:var(--peri)}
.mega-col a.mega-sub{font-size:var(--t-small);color:var(--peri);white-space:nowrap}   /* round-11 arrow rule */
.mega-sub .arr{display:inline-block}
/* Featured mega entry (round 7: PORTED from site/site.css). Round-7 cause on
   record: the featured-card markup rode the round-5 nav splice, but the
   homepage inlines every style and the .mega-feat rules were never ported
   (deferred in round 6 as "a future 6c decision"), so the card rendered
   unstyled here while every subpage drew it. The rules below are the
   site.css block verbatim (round-7 dials: rest border periwinkle at 30
   percent, draw and settled state at 55 percent, the draw ~700ms across
   the two staggered edge passes). The invariant-periwinkle rgba literals
   are the sanctioned exception; keep this block in sync with site.css. */
.mega-feat{position:relative;border:1px solid rgba(92,144,255,0.3);border-radius:12px;padding:0.95rem 1.1rem;margin:0 -1.1rem}
.mega-feat::before,.mega-feat::after{content:"";position:absolute;inset:-1px;border-radius:12px;border:1px solid transparent;pointer-events:none;opacity:0}
.mega-feat::before{border-top-color:rgba(92,144,255,0.55);border-right-color:rgba(92,144,255,0.55);transform-origin:top left}
.mega-feat::after{border-bottom-color:rgba(92,144,255,0.55);border-left-color:rgba(92,144,255,0.55);transform-origin:bottom right}
.has-menu.is-open .mega-feat::before{animation:mega-draw 0.36s var(--ease) forwards}
.has-menu.is-open .mega-feat::after{animation:mega-draw 0.36s var(--ease) 0.34s forwards}
@keyframes mega-draw{from{opacity:1;transform:scale(0)}to{opacity:1;transform:scale(1)}}
@media (max-width:1279px){.mega-feat{margin:0}}
@media (prefers-reduced-motion: reduce){.has-menu.is-open .mega-feat::before,.has-menu.is-open .mega-feat::after{animation:none;opacity:1;transform:none}}
.pill{display:inline-block;background:var(--lt);color:var(--field);font-size:0.62rem;font-weight:var(--w-6);letter-spacing:0.1em;text-transform:uppercase;padding:0.16rem 0.55rem;border-radius:999px;margin-left:0.5rem;vertical-align:middle}
.mega-foot{border-top:1px solid var(--hair);background:var(--field);display:flex;justify-content:space-between;align-items:center;gap:3rem;padding:1.4rem var(--gutter)}
.mega-foot p{font-size:var(--t-body);color:var(--lt-2);line-height:var(--lh-body)}
.mega-foot p a{color:var(--peri)}
/* open state: JS drops the hidden attribute and adds .is-open; the entrance
   plays from a forced reflow so the transition runs. Closing is instant. */
.mega,.menu{opacity:0;transform:translateY(-6px);transition:opacity 0.25s var(--ease),transform 0.25s var(--ease)}
.has-menu.is-open .mega,.has-menu.is-open .menu{opacity:1;transform:none}
@media (prefers-reduced-motion: reduce){.mega,.menu{transition:none;transform:none}.menu a,.mega-col a{transition:none}}
.nav-toggle{display:none;flex-direction:column;gap:5px;padding:0.6rem}
.nav-toggle span{display:block;width:22px;height:1.5px;background:var(--lt)}
.nav-cta{display:flex;align-items:center;gap:1.8rem;flex:none;white-space:nowrap}
.btn--nav{padding:0.75rem 1.4rem}
@media (max-width:1650px){
  .nav-links{gap:1.5rem}
  .nav-bar{gap:1.8rem}
}
@media (max-width:1279px){
  /* links collapse into the paper overlay; the button stays in the bar. The
     triggers read as accordion headers and the panels render in flow. The
     overlay is top-aligned and scrolls: an open mega is taller than the
     screen. */
  .nav-toggle{display:flex;position:relative;z-index:2;padding:0.85rem 0.6rem}   /* mobile hit area: 14.5px of bars + 27px padding = 41px tall */
  .nav-links{position:fixed;inset:0;background:var(--field);flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:1.6rem;padding:6.5rem var(--gutter) 9rem;overflow-y:auto;overscroll-behavior:contain;transform:translateY(-100%);transition:transform 0.6s var(--ease);z-index:1}
  .nav.is-open .nav-links{transform:translateY(0)}
  /* MOBILE PANEL THEME (defect fix, September 2026). The overlay is a PAPER
     panel per the always-light-panels rule, but the nav carries
     data-theme="dark", so background:var(--field) resolved to the DARK
     field (#131312) and the light-scoped mega/menu ink (#141413) painted
     onto it unreadable (the black-menu defect). While open, the nav
     re-declares the full light block (every token literally, per the
     palette rules), so the panel, the top-level links, the toggle bars,
     the lockup (via --ink-filter) and the bottom-pinned CTA all read
     ink-on-paper over any page section. Keep in sync with site/site.css. */
  .nav.is-open{
    --field:#F4F3EF; --field-2:#FFFFFF; --field-3:#ECEBE6; --field-deep:#FFFFFF;
    --lt:#141413; --lt-2:#3A3A37; --lt-3:#6B6B66;
    --hair:rgba(20,20,19,0.10); --hair-strong:rgba(20,20,19,0.22);
    --ink-rgb:20,20,19;
    --paper-rgb:244,243,239;
    --ink-filter:invert(1) hue-rotate(180deg);
    --navy:#0B1B3F;
    color-scheme:light;
  }
  .nav.is-open .nav-logo{position:relative;z-index:2}   /* the lockup stays visible over the open panel, inverted to ink by the tokens above */
  html.nav-locked{overflow:hidden}   /* scroll lock while the overlay is open (the nav toggle JS puts the class on <html>: body overflow never propagates to the viewport here because html carries overflow-x:hidden, so the lock must land on the scroller itself) */
  .nav-logo{display:inline-flex;padding:0.5rem;margin:-0.5rem}   /* 24px lockup + 16px padding = 40px hit area, margin-compensated */
  .nav-links>li>a,.nav-trigger{padding:0.7rem 0}   /* 19px label + 22px padding = 41px hit area */
  .nav-bar{justify-content:space-between}
  .nav-cta{margin-left:auto;margin-right:1rem}
  .nav-item.has-menu,.nav-item.has-drop{position:static;width:100%}
  .mega,.menu{position:static;box-shadow:none;border:0;background:transparent;transform:none;min-width:0;padding:0}
  .mega-cols{grid-template-columns:1fr;gap:1.6rem;padding:1.4rem 0 0.6rem;margin:0}
  .mega-col{padding-right:0}
  .mega-col+.mega-col{border-left:0;padding-left:0;border-top:1px solid var(--hair);padding-top:1.4rem}
  .mega-col a{padding:0.35rem 0}   /* 30px line + 11px padding = 41px hit area */
  .mega-col a.mega-sub{padding:0.6rem 0}   /* the smaller sub-link line (22px) needs 19px of padding to reach 41px */
  .mega-col a+a{margin-top:0.35rem}   /* rhythm held: 0.35 margin + 0.7 of paddings ~ the desktop 0.9 */
  .mega-foot{flex-direction:column;align-items:flex-start;gap:1rem;padding:1.4rem 0;background:transparent}
  .mega-foot p a{display:inline-block;padding:0.55rem 0.15rem;margin:-0.55rem -0.15rem}   /* inline free-check link: 26px line + 18px padding = 44px hit area, margin-compensated */
  .menu a{padding:0.55rem 0}
  /* the open toggle reads as a close affordance: bars fold to an X
     (transform/opacity only; reduced motion snaps) */
  .nav-toggle span{transition:transform 0.3s var(--ease),opacity 0.3s var(--ease)}
  .nav.is-open .nav-toggle span:nth-child(1){transform:translateY(6.5px) rotate(45deg)}
  .nav.is-open .nav-toggle span:nth-child(2){opacity:0}
  .nav.is-open .nav-toggle span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}
  @media (prefers-reduced-motion: reduce){.nav-toggle span{transition:none}}
}
@media (max-width:767px){
  /* the button follows the links into the overlay, pinned to the bottom,
     carrying its own paper fade so the scrolling menu list never collides
     with the button text (rgba over --paper-rgb, so the fade is the open
     panel's own ground) */
  .nav-cta{position:fixed;left:0;right:0;bottom:0;margin:0;justify-content:center;flex-direction:column;gap:1.2rem;padding:2.6rem var(--gutter) 2.4rem;background:linear-gradient(180deg,rgba(var(--paper-rgb),0),rgba(var(--paper-rgb),0.92) 45%,rgba(var(--paper-rgb),1) 70%);transform:translateY(120%);transition:transform 0.6s var(--ease);z-index:1}
  .nav.is-open .nav-cta{transform:none}
}
/* no-JS: the menus cannot open, so the top bar drops the trigger items and
   shows just Pricing, Case Studies and the CTA; inside the overlay range the
   panels would render statically in flow (the overlay itself needs JS to
   open, so this is a formality). The bar also holds its solid ground, since
   the scroll sync never runs. */
body:not(.js) .nav-bar{background:var(--navy);box-shadow:0 1px 0 rgba(255,255,255,0.12)}
body:not(.js) .has-menu{display:none}
@media (max-width:1279px){
  body:not(.js) .has-menu{display:block}
  body:not(.js) .has-menu .mega,body:not(.js) .has-menu .menu{display:block;position:static;box-shadow:none;border:0;opacity:1;transform:none}
}

/* ============ HERO (the water: signature) ============ */
/* A short pinned chapter (177vh section: 170vh chapter + 7vh hold detent,
   100vh sticky pin) over the Halcyon
   water: .hero-sea is a canvas running the reference's fragment shader in
   raw WebGL, no library; the palette and every uniform live in the SEA
   block above its IIFE; the heavy path is capped at 1x pixel ratio on
   desktop and 0.6 on touch, with 12 ripples instead of 28 on touch.
   The original blue Halcyon: night sky, stars, blue clouds, a pale blue
   sun low over deep water; ring off. The section is themed dark, so the
   copy is paper type on the water. At rest the waterline sits at
   1 - SEA.uHorizon of the pin and the copy sits above it (the grid's
   padding-top puts the headline at about 14% and the sub ends around 44%).
   THE TIDE COMES IN as the chapter leaves: scroll progress through the
   section (chased, rate capped, in the sea IIFE) raises the horizon to the
   top of the frame, lowers the camera so the surface reads closer, rides
   the light up with the horizon, adds mirror, runs a ripple burst, and
   fades the hero copy up and out; the after-hero wrapper (plan bar +
   ambassadors: light, opaque, z-index 2, pulled up by a full-viewport
   negative margin countered at vis 0 by the JS travel, so it starts at
   the fold) slides up over the water while it is still rising and covers
   the whole pin, plan strip under the nav, as it releases. Because the
   pin is dark
   and the arriving block is light, the canvas does not fade to the pin
   ground: a light .hero-veil between the canvas and the copy takes
   1 - canvasOpacity per frame, so the water dissolves to the arriving
   block's white. The tide is fully up by vis 0.55, before the section
   covers the water. Wheel scrolling through the chapter is governed (fine
   pointers only) to at least 2.4s end to end, so the transition cannot be
   skipped. Reduced motion: no chapter (.is-static: 100vh, pin in flow),
   one still frame, veil at 0. No-JS: same layout, no canvas, no veil, the
   section paints a flat night-waterline gradient as its ground. */
/* 177vh = 170vh chapter + 7vh hold detent (HOLD 0.07 in the hero sea IIFE:
   the CSS height MUST equal 170vh + HOLD * 100vh; change both or neither) */
.hero{position:relative;height:177vh;background:var(--field)}
.hero-pin{position:sticky;top:0;height:100vh;overflow:hidden;background:#00061a}   /* the sky top, so the frame edge never shows paper */
/* the sea canvas covers the pin, full-bleed, under the copy. No-JS hides it
   (the .hero gradient below stands in); reduced motion keeps it (one frame). */
.hero-sea{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
body:not(.js) .hero-sea{display:none}
body:not(.js) .hero,.hero.is-static{background:linear-gradient(180deg,#00061a 0%,#0f2f7a 56.5%,#0a2a66 56.5%,#000814 100%)}
/* the veil: the arriving block's light ground, between the canvas and the
   copy. The sea IIFE writes its opacity as 1 - canvasOpacity over the tide
   exit, so the water dissolves to white as the light block rises over it.
   Themed light in markup (the hero is dark) so --field-2 resolves white.
   Reduced motion and no-JS: never written, stays 0. */
.hero-veil{position:absolute;inset:0;background:var(--field-2);opacity:0;pointer-events:none}
/* no chapter under reduced motion (JS adds .is-static) or without JS */
body:not(.js) .hero,.hero.is-static{height:100vh}
body:not(.js) .hero-pin,.hero.is-static .hero-pin{position:relative}
.hero-grid{position:relative;z-index:1;display:block;height:100%;padding-top:22vh}
.hero-col{position:static;display:block}
.hero-core{position:relative;max-width:34em;will-change:opacity,transform}   /* faded and lifted per frame by the sea IIFE as the tide comes in */
.hero-entity{display:block;font-size:var(--t-entity);font-weight:var(--w-5);letter-spacing:0;color:var(--lt-3);margin-bottom:1.8rem}
.hero-display{display:block;font-family:var(--serif);font-weight:var(--w-4);font-size:var(--t-hero);line-height:var(--lh-disp);letter-spacing:var(--track-serif);max-width:9em}
.hero-sub{margin-top:2rem;font-size:var(--t-lede-lg);line-height:1.45;color:rgba(var(--ink-rgb),0.72);max-width:26em}   /* under the dark theme: paper at 72 percent */
/* the hero's one button: outlined on the dark water, in its own absolute
   wrapper toward the bottom of the pin (about 10vh above the frame edge,
   clear of the waterline), faded with the copy by the tide. Hover
   strengthens the border, like every bordered button (round 35). */
.btn--ghost{background:transparent;color:var(--lt);border:1px solid rgba(var(--ink-rgb),0.45)}
.btn--ghost:hover,.btn--ghost:focus-visible{opacity:1;border-color:rgba(var(--ink-rgb),0.9)}
.hero-cta{position:absolute;left:var(--gutter);bottom:10vh;z-index:2;will-change:opacity,transform}
/* ROUND 32: at phone widths the pinned CTA centers in the frame (at the
   gutter it read off-center with the arrow clipped at the right edge,
   Max's 390 screenshot: the pill measured 417px against the 390 frame).
   Full-width slot, the pill centers itself (margin-inline auto on a
   fit-content block), capped ~92vw; the label's tracking steps to about
   half the token so the long line fits its pill, and below 421px the
   label steps down one notch besides - the round-11 nowrap arrow rule
   holds, so the arrow always shares the label's line inside the pill and
   the label never wraps. No copy change. */
@media (max-width:767px){
  .hero-cta{left:0;right:0}
  .hero-cta .btn{display:block;width:fit-content;margin-inline:auto;max-width:92vw;padding:0.95rem 1rem;letter-spacing:calc(var(--track)*0.55)}
}
@media (max-width:420px){
  .hero-cta .btn{font-size:calc(var(--t-label) - 0.06rem)}
}


/* ============ AFTER-HERO (the arriving block: plan bar + ambassadors) ============ */
/* The wrapper is what slides up over the hero's water: pulled a FULL
   viewport up over the pin, its arrival riding the sea IIFE's chased
   progress (an inline translate3d of (1 - vis) * ARRIVE viewports, cleared
   at rest), so it still starts at the fold at vis 0 and the plan strip
   tops out under the nav at vis 1 with no veiled band above it. THE MARGIN
   MUST EQUAL THE JS TRAVEL: -100vh here is ARRIVE 1.0 in the hero sea
   IIFE; change both or neither. The hero's extra 7vh hold detent does NOT
   enter this margin: the block's (1 - holdP) * HOLD term absorbs it (see
   arrive() in the IIFE). Neither the wrapper nor its sections are
   in the [data-section] reveal list: that rule's transform transition
   would fight the per-frame writes. Its ground is a ::before gradient from
   transparent to white (--field-2) over its first 62vh, so the block fades
   in over the rising tide while the veil whitens the water behind it;
   isolation keeps the z-index:-1 layer inside the wrapper. The plan bar
   sits inside the gradient zone, transparent, so the wrapper's whitening
   ground is what the eye lands on as the water dissolves. */
.after-hero{position:relative;z-index:2;isolation:isolate;margin-top:-100vh;will-change:transform}
/* static hero (reduced motion, no WebGL) and no-JS: the travel never runs,
   so the pull-up margin would just bury the 100vh hero under the block;
   restore normal flow */
body:not(.js) .after-hero,.hero.is-static+.after-hero{margin-top:0}
.after-hero::before{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(180deg,rgba(255,255,255,0) 0,rgba(255,255,255,0.55) 30vh,var(--field-2) 62vh,var(--field-2) 100%)}
/* the top padding is NAV CLEARANCE: the hold seats this strip with its top
   at the viewport top, under the fixed bar, so the headline needs the bar's
   87px (the rendered .nav-bar height; arithmetic in the proof tight-pin
   comment) plus air above it. Permanent by design: it reads as ordinary
   section spacing when scrolled past. If the row looks low between its
   paddings, balance with the bottom padding, never by shrinking the top. */
.plan{padding:calc(87px + 2.2rem) 0 3.2rem;background:transparent;border-bottom:1px solid var(--hair)}
.plan-row{display:flex;align-items:center;justify-content:space-between;gap:2rem}
.plan-h{font-family:var(--serif);font-weight:600;font-size:1.5rem;letter-spacing:-0.01em}
.plan-sub{margin-top:0.4rem;color:var(--lt-3);font-size:var(--t-body)}
@media (max-width:767px){
  .plan-row{flex-direction:column;align-items:stretch}
  .plan-row .btn{display:block;text-align:center}
  /* ROUND 39 (phone): the hero is static under 800px (no chapter, no arrive,
     no seat under the fixed bar), so the 87px nav clearance in the top
     padding has no job here and read as 122px of air over 51px under (Max's
     screenshot). Equal padding above and below the copy + button group; the
     desktop seat padding above is untouched. */
  .plan{padding:3.2rem 0}
}

/* ============ AMBASSADORS (one row of portrait cards) ============ */
/* Centered header, then one row of four portrait cards, no flip: photo in a
   rounded 4/5 frame, name and one line beneath. Hover and focus: the photo
   scales 1.03 (transform only) and the name goes periwinkle. The case-study
   link sits centered under the row. 991: two columns; 600: one column with
   a squarer 4/4 frame. */
.amb{padding:var(--sec-pad) 0;background:var(--field)}
.amb-head--center{text-align:center;margin:0 auto 3.2rem;max-width:40em}
.amb-head--center .lede{margin-left:auto;margin-right:auto;line-height:1.8;font-weight:var(--w-6)}   /* round-15 pin: more leading, weight 600 on the $2B lede */
.amb-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1.6rem;list-style:none;margin:0;padding:0}
.amb-card{display:block;color:inherit}
.amb-img{aspect-ratio:4/5;border-radius:18px;overflow:hidden;background:var(--field-3)}
.amb-img img{width:100%;height:100%;object-fit:cover;object-position:50% 20%;transition:transform 0.6s var(--ease)}
.amb-card:hover .amb-img img,.amb-card:focus-visible .amb-img img{transform:scale(1.03)}
.amb-card h3{margin-top:1.1rem;font-family:var(--serif);font-weight:600;font-size:1.15rem;letter-spacing:-0.01em;transition:color 0.4s var(--ease)}
.amb-card:hover h3,.amb-card:focus-visible h3{color:var(--peri)}
.amb-card p{margin-top:0.25rem;font-size:var(--t-small);color:var(--lt-3)}
.amb-more{text-align:center;margin-top:2.8rem}
@media (max-width:991px){.amb-row{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.amb-row{grid-template-columns:1fr}.amb-img{aspect-ratio:4/4}}
@media (prefers-reduced-motion: reduce){
  .amb-img img,.amb-card h3{transition:none}
  .amb-card:hover .amb-img img,.amb-card:focus-visible .amb-img img{transform:none}
}

/* ============ TESTIMONIALS (pour-out card track) ============ */
/* Twelve light quote cards under periwinkle market eyebrows and one dark
   anchor card at the left. The pour mechanism is the services track's,
   re-skinned: the cards start stacked behind the anchor and pour out to
   the right in a stagger as the section climbs into view (JS,
   scroll-driven, lag-chased); after the pour they sit in a native
   horizontal rail the visitor drags (mouse or pen), swipes (touch), or
   arrows through, two cards per press. The anchor is position:sticky
   inside the rail, so it stays pinned at the gutter while the track moves
   behind it. Each card: market eyebrow, a large opening quote mark in
   hair-strong where the services number was, the quote, then name and
   role. Reduced motion and no-JS: cards sit in their natural row, the
   rail still scrolls (no-JS shows a thin scrollbar and hides the arrows). */
.testi{padding:var(--sec-pad) 0;background:var(--field);overflow:hidden}
.testi-head{display:flex;align-items:flex-end;justify-content:space-between;gap:2rem;margin-bottom:2.6rem}
.pour{position:relative}
.pour-rail{display:flex;gap:1.2rem;align-items:stretch;margin-left:var(--gutter);padding:0.8rem var(--gutter) 0.8rem 0;overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:none;scrollbar-width:none;cursor:grab}
.pour-rail::-webkit-scrollbar{display:none}
.pour-rail.is-dragging{cursor:grabbing;user-select:none;-webkit-user-select:none}
.pour-anchor{position:sticky;left:0;z-index:20;flex:none;width:300px;min-height:420px;display:flex;flex-direction:column;justify-content:flex-end;gap:0.9rem;padding:1.8rem;background:var(--lt);color:var(--field);border-radius:12px}
.pour-eyebrow{font-size:var(--t-small);letter-spacing:0.12em;text-transform:uppercase;color:var(--peri-dark);margin-bottom:auto}   /* the anchor card is an ink field: on-dark periwinkle per the round-14 rule */
.pour-anchor h3{font-family:var(--serif);font-weight:600;font-size:clamp(1.8rem,2.4vw,2.4rem);line-height:1.02;letter-spacing:var(--track-serif)}
.pour-lead{font-size:var(--t-body);color:rgba(var(--paper-rgb),0.72);max-width:15em}
/* the testimonials anchor's button sits on an ink card, so it inverts the
   family: paper fill on the ink ground; the shared hover dim applies */
.btn--paper{background:var(--field);color:var(--lt);align-self:flex-start;margin-top:0.6rem}
.pour-track{display:flex;gap:1.2rem;list-style:none;margin:0;padding:0;will-change:transform}
/* the belt: a compositor-driven keyframe animation on the track, one
   set-width per cycle (--loop, set by JS on measure), linear, infinite.
   Duration is set inline from loopW / DRIFT so speed is constant in px per
   second at any card width. Pauses via .is-held (drag, and a moment after
   an arrow press). Reduced motion: never applied. */
.pour-track.is-drifting{animation:pour-belt linear infinite;animation-duration:var(--dur,190s)}
.pour-track.is-held{animation-play-state:paused}
@keyframes pour-belt{from{transform:translate3d(0,0,0)}to{transform:translate3d(calc(-1 * var(--loop,0px)),0,0)}}
@media (prefers-reduced-motion: reduce){.pour-track.is-drifting{animation:none}}
.pour-card{position:relative;flex:none;width:300px;min-height:380px;display:flex;flex-direction:column;padding:1.6rem 1.5rem;background:var(--field-2);border:1px solid var(--hair-strong);border-radius:12px;will-change:transform}
.pour-card>*{will-change:opacity}
.pour-cat{font-size:var(--t-small);letter-spacing:0.12em;text-transform:uppercase;color:var(--peri)}
.pour-mark{margin-top:auto;font-family:var(--serif);font-weight:400;font-size:3rem;line-height:1;color:var(--hair-strong);letter-spacing:-0.02em}
.pour-quote{margin-top:0.5rem;font-size:1.1rem;font-weight:var(--w-5);line-height:1.45;color:var(--lt)}
.pour-who{margin-top:1.1rem;font-size:var(--t-small);line-height:1.4;color:var(--lt-3)}
.pour-clone{pointer-events:none}
.pour-nav{display:flex;gap:0.6rem;justify-content:flex-end;padding:1.4rem var(--gutter) 0}
.pour-btn{width:44px;height:44px;border-radius:50%;border:1px solid var(--hair-strong);background:transparent;color:var(--lt);font-size:1.1rem;cursor:pointer;transition:background 0.3s var(--ease),color 0.3s var(--ease)}
.pour-btn:hover,.pour-btn:focus-visible{background:var(--lt);color:var(--field)}
.pour-btn:disabled{opacity:0.35;cursor:default}
.pour-btn:disabled:hover{background:transparent;color:var(--lt)}
@media (max-width:767px){
  .pour-anchor{position:relative;left:auto;width:240px;min-height:360px}
  .pour-card{width:250px;min-height:340px}
}
@media (prefers-reduced-motion: reduce){
  .pour-card,.pour-card>*,.pour-track{will-change:auto}
  .pour-btn{transition:none}
}
body:not(.js) .pour-nav{display:none}
body:not(.js) .pour-rail{scrollbar-width:thin;cursor:auto}
body:not(.js) .pour-rail::-webkit-scrollbar{display:block;height:6px}

/* ============ DONE FOR YOU (SIGNATURE round 2: white-water chapter, expand-orbit cards, atom hub) ============ */
/* NOT a pinned chapter (round 3): the section sits in normal flow
   (min-height 100vh) on a SECOND instance of the Halcyon shader running
   THE HERO SCENE INVERTED (round 4): hero palette with sun and stars off,
   the canvas inverted and desaturated in CSS, so white sky, the hero's
   clouds in pale gray, silver-white water, no speckle (the sea IIFE is a
   factory, makeSea; DFY_SEA holds the overrides). Entry: as the
   section approaches, the canvas fades in and the horizon rises to its
   resting line over the last 40vh (progress q in the dfy fades IIFE).
   Exit: as the section departs, the canvas fades back out while the
   horizon rises gently to 0.60 (progress r). No content fade; the founder
   follows in normal flow with no gap. No wheel governor.
   The cards are the concept-4 expand-to-grid signature ported: hover
   intent (tap on coarse, focus from keyboard) expands a card's panel to
   fill the grid row via a transform-only FLIP; the six engine marks lift
   from their resting row beneath the atom hub and orbit the expanded
   panel on a wide ellipse at 1.45x WITH A DEPTH PASS (opacity 1 to 0.55
   and scale 1.45 to about 1.25, both fading continuously with depth;
   z-index swaps under the panel at the crossing), gliding home on
   collapse. Each card is a real
   <button>; its expanded panel is the button's SIBLING inside a static
   .dfy-cell (the panel holds the one link, and a link may not nest in a
   button), and the absolute panel still resolves to the grid box because
   the cell is static. The panel's final box is a compact box that centers
   on the hovered card, clamped to the row and guarded to cover the atom
   horizontally, clamp(680px, 60 percent of the row, 920px) by
   max(rowHeight, 280, atomBottom - rowTop + 16) so it always covers the
   hub, anchored to the row's top so extra height grows downward only, and
   its content runs two columns: name and lede left, more and the link
   right, in two .dfy-col wrappers. While a panel is open the other three
   cards recede to 0.12 opacity at scale 0.96 and stay hittable, so
   gliding across the row still switches panels. PALETTE-RULE
   EXCEPTION, by design: card and panel surfaces are NAVY (--navy, theme-
   invariant) with white literals for their type and hairlines, a fixed
   surface no theme token resolves to (same exception as the button
   sheet). The atom hub between row and marks pulses on rAF and cross-
   fades to a periwinkle-filtered twin while a card is open. Below 992:
   in-card accordion on the navy cell surface, no orbit. Reduced motion:
   one still sea frame at full opacity, instant panels, marks never leave
   the row. No-JS: canvas hidden, flat white waterline gradient, panels
   open statically. */
.dfy{position:relative;min-height:100vh;background:var(--field-2)}
.dfy-pin{position:relative;min-height:100vh;overflow:hidden;background:var(--field-2);display:flex;align-items:center}
/* the hero scene inverted: the canvas runs the hero's palette (stars off,
   a small sun back so the water has something to reflect) and this filter
   turns it pale with a faint blue cast (hue-rotate keeps the inverted
   blues blue, the low saturate quiets them) and enough contrast for the
   wave shading to read; the reduced-motion still frame keeps the same
   filter (the rule is unconditional) */
.dfy-sea{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;opacity:0;filter:invert(1) hue-rotate(180deg) saturate(0.22) brightness(1.04) contrast(1.18)}
body:not(.js) .dfy-sea{display:none}
/* flat waterline stand-in (no-JS and no-WebGL): white above 56 percent,
   pale grey water below; hex sanctioned as the shader palette's stand-in,
   as with the hero gradient */
body:not(.js) .dfy-pin,.dfy.is-flat .dfy-pin{background:linear-gradient(180deg,#FFFFFF 0%,#FFFFFF 56%,#DCDDE3 56%,#F1F2F5 100%)}
/* reduced motion (JS adds is-static): the factory's one still frame,
   full-on */
.dfy.is-static .dfy-sea{opacity:1}
.dfy-inner{position:relative;z-index:1;width:100%;padding-top:6rem;padding-bottom:3rem}
.dfy-head{text-align:center;max-width:44em;margin:0 auto}
.dfy-head .lede{margin:1rem auto 0}
.dfy-dim{color:var(--peri)}   /* the accent half of the headline: no italics in this system */
.dfy-label{font-size:0.68rem;font-weight:var(--w-6);letter-spacing:var(--track);text-transform:uppercase;color:var(--lt-3);text-align:center;margin:2rem 0 1rem}
.dfy-grid{position:relative;display:grid;grid-template-columns:repeat(4,1fr);gap:1.4rem}
.dfy-cell{display:flex;flex-direction:column}   /* static, so each cell's absolute .dfy-full resolves to the grid box */
.dfy-card{flex:1;display:flex;align-items:center;justify-content:center;text-align:center;background:var(--navy);color:#fff;border:1px solid rgba(255,255,255,0.08);border-radius:var(--r-card);min-height:160px;padding:1.2rem 1.5rem;font-size:1.25rem;cursor:pointer;transition:border-color 0.5s var(--ease),opacity 0.35s var(--ease),transform 0.35s var(--ease)}
.dfy-card:hover,.dfy-card:focus-visible{border-color:rgba(255,255,255,0.3)}
/* while a panel is open the other three cards recede to a faint ghost;
   they keep their hit areas, so gliding across the row still switches
   panels (the ghost is the aim point). Reduced motion zeroes .dfy-card
   transitions, so the fade snaps there */
@media (min-width:992px){
  .dfy-grid.has-open .dfy-cell:not(.is-exp):not(.is-hold) .dfy-card{opacity:0.12;transform:scale(0.96)}
}
/* ROUND 46: is-hold marks the card just left while the pointer crosses to
   a neighbour: has-open stays on through the 170ms hover intent (the three
   others never pulse bright and back) and the left card keeps its full
   opacity until the neighbour opens or the pointer leaves the cards */
.dfy-name{display:block;font-size:1.25rem;font-weight:600;letter-spacing:var(--track-h3);line-height:var(--lh-sub)}
/* the panel's final box is a compact box centered on the hovered card,
   clamped to the row and guarded to cover the atom horizontally: the
   expand JS writes inline left/top/width/height (clamp(680px, 60 percent
   of the row, 920px) by max(rowHeight, 280, atomBottom - rowTop + 16) so
   it always covers the hub, anchored to the row's top) before the FLIP,
   so the extra height grows downward only; the orbit's ellipse is
   computed from the same final box via panelBox(card) */
.dfy-full{position:absolute;inset:0;z-index:3;display:flex;align-items:center;padding:2.6rem 3rem;background:var(--navy);color:#fff;border:1px solid rgba(255,255,255,0.08);border-radius:var(--r-card);box-shadow:0 30px 70px rgba(0,0,0,0.28);opacity:0;visibility:hidden;transform-origin:0 0;transition:opacity 0.2s var(--ease),visibility 0s linear 0.2s}   /* ROUND 46: the collapse fade is the expand's 0.2s reversed; the JS holds the compact box until this fade has hidden the panel (FADE_MS) */
.dfy-cell.is-exp .dfy-full{opacity:1;visibility:visible;transition:opacity 0.2s var(--ease),visibility 0s}
.dfy-full.is-anim{transition:transform 0.55s var(--ease),opacity 0.2s var(--ease),visibility 0s}
/* two-column panel: name and lede left, more and the link right (the two
   .dfy-col wrappers are the grid items) */
.dfy-full-inner{display:grid;grid-template-columns:minmax(0,0.9fr) minmax(0,1.1fr);gap:3rem;align-items:center;max-width:none;width:100%;padding:0 0.6rem;text-align:left;opacity:0;transform:translateY(10px);transition:opacity 0.4s var(--ease),transform 0.4s var(--ease)}
.dfy-cell.is-exp .dfy-full-inner{opacity:1;transform:none;transition-delay:0.26s}
.dfy-col{display:block;min-width:0}
.dfy-full-name{display:block;font-size:1.9rem;font-weight:600;letter-spacing:var(--track-h3);line-height:1.05;color:#fff}
.dfy-lede{display:block;margin-top:0.9rem;font-size:1.15rem;font-weight:var(--w-5);line-height:1.35;color:rgba(255,255,255,0.92)}
.dfy-more{display:block;font-size:var(--t-body);line-height:1.5;color:rgba(255,255,255,0.72)}
/* the expanded panel is a navy card: on-dark periwinkle per the round-14
   rule (the no-JS and sub-992 fallbacks sit on the light dfy field, where
   the variant still reads as the accent; one rule serves both) */
.dfy-full .tlink{margin-top:1.2rem;display:inline-flex;color:var(--peri-dark)}
.dfy-full .tlink::before{background:rgba(92,144,255,0.3)}
.dfy-full .tlink::after{background:var(--peri-dark)}
/* hub: stem, atom (ink via the theme filter), periwinkle twin cross-faded
   in while a card is expanded. The twin's chain is solved to land the white
   glyph exactly on #5C90FF, the round-20 single hue (brightness(0) floors it
   to black first; the invert/sepia/saturate/hue-rotate walk it to the accent;
   36/215/128 re-solved headlessly via ctx.filter, exact rgb(92,144,255)). */
.dfy-hub{position:relative;display:flex;flex-direction:column;align-items:center;margin:1.4rem 0 0.8rem}
/* the light behind the atom: the sun is off in the shader (it would invert
   to a dark smudge), so its light lives here in CSS, un-inverted, sitting
   on the waterline and brightening while a card is open (is-lit, toggled
   by the expand-orbit IIFE alongside the atom's periwinkle state) */
.dfy-glow{position:absolute;left:50%;top:50%;width:420px;height:220px;transform:translate(-50%,-42%);border-radius:50%;background:radial-gradient(closest-side,rgba(201,210,255,0.85),rgba(201,210,255,0.35) 45%,transparent 72%);filter:blur(18px);pointer-events:none;z-index:0;opacity:0.85;transition:transform 0.4s var(--ease),opacity 0.4s var(--ease)}
.dfy-hub.is-lit .dfy-glow{transform:translate(-50%,-42%) scale(1.15);opacity:1}
.dfy-stem{position:relative;z-index:1;width:1px;height:38px;background:rgba(var(--ink-rgb),0.25)}
.dfy-atom-wrap{position:relative;z-index:1;width:64px;height:64px;margin-top:0.7rem;will-change:transform}
.dfy-atom{position:absolute;inset:0;width:64px;height:64px;filter:var(--ink-filter)}
.dfy-atom--peri{filter:brightness(0) invert(36%) sepia(100%) saturate(2000%) hue-rotate(215deg) brightness(128%);opacity:0;transition:opacity 0.45s var(--ease)}
.dfy-atom--peri.is-on{opacity:1}
/* ROUND 39 (phone, under 800px like the sea gates): the twin is a DIRECTLY
   TINTED derivative, no filter chain. The chain above only lands on the accent
   when the browser clamps between filter functions; evaluated unclamped the
   same chain resolves to magenta, which is the violet Max saw on his iPhone.
   The expand-orbit IIFE swaps the twin's src to assets/logo/derivatives/
   atom-peri.png (baked #4D96FF = rgb(77,150,255), the round-39 bluer target)
   under the same matchMedia, and this rule drops the chain so the PNG shows
   as baked. DIAL: node tools/tint-atom.mjs <hex> regenerates the derivative;
   the hex lives in that tool's default and nowhere else. Desktop keeps the
   chain (the parity gate holds it); unify once Max rules on the phone hue. */
@media (max-width:799px){.dfy-atom--peri{filter:none}}
/* engine marks row (ported from concept 4): resting row centered beneath
   the hub; .is-orbit lifts a mark for the JS ellipse, .is-return glides it
   home. The orbit has a DEPTH PASS: scale and opacity fade continuously
   with depth (1 to 0.55 opacity, 1.45 to about 1.25 scale, both written
   inline per frame by the JS; no opacity transition here, it would fight
   the per-frame write), and only the z-index swap under the z-3 panel is
   binary via .is-behind at the crossing. The marks take the theme's ink
   filter through the global rule. */
.dfy .engines-marks{display:flex;align-items:center;justify-content:center;gap:1.4rem;margin-top:3.4rem}   /* no label above (round 6); the drop clears the atom glow's footprint, the note beneath */
.dfy .engines-marks .eng-mark{width:36px;height:36px}
.engines-marks .eng-mark.is-orbit{position:relative;z-index:6;will-change:transform}
.engines-marks .eng-mark.is-orbit.is-behind{z-index:2}
.engines-marks .eng-mark.is-return{transition:transform 0.6s var(--ease) 0s,opacity 0.3s var(--ease) 0s}
/* the note under the marks */
.dfy-note{font-size:var(--t-small);color:var(--lt-3);text-align:center;margin:1.2rem auto 0;max-width:36em}
body:not(.js) .dfy-full{position:static;opacity:1;visibility:visible;border:0;box-shadow:none;background:transparent;color:inherit;padding:1.1rem 0 0;max-height:none;overflow:visible}
body:not(.js) .dfy-full-inner{display:block;opacity:1;transform:none}
body:not(.js) .dfy-full-name{display:none}
/* wide no-JS only: the static panel sits on the white pin below its navy
   card, so its text reads in ink (below 992 the panel sits INSIDE the navy
   cell and keeps its white type) */
@media (min-width:992px){
  body:not(.js) .dfy-lede{color:var(--lt-2);font-size:var(--t-body)}
  body:not(.js) .dfy-more{color:var(--lt-3);margin-top:0.4rem}
  body:not(.js) .dfy-full .tlink{margin-top:0.9rem}
}
@media (max-width:991px){
  /* in-card accordion: the CELL carries the navy surface so button and
     panel read as one card; the panel opens beneath the name, no orbit */
  .dfy-grid{grid-template-columns:1fr 1fr}
  .dfy-cell{background:var(--navy);border:1px solid rgba(255,255,255,0.08);border-radius:var(--r-card)}
  .dfy-card{background:transparent;border:0;border-radius:var(--r-card);min-height:110px}
  .dfy-full{position:static;display:block;opacity:1;visibility:visible;border:0;box-shadow:none;background:transparent;border-radius:0;padding:0 1.5rem;max-height:0;overflow:hidden;transition:max-height 0.5s var(--ease)}
  .dfy-cell.is-exp .dfy-full{max-height:380px;padding-bottom:1.4rem}
  .dfy-full-name{display:none}
  .dfy-full-inner{display:block;opacity:1;transform:none}
  .dfy-lede{font-size:1.05rem}
  .dfy-more{margin-top:0.4rem}
  .dfy-full .tlink{margin-top:0.9rem}
  /* the accordion max-height must not hide the open panels without JS; the
     side padding puts the text back inside the navy cell */
  body:not(.js) .dfy-full{max-height:none;overflow:visible;padding:0 1.5rem 1.4rem}
}
@media (max-width:600px){
  .dfy-grid{grid-template-columns:1fr}
}
/* short viewports (an 800-tall laptop included, now that the cards are
   200px): the prescribed reductions (head lede to body scale, stem to
   26px) plus tightened rhythm, so the section holds one viewport; if a
   viewport is shorter still, the unpinned section simply grows */
@media (max-height:820px){
  .dfy-head .lede{font-size:var(--t-body)}
  .dfy-stem{height:26px}
  /* the top padding must clear the fixed nav (about 87px) when the section
     top sits at the viewport top; the rhythm below pays for it */
  .dfy-inner{padding-top:5.5rem;padding-bottom:1rem}
  .dfy-label{margin:1rem 0 0.6rem}
  .dfy-hub{margin:0.8rem 0 0.5rem}
  .dfy-note{margin-top:0.5rem}
}
/* final reduced-motion guard for the dfy set: wins over the accordion
   transition above */
@media (prefers-reduced-motion: reduce){
  .dfy-card,.dfy-full,.dfy-full.is-anim,.dfy-atom--peri,.dfy-glow,.engines-marks .eng-mark.is-orbit,.engines-marks .eng-mark.is-return{transition:none}
  .dfy-full-inner{opacity:1;transform:none;transition:none}
}

/* ============ SITE (The AI Visibility Website: isometric stack) ============ */
/* Four live captures of theruthreffkinteam.com as an exploded isometric pile
   (rotateX 44 / rotateZ -20, z-steps of 90px, each lower layer offset down
   and to the right in the stack's plane, 16% / 12% per step, so the pile
   reads fanned, not dead-center). The stack rests at top 48% and the stage
   carries margin-top 3.5rem (the whole stage sits lower; 54% on the stack
   alone would push the bottom sheet past the stage bottom); sheets draw
   their own edges on dark-on-dark
   (26% hairline, inset top highlight, tight two-part shadow instead of a
   diffuse fog). Hover / tap / focus on a list item or a layer isolates it:
   the active layer pulls out of the fan toward the top-left and rises to
   330px (over the whole stack), the rest dim (0.62 at rest, 0.22 once
   picked), and the
   stack nudges its rotation toward the active layer. While the section is on screen and untouched for 6s
   the active layer auto-steps every 3.6s. Leaving the body does NOT clear
   the active item, so the stack never snaps back to undifferentiated.
   White literals on --navy: the dfy sanctioned exception. Refresh captures
   with: node tools/capture-ruth.mjs (hides the site's accessibility widget
   before each shot; edit HIDE in the script if the widget changes). */
.site{padding:var(--sec-pad) 0;background:var(--navy);color:var(--lt);overflow:hidden}
.site-head{max-width:36em;margin-bottom:3rem}
.site-head .lede{color:rgba(var(--ink-rgb),0.7)}
.site-body{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,0.65fr);gap:4rem;align-items:center}
.site-stage{position:relative;aspect-ratio:4/3;perspective:1600px;margin-top:3.5rem}
.site-stack{position:absolute;left:8%;top:48%;width:58%;aspect-ratio:16/10;transform-style:preserve-3d;transform:rotateX(44deg) rotateZ(-20deg);transition:transform 0.9s var(--ease)}
.site-layer{position:absolute;inset:0;margin:0;border-radius:10px;overflow:hidden;box-shadow:0 10px 26px rgba(0,0,0,0.6),0 2px 5px rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.26);background:#111;transform:translate3d(var(--tx),var(--ty),var(--z));transition:transform 0.8s var(--ease),opacity 0.5s var(--ease),filter 0.5s var(--ease);will-change:transform,opacity}
.site-layer img{display:block;width:100%;height:100%;object-fit:cover;object-position:top}
/* the inset top highlight rides an overlay: an inset box-shadow on the
   layer itself would paint UNDER the full-bleed capture img and never show */
.site-layer::after{content:"";position:absolute;inset:0;border-radius:inherit;box-shadow:inset 0 1px 0 rgba(255,255,255,0.32);pointer-events:none}
/* the fan: z steps of 90px plus an in-plane drift down-right, so each lower
   layer peeks out below and to the right of the one above it */
.site-layer[data-i="0"]{--tx:0%;--ty:0%;--z:270px}
.site-layer[data-i="1"]{--tx:16%;--ty:12%;--z:180px}
.site-layer[data-i="2"]{--tx:32%;--ty:24%;--z:90px}
.site-layer[data-i="3"]{--tx:48%;--ty:36%;--z:0px}
/* isolate, two levels. At REST (no pointer has entered the body since
   load, or the auto-step is driving) the inactive pages stay readable at
   0.62 with no blur: four distinct pages, the active one forward. Once
   PICKED (pointer / keyboard / tap has selected a page; is-picked drops 6s
   after the pointer leaves, when the auto-step resumes) the rest drop back
   hard to 0.22 with a soft blur. The active layer pulls out of the fan
   toward the top-left (the direction the pile opens) and rises to 330px,
   above Home's resting 270px, so it always sits over the whole stack; it
   also stops intercepting the pointer (pointer-events:none), so gliding
   across the fan lets each page under the cursor take over in turn. The
   0.15s delay is on the TRANSFORM only (the transition list is transform,
   opacity, filter), so the outgoing page starts settling back before the
   incoming one lifts. */
.site-stack.has-active .site-layer{opacity:0.62;filter:saturate(0.7)}
.site-stack.is-picked .site-layer{opacity:0.22;filter:saturate(0.5) blur(0.6px)}
.site-stack.has-active .site-layer.is-active{opacity:1;filter:none}
.site-layer.is-active{transform:translate3d(calc(var(--tx) - 4%),calc(var(--ty) - 5%),330px);transition-delay:0.15s,0s,0s;pointer-events:none}
/* the list and the visit link sit ABOVE the layers (an active layer's
   projection can reach into the right column): they stay legible and a
   floating layer never intercepts a hover meant for a list item */
.site-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;position:relative;z-index:2}
.site-item button{display:block;width:100%;text-align:left;padding:1.3rem 0;border:0;border-top:1px solid rgba(255,255,255,0.14);background:transparent;color:inherit;cursor:pointer;border-radius:0}
.site-item:last-child button{border-bottom:1px solid rgba(255,255,255,0.14)}
.site-num{display:block;font-size:0.68rem;letter-spacing:0.14em;text-transform:uppercase;color:rgba(255,255,255,0.5)}
.site-name{display:block;margin-top:0.4rem;font-family:var(--serif);font-weight:600;font-size:1.15rem;color:rgba(255,255,255,0.7);transition:color 0.3s var(--ease)}
.site-desc{display:block;margin-top:0.45rem;font-size:var(--t-body);line-height:1.5;color:rgba(255,255,255,0.5);transition:color 0.3s var(--ease)}
.site-item.is-active .site-name{color:#fff}
.site-item.is-active .site-desc{color:rgba(255,255,255,0.78)}
.site-item.is-active .site-num{color:var(--peri-dark)}   /* navy section: on-dark periwinkle per the round-14 rule */
.site-visit{margin-top:1.6rem;justify-self:start;grid-column:2;position:relative;z-index:2}
/* no-JS: the stack flattens to a 2x2 grid of plain screenshots */
body:not(.js) .site-stage{aspect-ratio:auto;perspective:none}
body:not(.js) .site-stack{position:static;width:auto;aspect-ratio:auto;transform:none;display:grid;grid-template-columns:1fr 1fr;gap:1rem}
body:not(.js) .site-layer{position:relative;transform:none;aspect-ratio:16/10;box-shadow:none}
@media (max-width:1099px){.site-body{grid-template-columns:1fr}.site-stage{aspect-ratio:5/4}.site-visit{grid-column:1}}
@media (max-width:767px){.site-stage{display:none}.site-list{gap:0}}
@media (prefers-reduced-motion: reduce){.site-stack,.site-layer{transition:none}}
/* ROUND 40 / 42: THE TRAVELING ACCORDION, the standard phone behavior of
   the four-pillar cycle (round 40 built it dormant behind ?exploded=c; round
   42 enabled it on Max's phone verdict and stripped the param). At phone
   widths the stage is hidden and the list runs its light-up cycle, so the
   site IIFE gives each list item a .site-exp row under its button holding a
   compact frame with that page's phone-weight top
   (assets/site/ruth/m/<page>.webp, 800x500), and the row is OPEN exactly
   when the item is active (.is-active, the shipped lit state, so the
   accordion is purely additive to it). The height rides grid-template-rows
   0fr to 1fr (the FAQ's technique; a fractional fr track resolves to that
   fraction of its content, so the collapsing row and the expanding row,
   identical in content height and run from the same setActive call on the
   same 0.4s curve, always sum to one frame: the list holds one constant
   footprint and the section never pumps), the frame fades on the same
   curve. Frame chrome: the round-38 card radius token, the site-layer's
   hairline and #111 ground (the block's sanctioned literals). The closing
   hairline moves from the last button to the list so it sits under the last
   panel. Desktop: no element exists, no rule here matches, no image is
   requested. The four page tops are lazy images (loading="lazy"), so they
   load as the section approaches view, not at page load. Reduced motion: no
   transitions (the first item stands expanded, static; the cycle is already
   off). Twin in websites.html, keep in sync. */
@media (max-width:767px){
  .site--xc .site-exp{display:grid;grid-template-rows:0fr;transition:grid-template-rows 0.4s var(--ease)}
  .site--xc .site-item.is-active .site-exp{grid-template-rows:1fr}
  .site--xc .site-exp-in{min-height:0;overflow:hidden}
  .site--xc .site-exp-frame{position:relative;aspect-ratio:16/10;margin:0 0 1.3rem;border-radius:var(--r-card);overflow:hidden;border:1px solid rgba(255,255,255,0.26);background:#111;opacity:0;transition:opacity 0.4s var(--ease)}
  .site--xc .site-exp-frame::after{content:"";position:absolute;inset:0;border-radius:inherit;box-shadow:inset 0 1px 0 rgba(255,255,255,0.32);pointer-events:none}
  .site--xc .site-item.is-active .site-exp-frame{opacity:1}
  .site--xc .site-exp-frame img{display:block;width:100%;height:100%;object-fit:cover;object-position:top}
  .site--xc .site-item:last-child button{border-bottom:0}
  .site--xc .site-list{border-bottom:1px solid rgba(255,255,255,0.14)}
}
@media (prefers-reduced-motion: reduce){.site--xc .site-exp,.site--xc .site-exp-frame{transition:none}}

/* ============ FOUNDER (steno customer-quote treatment) ============ */
/* Mark's wide photo as a large 16/11 frame left; the quote pushed far right
   with a lot of air between (7rem gap, 1.2fr / 0.8fr split), quiet
   attribution beneath. The veil is the same photo blown up behind the
   section as a STATIC blur at 0.62 (one static filter, never transitioned
   or keyframed) under a left-to-right charcoal wash (0.42 to 0.72) that
   keeps the photo visible on the left and holds quote contrast on the
   right. Directive-sanctioned founder presence, scoped to this variant. */
.founder{position:relative;padding:calc(var(--sec-pad) + 2rem) 0;background:var(--field-2);overflow:hidden}
.founder .wrap{max-width:1640px}
.founder-veil{position:absolute;inset:0;pointer-events:none}
.founder-veil img{position:absolute;left:-40px;top:-40px;width:calc(100% + 80px);height:calc(100% + 80px);object-fit:cover;object-position:62% 30%;filter:blur(26px) saturate(0.9);opacity:0.9}
.founder-veil::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(var(--paper-rgb),0.18) 0%,rgba(var(--paper-rgb),0.34) 55%,rgba(var(--paper-rgb),0.62) 100%)}
.founder-split{position:relative;z-index:1;display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,0.85fr);gap:6rem;align-items:center}
.founder-frame{aspect-ratio:16/11;overflow:hidden;background:var(--field-3);border:1px solid rgba(var(--ink-rgb),0.10);box-shadow:0 30px 80px rgba(0,0,0,0.45)}
.founder-frame img{width:100%;height:100%;object-fit:cover;object-position:50% 35%}
.founder-body{padding-left:1rem}
.founder-quote{margin-top:0}
.founder-quote p{font-family:var(--serif);font-weight:600;font-size:var(--t-quote);letter-spacing:var(--track-serif);line-height:1.22;max-width:15.5em}
.founder-attrib{margin-top:2.4rem;font-size:var(--t-body);color:var(--lt)}   /* batch-2 pin: one size step up (t-small to t-body), full ink (--lt), name included */
.founder-name{font-weight:var(--w-5)}

/* ============ FAQ (single-open accordion; all answers in DOM, collapsed by
   grid-rows, never removed; no-JS shows every answer open) ============ */
.faq{position:relative;padding:var(--sec-pad) 0;background:var(--field-2);border-top:1px solid var(--hair)}
.faq-body{display:grid;grid-template-columns:minmax(0,0.55fr) minmax(0,1.45fr);gap:4rem;align-items:start}
.faq-head{position:sticky;top:7rem}
.faq-list{border-top:1px solid var(--hair-strong)}
.faq-item{border-bottom:1px solid var(--hair-strong)}
.faq-item h3{margin:0;font-size:inherit;font-weight:inherit}
.faq-q{display:flex;align-items:center;justify-content:space-between;gap:1.5rem;width:100%;padding:1.5rem 0;background:none;border:0;text-align:left;cursor:pointer;color:var(--lt);font-family:var(--serif);font-weight:var(--w-6);font-size:var(--t-lede-lg);line-height:var(--lh-sub);letter-spacing:var(--track-h3);text-wrap:balance}
.faq-q:hover span:first-child,.faq-q:focus-visible span:first-child{color:var(--peri)}
.faq-q:focus-visible{outline:2px solid var(--peri);outline-offset:4px}
.faq-ico{position:relative;flex:none;width:16px;height:16px}
.faq-ico::before,.faq-ico::after{content:"";position:absolute;left:0;top:7px;width:16px;height:2px;background:var(--lt);transition:transform 0.4s var(--ease)}
.faq-ico::after{transform:rotate(90deg)}
.faq-q[aria-expanded="true"] .faq-ico::after{transform:rotate(0deg)}
.faq-a{display:grid;grid-template-rows:0fr;transition:grid-template-rows 0.45s var(--ease)}
.faq-item:has(.faq-q[aria-expanded="true"]) .faq-a{grid-template-rows:1fr}
.faq-a-inner{overflow:hidden}
.faq-a p{max-width:40em;padding:0 0 1.7rem;font-size:var(--t-lede);line-height:var(--lh-body);color:var(--lt-2)}
.faq-a p a{color:var(--peri)}   /* in-prose link grammar per .mega-foot p a; carries the answer's /audit link */
@media (max-width:991px){.faq-body{grid-template-columns:1fr;gap:2rem}.faq-head{position:static}}
@media (prefers-reduced-motion: reduce){.faq-a,.faq-ico::before,.faq-ico::after{transition:none}}
body:not(.js) .faq-a{grid-template-rows:1fr}

/* ============ PROOF (the audit demo, question list + engine panel) ============ */
/* Two columns: a MARKET RAIL stands on the left, five markets as rows of
   industry-family label + city (the big text mirrors the industries bar's
   exact strings; the specialty lives in the prompt itself, which sits in
   the ask bar and in an .sr span on each rail button) over a wide map tile
   filling the right side of the row (1500m renders, faded at both ends),
   the active row lit and the rest dropped well back; the engine panel sits
   right, showing ONE engine at a time behind tabs, with an agreement line
   under the count (how many names all four engines returned). The active
   market's question TYPES itself into the ask pill, breaking at the first
   sentence (pre-line; the IIFE swaps the first ". " for ".\n" on display,
   data-q stays verbatim) to the tallest prompt's height; a 1px rule tracks
   the cycle beneath the active rail item (its animationend advances, so
   pausing pauses the truth).
   Chips arrive ONE AT A TIME rather than as a batch, and the ghost "Your
   name?" slot lands last, after the real names have finished. The engine
   panel is the page's PERIWINKLE ZONE, ACCENT DEPLOYMENT 3 of 3: the count,
   the active question number, the active tab underline, the timing rule,
   the capture-note dot and the ghost slot's dashed ring all take --peri,
   and the panel edge reads faintly blue; nothing outside the panel and the
   active question item gains blue. The section is a SHORT PINNED CHAPTER
   with the hero's shape (tall outer, sticky 100vh inner, see the proof
   chapter IIFE): the ask bar is first seen alone, large and centered,
   typing the first question; on scroll it travels (one element, one
   uniform transform) onto an empty slot at the top of the stage, the stage
   clip drops open beneath it, the question column slides in, the close
   line fades up. Every value is an inline style written per frame, so the
   CSS defaults here ARE the finished state (no clip, no transform, full
   opacity). Hover, focus, or offscreen pauses everything. All five panels
   and all four engine groups stay in the DOM; reduced motion holds the
   first question completed with chips static; no-JS shows q1 with every
   engine visible. */
/* the 220vh is the chapter's scroll runway; the proof IIFE repeats it in
   its inline height, grown by the headwrap in short mode and by the pin's
   excess over the viewport in full mode (calc(220vh + Npx)), so the pin's
   STUCK runway is 120vh at every height: one constant, two homes, change
   both or neither */
.proof{position:relative;height:220vh;background:var(--field)}
/* the pin is min-height 100vh rather than a fixed 100vh: when the module is
   a little taller than the viewport (most laptops) the pin grows to fit it,
   sticks at the top, and its lower edge scrolls into view as it releases;
   the chapter's progress completes half a viewport of scroll BEFORE that
   release and latches (proof IIFE, round 38), so nothing is clipped */
.proof-pin{position:sticky;top:0;min-height:100vh;overflow:hidden;display:flex;align-items:center}
.proof-pin>.wrap{position:relative;width:100%;padding-top:6rem;padding-bottom:5rem}
.proof-head{max-width:820px;margin-bottom:3.2rem;will-change:transform,opacity}
.proof-head h2{font-family:var(--serif);font-weight:var(--w-4);font-size:var(--t-disp2);letter-spacing:var(--track-serif);line-height:var(--lh-disp);margin-bottom:1.4rem}
.dm{display:grid;grid-template-columns:minmax(0,0.86fr) minmax(0,1.14fr);gap:4.5rem;align-items:start}
.dm-qcol{position:relative;will-change:transform,opacity}
.dm-qlist{list-style:none;border-top:1px solid var(--hair)}
.aq{position:relative;display:flex;align-items:center;width:100%;text-align:left;padding:1.15rem 0;border-bottom:1px solid var(--hair);overflow:hidden;min-height:92px}
/* the tile is the right side of the row: a taller-than-row crop of the
   square source (height 200%) so streets, not padding, fill the strip;
   the horizontal mask fades it out at both ends */
.aq-map{position:absolute;right:0;top:50%;transform:translateY(-50%);height:200%;width:52%;object-fit:cover;opacity:0.3;filter:grayscale(1);transition:opacity 0.7s var(--ease),filter 0.7s var(--ease);pointer-events:none;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 40%,#000 82%,transparent 100%);mask-image:linear-gradient(90deg,transparent 0,#000 40%,#000 82%,transparent 100%)}
.aq-body{position:relative;z-index:1;display:flex;flex-direction:column;min-width:0;max-width:55%}
.aq-num{font-size:var(--t-idx);font-weight:var(--w-5);color:var(--lt-3);margin-bottom:0.35rem;transition:color 0.5s var(--ease)}
.aq-market{font-family:var(--serif);font-weight:var(--w-6);font-size:var(--t-lede-lg);line-height:var(--lh-sub);letter-spacing:var(--track-h3);color:var(--lt-3);opacity:0.5;transition:opacity 0.7s var(--ease),color 0.7s var(--ease)}
.aq-city{font-size:var(--t-small);color:var(--lt-3);opacity:0.6;transition:opacity 0.7s var(--ease)}
.aq[aria-current="true"] .aq-num{color:var(--peri)}
.aq[aria-current="true"] .aq-market{color:var(--lt);opacity:1}
.aq[aria-current="true"] .aq-city{opacity:1}
.aq[aria-current="true"] .aq-map{opacity:0.9;filter:none}
.aq:hover .aq-market,.aq:focus-visible .aq-market{opacity:0.8}
.aq:hover .aq-map,.aq:focus-visible .aq-map{opacity:0.55}
@media (prefers-reduced-motion: reduce){.aq-map,.aq-market,.aq-city,.aq-num{transition:none}}
.dm-rule{position:absolute;left:0;top:0;width:100%;height:1px;transition:transform 0.7s var(--ease);pointer-events:none}
.dm-run{position:absolute;left:0;top:0;width:100%;height:1px;background:var(--peri);transform:scaleX(0);transform-origin:left}
body.js .dm-run.is-run{animation:dm-run 4500ms linear forwards}
.dm.is-paused .dm-run.is-run{animation-play-state:paused}
@keyframes dm-run{from{transform:scaleX(0)}to{transform:scaleX(1)}}
/* round 38: the stage carries the card radius; its 2rem+ padding keeps every
   child (slot, meta, tabs, chips, capture line, the docked ask bar) clear
   of the corner arcs, and the unfurl clip is a straight bottom edge, so
   nothing inside needs its own rounding */
.dm-stage{position:relative;background:var(--field-2);border:1px solid rgba(92,144,255,0.14);border-radius:var(--r-card);padding:2rem 2.2rem 1.7rem;will-change:clip-path}
/* the slot holds the ask bar's place inside the stage (same box and margin
   the bar has when it lands); JS writes --ask-h from the bar's measured
   height so the slot always matches the real bar. The ask text breaks at
   the sentence (pre-line), not by balancing */
.dm-slot{height:var(--ask-h,62px);margin-bottom:1.7rem}
.dm-body{will-change:transform,opacity}
/* the ask bar lives outside the stage, absolutely positioned in the pin's
   wrap, and is moved by a single translate + uniform scale from its large
   centered rest box onto the slot. The text breaks after its first
   sentence (pre-line, newline supplied by the demo IIFE), and JS fixes
   the bar's min-height to the tallest prompt at the slot width, so a
   two-line question and a one-line question dock identically; flex centers
   a one-line prompt in the two-line-tall bar */
.dm-ask--float{position:absolute;left:0;top:0;transform-origin:0 0;will-change:transform;z-index:2}
.dm-ask{display:flex;align-items:center;border:1px solid var(--hair-strong);border-radius:999px;padding:0.85rem 1.4rem;background:var(--field-2)}
.dm-ask-text{font-family:var(--font);font-weight:var(--w-5);font-size:var(--t-lede);letter-spacing:0;line-height:var(--lh-sub);color:var(--lt);white-space:pre-line}
.dm-caret{display:inline-block;width:2px;height:0.95em;background:var(--lt);margin-left:4px;vertical-align:baseline;animation:dm-caret 1.1s steps(2,start) infinite}
@keyframes dm-caret{to{visibility:hidden}}
@media (prefers-reduced-motion: reduce){.dm-caret{animation:none}}
.dm-meta{display:flex;justify-content:space-between;align-items:baseline;gap:1.5rem;padding-bottom:1.3rem;font-size:var(--t-small);color:var(--lt-3)}
.dm-count{font-size:var(--t-lede);font-weight:var(--w-6);color:var(--peri);margin-right:0.45rem}
.dm-agree{font-size:var(--t-small);color:var(--lt-3);margin-top:0.35rem}
.dm-agree-n{color:var(--peri);font-weight:var(--w-6)}
.dm-tabs{display:flex;border-bottom:1px solid var(--hair);flex-wrap:wrap}
.dm-tab{display:inline-flex;align-items:center;gap:0.6rem;padding:0.95rem 1.15rem;font-size:var(--t-label);font-weight:var(--w-6);letter-spacing:var(--track);text-transform:uppercase;color:var(--lt-3);position:relative;transition:color 0.4s var(--ease)}
.dm-tab:first-child{padding-left:0}
.dm-tab[aria-current="true"]{color:var(--lt)}
.dm-tab[aria-current="true"]::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;background:var(--peri)}
.dm-tab:first-child[aria-current="true"]::after{left:0}
.dm-eng{padding-top:1.8rem;min-height:180px}
.dm-chips{list-style:none;display:flex;flex-wrap:wrap;gap:0.6rem}
.dm-chip{font-size:var(--t-small);color:var(--lt-2);background:transparent;border:1px solid var(--hair-strong);border-radius:999px;padding:0.42rem 0.95rem}
.dm-chip--more{color:var(--lt-3);border-style:dashed}
.dm-chip--you{color:var(--lt-3);border:1px dashed rgba(92,144,255,0.45)}
body.js .dm-eng{display:none}
body.js .dm-eng.is-shown{display:block}
body.js .dm-eng.is-lit .dm-chip{opacity:0;transform:translateY(7px);animation:dm-in 0.5s var(--ease) forwards}
body.js .dm-eng.is-lit .dm-chip--you{animation:dm-in 0.5s var(--ease) forwards,you-pulse 2.8s var(--ease) 1.1s infinite}
@keyframes dm-in{to{opacity:1;transform:none}}
@keyframes you-pulse{0%,100%{opacity:0.55}50%{opacity:1}}
@media (prefers-reduced-motion: reduce){
  body.js .dm-run.is-run{animation:none}
  body.js .dm-eng.is-lit .dm-chip,body.js .dm-eng.is-lit .dm-chip--you{opacity:1;transform:none;animation:none}
  .dm-rule{transition:none}
}
.dm-capture{display:flex;gap:0.8rem;align-items:center;margin-top:1.6rem;padding-top:1.3rem;border-top:1px solid var(--hair);font-size:var(--t-small);color:var(--lt-3)}
.dm-capture::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--peri);flex:none}
.proof-close{display:flex;justify-content:space-between;align-items:center;gap:2rem;margin-top:5rem;padding-top:2.4rem;border-top:1px solid var(--hair);flex-wrap:wrap;will-change:transform,opacity}
/* tight state (JS, on resize): when the wrap overruns the viewport the
   rhythm closes up before the chapter would fall back to short or static.
   The tight pin is TOP-ANCHORED with nav clearance instead of centered
   (centering a wrap taller than the viewport put negative space at both
   ends and clipped the headline's ascenders under the fixed bar); 87px is
   the rendered .nav-bar height (1.3rem x 2 bar padding + the 45px outline
   CTA: 0.72rem label at 1.65 line-height + 0.75rem x 2 padding + 2px
   border). The wrap's own top padding drops to 1rem: the pin's padding is
   the clearance now. */
body.js .proof.is-tight .proof-pin{align-items:flex-start;padding-top:calc(87px + 1.6rem)}
/* 1.5rem (from 2rem): the pin's nav padding pushed the close line to the
   fold at 1920x1080; the head margin is the bottom-end knob (it moves the
   full height and the head height equally, so the short-mode decision is
   unaffected by it) */
body.js .proof.is-tight .proof-head{margin-bottom:1.5rem}
body.js .proof.is-tight .proof-close{margin-top:3rem}
body.js .proof.is-tight .proof-pin>.wrap{padding-top:1rem}
/* short mode (JS): the full wrap is too tall for the pin but the wrap minus
   the head fits, so the chapter runs with the head RELOCATED above the pin
   (a reversible DOM move into .proof-headwrap, the JS-created first child
   of the section) where it scrolls off in normal flow before the pin
   sticks, instead of being clipped by the pin's overflow; the pin is a
   FIXED 100vh (never grows to the wrap, unlike the base min-height) with
   the wrap anchored to its bottom. The headwrap's padding-top stands in
   for the wrap's head rhythm; it is hidden outside short mode. Placed
   after the is-tight rules so flex-end and the zeroed pin padding win
   when both classes are on. */
.proof-headwrap{padding-top:5rem}
body.js .proof.is-short .proof-pin{height:100vh;align-items:flex-end;padding-top:0;padding-bottom:1.5rem}
/* short-mode compaction bundle: applies ONLY under is-short, so full mode
   never changes. The IIFE decides short mode by MEASURING this compacted
   layout (tentative class, reflow, fit check), so the fit is a
   measurement, not a guess. Sized deep enough that the module fits a real
   laptop browser viewport (~620px of innerHeight, not screen height). */
body.js .proof.is-short .aq{padding:0.65rem 0;min-height:72px}
body.js .proof.is-short .aq-market{font-size:1.15rem}
body.js .proof.is-short .dm{gap:3.5rem}
body.js .proof.is-short .proof-pin>.wrap{padding-bottom:2rem}
body.js .proof.is-short .proof-close{margin-top:1.5rem;padding-top:1.2rem}
body.js .proof.is-short .dm-capture{margin-top:0.8rem;padding-top:0.7rem}
.proof-close p{font-family:var(--serif);font-weight:var(--w-4);font-size:var(--t-ask);letter-spacing:var(--track-serif);line-height:var(--lh-sub)}
/* short viewports: tighten the module's internals so the whole chapter
   fits in 100vh (the vertical rhythm is handled by the is-tight guard in
   the IIFE; the chapter falls back to static when it still does not fit) */
@media (max-height:820px){
  body.js .proof .aq{padding:0.9rem 0;min-height:84px}
  body.js .proof .dm-eng{min-height:140px}
}
@media (max-height:700px){
  body.js .proof .proof-pin>.wrap{padding-top:4rem;padding-bottom:1.5rem}
  body.js .proof .proof-head h2{font-size:clamp(2.1rem,3vw,2.6rem)}
}
/* fallback (no-JS) and reduced motion (JS adds .is-static, and moves the
   bar into the stage before #dm-body): the pin collapses to normal flow,
   the slot is dropped and the bar sits statically where the slot was. Under
   no-JS the markup order leaves the bar after the module (below it); that
   is accepted: no-JS only needs to be readable, and it is. */
body:not(.js) .proof,.proof.is-static{height:auto}
body:not(.js) .proof-pin,.proof.is-static .proof-pin{position:static;height:auto;display:block;overflow:visible}
body:not(.js) .dm-ask--float,.proof.is-static .dm-ask--float{position:static;transform:none;margin-bottom:1.7rem}
body:not(.js) .dm-slot,.proof.is-static .dm-slot{display:none}
@media (max-width:1099px){
  .dm{grid-template-columns:1fr;gap:3rem}
}
@media (max-width:600px){
  .dm-stage{padding:1.4rem 1.2rem}
  .dm-tab{padding:0.8rem 0.75rem}
  .aq-map{width:44%;opacity:0.22}
}

/* ============ INDUSTRIES (thin divider bar, directly after the hero) ============ */
/* The concept-4 bar treatment restyled to this palette: all seven names in
   one quiet line between hairlines, the lit state stepping name to name on
   an IO-gated timer, hover pinning the highlight to the pointed name, Real
   Estate Agents the default lit state (and the reduced-motion / no-JS
   state). Hierarchy is tone plus a soft periwinkle radial glow behind the
   lit name (accent as state: it travels with the lit name). The glow is a
   ::before on the name with
   a negative-margin / positive-padding pair so the row's layout is
   unchanged; the row is a stacking context so the glow's z-index:-1 stays
   inside it. */
.industries{padding:3rem 0;background:var(--field-2)}
.ind-bar{border-top:1px solid var(--hair);border-bottom:1px solid var(--hair);padding:1.4rem 0 1.6rem;container-type:inline-size}
.ind-head{display:flex;justify-content:space-between;align-items:baseline;gap:2rem;margin-bottom:1.1rem}
.ind-row{list-style:none;display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:0.5rem 2rem;position:relative;z-index:0}
/* size: as large as ONE line allows. ROUND 14 (Mark's review): more air and
   more weight: the name gap steps up one token (1.4rem to 2rem, the wrapped
   state's own gap) and the names step up one weight (--w-5 to --w-6).
   ROUND 28 re-derivation, measured AFTER document.fonts.ready with Fontshare
   Switzer actually loaded (headless Chrome, letter-spacing normal): the
   seven names at weight 600 advance 68.484px per px of font size (per name
   8.644 / 8.671 / 10.463 / 15.510 / 9.492 / 6.997 / 8.707). Divisor =
   68.484 x 1.03 slack = 70.54, rounded up: 71 - the round-14 divisor stands
   (real slack 3.67%) against the 6 x 2rem gap total. FONTS-READY CAVEAT:
   measured before font load the strip reads the Arial fallback at 71.06px
   per px - over this budget - so every measurement of this strip (and any
   text-fit gate) must await document.fonts.ready first. The round-28
   staging wrap was NOT this formula: Webflow's base-sheet ul rule stole
   40px of the row as padding-left - see the html ul guard in the global
   layer. The wrap breakpoint moves with the fit (see the media rules): at
   the 0.9rem floor the names hold 986.2px, and a classic scrollbar splits
   the arithmetic (media width and the 5vw gutters key on innerWidth, the
   row on clientWidth, worst case 17px apart), so the 6 x 2rem gaps
   (986.2 + 192, +3px safety) need 0.9 x viewport - 17 >= 1181.2: one line
   from 1340 up; from 1280 to 1339 the column gap steps down one token to
   1.4rem (986.2 + 134.4 + 3 = 1123.6 <= 1135 at 1280 worst case) so laptop
   widths hold one line; below 1280 the row becomes a left-aligned wrapped
   list so a short last line never spreads one orphan across the bar. */
.ind-name{position:relative;padding:0.35rem 0.6rem;margin:-0.35rem -0.6rem;font-size:clamp(0.9rem,calc((100cqw - 6 * 2rem) / 71),1.3rem);font-weight:var(--w-6);color:var(--lt-3);transition:color 0.4s var(--ease)}
.ind-name::before{content:"";position:absolute;inset:-0.4rem -0.9rem;border-radius:999px;background:radial-gradient(closest-side,rgba(92,144,255,0.16),rgba(92,144,255,0.05) 60%,transparent);opacity:0;transition:opacity 0.6s var(--ease);pointer-events:none;z-index:-1}
.ind-name.is-lit{color:var(--lt)}
.ind-name.is-lit::before{opacity:1}
@media (prefers-reduced-motion: reduce){.ind-name{transition:none}.ind-name::before{transition:none}}
@media (min-width:1280px) and (max-width:1339px){.ind-row{gap:0.5rem 1.4rem}}   /* laptop squeeze: at the 0.9rem floor the 2rem gaps miss the row here; one token down (6 x 0.6rem = 57.6px back) holds one line from 1280 up. Round 28: the round-27 top edge (1309) was derived scrollbar-blind and left 1310-1325 wrapping with a classic scrollbar; the band now runs to 1339 per the worst-case arithmetic in the clamp comment above */
@media (max-width:1279px){.ind-row{justify-content:flex-start;gap:0.6rem 2rem}}   /* wrapped state, unchanged from round 14 (was <=1309 in round 27, <=1339 since round 28: the squeeze band above owns that window) */

/* ============ ENDING (the footer on the field) ============ */
/* The signature page ending, reused on every page: one wrapper holds the
   footer over a single lava-lamp field of periwinkle. Four blurred blobs
   in three tones of the one hue (deeper under, base, paler on top) drift
   on long alternating keyframes so the field reads as depth, not a stain.
   A linear mask on the whole layer does the fade: transparent at the
   footer's top, building through it, full strength at the close. The
   footer is transparent and only its content wrap is lifted. Reduced
   motion and no-JS: the blobs sit still at their from positions, still a
   gradient. */
.ending{position:relative;background:var(--field-2);overflow:hidden;isolation:isolate}
.ending-bg{position:absolute;inset:0;pointer-events:none;z-index:0;
  -webkit-mask-image:linear-gradient(180deg,transparent 0%,rgba(0,0,0,0.3) 30%,rgba(0,0,0,0.8) 65%,#000 100%);
  mask-image:linear-gradient(180deg,transparent 0%,rgba(0,0,0,0.3) 30%,rgba(0,0,0,0.8) 65%,#000 100%)}
.blob{position:absolute;border-radius:50%;filter:blur(90px);opacity:0.55;will-change:transform}
/* three tones of one hue: deeper under, base, paler on top. Round-14 triad,
   confirmed by the round-20 single-hue ruling: base tone is the one
   periwinkle's triplet 92,144,255 (#5C90FF); deep #416CD7 (65,108,215),
   pale #ADC6FF (173,198,255). Keep in sync with site/site.css's ending
   block. */
.blob-1{background:radial-gradient(circle at 40% 40%,rgba(92,144,255,0.85),rgba(92,144,255,0.35) 50%,transparent 72%);z-index:1}
.blob-2{background:radial-gradient(circle at 40% 40%,rgba(65,108,215,0.8),rgba(65,108,215,0.3) 50%,transparent 72%);z-index:0}
.blob-3{background:radial-gradient(circle at 40% 40%,rgba(173,198,255,0.95),rgba(173,198,255,0.4) 50%,transparent 72%);z-index:2}
.blob-4{background:radial-gradient(circle at 40% 40%,rgba(92,144,255,0.85),rgba(92,144,255,0.35) 50%,transparent 72%);z-index:1}
.blob-1{width:52vw;height:52vw;left:-14vw;top:8%;animation:drift1 26s ease-in-out infinite alternate}
.blob-2{width:44vw;height:44vw;right:-10vw;top:22%;animation:drift2 31s ease-in-out infinite alternate}
.blob-3{width:38vw;height:38vw;left:28vw;bottom:-12%;animation:drift3 23s ease-in-out infinite alternate}
.blob-4{width:30vw;height:30vw;right:18vw;bottom:2%;opacity:0.4;animation:drift4 35s ease-in-out infinite alternate}
@keyframes drift1{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(12vw,10vh,0) scale(1.15)}}
@keyframes drift2{from{transform:translate3d(0,0,0) scale(1.05)}to{transform:translate3d(-14vw,14vh,0) scale(0.9)}}
@keyframes drift3{from{transform:translate3d(0,0,0) scale(0.95)}to{transform:translate3d(-10vw,-12vh,0) scale(1.2)}}
@keyframes drift4{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(8vw,-8vh,0) scale(1.1)}}
@media (prefers-reduced-motion: reduce){.blob{animation:none}}
@media (max-width:767px){.blob{filter:blur(60px)}.blob-1,.blob-2{width:90vw;height:90vw}.blob-3,.blob-4{width:70vw;height:70vw}}

/* ============ FOOTER (transparent over the ending field, bare link grid) ============ */
/* No background and no top hairline of its own: the footer sits directly
   on the ending field, which fades in from its top edge. The navigation is
   a bare four-column link grid sitting directly on the field,
   one hairline above and one below, no card, no surface; headings in --lt-3
   and links in --lt (display register at reading scale) so they read on the
   field. Entity line and meta sit below the grid. */
.footer{position:relative;background:transparent;padding:7.5rem 0 2.2rem;overflow:hidden}
.footer>.wrap{position:relative;z-index:2}
/* atom-mark cursor trail (lives in the footer). White
   echoes at fixed per-echo CSS sizes; the JS applies translate-only
   transforms rounded to whole pixels and never scale(), so the trail
   settles sharp when the pointer rests. Layered below the footer content
   and the lockup. Absent on touch, hidden under reduced motion. */
.trail-echo{position:absolute;top:0;left:0;height:auto;pointer-events:none;opacity:0;z-index:1;will-change:transform}
.trail-echo:nth-of-type(1){width:74px}
.trail-echo:nth-of-type(2){width:64px}
.trail-echo:nth-of-type(3){width:54px}
.trail-echo:nth-of-type(4){width:46px}
.trail-echo:nth-of-type(5){width:38px}
@media (hover:none),(pointer:coarse){.trail-echo{display:none}}
@media (prefers-reduced-motion: reduce){.trail-echo{display:none}}
.foot-lead{max-width:22em}
.foot-lead h2{font-family:var(--serif);font-weight:500;font-size:var(--t-disp2);letter-spacing:var(--track-serif);line-height:var(--lh-disp)}
.foot-lead .tlink{margin-top:1.7rem}
.foot-card{background:transparent;border:0;padding:0.6rem 0 2.6rem;border-top:1px solid var(--hair);border-bottom:1px solid var(--hair);margin-top:3.6rem;display:grid;grid-template-columns:repeat(4,1fr);gap:2.4rem}
.foot-col h3{font-size:var(--t-small);font-weight:var(--w-5);color:var(--lt-3);margin-bottom:1.2rem}
.foot-col ul{list-style:none;display:flex;flex-direction:column;gap:0.75rem}
.foot-col a{font-family:var(--serif);font-weight:500;font-size:1.15rem;letter-spacing:var(--track-serif);color:var(--lt);position:relative}
.foot-col a::after{content:"";position:absolute;left:0;bottom:-2px;width:100%;height:1px;background:var(--lt);transform:scaleX(0);transform-origin:right;transition:transform 0.45s var(--ease)}
.foot-col a:hover::after,.foot-col a:focus-visible::after{transform:scaleX(1);transform-origin:left}
.foot-entity{margin-top:3rem;font-size:var(--t-small);color:var(--lt-3);max-width:52em}
.foot-row{display:flex;justify-content:space-between;align-items:center;gap:2rem;flex-wrap:wrap;margin-top:2.6rem;padding-top:2rem;border-top:1px solid var(--hair)}
.foot-row img{height:22px;width:auto;opacity:0.85}
.foot-meta{display:flex;gap:1.6rem;font-size:var(--t-small);color:var(--lt-3);flex-wrap:wrap;align-items:baseline}
.foot-osm{font-size:0.72rem;opacity:0.7}   /* OSM credit: ODbL requires the attribution (a licensing constraint, not a style choice); smallest register, lowest readable contrast */
@media (max-width:991px){
  .foot-card{grid-template-columns:1fr 1fr;gap:2rem;padding:0.6rem 0 2.2rem}
}
@media (max-width:600px){
  .foot-card{grid-template-columns:1fr;padding:0.6rem 0 1.8rem}
  .foot-row{flex-direction:column;align-items:flex-start}
  /* mobile hit areas (chrome audit, September 2026; keep in sync with
     site/site.css): 30px link line + 11px padding = 41px; the ul gap
     drops so the rhythm holds */
  .foot-col ul{gap:0.4rem}
  .foot-col a{display:inline-block;padding:0.35rem 0}
  .footer .tlink{padding-top:0.65rem}   /* 22px line + 10px top + 8px bottom = 40px */
}
@media (prefers-reduced-motion: reduce){.foot-col a::after{transition:none}}

/* display register: every display surface runs Switzer 600 (one family
   sitewide, weight and scale do the voice work) */
.hero-display,.founder-quote p,.proof-head h2,.proof-close p,.sec-h2,.aq-market,.faq-q,.foot-lead h2,.foot-col a{font-weight:600}

/* section headers: a large serif h2 with one line of support beneath,
   action cluster pushed right and bottom-aligned to the block. Replaces
   the tiny quiet-h2 label on the sections that open a full block; the
   thin industries bar keeps quiet-h2 (it is a divider, not a section
   opening). */
.sec-head-text{max-width:38em}
.sec-h2{font-family:var(--serif);font-size:var(--t-disp2);letter-spacing:var(--track-serif);line-height:var(--lh-disp)}
.sec-sub{margin-top:0.9rem;font-size:var(--t-lede);color:var(--lt-2);max-width:30em}
.testi-head{align-items:flex-end}

/* section reveal: every section below the hero rises gently into place
   once, on a lower threshold than the per-element .rv reveals so the
   block arrives first and its contents settle inside it. Nav and hero
   are excluded (the hero runs its own stagger). */
body.js [data-section="industries"],
body.js [data-section="testimonials"],
body.js [data-section="site"],
body.js [data-section="founder"],
body.js [data-section="faq"],
body.js [data-section="proof"],
body.js [data-section="footer"]{opacity:0;transform:translateY(34px);transition:opacity 1.1s var(--ease),transform 1.1s var(--ease)}
body.js [data-section].sec-in{opacity:1;transform:none}
@media (prefers-reduced-motion: reduce){
  body.js [data-section]{opacity:1;transform:none;transition:none}
}

/* ============ BREAKPOINTS ============ */
@media (max-width:991px){
  :root{--sec-pad:5.5rem}
  .founder-split{grid-template-columns:1fr;gap:2.6rem}
  .founder-frame{max-width:640px;aspect-ratio:16/11}
  .founder-body{padding-left:0}
  .dm-eng{grid-template-columns:130px 1fr;gap:1.2rem}
}
@media (max-width:767px){
  .dm-eng{grid-template-columns:1fr;gap:0.7rem;padding:1.2rem 0}
  .dm-eng-label{padding-top:0}
  .proof-close{flex-direction:column;align-items:flex-start}
  /* ROUND 39 (phone): the wrapped stack reads as CENTERED LINES. At the
     0.9rem floor (14.4px, Switzer 600) the seven names advance 124.5 / 124.9
     / 150.7 / 223.3 / 136.7 / 100.8 / 125.4px; the long one (Accountants &
     Financial Advisors, the 4th li) takes order:1 so it closes the stack
     alone and the other six pair up: with the 1.4rem gap the greedy wrap is
     271.8 / 309.8 / 248.6px per line, which holds 2 / 2 / 2 / 1 for every
     row width from 310 to 432px (viewports 345 to 480) and 3 / 3 / 1 wider
     (measured, fonts.ready). The industries IIFE walks the light along the
     lines as drawn (it re-sorts the step order by position on phones), so
     the visual reorder never makes the lit state jump. The head centers
     over the stack. */
  .ind-row{justify-content:center;gap:0.5rem 1.4rem}
  .ind-row .ind-name:nth-child(4){order:1}
  .ind-head{flex-wrap:wrap;row-gap:0.6rem;justify-content:center;text-align:center}
}
@media (max-width:478px){
  :root{--sec-pad:4.5rem}
  .foot-row{flex-direction:column;align-items:flex-start}
  .foot-meta{flex-direction:column}
}
