/* ===========================================================================
   Refract Spaces — refractspaces.com
   ---------------------------------------------------------------------------
   One brand hue (#2A73FF, hsl 219 100% 58%) refracted into a full tonal
   scale. Nothing on this site uses a colour off that hue except pure white
   and the hue-tinted near-blacks, which is what makes it read as one
   material rather than a palette.

   Contrast policy — the brand blue is only 3.6:1 on white, so:
     · #2A73FF is used on DARK surfaces (where it is brilliant) and as a
       non-text accent on light ones (rules, glows, icon strokes, borders).
     · Text and solid buttons on light surfaces use --b600 / --b700, which
       clear 4.5:1 and 7:1 respectively.
   Every text pairing in this file has been checked against WCAG AA.
   =========================================================================== */

:root {
    /* ---- The refracted scale. Single hue, 219°. ---- */
    --b50:  #F0F5FF;
    --b100: #DBE8FF;
    --b200: #B8D1FF;
    --b300: #8AB3FF;
    --b400: #5792FF;
    --b500: #2A73FF;   /* brand */
    --b600: #0C5BED;   /* text-safe on white — 4.9:1 */
    --b700: #0C4BC0;   /* strong text on white — 7.0:1 */
    --b800: #0F388A;
    --b900: #0E2558;
    --b950: #0B1732;

    /* ---- Hue-tinted neutrals. Never a true grey — everything leans 219°. ---- */
    --void:     #060B1A;   /* deepest surface: hero, footer, CTA */
    --canvas:   #0A1029;   /* raised dark surface */
    --canvas-2: #111A3D;   /* dark cards */
    --paper:    #F7F9FE;   /* page background */
    --surface:  #FFFFFF;
    --ink:      #0B1220;   /* body text on light — 17.4:1 */
    --ink-soft: #46536E;   /* secondary text on light — 7.5:1 */
    --ink-mute: #66718F;   /* tertiary / captions — 4.86:1 on white, verified */
    --line:     #DDE4F5;
    --line-str: #C3D0EC;

    /* On dark surfaces */
    --d-text:   #EEF3FF;   /* 16.9:1 on --void */
    --d-soft:   #A9B8DC;   /* 8.2:1  on --void */
    --d-mute:   #7C8CB4;   /* 4.9:1  on --void */
    --d-line:   rgba(138, 179, 255, 0.16);

    /* ---- Type ---- */
    --display: 'Instrument Sans', ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
    --sans:    'Inter', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Consolas, monospace;

    /* ---- Space & shape ---- */
    --maxw:   1140px;
    --narrow: 760px;
    --gutter: clamp(20px, 5vw, 48px);
    --r-sm:   8px;
    --r:      14px;
    --r-lg:   22px;

    /* ---- Motion. Short, decisive, one shared curve. "Quick" is the brief. ---- */
    --ease:      cubic-bezier(0.22, 1, 0.36, 1);   /* out-expo-ish: fast start, soft stop */
    --ease-in:   cubic-bezier(0.55, 0, 1, 0.45);
    --t-fast:    140ms;
    --t:         220ms;
    --t-slow:    380ms;

    --shadow-sm: 0 1px 2px rgba(11, 23, 50, 0.06), 0 2px 8px rgba(11, 23, 50, 0.04);
    --shadow:    0 2px 4px rgba(11, 23, 50, 0.05), 0 12px 32px rgba(11, 23, 50, 0.08);
    --shadow-lg: 0 4px 8px rgba(11, 23, 50, 0.06), 0 24px 60px rgba(11, 23, 50, 0.13);
    --glow:      0 0 0 1px rgba(42, 115, 255, 0.30), 0 8px 40px rgba(42, 115, 255, 0.28);
}

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

/* The UA rule for [hidden] is `display: none` at the lowest specificity, so
   any class that sets display (a grid, a flex row) silently defeats it and
   the element stays on screen. Enforce it once, here. */
[hidden] { display: none !important; }

html {
    scroll-behavior: smooth;
    scroll-padding-top: 88px;      /* sticky nav clearance for anchor jumps */
    -webkit-text-size-adjust: 100%;
}

/* Cross-document view transitions: page-to-page navigation cross-fades
   instead of flashing white. One declaration, no JavaScript, and browsers
   without support simply navigate as normal — so it costs nothing and makes
   a static multi-page site feel like one continuous surface.
   Deliberately faster than the default; a slow page transition reads as lag. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 180ms;
    animation-timing-function: var(--ease);
}

@media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root),
    ::view-transition-new(root) { animation: none; }
}

body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 17px;
    line-height: 1.62;
    font-feature-settings: "cv05" 1, "ss01" 1;   /* Inter: friendlier l, single-storey a */
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;            /* the hero beam overshoots the viewport by design */
}

img, svg, video { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }

/* Focus: visible, on-brand, and never clipped. Keyboard users are often the
   technical evaluator deciding whether we know what we're doing. */
:focus-visible {
    outline: 2px solid var(--b500);
    outline-offset: 3px;
    border-radius: 4px;
}
:focus:not(:focus-visible) { outline: none; }

::selection { background: var(--b200); color: var(--b950); }

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    background: var(--b700);
    color: #fff;
    padding: 12px 20px;
    border-radius: 0 0 var(--r-sm) 0;
    font-weight: 600;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------------------------------------
   Typography scale
   --------------------------------------------------------------------------- */
h1, h2, h3, h4 {
    font-family: var(--display);
    font-weight: 600;
    line-height: 1.08;
    letter-spacing: -0.028em;
    text-wrap: balance;            /* no orphan words in headlines */
}

h1 { font-size: clamp(2.35rem, 6.2vw, 4.15rem); letter-spacing: -0.035em; }
h2 { font-size: clamp(1.85rem, 4.2vw, 2.85rem); }
h3 { font-size: clamp(1.15rem, 2vw, 1.4rem); line-height: 1.22; letter-spacing: -0.02em; }
h4 { font-size: 1.0rem; line-height: 1.3; letter-spacing: -0.01em; }

p { text-wrap: pretty; }

a { color: var(--b700); text-decoration-color: var(--b300); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--b600); }

strong { font-weight: 650; color: var(--ink); }
/* On dark surfaces the light-mode ink would render strong text nearly
   invisible — which is exactly where the positioning lines live. */
.section--dark strong, .hero strong, .footer strong { color: var(--d-text); }

.lede {
    font-size: clamp(1.075rem, 1.7vw, 1.28rem);
    line-height: 1.55;
    color: var(--ink-soft);
    max-width: 62ch;
}

/* The mono kicker. Used once per section as an orientation label — it is the
   device that keeps "what page am I on, what is this" always answered. */
.kicker {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-family: var(--mono);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--b700);
    margin-bottom: 18px;
}
.kicker::before {
    content: "";
    width: 22px;
    height: 1px;
    background: linear-gradient(90deg, var(--b500), transparent);
}
.kicker--dark { color: var(--b300); }
.kicker--dark::before { background: linear-gradient(90deg, var(--b400), transparent); }

/* ---------------------------------------------------------------------------
   Layout
   --------------------------------------------------------------------------- */
.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: var(--narrow); }

.section { padding-block: clamp(72px, 10vw, 132px); }
.section--tight { padding-block: clamp(56px, 7vw, 88px); }

/* Dark sections. Used for the hero, the process spine, and the closing CTA —
   the three moments where the brand blue should actually glow. */
.section--dark {
    background: var(--void);
    color: var(--d-text);
    position: relative;
    isolation: isolate;
}
.section--dark h1, .section--dark h2, .section--dark h3 { color: var(--d-text); }
.section--dark .lede { color: var(--d-soft); }
.section--dark a { color: var(--b300); text-decoration-color: var(--b600); }

/* Faint refracted grid on dark surfaces — reads as engineering paper, adds
   depth without a texture file. Pure CSS, zero bytes over the wire. */
.section--dark::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-image:
        linear-gradient(to right, rgba(138, 179, 255, 0.055) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(138, 179, 255, 0.055) 1px, transparent 1px);
    background-size: 64px 64px;
    mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 20%, transparent 78%);
    -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 20%, transparent 78%);
    pointer-events: none;
}

.section-head { max-width: 68ch; margin-bottom: clamp(36px, 5vw, 60px); }
/* Headings carry no bottom margin by default, so the supporting line needs
   its own breathing room or it reads as a fourth line of the headline. */
.section-head .lede, .section-head h2 + p { margin-top: 16px; }

/* ---------------------------------------------------------------------------
   Buttons
   The primary CTA is the same object everywhere on the site — same colour,
   same words, same weight — so it is never a decision, only a click.
   --------------------------------------------------------------------------- */
.btn {
    --btn-bg: var(--b600);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 14px 24px;
    border: 1.5px solid transparent;
    border-radius: 10px;
    background: var(--btn-bg);
    color: #fff;
    font-family: var(--sans);
    font-size: 0.975rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: transform var(--t-fast) var(--ease),
                box-shadow var(--t) var(--ease),
                background-color var(--t-fast) var(--ease);
}
.btn:hover { background: var(--b700); transform: translateY(-1px); box-shadow: var(--glow); text-decoration: none; }
.btn:active { transform: translateY(0); transition-duration: 60ms; }

/* Refraction sweep: a band of light crosses the button on hover. It is the
   hero animation's motif, miniaturised — the same idea at button scale. */
.btn::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(105deg, transparent 32%, rgba(255,255,255,0.28) 50%, transparent 68%);
    transform: translateX(-110%);
    transition: transform 520ms var(--ease);
    pointer-events: none;
}
.btn:hover::after { transform: translateX(110%); }

.btn--lg { padding: 17px 32px; font-size: 1.05rem; border-radius: 12px; }
.btn--sm { padding: 10px 17px; font-size: 0.9rem; border-radius: 8px; }
.btn--block { width: 100%; }

.btn--ghost {
    background: transparent;
    color: var(--b700);
    border-color: var(--line-str);
}
.btn--ghost:hover {
    background: var(--b50);
    border-color: var(--b400);
    color: var(--b700);
    box-shadow: none;
}
.btn--ghost::after { display: none; }

/* On dark surfaces the brand blue finally gets to be the button itself. */
.section--dark .btn { --btn-bg: var(--b500); color: #04091A; }
.section--dark .btn:hover { background: var(--b400); }
.section--dark .btn--ghost {
    background: rgba(138, 179, 255, 0.06);
    color: var(--d-text);
    border-color: var(--d-line);
}
.section--dark .btn--ghost:hover { background: rgba(138, 179, 255, 0.12); border-color: var(--b400); color: #fff; }

/* Trailing arrow that steps forward on hover — a 3px cue that this goes
   somewhere, not a 300ms animation that makes you wait for it. */
.btn .arw { transition: transform var(--t) var(--ease); }
.btn:hover .arw { transform: translateX(3px); }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }

/* Reassurance text that rides under every primary CTA. Removing risk at the
   exact moment of the click is worth more than any amount of persuasion
   twenty lines earlier. */
.cta-note {
    font-size: 0.845rem;
    color: var(--ink-mute);
    margin-top: 14px;
    display: flex;
    align-items: center;
    gap: 7px;
}
.section--dark .cta-note { color: var(--d-mute); }
.cta-note svg { flex: none; }

/* ---------------------------------------------------------------------------
   Navigation
   --------------------------------------------------------------------------- */
.nav {
    position: sticky;
    top: 0;
    z-index: 50;
    background: rgba(247, 249, 254, 0.78);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid transparent;
    transition: border-color var(--t) var(--ease), background-color var(--t) var(--ease);
}
.nav.is-stuck { border-bottom-color: var(--line); background: rgba(247, 249, 254, 0.93); }

.nav__inner {
    max-width: var(--maxw);
    margin-inline: auto;
    padding: 14px var(--gutter);
    display: flex;
    align-items: center;
    gap: clamp(16px, 3vw, 36px);
}

.nav__brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: var(--display);
    font-weight: 600;
    font-size: 1.06rem;
    letter-spacing: -0.025em;
    color: var(--ink);
    text-decoration: none;
    margin-right: auto;
}
.nav__brand:hover { text-decoration: none; }
/* The real brand mark, traced to vector from the original artwork so it stays
   crisp at every size and weighs about a kilobyte. */
.nav__mark {
    flex: none;
    width: 30px;
    height: auto;
    transition: transform var(--t-slow) var(--ease);
}
/* Leans forward on hover — the direction the mark already points. */
.nav__brand:hover .nav__mark { transform: translateX(2px) scale(1.05); }

.nav__links { display: flex; gap: clamp(14px, 2vw, 26px); align-items: center; }
.nav__links a {
    font-size: 0.925rem;
    font-weight: 500;
    color: var(--ink-soft);
    text-decoration: none;
    padding: 6px 0;
    position: relative;
}
.nav__links a::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 1.5px;
    background: var(--b500);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--t) var(--ease);
}
.nav__links a:hover { color: var(--ink); text-decoration: none; }
.nav__links a:hover::after { transform: scaleX(1); }

/* Phone in the nav: SMB owners over ~45 look for a number before anything
   else. It is the credibility signal, not just a channel. */
.nav__phone {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-family: var(--mono);
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ink);
    text-decoration: none;
    white-space: nowrap;
}
.nav__phone:hover { color: var(--b700); text-decoration: none; }

.nav__toggle {
    display: none;
    background: none;
    border: 1px solid var(--line-str);
    border-radius: 8px;
    padding: 8px 10px;
    cursor: pointer;
}

@media (max-width: 900px) {
    .nav__links, .nav__cta { display: none; }
    .nav__toggle { display: inline-flex; }
    .nav.is-open .nav__links {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
        position: absolute;
        top: 100%; left: 0; right: 0;
        background: var(--surface);
        border-bottom: 1px solid var(--line);
        padding: 12px var(--gutter) 20px;
        box-shadow: var(--shadow);
    }
    .nav.is-open .nav__links a { width: 100%; padding: 11px 0; font-size: 1.02rem; }
    .nav.is-open .nav__cta { display: inline-flex; }
    .nav.is-open .nav__links::after {
        content: "";
        display: block; width: 100%; height: 1px;
        background: var(--line); margin: 8px 0;
    }
}
@media (max-width: 560px) {
    .nav__phone span { display: none; }   /* icon-only, keeps the tap target */
}

/* ---------------------------------------------------------------------------
   Mobile action bar
   ---------------------------------------------------------------------------
   Below 900px the nav's CTA collapses behind the hamburger, which buries the
   one action the whole site exists to produce — and mobile is where Google
   Business Profile traffic lands, at the highest intent we ever see. So both
   ways of reaching us stay pinned to the thumb instead.
   --------------------------------------------------------------------------- */
.mobile-bar { display: none; }

@media (max-width: 900px) {
    .mobile-bar {
        display: flex;
        gap: 10px;
        position: fixed;
        left: 0; right: 0; bottom: 0;
        z-index: 45;
        padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
        background: rgba(247, 249, 254, 0.94);
        backdrop-filter: saturate(180%) blur(14px);
        -webkit-backdrop-filter: saturate(180%) blur(14px);
        border-top: 1px solid var(--line);
    }
    .mobile-bar .btn { flex: 1; padding-block: 13px; }
    .mobile-bar .btn--ghost { flex: 0 0 auto; padding-inline: 18px; }
    /* Clear the bar so the footer and the last CTA are never trapped under it. */
    body { padding-bottom: 74px; }
}

@media print { .mobile-bar { display: none !important; } }

/* ---------------------------------------------------------------------------
   Hero + the signature refraction animation
   ---------------------------------------------------------------------------
   The brand argument, drawn: one beam goes in (what you're trying to do),
   it splits into a defined spectrum (the plan), and converges into a single
   output (the built system). Monochromatic, so the "spectrum" is seven tints
   of the one hue. Pure SVG + CSS — no library, no canvas, ~4KB, and it only
   animates transform/opacity/stroke-dashoffset so it stays on the compositor.
   --------------------------------------------------------------------------- */
.hero {
    background: var(--void);
    color: var(--d-text);
    position: relative;
    overflow: hidden;
    isolation: isolate;
    padding-block: clamp(64px, 11vw, 128px) clamp(72px, 11vw, 124px);
}

.hero__grid {
    position: absolute;
    inset: 0;
    z-index: -2;
    background-image:
        linear-gradient(to right, rgba(138, 179, 255, 0.06) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(138, 179, 255, 0.06) 1px, transparent 1px);
    background-size: 72px 72px;
    mask-image: radial-gradient(ellipse 80% 65% at 60% 40%, #000 10%, transparent 75%);
    -webkit-mask-image: radial-gradient(ellipse 80% 65% at 60% 40%, #000 10%, transparent 75%);
}

/* Ambient bloom behind the prism. Drifts on a long loop so the page is never
   quite static, but slowly enough that it is felt rather than watched. */
.hero__bloom {
    position: absolute;
    z-index: -1;
    width: min(760px, 85vw);
    aspect-ratio: 1;
    right: -6%;
    top: 44%;
    transform: translateY(-50%);
    background: radial-gradient(circle, rgba(42, 115, 255, 0.26) 0%, rgba(42, 115, 255, 0.09) 38%, transparent 68%);
    filter: blur(24px);
    animation: bloom 14s var(--ease) infinite alternate;
    pointer-events: none;
}
@keyframes bloom {
    from { transform: translateY(-50%) scale(1);    opacity: 0.85; }
    to   { transform: translateY(-54%) scale(1.09); opacity: 1; }
}

.hero__inner {
    position: relative;
    display: grid;
    /* Text gets the larger share: the headline is a full sentence, not a
       two-word slogan, and it needs the measure to read as one thought. */
    grid-template-columns: minmax(0, 1.28fr) minmax(0, 0.82fr);
    gap: clamp(28px, 4vw, 56px);
    align-items: center;
}

.hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: var(--mono);
    font-size: 0.72rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--b300);
    border: 1px solid var(--d-line);
    background: rgba(138, 179, 255, 0.05);
    padding: 7px 14px;
    border-radius: 999px;
    margin-bottom: 26px;
}
.hero__eyebrow .dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--b400);
    box-shadow: 0 0 0 0 rgba(87, 146, 255, 0.7);
    animation: pulse 2.6s var(--ease) infinite;
}
@keyframes pulse {
    0%   { box-shadow: 0 0 0 0 rgba(87, 146, 255, 0.65); }
    70%  { box-shadow: 0 0 0 7px rgba(87, 146, 255, 0); }
    100% { box-shadow: 0 0 0 0 rgba(87, 146, 255, 0); }
}

/* Deliberately smaller than the global h1 scale. This headline is a whole
   sentence — at display size it fills five lines and reads as shouting
   rather than speaking. Statement-led, not slogan-led. */
.hero h1 {
    color: #fff;
    font-size: clamp(1.9rem, 3.3vw, 2.9rem);
    line-height: 1.12;
    letter-spacing: -0.03em;
    margin-bottom: 22px;
}
/* The payoff phrase carries the brand gradient — one accent, on the words
   that do the work.

   A band of lighter blue drifts left-to-right across the phrase on a slow
   9s loop, like light travelling along a curved surface. Three things keep
   it tasteful rather than tacky: it stays entirely inside the existing blue
   scale (no hue ever leaves 219°), it is slow enough to be felt rather than
   watched, and the gradient's first and last stops are the same colour so
   the repeat tiles seamlessly with no visible seam on each pass.

   Cost: repaint of one ~250x60px text box. No layout, no compositing
   pressure, nothing else on the page is touched. Gated behind `.io`, so
   reduced-motion visitors never start it and simply keep the static
   gradient below. */
/* Seamlessness is the whole trick here, and it needs three things to be true
   at once:

   1. FIXED TILE, NOT A PERCENTAGE. Percentage background-position is measured
      against (element width − image width), so the distance travelled over a
      cycle has no fixed relationship to the tile width — the pattern lands
      mid-stride on restart and visibly jumps. A tile sized in `em` travels an
      exact, knowable distance.
   2. TRAVEL EXACTLY ONE TILE. The keyframes move background-position-x by
      precisely the tile width, so the final frame is pixel-identical to the
      first and the loop point is undetectable.
   3. MATCHING END STOPS. First and last colour stops are both --b500, so the
      repeat boundary inside the tiling has no seam either.

   The gradient is 90deg rather than angled: an angled gradient in a repeating
   tile does not line up across the tile edge, which reintroduces the seam
   that points 1 and 2 just removed.

   `em` keeps it proportional to the headline as the clamp() resizes it. */
.hero h1 .accent {
    background-image: linear-gradient(90deg,
        var(--b500)   0%,
        var(--b400)  25%,
        var(--b300)  50%,
        var(--b400)  75%,
        var(--b500) 100%);
    background-size: 10em 100%;
    background-repeat: repeat;
    background-position: 0 0;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.io .hero h1 .accent { animation: sheen 9s linear infinite; }

/* Exactly one tile of travel. Increasing background-position-x slides the
   image right, carrying the light band left-to-right through the words. */
@keyframes sheen {
    from { background-position: 0 0; }
    to   { background-position: 10em 0; }
}

.hero__lede {
    font-size: clamp(1.08rem, 1.7vw, 1.3rem);
    line-height: 1.55;
    color: var(--d-soft);
    max-width: 54ch;
    margin-bottom: 32px;
}

.hero__cta { margin-bottom: 30px; }

/* Trust strip directly under the CTA — the objections a first-time visitor
   has at the exact moment they consider clicking. */
.hero__trust {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 22px;
    font-size: 0.86rem;
    color: var(--d-mute);
}
.hero__trust li { list-style: none; display: flex; align-items: center; gap: 7px; }
.hero__trust svg { color: var(--b400); flex: none; }

/* --- The prism figure ---
   Scaled past its column and allowed to bleed. The text column needs the
   measure, but a figure confined to the remainder reads as an afterthought
   rather than the other half of the argument. */
.prism {
    width: 100%;
    height: auto;
    overflow: visible;
    transform: scale(1.22);
    transform-origin: center;
}
@media (max-width: 900px) { .prism { transform: none; } }

.prism .beam-in,
.prism .beam-out,
.prism .beam-focus {
    fill: none;
    stroke-linecap: round;
    stroke-dasharray: var(--len, 400);
    stroke-dashoffset: var(--len, 400);
}

/* Draw order tells the story: input arrives, spectrum fans, output converges.
   Total run ~2.6s, then it holds. It plays once — a looping hero animation
   competes with the headline for attention forever. */
.io .prism .beam-in    { animation: draw 620ms var(--ease) 180ms forwards; }
.io .prism .beam-out   { animation: draw 900ms var(--ease) var(--delay, 700ms) forwards; }
.io .prism .beam-focus { animation: draw 700ms var(--ease) 1700ms forwards; }
.io .prism .prism-body { opacity: 0; animation: fade-scale 620ms var(--ease) 520ms forwards; }
.io .prism .glint      { opacity: 0; animation: glint 1500ms var(--ease) 1150ms forwards; }
.io .prism .node       { opacity: 0; animation: fade-scale 420ms var(--ease) var(--delay, 1900ms) forwards; }
.io .prism .label      { opacity: 0; animation: rise 520ms var(--ease) var(--delay, 2100ms) forwards; }

@keyframes draw       { to { stroke-dashoffset: 0; } }
@keyframes fade-scale { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
@keyframes glint      { 0% { opacity: 0; } 40% { opacity: 0.9; } 100% { opacity: 0.35; } }
@keyframes rise       { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }

.prism .prism-body, .prism .node { transform-box: fill-box; transform-origin: center; }

@media (max-width: 900px) {
    .hero__inner { grid-template-columns: 1fr; }
    .hero__figure { order: -1; max-width: 460px; margin-inline: auto; }
}

/* ---------------------------------------------------------------------------
   Reveal-on-scroll
   Progressive enhancement: the hidden state only exists once JS adds .io to
   <html>, so content can never be stranded invisible. Reduced-motion users
   never get the class at all.
   --------------------------------------------------------------------------- */
.io .reveal {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.io .reveal.is-in { opacity: 1; transform: none; }
/* Stagger children by index — set --i in the markup. 55ms is fast enough to
   feel like one motion rather than a queue. */
.io .reveal[style*="--i"] { transition-delay: calc(var(--i) * 55ms); }

/* ---------------------------------------------------------------------------
   Cards
   --------------------------------------------------------------------------- */
.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: clamp(22px, 3vw, 30px);
    position: relative;
    overflow: hidden;
    transition: border-color var(--t) var(--ease),
                box-shadow var(--t) var(--ease),
                transform var(--t) var(--ease);
}
/* Light rakes across the top edge on hover — the refraction motif again,
   reduced to a single hairline. */
.card::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--b500), transparent);
    transform: scaleX(0);
    transition: transform var(--t-slow) var(--ease);
}
.card:hover { border-color: var(--line-str); box-shadow: var(--shadow); transform: translateY(-2px); }
.card:hover::before { transform: scaleX(1); }

a.card { text-decoration: none; color: inherit; display: block; }
a.card:hover { text-decoration: none; }

.card h3 { margin-bottom: 9px; }
/* :not(.kicker) matters — a bare `.card p` outranks `.kicker` on specificity
   and would silently resize every kicker that lives inside a card. */
.card p:not(.kicker) { color: var(--ink-soft); font-size: 0.96rem; }

.grid { display: grid; gap: clamp(16px, 2.2vw, 22px); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }

/* ---------------------------------------------------------------------------
   The three-phase process — a light beam runs the spine as you scroll
   --------------------------------------------------------------------------- */
.phases { position: relative; display: grid; gap: clamp(24px, 4vw, 40px); }
.phases::before {
    content: "";
    position: absolute;
    left: 23px; top: 12px; bottom: 12px;
    width: 2px;
    background: var(--d-line);
}
/* The travelling fill. Height is driven from JS scroll progress so the beam
   tracks the reader rather than a timer — it is their own motion, reflected. */
.phases::after {
    content: "";
    position: absolute;
    left: 23px; top: 12px;
    width: 2px;
    height: var(--progress, 0%);
    background: linear-gradient(180deg, var(--b500), var(--b300));
    box-shadow: 0 0 12px rgba(42, 115, 255, 0.6);
    transition: height 120ms linear;
}

.phase { display: grid; grid-template-columns: 48px 1fr; gap: clamp(16px, 2.5vw, 26px); align-items: start; }
.phase__num {
    width: 48px; height: 48px;
    display: grid; place-items: center;
    border-radius: 12px;
    background: var(--canvas-2);
    border: 1px solid var(--d-line);
    font-family: var(--mono);
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--b300);
    position: relative;
    z-index: 1;
    transition: background-color var(--t) var(--ease), border-color var(--t) var(--ease), color var(--t) var(--ease);
}
.phase.is-in .phase__num { background: var(--b600); border-color: var(--b400); color: #fff; }
.phase h3 { margin-bottom: 8px; }
/* Excluding .phase__ask keeps the quoted line its own colour — otherwise
   `.phase p` outranks it and the accent is lost. */
.phase p:not(.phase__ask) { color: var(--d-soft); max-width: 64ch; }
.phase__ask {
    margin-top: 12px;
    padding-left: 14px;
    border-left: 2px solid var(--b600);
    font-family: var(--mono);
    font-size: 0.86rem;
    color: var(--b200);
}

/* ---------------------------------------------------------------------------
   Offer / SKU table
   --------------------------------------------------------------------------- */
/* 230px, not 250px: four tracks plus three 16px gaps must fit inside the
   1044px content box, and 250px lands four pixels over — dropping the fourth
   SKU onto its own orphaned row. */
.offers { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); }

.offer {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: 26px 24px 24px;
    display: flex;
    flex-direction: column;
    position: relative;
    transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease), transform var(--t) var(--ease);
}
.offer:hover { border-color: var(--line-str); box-shadow: var(--shadow-sm); transform: translateY(-2px); }

/* Step 1 is visually the destination — every other card is explanation. */
.offer--lead {
    border-color: var(--b400);
    box-shadow: 0 0 0 1px var(--b400), var(--shadow);
    background: linear-gradient(180deg, var(--b50), var(--surface) 60%);
}
.offer--lead:hover { box-shadow: 0 0 0 1px var(--b500), var(--shadow-lg); }

.offer__step {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-mute);
    margin-bottom: 10px;
}
.offer--lead .offer__step { color: var(--b700); }
.offer h3 { margin-bottom: 4px; }
.offer__price {
    font-family: var(--mono);
    font-size: 1.02rem;
    font-weight: 600;
    color: var(--b700);
    margin-bottom: 12px;
}
.offer__price .sub { font-size: 0.8rem; font-weight: 400; color: var(--ink-mute); display: block; margin-top: 3px; letter-spacing: -0.01em; }
/* Only the description paragraph grows. Without the :not() guards this rule
   outranks .offer__step and .offer__price, handing them `flex: 1` too — which
   makes each card stretch its label and price by a different amount and knocks
   every heading out of alignment across the row. */
.offer p:not(.offer__step):not(.offer__price) {
    font-size: 0.94rem;
    color: var(--ink-soft);
    flex: 1;
}
.offer__foot { margin-top: 18px; }

/* The fee-credit mechanic gets its own object. It is the single most
   persuasive fact in the pricing story — deciding to proceed makes the
   planning free — so it is never buried in a paragraph. */
.mechanic {
    margin-top: 28px;
    display: flex;
    gap: 16px;
    align-items: flex-start;
    background: var(--b50);
    border: 1px solid var(--b200);
    border-radius: var(--r);
    padding: 20px 24px;
}
.mechanic svg { flex: none; color: var(--b600); margin-top: 2px; }
.mechanic p { font-size: 0.95rem; color: var(--ink-soft); margin: 0; }

/* ---------------------------------------------------------------------------
   Case studies — the three-beat structure from the org doc, made structural
   --------------------------------------------------------------------------- */
.beats { display: grid; gap: 2px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
@media (min-width: 820px) { .beats { grid-template-columns: repeat(3, 1fr); } }

.beat { background: var(--surface); padding: 26px 24px; }
.beat__label {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--b700);
    margin-bottom: 10px;
    display: block;
}
.beat h3 { font-size: 1.06rem; margin-bottom: 8px; }
.beat p { font-size: 0.94rem; color: var(--ink-soft); }

.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 22px; }
.chip {
    font-family: var(--mono);
    font-size: 0.76rem;
    font-weight: 500;
    color: var(--b700);
    background: var(--b50);
    border: 1px solid var(--b200);
    border-radius: 999px;
    padding: 5px 13px;
}

/* Result callout — the measurable change, given weight */
.result {
    margin-top: 20px;
    border-left: 3px solid var(--b500);
    padding: 4px 0 4px 20px;
}
.result__num {
    font-family: var(--display);
    font-size: clamp(1.6rem, 3vw, 2.1rem);
    font-weight: 600;
    letter-spacing: -0.03em;
    color: var(--b700);
    line-height: 1.05;
}
.result__label { font-size: 0.9rem; color: var(--ink-soft); }

/* ---------------------------------------------------------------------------
   Booking widget
   ---------------------------------------------------------------------------
   Three interactions total: pick a time, pick how, confirm. Real availability
   renders on the page rather than behind a click, because showing genuine
   open slots is the single largest lever on booking rate.
   --------------------------------------------------------------------------- */
.booker {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

/* The booker is a LIGHT card sitting inside a dark section, so it has to opt
   out of the dark-surface inheritance. Without this, headings and slot times
   render in near-white on white and the whole widget looks empty. */
.section--dark .booker { color: var(--ink); }
.section--dark .booker h1,
.section--dark .booker h2,
.section--dark .booker h3 { color: var(--ink); }
.section--dark .booker .lede { color: var(--ink-soft); }
.section--dark .booker a { color: var(--b700); text-decoration-color: var(--b300); }
/* `.section--dark strong` (0,2,1) outranks `.section--dark .booker` (0,2,0),
   so every <strong> in this light card was inheriting the dark section's
   near-white --d-text and rendering on white. The line it ruined was the
   confirmed date and time on the success screen — the single most important
   sentence in the whole funnel, effectively invisible. */
.section--dark .booker strong { color: var(--ink); }
.section--dark .booker .btn { --btn-bg: var(--b600); color: #fff; }
.section--dark .booker .btn:hover { background: var(--b700); }

.booker__head {
    padding: 22px clamp(20px, 3vw, 30px);
    border-bottom: 1px solid var(--line);
    display: flex;
    flex-wrap: wrap;
    gap: 12px 20px;
    align-items: baseline;
    justify-content: space-between;
}
.booker__head h3 { font-size: 1.22rem; }
.booker__tz { font-family: var(--mono); font-size: 0.78rem; color: var(--ink-mute); }
.booker__tz b { color: var(--ink-soft); font-weight: 500; }

.booker__body { padding: clamp(20px, 3vw, 30px); }

/* Progress rail — three dots, so the visitor always knows how much is left.
   Perceived length is what kills form completion, not actual length. */
.steps-rail { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; }
.steps-rail__dot {
    display: flex; align-items: center; gap: 8px;
    font-size: 0.82rem; font-weight: 500; color: var(--ink-mute);
    background: none; border: 0; padding: 0;
    font-family: inherit;
    cursor: default;
    transition: color var(--t) var(--ease);
}
/* A completed step is enabled, and therefore a real way back. */
.steps-rail__dot:not(:disabled) { cursor: pointer; }
.steps-rail__dot:not(:disabled):hover { color: var(--b700); }
.steps-rail__dot:not(:disabled):hover i { border-color: var(--b600); background: var(--b100); }
.steps-rail__dot i {
    font-style: normal;
    width: 22px; height: 22px;
    display: grid; place-items: center;
    border-radius: 50%;
    border: 1.5px solid var(--line-str);
    font-family: var(--mono); font-size: 0.7rem;
    transition: all var(--t) var(--ease);
}
.steps-rail__dot.is-active { color: var(--ink); }
.steps-rail__dot.is-active i { background: var(--b600); border-color: var(--b600); color: #fff; }
.steps-rail__dot.is-done i { background: var(--b50); border-color: var(--b400); color: var(--b700); }
.steps-rail__sep { flex: 1; height: 1px; background: var(--line); min-width: 12px; }

.bstep[hidden] { display: none; }
.bstep__title { font-size: 1.02rem; font-weight: 600; font-family: var(--display); letter-spacing: -0.02em; margin-bottom: 4px; }
.bstep__hint { font-size: 0.88rem; color: var(--ink-mute); margin-bottom: 18px; }

/* Steps cross-fade in rather than snapping. This is the conversion path, and
   an instant swap reads as a page reload — the fade tells you it's the same
   surface changing, which is what makes the three steps feel like one flow. */
.io .bstep:not([hidden]) { animation: step-in 200ms var(--ease) both; }
@keyframes step-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* Back affordances. Quiet by default — they must be findable without
   competing with the primary action. */
.bstep__back {
    background: none; border: 0; padding: 0;
    font: inherit; font-size: 0.86rem; font-weight: 500;
    color: var(--ink-mute); cursor: pointer;
    text-decoration: underline; text-decoration-color: var(--line-str);
    text-underline-offset: 3px;
    transition: color var(--t-fast) var(--ease), text-decoration-color var(--t-fast) var(--ease);
}
.bstep__back:hover { color: var(--b700); text-decoration-color: var(--b400); }
.bstep__back-row { margin-top: 16px; }

.summary__actions {
    display: flex; flex-wrap: wrap; gap: 16px;
    margin-top: 14px; padding-top: 12px;
    border-top: 1px solid var(--b200);
}

/* Day tabs.
   overflow-x:auto makes this a scroll container, which clips on BOTH axes —
   CSS forces overflow-y to auto when overflow-x isn't visible. The hover
   lift would therefore have its top edge shaved off. The vertical padding is
   what gives that 1px somewhere to go. */
.days {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    padding-block: 4px 10px;
    margin-bottom: 6px;
    scrollbar-width: thin;
    scroll-snap-type: x proximity;
    /* Fourteen days never fit, so the right edge fades to signal there is
       more to scroll. Without it the final tab just looks truncated. */
    mask-image: linear-gradient(90deg, #000 calc(100% - 36px), transparent);
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 36px), transparent);
}
.day { scroll-snap-align: start; }
.day {
    flex: none;
    min-width: 78px;
    padding: 10px 12px;
    border: 1.5px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    cursor: pointer;
    text-align: center;
    transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.day:hover:not(:disabled) { border-color: var(--b400); transform: translateY(-1px); }
.day[aria-pressed="true"] { border-color: var(--b600); background: var(--b50); }
.day:disabled { opacity: 0.4; cursor: not-allowed; }
.day__dow { display: block; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-mute); }
.day__num { display: block; font-family: var(--display); font-size: 1.15rem; font-weight: 600; letter-spacing: -0.02em; }
.day__free { display: block; font-size: 0.68rem; color: var(--b700); font-family: var(--mono); }

/* Slot grid */
.slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 9px; }
.slot {
    padding: 12px 8px;
    border: 1.5px solid var(--line);
    border-radius: 9px;
    background: var(--surface);
    font-family: var(--mono);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.slot:hover { border-color: var(--b500); background: var(--b50); transform: translateY(-1px); }
.slot[aria-pressed="true"] { background: var(--b600); border-color: var(--b600); color: #fff; }
/* Fast staggered entrance — 26ms apart reads as one motion arriving. */
.io .slot { opacity: 0; animation: slot-in 200ms var(--ease) forwards; animation-delay: calc(var(--i, 0) * 26ms); }
@keyframes slot-in { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }

/* How-we-meet choice */
.modes { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); }
.mode {
    display: flex; gap: 14px; align-items: flex-start;
    padding: 18px;
    border: 1.5px solid var(--line);
    border-radius: 12px;
    background: var(--surface);
    cursor: pointer;
    text-align: left;
    transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.mode:hover { border-color: var(--b400); transform: translateY(-1px); }
.mode[aria-pressed="true"] { border-color: var(--b600); background: var(--b50); box-shadow: 0 0 0 1px var(--b600); }
.mode svg { flex: none; color: var(--b600); margin-top: 1px; }
.mode b { display: block; font-weight: 600; font-size: 0.98rem; }
.mode span { font-size: 0.85rem; color: var(--ink-mute); }

/* Fields */
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 0.875rem; font-weight: 550; margin-bottom: 6px; }
.field .opt { font-weight: 400; color: var(--ink-mute); }
.field input, .field textarea {
    width: 100%;
    padding: 12px 14px;
    border: 1.5px solid var(--line-str);
    border-radius: 10px;
    background: var(--surface);
    font-size: 1rem;
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.field input:focus, .field textarea:focus {
    outline: none;
    border-color: var(--b500);
    box-shadow: 0 0 0 3px rgba(42, 115, 255, 0.14);
}
.field textarea { min-height: 88px; resize: vertical; }
.field__err { display: none; font-size: 0.84rem; color: #B3261E; margin-top: 5px; }
.field.has-err input, .field.has-err textarea { border-color: #B3261E; }
.field.has-err .field__err { display: block; }

/* Honeypot — a real field to a bot, invisible and unfocusable to a human.
   No CAPTCHA, so no friction on the highest-intent action on the site. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Confirmation summary */
.summary {
    background: var(--b50);
    border: 1px solid var(--b200);
    border-radius: 12px;
    padding: 18px 20px;
    margin-bottom: 18px;
}
.summary dl { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; font-size: 0.93rem; }
.summary dt { color: var(--ink-mute); }
.summary dd { font-weight: 550; }

.booker__status { font-size: 0.9rem; margin-top: 12px; }
.booker__status.is-error { color: #B3261E; }

/* Loading shimmer while availability resolves */
.skel { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 9px; }
.skel span {
    height: 44px; border-radius: 9px;
    background: linear-gradient(90deg, var(--b50) 25%, var(--b100) 37%, var(--b50) 63%);
    background-size: 400% 100%;
    animation: shimmer 1.3s ease-in-out infinite;
}
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }

/* ---------------------------------------------------------------------------
   About — the founder block
   --------------------------------------------------------------------------- */
.about {
    display: grid;
    gap: clamp(24px, 4vw, 52px);
    grid-template-columns: minmax(0, 0.4fr) minmax(0, 1fr);
    /* Centred against the text block: the portrait is shorter than the copy,
       and pinning it to the top leaves a heavy gap under it. */
    align-items: center;
}
.about__photo { margin: 0; }
.about__photo img {
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 5;
    object-fit: cover;
    border-radius: var(--r);
    border: 1px solid var(--line);
    box-shadow: var(--shadow);
}

/* The one line that states the whole business. Display face, brand rule,
   and enough size that it reads as a statement rather than a caption. */
.about__quote {
    margin-top: 26px;
    padding-left: 20px;
    border-left: 3px solid var(--b500);
    font-family: var(--display);
    font-size: clamp(1.05rem, 1.9vw, 1.32rem);
    font-weight: 500;
    letter-spacing: -0.02em;
    line-height: 1.35;
    color: var(--ink);
}

@media (max-width: 760px) {
    .about { grid-template-columns: 1fr; }
    .about__photo { max-width: 240px; }
}

/* ---------------------------------------------------------------------------
   FAQ — plain <details>. Native semantics, keyboard-complete, no JS, and
   Google reads it for the FAQ rich result.
   --------------------------------------------------------------------------- */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
    padding: 20px 40px 20px 0;
    cursor: pointer;
    font-family: var(--display);
    font-weight: 600;
    font-size: 1.05rem;
    letter-spacing: -0.02em;
    list-style: none;
    position: relative;
    transition: color var(--t-fast) var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--b700); }
.faq summary::after {
    content: "";
    position: absolute;
    right: 6px; top: 50%;
    width: 10px; height: 10px;
    border-right: 2px solid var(--b600);
    border-bottom: 2px solid var(--b600);
    transform: translateY(-70%) rotate(45deg);
    transition: transform var(--t) var(--ease);
}
.faq details[open] summary::after { transform: translateY(-30%) rotate(-135deg); }
.faq details p { padding-bottom: 22px; color: var(--ink-soft); max-width: 72ch; }
.faq details p + p { padding-top: 0; margin-top: -8px; }

/* ---------------------------------------------------------------------------
   Footer — carries the canonical NAP block. This exact string must match the
   Google Business Profile and every citation, byte for byte.
   --------------------------------------------------------------------------- */
.footer {
    background: var(--void);
    color: var(--d-soft);
    padding-block: clamp(48px, 6vw, 72px) 32px;
    font-size: 0.92rem;
}
.footer a { color: var(--d-soft); text-decoration: none; }
.footer a:hover { color: #fff; text-decoration: underline; text-decoration-color: var(--b500); }
.footer__grid {
    display: grid;
    gap: 32px;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
    padding-bottom: 34px;
    border-bottom: 1px solid var(--d-line);
}
.footer h4 {
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--b300);
    font-weight: 500;
    margin-bottom: 14px;
}
.footer ul { list-style: none; display: grid; gap: 9px; }
/* The real brand lockup, light-ink variant. The footer is the one place on
   the site with room for the full mark at a size where the wordmark is
   actually legible (~19px cap height at 240px wide). */
.footer__logo { display: block; width: 240px; max-width: 100%; height: auto; margin-bottom: 16px; }
.footer__nap { font-style: normal; line-height: 1.7; }
.footer__bottom {
    padding-top: 26px;
    display: flex;
    flex-wrap: wrap;
    gap: 12px 24px;
    justify-content: space-between;
    font-size: 0.85rem;
    color: var(--d-mute);
}

/* Email reveal: the address is base64 in the markup and only becomes a real
   mailto after a human click, so the literal string is never in page source
   for a scraper to harvest. */
.email-reveal { background: none; border: none; padding: 0; cursor: pointer; color: inherit; text-decoration: underline; text-decoration-color: var(--b500); text-underline-offset: 3px; font: inherit; }
.email-reveal:hover { color: #fff; }

/* ---------------------------------------------------------------------------
   Utilities
   --------------------------------------------------------------------------- */
.visually-hidden {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.center { text-align: center; }
/* Both forms matter. `.center .lede` covers a centred wrapper; `.lede.center`
   and `.section-head.center` cover the element carrying the class itself —
   without those, a max-width block gets centre-aligned TEXT inside a box that
   is still pinned left, which reads as subtly broken alignment. */
.center .lede, .center .section-head,
.lede.center, .section-head.center { margin-inline: auto; }
.mt-0 { margin-top: 0; }
.stack > * + * { margin-top: 1em; }

/* ---------------------------------------------------------------------------
   Reduced motion — every animation collapses to its finished state. Nothing
   is hidden, nothing moves, nothing is lost.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    .prism .beam-in, .prism .beam-out, .prism .beam-focus { stroke-dashoffset: 0 !important; }
    .prism .prism-body, .prism .glint, .prism .node, .prism .label { opacity: 1 !important; }
    .io .reveal { opacity: 1 !important; transform: none !important; }
    .io .slot { opacity: 1 !important; }
    .hero__bloom { animation: none; }
}

/* ---------------------------------------------------------------------------
   Print — someone will print the pricing page for a partner meeting.
   --------------------------------------------------------------------------- */
@media print {
    .nav, .booker, .hero__bloom, .hero__grid, .skip-link { display: none !important; }
    body { background: #fff; color: #000; font-size: 11pt; }
    .section--dark, .hero, .footer { background: #fff !important; color: #000 !important; }
    .section--dark h1, .section--dark h2, .section--dark h3,
    .hero h1, .footer, .footer a { color: #000 !important; }
    .hero h1 .accent { -webkit-text-fill-color: #000; color: #000; }
    a::after { content: " (" attr(href) ")"; font-size: 9pt; color: #444; }
    .card, .offer { break-inside: avoid; }
}
