:root{
  --bg:#0C0B0A; --surface:#161412; --raised:#211E1B; --border:#4A443E;
  --hair:#221F1C; --text:#F5F2ED; --muted:#948C84;
  --accent:#2A6B80; --accent-bright:#48AECB; --gold:#D9A441;
  --success:#4EBC55; --danger:#E8624A;
  --stone-a:#1C1917; --stone-b:#232019; --stone-c:#2A2622;
  --shadow:0 1px 0 rgba(245,242,237,.06) inset;
  --stone-shadow:0 14px 34px rgba(0,0,0,.55);
  --card-shadow:0 1px 0 rgba(245,242,237,.045) inset, 0 18px 44px rgba(0,0,0,.32);
  --glow:radial-gradient(58% 52% at 68% 42%, rgba(42,107,128,.30), transparent 72%);
}
:root[data-belay-theme="light"]{
  --bg:#F5F2ED; --surface:#EBE7E0; --raised:#E2DDD4; --border:#C9C1B7;
  --hair:#DED8CF; --text:#17140F; --muted:#6A625A;
  --accent:#1F5566; --accent-bright:#215D72; --gold:#8A6316;
  --success:#2F7F35; --danger:#B23F2B;
  --stone-a:#DDD7CD; --stone-b:#D3CCC1; --stone-c:#C8C0B4;
  --shadow:0 1px 0 rgba(255,255,255,.55) inset;
  --stone-shadow:0 12px 26px rgba(23,20,15,.16);
  --card-shadow:0 1px 0 rgba(255,255,255,.6) inset, 0 14px 32px rgba(23,20,15,.07);
  --glow:radial-gradient(58% 52% at 68% 42%, rgba(31,85,102,.13), transparent 72%);
}
*{box-sizing:border-box}
/* Smooth scrolling is a nicety; for a reader who asked the OS for less motion
   it is the opposite of one, and it also hijacks in-page anchor jumps. */
@media (prefers-reduced-motion: no-preference){html{scroll-behavior:smooth}}

/* The reveal's starting state lives here, not in app.js.
   `belay-js` is added by the inline <head> script (see scripts/build-site.mjs)
   before the first paint, and only when the reveal can finish — so sections are
   never painted, hidden, then animated back in, and without JavaScript this
   rule never matches and everything is simply visible. */
.belay-js [data-rise]{opacity:0}

/* --- hero atmosphere -------------------------------------------------------
   `--glow` was defined in both themes by the design import and then used by
   nothing at all — the layer was drawn and never hung. This is it.
   It drifts over 26 seconds, which is slow enough to read as light rather than
   as motion. That restraint is the point: the reader this page is written for
   is anxious about starting, and a hero that pulses at them is a hero they
   scroll past. Atmosphere, not attention-grabbing. */
.belay-glow{position:absolute;inset:-25% -12%;background:var(--glow);pointer-events:none;z-index:0;
  animation:belay-drift 26s ease-in-out infinite}
@keyframes belay-drift{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  50%    {transform:translate3d(-3%,2.5%,0) scale(1.07)}
}

/* --- the decomposition -----------------------------------------------------
   The one thing the page has to make somebody understand in three seconds:
   a task too big to start breaks into pieces, and one of them lights up.
   Every landing page worth copying shows the product doing its job; this site
   has no product screenshots yet, so it shows the mechanism instead.

   ⚠️ **The default state below is the FINISHED state, deliberately.** With no
   JavaScript — or under reduced motion, where `belay-js` is never added — a
   reader sees a boulder that has already broken, which is the idea. Only the
   `.belay-js` rules re-collapse it so there is something to animate, and that
   is the same discipline `[data-rise]` follows: never hide with a mechanism
   that might not be able to un-hide. */
[data-decompose] .bd-whole{opacity:.4;transform:scale(.93)}
[data-decompose] .bd-part {opacity:1;transform:translate(var(--x),var(--y))}

.belay-js [data-decompose] .bd-whole{opacity:1;transform:none;
  transition:opacity 1.2s ease .3s,transform 1.2s cubic-bezier(.22,.7,.25,1) .3s}
.belay-js [data-decompose] .bd-part {opacity:0;transform:translate(0,0) scale(.35);
  transition:opacity .7s ease,transform 1.05s cubic-bezier(.22,.7,.25,1)}

.belay-js [data-decompose].is-decomposed .bd-whole{opacity:.4;transform:scale(.93)}
.belay-js [data-decompose].is-decomposed .bd-part {opacity:1;transform:translate(var(--x),var(--y)) scale(1);
  transition-delay:calc(.32s + var(--i) * .15s)}

/* The stone stack breathes on an infinite loop. That is the one animation on
   the site a reader cannot escape by scrolling past it, so it has to answer to
   the OS setting — as does every transition, including the hover ones the
   cascade now owns. The reveal is already handled upstream: `belay-js` is never
   added under reduced motion, so nothing is hidden to begin with. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}
body{margin:0;background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Roboto,Helvetica,Arial,sans-serif;}
a{color:var(--accent-bright);text-decoration:none}
a:hover{color:var(--text)}
::selection{background:var(--accent);color:#F5F2ED}
@keyframes belay-rise{from{opacity:0;transform:translate3d(0,16px,0)}to{opacity:1;transform:none}}
@keyframes belay-breathe{0%,100%{transform:translate3d(0,0,0)}50%{transform:translate3d(0,-4px,0)}}
