/* ===== Midu Studio clone — tokens extracted from the live site's CSS ===== */
:root {
  --bg: #050505;
  --light: #e6e6e6;
  --text: #ffffff;
  --dim-60: rgba(255, 255, 255, .6);
  --dim-50: rgba(255, 255, 255, .5);
  --dim-40: rgba(255, 255, 255, .4);
  --card-glass: rgba(0, 0, 0, .4);          /* plan cards */
  --item-glass: rgba(255, 255, 255, .06);   /* faq items */
  --line: rgba(255, 255, 255, .07);
  --pad-x: 40px;
  /* live breakpoint system: values below are the 1280–1919 canvas;
     the ≥1920 media block swaps them to the larger canvas, as the original does */
  --w-heading: 900px;    /* statement/section headings, about, intro   (1920: 1200px) */
  --w-col: 900px;        /* faq column                                  (1920: 955px)  */
  --w-tools: 785px;      /* tools head/desc/cards                       (1920: 955px)  */
  /* ===== item 5: per-component motion. Each curve/duration below is a distinct transition
     object taken from the live home bundle, not one shared easing. ===== */
  --m-hero:      1s   cubic-bezier(.11, .06, .18, 1);   /* appear family, delays .75/.9/1.05 */
  --m-words:     1.2s cubic-bezier(.44, 0, .56, 1);     /* word reveal, .05s per-word step   */
  --m-reveal:    .65s cubic-bezier(.56, 0, .47, 1);     /* paragraph + card reveals          */
  --m-reveal-sm: .5s  cubic-bezier(.56, 0, .47, 1);
  --m-menu-in:   .4s  cubic-bezier(.12, .23, .5, 1);    /* menu open                         */
  --m-menu-out:  .4s  cubic-bezier(.5, 0, .88, .77);    /* menu close                        */
  --m-slide:     .55s cubic-bezier(.52, 0, .45, 1);     /* testimonial transitions           */
  --m-keycap:    .3s  cubic-bezier(.44, 0, .56, 1);     /* cookie buttons (was the keycaps)  */
  --m-faq:       .45s cubic-bezier(.44, 0, .56, 1);     /* FAQ expansion                     */
  --m-tile:      .55s cubic-bezier(.62, 0, .4, 1);      /* tool / service tiles              */
  --grid-pad: 40px;      /* highlights section side padding             (1920: 160px)  */
  --about-gap: 100px;    /* about/intro column gutter                   (1920: 190px)  */
  --fs-heading: 82px;    /* big headings: 42 / 65 / 82 / 98 per breakpoint */
  --font: "Switzer", "Inter", -apple-system, sans-serif;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --fs-body-lg: 24px;    /* about/intro copy (constant across desktop breakpoints) */
}
@media (min-width: 1920px) {
  :root {
    --w-heading: 1200px; --w-col: 955px; --w-tools: 955px;
    --grid-pad: 160px; --about-gap: 190px; --fs-heading: 98px;
  }
  /* The tools row is the one block that does NOT widen to 955 at this canvas: the live
     `ServicesIconsHover` container stays 785px and carries `transform: scale(1.2)` (present at
     2000px, absent at 1600px), which is why every icon measures 96px there rather than 80. */
  .tools-marquee { width: 785px; margin-inline: auto; transform: scale(1.2); }
}
@media (max-width: 1279px) { :root { --fs-heading: 65px; --fs-body-lg: 21px; } }
@media (max-width: 809px)  { :root { --fs-heading: 42px; --fs-body-lg: 19px; } }

* { margin: 0; padding: 0; box-sizing: border-box; }
/* Lenis owns scrolling (see assets/vendor/lenis + the init in each page's script);
   native smooth-scroll would fight it, so it is only a no-JS fallback. */
html { scroll-behavior: smooth; }
html.lenis { scroll-behavior: auto; }

/* The live site injects this from its ScrollbarHider component (forceHide), verbatim:
     .lenis { scrollbar-width: none; -ms-overflow-style: none; }
     .lenis::-webkit-scrollbar { display: none; width: 0 !important; height: 0 !important;
                                 background: transparent; }
     * { scrollbar-width: none !important; }
   Without it the 15px scrollbar shrinks the viewport and every centred 955/1200 column
   lands 8px left of the reference. */
.lenis { scrollbar-width: none; -ms-overflow-style: none; }
.lenis::-webkit-scrollbar { display: none; width: 0 !important; height: 0 !important; background: transparent; }
* { scrollbar-width: none !important; }
::-webkit-scrollbar { display: none; width: 0 !important; height: 0 !important; background: transparent; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.3;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
.dim { color: var(--dim-40); }

/* ===== Buttons — the live two-phase hover systems =====
   The reference has TWO button components and each runs a *transient middle variant* on
   mouseenter that resolves to the settled hover variant after a fixed delay. That middle
   phase is what reads as the "blur" on hover.

   BtnSecondary (translucent pills) — live variants and the state machine:
     rest   BtnBlurWhite       bg rgba(255,255,255,.1) · gap 12 · label filter none · text #fff
     enter  BtnBlurEffect      bg rgba(255,255,255,.2) · gap 22 · label filter blur(4px)
                               · icon opacity .8 rotate 45 · text rgb(196,196,196)
     +400ms BtnHover           same, but label filter back to none
     leave  -> BtnBlurWhite
     black family: rest rgba(0,0,0,.07) text rgb(3,3,3) · hover rgba(0,0,0,.16) text rgb(56,56,56)
     label transitions: blur IN  {duration:.4, ease:[.44,0,.56,1]}
                        blur OUT {duration:.4, ease:[.76,0,.61,1]}
     root .35s [.44,0,.56,1] (.5s inside the hover variants) · icon .3s [.5,0,.88,.77]

   BtnPrimary (solid pills) — no blur; a two-phase icon cascade instead:
     rest   BtnPrimary         bg rgb(255,255,255) · shadow 0 0 20px 5px rgba(255,43,43,0)
                               · IconStar rotate 0 scale 1
     enter  BtnPrimaryMiddle   bg rgb(230,230,230) · shadow none · IconStar rotate 45 scale .8
     +300ms BtnPrimaryHover    bg rgb(230,230,230) · IconStar rotate 90 scale 1.2
     black family: rgb(3,3,3) -> rgba(3,3,3,.8)
     phases: .3s [.5,0,.88,.77] then .3s [.12,.23,.5,1]; default context .3s [.44,0,.56,1]
   Both share: h48, padding 0 18px, radius 20px corner-shape superellipse(1.2). ===== */
.btn {
  display: inline-flex; align-items: center; gap: 12px;
  height: 48px; padding: 0 18px;
  border-radius: 17.8px; border-radius: 20px; corner-shape: superellipse(1.2);  /* live .892 fallback */
  font-size: 16px; font-weight: 500; letter-spacing: -.03em; line-height: 1.3;
  transition:
    gap             .35s cubic-bezier(.44, 0, .56, 1),
    background      .35s cubic-bezier(.44, 0, .56, 1),
    color           .35s cubic-bezier(.44, 0, .56, 1),
    box-shadow      .3s  cubic-bezier(.44, 0, .56, 1);
}
/* the icon rides its own curve (live: .3s [.5,0,.88,.77]) */
.btn > .ic, .btn > svg { transition: transform .3s cubic-bezier(.5, 0, .88, .77), opacity .3s cubic-bezier(.5, 0, .88, .77); }

/* --- The label blur is on BOTH families, so it lives on `.btn` --- */
/* Both components declare `filter: blur(4px)` on their text container for the middle variant, but
   the middle phase is a different length in each (400ms secondary / 300ms primary), so the blur is
   still on its way in when the phase ends and each family peaks somewhere different. Measured on
   the reference at 25ms intervals:
     BtnSecondary  0 -> 4.00px at 414ms -> 0 at 840ms
     BtnPrimary    0 -> 2.80px at 375ms -> 0 at 850ms
   Each family therefore gets its own keyframes so the peak lands where the reference's does:
   primary 2.8px at 44% of 850ms = 374ms, secondary 4px at 49% of 840ms = 412ms. */
.btn .flip { transition: filter .4s cubic-bezier(.76, 0, .61, 1); }
.btn:hover .flip { animation: btn-blur-primary .85s both; }
@keyframes btn-blur-primary {
  0%   { filter: blur(0px);   animation-timing-function: cubic-bezier(.44, 0, .56, 1); }
  44%  { filter: blur(2.8px); animation-timing-function: cubic-bezier(.76, 0, .61, 1); }
  100% { filter: blur(0px); }
}
.btn-secondary:hover .flip { animation: btn-blur-secondary .84s both; }
@keyframes btn-blur-secondary {
  0%   { filter: blur(0px); animation-timing-function: cubic-bezier(.44, 0, .56, 1); }
  49%  { filter: blur(4px); animation-timing-function: cubic-bezier(.76, 0, .61, 1); }
  100% { filter: blur(0px); }
}

/* --- BtnSecondary: the translucent family. Only this one widens its gap (live 12 -> 22). --- */
.btn-secondary { background: rgba(255, 255, 255, .1); color: #fff; }
.btn-secondary:hover { background: rgba(255, 255, 255, .2); color: rgb(196, 196, 196); gap: 22px; }
.btn-secondary.on-light { background: rgba(0, 0, 0, .07); color: rgb(3, 3, 3); }
.btn-secondary.on-light:hover { background: rgba(0, 0, 0, .16); color: rgb(56, 56, 56); }
.btn-secondary:hover > .ic, .btn-secondary:hover > svg { opacity: .8; transform: rotate(45deg); }

/* --- BtnPrimary: the solid family, icon cascade instead of blur --- */
.btn-light { background: #fff; color: #0a0a0a; box-shadow: 0 0 20px 5px rgba(255, 43, 43, 0); }
.btn-light:hover { background: rgb(230, 230, 230); box-shadow: none; }
.btn-dark { background: rgb(3, 3, 3); color: #fff; }
.btn-dark:hover { background: rgba(3, 3, 3, .8); }
.btn-light:hover > .ic, .btn-dark:hover > .ic { animation: btn-star .6s both; }
@keyframes btn-star {
  0%   { transform: rotate(0deg)  scale(1);  animation-timing-function: cubic-bezier(.5, 0, .88, .77); }
  50%  { transform: rotate(45deg) scale(.8); animation-timing-function: cubic-bezier(.12, .23, .5, 1); }
  100% { transform: rotate(90deg) scale(1.2); }
}
.btn-ghost { background: #fff; color: #0a0a0a; box-shadow: 0 8px 24px #00000014; }
/* sliding label: duplicate text below, whole stack rises on hover */
.flip { display: block; height: 20px; line-height: 20px; overflow: hidden; font-weight: inherit; }
.flip > b { display: block; font-weight: inherit; transition: transform .5s var(--ease); }
.flip > b::after { content: attr(data-l); display: block; }
.btn:hover .flip > b, .nav-menu-btn:hover .flip > b { transform: translateY(-20px); }

/* ===== Nav (live: fixed, padding 25px 40px) ===== */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  padding: 25px var(--pad-x);
  pointer-events: none;
}
.nav > * { pointer-events: auto; }
/* live: the logo is a single 70x21 wordmark lockup (mark + "midu"), not an icon + text */
.nav-logo { display: flex; align-items: center; }
.nav-logo-mark { width: 70px; height: 21px; display: block; color: #fff; }
/* --- The pill IS the menu (live MenuClose -> MenuOpen) ---
   Measured on the live page at 2000x1200:
     MenuClose  280x60   MenuOpen  450x537   both centred on the viewport
     fill rgba(21,21,21,.8) · backdrop-filter blur(10px) · radius 20px superellipse(1.2)
     column · gap 20 · align-items center · justify-content flex-start · overflow hidden
     MenuContainer stays 280 wide in BOTH states, so the row does not stretch with the panel
     60 (row) + 20 (gap) + 437 (list) = 517, and the pill is 537 -> 20px of bottom padding
   It opens on **mouseenter** and closes on mouseleave — it was a click-only dropdown here.
   Tap/click and Escape still work for touch and keyboard. */
.nav-pill {
  /* `top` must be pinned: as an absolutely-positioned child of a `align-items: center` flex row
     its static position is vertically centred, so growing to 537px hoisted it off-screen.
     19px is the live MenuClose top at 2000x1200.
     Centred with `left/right: 0` + `margin-inline: auto` and deliberately NO transform: an element
     that carries BOTH `backdrop-filter` and its own `transform` becomes its own backdrop root, so
     the blur samples nothing and silently does nothing. The reference avoids this by putting the
     centring translate on the *parent* container and the backdrop-filter on the pill. Auto margins
     also keep it centred for free when the width animates 280 -> 450. */
  position: absolute; top: 19px; left: 0; right: 0; margin-inline: auto;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 20px; padding: 0 0 20px;
  width: 280px; height: 60px; overflow: hidden;
  background: rgba(21, 21, 21, .8);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);   /* live is 10px, not 16 */
  border-radius: 17.8px; border-radius: 20px; corner-shape: superellipse(1.2);
  /* the live component has ONE transition for every property it animates */
  transition: width .35s cubic-bezier(.44, 0, .56, 1), height .35s cubic-bezier(.44, 0, .56, 1);
}
/* The live menu has three rows (450x537). This clone dropped the Pricing row with the pricing
   section, so the list is one 99px row + one 1px hairline shorter: 437 - 100 = 337, and the pill
   537 - 100 = 437. Every other value is still the reference's. */
.nav-pill.open { width: 450px; height: 437px; }
/* hover-open is gated on a real pointer so a touch tap-hold cannot half-open it */
@media (hover: hover) { .nav-pill:hover { width: 450px; height: 437px; } }
/* MenuContainer: fixed 280x60 row, live padding 0 20px 0 14px */
.nav-pill-row {
  flex: none; z-index: 5;
  display: flex; align-items: center; justify-content: space-between;
  width: 280px; height: 60px; padding: 0 20px 0 14px;
}
/* MenuBtn: 73x26, radius 4, gap 8, padding 3px 5px */
.nav-menu-btn {
  display: flex; align-items: center; gap: 8px; padding: 3px 5px; border-radius: 4px;
  font-size: 18px; font-weight: 500; letter-spacing: -.03em;
}
/* TextWrapper is a 22px window; the live labels sit at a 20px pitch, so the stack rises 20px.
   (The live labels are 21.6px tall and overlap by 1.6px inside the window — approximated here
   with a 20px line box, which is visually identical.) */
.nav-menu-btn .flip { height: 22px; line-height: 20px; }
.nav-menu-btn .flip > b { line-height: 20px; }
.nav-pill.open .nav-menu-btn .flip > b { transform: translateY(-20px); }
@media (hover: hover) { .nav-pill:hover .nav-menu-btn .flip > b { transform: translateY(-20px); } }
/* MenuIconDefualt -> MenuIcon2: the 2x2 grid is KEPT and each 4px dot rotates 45deg (this was a
   corner-to-edge-midpoint translate before, which is the MenuIcon1 variant, not this one).
   Live dots: 4x4, rgb(255,255,255), border-radius 25%, 6px pitch inside a 10x10 box. */
.dots { display: grid; grid-template-columns: repeat(2, 4px); gap: 2px; width: 10px; height: 10px; }
.dots i { width: 4px; height: 4px; background: rgb(255, 255, 255); border-radius: 25%; transition: transform .35s cubic-bezier(.44, 0, .56, 1); }
.nav-pill.open .dots i { transform: rotate(45deg); }
@media (hover: hover) { .nav-pill:hover .dots i { transform: rotate(45deg); } }
.nav-slots { color: var(--dim-60); font-size: 14px; letter-spacing: -.02em; white-space: nowrap; }
.nav-cta { font-size: 15px; }

/* ===== Menu list — the panel content, living INSIDE the pill =====
   Measured on the live page with the menu open (450px wide):
     MenuList     450x437 · gap 40 · column · justify center · align center
     ListWrapper  450x301 · gap 20
     List         line(1) item(99) line(1) item(99) line(1) item(99) line(1)
                  4 hairlines at rgba(255,255,255,.05)
     MenuItem     450x99 · padding 12px 20px · row · space-between · align center
     ItemContant  410x75 · label Switzer Regular 24px / -.03em / 100% / rgb(255,255,255)
                  thumbnail 95x75 · radius 16px corner-shape superellipse(1.5)
     ItemGradient absolute inset 0 · linear-gradient(270deg, rgba(255,255,255,0) 0%,
                  rgba(255,255,255,.03) 100%) · opacity 0 -> 1 on row hover
     ListSocials  450x96 · gap 20 · padding 0 20px · label 12px rgba(255,255,255,.4) / -.03em
                  list gap 8 · items 16px tall
   Nothing here fades or staggers: the whole list is always laid out and the pill's own
   overflow:hidden is what hides it. That is how the reference does it. ===== */
.menu-list {
  flex: none; width: 100%; height: 337px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 40px;
}
.menu-links { width: 100%; display: flex; flex-direction: column; }
.menu-links a {
  position: relative; isolation: isolate;
  display: flex; align-items: center; justify-content: space-between;
  height: 99px; padding: 12px 20px;
  border-top: 1px solid rgba(255, 255, 255, .05);
  color: #fff;
}
.menu-links a:last-child { border-bottom: 1px solid rgba(255, 255, 255, .05); }
.menu-item-label { font-size: 24px; font-weight: 400; letter-spacing: -.03em; line-height: 1; }
.menu-item-glow {
  position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0;
  background: linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, .03) 100%);
  transition: opacity .35s cubic-bezier(.44, 0, .56, 1);
}
.menu-links a:hover .menu-item-glow, .menu-links a:focus-visible .menu-item-glow { opacity: 1; }
.menu-thumb {
  width: 95px; height: 75px; flex: none;
  border-radius: 12px; border-radius: 16px; corner-shape: superellipse(1.5);   /* live .752 fallback */
}
/* reference assets (ItemContant) */
.th-home    { background: #0b0b0b url(assets/menu-home.png)    center/cover no-repeat; }
.th-pricing { background: #0b0b0b url(assets/menu-pricing.png) center/cover no-repeat; }
.th-work    { background: #0b0b0b url(assets/menu-work.png)    center/cover no-repeat; }
.menu-socials {
  width: 100%; padding: 0 20px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;
}
.menu-socials-label { width: 100%; color: rgba(255, 255, 255, .4); font-size: 12px; letter-spacing: -.03em; line-height: 1; }
.menu-socials-list { width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.menu-socials a { color: #e2e2e2; font-size: 14px; font-weight: 500; line-height: 16px; width: fit-content; transition: color .3s; }
.menu-socials a:hover { color: #fff; }
/* the CTA only lives inside the panel on phone (live) */
.menu-cta { display: none; }

/* ===== Contact drawer — what "Get in touch" actually opens on the reference =====
   The live CTA is a `<button>` with no href: it toggles a Framer overlay holding the `Form`
   component (variants FormDesktop / FormPhone). Measured at 2000x1200:

     scrim   position:fixed; inset:0 · background rgba(0,0,0,.4) · backdrop-filter blur(10px)
     host    position:fixed; top/right/bottom 8px · width 700px · z-index above the navbar
     panel   FormContainer .framer-1svb4gq — 700x1184 · background rgb(21,21,21)
             · border-radius 24px · padding 40px · gap 40px · overflow auto
     heading 56px / 56px / -2.24px (-0.04em)
     label   14px rgba(255,255,255,.6), 10px above its control
     toggle  36px tall · radius 46px · padding 0 12px · active = white fill, text rgb(5,5,5)
             · inactive text rgb(133,133,133)
     field   wrapper 306x45 (two per row, gap 8) · rgb(33,33,33) · radius 16 · padding 0 16px
             input transparent · 16px · rgb(255,255,255)
     chips   46px tall · rgb(33,33,33) · radius 16 · padding 15px 16px · 16px · rgb(133,133,133)
             · gap 8, wrapping
     area    wrapper 620x120 rgb(33,33,33) radius 16; textarea padding 16
     submit  620x50 · white · radius 20 · corner-shape superellipse(1.7) · 18px black
     privacy 14px rgba(255,255,255,.6)

   Motion lives in the block immediately below. */
/* ===== Drawer motion — keyframes, not `linear()` easing =====
   This was first written with `transition: transform .75s linear(0, .025 6.1%, ...)`. That is a
   trap: `linear()` is recent (Chrome 113 / Safari 17.2 / Firefox 112), and when a browser does not
   understand it the WHOLE `transition` shorthand containing it is invalid and dropped — so the
   drawer snapped with no animation at all instead of degrading to a default ease. The measured
   curve is a spring (slow start, 50% at ~40% of the run, very long tail) that no single
   cubic-bezier fits, so it is expressed as keyframe stops taken straight off the reference
   samples with `animation-timing-function: linear` between them. Percentage keyframes work
   everywhere.

   Sampled on midu.design at 2000x1200, 20-45ms apart:
     open   scrim  opacity 0 -> 1 over ~320ms starting ~110ms after the click — it LEADS the panel
            panel  translateX(400px) -> 0 over ~750ms after a ~200ms delay
     close  scrim  HOLDS at opacity 1 for the whole slide, then cuts when the overlay unmounts
            panel  translateX(0) -> 400px over ~760ms after a ~50ms delay
   The panel never changes opacity on the reference — it is a pure slide.
   The exit is driven by a `.closing` class that script.js removes when the run is over, so nothing
   depends on a `visibility` transition delay landing on the right frame. */
.contact-scrim {
  position: fixed; inset: 0; z-index: 59;
  background: rgba(0, 0, 0, .4);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  opacity: 0; visibility: hidden;
}
/* while closing the scrim just holds — removing `.closing` is the hard cut the reference makes */
.contact-scrim.closing { opacity: 1; visibility: visible; }
body.contact-open .contact-scrim {
  opacity: 1; visibility: visible;
  animation: cs-in .32s linear .1s both;
}
@keyframes cs-in {
  0%     { opacity: 0; }
  2.2%   { opacity: .037; }
  24.1%  { opacity: .231; }
  31.9%  { opacity: .351; }
  41.6%  { opacity: .505; }
  51.3%  { opacity: .655; }
  60.9%  { opacity: .790; }
  70.3%  { opacity: .893; }
  80%    { opacity: .960; }
  89.7%  { opacity: .994; }
  100%   { opacity: 1; }
}
.contact-drawer {
  position: fixed; top: 8px; right: 8px; bottom: 8px; z-index: 60;
  width: min(700px, calc(100vw - 16px));
  display: flex; visibility: hidden;
  --cd-x: 400px;                       /* live travel; the phone drawer slides its full width */
  transform: translateX(var(--cd-x));
  will-change: transform;              /* keep the 700px panel on the compositor for the slide */
}
body.contact-open .contact-drawer {
  visibility: visible; transform: translateX(0);
  animation: cd-in .75s linear .2s both;
}
.contact-drawer.closing {
  visibility: visible;
  animation: cd-out .76s linear .05s both;
}
@keyframes cd-in {
  0%     { transform: translateX(calc(var(--cd-x) * 1)); }
  6.1%   { transform: translateX(calc(var(--cd-x) * .975)); }
  13.9%  { transform: translateX(calc(var(--cd-x) * .942)); }
  21.5%  { transform: translateX(calc(var(--cd-x) * .890)); }
  27.5%  { transform: translateX(calc(var(--cd-x) * .815)); }
  33.3%  { transform: translateX(calc(var(--cd-x) * .690)); }
  39.1%  { transform: translateX(calc(var(--cd-x) * .522)); }
  44.9%  { transform: translateX(calc(var(--cd-x) * .347)); }
  52.6%  { transform: translateX(calc(var(--cd-x) * .210)); }
  58.4%  { transform: translateX(calc(var(--cd-x) * .135)); }
  64.5%  { transform: translateX(calc(var(--cd-x) * .087)); }
  70.5%  { transform: translateX(calc(var(--cd-x) * .052)); }
  76.4%  { transform: translateX(calc(var(--cd-x) * .030)); }
  82.2%  { transform: translateX(calc(var(--cd-x) * .015)); }
  88.2%  { transform: translateX(calc(var(--cd-x) * .005)); }
  100%   { transform: translateX(0); }
}
@keyframes cd-out {
  0%     { transform: translateX(0); }
  7.6%   { transform: translateX(calc(var(--cd-x) * .0025)); }
  14.4%  { transform: translateX(calc(var(--cd-x) * .015)); }
  21.3%  { transform: translateX(calc(var(--cd-x) * .040)); }
  28.5%  { transform: translateX(calc(var(--cd-x) * .0825)); }
  35.7%  { transform: translateX(calc(var(--cd-x) * .1725)); }
  42.8%  { transform: translateX(calc(var(--cd-x) * .320)); }
  49.9%  { transform: translateX(calc(var(--cd-x) * .5625)); }
  57%    { transform: translateX(calc(var(--cd-x) * .7525)); }
  64.3%  { transform: translateX(calc(var(--cd-x) * .860)); }
  71.5%  { transform: translateX(calc(var(--cd-x) * .9225)); }
  78.3%  { transform: translateX(calc(var(--cd-x) * .960)); }
  85.6%  { transform: translateX(calc(var(--cd-x) * .9825)); }
  92.8%  { transform: translateX(calc(var(--cd-x) * .995)); }
  100%   { transform: translateX(calc(var(--cd-x) * 1)); }
}
.contact-panel {
  position: relative;
  flex: 1; min-width: 0; overflow: auto;
  display: flex; flex-direction: column; align-items: flex-start; gap: 40px;
  background: rgb(21, 21, 21); border-radius: 24px; padding: 40px;
  scrollbar-width: none;
}
.cf-form { width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 40px; }
.contact-panel::-webkit-scrollbar { width: 0; height: 0; }
.contact-panel h2 {
  font-size: 56px; line-height: 56px; letter-spacing: -.04em; font-weight: 500;
  max-width: 620px;
}
.cf-group { width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.cf-label { font-size: 14px; letter-spacing: -.02em; color: rgba(255, 255, 255, .6); }
/* the Project based / Retainer model switch */
.cf-switch { display: flex; gap: 0; padding: 4px; border-radius: 46px; background: rgb(33, 33, 33); }
.cf-switch button {
  height: 36px; padding: 0 12px; border-radius: 46px;
  font-size: 14px; font-weight: 500; letter-spacing: -.02em;
  color: rgb(133, 133, 133); background: rgba(255, 255, 255, 0);
  transition: background .35s cubic-bezier(.44, 0, .56, 1), color .35s cubic-bezier(.44, 0, .56, 1);
}
.cf-switch button[aria-selected="true"] { background: #fff; color: rgb(5, 5, 5); }
/* text fields */
.cf-row { width: 100%; display: flex; gap: 8px; }
.cf-field {
  flex: 1 1 0; min-width: 0; height: 45px;
  display: flex; align-items: center; padding: 0 16px;
  background: rgb(33, 33, 33); border-radius: 16px;
}
.cf-field input, .cf-area textarea {
  width: 100%; background: none; border: 0; color: #fff;
  font: inherit; font-size: 16px; letter-spacing: -.02em;
}
.cf-field input::placeholder, .cf-area textarea::placeholder { color: rgb(133, 133, 133); }
.cf-field input:focus, .cf-area textarea:focus { outline: none; }
.cf-area { width: 100%; background: rgb(33, 33, 33); border-radius: 16px; }
.cf-area textarea { display: block; height: 120px; padding: 16px; resize: none; line-height: 1.4; }
/* the multiple-choice chips */
.cf-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.cf-chips button {
  padding: 15px 16px; border-radius: 16px;
  background: rgb(33, 33, 33); color: rgb(133, 133, 133);
  font-size: 16px; letter-spacing: -.02em; line-height: 1;
  transition: background .35s cubic-bezier(.44, 0, .56, 1), color .35s cubic-bezier(.44, 0, .56, 1);
}
/* the reference ships with nothing selected, so the selected treatment follows the switch's
   active state (white fill, near-black text) rather than being observed */
.cf-chips button[aria-pressed="true"] { background: #fff; color: rgb(5, 5, 5); }
.cf-submit {
  width: 100%; height: 50px; display: flex; align-items: center; justify-content: center;
  background: #fff; color: #000; font-size: 18px; font-weight: 500; letter-spacing: -.02em;
  border-radius: 17.8px; border-radius: 20px; corner-shape: superellipse(1.7);
  transition: background .35s cubic-bezier(.44, 0, .56, 1), opacity .3s;
}
.cf-submit:hover { background: rgb(230, 230, 230); }
.cf-submit[disabled] { opacity: .6; }
/* the status line is not in the reference at all — collapse it when empty so it does not add a
   phantom 40px gap between Submit and the privacy note */
.cf-status:empty { display: none; }
/* live: Submit ends at y822 and the privacy note starts at y834, i.e. 12px, not the 40px the
   container's own gap would give */
.cf-privacy { width: 100%; margin-top: -28px; font-size: 14px; letter-spacing: -.02em; color: rgba(255, 255, 255, .6); }
.cf-privacy a { color: inherit; text-decoration: underline; }
.cf-close {
  position: absolute; top: 24px; right: 24px; z-index: 1;
  width: 36px; height: 36px; display: grid; place-items: center;
  border-radius: 50%; background: rgb(33, 33, 33); color: #fff;
  transition: background .3s;
}
.cf-close:hover { background: rgb(48, 48, 48); }
.cf-status { width: 100%; font-size: 14px; letter-spacing: -.02em; color: rgba(255, 255, 255, .6); }
.cf-status.err { color: rgb(254, 75, 66); }
.cf-field.invalid { outline: 1px solid rgb(254, 75, 66); }
/* live FormPhone: the drawer takes the full width inside the same 8px inset */
@media (max-width: 809px) {
  .contact-drawer { width: calc(100vw - 16px); transform: translateX(100%); }
  .contact-panel { padding: 24px; gap: 28px; }
  .contact-panel h2 { font-size: 34px; line-height: 34px; }
  .cf-row { flex-direction: column; }
  .cf-close { top: 16px; right: 16px; }
}

/* ===== Giant wordmark ===== */
.giant-wordmark { overflow: hidden; user-select: none; position: relative; }
.giant-wordmark span {
  display: block;
  font-weight: 700; letter-spacing: -.06em;
  line-height: .74; text-align: center; white-space: nowrap;
  padding-right: .06em;
}

/* Hero — the live structure. The shader iframe fills the whole hero (z-0,
   unmasked). The wordmark is a separate layer above it: just the tint gradient,
   masked to the MIDU letters (luminance) and stamped onto the bright wave with
   mix-blend-mode: darken — exactly the declarations from the live CSS. */
.hero-shader { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.hero-shader iframe { display: block; width: 100%; height: 100%; border: 0; }
/* in-flow hero content paints above the positioned shader layer */
.hero > :not(.hero-shader) { position: relative; }

/* both letter layers live in one aspect box pinned above the hero's bottom pad */
/* live at 2000x1200: MiduLogoMain 1920x583 @40,677 and HeroMetaBar @40,622 — a 55px gap, and
   the wordmark runs 60px past the hero's bottom edge (the hero clips it). */
.hero-foot { margin-top: auto; margin-bottom: -60px; }   /* wordmark overhangs, hero clips it */
.hero-mark-stack {
  position: relative;
  width: 100%; aspect-ratio: 3.29298; height: auto;
  margin-top: 40px;                    /* 15px meta row + 40 = the live 55px gap */
}
/* MiduLogoMain — the subtle darkening stamp (live declarations) */
.hero-wordmark {
  position: absolute; inset: 0;
  background: linear-gradient(#8f8f8f00 0%, #b07d7d54 100%);
  mix-blend-mode: darken;
  -webkit-mask: url("assets/home/midu-mask.svg") 50% / cover no-repeat;
  -webkit-mask-source-type: luminance;
  mask: url("assets/home/midu-mask.svg") 50% / cover no-repeat luminance;
}

/* HeroLogoBlend — the color-dodge wrapper that makes the letters glow where the
   wave is bright (live: absolute bottom 20 / sides 40, z-1, color-dodge; inner
   layer masked to the letters with a radial #fff0 -> #d9b6b6 fill + darken) */
.hero-logo-blend {
  position: absolute; inset: 0; z-index: 1;
  mix-blend-mode: color-dodge;
  pointer-events: none;
  animation: rise80 1s cubic-bezier(.11, .06, .18, 1) .75s both;
}
.hero-logo-blend-fill {
  width: 100%; height: 100%;
  background: radial-gradient(56% 156% at 47.1% 1.9%, #fff0 0%, #d9b6b6 100%);
  mix-blend-mode: darken;
  -webkit-mask: url("assets/home/midu-mask.svg") 50% / cover no-repeat;
  -webkit-mask-source-type: luminance;
  mask: url("assets/home/midu-mask.svg") 50% / cover no-repeat luminance;
}

/* intro — the exact appear specs from the live site's animation JSON:
   wordmark y80 @.75s, meta y60 @.9s, tagline y40 @1.05s, nav y40 @1.15s,
   all 1s tweens on cubic-bezier(.11,.06,.18,1) */
.hero-wordmark { animation: rise80 1s cubic-bezier(.11, .06, .18, 1) .75s both; }
.hero-meta     { animation: rise60 1s cubic-bezier(.11, .06, .18, 1) .9s both; }
.hero-tagline  { animation: rise40 1s cubic-bezier(.11, .06, .18, 1) 1.05s both; }
.nav           { animation: rise40 1s cubic-bezier(.11, .06, .18, 1) 1.15s both; }
@keyframes rise80 { from { opacity: .001; transform: translateY(80px); } to { opacity: 1; transform: none; } }
@keyframes rise60 { from { opacity: .001; transform: translateY(60px); } to { opacity: 1; transform: none; } }
@keyframes rise40 { from { opacity: .001; transform: translateY(40px); } to { opacity: 1; transform: none; } }
@keyframes rise70 { from { opacity: .001; transform: translateY(70px); } to { opacity: 1; transform: none; } }

.footer-wordmark { height: 18.5vw; margin-top: 48px; }
.footer-wordmark span {
  /* THE ONE STYLING VALUE CHANGED BY THE CONTENT PASS, and only because the name got longer.
     "MIDU" is 4 glyphs and measured 1713px inside the 1920px box at 37vw. "HOSNY" is 5 and
     measures 2410px at the same size — a 490px overflow, so the Y was cut off. Measured fit is
     29.5vw at 2000px, 29vw at 1440 and 27.6vw at 390 (the box padding is fixed, so the ratio
     shifts); 27vw is the one value that fits every canvas, and it lands at a 92% fill against
     MIDU's original 89% — so the wordmark reads at the same density as before.
     Revert to 37vw the moment a real logo asset replaces this text wordmark. */
  font-size: 27vw;
  /* item 22: the reference reads dark maroon at the top and lights up toward the bottom —
     the previous gradient ran the other way (bright red on top) and was uniformly hot. */
  background:
    radial-gradient(120% 85% at 50% 118%, #ff5a3c 0%, #e02a12 26%, #8d1109 52%, #3a0806 74%, #1c0403 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ===== Progressive liquid-glass blur (live recipe: 8 layers, halving radii,
   12.5%-step masks) ===== */
.bottom-blur { position: fixed; inset: auto 0 0 0; z-index: 30; height: 150px; pointer-events: none; }
.bottom-blur i { position: absolute; inset: 0; display: block; }
.bottom-blur i:nth-child(1) { backdrop-filter: blur(0.13671875px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 0%, #000 12.5%, #000 25%, #0000 37.5%); mask-image: linear-gradient(to bottom, #0000 0%, #000 12.5%, #000 25%, #0000 37.5%); }
.bottom-blur i:nth-child(2) { backdrop-filter: blur(0.2734375px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 12.5%, #000 25%, #000 37.5%, #0000 50%); mask-image: linear-gradient(to bottom, #0000 12.5%, #000 25%, #000 37.5%, #0000 50%); }
.bottom-blur i:nth-child(3) { backdrop-filter: blur(0.546875px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 25%, #000 37.5%, #000 50%, #0000 62.5%); mask-image: linear-gradient(to bottom, #0000 25%, #000 37.5%, #000 50%, #0000 62.5%); }
.bottom-blur i:nth-child(4) { backdrop-filter: blur(1.09375px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 37.5%, #000 50%, #000 62.5%, #0000 75%); mask-image: linear-gradient(to bottom, #0000 37.5%, #000 50%, #000 62.5%, #0000 75%); }
.bottom-blur i:nth-child(5) { backdrop-filter: blur(2.1875px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 50%, #000 62.5%, #000 75%, #0000 87.5%); mask-image: linear-gradient(to bottom, #0000 50%, #000 62.5%, #000 75%, #0000 87.5%); }
.bottom-blur i:nth-child(6) { backdrop-filter: blur(4.375px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 62.5%, #000 75%, #000 87.5%, #0000 100%); mask-image: linear-gradient(to bottom, #0000 62.5%, #000 75%, #000 87.5%, #0000 100%); }
.bottom-blur i:nth-child(7) { backdrop-filter: blur(8.75px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 75%, #000 87.5%, #000 100%); mask-image: linear-gradient(to bottom, #0000 75%, #000 87.5%, #000 100%); }
.bottom-blur i:nth-child(8) { backdrop-filter: blur(17.5px);
  -webkit-mask-image: linear-gradient(to bottom, #0000 87.5%, #000 100%); mask-image: linear-gradient(to bottom, #0000 87.5%, #000 100%); }

/* ===== Hero (live: 100vh, padding 160px 40px 20px, pinned; page scrolls over) ===== */
.hero {
  position: sticky; top: 0; z-index: 0;
  height: 100svh; overflow: hidden;
  display: flex; flex-direction: column;
  padding: 160px var(--pad-x) 0;      /* live: the wordmark runs to the hero's bottom edge */
  background: var(--bg);
}
.hero > * { flex: none; }
.page-body { position: relative; z-index: 1; background: var(--bg); }
.footer { position: relative; z-index: 1; background: var(--bg); }

/* Hero intro — live at 2000px: HeroIntroContent is a 955px centred 3-column grid
   (290 / 1fr / 290) starting 160px below the hero top; the tagline sits in the RIGHT column
   at +40px and is 358px wide, so it overhangs that column to the right.
   Type: 32px / 35.2px / -0.64px / 500 Switzer Medium (was 26px / 1.25). */
/* the hero's own 160px padding-top already places this block at the live y=160 */
.hero-intro {
  width: 100%; max-width: var(--w-tools); margin: 0 auto;
  display: grid; grid-template-columns: 290px 1fr 290px;
}
.hero-tagline {
  grid-column: 3; width: 358px; max-width: none; transform: translateY(40px);
  font-size: 32px; font-weight: 500; letter-spacing: -.02em; line-height: 1.1;
}
/* live HeroMetaBar: one 15px row — StudioTagline + AvailabilityStatus grouped LEFT (x40 / x251),
   ScrollPrompt pinned RIGHT. Not space-between across the full width. */
.hero-meta {
  display: flex; align-items: center; gap: 40px;
  color: var(--dim-60); font-size: 14px; line-height: 1.1; letter-spacing: -.02em;
}
.hero-meta-left { display: flex; align-items: center; gap: 40px; }
.hero-clock { display: flex; align-items: center; gap: 4px; color: #ddd; }
.hero-scroll {
  margin-left: auto; display: flex; align-items: center; gap: 8px;
  color: var(--dim-40); letter-spacing: normal;
}

/* ===== Section headings (live: 82px / 500 / -0.04em / lh 1 / max-w 900) ===== */
.section-title {
  font-size: var(--fs-heading); font-weight: 500; letter-spacing: -.04em; line-height: 1;
  max-width: var(--w-heading); margin: 0 auto;
  text-indent: 1.3em;
}
.section-title .w { color: #fff; }
.section-title .g { color: var(--dim-60); }

/* ===== Statement + About (live: section pad 240 top, gaps 120/200) ===== */
.statement { padding: 240px var(--pad-x) 0; }
.statement h1 {
  font-size: var(--fs-heading); font-weight: 500; letter-spacing: -.04em; line-height: 1;
  max-width: var(--w-heading); margin: 0 auto;
  text-indent: 1.5em;
}

.about { padding: 120px var(--pad-x) 0; }
.about-grid {
  max-width: var(--w-heading); margin: 0 auto;
  display: grid; grid-template-columns: 1.5fr 1fr;
  column-gap: var(--about-gap);
}
.about-main { font-size: var(--fs-body-lg); font-weight: 500; letter-spacing: -.04em; line-height: 1.3; }
.about-main strong { font-weight: 500; }
.about-side { font-size: 16px; line-height: 1.4; letter-spacing: -.02em; }
.about > .btn { margin: 80px 0 0 max(calc((100% - var(--w-heading)) / 2), 0px); }

/* Showcase — live AboutBrandImage. The 1728x1144 previously recorded here was the image at
   its *start* scale, not its final size: the live element is `width:100%` inside a wrapper with
   `padding: 0 40px` (so 1920 at a 2000px viewport) with `aspect-ratio: 1.51111`, and it carries a
   scroll-linked style transform:
     __framer__transformTargets [{scale:.9, y:-80} -> {scale:1, y:0}]
     __framer__transformTrigger  'onScrollTarget'   viewportThreshold .5
   The scroll target is a marker div named `trigger-full-image-scroll` (1015px tall, 217px above
   the image's layout top). Measured on the live page at 2000x1200 the mapping is exactly LINEAR
   in the marker's own travel, with no easing:
     progress = clamp01((0.5 * vh - markerTop) / markerHeight)
   (markerTop 590 -> .011 -> scale .9011 · 90 -> .5025 -> .9503 · -410 -> ~1. Verified against
   23 sampled scroll positions.) `--sc` is driven by script.js. */
/* the live AboutImageWrapper has padding 0 40px and sits in an unpadded section; here the
   section already supplies --pad-x (40 desktop / 20 phone), so adding it again shrank the
   image to 1840 instead of the reference 1920. */
.showcase { position: relative; margin-top: 200px; }
/* the live scroll target: same height and same offset from the image, so the mapping matches
   regardless of how the prose above it wraps */
.showcase-trigger { position: absolute; left: 0; right: 0; top: -217px; height: 1015px; pointer-events: none; }
.showcase-art {
  position: relative; overflow: hidden;
  border-radius: 28.5px; border-radius: 32px; corner-shape: superellipse(1.2);   /* live */
  width: 100%; margin: 0 auto;
  aspect-ratio: 1.51111;                         /* live */
  background: url(assets/home/showcase-monitor.webp) center/cover no-repeat;
  display: grid; place-items: center;
  /* live: linear in scroll progress, so no transition — the value itself is the animation */
  transform: translateY(calc(-80px * (1 - var(--sc, 0)))) scale(calc(.9 + .1 * var(--sc, 0)));
}
.ph-label {
  position: absolute; bottom: 14px; left: 18px;
  font-size: 12px; color: #ffffff66; letter-spacing: .04em;
}

/* ===== Highlights (live: padding 240px 40px, gap 120, grid gap 20) ===== */
.highlights { padding: 240px var(--grid-pad); padding-bottom: 0; }
.highlights-intro {
  max-width: var(--w-heading);
  display: grid; grid-template-columns: 1.5fr 1fr;
  column-gap: var(--about-gap);
  margin: 120px auto 0;
  font-size: var(--fs-body-lg); font-weight: 500; letter-spacing: -.04em; line-height: 1.3;
}
.highlights-intro strong { font-weight: 500; color: var(--dim-60); }
.highlights-intro p:first-child { color: var(--dim-60); }
.highlights-intro p:first-child strong { color: #fff; }
.highlights-intro .dim { font-size: 16px; letter-spacing: -.02em; }

.project-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 120px; }
.project-card {
  position: relative; overflow: hidden;
  /* live: corner-shape superellipse(1.2) with a 24px radius; browsers without corner-shape
     get the same .892 fallback ratio the reference ships (24 x .892 = 21.4px) */
  border-radius: 21.4px; border-radius: 24px; corner-shape: superellipse(1.2);
  aspect-ratio: 830 / 841;                       /* live card at 2000px: 830x841 */
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 24px 24px 30px 40px;                  /* live padding */
  background: #131313;
}
/* live ProjectCard hover (recorded from the component's own variants, transition
   {delay:.1, duration:.7, ease:[.65,0,.32,1]}):
     art       base scale 1.08  ->  1     on the 2-tags / 3-tags variants
                               ->  1.04  on the 1-tag variant
     badge     40x40 white r16 superellipse(1.7) at bottom 24 / right 24
               scale 0, shadow none  ->  scale 1, shadow 0 2px 12px rgba(0,0,0,.1),
               corner-shape superellipse(1.2)
     its glyph the live 10x10 X asset, rotate 0 -> 135deg (an X at 135deg reads as a plus) */
.project-art {
  position: absolute; inset: 0; z-index: 0; display: grid; place-items: center;
  transform: scale(1.08);
  transition: transform .7s cubic-bezier(.65, 0, .32, 1) .1s;
}
.project-card:hover .project-art { transform: scale(1); }
/* Nova and Pawradise carry a single tag — the live 1-tag variant settles at 1.04, not 1 */
.p-nova:hover .project-art, .p-pawradise:hover .project-art { transform: scale(1.04); }
.card-badge {
  position: absolute; z-index: 1; bottom: 24px; right: 24px;
  width: 40px; height: 40px; display: grid; place-items: center;
  background: #fff;
  border-radius: 10.7px; border-radius: 16px; corner-shape: superellipse(1.7);  /* live .671 fallback */
  box-shadow: none; transform: scale(0);
  transition:
    transform    .7s cubic-bezier(.65, 0, .32, 1) .1s,
    box-shadow   .7s cubic-bezier(.65, 0, .32, 1) .1s,
    corner-shape .7s cubic-bezier(.65, 0, .32, 1) .1s;
}
.card-badge img { width: 10px; height: 10px; display: block; transition: transform .7s cubic-bezier(.65, 0, .32, 1) .1s; }
.project-card:hover .card-badge {
  transform: scale(1);
  border-radius: 14.3px; border-radius: 16px; corner-shape: superellipse(1.2);   /* live .892 fallback */
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
}
.project-card:hover .card-badge img { transform: rotate(135deg); }
/* live: Fixa and Kiwe cards layer a phone render over the card art (the "3-tag-phone" layer) */
.pa-phone { display: block; width: 62%; height: auto; max-height: 78%; object-fit: contain; }
/* controlled SVG glyphs, so arrows/sun/spark render identically on every OS (was emoji) */
.ic { width: 1em; height: 1em; flex: none; vertical-align: -.08em; }
.ic-sun { width: 14px; height: 14px; flex: none; }
.ic-arrow-down { width: 10px; height: 10px; flex: none; }
/* item 12: the card-art scale, tag lift and arrow rotation were invented, not observed on the
   reference, so they are gone. The title -> CTA slide IS in the reference and stays. */
.card-link { position: absolute; inset: 0; z-index: 2; }
.project-art .ph-label { left: 50%; right: auto; bottom: 84px; top: auto; transform: translateX(-50%); opacity: .45; white-space: nowrap; }
.project-tags, .project-meta { position: relative; z-index: 1; }
.project-tags { display: flex; gap: 12px; justify-content: flex-end; flex-wrap: wrap; }
.project-tags span {
  background: #ffffffd9; color: #222; backdrop-filter: blur(8px);
  font-size: 14px; padding: 9px 16px; border-radius: 999px;
  transition: transform .5s var(--ease), background .4s;
}

.dark-tags span { background: #adadad66; color: #fff; }
.project-card:hover .dark-tags span { background: #c9c9c98c; }

/* live hover: the title slides away inside a clipped 35px box, the CTA slides in */
.meta-slide { height: 35px; overflow: hidden; }
.meta-slide > div {
  display: flex; flex-direction: column; gap: 40px;   /* live gap 40 */
  transition: transform .6s var(--ease);
}
.project-card:hover .meta-slide > div { transform: translateY(-75px); }  /* 35 + 40 */
.meta-slide .t1 {
  font-size: clamp(22px, 2.1vw, 28px); font-weight: 500; letter-spacing: -.02em; line-height: 35px;
  white-space: nowrap;
}
.meta-slide .t2 {
  font-size: 14px; font-weight: 500; letter-spacing: -.03em; line-height: 35px;
  color: #ffffffcc;
}
.project-meta p { color: #ffffff99; font-size: 14px; margin-top: 8px; letter-spacing: -.02em; }
.p-kiwe .meta-slide .t1, .p-nova .meta-slide .t1 { color: #111; }
.p-kiwe .meta-slide .t2, .p-nova .meta-slide .t2 { color: #333; }
.p-kiwe .project-meta p, .p-nova .project-meta p { color: #00000080; }

/* placeholder art */
.p-fixa .project-art { background: #0f0d0c url(assets/home/proj-fixa.webp) center/cover no-repeat; }
.p-kiwe .project-art { background: #e3e3e6 url(assets/home/proj-kiwe.webp) center/cover no-repeat; }
.kiwe-card {
  width: clamp(120px, 13vw, 170px); aspect-ratio: 0.63;
  border-radius: 14px;
  background: linear-gradient(215deg, #4e7fe0 0%, #2b3f9e 55%, #1b2560 100%);
  color: #fff; font-weight: 700; font-size: 22px;
  display: grid; place-items: end center; padding-bottom: 18px;
  writing-mode: vertical-rl;
  box-shadow: 0 30px 60px #00000030;
}
.p-nova .project-art { background: #efe0b6 url(assets/home/proj-nova.webp) center/cover no-repeat; }
.nova-phone {
  width: clamp(150px, 15vw, 210px); aspect-ratio: 0.49;
  border-radius: 28px; background: #161616; border: 5px solid #3c3c40;
  box-shadow: 0 40px 80px #00000038;
  display: flex; flex-direction: column; gap: 14px; align-items: center; justify-content: center;
  rotate: 8deg;
}
.nova-phone b { background: #ff6a48; color: #fff; border-radius: 12px; padding: 14px 18px; font-size: 17px; font-weight: 600; }
.nova-phone b i { font-style: normal; opacity: .6; font-size: 12px; }
.nova-phone span { color: #eee; font-size: 13px; }
.p-pawradise .project-art { background: #48633a url(assets/home/proj-pawradise.webp) center/cover no-repeat; }
.paw-phone {
  width: clamp(140px, 14vw, 200px); aspect-ratio: 0.49;
  border-radius: 28px; background: #f4f4f2; border: 5px solid #2c2c2e;
  box-shadow: 0 40px 80px #00000045;
  display: grid; place-items: center;
  color: #111; font-size: 15px; font-weight: 600; text-align: left; padding: 16px;
}

/* ===== Trust (live: heading gap 200, cards max-w 1200, gap 20, radius 32) ===== */
.trust { padding: 240px var(--pad-x); padding-bottom: 240px; }
.trust-grid {
  display: grid; grid-template-columns: minmax(280px, 360px) 1fr; gap: 20px;
  max-width: 1200px; margin: 200px auto 0;
}
.trust-card, .testimonial-card {
  background: #121212; border: 1px solid var(--line); border-radius: 32px;
  padding: 30px; min-height: 340px;
}
.trust-card { display: flex; flex-direction: column; justify-content: space-between; gap: 30px; }
.trust-quotemark { font-size: 118px; font-weight: 700; line-height: .62; color: #2c2c2c; }
.trust-card h3 { font-size: 32px; font-weight: 500; letter-spacing: -.02em; }
.trust-card p { margin-top: 8px; font-size: 14.5px; }

.testimonial-card { position: relative; display: flex; flex-direction: column; gap: 24px; cursor: none; overflow: hidden; }
/* live cursor placement is `bottom` / alignment `start` with offset {x:25, y:-14}, so the pill
   hangs off the pointer's lower-right rather than being centred on it — script.js applies the
   offset, so no centring translate here. Scale .6 -> 1 is the inactive -> active variant. */
.next-pill {
  position: absolute; z-index: 3; top: 0; left: 0;
  pointer-events: none; white-space: nowrap;
  background: #3a3a3ad9; color: #fff; backdrop-filter: blur(8px);
  font-size: 14px; font-weight: 500; padding: 10px 18px; border-radius: 999px;
  opacity: 0; transform: scale(.6); transform-origin: 0 0;
  transition: opacity .3s var(--ease), transform .35s var(--ease);
}
.testimonial-card:hover .next-pill { opacity: 1; transform: scale(1); }
.testimonial-dots { display: flex; gap: 8px; }
.testimonial-dots button { width: 7px; height: 7px; border-radius: 50%; background: #3a3a3a; transition: background .3s, transform .35s var(--ease); padding: 0; }
.testimonial-dots button:hover { background: #7a7a7a; transform: scale(1.4); }
.testimonial-dots button.active { background: #fff; transform: scale(1.25); }

/* horizontal slider, like the live 500%-wide track */
.testimonial-viewport { flex: 1; overflow: hidden; }
/* no CSS transitions exist in the original — motion is JS springs; this curve
   approximates that long, soft settle instead of a quick snap */
/* transition is set per move by script.js so the invisible wrap can turn it off (item 14) */
.testimonial-track { display: flex; height: 100%; transition: transform var(--m-slide); }
.testimonial-slide {
  flex: none; width: 100%; padding-right: 10px;
  display: flex; flex-direction: column; justify-content: space-between; gap: 32px;
}
.testimonial-quote { font-size: clamp(19px, 1.5vw, 30px); font-weight: 500; letter-spacing: -.04em; line-height: 1.3; color: var(--dim-50); }
.testimonial-quote em { font-style: normal; color: #fff; }
.testimonial-foot { display: flex; justify-content: space-between; align-items: flex-end; }
.testimonial-person { display: flex; gap: 12px; align-items: center; }
.testimonial-avatar { object-fit: cover;
  width: 46px; height: 46px; border-radius: 10px;
  background: radial-gradient(120% 120% at 30% 25%, #8a7361 0%, #4e3d31 55%, #241b14 100%);
}
.testimonial-person b { font-weight: 600; display: block; font-size: 15px; }
.testimonial-person span { color: var(--dim-50); font-size: 14px; }
.testimonial-brand { max-height: 24px; width: auto; object-fit: contain; font-size: 24px; font-weight: 700; letter-spacing: -.02em; color: #fff; }

/* ===== Tools (live: bg #e6e6e6, radius 24, padding 200/40/240, blocks max-w 785) ===== */
.tools {
  background: var(--light); color: #030303;
  border-radius: 24px;
  margin-top: 0;
  padding: 200px var(--pad-x) 240px;
}
.tools-head { max-width: var(--w-tools); margin: 0 auto; }
.tools-title { font-size: var(--fs-heading); font-weight: 500; letter-spacing: -.04em; line-height: 1; }
.tools-title-right { text-align: right; }
/* ticker row is exactly the head-block width (live: 785 / 955 @1920), edge fade mask */
.tools-marquee {
  overflow: hidden; margin: 25px 0;
  padding: 8px 0 46px;   /* room for the hover grow + name tag */
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
/* live Ticker props: gap 0px, velocity 60px/s, hoverModifier 100 (hover does not slow it).
   With gap 0 a 20-tile track is exactly two 10-tile sets, so translateX(-50%) loops seamlessly —
   any gap here leaves half a gap of jump at the wrap. 10 x 80px / 60px per s = 13.333s. */
/* fixed row height so a growing tile cannot change the track's height mid-loop */
.tools-track { display: flex; align-items: center; gap: 0; height: 100px; width: max-content; animation: marquee 13.333s linear infinite; }
@keyframes marquee { to { transform: translateX(-50%); } }
/* live component `MacosIcon` — three size variants, not a scale, and it is a DOCK: the hovered
   tile goes to `l` and BOTH its neighbours go to `m` (verified live: 80 90 100 90 80 ...).
     s  80x80   (default)      m  90x90        l  100x100
   The icon itself is `position:absolute; inset:10px` inside the tile, radius 18px
   corner-shape superellipse(1.2), box-shadow 0 8px 13px rgba(0,0,0,0) -> rgba(0,0,0,.1) on `l`.
   The name tag sits *behind* the icon at bottom:10px and slides out to bottom:-17px, going
   opacity 0 -> 1 and scale .9 -> 1, with fill rgba(255,255,255,.6), radius 10px
   superellipse(1.7), padding 4px 7px 4px 8px, Switzer Regular 12px rgba(0,0,0,.6).
   One transition for the whole component: {duration:.35, ease:[.12,.23,.5,1]}. */
.tool-chip {
  position: relative; flex: none;
  width: 80px; height: 80px;
  transition: width .35s cubic-bezier(.12, .23, .5, 1), height .35s cubic-bezier(.12, .23, .5, 1);
}
.tool-chip.is-m { width: 90px; height: 90px; }
.tool-chip.is-l { width: 100px; height: 100px; }
/* sized off the tile rather than with `inset: 10px`: for an absolutely-positioned *replaced*
   element the insets do not resolve `width: auto` — the intrinsic size wins — so the icon was
   filling the whole tile. calc() keeps the live 10px inset at every variant (60 / 70 / 80). */
.tool-chip > img {
  position: absolute; top: 10px; left: 10px; z-index: 1;
  width: calc(100% - 20px); height: calc(100% - 20px); object-fit: cover; display: block;
  border-radius: 16.1px; border-radius: 18px; corner-shape: superellipse(1.2);   /* live .892 fallback */
  box-shadow: 0 8px 13px 0 rgba(0, 0, 0, 0);
  transition: box-shadow .35s cubic-bezier(.12, .23, .5, 1);
}
.tool-chip.is-l > img { box-shadow: 0 8px 13px 0 rgba(0, 0, 0, .1); }
.tool-chip::after {
  content: attr(data-name);
  position: absolute; bottom: 10px; left: 50%;
  transform: translateX(-50%) scale(.9);
  background: rgba(255, 255, 255, .6); color: rgba(0, 0, 0, .6);
  font-size: 12px; font-weight: 400; letter-spacing: -.03em; line-height: 1.1;
  padding: 4px 7px 4px 8px;
  border-radius: 6.7px; border-radius: 10px; corner-shape: superellipse(1.7);    /* live .671 fallback */
  white-space: nowrap; opacity: 0; pointer-events: none;
  transition:
    bottom    .35s cubic-bezier(.12, .23, .5, 1),
    opacity   .35s cubic-bezier(.12, .23, .5, 1),
    transform .35s cubic-bezier(.12, .23, .5, 1);
}
.tool-chip.is-l::after { bottom: -17px; opacity: 1; transform: translateX(-50%) scale(1); }
.tools-desc { max-width: var(--w-tools); margin: 80px auto 0; padding-left: 40px; }
.tools-desc p { max-width: 320px; color: #55555599; color: rgba(3,3,3,.55); font-size: 16px; letter-spacing: -.01em; }
.tools-desc .btn { margin-top: 32px; }

/* service cards (live: card 373px wide, padding 45px 40px, gap 30) */
.service-grid {
  max-width: var(--w-tools); margin: 80px auto 0;
  display: flex; gap: 40px;                /* live: ServicesListContainer gap 40 */
}
.svc-col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 40px; }
.svc-col-left { padding-top: 80px; }       /* live: ServicesListLeft padding 80 0 0 */
.service-card {
  position: relative; background: #fff; border-radius: 36px;   /* live: 36px superellipse */
  padding: 45px 40px 70px;
  box-shadow: 0 24px 60px #00000012;
  transition: transform .6s var(--ease), box-shadow .6s;
}
.service-card:hover { box-shadow: 0 44px 80px #00000024; }   /* item 12: no invented lift/scale */
.service-card h3 { font-size: 30px; line-height: 1.1; font-weight: 600; letter-spacing: -.04em; transition: transform .5s var(--ease); }  /* live: 30/33/-1.2px/600 */
.service-card:hover h3 { transform: translateX(4px); }
.service-card hr { border: 0; border-top: 1px solid #00000014; margin: 24px 0; transition: border-color .4s; }
.service-card:hover hr { border-top-color: #00000026; }
.svc-label { color: #9a9a9a; font-size: 14px; margin-bottom: 8px; }
.service-card > p:last-of-type { color: #333; font-size: 16px; line-height: 1.4; }
.svc-arrow {
  position: absolute; right: 22px; bottom: 22px;
  width: 40px; height: 40px; border-radius: 12px;
  background: #ededed; display: grid; place-items: center;
  font-size: 17px; transition: background .3s, transform .4s var(--ease);
}
.service-card:hover .svc-arrow { background: #0a0a0a; color: #fff; }   /* item 12: no rotation */

/* ===== FAQ (live: block max-w 900, heading 32px, item pad 24x28, q 18px,
   cols gap 20, items gap 12, chevron 32x22) ===== */
/* The top padding was 0 because on the reference the FAQ is the tail of the pricing block
   (`PricingFaq`) and leaned on that section's 240px bottom padding. With pricing removed (§9.11)
   the FAQ butted straight against the light Tools panel — whose own bottom padding sits *inside*
   its rounded background, so it contributes no gap. 240px is the site's standard section top
   padding (`.statement`, `.highlights`, `.trust`, and the removed `.pricing` all used it), so this
   restores exactly the spacing that was there before the section went. */
.faq { padding: 240px var(--pad-x); }
.faq > * { max-width: var(--w-col); margin-left: auto; margin-right: auto; }
.faq-title { font-size: 32px; font-weight: 500; letter-spacing: -.03em; }
.faq-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 20px; align-items: start; margin-top: 40px; }
.faq-col { display: flex; flex-direction: column; gap: 12px; }
.faq-item {
  background: var(--item-glass);
  border-radius: 14.3px; border-radius: 16px; corner-shape: superellipse(1.2);
  overflow: hidden;
  transition: background var(--m-faq);
}
.faq-item:hover { background: #ffffff12; }
/* item 20: one surface grows — no separate panel tint for the answer */
.faq-item.open { background: var(--item-glass); }
.faq-q {
  width: 100%; display: flex; justify-content: space-between; align-items: center; gap: 24px;
  text-align: left; padding: 24px 28px;
  font-size: 18px; font-weight: 500; letter-spacing: -.02em; line-height: 1.3;
}
.faq-chevron {
  flex: none; width: 32px; height: 22px; border-radius: 8px;
  background: #ffffff0f; display: grid; place-items: center;
  transition: transform var(--m-faq), background var(--m-faq);
}
.faq-item:hover .faq-chevron { background: #ffffff1f; }
.faq-item.open .faq-chevron { transform: rotate(180deg); background: #fff; color: #111; }
.faq-a {
  max-height: 0; overflow: hidden; background: none;
  transition: max-height var(--m-faq);
}
.faq-a p { padding: 0 28px 24px; color: var(--dim-60); font-size: 15.5px; line-height: 1.45; }

/* ===== Footer ===== */
.footer { padding: 160px var(--pad-x) 0; overflow: hidden; }
.footer-top {
  display: grid; grid-template-columns: 1fr auto auto; gap: 60px clamp(60px, 10vw, 180px);
  align-items: start;
}
.footer-clock { font-size: 14px; }
.footer-tagline { font-size: clamp(20px, 1.9vw, 24px); font-weight: 500; letter-spacing: -.03em; line-height: 1.3; margin: 20px 0 48px; }
.footer-col { display: flex; flex-direction: column; gap: 10px; font-size: 16px; }
.footer-col p { font-size: 14px; margin-bottom: 8px; }
.footer-col a { color: #ddd; transition: color .3s; }
.footer-col a:hover { color: #fff; }
.footer-legal {
  display: flex; justify-content: space-between;
  margin-top: clamp(80px, 10vh, 140px);
  font-size: 12.5px; letter-spacing: .05em; text-transform: uppercase;
}
.footer-legal-links { text-align: right; }
.footer-legal a { transition: color .3s; }
.footer-legal a:hover { color: #fff; }

/* ===== Reveal animations =====
   The live in-view reveal, extracted verbatim from page-components.mjs:
     initial    { opacity: 0, y: 20 }                       (SSR inline style on every
                                                             will-change:transform element)
     transition { delay: .15, duration: .85, ease: [.56, .09, .38, .9], type: "tween" }
   Elements that deviate use their own y/delay (see the phone-assembly rules in the Build
   section). Blur is words-only. ===== */
.reveal {
  opacity: 0; transform: translateY(20px);
  transition: opacity var(--m-reveal), transform var(--m-reveal);
  transition-delay: var(--d, 0s);
}
/* the how-we-work bundle uses a different reveal curve and a .15s lead-in than the home one */
.process-page .reveal, .case-page .reveal {
  transition:
    opacity   .85s cubic-bezier(.56, .09, .38, .9),
    transform .85s cubic-bezier(.56, .09, .38, .9);
  transition-delay: var(--d, .15s);
}
.reveal.in { opacity: 1; transform: none; }
/* set by script.js once the reveal has finished; carries the end state without holding a
   transition that would override the component's own hover timing (item 27) */
.revealed { opacity: 1; }
/* heading words: per-word blur-dissolve — the live SSR initial state is
   opacity .001, filter blur(4px), translateY(10px); no clip box, no rotation */
.reveal-words .word { display: inline-block; }
.reveal-words .line { display: inline; }   /* item 5: per-line tokenization wrapper */
.reveal-words .word, .reveal-words .word > i { text-indent: 0; }
.reveal-words .word > i {
  display: inline-block; font-style: inherit;
  opacity: .001; filter: blur(4px); transform: translateY(10px);
  /* live transition: duration 1.2s, tween ease [.44, 0, .56, 1] */
  transition:
    transform 1.2s cubic-bezier(.44, 0, .56, 1),
    opacity   1.2s cubic-bezier(.44, 0, .56, 1),
    filter    1.2s cubic-bezier(.44, 0, .56, 1);
}
.reveal-words.in .word > i { transform: none; opacity: 1; filter: none; }
.reveal-stagger > * { transition-delay: var(--d, 0ms); }
.t-fade { animation: tFade .5s var(--ease); }
@keyframes tFade { from { opacity: 0; transform: translateY(10px); } }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal-words .word > i,
  .pc-label, .build-panel .fm-sub, .build-panel .fm-cta {
    opacity: 1 !important; transform: none !important; filter: none !important; transition: none !important;
  }
  .tools-track, .hero-tagline, .hero-meta, .nav, .team-content,
  .hero-intro, .hero-foot, .hero-wordmark, .hero-logo-blend { animation: none !important; }
  /* item 29: nothing added later should slip past this block */
  .hr-rays { animation: none !important; }
  .nav-pill, .menu-links a, .menu-item-glow, .menu-socials a, .card-badge, .card-badge img,
  .faq-item, .faq-a, .faq-chevron, .cookie-panel,
  .tool-chip, .pc-thumb, .pc-strip, .pc-label, .project-art, .meta-slide > div,
  .contact-scrim, .contact-drawer, .cf-switch button, .cf-chips button, .cf-submit {
    transition: none !important;
  }
  /* the button hover blur is decorative — drop it rather than flash it */
  .btn:hover .flip, .btn-secondary:hover .flip { animation: none !important; filter: none !important; }
  /* the drawer still has to appear, just without the 750ms slide. Both the open and the exit
     animations go; the open rule's own `transform`/`opacity` declarations are what remain, so the
     drawer and scrim still land in the right state. */
  body.contact-open .contact-drawer, .contact-drawer.closing,
  body.contact-open .contact-scrim, .contact-scrim.closing { animation: none !important; }
  body.contact-open .contact-drawer { transform: none; }
  .contact-drawer.closing { visibility: hidden; }
  /* no cross-document crossfade either */
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
  .cookie-panel { opacity: 1; transform: none; }
  .hero-wordmark, .hero-logo-blend { animation-duration: 0.01s; animation-delay: 0s; }
  html { scroll-behavior: auto; }
}

/* ===== Page transitions =====
   The reference is **client-side routed**: clicking a menu link swaps the URL and the DOM in place
   (`readyState` never leaves `complete`, the document height changes at ~310ms) with **no root fade,
   transform or filter at any point** — verified by sampling 22 frames through a home -> /how-we-work
   navigation. What makes it feel polished is therefore not an effect, it is two absences:

     1. no document reload, so no flash and no re-mount of the persistent chrome
     2. the navbar and menu stay mounted, so their load "appear" animations do NOT replay

   This clone is static multi-page, so it cannot reproduce (1) by architecture. The two things it
   can do, and now does:

   **Cross-document view transitions.** The platform feature built for exactly this — it hands the
   browser a snapshot of the outgoing page and crossfades to the incoming one, so there is no white
   flash and no content jump. Timed with the reference's own page-flow transition object
   (`nd = {duration: .55, ease: [.56, .09, .38, .9]}`), which is the closest thing it has to a
   route-change curve. Browsers without it simply navigate as before — this degrades to nothing.

   **Suppressing the load appears on in-session navigations.** An inline head script tags the
   document `.revisit` on any page view after the first (sessionStorage), and the rules below drop
   the appear family. Without this the navbar sinks and floats back in 1.15s after every single
   navigation, which is the most obviously un-reference-like part of moving around the clone.
   A first visit still gets the full signature entrance. ===== */
@view-transition { navigation: auto; }
::view-transition-group(root),
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .55s;
  animation-timing-function: cubic-bezier(.56, .09, .38, .9);
}
/* on a revisit the chrome and hero are already in their resting state, exactly as they stay on the
   reference's persistent components */
html.revisit .nav,
html.revisit .hero-wordmark,
html.revisit .hero-logo-blend,
html.revisit .hero-meta,
html.revisit .hero-tagline,
html.revisit .hero-intro,
html.revisit .hero-foot,
html.revisit .ph-title,
html.revisit .case-hero-head,
html.revisit .case-desc,
html.revisit .phase-cycler,
html.revisit .ph-desc,
html.revisit .team-content {
  animation: none;
}

/* ===== Responsive ===== */
@media (max-width: 1024px) {
  .svc-col-left { padding-top: 0; }
}
@media (max-width: 809px) {   /* live structural division is 809/810, not 860 */
  :root { --pad-x: 20px; --grid-pad: 20px; }   /* live phone page padding is 20px (item 11) */
  .nav { padding: 16px var(--pad-x); }
  .nav-slots, .nav-cta { display: none; }
  /* live phone MenuOpen is 350x454; the row keeps the pill's own width and the CTA moves inside.
     One row lighter than the reference (no Pricing), so 454 - 72 = 382. */
  .nav-pill { width: min(280px, calc(100vw - 2 * var(--pad-x))); }
  .nav-pill:hover, .nav-pill.open { width: min(350px, calc(100vw - 2 * var(--pad-x))); height: 382px; }
  .nav-pill-row { width: 100%; }
  .menu-list { height: auto; flex: 1 1 auto; min-height: 0; gap: 16px; }
  .menu-links a { height: 72px; }
  .menu-thumb { width: 76px; height: 60px; }
  .menu-item-label { font-size: 20px; }
  .menu-cta { display: flex; margin: 0 20px; align-self: stretch; justify-content: center; }
  .hero { padding-top: 120px; }
  /* live phone tagline: a narrower four-line block ~263px wide (item 6) */
  .hero-intro { grid-template-columns: 1fr; max-width: none; }
  .hero-tagline { grid-column: 1; width: 263px; margin-top: 0; font-size: 26px; }
  .hero-scroll { display: flex; }        /* live keeps the scroll prompt on phone */
  /* live phone metadata is TWO lines, not one cramped row (item 6) */
  .hero-meta { flex-wrap: wrap; gap: 8px 12px; }
  .hero-meta-left { flex-wrap: wrap; gap: 8px 16px; width: 100%; }
  .hero-scroll { margin-left: 0; }
  .statement, .highlights, .trust, .faq { padding-top: 140px; }
  /* live phone AboutImageWrapper: padding 0 20px, and the image drops aspect for a 450px height */
  .showcase-art { aspect-ratio: auto; height: 450px; }
  .showcase-trigger { top: -217px; height: 483px; }   /* live phone marker height */
  .about-grid, .highlights-intro { grid-template-columns: 1fr; row-gap: 32px; }
  .about > .btn { margin-left: 0; }
  .project-grid, .faq-grid { grid-template-columns: 1fr; }
  /* item 19: phone shows ONE plan at a time behind Standard/Pro tabs instead of stacking both */
  /* live phone card is ~350x440, not 295x480 (item 11) */
  .project-card { aspect-ratio: 350 / 440; min-height: 0; }
  .faq-grid { row-gap: 12px; }
  .trust-grid { grid-template-columns: 1fr; margin-top: 100px; }
  .service-grid { flex-direction: column; }
  /* ===== items 16 + 17: live phone Tools layout ===== */
  .tools { padding: 100px var(--pad-x) 140px; }
  .tools-marquee { margin: 16px 0; }             /* was 24 — the live gap is tighter */
  .tools-title { font-size: 52px; }              /* live phone Tools/Pricing heading is 52px */
  .tools-title-right { text-align: left; }
  .tools-desc { margin-top: 32px; padding-left: 0; }   /* was 80px of dead space */
  .tool-chip { width: 60px; height: 60px; border-radius: 15px; }   /* live phone icon 60x60 */
  /* 10 x 60px / 60px per second = 10s for one set */
  .tools-track { animation-duration: 10s; }
  /* live phone CTA in the light section is the grey treatment, not white-on-white */
  .tools-desc .btn { background: #d4d4d4; color: #0a0a0a; }
  .footer-top { grid-template-columns: 1fr 1fr; }
  .footer-top > :first-child { grid-column: 1 / -1; }
}

/* ===== Case study page (values extracted from the live /nova CSS) ===== */
/* hero: sticky, pad 240/0/120, gap 160, centered column */
.case-hero {
  position: sticky; top: 0; z-index: 0;
  display: flex; flex-direction: column; align-items: center; gap: 160px;
  padding: 240px var(--pad-x) 120px;
  background: var(--bg);
}
.case-hero-head {
  display: flex; flex-direction: column; align-items: center; gap: 24px;   /* live: gap 24 */
  animation: rise80 1s cubic-bezier(.11, .06, .18, 1) .25s both;
}
.case-title {
  font-size: var(--fs-heading); font-weight: 500;
  letter-spacing: -.03em; line-height: 1; text-align: center;
}
.case-tags { display: flex; align-items: center; gap: 8px; font-size: 16px; letter-spacing: -.02em; }
.case-tags i { width: 4px; height: 4px; border-radius: 1px; background: #fff9; }   /* live dot */
.case-desc {
  width: 100%; max-width: 785px;
  display: flex; justify-content: space-between; gap: 40px;
  animation: rise40 1s cubic-bezier(.11, .06, .18, 1) .45s both;
}
.case-desc p {
  flex: 1; max-width: 320px;                     /* live: two 320px columns */
  font-size: 18px; font-weight: 500; letter-spacing: -.04em; line-height: 1.3;
  color: var(--dim-60);
}

/* hero image (live: pad 0 40 120, z-2) */
.case-image-hero { padding: 0 var(--pad-x) 120px; }
.case-img {
  position: relative; width: 100%; overflow: hidden;
  background: radial-gradient(90% 110% at 60% 25%, #2c2c31 0%, #17171a 55%, #0d0d0f 100%);
}
.hero-img { aspect-ratio: 1800 / 1046; border-radius: 24px; }
.ov-img { aspect-ratio: 1.61667; border-radius: 16px; }     /* live aspects + radius 16 */
.ch-img { aspect-ratio: 1.56504; border-radius: 16px; }
.case-img .ph-label { left: 50%; bottom: auto; top: 50%; transform: translate(-50%, -50%); white-space: nowrap; }

/* case body: sticky agenda (350, 100vh, centered) + content column, gap 80 */
.case-section {
  display: flex; align-items: flex-start; gap: 80px;
  padding: 0 var(--pad-x) 200px;
}
.case-agenda {
  position: sticky; top: 0;
  flex: 1 1 0; max-width: 350px; height: 100vh;
  display: flex; flex-direction: column; justify-content: center; gap: 16px;
}
.agenda-point {
  width: 100%;
  background: rgba(255, 255, 255, .07);        /* live card fill */
  border-radius: 24px; padding: 24px;          /* live: radius 24, pad 24 */
  overflow: hidden; cursor: pointer;
  transition: background .35s;
}
.agenda-point:hover { background: rgba(255, 255, 255, .1); }
.ap-label { font-size: 15px; letter-spacing: -.03em; line-height: 1; color: var(--dim-60); }
.agenda-point.open .ap-label { color: #fff; }
.ap-body {
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height .6s var(--ease), opacity .5s var(--ease), margin .6s var(--ease);
}
.agenda-point.open .ap-body { max-height: 320px; opacity: 1; margin-top: 40px; }   /* live gap 40 */
.ap-h { font-size: 24px; font-weight: 500; letter-spacing: -.02em; line-height: 1.1; }
.ap-p { margin-top: 12px; font-size: 15.5px; letter-spacing: -.02em; line-height: 1.4; color: var(--dim-60); }

.case-wrapper { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 40px; }
.case-block { display: flex; flex-direction: column; gap: 16px; scroll-margin-top: 15vh; }
.case-tag { font-size: 24px; font-weight: 500; letter-spacing: -.02em; line-height: 1.1; }
.point-inline { display: none; }

/* prev / next case (live: centered row, gap 40, pad-top 40) */
.case-nav { display: flex; justify-content: center; gap: 40px; padding-top: 40px; }
.case-nav-btn {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: 17px; font-weight: 500; letter-spacing: -.03em;
}
.cn-arrow { font-size: 14px; display: inline-block; transition: transform .4s var(--ease); }
.cn-arrow.prev { transform: rotate(-135deg); }   /* live rotations */
.cn-arrow.next { transform: rotate(45deg); }
.case-nav-btn:hover .cn-arrow.prev { transform: rotate(-135deg) translateY(-3px); }
.case-nav-btn:hover .cn-arrow.next { transform: rotate(45deg) translateY(-3px); }

@media (max-width: 1024px) {
  .case-section { flex-direction: column; gap: 60px; }
  .case-agenda { display: none; }
  .point-inline {
    display: block; background: rgba(255, 255, 255, .07);
    border-radius: 20px; padding: 20px; margin-bottom: 8px;
  }
  .point-inline .ap-h { margin-top: 24px; }
}
@media (max-width: 809px) {
  .case-hero { gap: 100px; padding: 180px var(--pad-x) 80px; }
  .case-desc { flex-direction: column; }
  .case-image-hero, .case-section { padding-left: 20px; padding-right: 20px; }
}

/* ===== How-we-work page (values extracted from the live /how-we-work CSS) ===== */
/* 1. Process hero — column centered, gap 120, pad 200px 40px */
.process-hero {
  display: flex; flex-direction: column; align-items: center; gap: 120px;
  padding: 200px var(--pad-x);
}
.ph-title {
  width: 100%; max-width: var(--w-tools);          /* live: 785 -> 955 @1920 */
  font-size: var(--fs-heading); font-weight: 500;
  letter-spacing: -.04em; line-height: 1; text-align: left;   /* item 6: live is 98px/98px */
  animation: rise40 1s cubic-bezier(.11, .06, .18, 1) 1s both;   /* live appear */
}
.ph-content {
  width: 100%; max-width: var(--w-tools);
  display: flex; justify-content: space-between; align-items: center; gap: 40px;
}
.ph-desc {
  flex: 1 0 0; max-width: 290px;                    /* live column width */
  font-size: 18px; font-weight: 500; letter-spacing: -.04em; line-height: 1.3;
  color: var(--dim-60);
  animation: rise50 1s cubic-bezier(.11, .06, .18, 1) .9s both;
}
.ph-desc b { color: #fff; font-weight: 500; }
@keyframes rise50 { from { opacity: .001; transform: translateY(50px); } to { opacity: 1; transform: none; } }

/* phase cycler — 5-slot sliding strip, live values:
     thumb 110x110 r24 · pitch 126px · frame 120x120 r29 at -5px, 1px rgba(255,255,255,.2)
     advance 0.9s cubic-bezier(.54,0,.28,1) · dwell 2s Blueprint / 3s Spark / 3s Build
     label at left 41 / bottom -22 from the frame, crossfading 10px below itself */
.phase-cycler {
  position: relative; width: 362px; height: 110px; flex: none;
  /* item 10: the slot -1 / slot 3 buffers sit at +-126px and were widening the document
     (390px viewport -> 507px scrollWidth). Clip them, but keep an 8px margin so the frame's
     -5px bleed still shows. */
  overflow: clip; overflow-clip-margin: 8px;
  animation: rise50 1s cubic-bezier(.11, .06, .18, 1) .85s both;
}
.pc-strip {
  position: absolute; inset: 0;
  transition: transform .9s cubic-bezier(.54, 0, .28, 1);
}
/* #2: during the invisible snap-back the strip AND its thumbs must not animate — leaving the
   thumb opacity transition live made the reset visibly flicker. */
.pc-strip.no-anim, .pc-strip.no-anim * { transition: none !important; }
.pc-thumb {
  position: absolute; top: 0; width: 110px; height: 110px;
  border-radius: 24px; overflow: hidden;
  transition: opacity .9s cubic-bezier(.54, 0, .28, 1);
}
/* live: the frame sits BEHIND the thumb row (frame z-index 1, Images row above it) */
.pc-frame {
  position: absolute; top: -5px; left: -5px; width: 120px; height: 120px;
  border: 1px solid rgba(255, 255, 255, .2); border-radius: 29px;
  pointer-events: none; z-index: 1;
}
.pc-strip { z-index: 2; }
/* live, measured at 1920: label container sits +36px / +122px from the active thumb's
   top-left and is 15px tall (dot 4x4 + 4px gap + 15px text) */
.pc-labels { position: absolute; left: 36px; top: 122px; height: 15px; }
.pc-label {
  position: absolute; left: 0; top: 0;
  display: flex; align-items: center; gap: 4px;
  font-size: 14px; line-height: 15px; letter-spacing: -.02em; white-space: nowrap;
  color: var(--dim-60);                                       /* live: dot and text both 60% */
  transition:
    transform .9s cubic-bezier(.54, 0, .28, 1),
    opacity   .9s cubic-bezier(.54, 0, .28, 1);
  transition-delay: .3s;                                      /* live: incoming delay .3s */
}
.pc-label.enter { opacity: 0; transform: translateY(-30px); }  /* live: drops in from y -30 */
.pc-label.exit  { opacity: 0; transform: translateY(10px); transition-delay: 0s; }
.pc-label i { width: 4px; height: 4px; border-radius: 1px; background: currentColor; }
/* phase art — reference assets (BlueprintImage / SparkImage / BuildImage) */
.pc-img { width: 100%; height: 100%; background: center/cover no-repeat; }
.pc-img.p-blueprint { background-image: url(assets/phase-blueprint.png); }
.pc-img.p-spark     { background-image: url(assets/phase-spark.png); }
.pc-img.p-build     { background-image: url(assets/phase-build.png); }

@media (max-width: 809px) {
  .process-hero { padding: 200px 20px; }
  .ph-content { flex-direction: column; align-items: flex-start; gap: 40px; }
  .ph-desc { max-width: none; flex: none; }
}

/* 2. Team section — full-viewport #0f0f0f panel with collage + centered copy */
.team-section { height: 100vh; min-height: 640px; padding: 120px var(--pad-x) 40px; display: flex; }
.team-content {
  position: relative; flex: 1;
  background: #0f0f0f; border-radius: 24px; overflow: hidden;
  /* live: column / space-between / padding 40 — title pinned top, description pinned bottom */
  display: flex; flex-direction: column; justify-content: space-between; align-items: center;
  padding: 40px;
  /* live: this panel is a LOAD appear (appear-id 1m2sc8k), not an in-view reveal —
     y 70 -> 0, opacity .001 -> 1, delay .75s, duration 1s, ease [.11,.06,.18,1] */
  animation: rise70 1s cubic-bezier(.11, .06, .18, 1) .75s both;
}
.team-grad {
  position: absolute; left: calc(50% - 337px); width: 674px; z-index: 2; pointer-events: none;
  background: radial-gradient(50% 100% at 50% 0, #0f0f0f 0%, #0f0f0f00 100%);
}
.team-grad.top { top: 0; height: 168px; }
.team-grad.bottom { bottom: 0; height: 130px; transform: rotate(180deg); }
/* centered fade keeps the copy readable over nearby cards */
.team-grad.mid {
  top: 50%; left: 50%; width: 1000px; height: 380px;
  transform: translate(-50%, -50%);
  background: radial-gradient(50% 50% at 50% 50%, #0f0f0f 0%, #0f0f0fd9 45%, #0f0f0f00 100%);
}
/* live: both copy blocks are z-index 2 and pointer-events:none / user-select:none,
   so a node can be dragged straight through them */
.team-title, .team-desc { z-index: 2; pointer-events: none; user-select: none; }
/* live at 1920: 50px / lh 55px / ls -1px / weight 500 / centre. 48px on 810-1919. */
.team-title {
  width: 100%; text-align: center;
  font-size: 48px; font-weight: 500; letter-spacing: -.02em; line-height: 1.1;
}
/* live: 505px wide, 16px / lh 20.8 / ls -.64px / weight 500 / centre / rgba(255,255,255,.6) */
.team-desc {
  max-width: 505px; text-align: center;
  font-size: 16px; font-weight: 500; letter-spacing: -.04em; line-height: 1.3;
  color: var(--dim-60);
}
@media (min-width: 1920px) { .team-title { font-size: 50px; } }
/* connectors — every stroke, colour and dash is set by process.js from the live component's
   own props (gradients, dots, shimmer). Only the container lives here.
   live: pointer-events none, z-index 9999, overflow visible, absolute inset 0 */
/* live: the wires' own container is z-index 1 — the same as the nodes — and it comes first in
   the DOM, so the node cards paint OVER the wires. (The component sets zIndex:9999 on its
   inner root, but that is scoped inside the container and never escapes it.) */
.node-wires {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 1; overflow: visible; pointer-events: none; display: block;
}
/* collage cards: image fills the card, 10px label hangs below (live: bottom -20, left 0),
   24px badge at top:0 left:-32px. Geometry lives here (not inline) so the four
   canvases can override it — all values read off the live CSS. */
/* live inline style on every node: translate:0px 0px; cursor:grab; user-select:none;
   touch-action:none — and nothing else. No idle float, no opacity dial-back: the live
   stylesheet contains zero @keyframes and zero animation declarations. */
.tc-card {
  position: absolute; z-index: 1; transform: translate(-50%, -50%);
  cursor: grab; user-select: none; touch-action: none;
}
.tc-card:active, .tc-card.dragging { cursor: grabbing; }
/* live: the artwork wrappers and badges declare NO border-radius — the PNGs carry their
   own rounded corners and transparency */
.tc-card .tc-img { position: absolute; inset: 0; background: center/cover no-repeat; }
/* live label: width auto (shrink to fit) at left 0 / bottom -20, 10px / lh 12 / centre / .5 */
.tc-card span {
  position: absolute; bottom: -20px; left: 0;
  font-size: 10px; line-height: 12px; letter-spacing: -.04em;
  text-align: center; color: var(--dim-50);
}
.tc-card i {
  position: absolute; top: 0; left: -32px; z-index: 1;        /* live: 24px @ top 0 / left -32 */
  width: 24px; height: 24px;
  background: url(assets/badge-midu.png) center/cover no-repeat;   /* live: "Midu icon" */
}
.tc-card i.av { background-image: url(assets/avatar-client.png); }  /* live: "Client photo" */
.tc-card i.av.two { left: -60px; }   /* live node-8 carries both, 28px apart */
/* node art — reference assets */
.tc-img.g1     { background-image: url(assets/node-brief.png); }
.tc-img.g2     { background-image: url(assets/node-research.png); }
.tc-img.g3     { background-image: url(assets/node-moodboard.png); }
.tc-img.g4     { background-image: url(assets/node-wireframes.png); }
.tc-img.g5     { background-image: url(assets/node-system.png); }
.tc-img.g6     { background-image: url(assets/node-concepts.png); }
.tc-img.g7     { background-image: url(assets/node-final.png); }
.tc-img.g-logo { background-image: url(assets/node-midu.png); }

/* node placement — live: top/left calc(P% - half) == P% + translate(-50%,-50%) */
.tc-card[data-node="brief"]    { top: 22.8125%; left: 11.8333%; width: 164px; height: 165px; }
.tc-card[data-node="research"] { top: 57.2059%; left: 26.5517%; width: 100px; height: 103px; }
.tc-card[data-node="midu"]     { top: 78.2353%; left: 12.2414%; width: 100px; height: 100px; }
.tc-card[data-node="mood"]     { top: 38.2353%; left: 44.6552%; width: 118px; height: 114px; }
.tc-card[data-node="concepts"] { top: 68.5938%; left: 52.4167%; width: 131px; height: 103px; }
.tc-card[data-node="wire"]     { top: 45.1471%; left: 70.5172%; width: 112px; height: 114px; }
.tc-card[data-node="system"]   { top: 20.1471%; left: 85.6035%; width: 120px; height: 120px; }
.tc-card[data-node="final"]    { top: 75.7353%; left: 90%;      width: 114px; height: 114px; }

@media (min-width: 1920px) {
  .tc-card[data-node="brief"]    { top: 25.3125%; left: 13.1522%; width: 184px; height: 185px; }
  .tc-card[data-node="research"] { top: 57.1875%; left: 28.6957%; width: 120px; height: 124px; }
  .tc-card[data-node="midu"]     { top: 79.6875%; left: 14.4022%; }
  .tc-card[data-node="wire"]     { width: 132px; height: 134px; }
  .tc-card[data-node="system"]   { top: 21.875%;  left: 83.9674%; }
  .tc-card[data-node="final"]    { top: 78.5938%; left: 86.7391%; width: 144px; height: 144px; }
}
@media (min-width: 810px) and (max-width: 1279.98px) {
  .tc-card[data-node="brief"]    { top: 27%; left: 17%; width: 124px; height: 135px; }
  .tc-card[data-node="research"] { top: 56%; left: 25%; width: 80px;  height: 93px; }
  .tc-card[data-node="midu"]     { top: 75%; left: 12%; width: 80px;  height: 90px; }
  .tc-card[data-node="mood"]     { top: 38%; left: 45%; width: 98px;  height: 104px; }
  .tc-card[data-node="concepts"] { top: 69%; left: 52%; width: 111px; height: 95px; }
  .tc-card[data-node="wire"]     { top: 50%; left: 71%; width: 92px;  height: 104px; }
  .tc-card[data-node="system"]   { top: 26%; left: 87%; width: 100px; height: 110px; }
  .tc-card[data-node="final"]    { top: 76%; left: 86%; width: 94px;  height: 104px; }
}
@media (max-width: 809px) {
  .team-section { padding: 10px; height: auto; min-height: 100vh; }
  .team-content { padding: 120px 20px; }
  /* live phone graph: nodes 2 (Midu), 5 (Concepts) and 7 (Design system) carry
     hidden-23dirc, so only 5 of the 8 render and the topology drops to 4 wires. */
  .tc-card[data-node="midu"],
  .tc-card[data-node="concepts"],
  .tc-card[data-node="system"] { display: none; }
  .tc-card[data-node="brief"]    { top: 30%; left: 50px; width: 144px; height: 145px; }
  .tc-card[data-node="research"] { top: 31%; left: auto; right: 30px; width: 80px;  height: 83px; }
  .tc-card[data-node="mood"]     { top: 49%; left: 28%; width: 98px;  height: 95px; }
  .tc-card[data-node="wire"]     { top: 54%; left: 79%; width: 102px; height: 104px; }
  .tc-card[data-node="final"]    { top: 70%; left: 41%; width: 104px; height: 104px; }
}

/* 3. Phase sections (live: col centered, gap 40, pad 200/40/120) */
.phase-section {
  display: flex; flex-direction: column; align-items: center; gap: 40px;
  padding: 200px var(--pad-x) 120px;
}
/* timeline chip: thumb + name + segmented bar + weeks */
.phase-chip { display: flex; align-items: center; gap: 16px; }
.pch-thumb { width: 56px; height: 56px; border-radius: 12px; flex: none; }
.pch-info { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.pch-name { display: flex; align-items: center; gap: 8px; font-size: 14px; letter-spacing: -.02em; }
.pch-name i { width: 4px; height: 4px; border-radius: 1px; background: #fff; }
/* ===== #5: the weeks progress pill =====
   Live Timeline component (page-components.mjs):
     pill    rgba(21,21,21,.8) r20, padding 8, gap 8, width min-content, scale 1
             -> scale .9 while filling, back to 1 on the final state (the container pulse)
     track   60x4, r10, rgba(255,255,255,.2)
     fill    starts width 2% / opacity 0 / rgba(255,255,255,.4)
             -> width 100% / opacity 1, and brightens to rgba(255,255,255,.8) on Final
     motion  {duration:.6, ease:[0,.3,.5,1]}, one segment every 500ms
   Scroll-triggered, then time-based — not continuously scroll-linked. ===== */
.pch-bar {
  display: flex; gap: 8px; padding: 8px; width: min-content;
  background: rgba(21, 21, 21, .8); border-radius: 20px;
  transform: scale(1);
  transition: transform .6s cubic-bezier(0, .3, .5, 1);
}
.pch-bar.filling { transform: scale(.9); }
.pch-bar em {
  display: block; width: 60px; height: 4px; flex: none;
  border-radius: 10px; background: rgba(255, 255, 255, .2); overflow: hidden;
}
.pch-bar b {
  display: block; width: 2%; height: 100%; border-radius: 10px;
  background: rgba(255, 255, 255, .4); opacity: 0;
  transition:
    width .6s cubic-bezier(0, .3, .5, 1),
    opacity .6s cubic-bezier(0, .3, .5, 1),
    background-color .6s cubic-bezier(0, .3, .5, 1);
}
.pch-bar em.on > b { width: 100%; opacity: 1; }
.pch-bar.done b { background: rgba(255, 255, 255, .8); }
.pch-weeks { font-size: 14px; letter-spacing: -.02em; color: var(--dim-60); }
/* headline block — live: ONE left-aligned 28px h2 at max-w 665 (785 at >=1920). The body copy
   is the same 28px, just dropped to rgba(255,255,255,.4); only the lead sentence is white. */
.phase-head { display: flex; flex-direction: column; align-items: center; gap: 80px; }
.phase-title { max-width: 665px; text-align: left; }
.phase-title h3 {
  font-size: 28px; font-weight: 500; letter-spacing: -.03em; line-height: 1.2;
  color: var(--dim-40);
}
.phase-title h3 > span { color: #fff; }
@media (min-width: 1920px) { .phase-title { max-width: 785px; } }
/* question bubbles — live: both centred (no sideways offset), padding 8px 18px, 48px/110%,
   max-width 538px and 581px respectively */
.phase-q { display: flex; flex-direction: column; gap: 12px; width: 100%; align-items: center; }
.q-bubble {
  max-width: 538px; width: 100%;
  background: #151515cc; border-radius: 24px; padding: 8px 18px;
  font-size: 48px; font-weight: 500; letter-spacing: -.03em; line-height: 1.1;
  text-align: center;
}
.q-bubble.right { max-width: 581px; }
@media (max-width: 809px) { .q-bubble { font-size: 30px; } }
/* interactive demo row (live: sides max 320 stretch, center 42% @1.18, pad 80 0) */
.phase-demo {
  display: flex; justify-content: center; align-items: stretch; gap: 10px;
  width: 100%; padding: 80px 0;
}
.pd-col {
  flex: 1 0 0; max-width: 320px; max-height: 600px; padding: 50px 0;
  display: flex; flex-direction: column; justify-content: space-between; gap: 20px;
}
.pd-col.left { align-items: flex-end; }
.pd-col.right { align-items: flex-start; }
.pd-center {
  width: 49%; aspect-ratio: 1.18182;   /* item 17: 49% at 1280-1919 */ border-radius: 24px;
  position: relative; overflow: hidden; flex: none;
}
.pd-center > img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* side-column reference shots (live widths: arrow card 200px @1.754, hover card 201px @1.271) */
.pd-shot { display: block; height: auto; border-radius: 14px; }
.pd-shot.bp-arrow { width: 200px; }
/* item 16: both PhoneImages carry hidden-* classes above 809px in the reference */
.pd-shot.bp-phone { display: none; }
@media (max-width: 809px) { .pd-shot.bp-phone { display: block; width: 69%; min-width: 180px; } }
/* ===== #4: the card beside the laptop =====
   Live InteractiveRight hover variant: BOTH image layers scale together to 1.1 while the
   alternate state crossfades in, and the block lifts y -30 -> 0. Transition
   {delay:.3/.35, duration:.9, ease:[.54,0,.28,1]} — not a flat .5s opacity fade. ===== */
.pd-hover { position: relative; width: 201px; overflow: hidden; border-radius: 14px; }
.pd-hover img {
  display: block; width: 100%; height: auto; border-radius: 14px;
  transform: scale(1);
  transition: transform .9s cubic-bezier(.54, 0, .28, 1);
}
.pd-hover img.hov {
  position: absolute; inset: 0; opacity: 0;
  transition:
    opacity   .9s cubic-bezier(.54, 0, .28, 1) .3s,
    transform .9s cubic-bezier(.54, 0, .28, 1);
}
/* both layers scale simultaneously — the previous rule only crossfaded */
.pd-hover:hover img,
.pd-hover:focus-within img { transform: scale(1.1); }
.pd-hover:hover img.hov,
.pd-hover:focus-within img.hov { opacity: 1; }
.pd-pill {
  background: #151515cc; border: 1px solid var(--line); border-radius: 999px;
  padding: 12px 18px; font-size: 14px; letter-spacing: -.02em; width: fit-content;
}
.pd-pill.tag { background: #fff; color: #111; }
.pd-card {
  background: #151515cc; border: 1px solid var(--line); border-radius: 18px;
  padding: 18px; max-width: 250px;
}
.pd-card b { display: block; font-size: 15px; font-weight: 600; }
.pd-card p { margin-top: 8px; font-size: 13.5px; line-height: 1.35; color: var(--dim-60); }
.pd-avatar {
  display: block; width: 36px; height: 36px; border-radius: 50%; margin-bottom: 10px;
  background: radial-gradient(120% 120% at 30% 25%, #9a8062 0%, #4e3d31 60%, #241b14 100%);
}
/* timeline-chip art — reference assets (shared with the hero cycler) */
.g-blueprint { background: url(assets/phase-blueprint.png) center/cover no-repeat; }
.g-spark     { background: url(assets/phase-spark.png)     center/cover no-repeat; }
.g-build     { background: url(assets/phase-build.png)     center/cover no-repeat; }

/* ===== item 2: Spark — the pinned copy, the travelling artwork =====
   Live: SparkTopWrapper 300vh (380vh <=809) with overflow clip; SparkTop is the only sticky
   child (100vh, top 0, z-index 1) and holds ONLY the timeline chip and the description.
   SparkTimeline sits at z-index -1, i.e. behind the artwork. The 10 images, the video badge and
   the typography card are absolute children of the wrapper at the live percentage coords, so
   they move through the frame while the copy stays put. ===== */
.spark-scroller { position: relative; width: 100%; height: 300vh; overflow: clip; z-index: 0; }
.spark-top {
  position: sticky; top: 0; z-index: 1;
  height: 100vh; display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  pointer-events: none;
}
.spark-top .phase-head { pointer-events: auto; }
.spark-field { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.spark-field img, .sf-video, .sf-type {
  position: absolute; transform: translate(-50%, -50%);
  height: auto;
  border-radius: 12px; object-fit: cover; z-index: 1;
  /* each piece is offset and faded by the section's scroll progress (--sp, 0 -> 1) and its own
     lane (--lane) so they enter and leave individually rather than as one block */
  translate: 0 calc((var(--sp, 0) - var(--lane, .5)) * -70vh);
  /* a two-sided window: each piece fades in as its lane approaches, holds, then fades out as
     the sequence carries it past — so the frame is never just accumulating artwork */
  opacity: clamp(0, min(
      calc((var(--sp, 0) - var(--lane, .5) + .40) / .18),
      calc((var(--lane, .5) + .46 - var(--sp, 0)) / .18)), 1);
  will-change: translate, opacity;
}
/* the looping badge: live 15% wide, aspect 2.36, at top 82% / left 17% (10% / 87% at >=1920) */
.sf-video {
  width: 15%; max-width: 180px; aspect-ratio: 2.36; top: 82%; left: 17%;
  z-index: 2; border-radius: 12px; --lane: .68;
}
/* the frosted typography card: live aspect .904523, #ffffff1a, blur(10px), r24 */
.sf-type {
  width: 13%; min-width: 150px; aspect-ratio: .904523; top: 36%; left: 78%;
  background: #ffffff1a; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-radius: 21.4px; border-radius: 24px; corner-shape: superellipse(1.2);
  display: flex; flex-direction: column; justify-content: flex-start;
  padding: 16px; gap: 4px; --lane: .5;
}
.sft-name { font-size: 12px; letter-spacing: -.02em; color: #fff; }
.sft-set { font-size: 11px; color: var(--dim-60); }
.sft-aa { margin-top: auto; font-size: 44px; font-weight: 500; letter-spacing: -.03em; line-height: 1; }
/* item 2: the vignette develops across the sequence */
.spark-vignette {
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  opacity: var(--spark-vig, 0);
  background:
    linear-gradient(180deg, #000 0%, transparent 26%),
    linear-gradient(0deg, #000 0%, transparent 26%);
  transition: opacity .3s linear;
}
.sf1  { --lane: .30;  aspect-ratio: .755906; width: 8%;  top: 39%; left: 12%; }
.sf2  { --lane: .86;  aspect-ratio: 1.62162; width: 23%; top: 96%; left: 48%; }
.sf3  { --lane: .74;  aspect-ratio: .972028; width: 12%; top: 79%; left: 9%; }
.sf4  { --lane: .22;  aspect-ratio: .968326; width: 18%; top: 21%; left: 13%; }
.sf5  { --lane: .14;  aspect-ratio: 3.80488; width: 13%; top: 14%; left: 11%; }
.sf6  { --lane: .62;  aspect-ratio: 1;       width: 8%;  top: 67%; left: 90%; z-index: 2; }
.sf7  { --lane: .58;  aspect-ratio: 1.07834; width: 18%; top: 64%; left: 80%; }
.sf8  { --lane: .10;  aspect-ratio: 1.68627; width: 7%;  top: 7%;  left: 84%; }
.sf9  { --lane: .06;  aspect-ratio: 3.62687; width: 20%; top: 4%;  left: 79%; }
.sf10 { --lane: .44;  aspect-ratio: 1.1465;  width: 15%; top: 47%; left: 28%; }
@media (min-width: 1920px) {
  .sf1  { --lane: .30;  width: 5%;  top: 44%; left: 13%; }
  .sf2  { --lane: .86;  width: 18%; top: 96%; left: 50%; }
  .sf3  { --lane: .74;  width: 8%;  top: 83%; left: 14%; }
  .sf4  { --lane: .22;  width: 13%; top: 18%; left: 12%; }
  .sf5  { --lane: .14;  width: 10%; top: 9%;  left: 19%; }
  .sf6  { --lane: .62;  width: 5%;  top: 73%; left: 85%; }
  .sf7  { --lane: .58;  width: 10%; top: 69%; left: 78%; }
  .sf8  { --lane: .10;  width: 5%;  top: 7%;  left: 87%; }
  .sf9  { --lane: .06;  width: 12%; top: 4%;  left: 84%; }
  .sf10 { --lane: .44;  width: 11%; top: 54%; left: 32%; }
}

/* Build: 1200px panel (live: ar 1.62724, r24, pad 58/0/62) with the phone at 24% */
.build-panel {
  width: 100%; max-width: 1200px; aspect-ratio: 1.62724;
  border-radius: 24px; overflow: hidden;
  background: url(assets/build-panel.webp) center/cover no-repeat;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding: 58px 0 62px;
}
.bld-phone {
  position: relative; width: 24%; aspect-ratio: .459384; flex: none; z-index: 2;
  display: flex; flex-direction: column; justify-content: space-between;
}
.bph-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; display: block; }
/* live BuildContentBack: a scrim over the photo panel, rgba(0,0,0,0) -> rgba(0,0,0,.6),
   delay .3s, ease [.44,0,.56,1] (item 3, stage 2) */
.bld-scrim {
  position: absolute; inset: 0; z-index: 1;
  background-color: rgba(0, 0, 0, 0);
  transition: background-color .8s cubic-bezier(.44, 0, .56, 1) .3s;
}
/* stage 3 — Fixa nav + burger, white glass, enters from y -71 at 1.2s / .8s */
.bph-menu {
  position: relative; z-index: 2; margin: 6% 6% 0;
  display: flex; align-items: center; justify-content: space-between;
  background: #ffffff; color: #111; border-radius: 12px;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  padding: 8px 12px; font-size: clamp(10px, .7vw, 13px); font-weight: 600;
  opacity: 0; transform: translateY(-71px);
  transition:
    opacity   .8s cubic-bezier(.56, .09, .38, .9) 1.2s,
    transform .8s cubic-bezier(.56, .09, .38, .9) 1.2s;
}
.bph-burger { display: flex; flex-direction: column; gap: 3px; }
.bph-burger i { display: block; width: 14px; height: 1.5px; background: #111; border-radius: 1px; }
.bph-bot {
  position: relative; z-index: 2; margin: 0 6% 7%;
  display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
}
/* stages 4-7, each on its own y and delay (live values) */
.bph-bot > * {
  opacity: 0;
  transition:
    opacity   .75s cubic-bezier(.56, .09, .38, .9),
    transform .75s cubic-bezier(.56, .09, .38, .9);
}
.build-panel .fm-title  { transform: translateY(20px); transition-delay: 1.05s; }
.build-panel .fm-sub    { transform: translateY(20px); transition-delay: .9s; }
.build-panel .bph-banner{ transform: translateY(25px); transition-delay: .7s; }
.build-panel .fm-cta    { transform: translateY(65px); transition-delay: .6s; }
/* live: the tail of the statement is italic Instrument Serif */
.build-panel .fm-title em { font-family: "Instrument Serif", Georgia, serif; font-style: italic; }
.bph-banner {
  background: rgba(0, 0, 0, .25); color: #fff;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-radius: 12px; padding: 8px 12px;
  font-size: clamp(9px, .62vw, 11.5px); line-height: 1.3;
}
.fm-title { font-size: clamp(15px, 1.1vw, 20px); font-weight: 500; letter-spacing: -.02em; }
.fm-sub { font-size: clamp(10px, .72vw, 13px); color: #ffffffb3; }
.fm-cta { background: #fff; color: #111; border-radius: 999px; padding: 8px 16px; font-size: 12px; }
/* the live phone assembles itself from staged offsets, each with its own y and delay:
   PhoneMenu y-71 d1.2/.8s · PhoneSubDescription y20 d.9/.75s
   PhoneCTABanner y25 d.7/.75s · PhoneCTA y65 d.6/.75s — all ease [.56,.09,.38,.9] */
.build-panel.assembled .bld-scrim { background-color: rgba(0, 0, 0, .6); }
.build-panel.assembled .bph-menu,
.build-panel.assembled .fm-title,
.build-panel.assembled .fm-sub,
.build-panel.assembled .bph-banner,
.build-panel.assembled .fm-cta { opacity: 1; transform: none; }

/* deliverables card — live: 1200px wide, vertical gradient fill, NO border, padding 32/40,
   column gap 40. DelivLine is a single ROW of 5 equal columns (flex:1 0 0; width:1px) with the
   icon stacked ABOVE its label, gap 16. */
.deliverables {
  width: 100%; max-width: 1200px;
  background: linear-gradient(#15151599 0%, #15151500 100%);
  border-radius: 24px; padding: 32px 40px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 40px;
}
.dl-head { display: flex; flex-direction: column; gap: 8px; }
.dl-label { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--dim-40); }
.dl-label i { width: 4px; height: 4px; border-radius: 1px; background: #fff6; }
/* live: this is a 32px white Switzer Medium h2, not a dim caption */
.dl-title { font-size: 32px; font-weight: 500; letter-spacing: -.02em; line-height: 1.1; color: #fff; }
.dl-grid {
  display: flex; flex-direction: row;
  justify-content: flex-start; align-items: flex-start;
  gap: 40px; width: 100%;
}
.dl-row {
  flex: 1 0 0; width: 1px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 16px;
  font-size: 16px; letter-spacing: -.04em; line-height: 1.2; color: var(--dim-50);
}
/* live: 50px superellipse (r18 x .843), #ffffff12, 12px white glyph centered */
.dl-ic {
  flex: none; width: 50px; height: 50px; border-radius: 15px;
  background: #ffffff12 center / 12px 12px no-repeat;
}
/* reference glyphs — Blueprint's shipped inline, Spark/Build as hosted SVGs */
#blueprint .dl-ic.i1 { background-image: url(assets/dl-bp-1.svg); }
#blueprint .dl-ic.i2 { background-image: url(assets/dl-bp-2.svg); }
#blueprint .dl-ic.i3 { background-image: url(assets/dl-bp-3.svg); }
#blueprint .dl-ic.i4 { background-image: url(assets/dl-bp-4.svg); }
#blueprint .dl-ic.i5 { background-image: url(assets/dl-bp-5.svg); }
#spark .dl-ic.i1 { background-image: url(assets/dl-sp-1.svg); }
#spark .dl-ic.i2 { background-image: url(assets/dl-sp-2.svg); }
#spark .dl-ic.i3 { background-image: url(assets/dl-sp-3.svg); }
#spark .dl-ic.i4 { background-image: url(assets/dl-sp-4.svg); }
#spark .dl-ic.i5 { background-image: url(assets/dl-sp-5.svg); }
#build .dl-ic.i1 { background-image: url(assets/dl-bd-1.svg); }
#build .dl-ic.i2 { background-image: url(assets/dl-bd-2.svg); }
#build .dl-ic.i3 { background-image: url(assets/dl-bd-3.svg); }
#build .dl-ic.i4 { background-image: url(assets/dl-bd-4.svg); }
#build .dl-ic.i5 { background-image: url(assets/dl-bd-5.svg); }

@media (max-width: 1024px) {
  .phase-demo { flex-direction: column; align-items: center; }
  .pd-col { max-width: 480px; width: 100%; padding: 0; align-items: center !important; }
  .pd-center { width: 100%; }
  .q-bubble, .q-bubble.right { transform: none; }
}
@media (min-width: 810px) and (max-width: 1279.98px) {
  .build-panel { aspect-ratio: 1.00898; }   /* live */
  .bld-phone { width: 38%; }
}
@media (max-width: 809px) {
  .phase-section { padding: 160px 20px 0; }
  /* live phone override: DelivLine flips to a column with gap 20 and the items go row-wise */
  .dl-grid { flex-direction: column; gap: 20px; }
  .dl-row { flex: none; width: 100%; flex-direction: row; align-items: center; }
  .build-panel { aspect-ratio: .506146; }   /* live */
  .bld-phone { width: 75%; }
  /* the live mobile field stacks the collage; a 2-col grid is the cheap stand-in */
  /* item 2: the live phone sequence is art-directed over 380vh, not collapsed to a grid */
  .spark-scroller { height: 380vh; overflow: clip; }
  .spark-top { height: 100vh; }
  .sf-type { width: 34%; min-width: 120px; }
  .sf-video { width: 40%; }
  .spark-field img {
    position: static; transform: none; width: 100%; aspect-ratio: 1; z-index: auto;
    top: auto; left: auto;
  }
}

/* 4. What stays constant (live: pad 120/40, inner max-w 900->1200, gap 80) */
.constants { padding: 120px var(--pad-x); display: flex; justify-content: center; }
.const-inner { width: 100%; max-width: var(--w-heading); display: flex; flex-direction: column; gap: 80px; }
.const-intro { max-width: 320px; font-size: 18px; letter-spacing: -.03em; line-height: 1.3; color: var(--dim-40); }
/* item 4: three 373x373 artwork cards side by side, copy beneath each */
.const-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; }
.const-card { display: flex; flex-direction: column; }
.cc-art {
  width: 100%; max-width: 373px; aspect-ratio: 1;
  border-radius: 21.4px; border-radius: 24px; corner-shape: superellipse(1.2);
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.cc-art.c1 { background-image: url(assets/const-1.png); }   /* live: CardImage */
.cc-art.c2 { background-image: url(assets/const-2.png); }
.cc-art.c3 { background-image: url(assets/const-3.png); }
.const-card h3 { margin-top: 32px; font-size: 24px; font-weight: 500; letter-spacing: -.02em; line-height: 1.2; }
.const-card p { margin-top: 12px; font-size: 16px; letter-spacing: -.02em; line-height: 1.4; color: var(--dim-60); }

/* 5. Contact (live: pad 120/40/240, row max-w 900->1200, copy col max-w 300->330) */
.contact { padding: 120px var(--pad-x) 240px; display: flex; justify-content: center; }
.contact-inner {
  width: 100%; max-width: var(--w-heading);
  display: flex; gap: 80px; align-items: flex-start;
}
.contact-copy { flex: 1 0 0; max-width: 300px; position: sticky; top: 120px; }
.contact-copy h2 { font-size: 50px; font-weight: 500; letter-spacing: -.03em; line-height: 1.1; }   /* item 25 */
.contact-copy p { margin-top: 16px; font-size: 15.5px; letter-spacing: -.02em; line-height: 1.4; color: var(--dim-60); }
/* item 24: the fields sat directly on the black page — the live form is one rounded card */
.contact-form {
  flex: 1.6 1 0; display: flex; flex-direction: column; gap: 24px;
  background: #10101080; border: 1px solid var(--line);
  border-radius: 21.4px; border-radius: 24px; corner-shape: superellipse(1.2);
  padding: 32px;
}
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }   /* item 26 */
.contact-form fieldset { border: 0; display: flex; flex-direction: column; gap: 10px; }
.contact-form legend { font-size: 14px; color: var(--dim-40); margin-bottom: 12px; letter-spacing: -.02em; }
.contact-form input, .contact-form textarea {
  width: 100%; background: #12121280; border: 1px solid var(--line); border-radius: 14px;
  padding: 16px 18px; font: inherit; font-size: 15px; color: #fff; letter-spacing: -.02em;
  transition: border-color .3s, background .3s;
}
.contact-form input::placeholder, .contact-form textarea::placeholder { color: var(--dim-40); }
.contact-form input:focus, .contact-form textarea:focus { outline: 0; border-color: #ffffff3d; background: #16161680; }
.contact-form textarea { resize: vertical; min-height: 110px; }
.chips { display: flex; flex-wrap: wrap; gap: 10px; }
.chip {
  background: #1e1e1e; border: 1px solid transparent; border-radius: 999px;   /* item 26: filled */
  padding: 12px 20px; font-size: 14.5px; letter-spacing: -.02em; color: #ddd;
  transition: background .3s, color .3s, border-color .3s;
}
.chip:hover { background: #262626; }
.chip.on { background: #fff; color: #111; border-color: #fff; }
.form-submit { width: 100%; justify-content: center; min-height: 50px; }   /* items 26 + 27 */
.form-submit[disabled] { opacity: .55; pointer-events: none; }
.form-status { font-size: 13.5px; letter-spacing: -.02em; min-height: 1em; }
.form-status.ok { color: #8ee6a8; }
.form-status.err { color: #ff9a8a; }
.contact-form :invalid:not(:placeholder-shown) { border-color: #ff6a55; }
.form-note { font-size: 13px; color: var(--dim-40); }
.form-note a { text-decoration: underline; }

@media (max-width: 1024px) {
  .contact-inner { flex-direction: column; gap: 48px; }
  .contact-copy { position: static; max-width: none; }
}


/* ===== item 23: cookie consent panel (live: 490x111, bottom-right, buttons 65x48,
   whileHover opacity .6, whileTap opacity .4) ===== */
.cookie-panel {
  position: fixed; right: 20px; bottom: 20px; z-index: 60;
  width: min(490px, calc(100vw - 40px));
  background: rgba(21, 21, 21, .82);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--line);
  border-radius: 17.8px; border-radius: 20px; corner-shape: superellipse(1.2);
  padding: 18px 20px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  box-shadow: 0 30px 70px #00000080;
  opacity: 0; transform: translateY(12px);
  transition: opacity var(--m-menu-in), transform var(--m-menu-in);
}
.cookie-panel[hidden] { display: none; }
.cookie-panel.in { opacity: 1; transform: none; }
.cookie-title { font-size: 15px; font-weight: 500; letter-spacing: -.02em; width: 100%; }
.cookie-body { font-size: 13.5px; line-height: 1.35; color: var(--dim-60); flex: 1 1 220px; }
.cookie-actions { display: flex; gap: 8px; margin-left: auto; }
.cookie-btn {
  min-width: 65px; height: 48px; padding: 0 18px; border-radius: 999px;
  font-size: 14px; letter-spacing: -.02em;
  transition: opacity var(--m-keycap);
}
.cookie-accept { background: #fff; color: #111; }
.cookie-decline { background: #ffffff14; color: #fff; }
.cookie-btn:hover { opacity: .6; }     /* live whileHover */
.cookie-btn:active { opacity: .4; }    /* live whileTap   */

/* ===== item 30: hero poster under the WebGL iframe ===== */
.hero-poster {
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(120% 90% at 22% 8%, #ff6a3d 0%, #d8321a 22%, #7d1510 46%, #2a0806 70%, #050505 100%);
}
.hero-shader iframe { position: relative; z-index: 1; opacity: 0; transition: opacity .6s linear; }
.hero-shader iframe.ready { opacity: 1; }

/* ===== item 29: focus, keyboard and touch ===== */
:where(a, button, input, textarea, [tabindex]):focus-visible {
  outline: 2px solid #ff5a3c; outline-offset: 3px; border-radius: 6px;
}
/* touch equivalents: the project title -> CTA slide also fires on tap-focus, and the FAQ /
   service affordances respond to :focus-within where they only had :hover */
.project-card:focus-within .meta-slide > div { transform: translateY(-75px); }
.service-card:focus-within { box-shadow: 0 44px 80px #00000024; }
.faq-item:focus-within { background: #ffffff12; }
@media (hover: none) {
  .tool-chip:hover { transform: none; box-shadow: 0 10px 24px #00000018; }
}


/* ===== item 25: explicit tier for the reference's 810-1279 canvas =====
   The other three ranges are covered by the <=809 block, the 1280-1919 defaults and the
   >=1920 block. This range previously fell through to fluid clamps, so 810-860 in particular
   mixed phone structure with tablet type. ===== */
@media (min-width: 810px) and (max-width: 1279.98px) {
  :root { --pad-x: 40px; --grid-pad: 40px; --fs-heading: 65px; }
  .hero-intro { grid-template-columns: 1fr 290px; max-width: 100%; }
  .hero-tagline { grid-column: 2; width: 290px; font-size: 28px; }
  .hero-meta { gap: 24px; }
  .project-grid { grid-template-columns: 1fr 1fr; gap: 20px; }
  .project-card { aspect-ratio: 830 / 841; }
  .showcase-art { max-width: 100%; }
  .tools-title { font-size: 65px; }
  .service-grid { flex-direction: row; gap: 24px; }
  .faq-grid { grid-template-columns: 1fr 1fr; }
}


/* ===== item 1: animated red hero atmosphere (see the markup comment for provenance) ===== */
.process-hero { position: relative; isolation: isolate; }
.process-hero > :not(.hero-rays) { position: relative; z-index: 1; }
.hero-rays {
  position: absolute; inset: 0; z-index: 0; overflow: clip; pointer-events: none;
}
/* Corrected from the property controls rather than from a screenshot:
     position: 50  -> the origin is 50% ACROSS, i.e. horizontally centred (I had it at 20% left)
     intensity: 0  -> the instance runs intensity at its MINIMUM (default is 50), so this is a
                      restrained bloom, not a hot one
     reach: 40     -> a 40%-of-height falloff */
.hr-bloom {
  position: absolute; inset: -6% -6% 0;
  background:
    radial-gradient(46% 40% at 50% -6%, rgba(222, 111, 55, .58) 0%, rgba(214, 21, 34, .42) 28%,
                    rgba(140, 14, 22, .22) 52%, rgba(60, 8, 10, .08) 72%, transparent 88%);
}
/* 12 rays, colour1 -> colour2, rotating at the live speed (21 -> ~34s for a full sweep) */
.hr-rays {
  position: absolute; left: 50%; top: -30%;   /* position: 50 -> centred origin */
  width: 160vmax; height: 160vmax; transform-origin: 0 0;
  translate: -50% 0;
  background: repeating-conic-gradient(from 0deg at 50% 50%,
    rgba(222, 111, 55, .16) 0deg, rgba(222, 111, 55, 0) 7deg,
    rgba(214, 21, 34, .13) 15deg, rgba(214, 21, 34, 0) 22deg,
    transparent 30deg);
  -webkit-mask: radial-gradient(40% 40% at 50% 50%, #000 0%, transparent 78%);
          mask: radial-gradient(40% 40% at 50% 50%, #000 0%, transparent 78%);
  filter: blur(28px);
  animation: heroRays 34s linear infinite;
  will-change: transform;
}
@keyframes heroRays { to { rotate: 360deg; } }
/* live ProgressiveBlur {blur:35, blurDirection:"toBottom"} + the fade into black */
.hr-fade {
  position: absolute; inset: 0;
  backdrop-filter: blur(35px); -webkit-backdrop-filter: blur(35px);
  -webkit-mask: linear-gradient(180deg, transparent 34%, #000 78%);
          mask: linear-gradient(180deg, transparent 34%, #000 78%);
  background: linear-gradient(180deg, transparent 30%, #050505 82%);
}
@media (max-width: 809px) {
  /* live phone shader area is shorter and its red light sits higher */
  .hero-rays { bottom: 42%; }
  .hr-bloom { background: radial-gradient(62% 44% at 50% -8%, rgba(222, 111, 55, .55) 0%, rgba(214, 21, 34, .4) 26%, rgba(140, 14, 22, .2) 50%, transparent 82%); }
}


/* ===== item 27: phone contact form — live is x40 / 310px wide with a 310x50 submit ===== */
@media (max-width: 809px) {
  .contact { padding-left: 40px; padding-right: 40px; }
  .contact-form { padding: 24px 20px; gap: 20px; }
  .field-row { grid-template-columns: 1fr; }
  .form-submit { width: 100%; height: 50px; }
  .contact-copy h2 { font-size: 34px; }
}


/* ===================================================================================
   How-we-work: the 809/810 recomposition (items 4, 9, 12, 18, 20, 21, 23, 33)
   The breakpoint existed but only changed type — these blocks actually recompose.
   =================================================================================== */
@media (max-width: 809px) {
  /* item 12: the live phone team panel */
  .team-title { font-size: 24px; line-height: 1.15; }
  .team-content { padding: 40px 20px; }              /* was 120px of dead vertical space */
  .team-desc { font-size: 14px; }
  /* keep the heading above the diagram instead of letting the nodes run under it */
  .team-content { justify-content: flex-start; gap: 24px; }
  .team-desc { margin-top: auto; }
  /* item 12: pull the left-hand nodes in so their artwork is not clipped */
  .tc-card[data-node="brief"]    { top: 34%; left: 26%; }
  .tc-card[data-node="research"] { top: 36%; left: auto; right: 24px; }
  .tc-card[data-node="mood"]     { top: 54%; left: 30%; }
  .tc-card[data-node="wire"]     { top: 58%; left: 74%; }
  .tc-card[data-node="final"]    { top: 76%; left: 44%; }

  /* item 18: phase prose 28 -> 20px, and halve the heading gap */
  .phase-title h3 { font-size: 20px; line-height: 1.25; }
  .phase-head { gap: 40px; }
  /* item 18: one rounded question surface instead of two stacked pills */
  .phase-q { gap: 0; }
  .q-bubble {
    max-width: 350px; font-size: 26px; padding: 14px 18px;
    border-radius: 0; background: #151515cc;
  }
  .q-bubble:first-child { border-radius: 24px 24px 0 0; padding-bottom: 0; }
  .q-bubble.right { max-width: 350px; border-radius: 0 0 24px 24px; padding-top: 0; }

  /* item 20 + 21: 48px thumb, wider chip */
  .pch-thumb { width: 48px; height: 48px; }
  .phase-chip { gap: 12px; min-width: 210px; }
  .pch-bar em { width: 48px; }
  .pch-bar { gap: 6px; padding: 6px; }

  /* item 23: deliverable content should start at x40, not x60 */
  .deliverables { padding: 24px 20px; }

  /* item 4: the constants cards stack at ~350x350 instead of shrinking to thumbnails */
  .const-cards { grid-template-columns: 1fr; gap: 48px; }
  .cc-art { max-width: 350px; }
  .const-inner { gap: 48px; }

  /* item 9: right-align the phone menu around x275 instead of centring it at x148 */
  .nav-pill { top: 16px; left: auto; right: var(--pad-x); margin-inline: 0; }   /* phone nav pad is 16 */
  .nav-logo-mark { width: 56px; height: 17px; }      /* item 9: smaller phone logo */

  /* item 9: description before the phase icons */
  .ph-content { flex-direction: column; align-items: flex-start; gap: 32px; }
  .ph-desc { order: 1; }
  .phase-cycler { order: 2; }
}
@media (min-width: 810px) and (max-width: 1279.98px) {
  .team-title { font-size: 32px; }                   /* item 12: 32px on the second canvas */
  .team-content { padding: 40px; }
  .phase-title h3 { font-size: 24px; }
  .phase-head { gap: 56px; }
}

@media (min-width: 1920px) { .pd-center { width: 42%; } }   /* item 17: 42% only at >=1920 */

/* ===== item 30: component-specific springs for the phase pieces =====
   Titles, artwork and the question panels each get their own settle instead of sharing one
   reveal curve. Durations/curves are the live per-component transitions. ===== */
.phase-title, .phase-head.reveal .phase-title { transition-duration: .85s; }
.phase-q.reveal {
  transition:
    opacity   .55s cubic-bezier(.52, 0, .45, 1),
    transform .55s cubic-bezier(.52, 0, .45, 1);
}
.phase-demo.reveal, .const-card.reveal {
  transition:
    opacity   .65s cubic-bezier(.56, 0, .47, 1),
    transform .65s cubic-bezier(.56, 0, .47, 1);
}


/* ===== #4: Blueprint custom cursor (see the markup comment for provenance) ===== */
.bp-cursor {
  position: fixed; left: 0; top: 0; z-index: 70;
  width: 68px; height: 29px;
  display: flex; flex-direction: row; align-items: flex-start; gap: 6px;
  overflow: hidden; pointer-events: none;
  opacity: 0;                                  /* only shown while inside the section */
  will-change: transform;
}
.bp-cursor.on { opacity: 1; }
.bpc-arrow, .bpc-pill {
  /* live variant swap: active opacity 1 / scale 1, inactive opacity 0 / scale .6,
     on a {bounce:.2, duration:.4} spring — the overshoot below is that bounce */
  opacity: 0; transform: scale(.6);
  transition:
    opacity   .4s cubic-bezier(.34, 1.4, .5, 1),
    transform .4s cubic-bezier(.34, 1.4, .5, 1);
}
.bp-cursor.active .bpc-arrow,
.bp-cursor.active .bpc-pill { opacity: 1; transform: scale(1); }
.bpc-arrow { width: 16px; height: 16px; flex: none; display: block; }
.bpc-arrow svg { width: 16px; height: 16px; display: block; overflow: visible; }
.bpc-pill {
  background: rgb(0, 150, 250); color: #fff; border-radius: 8px;
  padding: 4px 8px; font-size: 13px; font-weight: 500; letter-spacing: -.04em; line-height: 1.2;
  white-space: nowrap;
}
/* live: .framer-cursor-none * { cursor: none !important } within the cursor's region */
.bp-cursor-host, .bp-cursor-host * { cursor: none !important; }
@media (hover: none) { .bp-cursor { display: none; } .bp-cursor-host, .bp-cursor-host * { cursor: auto !important; } }


/* ===== The elements beside the laptop — live hover system =====
   JTBD component: 238x203, overflow visible. Three bubbles, each 200px wide with 12px padding
   and a 12px gap, fills rgb(76,76,76) / rgb(50,50,50) / rgb(34,34,34) at r10, each with a
   12x12 rgb(176,66,254) dot. Frame 50 also carries a base rotate of 1deg.
   Every bubble has its own onMouseEnter which switches the WHOLE group's variant, so all three
   reflow together and the hovered one scales to 1.2:
     variant 1 (base) TWqY2N7t7 · 2 fhrKDvw0c · 3 pAQQ3XHF6 · 4 XXW731J0p
   bottom/right per variant, straight from the live CSS:
                 base        v2          v3          v4
     Frame 50   124/20      124/20      137/19      134/-26
     Frame 54    45/34       27/34       45/34        76/59
     Frame 99    23/3        13/3         3/-27       29/19
   Motion is the section's own default transition, {duration:.9, ease:[.54,0,.28,1]}. ===== */
.bp-jtbd { position: relative; width: 238px; height: 203px; overflow: visible; flex: none; }
.jt {
  position: absolute; width: 200px; padding: 12px; border-radius: 10px;
  display: flex; flex-direction: row; gap: 12px; align-items: flex-start;
  transform-origin: 50% 50%;
  transition:
    bottom    .9s cubic-bezier(.54, 0, .28, 1),
    right     .9s cubic-bezier(.54, 0, .28, 1),
    transform .9s cubic-bezier(.54, 0, .28, 1);
}
.jt > i {
  flex: none; width: 12px; height: 12px; border-radius: 50%;
  background: rgb(176, 66, 254);
}
.jt > p {
  flex: 1 0 0; width: 1px;
  font-size: 13px; line-height: 1.3; letter-spacing: -.02em; color: #fff;
  display: flex; flex-direction: column; gap: 6px;
}
.jt > p > b { font-weight: 600; }
.jt1 { background: rgb(76, 76, 76); bottom: 124px; right: 20px; transform: rotate(1deg) scale(1); }
.jt2 { background: rgb(50, 50, 50); bottom: 45px;  right: 34px; transform: scale(1); }
.jt3 { background: rgb(34, 34, 34); bottom: 23px;  right: 3px;  transform: scale(1); }
/* variant 2 — Frame 50 hovered */
.bp-jtbd[data-variant="2"] .jt1 { transform: rotate(1deg) scale(1.2); }
.bp-jtbd[data-variant="2"] .jt2 { bottom: 27px; right: 34px; }
.bp-jtbd[data-variant="2"] .jt3 { bottom: 13px; right: 3px; }
/* variant 3 — Frame 54 hovered */
.bp-jtbd[data-variant="3"] .jt1 { bottom: 137px; right: 19px; }
.bp-jtbd[data-variant="3"] .jt2 { transform: scale(1.2); }
.bp-jtbd[data-variant="3"] .jt3 { bottom: 3px; right: -27px; }
/* variant 4 — Frame 99 hovered */
.bp-jtbd[data-variant="4"] .jt1 { bottom: 134px; right: -26px; }
.bp-jtbd[data-variant="4"] .jt2 { bottom: 76px;  right: 59px; }
.bp-jtbd[data-variant="4"] .jt3 { bottom: 29px;  right: 19px; transform: scale(1.2); }

/* ===== the persona — live Wireframe component, rebuilt from its own values =====
   Root 230x164, column, gap 6, padding 0 16px, r32 superellipse(1.5),
   background linear-gradient(180deg, rgba(35,35,35,0) 0%, rgb(35,35,35) 100%).
   Row (.n841v7): two cards flex:1 0 0, h54, padding 10, gap 6,
     background linear-gradient(180deg, rgba(25,25,25,0) 0%, rgb(25,25,25) 100%), r10 / r12
     inner row gap 12: 18x18 avatar rgb(44,44,44) r20 + column with a 4px rgb(68,68,68) r20 bar
     and a 61%-wide column holding a 2px rgb(44,44,44) r20 bar
   Chip row (.rdqbca): gap 2, two 44x17 chips — rgb(25,25,25) r12 and
     linear-gradient(90deg, rgb(25,25,25) 0%, rgba(25,25,25,0) 30%) r12
   Selected card (.1wnf79s): 203x61 at bottom 10 / right -12, with a 27x27 avatar at 17/16,
     a 64x6 line at 23/57, a 107x6 line at 32/57 and a 4x4 handle in each corner.
     (The card artwork itself is a runtime SVG sprite in the reference, so the pieces here are
     rebuilt at the live geometry in the live palette.)
   Cursor row (.wbffka): gap 7 at bottom -9 / left 128 — the real 16x16 rgb(254,75,66) arrow
     plus the Julia chip, padding 5px 10px, rgb(254,75,66), r8, Switzer 500 / -.04em / 120%.
   Hover (variant ehymq): the card row dims to .5 and scales .9; the selected card moves to
   bottom 14 / right 14; the cursor row to bottom -5 / right 54. ===== */
.bp-wire {
  position: relative; width: 230px; height: 164px; flex: none;
  display: flex; flex-direction: column; gap: 6px; padding: 0 16px;
  border-radius: 24.1px; border-radius: 32px; corner-shape: superellipse(1.5);
  background: linear-gradient(180deg, rgba(35, 35, 35, 0) 0%, rgb(35, 35, 35) 100%);
  overflow: visible;
}
.bpw-row {
  display: flex; flex-direction: row; gap: 6px; width: 100%;
  opacity: 1; transform: scale(1); transform-origin: 50% 50%;
  transition:
    opacity   .9s cubic-bezier(.54, 0, .28, 1),
    transform .9s cubic-bezier(.54, 0, .28, 1);
}
.bp-wire:hover .bpw-row, .bp-wire:focus-within .bpw-row { opacity: .5; transform: scale(.9); }
.bpw-card {
  flex: 1 0 0; width: 1px; height: 54px; padding: 10px;
  display: flex; flex-direction: column; gap: 6px;
  background: linear-gradient(180deg, rgba(25, 25, 25, 0) 0%, rgb(25, 25, 25) 100%);
  border-radius: 10px;
}
.bpw-card.b { border-radius: 12px; }
.bpw-line { display: flex; flex-direction: row; gap: 12px; width: 100%; }
.bpw-av { flex: none; width: 18px; height: 18px; border-radius: 20px; background: rgb(44, 44, 44); }
.bpw-txt { flex: 1 0 0; width: 1px; display: flex; flex-direction: column; gap: 0; }
.bpw-txt > b { display: block; width: 100%; height: 4px; border-radius: 20px; background: rgb(68, 68, 68); }
.bpw-txt > span { display: block; width: 61%; height: 2px; margin-top: 4px; border-radius: 20px; background: rgb(44, 44, 44); }
.bpw-chips { display: flex; flex-direction: row; gap: 2px; width: 100%; }
.bpw-chips em { display: block; width: 44px; height: 17px; border-radius: 12px; background: rgb(25, 25, 25); }
.bpw-chips em.fade { background: linear-gradient(90deg, rgb(25, 25, 25) 0%, rgba(25, 25, 25, 0) 30%); }
.bpw-sel {
  position: absolute; bottom: 10px; right: -12px; width: 203px; height: 61px;
  border: 1px solid rgb(68, 68, 68); border-radius: 6px; background: rgb(25, 25, 25);
  transition: bottom .9s cubic-bezier(.54, 0, .28, 1), right .9s cubic-bezier(.54, 0, .28, 1);
}
.bp-wire:hover .bpw-sel, .bp-wire:focus-within .bpw-sel { bottom: 14px; right: 14px; }
.bpw-sel-av { position: absolute; top: 17px; left: 16px; width: 27px; height: 27px; border-radius: 50%; background: rgb(44, 44, 44); }
.bpw-sel s { position: absolute; display: block; height: 6px; border-radius: 20px; background: rgb(68, 68, 68); }
.bpw-sel s.l1 { top: 23px; left: 57px; width: 64px; }
.bpw-sel s.l2 { top: 32px; left: 57px; width: 107px; background: rgb(44, 44, 44); }
.bpw-sel u.h { position: absolute; width: 4px; height: 4px; background: rgb(254, 75, 66); }
.bpw-sel u.tl { top: -2px; left: -2px; }
.bpw-sel u.tr { top: -2px; right: -2px; }
.bpw-sel u.bl { bottom: -2px; left: -2px; }
.bpw-sel u.br { bottom: -2px; right: -2px; }
.bpw-cur {
  position: absolute; bottom: -9px; left: 128px;
  display: flex; flex-direction: row; align-items: center; gap: 7px;
  transition: bottom .9s cubic-bezier(.54, 0, .28, 1),
              left   .9s cubic-bezier(.54, 0, .28, 1),
              right  .9s cubic-bezier(.54, 0, .28, 1);
}
.bp-wire:hover .bpw-cur, .bp-wire:focus-within .bpw-cur { bottom: -5px; left: auto; right: 54px; }
.bpw-cur img { display: block; width: 16px; height: 16px; }
.bpw-tag {
  background: rgb(254, 75, 66); color: #fff; border-radius: 8px; padding: 5px 10px;
  font-size: 12px; font-weight: 500; letter-spacing: -.04em; line-height: 1.2; white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
  .jt, .bpw-row, .bpw-sel, .bpw-cur { transition: none !important; }
}
