/* ==========================================================================
   KAIRO — dark-field system (v2 experiment)

   Adapted from the SYSTEM measured on inthebrandlab.com 2026-08-04
   (docs/teardown_brez_brandlab.md), rendered in Kairo's own identity.
   What was taken is the discipline, not the design:

   1. THREE VOICES, POLICED.
      Geist         — all structure, all body, all UI.
      Fraunces ital — the SECOND HALF OF A HEADLINE. Nowhere else. Ever.
      Geist Mono    — bracket labels only, 11-12px, 0.3em tracking, uppercase.
   2. ONE BOLD PER PAGE. Weight 700 belongs to the h1 and nothing else.
      Everything else lives at 300/400/500, occasionally 600.
   3. HIERARCHY FROM OPACITY, NOT FROM A GREY RAMP. White at 1/.78/.62/.45
      on the navy field. Guarantees harmony, removes a whole ramp of decisions.
   4. PILL-FIRST GEOMETRY. 999px for anything interactive, 20px for cards.
   5. ONE ACCENT HUE.

   Colour decisions specific to Kairo:
   - The field is navy because the LOGO is already a white mark on navy
     (#234468). A dark navy site is the logo's native habitat, so the mark
     needs no alteration to sit on it.
   - The accent moved from bronze #8F5423 to amber #E8A65C. Bronze on navy is
     muddy — brown-on-blue, and it fails contrast at small sizes. Amber keeps
     the warm identity (which suits outdoor living: sunset, wood, warm light)
     and actually reads. Deliberately NOT a green — that would be both
     derivative of Brand Lab and cold for this trade.
   ========================================================================== */

:root{
  /* Field — navy, pulled from the logo's own blue */
  --navy-950:#060D18;
  --navy-900:#0B1524;
  --navy-800:#122238;
  --navy-700:#1A3352;
  --navy-600:#234468;   /* the logo's blue, exactly */

  /* Text — opacity ladder, not a grey ramp */
  --t-1:rgba(255,255,255,1);
  --t-2:rgba(255,255,255,.78);
  --t-3:rgba(255,255,255,.62);
  --t-4:rgba(255,255,255,.45);
  --hair:rgba(255,255,255,.12);
  --hair-soft:rgba(255,255,255,.07);
  --sunk:rgba(255,255,255,.04);

  /* Paper — warm, never pure white */
  --paper:#F7F5F1;
  --paper-raised:#FFFFFF;

  /* Accent — ONE hue, two values, because one value cannot serve both
     surfaces. Amber reads on navy; on paper it is invisible. Bronze reads on
     paper; on navy it goes muddy. Same hue family, revalued per surface. */
  --accent:#E8A65C;
  --accent-dim:#C9873F;
  --accent-glow:rgba(232,166,92,.16);

  /* Card surface, as a variable so the same .card works on both fields */
  --card-bg:linear-gradient(180deg,rgba(255,255,255,.045),rgba(255,255,255,.015));

  /* Type scale */
  --f-mono:11px; --f-xs:13px; --f-sm:15px; --f-base:17px; --f-lg:19px;
  --f-xl:24px; --f-2xl:32px;
  --f-3xl:clamp(2rem,1.4rem + 2.6vw,3rem);
  --f-4xl:clamp(2.5rem,1.5rem + 4.2vw,4.25rem);
  --f-5xl:clamp(3rem,1.4rem + 6.4vw,5.75rem);

  --r-card:20px; --r-sm:12px; --r-pill:999px;
  --ease:cubic-bezier(.16,1,.3,1);
  --dur:420ms; --dur-micro:180ms;
  --container:74rem;
}

/* ---- The light surface ---------------------------------------------------
   Every component reads its colours from the variables above, so a section
   only has to REDECLARE them to invert. No component needs a light variant,
   and nothing can drift between the two surfaces.

   Why this exists at all: an all-dark site is fine for a short page, but this
   one has real reading on it (four build steps, a full scope list). Long body
   copy is measurably slower to read light-on-dark. Dark is for the moments —
   hero, closing — and paper is for anything anyone actually reads.          */
.light{
  --t-1:#0B1524;
  /* The ladder was .74 / .58 / .42. Measured against the warm paper that is
     4.9 / 4.4 / 2.7 to 1 — so rung three sat just under AA and rung four,
     which carries EVERY mono label, every card paragraph and every step
     bullet on this site, was at 2.7. Unreadable is not a style.

     The system's principle is kept: hierarchy still comes from opacity, not
     from a grey ramp. The range is simply compressed into the part of it that
     a human eye can actually resolve. Rung four now clears 4.5:1 and the
     spacing between rungs is still visible. This matters more here than on
     most sites — the audience is 40-60 year old contractors, which is exactly
     the group whose contrast sensitivity has started to drop. */
  --t-2:rgba(11,21,36,.80);
  --t-3:rgba(11,21,36,.70);
  --t-4:rgba(11,21,36,.62);
  --hair:rgba(11,21,36,.13);
  --hair-soft:rgba(11,21,36,.08);
  --sunk:rgba(11,21,36,.03);
  --accent:#8F5423;            /* bronze returns on paper */
  --accent-glow:rgba(143,84,35,.14);
  --card-bg:var(--paper-raised);
  background:var(--paper);
  color:var(--t-1);
}
.light .btn-white{background:var(--navy-900);color:#fff;}
/* .btn-primary paints --accent behind navy-950 text. That is correct on the
   navy field, where the accent is amber. On paper the accent revalues to
   bronze, so the same rule produced near-black on dark bronze — about 2:1,
   and it landed on "Show my estimate", the single most important control on
   the site. White text on bronze is ~5.9:1. */
.light .btn-primary{color:#fff;}
.light .btn-primary:hover{background:var(--accent);filter:brightness(1.12);}
.light .card{box-shadow:0 1px 2px rgba(11,21,36,.04),0 8px 24px rgba(11,21,36,.05);}
.light .stat{background:var(--paper);}

*,*::before,*::after{box-sizing:border-box;}
*{margin:0;}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;}
body{
  background:var(--navy-950); color:var(--t-1);
  font-family:'Geist','Geist Fallback',ui-sans-serif,system-ui,-apple-system,sans-serif;
  font-size:var(--f-base); line-height:1.6; font-weight:400;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  font-synthesis-weight:none;
  display:flex; flex-direction:column; min-height:100vh;
  overflow-x:hidden;
}
img,svg{display:block;max-width:100%;height:auto;}
a{color:inherit;text-decoration:none;}
ul{list-style:none;padding:0;}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;}
main{flex:1;}
::selection{background:var(--accent);color:var(--navy-950);}

/* ---- Type ---------------------------------------------------------------
   RULE: h1 is the ONLY 700 on a page. h2/h3 sit at 500-600 and get their
   presence from size and tracking, not from weight.                        */
h1,h2,h3{letter-spacing:-.035em;line-height:1.02;text-wrap:balance;font-weight:600;}
h1{font-size:var(--f-5xl);font-weight:700;}
h2{font-size:var(--f-4xl);}
h3{font-size:var(--f-xl);letter-spacing:-.02em;line-height:1.25;}
p{text-wrap:pretty;color:var(--t-2);}

/* THE SIGNATURE MOVE. The sans sets up, the italic serif pays off.
   Only ever applied to the closing phrase of a headline. */
.said{
  font-family:'Fraunces',Georgia,serif;
  font-style:italic; font-weight:400;
  letter-spacing:-.025em;
  color:var(--accent);
  /* Fraunces sits small next to Geist at the same px, so it is nudged up. */
  font-size:1.06em;
}
.said-plain{color:var(--t-1);}

/* Bracket label — the technical voice. Mono, wide tracking, always uppercase. */
.tag{
  display:inline-flex;align-items:center;gap:.7rem;
  font-family:'Geist Mono',ui-monospace,SFMono-Regular,monospace;
  font-size:var(--f-mono);font-weight:500;
  letter-spacing:.3em;text-transform:uppercase;
  color:var(--t-4);
}
.tag::before{content:"";width:1.75rem;height:1px;background:currentColor;opacity:.5;}
.tag.no-rule::before{display:none;}
.tag.accent{color:var(--accent);}

.lead{font-size:var(--f-lg);line-height:1.65;color:var(--t-2);font-weight:300;}
.measure{max-width:38rem;} .measure-lg{max-width:46rem;}
.mx-auto{margin-inline:auto;} .center{text-align:center;}
.mt-2{margin-top:.5rem}.mt-3{margin-top:.9rem}.mt-4{margin-top:1.4rem}
.mt-5{margin-top:2rem}.mt-6{margin-top:3rem}.mt-8{margin-top:5rem}

/* ---- Layout -------------------------------------------------------------- */
.container{width:100%;margin-inline:auto;padding-inline:1.5rem;max-width:var(--container);}
@media(min-width:768px){.container{padding-inline:2.5rem;}}
.section{padding-block:clamp(4.5rem,2rem + 8vw,8rem);position:relative;}
.section-tight{padding-block:clamp(3rem,1.5rem + 5vw,5rem);position:relative;}
.rule{height:1px;background:var(--hair-soft);}

/* The field: a navy wash that is darker at the edges than the middle, so
   content sits in a pool of light rather than on a flat rectangle. */
.field{position:relative;isolation:isolate;}
.field::before{
  content:"";position:absolute;inset:0;z-index:-2;
  background:
    radial-gradient(120% 90% at 12% 0%, var(--navy-700) 0%, transparent 62%),
    radial-gradient(100% 80% at 92% 8%, var(--navy-600) 0%, transparent 55%),
    linear-gradient(180deg, var(--navy-900) 0%, var(--navy-950) 78%);
}
/* Faint engineering grid. It is a build company; the grid is the one texture
   that is on-message rather than decorative. */
.field::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:
    linear-gradient(var(--hair-soft) 1px,transparent 1px),
    linear-gradient(90deg,var(--hair-soft) 1px,transparent 1px);
  background-size:80px 80px;
  mask-image:radial-gradient(120% 80% at 50% 0%,#000 0%,transparent 75%);
  -webkit-mask-image:radial-gradient(120% 80% at 50% 0%,#000 0%,transparent 75%);
  opacity:.5;
}

/* ---- Nav ---------------------------------------------------------------- */
.navwrap{position:fixed;inset-inline:0;top:0;z-index:60;padding-top:1.1rem;
  transition:transform var(--dur) var(--ease);}
.navwrap.scrolled{transform:translate3d(0,-.35rem,0);}
.nav{display:flex;justify-content:center;padding-inline:1.5rem;}
.nav-pill{
  display:flex;align-items:center;justify-content:space-between;gap:2rem;
  width:100%;max-width:var(--container);
  padding:.7rem .8rem .7rem 1.15rem;border-radius:var(--r-pill);
  border:1px solid transparent;
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),
             box-shadow var(--dur) var(--ease);
}
.navwrap.scrolled .nav-pill{
  background:rgba(11,21,36,.72);
  -webkit-backdrop-filter:blur(18px) saturate(170%);
  backdrop-filter:blur(18px) saturate(170%);
  border-color:var(--hair);
  box-shadow:0 10px 40px rgba(0,0,0,.42);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .navwrap.scrolled .nav-pill{background:rgba(11,21,36,.97);}
}
.brand{display:flex;align-items:center;gap:.6rem;flex-shrink:0;font-weight:600;
  letter-spacing:-.03em;font-size:1.0625rem;}
.brand img{width:26px;height:26px;}
.nav-links{display:none;align-items:center;gap:.35rem;}
@media(min-width:900px){.nav-links{display:flex;}}
.nav-links a{padding:.5rem .9rem;border-radius:var(--r-pill);font-size:var(--f-xs);
  color:var(--t-3);transition:color var(--dur-micro) var(--ease),background var(--dur-micro) var(--ease);}
.nav-links a:hover{color:var(--t-1);background:var(--sunk);}

/* ---- Buttons — pill first ------------------------------------------------ */
.btn{
  display:inline-flex;align-items:center;gap:.55rem;
  padding:.8rem 1.4rem;border-radius:var(--r-pill);
  font-size:var(--f-xs);font-weight:500;letter-spacing:-.01em;
  transition:transform var(--dur-micro) var(--ease),background var(--dur-micro) var(--ease),
             box-shadow var(--dur-micro) var(--ease),border-color var(--dur-micro) var(--ease);
  will-change:transform;
}
.btn:hover{transform:translateY(-1px);}
.btn-primary{background:var(--accent);color:var(--navy-950);font-weight:600;
  box-shadow:0 6px 22px var(--accent-glow);}
.btn-primary:hover{background:#F0B472;box-shadow:0 10px 30px rgba(232,166,92,.26);}
.btn-ghost{border:1px solid var(--hair);color:var(--t-2);}
.btn-ghost:hover{border-color:rgba(255,255,255,.3);color:var(--t-1);background:var(--sunk);}
.btn-white{background:#fff;color:var(--navy-950);font-weight:600;}
.btn .arw{transition:transform var(--dur-micro) var(--ease);}
.btn:hover .arw{transform:translateX(3px);}

/* ---- Cards --------------------------------------------------------------- */
.card{
  border:1px solid var(--hair);border-radius:var(--r-card);
  background:var(--card-bg);
  padding:1.9rem;
  transition:border-color var(--dur) var(--ease),transform var(--dur) var(--ease),
             background var(--dur) var(--ease);
}
.card.lift:hover{transform:translateY(-3px);border-color:rgba(255,255,255,.24);}
.card h3{color:var(--t-1);}
.card p{color:var(--t-3);font-size:var(--f-sm);margin-top:.7rem;}
.grid{display:grid;gap:1.1rem;}
@media(min-width:700px){.g2{grid-template-columns:repeat(2,1fr);}
  .g3{grid-template-columns:repeat(3,1fr);}}
@media(max-width:699px){.g3{grid-template-columns:1fr;}}

/* ---- Step rows — the named-method page ---------------------------------- */
.step{display:grid;gap:1.6rem;padding-block:3.2rem;border-top:1px solid var(--hair-soft);}
@media(min-width:900px){.step{grid-template-columns:14rem 1fr;gap:3rem;}}
.step-n{font-family:'Geist Mono',ui-monospace,monospace;font-size:3.5rem;
  font-weight:500;color:var(--t-4);line-height:1;letter-spacing:-.04em;}
.step h3{font-size:var(--f-2xl);letter-spacing:-.03em;line-height:1.15;}
.step ul{margin-top:1.5rem;display:grid;gap:.6rem;}
.step li{position:relative;padding-left:1.4rem;color:var(--t-3);font-size:var(--f-sm);}
.step li::before{content:"";position:absolute;left:0;top:.62em;width:5px;height:5px;
  border-radius:50%;background:var(--accent);opacity:.85;}
.step .close{margin-top:1.5rem;padding-top:1.2rem;border-top:1px solid var(--hair-soft);
  color:var(--t-4);font-size:var(--f-sm);}

/* ---- Stat strip ---------------------------------------------------------- */
.stats{display:grid;gap:1px;background:var(--hair-soft);border-block:1px solid var(--hair-soft);}
@media(min-width:700px){.stats{grid-template-columns:repeat(3,1fr);}}
.stat{background:transparent;padding:2.2rem 1.5rem;text-align:center;}
.stat b{display:block;font-size:2.5rem;font-weight:500;letter-spacing:-.04em;line-height:1;}
.stat span{display:block;margin-top:.8rem;font-family:'Geist Mono',ui-monospace,monospace;
  font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:var(--t-4);}

/* ---- Motion — one curve, and it respects the user --------------------------
   Preferred path is a SCROLL-DRIVEN animation: animation-timeline runs on the
   compositor, so the reveal is tied to scroll position rather than to a JS
   callback, and it cannot jank the main thread. The IntersectionObserver in
   base.html is the fallback for browsers without it, and the script checks
   CSS.supports() so the two never both run.                                  */
@supports (animation-timeline: view()){
  .rise{
    opacity:1;transform:none;
    animation:rise-scroll linear both;
    animation-timeline:view();
    animation-range:entry 2% cover 26%;
  }
  @keyframes rise-scroll{
    from{opacity:0;transform:translateY(26px);}
    to{opacity:1;transform:none;}
  }
  /* The hero settles as it leaves — a slow drift, not a parallax gimmick. */
  .hero-drift{
    animation:hero-settle linear both;
    animation-timeline:view();
    animation-range:exit 0% exit 90%;
  }
  @keyframes hero-settle{
    from{opacity:1;transform:none;}
    to{opacity:.32;transform:translateY(-26px);}
  }
}

.rise{opacity:0;transform:translateY(18px);
  transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease);}
.rise.in{opacity:1;transform:none;}
.stagger>*{opacity:0;transform:translateY(16px);
  animation:rise-in .7s var(--ease) forwards;
  animation-delay:calc(var(--i,0) * 70ms);}
@keyframes rise-in{to{opacity:1;transform:none;}}
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important;}
  .rise{opacity:1;transform:none;}
  .stagger>*{opacity:1;transform:none;animation:none;}
}

/* ---- Footer -------------------------------------------------------------- */
footer{border-top:1px solid var(--hair-soft);padding-block:3.5rem 2.5rem;}
.foot-grid{display:grid;gap:2.5rem;}
@media(min-width:760px){.foot-grid{grid-template-columns:1.6fr 1fr 1fr;}}
footer a{color:var(--t-3);font-size:var(--f-xs);transition:color var(--dur-micro) var(--ease);}
footer a:hover{color:var(--accent);}
footer li{margin-top:.55rem;}
.foot-bottom{margin-top:3rem;padding-top:1.6rem;border-top:1px solid var(--hair-soft);
  display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;
  color:var(--t-4);font-size:var(--f-xs);}

.skip{position:absolute;left:-9999px;}
.skip:focus{left:1rem;top:1rem;z-index:99;background:var(--accent);
  color:var(--navy-950);padding:.7rem 1.1rem;border-radius:var(--r-pill);}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px;}

/* ---- .prose — long-form document pages (/terms/) ------------------------- */
.prose h1{font-size:var(--f-3xl);letter-spacing:-.03em;line-height:1.1;}
.prose h2{font-size:var(--f-xl);margin-top:3.25rem;padding-top:1.9rem;border-top:1px solid var(--hair-soft);}
.prose hr+h2{margin-top:0;padding-top:0;border-top:0;}
.prose h3{font-size:var(--f-lg);margin-top:1.9rem;}
.prose p{margin-top:1rem;line-height:1.72;}
.prose ul{margin-top:1rem;padding-left:1.35rem;}   /* never flex — kills markers */
.prose li{list-style:disc;margin-top:.5rem;color:var(--t-3);}
.prose li::marker{color:var(--t-4);}
.prose strong{color:var(--t-1);font-weight:600;}
.prose code{font-family:'Geist Mono',ui-monospace,monospace;font-size:.875em;
  background:var(--sunk);padding:.1em .35em;border-radius:5px;}
.prose hr{border:0;border-top:1px solid var(--hair-soft);margin:2.5rem 0;}
.prose blockquote{margin-top:1.5rem;padding:1.2rem 1.4rem;border-radius:var(--r-sm);
  background:var(--sunk);border-left:3px solid var(--accent);line-height:1.65;}

/* Exclusion list — needs a visible marker or the items read as loose
   paragraphs. A rule-and-cross, not a bullet: these are things you do NOT get. */
.excl{display:grid;gap:0;}
.excl li{position:relative;padding:.95rem 0 .95rem 2rem;color:var(--t-3);
  font-size:var(--f-sm);border-top:1px solid var(--hair-soft);}
.excl li:last-child{border-bottom:1px solid var(--hair-soft);}
.excl li::before{content:"";position:absolute;left:.45rem;top:1.35em;
  width:9px;height:1px;background:var(--t-4);}

/* ---- Instant Estimator demo ---------------------------------------------
   Demonstrates two deliverables at once: the signature feature, and the
   low-friction lead capture the design language asks for (max two required
   fields, the price gated behind them). */
.est-label{display:block;font-size:.9375rem;font-weight:500;color:var(--t-1);
  margin-bottom:.5rem;margin-top:1.25rem}
.est-label:first-of-type{margin-top:1.25rem}
.est-input{width:100%;font:inherit;font-size:1rem;color:var(--t-1);
  background:var(--paper-raised);border:1px solid var(--hair);
  border-radius:var(--r-sm);padding:.85rem 1rem;
  transition:border-color var(--dur-micro) var(--ease);min-height:48px}
.est-input:focus{outline:2px solid var(--accent);outline-offset:2px;border-color:transparent}
.est-hint{margin-top:.5rem;font-size:.8125rem;color:var(--t-4)}
.est-gate{margin-top:1.75rem;padding-top:1.5rem;border-top:1px solid var(--hair-soft)}
.est-gate-title{font-size:.9375rem;font-weight:500;color:var(--t-1)}
.est-result{margin-top:1.75rem;padding-top:1.5rem;border-top:1px solid var(--hair-soft)}
.est-range{font-size:clamp(2rem,5vw,3rem);font-weight:700;letter-spacing:-.04em;
  line-height:1.05;margin-top:.9rem;color:var(--t-1)}
.est-note{margin-top:.7rem;font-size:.9375rem;color:var(--t-3)}
.est-disclaimer{margin-top:1rem;font-size:.8125rem;color:var(--t-4);line-height:1.5}
.est-source{margin-top:1.5rem;font-size:.8125rem;color:var(--t-4);line-height:1.6;text-align:center}
.est-source strong{color:var(--t-2);font-weight:600}
.est-error{color:#B4443F;font-size:.8125rem;margin-top:.5rem}

/* ==========================================================================
   LIVE LAYER — added 2026-08-05

   The v2 base was correct and completely inert: every surface was a flat
   gradient, nothing moved until you scrolled, and the hero's right half was
   empty. This layer is what makes it feel built rather than typeset.

   The rule for everything below: ANIMATE ONLY transform AND opacity. Those two
   run on the compositor and never touch layout or paint, so all of this costs
   effectively nothing per frame. Anything that would repaint (a moving
   gradient, a filter) is done once, on a promoted layer, at low frequency —
   never bound to scroll or pointer.
   ========================================================================== */

/* ---- 1. The field breathes ------------------------------------------------
   Two soft light pools drifting on a long loop. This is the difference between
   a background and a room. They are plain radial gradients on their own layer,
   moved with transform only, so the browser composites them and never repaints.
   40s and 55s are deliberately coprime — the pair never visibly repeats.      */
/* .field must clip. The aurora box is deliberately larger than the section so
   the pools can bleed in from off-edge, and without this it widened the
   document by 31px at 390px — a horizontal scrollbar on every phone, caused
   entirely by decoration. Verified with Playwright at 390x844. */
.field{overflow:hidden;}
.aurora{
  position:absolute;inset:-12% -8%;z-index:-2;pointer-events:none;
  overflow:hidden;contain:strict;
}
.aurora i{
  position:absolute;display:block;border-radius:50%;
  will-change:transform;
  filter:blur(60px);
  opacity:.55;
}
/* The pools sit INSIDE the visible area. An earlier pass had them at inset
   -30%, which put both centres above the fold — the drift ran perfectly and
   was almost entirely off-screen. */
.aurora i:nth-child(1){
  width:50vw;height:50vw;left:-8%;top:6%;
  background:radial-gradient(circle,rgba(35,68,104,.9) 0%,rgba(35,68,104,0) 68%);
  animation:drift-a 44s ease-in-out infinite;
}
.aurora i:nth-child(2){
  width:42vw;height:42vw;right:-2%;top:0%;
  background:radial-gradient(circle,rgba(232,166,92,.17) 0%,rgba(232,166,92,0) 66%);
  animation:drift-b 61s ease-in-out infinite;
}
@keyframes drift-a{
  0%,100%{transform:translate3d(0,0,0) scale(1);}
  33%    {transform:translate3d(8vw,4vh,0) scale(1.14);}
  66%    {transform:translate3d(3vw,-5vh,0) scale(.93);}
}
@keyframes drift-b{
  0%,100%{transform:translate3d(0,0,0) scale(1);}
  40%    {transform:translate3d(-9vw,6vh,0) scale(1.2);}
  75%    {transform:translate3d(-2vw,-3vh,0) scale(.95);}
}

/* ---- 2. Cursor spotlight --------------------------------------------------
   The one move that reads as "this page is aware of me". A fixed-size disc of
   warm light that follows the pointer and brightens the engineering grid under
   it. It is MOVED WITH TRANSFORM, never by redrawing a gradient at a new
   position — that distinction is the whole reason this is free.

   Hidden until the pointer actually arrives (.on), so it never flashes at 0,0
   on load, and it is never created at all on touch (no hover => no cursor).  */
.spot{
  position:absolute;top:0;left:0;width:38rem;height:38rem;
  margin:-19rem 0 0 -19rem;
  z-index:-1;pointer-events:none;
  background:radial-gradient(circle closest-side,
    rgba(232,166,92,.10) 0%, rgba(232,166,92,.045) 38%, transparent 70%);
  opacity:0;transition:opacity 600ms var(--ease);
  will-change:transform;
}
.spot.on{opacity:1;}
@media(hover:none){.spot{display:none;}}

/* The grid gains a little contrast so the spotlight has something to catch. */
.field::after{opacity:.62;}

/* ---- 3. Headline reveal ---------------------------------------------------
   The signature move of the type system is that the sans sets up and the italic
   pays off. The reveal now PERFORMS that: the sans rises first, the italic
   lands 180ms behind it.

   Deliberately CSS-only, no JS and no observer. A JS mount animation freezes at
   opacity 0 in any tab that starts hidden (a background tab, a link opened in
   the background, our own preview pane) — which means the headline is invisible
   in exactly the case you cannot see to debug. CSS animations run regardless. */
/* padding/margin pair: the mask must clip the rising text but must NOT clip the
   descenders of the settled text. */
.rv{overflow:hidden;display:block;padding-bottom:.14em;margin-bottom:-.14em;}
.rv>span{
  display:block;
  animation:rv-up 1.15s var(--ease) both;
}
.rv-late>span{animation-delay:.18s;}
@keyframes rv-up{
  from{transform:translate3d(0,110%,0);opacity:0;}
  to  {transform:translate3d(0,0,0);opacity:1;}
}

/* ---- 4. Magnetic buttons --------------------------------------------------
   The pointer pulls the pill toward it inside a small radius. The offset is set
   by JS as two custom properties; the transform itself lives here, so the JS
   never touches style.transform directly and there is a single source of truth
   for the resting state.                                                     */
.btn{--bx:0px;--by:0px;
  transform:translate3d(var(--bx),var(--by),0);}
.btn:hover{transform:translate3d(var(--bx),calc(var(--by) - 1px),0);}
.btn-primary{position:relative;overflow:hidden;}
/* A slow sheen crossing the primary action. Once every 6s, transform-only. */
.btn-primary::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.42) 50%,transparent 62%);
  transform:translate3d(-120%,0,0);
  animation:sheen 6s ease-in-out 1.6s infinite;
}
@keyframes sheen{0%,72%{transform:translate3d(-120%,0,0);}88%,100%{transform:translate3d(120%,0,0);}}

/* ---- 5. Cards that answer the cursor -------------------------------------
   A card should acknowledge the pointer before it is clicked. Two signals: the
   border picks up the accent, and a soft pool of light tracks the cursor across
   the surface. Both are opacity-gated so an untouched card is exactly as it was.
   The gradient position is a custom property rather than a moving element,
   because a card is small and repaints cheaply — and only while hovered.     */
.card{position:relative;overflow:hidden;--cx:50%;--cy:0%;}
.card::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(20rem 20rem at var(--cx) var(--cy),
    var(--accent-glow),transparent 68%);
  opacity:0;transition:opacity 320ms var(--ease);
}
.card.lift:hover::before{opacity:1;}
.card.lift:hover{border-color:rgba(232,166,92,.34);}
.light .card.lift:hover{border-color:rgba(143,84,35,.3);}
.card>*{position:relative;}

/* ---- 6. Nav that reacts ---------------------------------------------------
   Before: the pill only faded a background in. Now it also tightens — narrower,
   shorter, tucked up. Reads as the page acknowledging that you have started
   reading, which is the cheapest possible way to feel responsive.            */
.navwrap.scrolled .nav-pill{max-width:64rem;padding-block:.5rem;}
/* The scrolled pill was 72% navy over a backdrop blur. On the navy field that
   is glass; over the paper sections it blurs paper and lands as a muddy grey
   slab — the one element on the site that looked cheap. Raising the alpha keeps
   it glass on navy and makes it a clean deep pill on paper. */
.navwrap.scrolled .nav-pill{background:rgba(9,17,30,.9);}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .navwrap.scrolled .nav-pill{background:rgba(9,17,30,.98);}
}
.nav-pill{transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),
  box-shadow var(--dur) var(--ease),max-width var(--dur) var(--ease),padding var(--dur) var(--ease);}
/* Underline that grows from the left rather than a background swap. */
.nav-links a{position:relative;}
.nav-links a::after{
  content:"";position:absolute;left:.9rem;right:.9rem;bottom:.28rem;height:1px;
  background:var(--accent);transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-micro) var(--ease);
}
.nav-links a:hover{background:transparent;}
.nav-links a:hover::after{transform:scaleX(1);}

/* ---- 7. The seam ----------------------------------------------------------
   Navy meeting paper was a hard horizontal cut — it read as two sites glued
   together. A short gradient band on the paper section's leading edge lets one
   surface arrive rather than start.

   A first attempt washed 7rem of navy at 16% over the paper. On a warm paper
   that reads as a flat grey band, not as a transition — the wash was visible
   as an object in its own right. What actually works is a short, steep falloff
   that behaves like contact shadow: the paper looks like it is sitting ON the
   navy rather than butted against it. 2.5rem, and gone.                      */
.light{position:relative;}
.light::before{
  content:"";position:absolute;left:0;right:0;top:0;height:2.5rem;pointer-events:none;
  background:linear-gradient(180deg,rgba(11,21,36,.10),rgba(11,21,36,.02) 55%,transparent);
}
/* The seam is a NAVY-MEETS-PAPER treatment. Two paper sections in a row are
   already the same surface, so a shadow between them is just a dirty line
   across the middle of the page — which is exactly what it looked like. */
.light + .light::before,
.stats.light::before{display:none;}

/* ---- 8. Hero proof panel --------------------------------------------------
   The hero's right half was empty at every width above 1100px, and five pages
   described the Instant Estimator without ever showing one. This panel fixes
   both at once: it fills the column with the product rather than with
   decoration, and it is the only element on the page that demonstrates instead
   of asserting.

   The numbers are the same published Orange County market rates the estimator
   page runs on (Patio Warehouse Inc. 2026 guide) — not invented, and not
   presented as any contractor's own pricing.                                 */
.hero-grid{display:grid;gap:3.5rem;align-items:center;}
@media(min-width:1080px){
  .hero-grid{grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);gap:4rem;}
}
/* On a phone the panel stacks under the copy, so the hero's desktop top
   padding pushed it a long way below the fold. !important because the padding
   is an inline style on the section. */
@media(max-width:767px){
  .field.hero-drift{padding-top:7.5rem!important;padding-bottom:3.5rem!important;}
  .hero-grid{gap:2.5rem;}
}
.mock{
  border:1px solid var(--hair);border-radius:18px;
  background:linear-gradient(168deg,rgba(255,255,255,.07),rgba(255,255,255,.022));
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  box-shadow:0 30px 80px -20px rgba(0,0,0,.6),0 2px 0 0 rgba(255,255,255,.06) inset;
  overflow:hidden;
  animation:mock-in 1.2s var(--ease) .45s both;
}
@keyframes mock-in{from{opacity:0;transform:translate3d(0,26px,0) scale(.985);}
  to{opacity:1;transform:none;}}
/* A very slow float, so the panel is never quite still. 1.5px, 9s — under the
   threshold where it reads as movement, above the threshold where it reads as
   a screenshot. */
.mock-float{animation:mock-float 9s ease-in-out infinite;}
@keyframes mock-float{0%,100%{transform:translate3d(0,0,0);}50%{transform:translate3d(0,-6px,0);}}
.mock-bar{
  display:flex;align-items:center;gap:.5rem;
  padding:.7rem .9rem;border-bottom:1px solid var(--hair-soft);
  background:rgba(255,255,255,.03);
}
.mock-bar u{display:block;width:8px;height:8px;border-radius:50%;background:var(--hair);}
.mock-url{
  margin-left:.4rem;flex:1;text-align:center;
  font-family:'Geist Mono',ui-monospace,monospace;font-size:10px;letter-spacing:.12em;
  color:var(--t-4);background:rgba(255,255,255,.04);
  border-radius:var(--r-pill);padding:.3rem .8rem;
}
.mock-body{padding:1.5rem 1.5rem 1.6rem;}
.mock-row{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;
  padding:.7rem 0;border-bottom:1px solid var(--hair-soft);font-size:var(--f-xs);}
.mock-row span:first-child{color:var(--t-4);}
.mock-row span:last-child{color:var(--t-2);font-weight:500;}
.mock-out{margin-top:1.4rem;}
.mock-num{
  font-size:clamp(1.75rem,1.1rem + 1.7vw,2.4rem);font-weight:600;letter-spacing:-.04em;
  line-height:1.05;margin-top:.55rem;
  font-variant-numeric:tabular-nums;   /* so the count-up cannot reflow */
}
.mock-sub{margin-top:.5rem;font-size:12px;color:var(--t-4);line-height:1.5;}
/* The lead notification. Deliberately says only that a lead was sent — no
   invented name, no invented result. It demonstrates the mechanism.          */
.mock-toast{
  display:flex;align-items:center;gap:.65rem;
  margin-top:1.3rem;padding:.75rem .9rem;
  border:1px solid rgba(232,166,92,.26);border-radius:12px;
  background:rgba(232,166,92,.07);
  font-size:12px;color:var(--t-2);
  animation:toast-in 700ms var(--ease) 2.1s both;
}
@keyframes toast-in{from{opacity:0;transform:translate3d(0,10px,0);}to{opacity:1;transform:none;}}
.mock-dot{width:7px;height:7px;border-radius:50%;background:var(--accent);flex-shrink:0;
  box-shadow:0 0 0 0 var(--accent-glow);animation:pulse 2.4s ease-out infinite;}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(232,166,92,.5);}
  70%,100%{box-shadow:0 0 0 9px rgba(232,166,92,0);}}

/* ---- 9. Split section header ---------------------------------------------
   Every interior section was a 46rem block pinned left, which meant that above
   about 1100px the right-hand HALF of the page was empty on every screen. That
   is not confident whitespace, it reads as unfinished.

   The fix is editorial rather than decorative: the headline takes the left
   column and its body copy takes the right, so the section uses its width
   without a single word being added. Below 1000px it stacks back into exactly
   the block it was, so nothing changes on a phone.                           */
.split{display:grid;gap:1.4rem;}
@media(min-width:1000px){
  .split{grid-template-columns:minmax(0,1fr) minmax(0,.86fr);gap:4.5rem;align-items:start;}
  /* Optical, not mathematical: cap-height sits below the line box, so a body
     paragraph aligned to the same grid line reads high against a large h2. */
  .split-b{padding-top:.6rem;}
}
.split-b p + p{margin-top:1.1rem;}
.split-a h2{margin-top:.9rem;}

/* ---- 10. Stat count-up ---------------------------------------------------- */
.stat b{font-variant-numeric:tabular-nums;}

/* ---- 11. Respect the user -------------------------------------------------
   One switch. Everything above is decoration; none of it carries meaning that
   is lost when it stops, so all of it stops.                                 */
@media(prefers-reduced-motion:reduce){
  .aurora i,.mock-float,.mock-dot,.btn-primary::after{animation:none!important;}
  .spot{display:none;}
  .rv>span,.mock,.mock-toast{animation:none!important;opacity:1!important;transform:none!important;}
}
