/* home.css :: the homepage. Self-contained: needs ONLY base.css for tokens, so it
   never collides with index.css / kokonut.css and neither of those is loaded here.

   Brand: light and warm (rebranded 2026-07-29).
   - Only two things sit behind content: the off-white family, or --black.
     Beige and teal are barred from surface duty.
   - Cards lift by getting LIGHTER, never darker. Depth is --panel-lift, never a border.
   - --cream is text and accents ON BLACK only, never a background.
   - --pop is 3.2:1 and fails AA at body size: large marks, numerals and rules only.
     Small text that needs the accent uses --pop-deep (4.9:1).
   - Cabinet Grotesk has NO weight 600. 500 for letterspaced labels, 700 for buttons.
   - Bodoni Moda never below ~1.8rem, its hairlines break up.
   - One theme. Black is an emphasis surface on a light page, not a dark mode.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; color-scheme: light; }

/* Nav height is the one number the fold maths depends on: the hero is sized as
   100dvh minus this, so if it under-states the real nav the hero runs past the bottom
   of the screen.
   ⚠️ IT IS DERIVED, NOT PICKED. The nav is 1rem of padding top and bottom plus the
   logo, so --nav-h must be logo + 2rem. Change .nav-logo img and you MUST change this
   in the same edit, or the hero silently overflows.
     logo 56px + 32px padding = 88px = 5.5rem
     logo 44px + 32px padding = 76px = 4.75rem   (under 560px)
   It sat at 4.2rem against a 76px nav between 2026-08-29 and 2026-08-31, which is why
   the hero was running 9px long. */
:root { --nav-h: 5.5rem; }
@media (max-width: 560px) { :root { --nav-h: 4.75rem; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--f-body);
  font-weight: 400;
  font-size: clamp(1rem, .96rem + .2vw, 1.0625rem);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(10,23,29,.08);
  overflow-x: hidden;
}

h1, h2, h3 { color: var(--ink); margin: 0; text-wrap: balance; }
p { margin: 0 0 1rem; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; height: auto; display: block; }
a { color: var(--teal-mid); }

:where(a, button, summary, details):focus-visible {
  outline: 2px solid var(--pop-deep);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--black); color: var(--cream);
  padding: .75rem 1.25rem; font-weight: 700; text-decoration: none;
}
.skip:focus { left: 0; }

[id] { scroll-margin-top: 5.5rem; }

.wrap { width: min(100% - 2.5rem, 68rem); margin-inline: auto; }
.wrap.narrow { width: min(100% - 2.5rem, 44rem); }

/* ---------- Lenis ----------
   Lenis drives scrolling itself, so native smooth scrolling has to get out of the
   way while it is running. These classes only exist once home.js has started it,
   which it never does under reduced motion. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

/* ---------- scroll reveals ----------
   The default state is VISIBLE. Content only starts hidden once home.js has added
   .js-reveal to <html>, and home.js refuses to add it under reduced motion. So with
   JavaScript off, or motion disabled, or the observer never firing, every element on
   this page is fully visible and nothing is lost. */
html.js-reveal .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.22,.61,.36,1);
  will-change: opacity, transform;
}
html.js-reveal .reveal.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.js-reveal .reveal { opacity: 1; transform: none; transition: none; }
}

/* ---------- 1. nav ---------- */

#main-nav {
  position: sticky; top: 0; z-index: 100;
  display: flex; align-items: center; gap: 2rem;
  padding: 1rem clamp(1.25rem, 4vw, 2.5rem);
  padding-left: max(clamp(1.25rem, 4vw, 2.5rem), env(safe-area-inset-left));
  padding-right: max(clamp(1.25rem, 4vw, 2.5rem), env(safe-area-inset-right));
  background: rgba(251,247,239,.86);
  backdrop-filter: blur(12px);
  transition: box-shadow .25s ease, background .25s ease;
}
#main-nav.scrolled { box-shadow: 0 1px 0 rgba(10,23,29,.07); background: rgba(251,247,239,.95); }
/* Logo sized up from 30px on 2026-08-29 at Bahush's request. #main-nav is a flex row with
   align-items:center and no fixed height, so the bar simply grows with it. The 560px
   step-down exists because at 44px the logo and the pill CTA start competing for width on
   a narrow phone, and the CTA is the thing that has to survive.
   ⚠️ Swapped from the padded logo.png to the INLINE traced SVG 2026-09-02: it paints in
   currentColor, so .nav-logo must set the ink colour itself or the mark inherits the
   page's teal link colour. The sizes here still drive --nav-h: logo + 2rem, always. */
.nav-logo { color: var(--ink); }
.nav-logo svg { height: 56px; width: auto; display: block; }
@media (max-width: 560px) { .nav-logo svg { height: 44px; } }

/* Hidden on the opening screen, fades in the moment you scroll past it, then follows
   you down the rest of the page. The opener is meant to be the mark and the sentence
   and nothing else, but every screen after it should have a way to book. */
.nav-cta {
  opacity: 0;
  pointer-events: none;
  transform: translateY(-4px);
  transition: opacity .45s ease, transform .45s cubic-bezier(.22,.61,.36,1), background .18s ease;
}
#main-nav.past-opener .nav-cta { opacity: 1; pointer-events: auto; transform: none; }
/* No JavaScript means no .past-opener, so the button must default to visible. */
html:not(.js-hero) .nav-cta { opacity: 1; pointer-events: auto; transform: none; }

.nav-cta {
  margin-left: auto;
  background: var(--ink); color: var(--paper);
  padding: .6rem 1.15rem; border-radius: 999px;
  font-size: .9063rem; font-weight: 700; text-decoration: none;
  white-space: nowrap; transition: background .18s ease, transform .18s ease;
}
.nav-cta:hover { background: var(--teal); transform: translateY(-1px); }

@media (max-width: 560px) {
  .nav-cta { font-size: .8125rem; padding: .55rem .9rem; }
}

/* ---------- buttons ---------- */

.btn {
  display: inline-block; text-decoration: none; text-align: center;
  padding: .95rem 1.6rem; border-radius: 999px;
  font-family: var(--f-body); font-weight: 700; font-size: 1rem;
  transition: background .18s ease, transform .18s ease, color .18s ease;
}
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { background: var(--teal); transform: translateY(-2px); }
/* The CTA that sits on a black band. Filled with --paper, NOT --cream: cream is text
   and accents on black only and is never a background, and off-white is one of the two
   colours allowed to sit behind content. It also reads harder against black than cream
   does, and it makes this button the exact inverse of .btn-primary. Hover lifts to
   --card, which is the same lighter-not-darker move panels make. */
.btn-light { background: var(--paper); color: var(--black); }
.btn-light:hover { background: var(--card); transform: translateY(-2px); }

/* Section eyebrow. */
.eyebrow {
  font-size: .8125rem; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: var(--pop-deep);
  margin: 0 0 1.1rem;
}

/* ---------- 2. the opener ----------
   One screen, one sentence, nothing to click. The sunset owns it edge to edge and the
   nav is stripped back to the mark alone, so the only two things on it are the logo and
   the promise. The booking button is deliberately absent: this screen makes the claim,
   and the very next one starts backing it up with a button on it. */

.opener {
  position: relative;
  overflow: hidden;
  min-height: calc(100dvh - var(--nav-h));
  display: flex;
  align-items: center;
  padding: clamp(2rem, 5vw, 4rem) 0 clamp(4rem, 9vw, 7rem);
}
@supports not (height: 100dvh) { .opener { min-height: calc(100vh - var(--nav-h)); } }

.opener-inner {
  position: relative;
  z-index: 1;
  width: min(100% - 3rem, 74rem);
  margin-inline: auto;
  /* Centred, not ragged-left: Bahush's call 2026-09-01. The sentence is the only
     thing on the screen, so it sits in the middle like a title card. */
  text-align: center;
}

/* The sentence. Cormorant at display size, ragged left, two clauses on two blocks so
   the promise and the risk reversal land as separate beats rather than one long line. */
.opener-line {
  font-family: var(--f-display);
  font-weight: 400;
  font-size: clamp(2.1rem, 5.1vw, 4.6rem);
  line-height: 1.1;
  letter-spacing: -.018em;
  margin: 0;
  text-wrap: balance;
}
.opener-line .ol-a { display: block; color: var(--ink); }
/* The tag lines (Bahush's line order, 2026-09-01): "Done-for-you. 100% Free" then
   "until the first one turns up." as two blocks in the same roman voice as line one.
   Only the FIRST gets the breath of space; the second hugs it as a continuation. */
.opener-line .ol-tag { display: block; color: var(--ink); }
.opener-line .ol-a + .ol-tag { margin-top: .12em; }
/* "100%" set in Bodoni, not Cormorant: Cormorant's serif "1" reads as a capital I
   at display size (Bahush caught it on "100%"). Bodoni is already this site's
   display-numeral face (the 01/02/03 panels, the step numbers), its 1 is
   unmistakably a numeral, and the tag line sits far above Bodoni's 1.8rem floor.
   Slightly downsized: Bodoni runs optically larger than Cormorant at equal size. */
.opener-line .ol-num {
  font-family: var(--f-editorial);
  /* 700 and underlined (Bahush, 2026-09-01). Bodoni ships 400 and 700 here, nothing
     between. The underline is tuned thin and dropped clear of the descender-free
     digits so it reads as a rule under a figure, not a browser link. */
  font-weight: 700;
  font-size: .92em;
  text-decoration: underline;
  text-decoration-thickness: .045em;
  text-underline-offset: .09em;
  /* The highlight (Bahush: "more highlight too"): a marker band of --pop-soft under
     the lower half of the digits, like a highlighter run over the figure, and the
     underline takes the full accent. Ink glyphs on pop-soft stay high contrast, and
     --pop on a display-size rule is one of its sanctioned uses. */
  text-decoration-color: var(--pop);
  /* The highlight sits UNDER the digits (Bahush, 2026-09-01, after trying half and
     full coverage): a marker swash below the number, with the orange underline
     running inside it. Bodoni's baseline is ~.53em above the box bottom, so a band
     to .50em stops just shy of the glyphs and reads as underneath, not over. */
  background: linear-gradient(to top, var(--pop-soft) 0 .50em, transparent .50em);
  padding-inline: .08em;
  border-radius: .06em;
}
.opener-line .ol-b {
  display: block;
  color: var(--teal);
  font-style: italic;
  font-size: .74em;
  /* Its own line-height. The block inherits 1.1, which is right for the big roman line
     above but crushes an italic running over three lines. */
  line-height: 1.26;
  margin-top: .58em;
  /* 48ch, widened from 26ch on 2026-09-01 (clump fix, then the shorter "until then"
     rewrite): wide enough that the whole italic line sits on ONE row on desktop
     instead of stacking into a clump under the headline. */
  max-width: 48ch;
  /* The block is width-capped, so it has to centre itself inside the centred column
     or it stays pinned left while the line above sits in the middle. */
  margin-inline: auto;
}

/* The cue. A rule that draws itself downward, then the word. Reads as an invitation
   rather than a button, which is the point on a screen with nothing to click. */
.opener-cue {
  display: inline-flex;
  align-items: center;
  gap: .85rem;
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
  color: var(--ink-2);
  font-size: .8125rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
}
.opener-cue-rule {
  display: block;
  width: 1px;
  height: 2.75rem;
  background: linear-gradient(to bottom, var(--pop) 0%, rgba(226,99,60,0) 100%);
  transform-origin: top;
}
html.js-hero .opener-cue-rule { animation: cue-draw 2.6s ease-in-out infinite; }
@keyframes cue-draw {
  0%, 100% { transform: scaleY(.45); opacity: .45; }
  50%      { transform: scaleY(1);   opacity: 1; }
}
.opener-cue:hover { color: var(--ink); }

/* Short screens: the sentence is the only thing here, so it can simply shrink. */
@media (max-height: 720px) {
  .opener-line { font-size: clamp(1.8rem, 4.2vw, 3.1rem); }
  .opener-cue { margin-top: clamp(1.5rem, 4vw, 2.5rem); }
  .opener-cue-rule { height: 2rem; }
}

/* The sunset softens toward the bottom edge but no longer dissolves to nothing.
   The old fade ran 62% to 100% and was built for the stacked layout, where the scene
   had to melt into the paper section below; it also happened to sit exactly on the
   land band (the bottom ~7% of the screen) and crushed the hills to under 20%
   opacity, which is why they read as barely there (Bahush, 2026-09-01). With the
   handover now sideways, the bottom only needs a gentle settle: full strength to
   88%, easing to 45% at the very edge. */
.opener .hero-scene {
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 88%, rgba(0,0,0,.45) 100%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 88%, rgba(0,0,0,.45) 100%);
}
/* ⚠️ The gentle mask above is only safe where the SIDEWAYS handover runs, because
   there the opener never sits on top of the steps. Phones and reduced motion keep
   the STACKED layout, and there the 45% floor left the meadow ending in a hard
   horizontal cut against the paper below (caught 2026-09-01). These two cases get a
   full dissolve again, starting at 84% rather than the original 62% so the hills
   stay roughly twice as present as they were before the prominence fix. */
@media (max-width: 860px) {
  .opener .hero-scene {
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 84%, rgba(0,0,0,0) 100%);
            mask-image: linear-gradient(to bottom, #000 0%, #000 84%, rgba(0,0,0,0) 100%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .opener .hero-scene {
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 84%, rgba(0,0,0,0) 100%);
            mask-image: linear-gradient(to bottom, #000 0%, #000 84%, rgba(0,0,0,0) 100%);
  }
}

/* ---------- the sideways handover ----------
   Opener and steps share one sticky stage two panes wide. Scrolling down translates
   the track left, so the opener exits left while the steps arrive from the right, and
   after one viewport of scroll the page carries on vertically as normal.

   EVERYTHING here is scoped to html.js-hslide, which home.js adds only when motion is
   allowed AND the viewport is 861px or wider. Without the class the three wrappers are
   plain blocks and the two sections stack exactly as they always did, so no-JS,
   reduced motion and phones all keep the verified vertical layout.

   Desktop only on purpose: the 861px floor matches the fold-compression media queries
   below, which are what guarantee the steps screen FITS inside one viewport. On a
   phone nothing guarantees that, and a pane taller than the stage would clip. */
html.js-hslide .hslide {
  /* Stage height plus one full viewport of travel. The travel distance is what the
     scroll progress is measured against in home.js: change one, check the other. */
  height: calc(200dvh - var(--nav-h));
}
html.js-hslide .hslide-sticky {
  position: sticky;
  top: var(--nav-h);
  height: calc(100dvh - var(--nav-h));
  overflow: hidden;
}
@supports not (height: 100dvh) {
  html.js-hslide .hslide        { height: calc(200vh - var(--nav-h)); }
  html.js-hslide .hslide-sticky { height: calc(100vh - var(--nav-h)); }
}
html.js-hslide .hslide-track {
  display: flex;
  width: 200%;
  height: 100%;
  will-change: transform;
  position: relative;
}
/* The seam softener. Without it the sunset's tint, grain and green land band stop
   dead at the opener pane's right edge, which reads as a hard vertical rule sliding
   across the screen. This gradient sits glued to the join between the two panes and
   dissolves the scene into paper just before the edge, so the handover reads as one
   surface melting into the next rather than two cards butted together.
   Its opacity is --hs-seam, set by home.js from slide progress: zero at rest and zero
   once the handover completes, so the opening screen never shows a washed right edge
   and the steps screen never carries a ghost stripe. */
html.js-hslide .hslide-track::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: calc(50% - clamp(14rem, 24vw, 22rem));
  width: clamp(14rem, 24vw, 22rem);
  background: linear-gradient(to right, rgba(251,247,239,0) 0%, var(--paper) 92%);
  opacity: var(--hs-seam, 0);
  pointer-events: none;
}
html.js-hslide .hslide-pane {
  width: 50%;
  flex: none;
  height: 100%;
  overflow: hidden;
}
/* Inside the stage both panes are exactly stage height, so the opener's own viewport
   sizing and the hero's generous padding both stand down and flex centring takes over. */
html.js-hslide .opener { min-height: 0; }
html.js-hslide .hero   { padding-top: 1rem; padding-bottom: 1rem; }

/* ---------- the native scrub ----------
   Where the browser supports scroll-driven animations, the COMPOSITOR scrubs the
   track against scroll position directly and JavaScript never touches the transform
   (home.js detects the same support and stands down its per-frame writes). This is
   the fix for Safari's "moving in frames" handover: Safari throttles rAF JavaScript
   during threaded momentum scrolling, so any JS-driven scrub updates in coarse
   ticks no matter how cheap the paint is. Compositor-driven, it runs at full
   refresh in both Safari and Chrome.
   The 100dvh range is exact, not approximate: travel = container (200dvh - nav)
   minus stage (100dvh - nav) = 100dvh, and the container is the first block on the
   page, so document scroll 0 to 100dvh IS the handover. Change the container
   height and this range must move with it (home.js computes the same number).
   The bezier approximates the JS path's smoothstep; the seam keyframes approximate
   its fast-in, hold, fast-out ramp. */
@supports (animation-timeline: scroll()) {
  html.js-hslide .hslide-track {
    animation: hs-slide-native cubic-bezier(.42, 0, .58, 1) both;
    animation-timeline: scroll(root);
    animation-range: 0 100dvh;
  }
  html.js-hslide .hslide-track::after {
    animation: hs-seam-native linear both;
    animation-timeline: scroll(root);
    animation-range: 0 100dvh;
  }
  @keyframes hs-slide-native {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(-50%, 0, 0); }
  }
  @keyframes hs-seam-native {
    0%   { opacity: 0; }
    22%  { opacity: 1; }
    78%  { opacity: 1; }
    100% { opacity: 0; }
  }
}

/* ---------- Safari, and ONLY while the handover is in flight ----------
   Vertical scroll is smooth in Safari; the sideways slide was not (2026-09-02),
   because translating the track forces Safari to re-render the masked, blended,
   animating scene every frame, where Chrome slides a cached texture. While
   .hs-moving is set (home.js, slide genuinely between its endpoints) Safari pauses
   the scene's clocks and lifts the grain blend. Pausing, not stopping: every
   animation resumes exactly where it was the moment the slide settles. Nothing here
   changes a single at-rest pixel, and no other browser matches these selectors. */
html.is-safari .hslide-pane { transform: translateZ(0); }
/* Round two (still laggy): the three remaining per-frame costs go dark in flight.
   The MASK is the big one, Safari re-rasterises masked content on every transform
   tick; the grain texture and the nav's backdrop blur are the other two. The mask
   coming off mid-slide only strengthens the scene's bottom edge while it is
   already sweeping sideways, and the nav swaps blur for near-opaque paper. */
html.is-safari.hs-moving .opener .hero-scene {
  -webkit-mask-image: none;
          mask-image: none;
}
html.is-safari.hs-moving .hero-scene::after { display: none; }
html.is-safari.hs-moving #main-nav { backdrop-filter: none; background: rgba(251,247,239,.97); }
html.is-safari.hs-moving .bc-sun,
html.is-safari.hs-moving .bc-halo,
html.is-safari.hs-moving .bc-lit,
html.is-safari.hs-moving .bc-ridge-far,
html.is-safari.hs-moving .bc-ridge-mid,
html.is-safari.hs-moving .bc-meadow,
html.is-safari.hs-moving .bc-hedges,
html.is-safari.hs-moving .bc-trees,
html.is-safari.hs-moving .bc-bird,
html.is-safari.hs-moving .bc-birds { animation-play-state: paused; }

/* ---------- 3. what I actually do (was the hero) ---------- */
/* ---------- shared hero type styles ---------- */

.hero {
  position: relative;
  overflow: hidden;
  min-height: auto;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(4rem, 9vw, 7rem) 0 clamp(3.5rem, 8vw, 6rem);
  text-align: center;
}

.hero .wrap { position: relative; z-index: 1; }

/* ---------- the sunrise ----------
   A valley at golden hour, seen from a hilltop. Cartoon shapes, cinematic light, and
   everything moves in STEPS rather than smoothly, which is what makes it read as stop
   motion instead of an animated gradient.

   The scene spans the FULL hero (it used to be only the lower 58%, changed 2026-08-31
   when the sun started arcing over the type). The land still sits at the bottom of the
   viewBox with the horizon at roughly 92% of the hero, so the type stays on open sky.
   That is a readability constraint first and a composition second: it is also exactly
   the shot you get standing on a hill looking down. */
/* Full hero, not just the lower band. The sun has to climb OVER the type, so the scene
   has to reach the top. The land still sits at the bottom of the taller viewBox, so the
   composition is unchanged. */
.hero-scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.hero-scene svg { display: block; width: 100%; height: 100%; }

/* Grain over the whole scene, so the flat cartoon bands read as printed rather than
   vector-clean. Same tooth the previous flat sun had. */
.hero-scene::after {
  content: ""; position: absolute; inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.30'/%3E%3C/svg%3E");
  mix-blend-mode: multiply;
  opacity: .38;
}

/* THE STOP MOTION.
   steps() is the whole trick. A smooth transform reads as a slick web animation; the
   same transform quantised into a small number of frames reads as something shot one
   frame at a time. 14 steps over 30s is roughly one move every two seconds, which is
   slow enough to feel deliberate rather than juddery.
   Every one of these is transform or opacity only, so the scene stays on the compositor
   and never costs layout. */
/* THE PULSE.
   The sun is parked and simply breathes. It arced over the type until 2026-08-31 and
   climbed before that; both were removed because a moving sun pulls the eye off the
   copy, which is the one thing the hero cannot afford.
   Smooth, NOT stepped. Everything else in this scene is stepped, but a soft glow
   quantised into frames reads as a flicker or a failing bulb rather than as light.
   The stop motion lives in the boil and the birds; the sun is the calm thing. */
@keyframes bc-pulse {
  0%, 100% { transform: scale(1);     opacity: .92; }
  50%      { transform: scale(1.045); opacity: 1; }
}
/* The halo gets its own, much deeper breath on a different clock to the disc. The
   4.5% disc pulse alone read as almost still (Bahush, 2026-09-01: "less still"), so
   the GLOW is what moves: it swells to 112% and dims to 68% while the disc barely
   stirs, and the two periods (5.5s vs 3.8s) drift in and out of phase so the light
   never settles into a metronome. Still smooth, never stepped: a stepped glow reads
   as a flickering bulb, which is the one thing this scene must never do.
   The position stays parked. Only the breathing gets bigger. */
@keyframes bc-glow {
  0%, 100% { transform: scale(1);    opacity: .68; }
  50%      { transform: scale(1.12); opacity: 1; }
}
/* The boil: real stop motion never holds perfectly still, because the artist's hand
   moves the paper a fraction between shots. Two frames, snapped, no interpolation. */
@keyframes bc-boil {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(.9px, -.7px); }
}
@keyframes bc-boil-alt {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(-.8px, .6px); }
}
/* The light on the meadow strengthens as the sun clears the ridge. */
@keyframes bc-warm {
  from { opacity: .78; }
  to   { opacity: 1; }
}
/* Birds cross the sky, and their wings flap on their own much faster step. */
@keyframes bc-fly {
  from { transform: translate(-120px, 14px); }
  to   { transform: translate(1180px, -46px); }
}
@keyframes bc-flap {
  0%, 100% { transform: scaleY(1); }
  50%      { transform: scaleY(.62); }
}

/* Nothing below runs unless .js-hero is present, and home.js only adds that when motion
   is allowed. With reduced motion or no JavaScript the scene renders as one still
   frame: sun partway up, light already on the meadow. A frozen frame of a good
   illustration, which is a perfectly good background. */
/* The sun crosses in 15s, which is the "quite a bit quicker" you asked for, down from
   the 30s half-rise it replaced.
   ⚠️ THE STEP COUNT IS THE WHOLE LESSON HERE. The first version used steps(14) over
   30s, which is one jump every 2.1 seconds, and that reads as the page glitching rather
   than as a sunrise. steps(50) over 15s is 0.3s per frame, roughly 3fps: still visibly
   stepped, still stop motion, but the cadence reads as animation instead of a fault.
   If this ever needs slowing down again, raise the step count with the duration. Keep
   the per-frame interval under about half a second. */
/* transform-box: fill-box is what makes scale() grow from the sun's own centre. Without
   it an SVG element scales about the viewBox origin and the sun slides off to one side
   as it pulses. */
.bc-sun { transform-box: fill-box; transform-origin: center; }
.bc-halo { transform-box: fill-box; transform-origin: center; }
html.js-hero .bc-sun  { animation: bc-pulse 5.5s ease-in-out infinite; }
html.js-hero .bc-halo { animation: bc-glow 3.8s ease-in-out infinite; }
/* The light on the meadow breathes with it, at half the depth so it stays subordinate. */
html.js-hero .bc-lit { animation: bc-warm 5.5s ease-in-out infinite alternate; }
html.js-hero .bc-ridge-far { animation: bc-boil .62s steps(1, end) infinite; }
html.js-hero .bc-ridge-mid { animation: bc-boil-alt .5s steps(1, end) infinite; }
html.js-hero .bc-meadow,
 html.js-hero .bc-hedges    { animation: bc-boil .44s steps(1, end) infinite; }
html.js-hero .bc-trees     { animation: bc-boil-alt .58s steps(1, end) infinite; }
/* 🔴 transform-box: fill-box IS LOAD BEARING, do not drop it.
   On an SVG element, transform-origin: center resolves against the whole viewBox
   (600, 350 here), NOT the element. Without fill-box, scaleY on a bird sitting at
   y=516 squashed it toward y=350 and threw it about 90px up the sky every 0.3s. That
   was the "glitching" and it was never the travel: the birds were teleporting, not
   flapping. fill-box makes the origin the bird's own box, which is what was meant. */
html.js-hero .bc-bird {
  animation: bc-flap .34s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}
html.js-hero .bc-bird-1 { animation-duration: .62s; }
html.js-hero .bc-bird-2 { animation-duration: .78s; }
html.js-hero .bc-bird-3 { animation-duration: .70s; }
/* Smooth and linear, not stepped. steps(30) over 54s moved them in 43px jumps every
   1.8 seconds, which reads as teleporting rather than flight. The birds are the one
   thing in this scene that should NOT be stop motion: everything else holds still and
   boils, they are the thing that actually travels. */
html.js-hero .bc-birds  { animation: bc-fly 34s linear infinite; }

/* Phones get the still frame. The scene is decorative, and a phone should spend its
   battery on scrolling the page rather than boiling a ridge line it can barely see. */
@media (max-width: 700px) {
  html.js-hero .bc-ridge-far,
  html.js-hero .bc-ridge-mid,
  html.js-hero .bc-meadow,
  html.js-hero .bc-bird,
  html.js-hero .bc-birds { animation: none; }
}/* Wide on purpose. Each beat of the manifesto has to sit on its OWN line, and the
   longest one is 42 characters, so at this type size the measure has to be wide enough
   to hold it. Narrow it and the first beat wraps, which breaks the shortening-stack
   shape the whole hero is built on. The terms line stays narrow via its own max-width. */
.hero .wrap { width: min(100% - 3rem, 76rem); }

/* The page title. Deliberately kept small against the manifesto below it: two large
   type events stacked would compete, and the manifesto is the one carrying the offer.
   It is also the only element that can be added here without costing the fold, which is
   already tight, so weight comes from the letterspacing and the accent, not the size. */
.hero-title {
  font-family: var(--f-body);
  font-weight: 700;
  font-size: clamp(.9375rem, .88rem + .3vw, 1.1875rem);
  letter-spacing: .01em;
  line-height: 1.35;
  color: var(--ink);
  margin: 0 0 clamp(.7rem, 1.5vw, 1.05rem);
  text-wrap: balance;
}
/* The brand play gets the accent, so "creatively bespoke" reads as the signature it is
   rather than as an odd adverb. --pop-deep, not --pop: this is body-sized text. */
.hero-title span { color: var(--pop-deep); }

.manifesto {
  font-family: var(--f-display);
  font-weight: 400;
  font-size: clamp(1.85rem, 4.3vw, 3.9rem);
  line-height: 1.24;
  letter-spacing: -.016em;
  margin: 0 0 clamp(1.35rem, 3.1vw, 2.1rem);
  text-wrap: balance;
  /* One big I, four actions beside it. Two columns sized to content and centred as
     a block; the I spans all four beat rows, the "You" line spans both columns. */
  display: grid;
  grid-template-columns: auto auto;
  /* Left-RAGGED but centre-SEATED (Bahush, 2026-09-01): every line inside the block
     aligns left like a list being read down, and the whole block is then picked up
     and centred in the section as one unit. */
  justify-content: center;
  align-items: center;
  column-gap: clamp(1.5rem, 3.5vw, 3rem);
  text-align: left;
}
/* The one I that owns all four lines. Pop, like the four small ones it replaced:
   a display-size mark is --pop's sanctioned use. Sized to stand as tall as the
   stack it governs without dwarfing the wrap on a phone. */
.manifesto-i {
  grid-row: 1 / span 4;
  /* 4.4em spans visually from the first line to the last; 3.1em only reached three
     of the four rows and read as floating rather than owning the stack. */
  font-size: 4.4em;
  line-height: .8;
  color: var(--pop);
}
.manifesto .beat { display: block; color: var(--ink); position: relative; z-index: 0; }
/* The "You" line rides the phrase column, so the handover lands exactly where the
   eye already is after reading the four actions. */
.manifesto em { grid-column: 2; text-align: left; }

/* ---------- the travelling spotlight ----------
   Every beat is fully legible with no JavaScript and under reduced motion, because the
   dimming only exists inside html.js-hero and home.js refuses to add that class when
   motion is disabled. So the worst case is four bright lines and no animation, which is
   exactly the page as it was.
   Opacity does all the work. Nothing here transitions colour, size or position, so the
   whole cycle stays on the compositor and cannot jank the type. */
/* .55, and not lower. This is the version where nothing is ever hidden, so the resting
   state has to stay genuinely READABLE, not decorative.
   MEASURED against the real rendered background, sun tint included: the three resting
   lines land at 3.90 to 3.94:1 and the lit line at 15.2:1. AA for large text is 3:1, so
   the resting state clears it with margin while the step up still reads as a spotlight.
   An earlier pass had this at .26, which measured 3.35:1 and looked like texture rather
   than copy. Do not push it back down. */
html.js-hero .manifesto .beat {
  opacity: .55;
  transition: opacity .75s cubic-bezier(.22, .61, .36, 1);
  will-change: opacity;
}
html.js-hero .manifesto .beat.is-on { opacity: 1; }

/* The warm bloom that rides with the active line. Sits behind the glyphs inside the
   beat's own stacking context, so it lights the text without touching the sun below. */
.manifesto .beat::before {
  content: ""; position: absolute; z-index: -1;
  left: 50%; top: 50%;
  width: 116%; height: 260%;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(226,99,60,.20) 0%, rgba(226,99,60,.07) 46%, rgba(226,99,60,0) 100%);
  opacity: 0;
  transition: opacity .75s cubic-bezier(.22, .61, .36, 1);
  pointer-events: none;
}
html.js-hero .manifesto .beat.is-on::before { opacity: 1; }

/* Step numbers. Always rendered in a fixed-width slot, so the line never reflows as the
   spotlight moves. Cabinet Grotesk rather than Bodoni: at this size Bodoni's hairlines
   would break up, and the brief puts its floor at ~1.8rem. */
.manifesto .beat-n {
  display: inline-block;
  width: 2.9em;
  margin-right: .55em;
  font-family: var(--f-body);
  font-weight: 500;
  font-size: .26em;
  letter-spacing: .1em;
  font-variant-numeric: tabular-nums;
  color: var(--pop-deep);
  vertical-align: .5em;
}
/* The number deliberately has NO dim state of its own. It rides its line's opacity, so
   it is always exactly as legible as the words next to it. An earlier pass gave it a
   separate .42, which multiplied with the line's .55 and pushed the resting numbers to
   about 23% effective, well under anything readable. One opacity per line, not two. */
.manifesto em {
  display: block;
  font-style: italic;
  color: var(--teal);
  margin-top: .5em;
}

/* ⚠️ Contrast rule for anything small added to this hero: --ink-2, never --ink-3.
   MEASURED: --ink-3 is only 4.6:1 on bare paper, and the sunrise's warm wash pulled
   hero small text to 3.4 to 4.2:1, under the 4.5:1 AA floor.
   (The .handover block that carried this lesson was cut 2026-09-01 as redundant
   copy; the lesson outlives it.) */
.terms-line {
  font-size: clamp(.875rem, .84rem + .14vw, 1rem);
  line-height: 1.8;
  color: var(--ink-2);
  max-width: 46rem;
  margin: 0 auto clamp(1.75rem, 4vw, 2.5rem);
}
.terms-line b { color: var(--ink); font-weight: 700; }

.cta { display: flex; justify-content: center; }

.scroll-cue {
  display: inline-block;
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
  color: var(--ink-2);
  font-size: .875rem;
  text-decoration: none;
  transition: color .18s ease;
}
.scroll-cue::after { content: " \2193"; }
.scroll-cue:hover { color: var(--ink); }

/* The 861 to 940px height band, which is where a 1440x900 laptop lands. The taller nav
   left the hero content overrunning its box here, squeezing the scroll cue to 16px off
   the fold. This trims the hero's own padding rather than the type, so the manifesto
   keeps its full size at the single most common laptop resolution. */
@media (min-width: 861px) and (min-height: 861px) and (max-height: 940px) {
  .hero { padding: 1.75rem 0; }
  .manifesto { margin-bottom: clamp(1.1rem, 2.4vw, 1.6rem); }
  .terms-line { margin-bottom: 1.25rem; }
  .scroll-cue { margin-top: 1.25rem; }
}

/* Short laptops: the offer must never fall below the fold, so it compresses. These
   caps are what the 1366x768 and 1280x700 checks are actually measuring. */
@media (min-width: 861px) and (max-height: 860px) {
  .hero { padding: 1.5rem 0; }
  .manifesto { font-size: clamp(1.7rem, 3.35vw, 2.85rem); line-height: 1.22; margin-bottom: 1.5rem; }
  .terms-line { margin-bottom: 1.5rem; line-height: 1.7; }
  .scroll-cue { margin-top: 1.25rem; }
}
/* Short phones, same reason. */
@media (max-width: 860px) and (max-height: 720px) {
  .hero { padding: 1.25rem 0; }
  .manifesto { font-size: clamp(1.5rem, 5.2vw, 2rem); line-height: 1.24; margin-bottom: 1.15rem; }
  .terms-line { margin-bottom: 1.15rem; line-height: 1.65; }
  .scroll-cue { margin-top: 1rem; }
}

/* ---------- 3. the problem ----------
   Flat --black, no imagery. Two-tone headline: the admission in cream, the turn in
   pop. Pop is legal here because a display headline is a large mark. */

.problem {
  background: var(--black);
  padding: clamp(4rem, 9vw, 6.5rem) 0 clamp(3.5rem, 8vw, 5.5rem);
  text-align: center;
  /* Half of the 2px overlap with .shape-divider below. See the note there. */
  margin-bottom: -1px;
}
.problem h2 {
  font-family: var(--f-display); font-weight: 400;
  color: var(--cream);
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3.15rem);
  line-height: 1.1; letter-spacing: -.01em;
  margin-bottom: clamp(1.5rem, 3vw, 2rem);
}
.problem h2 span { display: block; color: var(--pop); }
.problem p {
  color: rgba(218,202,164,.78);
  max-width: 46ch;
  margin: 0 auto 1rem;
}
.problem .btn { margin-top: clamp(1.25rem, 3vw, 1.75rem); }

/* ---------- 4. the shaped transition ----------
   The black band's bottom edge cut on a diagonal, so black pours into paper instead
   of stopping at a ruled line. Static geometry, so reduced motion has nothing to
   turn off here. */

.shape-divider {
  height: clamp(3rem, 8vw, 6.5rem);
  background: var(--black);
  clip-path: polygon(0 0, 100% 0, 100% 34%, 0 100%);
  /* THE HAIRLINE FIX. This black sits directly under another black band, and the join
     between two stacked elements lands on a fractional pixel once display scaling or
     browser zoom is involved. The browser antialiases that join, and the off-white page
     behind shows through as a thin light rule across the full width.
     Both sides now pull toward each other by 1px, so the two blacks overlap by 2px and
     there is no join left to antialias. The wedge is ~104px tall, so losing 2px of it
     is invisible. Do not remove either margin: they only work as a pair. */
  margin-top: -1px;
}

/* ---------- bands ---------- */

.band { padding: clamp(3.5rem, 8vw, 6rem) 0; }
.band-sunk { background: var(--paper-sunk); }
.band h2 {
  font-family: var(--f-display); font-weight: 400;
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3.15rem);
  line-height: 1.08; letter-spacing: -.01em;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

/* ---------- 5. how it works: the travelling timeline ----------
   A track, a fill that grows, and a dot riding the fill's leading edge. Both move on
   transform only, driven by a single --p custom property that home.js sets from
   scroll position. With no JavaScript --p stays at its declared 1, so the line reads
   as a finished, fully drawn rule rather than an empty track. */

.timeline { position: relative; --p: 1; }

.timeline-track {
  position: absolute;
  left: 0; top: .75rem; bottom: .75rem;
  width: 2px;
  background: rgba(46,90,94,.16);
  border-radius: 2px;
}
.timeline-fill {
  position: absolute; inset: 0;
  background: var(--teal-mid);
  border-radius: 2px;
  transform: scaleY(var(--p));
  transform-origin: top;
}
/* The runner is exactly as tall as the track, so translating it by a percentage
   moves the dot by that fraction of the TRACK, which is the behaviour we want.
   A percentage on the dot itself would resolve against the dot. */
.timeline-runner {
  position: absolute; inset: 0;
  transform: translateY(calc(var(--p) * 100%));
}
.timeline-dot {
  position: absolute; left: 50%; top: 0;
  width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px;
  border-radius: 50%;
  background: var(--pop);
  box-shadow: 0 0 0 5px rgba(226,99,60,.14);
}

.timeline-steps { padding-left: clamp(1.75rem, 5vw, 3rem); }
.timeline-steps li {
  display: flex; gap: clamp(1rem, 3vw, 2rem);
  padding: 1.75rem 0;
  box-shadow: inset 0 -1px 0 rgba(88,118,120,.18);
}
.timeline-steps li:last-child { box-shadow: none; }
.step-n {
  font-family: var(--f-editorial);
  font-size: clamp(2.25rem, 4vw, 3.25rem);
  line-height: 1; color: var(--pop); flex: none; min-width: 2ch;
  font-variant-numeric: tabular-nums;
}
.timeline-steps li > div { min-width: 0; }
.timeline-steps h3 { font-size: 1.1875rem; font-weight: 700; margin-bottom: .5rem; }
.timeline-steps p { margin: 0; max-width: 58ch; }

/* Stagger the three steps so they arrive in sequence rather than as one block. */
html.js-reveal .timeline-steps li:nth-child(2) { transition-delay: .1s; }
html.js-reveal .timeline-steps li:nth-child(3) { transition-delay: .2s; }

/* ---------- 5. the three ways ----------
   Stacked hairline rows (never three equal cards). Reuses .step-n for the numerals
   so the ways and the timeline speak the same visual language. Copy is deliberately
   outcome-only: no system, channel or engine is ever named here. */
.ways-lead { color: var(--ink-2); max-width: 58ch; }
.ways-list { margin: clamp(1.25rem, 2.5vw, 1.75rem) 0 0; }
.ways-list li {
  display: flex; align-items: baseline;
  gap: clamp(1rem, 3vw, 2rem);
  padding: 1.4rem 0;
  box-shadow: inset 0 -1px 0 rgba(88,118,120,.18);
}
.ways-list li:last-child { box-shadow: none; }
.ways-list p {
  margin: 0;
  font-size: clamp(1.125rem, 1.02rem + .5vw, 1.4375rem);
  line-height: 1.45;
  color: var(--ink);
  max-width: 52ch;
}
.ways-close { color: var(--ink-2); max-width: 58ch; margin: clamp(1.25rem, 2.5vw, 1.75rem) 0 0; }
html.js-reveal .ways-list li:nth-child(2) { transition-delay: .1s; }
html.js-reveal .ways-list li:nth-child(3) { transition-delay: .2s; }

/* ---------- 6. the numbered panels ----------
   Capped below a full viewport on purpose: three true 100dvh blocks around one short
   headline each reads as padding on a 700px-tall laptop. This keeps the cadence and
   lets the next panel peek. */

.panel {
  min-height: 78dvh;
  display: flex; align-items: center;
  padding: clamp(3rem, 8vw, 5rem) 0;
}
@supports not (height: 78dvh) { .panel { min-height: 78vh; } }
@media (max-width: 700px) { .panel { min-height: 62dvh; } }

.panel-sunk  { background: var(--paper-sunk); }
.panel-paper { background: var(--paper); }
.panel-black { background: var(--black); }

.panel-n {
  display: block;
  font-family: var(--f-editorial);
  font-weight: 400;
  font-size: clamp(4.5rem, 12vw, 9rem);
  line-height: .85;
  color: var(--pop);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
  margin-bottom: clamp(1rem, 2.5vw, 1.75rem);
}
.panel h2 {
  font-family: var(--f-display); font-weight: 400;
  font-size: clamp(2rem, 1.4rem + 2.6vw, 3.4rem);
  line-height: 1.06; letter-spacing: -.01em;
  margin-bottom: clamp(.85rem, 2vw, 1.25rem);
}
.panel p { max-width: 44ch; margin: 0; }
.panel-black h2 { color: var(--cream); }
.panel-black p { color: rgba(218,202,164,.78); }

html.js-reveal .panel h2 { transition-delay: .08s; }
html.js-reveal .panel p  { transition-delay: .16s; }

/* ---------- 7. who runs it ---------- */

.who {
  display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  gap: clamp(1.75rem, 5vw, 4rem);
  align-items: center;
}
/* The founder photo carries its own studio backdrop, so no ground colour sits behind
   it. Cropped 2:3 and biased upward, which keeps the frame on him and shows less
   backdrop than a square crop would. No border: depth is the lift shadow. */
.who-photo {
  border-radius: 20px;
  overflow: hidden;
  box-shadow: var(--panel-lift);
}
.who-photo img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  object-position: 50% 18%;
}
.who-copy h2 {
  font-family: var(--f-display); font-weight: 400;
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3.15rem);
  line-height: 1.08; letter-spacing: -.01em;
  margin-bottom: 1.25rem;
}
.who-sign {
  font-family: var(--f-display); font-style: italic;
  font-size: 1.125rem; color: var(--ink-3); margin: 1.5rem 0 0;
}
html.js-reveal .who-copy { transition-delay: .12s; }

@media (max-width: 760px) {
  .who { grid-template-columns: 1fr; gap: 1.75rem; }
  .who-photo { max-width: 17rem; }
}

/* ---------- 8. faq ---------- */

details {
  padding: 1.15rem 0;
  box-shadow: inset 0 -1px 0 rgba(88,118,120,.2);
}
summary {
  cursor: pointer; list-style: none;
  font-weight: 700; color: var(--ink); font-size: 1.0625rem;
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
}
summary::-webkit-details-marker { display: none; }
summary::after {
  content: "+"; font-size: 1.4rem; font-weight: 400; color: var(--pop-deep);
  line-height: 1; flex: none; transition: transform .2s ease;
}
details[open] summary::after { transform: rotate(45deg); }
details p { margin: .85rem 0 0; max-width: 60ch; }

/* ---------- 9. closer and footer ---------- */

.closer { background: var(--black); padding: clamp(3.5rem, 8vw, 5.5rem) 0; text-align: center; }
.closer h2 {
  font-family: var(--f-display); font-weight: 400; color: var(--cream);
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3.15rem); line-height: 1.08; margin-bottom: 1rem;
}
.closer p { color: rgba(218,202,164,.76); max-width: 44ch; margin: 0 auto 2rem; }
/* The sign-off. Small, letterspaced, sitting under the button as a mark rather than a
   sentence. --cream is TEXT on black here, which is its one permitted use. */
/* ⚠️ .closer p.closer-sign, NOT bare .closer-sign. The `.closer p` rule above is
   class+type, which outranks a lone class, so a bare .closer-sign margin is dead CSS
   and the sign-off collapses onto the button. That is exactly the uneven spacing bug
   shipped on 2026-08-31: keep the specificity or the margin silently vanishes again. */
.closer p.closer-sign {
  /* Top margin MATCHES the section's own bottom padding, so the air above the
     sign-off equals the air below it and it sits centred in the space under the
     button instead of stuck to it. Change .closer's padding, change this with it. */
  margin: clamp(3.5rem, 8vw, 5.5rem) auto 0;
  font-family: var(--f-body);
  font-weight: 500;
  font-size: .8125rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  /* .7, not .5. MEASURED: cream at 50% over --black composites to (115,107,89), which
     is 3.68:1 at 13px, under the 4.5:1 floor for small text. .7 lands near 6.5:1 and
     still reads as a quiet sign-off rather than a second headline. */
  color: rgba(218,202,164,.7);
}
.closer-sign span { color: var(--pop); }

footer { background: var(--paper-sunk); padding: 3rem 0 2rem; font-size: .9375rem; }
.footer-top { display: flex; flex-wrap: wrap; gap: 1.5rem 2.5rem; align-items: center; padding-bottom: 1.75rem; }
.footer-logo { font-family: var(--f-display); font-size: 1.35rem; color: var(--ink); }
.footer-nav { display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; margin-right: auto; }
.footer-nav a, .footer-mail { color: var(--ink-3); text-decoration: none; }
.footer-nav a:hover, .footer-mail:hover { color: var(--ink); }
.footer-bottom {
  display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; justify-content: space-between;
  padding-top: 1.5rem; box-shadow: inset 0 1px 0 rgba(88,118,120,.2);
  color: var(--ink-3); font-size: .8438rem;
}
.footer-bottom p { margin: 0; }
.footer-bottom a { color: var(--ink-3); text-decoration: none; }
.footer-bottom a:hover { color: var(--ink); }
.abn { white-space: nowrap; }
