/* Below-fold sections. Whole-site-animated standard: one living element per
   section at whisper level, entrances choreographed, nothing snaps. */

/* ---------- nav ---------- */

/* 12 September 2026, Phase 1: the nav is a floating pill inset from the top,
   glass fill and hairline border from first paint. The old transparent-then-
   solid phase is gone; .solid now only deepens the fill slightly on scroll. */
.nav{
  position:fixed;
  top:12px;
  left:50%;
  right:auto;
  transform:translateX(-50%);
  width:min(1180px,calc(100% - 2*var(--gut)));
  z-index:50;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:18px;
  padding:8px 10px 8px 16px;
  border-radius:999px;
  border:1px solid var(--hairline);
  background:rgba(14,20,32,.72);
  backdrop-filter:blur(14px);
  box-shadow:0 10px 40px rgba(0,0,0,.35);
  transition:background .5s var(--ease),box-shadow .5s var(--ease);
}
.nav.solid{
  background:rgba(14,20,32,.82);
}
/* fix, 23 August 2026 (phone report): on the static-hero breakpoints the nav's
   transparent phase (JS only adds .solid past 60% of one viewport's worth of
   scroll) let the compact static hero copy scroll up and show through the
   fixed, transparent nav within the first few hundred px, producing the
   overlapping-text look on phones. The 60%-scroll threshold assumes the full
   100vh sticky animated stage, which the phone breakpoint never uses. Same
   breakpoints as .static-hero in hero.css: skip the transparent phase there
   and stay solid from first paint, independent of scroll position. */
@media (max-width: 720px),
       (orientation: portrait) and (max-width: 1024px),
       (orientation: portrait) and (pointer: coarse),
       (orientation: landscape) and (pointer: coarse) and (max-height: 560px),
       (prefers-reduced-motion: reduce){
  .nav{
    background:rgba(14,20,32,.82);
  }
}
.nav .brand{
  display:flex;
  align-items:center;
  gap:12px;
  text-decoration:none;
  color:var(--text-primary);
}
.nav .brand img{height:38px;width:auto;display:block}
.nav .brand .name{
  font-family:var(--display);
  font-weight:700;
  font-size:19px;
  letter-spacing:.01em;
}
.nav .links{
  display:flex;
  align-items:baseline;
  gap:26px;
}
.nav .links a{
  color:var(--text-secondary);
  text-decoration:none;
  font-size:13.5px;
  font-weight:500;
  letter-spacing:.05em;
  transition:color .3s var(--ease);
}
.nav .links a:hover{color:var(--text-primary)}
.nav .btn{padding:10px 18px;font-size:14px;border-radius:999px}
@media (max-width:860px){
  /* 24 August 2026 (phone report): the "Book a Free Consult" button stayed
     in the top bar alongside the hamburger and wrapped to two lines on
     narrow phones, making the nav taller than the fixed 66px the dropdown
     menu below assumes, so the menu's first item (Impact) rendered partly
     under the nav. The button is already the first link inside the
     dropdown, so drop it from the bar entirely here and keep the bar to a
     single line: logo and hamburger only. */
  .nav .links a{display:none}
}

/* ---------- section scaffolding ---------- */

/* 13 September 2026, Phase 3 density pass: 12vh top and bottom meant two
   adjacent boundaries could eat a full viewport between them, which is the
   "empty screens" finding in the 12 Sep audit. 8vh still reads as a section
   break and removes the dead scroll. */
.section{
  position:relative;
  padding:clamp(64px,8vh,104px) 0;
}
.section .head{max-width:720px}
/* 23 August 2026: 12vh of section padding on both sides of every boundary
   read as a dead gap on a phone, not a section break. Tighten to a padding
   that still signals "new section" without the empty scroll. */
@media (max-width:720px){
  .section{padding:52px 0}
}

/* alternating skeletons so no two neighbors match */
.split{
  display:grid;
  grid-template-columns:5fr 7fr;
  gap:clamp(28px,5vw,72px);
  align-items:start;
}
.split.rev{grid-template-columns:7fr 5fr}
@media (max-width:900px){
  .split,.split.rev{grid-template-columns:1fr}
}

/* Phase 3: hairline cards share edges rather than float apart, so the gap
   closes from 22 to 18 and the grid sits nearer its heading. */
.grid-3{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:18px;
  margin-top:44px;
}
.grid-2{
  display:grid;
  grid-template-columns:repeat(2,1fr);
  gap:18px;
  margin-top:44px;
}
@media (max-width:900px){
  .grid-3{grid-template-columns:1fr}
  .grid-2{grid-template-columns:1fr}
}

/* ---------- cards ---------- */

/* 13 September 2026, Phase 3: the rounded, filled, blue-glowing card is the
   visual language of a SaaS template and it was the loudest thing separating
   us from the reference builds. Square, unfilled, one hairline. Hover
   brightens the edge and lays down a 3% white wash, nothing lifts, nothing
   glows. Actions stay pills; surfaces are square. That contrast is the point. */
.card{
  position:relative;
  background:transparent;
  border:1px solid var(--hairline);
  border-radius:0;
  padding:30px 28px;
  overflow:hidden;
  transition:border-color .45s var(--ease),background .45s var(--ease);
}
.card:hover{
  border-color:var(--border-strong);
  background:rgba(232,238,245,.03);
}
.card h3{font-size:21px;margin:14px 0 10px}
.card p{color:var(--text-secondary);font-size:15.5px;margin:0}
.card .mark{
  width:34px;height:34px;
  color:var(--text-secondary);
  opacity:.9;
}

/* ---------- entrance choreography ---------- */

.io .part{
  opacity:0;
  transform:translateY(26px);
  transition:opacity .8s var(--ease-out),transform .8s var(--ease-out);
}
.io.in .part{opacity:1;transform:none}
.io.in .part:nth-child(2){transition-delay:.09s}
.io.in .part:nth-child(3){transition-delay:.18s}
.io.in .part:nth-child(4){transition-delay:.27s}
.io.in .part:nth-child(5){transition-delay:.36s}
.io.in .part:nth-child(6){transition-delay:.45s}
/* retire the stagger after entry so hovers never lag; matches specificity */
.io.done .part:nth-child(n){transition-delay:0s}

/* ---------- the seam (signature element) ---------- */

.seam-wrap{
  position:absolute;
  inset:0;
  pointer-events:none;
  z-index:0;
}
.seam{
  position:absolute;
  left:0;top:0;
  width:100%;height:100%;
}
.seam path{
  fill:none;
  stroke:var(--text-secondary);
  stroke-width:1.6;
  opacity:.5;
  filter:none;
}
.seam .node{
  fill:var(--text-secondary);
  opacity:.55;
}
.paused-ok .seam .node{animation:nodepulse 6s var(--ease) infinite}
.seam .node:nth-of-type(2){animation-delay:-1.2s}
.seam .node:nth-of-type(3){animation-delay:-2.6s}
.seam .node:nth-of-type(4){animation-delay:-4.1s}
@keyframes nodepulse{
  0%,100%{opacity:.35}
  50%{opacity:.85}
}

/* ---------- process: the horizontal pipeline ---------- */

/* 13 September 2026, Phase 3: the four steps were a vertical stack of
   border-left cards. Shaped as a connected horizontal run they read as a
   system rather than a list, which is the one structural idea worth taking
   from the reference build.

   Two constraints this shape has to respect:
   1. main.js lightSteps() queries #steps for .step and toggles .lit as the
      hold fills, so both hooks survive the reshape. The hold now lights the
      pipeline stage by stage, left to right, which is a better payoff than
      the vertical version ever had.
   2. .rail was already claimed twice on this page, by the hero chapter list
      and by the fragment track inside .hold. This one is .pipe. */

.pipe{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  gap:0;                 /* zero, so the stage borders meet as one line */
  margin-top:48px;
}

.step{
  position:relative;
  border-top:1px solid var(--hairline);
  padding:26px 30px 0 0;
  transition:border-color .6s var(--ease);
}
/* the stage node, sitting centred on the hairline it interrupts */
.step::before{
  content:"";
  position:absolute;
  left:0;
  top:-4px;
  width:7px;height:7px;
  border-radius:50%;
  background:var(--canvas);
  border:1px solid var(--border-strong);
  transition:background .6s var(--ease),border-color .6s var(--ease);
}
.step .num{
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:.16em;
  color:var(--text-secondary);
}
.step h3{font-size:19px;margin:10px 0 8px}
.step p{color:var(--text-secondary);font-size:15px;margin:0}

/* lit, driven by the hold. Phase 1 moved decorative accent to grey but this
   rule kept a blue text-shadow on the step number; it is a neutral lift now. */
.step.lit{border-top-color:var(--border-strong)}
.step.lit::before{
  background:var(--text-secondary);
  border-color:var(--text-secondary);
}
.step.lit .num{color:var(--text-primary)}

/* under 900 four columns stop fitting, so the run returns to a vertical list
   and the node moves to the left edge of each stage */
@media (max-width:900px){
  .pipe{grid-template-columns:1fr;margin-top:36px}
  .step{
    border-top:0;
    border-left:1px solid var(--hairline);
    padding:22px 0 22px 26px;
  }
  .step::before{left:-4px;top:26px}
  .step.lit{border-top-color:transparent;border-left-color:var(--border-strong)}
}

/* ---------- the hold moment ---------- */

.hold{
  position:relative;
  border:1px solid var(--hairline);
  border-radius:0;
  background:transparent;
  padding:34px 30px;
  margin-top:44px;
  text-align:center;
  user-select:none;
  -webkit-user-select:none;
  touch-action:manipulation;
}
/* on touch, the browser must not claim the finger for scrolling mid-hold */
.hold .hold-btn{
  touch-action:none;
  -webkit-touch-callout:none;
}
/* touch enabled 23 August 2026: the hold logic runs on pointer events with
   touch-action:none on the button, so the same press-and-hold works on phones. */
.hold .frag-stage{position:relative;height:150px;margin:6px auto 18px;max-width:340px}
.hold .frag{
  position:absolute;
  width:14px;height:14px;
  background:linear-gradient(135deg,#3d5a7d,#7FB3E8);
  clip-path:polygon(12% 0,100% 22%,82% 100%,0 74%);
  opacity:.85;
  transform:translate(var(--fx,0px),var(--fy,0px)) rotate(var(--fr,0deg)) scale(var(--fs,1));
  transition:transform .12s linear;
}
.hold .rail{
  position:absolute;
  left:8%;right:8%;
  bottom:26px;
  height:3px;
  border-radius:3px;
  background:linear-gradient(90deg,rgba(157,175,196,0),var(--text-secondary) 18%,var(--text-secondary) 82%,rgba(157,175,196,0));
  opacity:.25;
  transition:opacity .4s var(--ease);
}
/* 13 September 2026: this read `.hold.done-state .rail,{opacity:1}`. The
   trailing comma made the whole selector list invalid, so the browser
   discarded the rule and the track never brightened when the fragments
   finished assembling. One character. */
.hold.done-state .rail{opacity:1}
.hold .rail::after{
  content:"";
  position:absolute;
  inset:-7px 0;
  border-radius:8px;
  box-shadow:0 0 26px rgba(74,144,226,.7);
  opacity:var(--hp,0);
  transition:opacity .2s linear;
}
.hold .hint{
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:.15em;
  text-transform:uppercase;
  color:var(--text-secondary);
}
.hold .hold-btn{
  margin-top:14px;
}

/* ---------- team ---------- */

.person{
  display:grid;
  grid-template-columns:132px 1fr;
  gap:24px;
  align-items:start;
  background:transparent;
  border:1px solid var(--hairline);
  border-radius:0;
  padding:28px;
}
.person img{
  width:132px;height:132px;
  object-fit:cover;
  border-radius:0;
  border:1px solid var(--hairline);
}
.person h3{font-size:22px;margin:0}
.person .role{
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--text-secondary);
  margin:6px 0 12px;
}
.person p{color:var(--text-secondary);font-size:15px;margin:0 0 10px}
@media (max-width:640px){
  .person{grid-template-columns:1fr}
  .person img{width:110px;height:110px}
}

/* ---------- values ---------- */

.value{
  display:grid;
  grid-template-columns:44px 1fr;
  gap:18px;
  padding:22px 0;
  border-bottom:1px solid var(--hairline);
  align-items:baseline;
}
.value:last-child{border-bottom:0}
.value .vnum{
  font-family:var(--mono);
  font-size:13px;
  color:var(--text-secondary);
  letter-spacing:.1em;
}
.value h3{font-size:20px;margin:0 0 6px}
.value p{color:var(--text-secondary);font-size:15.5px;margin:0}

/* ---------- artifact panels, 13 September 2026 (Phase 3) ---------- */

/* The audit's central finding: the reference build never makes an abstract
   claim without showing the thing, and we make claims and show nothing.
   These are the missing right half.

   Deliberately generic. No client names, no record IDs, no invented metrics,
   nothing that could be read as a measured result. They show the SHAPE of a
   system we build, which is something we can stand behind, rather than an
   outcome we would be making up. Set in mono so they read as an instrument
   panel and never as decoration. */

.artifact{
  border:1px solid var(--hairline);
  background:transparent;
  padding:22px 22px 20px;
  font-family:var(--mono);
  font-size:12.5px;
  line-height:1.5;
  color:var(--text-secondary);
}
.artifact .a-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:14px;
  padding-bottom:13px;
  border-bottom:1px solid var(--hairline);
  font-size:11px;
  letter-spacing:.16em;
  text-transform:uppercase;
  margin:0;
}
.artifact .a-head b{font-weight:500;color:var(--text-primary)}
.artifact .a-foot{
  margin:16px 0 0;
  padding-top:13px;
  border-top:1px solid var(--hairline);
  font-size:12px;
}
.artifact .a-foot b{color:var(--text-primary);font-weight:500}

/* the run log */
.trace{list-style:none;margin:12px 0 0;padding:0}
.trace li{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:16px;
  padding:7px 0;
}
.trace .s{flex:none;opacity:.7}
.trace li.ok{color:var(--text-primary)}
.trace li.ok .s{opacity:1}
/* the held step is the whole point of the panel: it is the visible proof of
   "people stay in control", so it is the one row that gets a boxed state */
.trace li.held{color:var(--text-primary)}
.trace li.held .s{
  opacity:1;
  border:1px solid var(--border-strong);
  padding:1px 8px;
  letter-spacing:.08em;
  text-transform:uppercase;
  font-size:11px;
}
.trace li.wait{opacity:.42}

/* sticky in the left column of #why, so it holds beside the five values */
.aside-stick{position:sticky;top:100px;margin-top:34px}

/* before / after */
.artifact.ba{
  padding:0;
  display:grid;
  grid-template-columns:1fr 1fr;
}
/* 13 September 2026: the panel runs full width under the Impact split now, so
   the inner padding grows with it; 22px read thin across a 1200px box. */
.ba-col{padding:26px 30px}
.ba-col + .ba-col{border-left:1px solid var(--hairline)}
.ba-h{
  margin:0 0 12px;
  font-size:11px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--text-secondary);
}
.ba-col.after .ba-h{color:var(--text-primary)}
.ba-col ul{list-style:none;margin:0;padding:0}
.ba-col li{display:flex;gap:10px;padding:6px 0;align-items:baseline}
.ba-col li i{flex:none;font-style:normal;opacity:.5}
.ba-col.after li{color:var(--text-primary)}
.ba-col.after li i{opacity:1}

/* 13 September 2026: the merged closing row. Spans both halves so the panel
   reads as one object with a conclusion, instead of a two-column box with a
   loose sentence floating under it. Stays in mono: it is inside the artifact,
   and switching to the body face here would break the panel in half again.
   grid-column 1 / -1 spans whatever the column count is, so this keeps working
   when the panel collapses to a single column under 900px. */
.ba-foot{
  grid-column:1 / -1;
  margin:0;
  padding:20px 30px;
  border-top:1px solid var(--hairline);
  font-size:13px;
  line-height:1.65;
  color:var(--text-secondary);
  max-width:none;
}

@media (max-width:900px){
  .aside-stick{position:static;margin-top:28px}
  .artifact.ba{grid-template-columns:1fr}
  .ba-col + .ba-col{border-left:0;border-top:1px solid var(--hairline)}
}

/* ---------- FAQ ---------- */

.faq{border-top:1px solid var(--hairline)}
.faq details{
  border-bottom:1px solid var(--hairline);
}
.faq summary{
  cursor:pointer;
  list-style:none;
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:18px;
  padding:22px 4px;
  font-family:var(--display);
  font-weight:700;
  font-size:17.5px;
  transition:color .3s var(--ease);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--accent-hover)}
.faq summary .tick{
  font-family:var(--mono);
  color:var(--text-secondary);
  transition:transform .35s var(--ease);
  flex:none;
}
.faq details[open] summary .tick{transform:rotate(45deg)}
.faq .a{
  overflow:hidden;
  padding:0 4px 22px;
  color:var(--text-secondary);
  font-size:15.5px;
  max-width:68ch;
}

/* ---------- imagery ---------- */

/* 13 September 2026: <figure> carries a browser default of `margin:1em 40px`
   and nothing here ever reset it, so every figure on the site has been inset
   40px each side and pushed 17px down for its whole life. It was invisible
   while a figure was the only thing in its column. The moment the Impact
   before/after panel landed underneath at full column width, the image read
   as misaligned with the panel, which it was. */
.figure{
  position:relative;
  margin:0;
  border-radius:0;
  overflow:hidden;
  border:1px solid var(--hairline);
}
.figure img{
  width:100%;height:100%;
  object-fit:cover;
  display:block;
  will-change:transform;
  transform:translateY(var(--py,0px)) scale(1.08);
}
/* whisper drift: every image breathes */
.paused-ok .figure img{animation:kenburns 46s var(--ease) infinite alternate}
.figure:nth-of-type(odd) img{animation-delay:-12s}
@keyframes kenburns{
  from{transform:translateY(var(--py,0px)) scale(1.08) translateX(-0.6%)}
  to{transform:translateY(var(--py,0px)) scale(1.14) translateX(0.6%)}
}
.figure::after{
  content:"";
  position:absolute;
  inset:0;
  background:linear-gradient(180deg,rgba(14,20,32,0) 55%,rgba(14,20,32,.45));
  pointer-events:none;
}

/* ---------- contact ---------- */

/* 23 August 2026: stacked full-width per Chris, side-by-side squeezed the
   form fields and left the booking calendar too narrow to be usable. */
.contact-grid{
  display:grid;
  grid-template-columns:1fr;
  gap:26px;
  margin-top:52px;
  align-items:start;
}

.panel{
  background:transparent;
  border:1px solid var(--hairline);
  border-radius:0;
  padding:30px;
}
.panel h3{font-size:20px;margin:0 0 6px}
.panel .note{color:var(--text-secondary);font-size:14px;margin:0 0 20px}

.field{margin-bottom:16px}
.field label{
  display:block;
  font-family:var(--mono);
  font-size:11.5px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--text-secondary);
  margin-bottom:7px;
}
.field input,.field textarea{
  width:100%;
  background:#111A2A;
  color:var(--text-primary);
  border:1px solid var(--border-strong);
  border-radius:0;
  padding:13px 14px;
  font-family:var(--body);
  font-size:16px; /* 16 minimum: below this iOS force-zooms the focused field */
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease);
}
.field input:focus,.field textarea:focus{
  outline:none;
  border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(74,144,226,.18);
}
.field textarea{min-height:110px;resize:vertical}

.form-status{
  margin-top:14px;
  font-size:14.5px;
  color:var(--text-secondary);
  min-height:1.4em;
}
.form-status.ok{color:#8CD99A}
.form-status.err{color:#E8A0A0}

.booking-frame{
  width:100%;
  min-height:640px;
  border:0;
  border-radius:0;
  background:#111A2A;
}

.booking-fallback{
  border:1px dashed var(--border-strong);
  border-radius:0;
  padding:34px 28px;
  text-align:center;
}
.booking-fallback p{
  color:var(--text-secondary);
  font-size:15px;
  margin:0 0 20px;
  max-width:40ch;
  margin-inline:auto;
}

.direct{
  margin-top:18px;
  font-size:15px;
  color:var(--text-secondary);
}
.direct a{color:var(--accent-hover);text-decoration:none}
.direct a:hover{text-decoration:underline}

/* ---------- footer ---------- */

footer{
  position:relative;
  border-top:1px solid var(--hairline);
  padding:44px 0 54px;
  color:var(--text-secondary);
  font-size:14px;
}
footer .cols{
  display:flex;
  flex-wrap:wrap;
  gap:26px;
  justify-content:space-between;
  align-items:baseline;
}
footer a{color:var(--text-secondary);text-decoration:none}
footer a:hover{color:var(--text-primary)}

/* ---------- reduced motion, complete ---------- */

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation:none !important;
    transition:none !important;
    transition-delay:0s !important;
  }
  .io .part{opacity:1;transform:none}
  .seam path{stroke-dashoffset:0 !important}
  .step{border-left-color:var(--border-strong)}
  .hold .rail{opacity:1}
}

/* ---------- mobile fixes, 23 August 2026 (screenshot audit, Samsung S26) ---------- */

/* the nav CTA: .nav .links a outranks .btn, so the button text inherited the
   grey link color. Re-state the button colors at the winning specificity. */
.nav .links a.btn{color:var(--canvas)}
.nav .links a.btn:hover{color:var(--canvas)}

/* the seam is a desktop signature. On phones it renders as a stray diagonal
   line slashing through headings and body copy, so it does not run there. */
@media (max-width:900px),(pointer:coarse){
  .seam-wrap{display:none}
}

@media (max-width:640px){
  /* body copy in cards, steps, values and bios was 15 to 15.5px, small on a phone */
  .card p,.step p,.value p,.person p{font-size:16px}
  /* the numbered gutter reads wide on a narrow screen, tighten it */
  .value{grid-template-columns:34px 1fr;gap:14px}
  /* the webchat bubble floats over the last content, give the page tail clearance */
  footer{padding-bottom:130px}
}

/* touch targets: footer and inline nav links get real tap height */
@media (pointer:coarse){
  footer a{display:inline-block;padding:10px 2px}
}

/* ---------- mobile completion pass, 23 August 2026 ---------- */

/* section headings had no size rule at all and rendered at browser default,
   nearly the same size as card titles. Explicit scale, desktop included. */
.section .head h2{font-size:clamp(28px,4.2vw,42px)}

/* the mobile nav menu: hamburger in the bar, panel drops under it */
.nav-toggle{
  display:none;
  background:transparent;
  border:1px solid var(--border-strong);
  border-radius:999px;
  color:var(--text-primary);
  width:44px;height:44px;
  align-items:center;justify-content:center;
  cursor:pointer;
  flex:none;
}
.nav-menu{display:none}
@media (max-width:860px){
  .nav-toggle{display:inline-flex}
  .nav-menu{
    position:fixed;
    /* 12 September 2026: the pill nav sits at top:12px and runs ~58px tall,
       so the dropdown clears it at 80 instead of the old bar's 66 */
    top:80px;left:0;right:0;
    z-index:49;
    background:rgba(14,20,32,.97);
    backdrop-filter:blur(12px);
    border-bottom:1px solid var(--hairline);
    padding:6px var(--gut) 14px;
    flex-direction:column;
  }
  .nav-menu.open{display:flex}
  .nav-menu a{
    color:var(--text-primary);
    text-decoration:none;
    font-size:16px;
    padding:14px 2px;
    border-bottom:1px solid var(--hairline);
  }
  .nav-menu a:last-child{border-bottom:0}
}

/* small-phone tier: nothing existed under 640, narrow devices got tablet spacing */
@media (max-width:400px){
  :root{--gut:16px}
  .section{padding:64px 0}
  .static-hero h1{font-size:30px}
}
