/*
Theme Name: Ignite Rebuild
Theme URI: https://digital-ignite.com
Author: Digital Ignite
Description: Custom theme for the Ignite rebuild. Single design system, zero third-party JavaScript.
             Ported from the self-contained mock; the hash router was removed in favour of real
             WordPress pages. Requires PHP 7.4+ (written 7.4-safe deliberately).
Version: 1.5.35
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 7.4
Text Domain: ignite
*/

/* ==========================================================================
   PORTED VERBATIM from the mock's single <style> block. Read these first:

   1. ONE easing curve — cubic-bezier(.2,.8,.2,1). Do not add others.
   2. Gradient text needs THREE fallback blocks: @supports not (background-clip:text),
      @media (forced-colors:active), and @media print. Miss one and the text renders
      as literally nothing.
   3. Never put `filter` on an element that also has background-clip:text — it promotes
      the element to its own composited layer which can pick up an opaque black backing
      on some GPUs and in Safari. See .mark-hot and .ic-word button; both use text-shadow.
   4. The hero torch (.fmark-hot) is masked by a radial-gradient driven from site.js. Never
      add `filter` to it — the halo belongs inside the SVG. See rule 3 and parts/hero-mark.php.
   5. 1px hairlines only, never box-shadows, for dividers.
   ========================================================================== */

  @property --ang{syntax:'<angle>'; inherits:false; initial-value:120deg;}
  @keyframes angspin{to{--ang:480deg;}}

  :root{
    --bg:#171311;
    --bg-2:#1c1714;
    --bg-3:#241d18;
    --orange:#ff6a3d;
    --pink:#ff4d8d;
    --amber:#ffb43d;
    --cream:#fff3d6;
    --off:#f5f0ea;
    --muted:#d8d1c7;
    --muted-2:#b8afa4;
    --deep:#5b1d02;
    --line:rgba(245,240,234,0.10);
    --line-2:rgba(245,240,234,0.38);
    --grad:linear-gradient(120deg, var(--orange), var(--pink));
  }
  *{box-sizing:border-box;}
  html{scroll-behavior:smooth; scroll-padding-top:96px;}
  body{
    margin:0; background:var(--bg); color:var(--off);
    font-family:'Space Grotesk', system-ui, sans-serif; line-height:1.5;
    /* 31 Aug: -webkit-font-smoothing:antialiased REMOVED. It forced grayscale antialiasing on
       macOS/iOS, which renders glyphs thinner — and this site is light text on a near-black
       ground at body weight, the exact combination where that reads as soft or blurry. Alex
       reported body copy hard to read on desktop; contrast was never the issue (--muted on --bg
       measures 12.19:1, ~3x the WCAG minimum), the strokes were simply too thin. Letting macOS
       use subpixel rendering thickens them. Paired with the 300 -> 400 body-weight change in the
       same version. Note this property is a NO-OP on Linux, so it cannot be evaluated from a
       Cowork sandbox — a Mac or iPhone is the only instrument. */
    overflow-x:hidden;
  }
  a{color:inherit; text-decoration:none;}
  h1,h2,h3{margin:0; letter-spacing:-0.035em; text-wrap:balance; font-weight:700; line-height:0.95;}
  p{text-wrap:pretty;}
  :focus-visible{outline:none; box-shadow:0 0 0 2px var(--bg), 0 0 0 4px var(--orange); border-radius:6px;}

  main:focus{outline:none;}
  .skip{position:absolute; left:-9999px; background:var(--orange); color:#171311; padding:12px 20px; font-weight:600; z-index:500;}
  .skip:focus{left:0; top:0;}
  .sr{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap;}

  .wrap{max-width:1240px; margin:0 auto; padding:0 34px;}
  .mono{font-family:'IBM Plex Mono', monospace;}
  .kicker{
    font-family:'IBM Plex Mono', monospace; font-size:11.5px; letter-spacing:.13em;
    text-transform:uppercase; color:var(--orange); margin:0 0 26px;
    display:flex; align-items:center; gap:12px;
  }
  .kicker::before{content:""; width:26px; height:1px; background:var(--grad);}
  .grad{background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent;}
  /* wordmark per rebrand deck slide 19: Space Grotesk Medium, horizontal orange -> pink */
  .wordmark{
    font-family:'Space Grotesk', sans-serif; font-weight:700; letter-spacing:-0.022em;
    background:linear-gradient(90deg, var(--orange) 0%, var(--pink) 100%);
    -webkit-background-clip:text; background-clip:text; color:transparent;
  }
  .wordmark-bw{
    font-family:'Space Grotesk', sans-serif; font-weight:700; letter-spacing:-0.022em;
    color:var(--off); background:none; -webkit-text-fill-color:var(--off);
  }
  .flow{
    background:linear-gradient(var(--ang), var(--orange), var(--pink), var(--amber), var(--orange));
    -webkit-background-clip:text; background-clip:text; color:transparent;
    animation:angspin 13s linear infinite;
  }
  /* if the browser can't clip background to text, keep the type visible */
  @supports not ((-webkit-background-clip:text) or (background-clip:text)){
    .grad, .flow, .wordmark, .c-num, .aw-yr, .about-cta h2 a, .ppo div:nth-child(3) dt{
      background:none !important; color:var(--orange) !important;
      -webkit-text-fill-color:var(--orange) !important; animation:none !important;
    }
  }
  .grain{
    /* 31 Aug: z-index was 400 — FOUR TIMES the header's 100 — so this full-viewport fixed
       layer sat over the entire UI, and the only thing letting clicks through was
       pointer-events:none. One dropped declaration (an over-eager CSS optimiser, UCSS) and the
       whole site becomes unclickable; and a fixed blend-mode + contain:paint layer over the nav
       is a known source of touch hit-test trouble on real mobile hardware. Lowered to 90, just
       under the header (100), scrim (98) and menu (99), so the navigation can never be affected
       by it. Cost: the 5% noise no longer overlays the header band and the open menu panel.
       Imperceptible in practice. */
    position:fixed; inset:0; z-index:90; pointer-events:none; opacity:.05; mix-blend-mode:overlay;
    transform:translateZ(0); contain:paint;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  }

  .btn{
    display:inline-flex; align-items:center; justify-content:center; gap:10px;
    font-family:inherit; font-weight:600; font-size:15.0px; padding:16px 30px; border-radius:100px;
    border:1px solid var(--line-2); background:transparent; color:var(--off); cursor:pointer;
    transition:box-shadow .3s ease, border-color .25s ease, color .25s ease, background .25s ease;
  }
  .btn-p{background:var(--grad); color:#171311; border-color:transparent;}
  .btn-p:hover{box-shadow:0 10px 40px -10px rgba(255,77,141,.7);}
  .btn-g:hover{border-color:var(--orange); color:var(--orange);}

  /* ---------- NAV: stripped to almost nothing ---------- */
  header{
    position:fixed; top:0; left:0; right:0; z-index:100; padding:22px 0;
    transition:background .35s ease, padding .35s ease, border-color .35s ease;
    border-bottom:1px solid transparent;
  }
  header.on{background:rgba(23,19,17,.88); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); padding:13px 0; border-bottom-color:var(--line);}
  .nav{display:flex; align-items:center; justify-content:space-between;}
  .logo{font-size:clamp(30px,3.1vw,42px); font-weight:700; letter-spacing:-0.028em; line-height:1;}
  /* the global :focus-visible ring uses var(--bg) as a "moat" so the orange ring
     has breathing room from the text — that only works over a flat var(--bg) fill.
     The nav wordmark sits over the dynamic hero/header backdrop (grain, ember glow,
     mesh, blurred scroll state), so that moat painted a visible dark pill behind the
     transparent gradient-clipped letters. Outline instead, offset clear of the glyphs,
     so nothing gets filled regardless of what's behind it. */
  a.wordmark:focus-visible{outline:2px solid var(--orange); outline-offset:8px; box-shadow:none;}

  /* ---------- BRAND LOCKUP ----------
     15 Sept: the header and footer wordmarks were live text (Space Grotesk 700, gradient
     clipped to the glyphs). They are now the brand lockup from Ignite_SecondaryLogo_Color.svg,
     inlined by parts/logo.php — flame mark plus outlined "Ignite" lettering.

     HEIGHT is expressed in em so the existing .logo font-size drives it, and the responsive
     steps further down (1291 / 1335 / 1339) keep working with no new breakpoints. 1.5em
     rather than 1em because the artwork's box height is set by the flame, which stands taller
     than the lettering — at 1em the wordmark reads visibly smaller than the text it replaced.
     1.5em was chosen from a rendered comparison at 1 / 1.2 / 1.35 / 1.5em, not calculated.

     STILL OPEN: the gradient is mapped in user space across the whole 656-unit artboard, so
     the flame (left ~110 units) only catches the orange end and reads nearly flat at header
     size. Remapping to objectBoundingBox would give the mark the full orange->pink range but
     would change the colour distribution the designer set. Left as delivered.

     The gradient stops are bound to the theme variables so the lockup matches the gradient
     text beside it; parts/logo.php carries literal hex fallbacks for engines that will not
     resolve a custom property inside a stop. */
  .ig-lockup{display:block; width:auto; height:1.5em;}
  /* 15 Sept: the header dropped the flame and shows the lettering alone. Its viewBox is
     tightened to the letters, so the same em height would render them much larger than the
     full lockup does — 1.25em matches the size the lettering had inside the lockup. */
  .ig-lockup--text{height:1.25em;}
  /* 15 Sept: footer sits at a 22px base and 1.5em crowds the address block under it,
     so the footer lockup stays at the smaller ratio. */
  .f .ig-lockup{height:1.35em;}
  /* 16 Sept: footer went to the text variant as well. Same reasoning as the header's 1.25em -
     the text viewBox is 174.63 tall against the full lockup's 213.66, a ratio of 0.817, so the
     footer's 1.35em lockup height becomes 1.35 x 0.817 = 1.10em for the lettering alone.
     Specificity here equals .f .ig-lockup (0,2,0); it wins on source order, so keep it below. */
  .f .ig-lockup--text{height:1.1em;}
  .ig-lockup-a{stop-color:var(--orange);}
  .ig-lockup-b{stop-color:var(--pink);}
  a.lockup:focus-visible{outline:2px solid var(--orange); outline-offset:8px; box-shadow:none;}

  .nav-r{display:flex; align-items:center; gap:26px;}





  /* ---------- 02 HERO ----------
     UPDATED (theme re-cut, 18 Aug 2026): the scrolling proof band that used to sit
     above the hero and carry the fixed-header clearance is gone (see the logo
     showcase note further down) — the hero now carries that clearance itself via
     --hdr-h, and goes back to a full min-height:100svh since nothing sits above it
     any more. */
  .hero{min-height:100svh; display:flex; align-items:center; position:relative; overflow:hidden; padding:calc(var(--hdr-h) + 36px) 0 88px;}
  .hero .wrap{position:relative; z-index:3; width:100%;}
  .ember{
    position:absolute; z-index:0; pointer-events:none; width:min(1000px,110vw); aspect-ratio:1;
    top:-40%; right:-14%;
    background:radial-gradient(circle, rgba(255,106,61,.30), rgba(255,77,141,.12) 44%, transparent 68%);
    animation:emberIn 1.7s cubic-bezier(.2,.85,.25,1) both;
  }
  @keyframes emberIn{from{opacity:0; transform:scale(.5);} to{opacity:1; transform:scale(1);}}
  /* ---------- HERO TORCH ----------
     15 Sept: was two <p>Ignite</p> layers with a gradient clipped to the glyphs by
     background-clip:text. It is now the flame from the brand lockup, as two stacked SVGs
     (parts/hero-mark.php). The mechanism is unchanged: a cold base always visible at very low
     opacity, and a hot gradient layer revealed only inside a soft circle at the cursor.

     site.js is untouched — it still finds #markHot, measures it and writes --tx / --ty / --tr.

     One thing got SIMPLER. The old .mark-hot needed a negative inset with matching padding
     because line-height:.72 made its box shorter than the glyphs, so the mask (whose origin is
     the border box) sliced the ascenders flat. An SVG's box is its own viewBox — there is no
     overflow and no correction needed. The site.js comment about markHot being "0.28em taller
     than the stack" is now stale; the rects coincide.

     The glow is an feDropShadow inside the hot SVG, NOT a CSS filter. See the note below about
     filter + mask promoting a layer that paints an opaque black backing on some GPUs. */
  .mark-stack{
    /* 15 Sept: was right:-3vw bottom:-5vw, from when this was the wordmark. The flame is tall
       and narrow where "Ignite" was wide, so hugging the corner made it read as a small ornament
       rather than the backdrop the wordmark was. Pulled in off the right edge and grown past the
       viewport height, so what shows is a slice of something large. */
    position:absolute; z-index:1; right:6vw; bottom:-8vw; pointer-events:none; user-select:none;
  }
  .fmark{display:block; height:110vh; width:auto;}
  /* .035, not .05: the cold layer was tuned for letterforms, which are mostly gaps. A solid
     flame at this size held far more light and started reading as a visible grey shape. */
  .fmark-cold{fill:rgba(245,240,234,.035);}
  .fmark-hot{
    position:absolute; inset:0;
    /* torch: only visible inside a soft circle at the cursor, which fades on exit */
    --tx:50%; --ty:50%; --tr:0px;
    -webkit-mask-image:radial-gradient(circle var(--tr) at var(--tx) var(--ty), #000 0%, rgba(0,0,0,.55) 55%, transparent 78%);
    mask-image:radial-gradient(circle var(--tr) at var(--tx) var(--ty), #000 0%, rgba(0,0,0,.55) 55%, transparent 78%);
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
    transition:--tr .9s cubic-bezier(.2,.8,.2,1);
    /* Do NOT add filter or will-change here. filter + mask-image on one element forces a
       composited layer, and a promoted layer whose paint is mostly transparent gets an opaque
       black backing on some GPU/driver combinations and in Safari — which reads as a black box
       behind the lit flame, made worse by .grain's mix-blend-mode:overlay sampling it as a
       backdrop. The halo lives inside the SVG instead (parts/hero-mark.php). */
  }
  @property --tr{syntax:'<length>'; inherits:false; initial-value:0px;}
  /* 15 Sept: the hero torch no longer depends on background-clip:text, so the old
     "hide .mark-hot where it is unsupported" rule is gone. SVG gradients are universal. */
  .mesh{
    position:absolute; inset:0; z-index:2; pointer-events:none;
    background-image:linear-gradient(rgba(245,240,234,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(245,240,234,.05) 1px,transparent 1px);
    background-size:84px 84px;
    mask-image:radial-gradient(ellipse 70% 60% at 20% 34%,#000 26%,transparent 82%);
    -webkit-mask-image:radial-gradient(ellipse 70% 60% at 20% 34%,#000 26%,transparent 82%);
  }
  h1{font-size:clamp(46px, 9.4vw, 132px); max-width:13ch; letter-spacing:-0.035em;}
  /* 31 Aug: hero headline enlarged at Alex's request, desktop AND mobile. Scoped to `.hero h1`
     deliberately — the base h1 above is inherited by legacy pages through .legacy-body, which has
     no h1 rule of its own, so raising the base floor would have made those pages worse.
     Sizes are measured, not chosen. Ladder run at 320/375/390/430/768/1024/1280/1440/1600/1920
     with the REAL Space Grotesk (the sandbox cannot reach Google Fonts; the woff2 is loaded
     locally for measurement — a fallback font gives wrong line breaks and produced a bad
     recommendation once already on 31 Aug).
       - floor 58px is the largest that keeps BOTH headline lines at 2 rows on a 375px phone.
       - 10.8vw / 150px cap is the largest that keeps the sub-paragraph above the fold at 1280.
         11.5vw / 160px pushed it below at that width.
       - 320px CANNOT take more than 46px: at 50px and up it breaks to 6 lines with "just" and
         "We" orphaned. Hence the override below. Do not remove it without re-running the ladder. */
  .hero h1{font-size:clamp(58px, 10.8vw, 150px);}
  @media (max-width:360px){ .hero h1{font-size:46px;} }
  .ln{display:block; overflow:hidden;}
  .ln > span{display:block; transform:translateY(106%); animation:up 1s cubic-bezier(.16,.84,.28,1) forwards;}
  .ln:nth-child(2) > span{animation-delay:.11s;}
  @keyframes up{to{transform:translateY(0);}}
  .hero-sub{font-size:clamp(18px,1.85vw,22px); color:var(--muted); max-width:52ch; line-height:1.72; margin:34px 0 40px; font-weight:400;}
  /* 27 Aug: the hero's "Let's Talk" button was removed, so .hero-sub is now the last
     child of the hero .wrap and its 40px bottom margin dangled — the hero centres its
     content vertically, so a trailing margin pushes everything visually upward.
     .hero-cta is kept below in case the button returns. */
  .hero-sub:last-child{margin-bottom:0;}
  .hero-cta{display:flex; gap:14px; flex-wrap:wrap; align-items:center;}
  .cue{
    position:absolute; left:34px; bottom:34px; z-index:3; display:flex; align-items:center; gap:13px;
    font-family:'IBM Plex Mono', monospace; font-size:11.5px; letter-spacing:.13em; text-transform:uppercase;
    color:var(--muted-2); transition:opacity .4s ease;
  }
  .cue i{display:block; width:1px; height:48px; background:linear-gradient(180deg,var(--orange),transparent); position:relative; overflow:hidden;}
  .cue i::after{content:""; position:absolute; inset:0; background:var(--amber); animation:run 2.2s cubic-bezier(.5,0,.5,1) infinite;}
  @keyframes run{0%{transform:translateY(-100%);}100%{transform:translateY(100%);}}

  /* ---------- LOGO SHOWCASE ----------
     REMOVED (theme re-cut, 18 Aug 2026): the old scrolling proof band (.band/.mq/.mq2 —
     an auto-scrolling logo ticker + capability-word ticker directly under the header)
     is gone from every template. It's replaced by the static "Brands that have trusted us"
     grid below (.show/.show-g/.show-i/.wm), which is no longer the first thing under
     the header and no longer carries the fixed-header clearance — the hero does that
     now (see the HERO section above). --hdr-h is kept: the hero's padding still
     reads it. */
  :root{--hdr-h:90px;}
  @media (max-width:560px){
    .vlock{font-size:20px;}
    .vhead-in{gap:12px; flex-wrap:wrap; padding:0 20px;}
    .vnav{gap:12px; justify-content:flex-start;}
  }

  /* ---------- 03 WORK: draggable rail ---------- */
  .work{padding:120px 0 110px; position:relative;}
  .work-head{
    display:flex; align-items:flex-end; justify-content:space-between; gap:30px;
    margin-bottom:38px; padding-bottom:20px; border-bottom:1px solid var(--line); flex-wrap:wrap;
  }
  h2{font-size:clamp(34px,5.6vw,68px); max-width:15ch;}
  .rail-wrap{position:relative; width:100%;}
  /* full-bleed rail whose first card still lines up with the centred container */
  .rail-pad{padding-left:max(34px, calc((100% - 1240px) / 2 + 34px)); padding-right:34px;}
  .rail{
    display:flex; align-items:flex-start; gap:20px; overflow-x:auto; padding-top:6px; padding-bottom:26px;
    scroll-snap-type:x mandatory; scrollbar-width:none; cursor:grab; scroll-behavior:smooth;
    scroll-padding-left:max(34px, calc((100% - 1240px) / 2 + 34px));
  }
  .rail::-webkit-scrollbar{display:none;}
  .rail.drag{cursor:grabbing; scroll-behavior:auto; scroll-snap-type:none;}
  .rail.drag *{pointer-events:none;}
  .card{
    flex:0 0 clamp(300px,27vw,392px); scroll-snap-align:start; position:relative;
    background:var(--bg-2); border:1px solid var(--line); border-radius:20px; padding:30px 28px 26px;
    display:flex; flex-direction:column; min-height:470px;
    transition:flex-basis .45s cubic-bezier(.2,.8,.2,1), border-color .35s ease,
               background .35s ease, transform .35s cubic-bezier(.2,.8,.2,1);
  }
  .c-face{display:flex; flex-direction:column; flex:1 1 auto; min-width:0;}
  .card.open{
    flex-basis:min(470px, 88vw);
    border-color:rgba(255,106,61,.55); background:var(--bg-3); transform:none;
  }
  .card.open::before{transform:scaleY(1);}
  @media (prefers-reduced-motion:reduce){ .card{transition:none;} }
  .c-face{display:flex; flex-direction:column; min-width:0;}
  /* opening widens the card in place and unfolds a second column beside the face */
  .card.open::before{transform:scaleY(1);}
  @media (prefers-reduced-motion:reduce){ .card{transition:none;} }
  .card::before{content:""; position:absolute; left:0; top:26px; bottom:26px; width:2px; background:var(--grad); transform:scaleY(0); transform-origin:top; transition:transform .5s cubic-bezier(.2,.8,.2,1);}
  .card:hover{border-color:rgba(255,106,61,.45); background:var(--bg-3); transform:translateY(-5px);}
  .card:hover::before{transform:scaleY(1);}
  .c-cat{font-family:'IBM Plex Mono',monospace; font-size:11.0px; letter-spacing:.13em; text-transform:uppercase; color:var(--muted-2); margin:0 0 auto;}
  .c-num{
    display:block; font-size:clamp(52px,5.4vw,74px); font-weight:700; line-height:.95; letter-spacing:-0.038em;
    background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent; margin:34px 0 6px;
  }
  .c-unit{font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--muted-2); margin:0 0 22px;}
  .c-client{font-size:16.0px; font-weight:600; margin:0 0 8px;}
  .c-how{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; line-height:1.75; letter-spacing:.02em;
    color:var(--muted-2); margin:0 0 14px; padding-left:11px; border-left:1px solid var(--line-2);
  }
  .c-line{font-size:14.0px; color:var(--muted); line-height:1.72; margin:0 0 20px; font-weight:400;}
  .c-foot{display:flex; gap:20px; padding-top:18px; border-top:1px solid var(--line); font-family:'IBM Plex Mono',monospace; font-size:11.5px; color:var(--muted-2); letter-spacing:.06em;}
  .rb{
    width:44px; height:44px; border-radius:50%; border:1px solid var(--line-2); background:transparent;
    color:var(--off); cursor:pointer; font-size:16.0px; display:flex; align-items:center; justify-content:center;
    transition:background .25s ease,border-color .25s ease,color .25s ease,transform .25s ease;
  }
  .rb:hover{background:var(--grad); border-color:transparent; color:#171311; transform:scale(1.07);}
  .rb[disabled]{opacity:.28; cursor:default; transform:none; background:transparent; border-color:var(--line); color:var(--muted-2);}
  .rail-ctl{display:flex; align-items:center; gap:11px; margin-top:10px;}
  .rb-hint{font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.12em; color:var(--muted-2); margin-left:8px;}
  /* Sits under the rail controls, aligned to the same left edge as the section heading
     and the rail's first card rather than centred — the page is left-aligned throughout. */
  .work-cta{margin-top:34px;}
  @media (max-width:760px){ .work-cta{margin-top:26px;} }

    /* ---------- CLIENT PHOTOGRAPHY on the work rail (19 Aug) ----------
     Full-bleed photo cards. IMPORTANT: the class "card" is kept on every article
     because the drag/prev/next JS does rail.querySelectorAll('.card') — renaming
     these breaks the rail, the counter and the keyboard handler. "card-ph" is a
     modifier layered on top, nothing more.

     The photo and scrim are absolutely positioned so they escape the card's own
     padding without it needing to change.

     Scrim is weighted to the LOWER THIRD rather than spread evenly: an even scrim
     dims the whole frame and flattens faces, while this keeps the top of the picture
     bright and still buys enough contrast for the type. Tested against the real
     client photography, not guessed.

     c-how, c-line and c-foot are hidden on photo cards — that copy cannot survive
     over a photograph at this size. It is display:none rather than deleted so the
     text is still in the file and can be brought back. See the note in the changelog.

     TO ADD A PHOTO to a pending card: delete the <span class="c-ph-fb"> line, drop in
     <img class="c-ph" src="..." alt="..."> in its place, and remove class "card-ph-none".
     ---------------------------------------------------------------- */
  .card-ph{overflow:hidden; justify-content:flex-end;}
  .card-ph .c-ph{
    position:absolute; inset:0; z-index:0; width:100%; height:100%;
    object-fit:cover; display:block;
    transition:transform .7s cubic-bezier(.2,.8,.2,1);
  }
  .card-ph:hover .c-ph{transform:scale(1.05);}
  .card-ph .c-scrim{
    position:absolute; inset:0; z-index:1; pointer-events:none;
    background:linear-gradient(180deg,
      rgba(23,19,17,.08) 0%, rgba(23,19,17,.26) 30%,
      rgba(23,19,17,.88) 56%, rgba(23,19,17,.985) 84%);
  }
  .card-ph .c-face, .card-ph .c-more{position:relative; z-index:2;}
  /* auto margin on TOP so the whole text block sits on the floor of the card.
     The three following rules matter for CONTRAST, not just rhythm: .c-num carries a
     34px top margin on a normal card, which left the category label floating in the
     middle of the frame — over the brightest part of a photo, where the scrim is still
     only ~30% and muted grey type on a pale background failed. Tightening the group
     pulls every line down into the lower third where the scrim is 82%+ . Do not
     reintroduce the gap without re-checking the label against a light photograph. */
  /* --muted-2 measures 8.2:1 on the flat page but only ~3.4:1 over a photograph, and
     this label is 11px, so it needs 4.5:1. Measured, not assumed: the backdrop was
     sampled with the type hidden and the lightest decile taken as the worst case.
     --muted clears the bar on all five photographs with the scrim below. */
  .card-ph .c-cat{margin:auto 0 10px; color:var(--muted);}
  .card-ph .c-num{margin:0 0 5px;}
  .card-ph .c-unit{margin:0 0 12px;}
  .card-ph .c-client{margin:0 0 12px;}
  .card-ph .c-how, .card-ph .c-line, .card-ph .c-foot{display:none;}
  .card-ph .c-more{border-top-color:rgba(245,240,234,.22);}
  /* an image is the point of this card, so don't also paint a hover background */
  .card-ph:hover{background:var(--bg-2);}

  /* placeholder for a client whose photograph has not arrived. Reuses the hero's
     ember + mesh so it still reads as the brand rather than as a missing asset. */
  .card-ph-none{background:linear-gradient(150deg,#2a1a14 0%,#4a1d18 44%,#6d2320 100%);}
  .card-ph-none .c-ph-fb{position:absolute; inset:0; z-index:0;}
  .card-ph-none .c-ph-fb::before{
    content:""; position:absolute; inset:0;
    background:radial-gradient(circle at 74% 16%, rgba(255,106,61,.42), rgba(255,77,141,.16) 44%, transparent 70%);
  }
  .card-ph-none .c-ph-fb::after{
    content:""; position:absolute; inset:0;
    background-image:linear-gradient(rgba(245,240,234,.05) 1px,transparent 1px),
                     linear-gradient(90deg,rgba(245,240,234,.05) 1px,transparent 1px);
    background-size:64px 64px;
    -webkit-mask-image:radial-gradient(ellipse 74% 62% at 26% 30%,#000 24%,transparent 80%);
    mask-image:radial-gradient(ellipse 74% 62% at 26% 30%,#000 24%,transparent 80%);
  }
  .card-ph-none .c-scrim{
    background:linear-gradient(180deg, transparent 0%, rgba(23,19,17,.40) 54%, rgba(23,19,17,.88) 100%);
  }
  /* 24 Aug: HUB CITY — written when the only Hub City asset in the Drive library was the
     white mascot logomark (no photograph existed), so that card carried the mark on the
     .card-ph-none gradient field instead of a photo, sat under .c-scrim like a photo
     would, pulled up so the text block below stayed clear of it.
     3 Sept: the Hub City card was removed from this rail (replaced by Cogswell for Mayor,
     which shipped with a real photo, Alex's request) — .card-ph-none/.c-mark currently
     render no card. Left in place on purpose: it is the ready-made treatment for the next
     client card that arrives with a logo but no photograph, not a one-off tied to Hub City.
     The case_study itself is untouched and still appears in the full case-studies index —
     only this rail's curated ten changed. */
  .card-ph-none .c-mark{
    position:absolute; z-index:0; left:50%; top:30%; transform:translate(-50%,-50%);
    width:62%; height:auto; opacity:.9; pointer-events:none;
  }
  /* .c-pend: unused staging affordance, kept in case one is wanted again.
     31 Aug: this comment previously carried a launch-checklist instruction telling the reader
     to delete this rule AND the .card-ph-none cards. The second half was wrong and the phrase
     is deliberately not repeated here so it cannot be found by grep again. That specific
     card (Hub City Spartanburgers) was in fact removed later, on 3 Sept — but as a deliberate
     content swap, not by following this old instruction, and .card-ph-none itself was kept
     (see the 24 Aug/3 Sept note above). Anyone grepping "BEFORE LAUNCH" should still not
     delete .card-ph-none on the strength of this comment alone. */
  .c-pend{
    position:absolute; top:16px; left:16px; z-index:3;
    font-family:'IBM Plex Mono',monospace; font-size:9px; letter-spacing:.14em;
    text-transform:uppercase; color:var(--amber); padding:5px 9px; border-radius:3px;
    background:rgba(23,19,17,.80); border:1px solid rgba(255,180,61,.42);
  }
  @media print{ .c-pend{display:none !important;} }

  /* ---------- 03B MISSION / ETHOS / BELIEFS (rebrand slides 3-5) ---------- */
  .sol{padding:132px 0 118px; border-top:1px solid var(--line); position:relative;}
  .sol .wrap{max-width:1140px;}
  .sol h2{max-width:20ch;}
  .grad-pink{background:linear-gradient(90deg, var(--pink), var(--orange)); -webkit-background-clip:text; background-clip:text; color:transparent;}
  /* quote leads; support sits on its baseline rather than beside it as an equal */
  .voice{
    display:grid; grid-template-columns:minmax(0,1.28fr) minmax(0,1fr);
    gap:0 clamp(44px,5.4vw,86px); align-items:end;
    margin:38px 0 0; padding-bottom:54px; border-bottom:1px solid var(--line);
  }
  .pull{
    font-size:clamp(30px,4.4vw,54px); font-weight:700; line-height:1.06; letter-spacing:-0.035em;
    margin:0; max-width:16ch;
  }
  .voice-body{font-size:17.0px; color:var(--muted); line-height:1.7; margin:0 0 7px; max-width:38ch; font-weight:400;}
  .mlabel{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.12em; text-transform:uppercase;
    color:var(--muted-2); margin:0 0 16px;
  }
  /* People / Process / Outcomes promoted to display type — the three words ARE the structure */
  .ppo{
    margin:0; display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
    gap:0 clamp(26px,3.2vw,54px);
  }
  .ppo div{padding:26px 0 0; border-top:1px solid var(--line-2);}
  .ppo dt{
    font-family:'Space Grotesk',sans-serif; font-size:clamp(20px,2.2vw,27px);
    font-weight:700; letter-spacing:-0.028em; line-height:1.1; color:var(--off); margin:0 0 13px;
  }
  .ppo div:nth-child(3) dt{
    background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent;
  }
  .ppo dd{margin:0; font-size:15.5px; line-height:1.72; color:var(--muted); font-weight:400;}
  @media (max-width:760px){ .ppo dd{font-size:14.5px;} }
  .pillars-chips{list-style:none; display:flex; flex-wrap:wrap; gap:10px; margin:0; padding:0;}
  .beliefs .mlabel{margin:0 0 14px;}
  .pillars-chips li{
    font-size:14.0px; color:var(--orange); border:1px solid rgba(255,106,61,.5);
    border-radius:3px; padding:9px 18px; transition:background .25s ease, color .25s ease, border-color .25s ease;
  }
  .pillars-chips li:hover{background:var(--orange); color:#171311; border-color:transparent;}
  /* chips that link to a case study (Services page, via ignite_engine_list($linked=true)) —
     the <a> fills the whole chip so the existing padding stays the hit target. */
  .pillars-chips li a{color:inherit; text-decoration:none; display:block; margin:-9px -18px; padding:9px 18px;}

  .beliefs{padding:118px 0 126px; border-top:1px solid var(--line); position:relative;}
  .beliefs .wrap{max-width:960px;}
  .ethos{
    font-size:clamp(19px,2.35vw,29px); font-weight:400; line-height:1.5; letter-spacing:-0.015em;
    color:var(--off); max-width:32ch; margin:38px 0 52px;
    padding-left:26px; border-left:2px solid var(--orange);
  }

  /* one column and a closing rule — the two-column version left ragged rows and no bottom edge */
  .creed{
    list-style:none; margin:52px 0 0; padding:0; counter-reset:creed;
    display:grid; grid-template-columns:1fr; gap:0; border-bottom:1px solid var(--line);
  }
  .creed li{
    counter-increment:creed; position:relative; max-width:52ch;
    font-size:clamp(18px,2.05vw,26px); font-weight:700; letter-spacing:-0.025em; line-height:1.3;
    color:var(--off); padding:26px 0 26px 52px; border-top:1px solid var(--line);
  }
  .creed li::before{
    content:"0" counter(creed);
    position:absolute; left:0; top:30px;
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; font-weight:400;
    letter-spacing:.12em; color:var(--muted-2);
  }

  /* ---------- 03C ICARE MANTRA ---------- */
  /* ---------- ICARE: hover (or focus) a letter to read the value ---------- */
  .icare{position:relative; padding:112px 0; border-top:1px solid var(--line); text-align:center;}
  .ic-kick{font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.11em;
           text-transform:uppercase; color:var(--muted-2); margin:0 0 12px;}
  .ic-hint{font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.09em;
           color:var(--muted-2); margin:0 0 34px; opacity:.75;}
  /* 27 Aug: .ic-hint ("Hover a letter") was removed at Alex's request. It carried the
     34px gap between the kicker and the letters, so without this the two collapse to
     .ic-kick's 12px. Adjacent sibling, so the gap returns by itself if the hint ever
     comes back. Same pattern as .cases-hero h1 + .cases-index. */
  .ic-kick + .ic-word{margin-top:34px;}
  .ic-word{display:flex; gap:clamp(6px,1.6vw,22px); justify-content:center; margin:0 0 36px; flex-wrap:wrap;}
  .ic-word button{
    font-family:'Space Grotesk',sans-serif; font-weight:700;
    font-size:clamp(52px,12vw,148px); line-height:.86; letter-spacing:-0.038em;
    background:none; border:none; padding:0 .04em; cursor:pointer;
    color:rgba(245,240,234,.42);
    transition:color .35s ease, transform .35s cubic-bezier(.2,.8,.2,1), text-shadow .35s ease;
  }
  .ic-word button:hover, .ic-word button:focus-visible, .ic-word button[aria-current="true"]{
    background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent;
    transform:translateY(-8px);
    /* text-shadow, NOT filter:drop-shadow — this is the same trap documented at .mark-hot.
       filter on an element with background-clip:text and a transparent fill promotes it to its
       own composited layer, which can pick up an opaque backing on some GPUs and in Safari, and
       can also break the text clip so the raw gradient rect paints. The hero was fixed; this
       instance was missed. Same halo, no layer promotion. Do not reintroduce filter here. */
    text-shadow:0 12px 26px rgba(255,106,61,.30);
  }
  @supports not ((-webkit-background-clip:text) or (background-clip:text)){
    .ic-word button:hover, .ic-word button[aria-current="true"]{color:var(--orange);}
  }
  /* min-height stops the block jumping as you move across the letters. It was 104px,
     tuned for the old one-line values; the 24 Aug copy runs 93-123 characters, which is
     three lines at this measure for I/C/A and two for R/E — a 26px shift on hover.
     130px is the tallest of the five, measured, not guessed. Re-measure if the copy
     changes length again. */
  .ic-body{min-height:130px; max-width:46ch; margin:0 auto; padding:0 22px;}
  .ic-name{font-size:clamp(20px,2.6vw,30px); font-weight:700; margin:0 0 12px; letter-spacing:-0.02em; line-height:1.1;
           background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent;}
  @supports not ((-webkit-background-clip:text) or (background-clip:text)){ .ic-name{color:var(--orange);} }
  .ic-line{font-size:16.5px; color:var(--muted); line-height:1.72; margin:0; font-weight:400;}
  .ic-body{transition:opacity .22s ease;}
  .ic-body.swap{opacity:0;}

  /* ---------- forced-colors: background-clip:text elements lose their paint and,
       with color:transparent still applied, render as nothing at all ---------- */

  /* ---------- the engine (capabilities deck, slide 8) ---------- */
  .eng{padding:104px 0 108px; border-top:1px solid var(--line); position:relative;}
  .eng .wrap{
    display:grid; grid-template-columns:minmax(0,3fr) minmax(0,8.4fr);
    gap:0 clamp(30px,4vw,68px); align-items:start;
  }
  .eng-head{position:sticky; top:118px;}
  /* 24 Aug: on the Services page the heading and lead live in the page hero, so the
     section holds only the cards — collapse the sticky-head column or the grid would
     be squeezed into the narrow 3fr track. */
  .eng-solo .wrap{grid-template-columns:1fr;}
  /* the "The engine" kicker was dropped 19 Aug; it carried margin:0 0 26px, and the
     gradient dash of .kicker::before was this section's only accent above the heading.
     .eng::before still draws the section's top hairline, so the accent is not lost —
     but the heading needs its own breathing room now that nothing sits above it. */
  /* 31 Aug: letter-spacing added here to match .cases-hero h1. Both carry
     "Three systems. One outcome."; at the old -0.035em/-0.038em the display sizes read
     cramped. Loosened to -0.018em in both places so the heading tracks the same wherever
     it appears. */
  /* 3 Sept: loosened from -0.018em to -0.010em — Alex flagged "Three systems. One
     outcome." as reading cramped at the display size clamp() pushes this to. Kept in
     sync with .cases-hero h1 below, same reason as the 31 Aug note above.
     line-height loosened too, homepage only — the sticky .eng-head column is only
     3fr of the section's 11.4fr grid (see .eng .wrap above), narrow enough that this
     heading wraps to 4 lines there, and at the sitewide h1/h2/h3 line-height:.95 the
     "y" descender in "systems." was landing right on top of "One outcome." below it.
     .cases-hero h1 is untouched — different selector, and at its wider hero width
     this heading doesn't wrap the same way, so it wasn't showing the collision. */
  .eng-h{margin-top:6px; letter-spacing:-0.010em; line-height:1.05;}
  .eng-lead{margin-bottom:0;}
  .eng-lead{
    font-size:17.0px; color:var(--muted); max-width:60ch; line-height:1.75;
    font-weight:400; margin:20px 0 52px;
  }
  /* ---------- ENGINE AS CARDS (24 Aug) ----------
     Card chassis lifted from the client rail so the two sections share a language:
     same radius, same hairline border, same bg-2 ground, same gradient edge that
     wipes in on hover, same lift. The column dividers that used to separate the three
     systems are gone — a border AND a divider is one line too many.
     NOTE: the .sys h3 rules below are NOT decoration. An earlier edit replaced this
     whole block and silently took the 01/02/03 counter, the heading size and the
     heading's underline with it, and broke .sys-i's absolute positioning by removing
     position:relative. Keep them together. */
  .sys{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:18px; counter-reset:sysn;}
  .sys > div{
    counter-increment:sysn; position:relative; overflow:hidden;
    background:var(--bg-2); border:1px solid var(--line); border-radius:20px;
    transition:border-color .35s ease, background .35s ease, transform .35s cubic-bezier(.2,.8,.2,1);
  }
  /* 3 Sept: padding moved from here onto .sys-face (front/back each need their own —
     see the click-to-flip block below). Do not put padding back here or it stacks
     with the faces' padding. */
  .sys > div::before{
    content:""; position:absolute; left:0; top:24px; bottom:24px; width:2px;
    background:var(--grad); transform:scaleY(0); transform-origin:top;
    transition:transform .5s cubic-bezier(.2,.8,.2,1);
  }
  .sys > div:hover{border-color:rgba(255,106,61,.45); background:var(--bg-3); transform:translateY(-4px);}
  .sys > div:hover::before{transform:scaleY(1);}
  .sys h3{
    position:relative;
    font-size:clamp(18px,1.6vw,21px); font-weight:700; letter-spacing:-.018em; line-height:1.2;
    margin:0 0 16px; padding-bottom:13px; border-bottom:1px solid var(--line-2);
  }
  /* Heading icon, top-right, level with the 01/02/03 counter. These rules were
     collateral damage of the card refactor once already — they lived inside the .sys
     block that got replaced, and losing them dropped .sys-i back to inline flow where
     it butted straight into the first letter of the title. They belong here now, next
     to the h3 rules they depend on. */
  .sys-t{display:block;}
  .sys-i{position:absolute; top:-2px; right:0; width:30px; height:30px; display:block;}
  @media (max-width:940px){ .sys-i{width:28px; height:28px;} }
  .sys h3::before{
    content:"0" counter(sysn); display:block; margin-bottom:10px;
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.12em;
    font-weight:400; color:var(--muted-2);
  }
  .sys ul{list-style:none; margin:0; padding:0;}
  .sys li{
    display:flex; align-items:center; gap:11px;
    font-size:14.5px; line-height:1.45; color:var(--muted); font-weight:400;
    padding:9px 0; border-top:1px solid var(--line);
  }
  .sys li:first-child{border-top:0;}
  .sys li::before{content:none;}
  /* 26px is the ceiling a 14.5px row can carry. It is under the 34px the heading marks
     needed, so only the simpler icons in the library are used per-item; the detailed
     ones (Programmatic, AI, Podcast) are illegible at this size — see the note in the
     changelog about which three items are therefore carrying an approximate icon. */
  .sv-i{flex:0 0 auto; display:block; width:26px; height:26px;}
  /* ---------- ENGINE HOVER (24 Aug) ----------
     Three layers, all built from idioms already on the page rather than new ones:

     1. ROW FEEDBACK. Nineteen rows previously had no hover state at all while sitting
        inside a card that lifts — they looked interactive and answered nothing. Text
        lifts to --off, the icon grows slightly, the row nudges right. Same nudge
        distance as .cases-index a and .b-rows, so it reads as the same system.

     2. SIBLING RECESSION. Hovering one card fades the OTHER two back. This dims the
        h3 and li rather than the card itself on purpose: .sys > div carries the .rv
        scroll-reveal class, and .js .rv.in{opacity:1} has higher specificity than any
        reasonable sibling selector — dimming the card directly loses to the reveal and
        silently does nothing. Targeting the children sidesteps the collision entirely.
        No :has() either, so this works without relying on selector support.

     3. CURSOR SPOTLIGHT. A radial gradient tracking the pointer inside the hovered
        card, driven by --mx/--my set in JS. This is the same technique as the page
        .glow (--gx/--gy) and the hero torch (--tx/--ty) — third instance, not a new
        pattern. On ::after because ::before is already the gradient left edge, and the
        card's children get position:relative so the gradient paints behind them.
        Falls back to a centred glow when pointer tracking is off. */
  .sys li{transition:color .22s ease, padding-left .22s ease, opacity .3s ease;}
  .sys li:hover{color:var(--off); padding-left:8px;}
  .sv-i{transition:transform .28s cubic-bezier(.2,.8,.2,1);}
  .sys li:hover .sv-i{transform:scale(1.1);}

  .sys > div h3, .sys > div li{transition:opacity .3s ease, color .22s ease, padding-left .22s ease;}
  .sys:hover > div:not(:hover) h3, .sys:hover > div:not(:hover) li,
  .sys:hover > div:not(:hover) .sys-back-copy, .sys:hover > div:not(:hover) .sys-trigger{opacity:.4;}

  .sys > div::after{
    content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
    border-radius:inherit; opacity:0; transition:opacity .35s ease;
    background:radial-gradient(300px circle at var(--mx,50%) var(--my,50%),
      rgba(255,106,61,.13), rgba(255,77,141,.05) 42%, transparent 68%);
  }
  .sys > div:hover::after{opacity:1;}
  .sys > div > *{position:relative; z-index:1;}

  /* ---------- ENGINE CARDS: click-to-flip (3 Sept) ----------
     Mocked up on a Claude Design canvas and approved by Alex before this went into
     the theme; see ignite_engine_cards() in functions.php for the copy/markup and the
     reasoning on click-vs-hover.
     .sys > div keeps every rule above completely unchanged — background, border,
     radius, hover lift, gradient edge, cursor spotlight, sibling recession — this
     only adds perspective and a 3D-rotating inner wrapper around the card's content.
     .sys-face-front is the ONLY face in normal flow (the back is position:absolute),
     so it alone establishes the card's height — grid's align-items:stretch then
     fills that height for the two shorter cards exactly as it always has, and
     .sys-face-back inherits that same height for free via inset:0. */
  .sys > div{perspective:1600px;}
  .sys-flip-inner{
    position:relative; height:100%; transform-style:preserve-3d;
    transition:transform .6s cubic-bezier(.2,.8,.2,1);
  }
  .sys > div.flip .sys-flip-inner{transform:rotateY(180deg);}
  .sys-face{
    position:relative; height:100%; padding:26px 24px 22px;
    backface-visibility:hidden; -webkit-backface-visibility:hidden;
    display:flex; flex-direction:column;
  }
  .sys-face-back{position:absolute; inset:0; transform:rotateY(180deg);}
  .sys-back-copy{
    font-size:14.5px; line-height:1.65; color:var(--muted); font-weight:400; margin:0;
    flex:1 1 auto;
  }
  /* trigger row — same shape as .c-more (case studies "Read more"): mono uppercase
     label, hairline top border, chevron that nudges on hover/focus. Negative margin
     cancels the face's own side/bottom padding so the hairline runs edge to edge and
     the row sits flush with the card's bottom corners; margin-top:auto pins it to the
     floor of the (possibly stretched) flex column on both faces. */
  .sys-trigger{
    all:unset; cursor:pointer; display:block; margin:auto -24px -22px; padding:14px 24px 16px;
    border-top:1px solid var(--line); color:var(--muted-2);
    transition:color .25s ease, background .25s ease;
  }
  .sys-trigger:hover, .sys-trigger:focus-visible{color:var(--orange); background:rgba(255,106,61,.06);}
  .sys-trigger:focus-visible{outline:none; box-shadow:inset 0 0 0 2px var(--orange);}
  .trig-in{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.12em; text-transform:uppercase;
  }
  .sys-chev{
    width:9px; height:9px; flex-shrink:0; border-right:1.5px solid currentColor;
    border-bottom:1.5px solid currentColor; transform:rotate(-45deg);
    transition:transform .3s cubic-bezier(.2,.8,.2,1);
  }
  .sys-trigger:hover .sys-chev, .sys-trigger:focus-visible .sys-chev{transform:rotate(-45deg) translate(3px,3px);}
  /* the back face's chevron points the other way (back toward the front) */
  .sys-face-back .sys-chev{transform:rotate(135deg);}
  .sys-face-back .sys-trigger:hover .sys-chev, .sys-face-back .sys-trigger:focus-visible .sys-chev{transform:rotate(135deg) translate(-3px,-3px);}
  @media (prefers-reduced-motion:reduce){ .sys-flip-inner{transition:none;} }
  /* 28 Aug: a one-column @media(max-width:940px) .sys rule used to sit here. It was DEAD —
     the @media(max-width:940px) block further down re-declared .sys to two columns twice, and
     later-in-source wins at equal specificity. Removed rather than left to mislead. Column
     counts are unchanged: 3 above 940, 2 from 761-940, 1 at 760 and below. */
  /* the point of the section is the asymmetry: KPIs recede, outcomes carry the weight */
  .col.kpi{background:rgba(245,240,234,.03);}
  /* below this the 3-up columns get too narrow beside a sidebar, so drop the sidebar first */
  @media (max-width:1080px){
    .eng .wrap{grid-template-columns:1fr; gap:0;}
    .eng-head{position:static;}
    .eng-lead{margin-bottom:44px; max-width:60ch;}
  }
  @media (max-width:940px){
    /* 28 Aug: .sys > div used to get padding:0 22px here, with padding-left:0 on odd
       children. But the base rule gives these cards a background, a 1px border and a 20px
       radius, and none of that was removed — so cards 1 and 3 rendered with their heading and
       the 01/03 counter flush against, and clipped by, their own left border. Card 2 looked
       fine, which is why it read as a rendering glitch rather than a CSS bug. The cards now
       keep the base padding at every width. */
    .sys{grid-template-columns:1fr 1fr; gap:18px;}
    .ppo{grid-template-columns:1fr; gap:0;}
    .ppo div{padding:22px 0 24px;}
    .voice{grid-template-columns:1fr; gap:26px; align-items:start; padding-bottom:40px;}
    .voice-body{margin-bottom:0;}
  }
  @media (max-width:760px){
    .eng{padding:66px 0;}
    /* 28 Aug: same fix as the 940 block — the old rules set padding:0 and swapped the left
       border for a top one, but left background, border and border-radius:20px in place, so
       every card clipped its own content. Alex's call: keep them as CARDS on mobile rather
       than flattening to a list. 22px horizontal padding (not the base 24px) buys back a
       little line width at 390px. */
    .sys{grid-template-columns:1fr; gap:16px;}
    .sys-face{padding:26px 22px 22px;}
    .sys-trigger{margin:auto -22px -22px; padding:14px 22px 16px;}
    .beliefs{padding:70px 0 76px;}
    .sol{padding:80px 0 70px;}
    .eng-lead{margin-bottom:36px;}
  }

  /* ---------- expandable case studies ---------- */
  /* summary keeps a display value that preserves its disclosure behaviour;
     the flex layout lives on the inner span instead */
  .c-more{
    display:block; margin:auto 0 0; padding:14px 0 0; border-top:1px solid var(--line);
    color:var(--muted-2); transition:color .25s ease;
  }
  .c-more:hover, .c-more:focus-visible{color:var(--orange);}
  .c-more-in{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.12em;
    text-transform:uppercase;
  }
  .c-more:hover, .c-more:focus-visible{color:var(--orange);}
  .c-chev{
    width:9px; height:9px; flex-shrink:0; border-right:1.5px solid currentColor;
    border-bottom:1.5px solid currentColor; transform:rotate(-45deg);
    transition:transform .3s cubic-bezier(.2,.8,.2,1);
  }
  .c-more:hover .c-chev, .c-more:focus-visible .c-chev{transform:rotate(-45deg) translate(3px,3px);}
  /* the extra width earned by opening goes to the copy, two-up where there is room */
  /* an open card sheds the lift so it reads as pinned rather than hovering */
  .card.open{border-color:rgba(255,106,61,.45); background:var(--bg-3); transform:none;}
  @media (prefers-reduced-motion:reduce){ .c-chev{transition:none;}
  }
  /* the card that opened the panel stays lit */
  .card.open::before{transform:scaleY(1);}

  @media (max-width:860px){
    .card.open{flex-basis:86vw; grid-template-columns:minmax(0,1fr); gap:26px 0;}
  }
  

  /* ---------- Case Studies view ---------- */
  /* 31 Aug: padding-top added when .vhead was retired (see the .vhead block below).
     The site header is position:fixed and therefore out of flow, so without this every
     .cases page began at y=0 UNDERNEATH it. This also fixes page-case-studies.php, which
     never had a .vhead and was quietly overlapping by 14px — .cases-hero pads 76px against
     a 90px header. One rule, both cases. Do not remove without restoring clearance. */
  .cases{background:var(--bg); color:var(--off); padding-top:var(--hdr-h);}
  .cases[hidden]{display:none;}
  .cases-hero{padding:76px 0 66px; border-bottom:1px solid var(--line);}
  /* 3 Sept: loosened from -0.018em to -0.010em, matching .eng-h above — see its note.
     This rule is shared by every page-hero h1 (Services, Blog, 404, single posts,
     generic pages, taxonomy pages), not just "Three systems. One outcome.", so this
     loosens all of them; Alex confirmed that's what he wants rather than the two
     "Three systems." headings drifting apart. */
  .cases-hero h1{
    font-size:clamp(40px,7vw,96px); line-height:.98; letter-spacing:-0.010em; margin:0;
    max-width:none;
  }
  .cases-lead{
    font-size:17.0px; color:var(--muted); line-height:1.75; font-weight:400;
    max-width:60ch; margin:26px 0 46px;
  }
  .cases-index ol{
    list-style:none; margin:0; padding:0; display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr)); gap:0 clamp(24px,3vw,54px);
    border-top:1px solid var(--line);
  }
  .cases-index li{border-bottom:1px solid var(--line);}
  .cases-index a{
    display:flex; align-items:baseline; gap:16px; padding:15px 0;
    font-size:16.5px; color:var(--muted); transition:color .25s ease, padding-left .25s ease;
  }
  .cases-index a span{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.1em;
    color:var(--muted-2); flex-shrink:0;
  }
  .cases-index a:hover, .cases-index a:focus-visible{color:var(--orange); padding-left:8px;}
  /* 24 Aug: the lead paragraph used to carry the 46px between the headline and the
     index. With no lead the list butted against the h1's descenders, so the spacing
     now lives on whatever follows the headline directly. */
  .cases-hero h1 + .cases-index,
  .cases-hero h1 + .cases-filter{margin-top:46px;}

  .cbrief{padding:84px 0; border-bottom:1px solid var(--line); scroll-margin-top:96px;}
  .cbrief:nth-child(even){background:var(--bg-2);}
  .cb-top{display:flex; align-items:flex-start; gap:clamp(18px,2.4vw,40px);}
  .cb-n{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.14em;
    color:var(--muted-2); margin:9px 0 0; flex-shrink:0;
  }
  .cb-cat{
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.14em;
    text-transform:uppercase; color:var(--orange); margin:0 0 10px;
  }
  .cb-client{font-size:clamp(28px,4.2vw,54px); letter-spacing:-0.032em; line-height:1.04; margin:0; max-width:18ch;}
  .cb-period{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.04em;
    color:var(--muted-2); margin:12px 0 0;
  }
  .cb-stats{
    display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0;
    margin:44px 0 42px; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  }
  .cb-stats div{padding:26px clamp(14px,2vw,30px) 24px; border-left:1px solid var(--line);}
  .cb-stats div:first-child{border-left:0; padding-left:0;}
  .cb-stats b{
    display:block; font-size:clamp(26px,3.6vw,48px); font-weight:700; letter-spacing:-0.036em;
    line-height:1; background:var(--grad); -webkit-background-clip:text; background-clip:text;
    color:transparent; font-variant-numeric:tabular-nums;
  }
  .cb-stats span{
    display:block; margin-top:12px; font-family:'IBM Plex Mono',monospace; font-size:11px;
    letter-spacing:.12em; text-transform:uppercase; color:var(--muted-2); line-height:1.45;
  }
  .cb-body{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(24px,3vw,50px);}
  .cb-body h3{
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.13em; text-transform:uppercase;
    color:var(--muted-2); font-weight:400; margin:0 0 12px; line-height:1;
  }
  .cb-body p{font-size:15px; line-height:1.78; color:var(--muted); font-weight:400; margin:0;}

  .cb-extra{
    margin-top:42px; padding:30px clamp(22px,2.6vw,36px) 28px;
    border:1px solid var(--line); border-left:2px solid var(--orange); border-radius:0 14px 14px 0;
  }
  .cb-extra h3{font-size:17px; letter-spacing:-0.018em; margin:0 0 12px; line-height:1.2;}
  .cb-extra > p{font-size:15px; line-height:1.78; color:var(--muted); font-weight:400; margin:0; max-width:78ch;}
  .cb-stats-sm{margin:26px 0 0; border-bottom:0;}
  .cb-stats-sm b{font-size:clamp(20px,2.4vw,30px);}
  .cb-extra .cb-note{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; line-height:1.7;
    color:var(--muted-2); margin:22px 0 0; max-width:70ch;
  }

  .cb-foot{
    display:flex; align-items:flex-start; justify-content:space-between; gap:30px; flex-wrap:wrap;
    margin-top:40px; padding-top:22px; border-top:1px dashed var(--line-2);
  }
  .cb-ch{list-style:none; display:flex; flex-wrap:wrap; gap:8px; margin:0; padding:0;}
  .cb-ch li{
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.06em;
    color:var(--muted-2); border:1px solid var(--line); border-radius:3px; padding:8px 13px;
  }
  .cb-src{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; line-height:1.7; color:var(--muted-2);
    margin:0; max-width:48ch; flex:1 1 300px;
  }
  /* was rgba(245,240,234,.34) = 2.88:1, a genuine WCAG AA failure (needs 4.5:1 at this size)
     and it was on the source attribution under every case study — the line that makes the
     numbers credible, set as the faintest text on the site. --muted-2 measures 8.21:1. */
  .cb-src em{display:block; margin-top:9px; font-style:normal; color:var(--muted-2);}

  @media (max-width:940px){
    .cb-body{grid-template-columns:1fr; gap:26px;}
    .cases-index ol{grid-template-columns:1fr;}
  }
  @media (max-width:760px){
    .cases-hero{padding:52px 0 46px;}
    .cbrief{padding:56px 0;}
    .cb-stats{grid-template-columns:1fr; margin:32px 0 30px;}
    .cb-stats div{border-left:0; border-top:1px solid var(--line); padding-left:0;}
    .cb-stats div:first-child{border-top:0;}
    .cb-top{flex-direction:column; gap:10px;}
    .cb-n{margin:0;}
  }

  /* ---------- header menu ---------- */
  .burger{
    width:44px; height:44px; flex-shrink:0; display:flex; flex-direction:column;
    align-items:center; justify-content:center; gap:6px; cursor:pointer;
    background:none; border:1px solid var(--line-2); border-radius:100px; padding:0;
    transition:border-color .25s ease, background .25s ease;
  }
  .burger:hover, .burger:focus-visible{border-color:rgba(255,106,61,.55);}
  .burger-b{
    display:block; width:17px; height:1.5px; background:var(--off); border-radius:2px;
    transition:transform .32s cubic-bezier(.2,.8,.2,1), opacity .2s ease;
  }
  .burger[aria-expanded="true"]{background:var(--grad); border-color:transparent;}
  .burger[aria-expanded="true"] .burger-b{background:#171311;}
  .burger[aria-expanded="true"] .burger-b:first-child{transform:translateY(3.75px) rotate(45deg);}
  .burger[aria-expanded="true"] .burger-b:last-child{transform:translateY(-3.75px) rotate(-45deg);}

  .menu-scrim{position:fixed; inset:0; z-index:98; background:rgba(10,8,7,.55); backdrop-filter:blur(2px);}
  .menu-scrim[hidden], .menu[hidden]{display:none;}
  .menu{
    position:fixed; top:0; left:0; right:0; z-index:99;
    padding:104px 0 46px; background:rgba(23,19,17,.97);
    backdrop-filter:blur(18px); -webkit-backdrop-filter:blur(18px);
    border-bottom:1px solid var(--line);
  }
  .menu-in{
    max-width:1240px; margin:0 auto; padding:0 34px;
    display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
    gap:clamp(30px,5vw,90px);
  }
  .menu-h{
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.15em;
    text-transform:uppercase; color:var(--muted-2); margin:0 0 14px;
    padding-bottom:12px; border-bottom:1px solid var(--line);
  }
  .menu ul{list-style:none; margin:0; padding:0;}
  .menu li{border-bottom:1px solid var(--line);}
  .menu a{
    display:flex; flex-direction:column; gap:6px; padding:16px 0;
    color:var(--muted); font-size:19px; letter-spacing:-0.012em;
    transition:color .22s ease, padding-left .22s ease;
  }

  .menu a:hover, .menu a:focus-visible{color:var(--orange); padding-left:8px;}

  .menu-views a em{
    font-family:'IBM Plex Mono',monospace; font-size:11px; font-style:normal;
    letter-spacing:.06em; color:var(--muted-2);
  }
  /* 24 Aug: the link column lost its .menu-h, so the list carries its own top rule */
  .menu-views{border-top:1px solid var(--line);}
  .menu-views a.soon em{color:var(--amber);}
  .menu-h + .menu-foot{margin-top:14px;}
  .menu-foot{
    font-family:'IBM Plex Mono',monospace; font-size:11.5px; line-height:1.8;
    color:var(--muted-2); margin:26px 0 0;
  }
  .menu-foot a{display:inline; padding:0; font-size:11.5px;}
  /* entrance is decoration only — the panel is shown by removing [hidden] */
  .menu .menu-in{opacity:0; transform:translateY(-8px);}
  .menu.in .menu-in{opacity:1; transform:none; transition:opacity .3s ease, transform .38s cubic-bezier(.2,.8,.2,1);}
  @media (prefers-reduced-motion:reduce){
    .menu .menu-in{opacity:1; transform:none;} .menu.in .menu-in{transition:none;}
    .burger-b{transition:none;}
  }
  @media (max-width:760px){
    .menu{padding:88px 0 34px; max-height:100svh; overflow-y:auto;}
    .menu-in{grid-template-columns:1fr; gap:30px;}
    .menu a{font-size:15.5px; padding:11px 0;}
  }

  /* the about view reuses the case-study chassis, with the two sections dropped in */
  .about .sol, .about .beliefs{border-top:1px solid var(--line);}
  .about .sol::before, .about .beliefs::before{
    content:""; position:absolute; top:0; left:0; width:clamp(64px,7vw,104px); height:1px;
    background:var(--grad); z-index:2;
  }
  .about-cta{padding:78px 0 96px; border-top:1px solid var(--line); background:var(--bg-2);}
  .about-cta h2{font-size:clamp(30px,4.6vw,58px); letter-spacing:-0.032em; margin:0; max-width:16ch;}
  .about-cta h2 a{
    background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent;
    border-bottom:2px solid rgba(255,106,61,.4); transition:border-color .25s ease;
  }
  .about-cta h2 a:hover{border-bottom-color:var(--orange);}
  .about-cta .cases-lead{margin:24px 0 0;}
  @media (max-width:760px){ .about-cta{padding:52px 0 62px;} }

  /* ---------- craft ---------- */
  /* each section rule opens with a short accent run, echoing .kicker::before */
  .sol::before, .beliefs::before, .eng::before{
    content:""; position:absolute; top:0; left:0; width:clamp(64px,7vw,104px); height:1px;
    background:var(--grad); z-index:2;
  }
  ::selection{background:var(--orange); color:#171311;}
  input, textarea, select{caret-color:var(--orange);}
  @media (prefers-reduced-motion:no-preference){
    .ppo div, .sys > div{transition:border-color .3s cubic-bezier(.2,.8,.2,1);}
    .ppo div:hover, .sys > div:hover{border-color:rgba(255,106,61,.42);}
  }

  /* ---------- fixes for ID rules that outrank their own breakpoints ----------
     NOTE (theme re-cut, Aug 2026): this block was inherited from the v1.1.0 port
     as invalid CSS — an unclosed comment had swallowed its own opening "/*", so
     the browser was parsing "is (1,0,1) and beat .vert section{padding:62px}"
     as a literal (invalid) rule. No selector in the mock ever matched it, so
     removing it is a no-op visually; kept as a comment for the history. */
  @media (max-width:560px){
    /* the brand row wraps here with row-gap:0, so the underline hit the next line's caps */
    .brandrow{gap:6px 2px;}
  }
  @media (max-width:400px){
    .nav-r .btn-p{display:none;}
  }
  /* 761-940px: creed and voice were still two columns, giving an 18px bold line a ~280px measure */
  @media (max-width:940px){
    .creed{grid-template-columns:1fr;}
    .voice{grid-template-columns:1fr;}
  }
  /* the header CTA collided with the brand row around 765-800px */
  @media (max-width:860px){

    .nav-r{flex-shrink:0;}
  }
  /* the count-up rewrites the number ~84 times; proportional digits made it jitter */
  .c-num,    .c-foot{
    font-variant-numeric:tabular-nums; font-feature-settings:'tnum' 1;
  }
  /* the verticals have no fixed header, so the global scroll offset overshot every anchor */
  body.on-vert{scroll-padding-top:88px;}

  @media (forced-colors:active){
    /* 15 Sept: the lockup is an SVG gradient fill — it does not respond to the colour
       flattening below, so it is flattened separately. */
    .ig-lockup-p, .fmark path{fill:CanvasText !important;}
    .fmark-hot{display:none !important;}
    .grad,    .flow,    .wordmark,    .grad-pink,    .c-num,    .aw-yr,    .ic-name,    .logo,    .about-cta h2 a,    .ppo div:nth-child(3) dt{
      background:none !important; color:CanvasText !important;
      -webkit-text-fill-color:CanvasText !important; animation:none !important;
    }
    .grain,  .glow,  .ember,  .mesh{display:none !important;}
    :focus-visible{outline:2px solid Highlight !important; outline-offset:2px;}
    .btn,   .f input,   .f select{border:1px solid ButtonBorder !important;}
  }

  /* ---------- print: the site is dark-on-dark, so paper needs an inversion.
       without this, body text and every gradient heading print as blank ---------- */
  @media print{
    @page{margin:16mm;}
    .ig-lockup-p{fill:#000 !important;}   /* 15 Sept: SVG fill, see forced-colors above */
    .mark-stack{display:none !important;}
    *{background:transparent !important; box-shadow:none !important; text-shadow:none !important;}
    html, body{background:#fff !important; color:#000 !important;}
    .grad,    .flow,    .wordmark,    .grad-pink,    .c-num,    .aw-yr,    .ic-name,    .logo,    .about-cta h2 a,    .ppo div:nth-child(3) dt{
      background:none !important; color:#000 !important;
      -webkit-text-fill-color:#000 !important; animation:none !important;
    }
    h1, h2, h3, h4, p, li, td, th, span, a, b, strong{color:#000 !important;}
    header{position:static !important; border:0 !important;}
    /* the rail prints only its first card otherwise */
    .rail{display:block !important; overflow:visible !important; height:auto !important;}
    .rail .card{width:100% !important; max-width:none !important; page-break-inside:avoid; margin:0 0 12px;}
    .hero{min-height:0 !important; padding:24px 0 !important;}
    section{padding:18px 0 !important; page-break-inside:avoid;}
    a[href^="http"]::after, a[href^="mailto"]::after{content:" (" attr(href) ")"; font-size:10px;}
    [hidden]{display:none !important;}
  }

  @media (prefers-reduced-motion:reduce){
    .ic-word button{transition:none;}
    .ic-body{transition:none;}
  }
  @media (max-width:640px){
    .icare{padding:72px 0;}
    .ic-word{gap:4px;}
    .ic-body{min-height:148px;}
  }
  /* Narrow phones need one more line than mid-width ones: the Accountability value is
     the longest of the five and wraps to a fourth line below ~370px. Measured naturally
     (min-height forced to 0) across 320-620px — tallest was 176px at 320-360, 148px at
     375-414, 119px from 480 up. These two floors stop the block jumping when a letter is
     tapped, which matters on touch where there is no hover to preview it.
     RE-MEASURE THESE IF THE ICARE COPY CHANGES LENGTH. */
  @media (max-width:370px){
    .ic-body{min-height:176px;}
  }
  /* cursor-reactive heat — now follows across the whole page */
  .glow{
    position:fixed; z-index:0; pointer-events:none; width:720px; height:720px; border-radius:50%;
    left:0; top:0; margin:-360px 0 0 -360px;
    transform:translate3d(var(--gx, 50vw), var(--gy, 50vh), 0);
    background:radial-gradient(circle, rgba(255,106,61,.15), rgba(255,77,141,.07) 40%, transparent 66%);
    opacity:0; transition:opacity .6s ease; will-change:transform;
  }
  .glow.on{opacity:1;}
  /* warmer and wider over the calculator, where the brand moment lives */
  .glow.hot{
    width:900px; height:900px; margin:-450px 0 0 -450px;
    background:radial-gradient(circle, rgba(255,106,61,.24), rgba(255,77,141,.11) 40%, transparent 66%);
  }
  /* keep page content stacked above the glow */
  main > section, footer{position:relative; z-index:1;}
  

  /* ---------- 05 CONTACT ---------- */
  .cta{padding:120px 0 140px; border-top:1px solid var(--line); position:relative; overflow:hidden;}
  .cta::after{content:""; position:absolute; left:0; right:0; bottom:-1px; height:76px; background:var(--grad); opacity:.85; clip-path:polygon(0 100%,100% 32%,100% 100%,0 100%);}
  .cta-grid{
    display:grid; grid-template-columns:minmax(0,1fr) minmax(0,.78fr);
    gap:clamp(40px,5vw,80px); align-items:start; position:relative; z-index:2;
  }
  /* 24 Aug: the headline sat flush on the lead (measured gap: 0px) because .cta h2
     carried no bottom margin and .lead only has a bottom one. */
  .cta h2{font-size:clamp(38px,6.4vw,80px); max-width:12ch; margin:0 0 clamp(18px,2vw,26px);}
  .cta-grid p.lead{color:var(--muted); font-size:17.0px; line-height:1.75; margin:0 0 24px; max-width:44ch; font-weight:400;}
  .ticks{list-style:none; margin:0; padding:0; font-size:14.5px; color:var(--muted);}
  .ticks li{display:flex; gap:12px; margin-bottom:11px;}
  .ticks li::before{content:"→"; color:var(--orange);}
  .who-h{font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.11em; text-transform:uppercase; color:var(--muted-2); font-weight:500; margin:36px 0 16px;}
  .who{list-style:none; margin:0; padding:0; border-top:1px solid var(--line);}
  .who li{display:grid; grid-template-columns:118px 1fr; gap:16px; padding:13px 0; border-bottom:1px solid var(--line); align-items:baseline;}
  .who .wr{font-size:14.0px; font-weight:600; color:var(--off);}
  .who .wd{font-size:14.0px; color:var(--muted); line-height:1.68; font-weight:400;}
  .who-note{font-size:13.0px; color:var(--muted-2); margin:14px 0 0;}
  @media (max-width:520px){ .who li{grid-template-columns:1fr; gap:3px;} }
  .form{background:var(--bg-2); border:1px solid var(--line-2); border-radius:20px; padding:34px;}
  .form h3{font-size:21.0px; margin-bottom:6px;}
  .form .fs{font-size:14.0px; color:var(--muted-2); margin:0 0 24px;}
  .f{margin-bottom:15px;}
  .f label{display:block; font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2); margin-bottom:8px;}
  .f input, .f select{
    width:100%; background:var(--bg); border:1px solid var(--line-2); border-radius:10px; padding:13px 15px;
    color:var(--off); font-family:inherit; font-size:14.5px; transition:border-color .25s ease;
  }
  .f input::placeholder{color:#8f8578;}
  .f input:focus, .f select:focus{border-color:var(--orange); outline:none;}
  .form .btn{width:100%; margin-top:8px;}
  .fnote{font-size:12.0px; color:var(--muted-2); margin:14px 0 0; line-height:1.68;}
  .hp{position:absolute; left:-9999px;}
  .fstat{margin:14px 0 0; font-size:14.0px; color:var(--orange); font-weight:600;}

  /* ---------- LEGACY PAGE BODY (25 Aug) ----------
     page.php wraps the content of the nine pages the new design does not account for in
     .legacy-body. That class shipped with NO rules behind it, so every one of those pages —
     including /privacy-policy/, /procurement/ and the three active client pages updated in
     July — rendered on raw browser defaults over a dark ground: default-blue links, unstyled
     lists and tables, images free to overflow, and iframes at the 300x150 default.

     Deliberately plain, as page.php's note says. This is not part of the design; it is the
     minimum needed for arbitrary old content to be readable and not overflow.

     The iframe rules matter most: /dream-finders-homes/ (and the other client pages of that
     shape) are thin WordPress shells wrapping a standalone module hosted outside WordPress at
     /Special-Projects/. Those embeds ARE the page. An iframe carrying its own height attribute
     keeps it; one without gets a viewport-relative floor so it cannot collapse to 150px. */
  .legacy-body{max-width:74ch; font-size:16.5px; line-height:1.72; color:var(--muted);}
  .legacy-body > :first-child{margin-top:0;}
  .legacy-body > :last-child{margin-bottom:0;}
  .legacy-body h2{font-size:clamp(24px,2.6vw,32px); line-height:1.18; margin:44px 0 14px; color:var(--off);}
  .legacy-body h3{font-size:clamp(19px,2vw,23px); line-height:1.24; margin:34px 0 12px; color:var(--off);}
  .legacy-body h4, .legacy-body h5, .legacy-body h6{
    font-family:'IBM Plex Mono',monospace; font-size:12.5px; letter-spacing:.1em;
    text-transform:uppercase; color:var(--muted-2); margin:30px 0 10px; font-weight:500;
  }
  .legacy-body p{margin:0 0 18px;}
  .legacy-body a{color:var(--orange); text-decoration:underline; text-underline-offset:3px;}
  .legacy-body a:hover{color:var(--amber);}
  .legacy-body strong, .legacy-body b{color:var(--off);}
  .legacy-body ul, .legacy-body ol{margin:0 0 18px; padding-left:22px;}
  .legacy-body li{margin:0 0 8px;}
  .legacy-body blockquote{
    margin:26px 0; padding:2px 0 2px 20px; border-left:2px solid var(--orange);
    color:var(--off); font-size:18px;
  }
  .legacy-body hr{border:0; border-top:1px solid var(--line); margin:36px 0;}
  .legacy-body code, .legacy-body kbd, .legacy-body samp{
    font-family:'IBM Plex Mono',monospace; font-size:.9em;
    background:var(--bg-3); padding:2px 6px; border-radius:4px;
  }
  .legacy-body pre{
    background:var(--bg-3); border:1px solid var(--line); border-radius:10px;
    padding:16px 18px; overflow-x:auto; margin:0 0 20px;
  }
  .legacy-body pre code{background:none; padding:0;}
  .legacy-body img, .legacy-body video{max-width:100%; height:auto; display:block; border-radius:10px;}
  .legacy-body figure{margin:26px 0;}
  .legacy-body figcaption{font-size:13px; color:var(--muted-2); margin-top:8px;}
  .legacy-body table{width:100%; border-collapse:collapse; margin:0 0 22px; font-size:15px; display:block; overflow-x:auto;}
  .legacy-body th, .legacy-body td{border:1px solid var(--line); padding:9px 12px; text-align:left;}
  .legacy-body th{color:var(--off); font-weight:600; background:var(--bg-2);}
  /* EMBEDS — see the note above. On these client pages the iframe IS the page. */
  .legacy-body iframe, .legacy-body embed, .legacy-body object{
    display:block; width:100%; max-width:100%; border:0; margin:0 0 22px; border-radius:10px;
  }
  .legacy-body iframe:not([height]){min-height:min(78vh, 900px);}

  /* ---------- CONTACT FORM 7 (25 Aug) ----------
     The form's HTML is written by hand in the CF7 form's own Form tab, so every class above
     still applies. These rules only cover the wrappers CF7 injects around each field and the
     status elements it prints, which nothing in the design system knows about.

     The load-bearing one is the first: CF7 wraps every control in an INLINE <span>, and a
     block-level input inside an inline span collapses the .f row layout. Everything else is
     making CF7's messages look like .fstat instead of like a plugin. */
  .form .wpcf7-form-control-wrap{display:block;}
  .form .wpcf7 form .wpcf7-response-output{
    margin:14px 0 0; padding:0; border:0;
    font-size:14.0px; color:var(--orange); font-weight:600;
  }
  /* CF7 marks a failed submit on the form itself; keep the message readable rather than red-on-dark */
  .form .wpcf7 form.invalid .wpcf7-response-output,
  .form .wpcf7 form.unaccepted .wpcf7-response-output,
  .form .wpcf7 form.spam .wpcf7-response-output,
  .form .wpcf7 form.failed .wpcf7-response-output{color:var(--amber);}
  .form .wpcf7-not-valid-tip{
    display:block; margin-top:7px;
    font-family:'IBM Plex Mono',monospace; font-size:11.0px; letter-spacing:.04em;
    color:var(--amber); font-weight:500;
  }
  .form .f input.wpcf7-not-valid{border-color:var(--amber);}
  /* the default spinner is a light GIF on a dark panel; a text status is already announced */
  .form .wpcf7-spinner{display:none;}
  .form .wpcf7 form.submitting .btn-p{opacity:.6; pointer-events:none;}
  /* CF7 runs its form content through wpautop; kill the stray empty paragraphs that leaves */
  .form .wpcf7 form > p:empty, .form .wpcf7 form br{display:none;}

  footer{padding:56px 0 40px; border-top:1px solid var(--line);}
  .f-top{display:grid; grid-template-columns:1.5fr 1fr 1fr; gap:40px; margin-bottom:38px;}
  .f-top p{color:var(--muted-2); font-size:14.0px; line-height:1.7; margin:12px 0 0; max-width:30ch;}
  .f-col h4{font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--muted-2); margin:0 0 14px; font-weight:500;}
  .f-col ul{list-style:none; margin:0; padding:0;}
  .f-col li{margin-bottom:9px;}
  .f-col a{font-size:14.0px; color:var(--muted);}
  .f-col a:hover{color:var(--off);}
  .f-bot{display:flex; justify-content:space-between; gap:18px; flex-wrap:wrap; padding-top:26px; border-top:1px solid var(--line); font-family:'IBM Plex Mono',monospace; font-size:12.5px; color:var(--muted-2);}
  .f-bot p{margin:0;}

  /* scoped to .js so content stays visible with scripting off, or while the doc parses */
  .js .rv{opacity:0; transform:translateY(26px);}
  .js .rv{transition:opacity .8s ease, transform .8s cubic-bezier(.2,.8,.2,1);}
  .js .rv.in{opacity:1; transform:none;}

  @media (prefers-reduced-motion: reduce){
    html{scroll-behavior:auto;}
    *{animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important;}
    .js .rv{opacity:1; transform:none;}
    .ln > span{transform:none; animation:none;}
  }

  @media (max-width:940px){
    .cta-grid{grid-template-columns:1fr; gap:44px;}
    .f-top{grid-template-columns:1fr 1fr;}
  }
  @media (max-width:760px){
    .wrap{padding:0 22px;} .cue{display:none;}

    .logo{font-size:24.0px;}
    /* 27 Aug: was `padding:40px 0 72px`, whose 40px top dated from when the
       retired proof band above the hero carried the fixed header's clearance.
       The band went on 18 Aug and the clearance went with it, leaving the H1
       overlapping the logo by 15px at every width <=760. --hdr-h is 90px at rest
       and the logo bottom is 55px, so hdr-h - 10 leaves a 25px gap under it.
       Bottom 72 -> 36 so the hero keeps roughly its old height. */
    /* 28 Aug: min-height was `auto`, so on a phone the hero was only as tall as its content
       and the next section showed above the fold. Back to 100svh — the same value the base
       rule uses. svh, NOT vh: on mobile browsers 100vh measures the viewport with the address
       bar collapsed, so the hero would run taller than the visible area and push its own
       content under the browser chrome. The padding above is unchanged; it fixes a separate
       H1/logo overlap documented in the comment above. */
    .hero{padding:calc(var(--hdr-h) - 10px) 0 36px; min-height:100svh;}
    .mark-stack{right:-4vw; bottom:-8vw;}   /* narrower screen: let it bleed rather than crowd the copy */
    /* 15 Sept: was `.mark, .mark-hot{font-size:38vw}` plus `.mark-hot{display:none}` when the
       hero mark was text. The flame is sized by height, not font-size, so the first rule is
       gone; the second is kept and repointed — the torch is still a fine-pointer affordance
       and there is no cursor to follow on a phone. */
    .fmark{height:78vh;}
    .fmark-hot{display:none;} /* torch is a fine-pointer affordance */
    .work{padding:80px 0 70px;}
    .rail-pad{padding-left:22px; padding-right:22px;}
    .rail{scroll-padding-left:22px;}
    .card{flex-basis:80vw; min-height:380px;}
    .voice{grid-template-columns:1fr; gap:40px; margin:36px 0 64px;}
    .sol{padding:80px 0 70px;}
    .ethos{margin:26px 0 46px; padding-left:18px;}
    .creed{grid-template-columns:1fr; gap:0;}
    .creed li{padding:20px 0 20px 44px;}
    .creed li::before{top:24px;}
    .cta{padding:80px 0 110px;}
    .f-top{grid-template-columns:1fr; gap:30px;}
  }


  /* ================= VERTICAL TABS + SUB-BRAND VIEWS ================= */
  #view-main[hidden]{display:none;}
  body.on-vert .glow{display:none;}

  /* verticals sit inline beside the wordmark, each in its own deck lockup */
  .brandrow{display:flex; align-items:baseline; gap:0; flex-wrap:nowrap; min-width:0;}
  /* registered so the browser can interpolate them — plain custom props would snap */
  @property --tab1{syntax:'<color>'; inherits:false; initial-value:#f5f0ea;}
  @property --tab2{syntax:'<color>'; inherits:false; initial-value:#f5f0ea;}
  @property --tab3{syntax:'<color>'; inherits:false; initial-value:#f5f0ea;}
  
  @media (max-width:820px){
    .logo{font-size:26px;}
  }
  @media (max-width:560px){
    .brandrow{gap:0 2px;}
    .logo{font-size:21px;}
    .brandrow{flex-wrap:wrap;}
  }

  /* mirrors the main header: pins to the top and gains a frosted ground on scroll.
     sticky rather than fixed so it doesn't cover the launch strip sitting above it. */
  /* 25 Aug: z-index was 100 — the SAME as the fixed site header — and .vhead comes later
     in the DOM, so it won the tie and painted over the header on every page that has one
     (Services, We are Ignite, Blog, single posts, archives, generic pages). The bar is
     transparent until scrolled, so the header still LOOKED right while the hamburger and
     "Let's talk" were dead to a click — the hit test landed on HEADER.vhead. Measured with
     elementFromPoint over the burger, not guessed. It also sat above .menu (99) and
     .menu-scrim (98), so an opened panel would have rendered behind it.
     40 keeps it above page content (which tops out at 3) and below the whole menu stack.
     Do not raise this to 98 or above. */
  /* ── .vhead — RETIRED 31 Aug 2026, markup removed from all nine templates ──────────
     Kept here, not deleted, so it can be restored if the page-name bar is ever wanted back.
     WHY IT WENT: `header` is position:fixed z-index:100; .vhead was position:sticky top:0
     z-index:40 with NO clearance, so on every sub-page the site header painted straight over
     it. Measured at 1280: both .vnav links hit-tested to HEADER — visible but unclickable —
     and "Ignite" / "Ignite Services" stacked at the same x, 37px apart. It only failed at
     >=561px; below that the nav wrapped clear, which is why it survived this long.
     It existed because the MOCK hides #view-main (and therefore the header) when a sub-view
     is showing, so .vhead was the only bar on screen there. Real WordPress pages always
     render the header, so the component had no job. The site header already carries the
     wordmark, "Let's talk" and the full menu.
     NOTE: the mock still shows .vhead on its sub-views and is CORRECT to — its router
     architecture differs. This is a deliberate, documented mock/theme divergence.
     If restoring: add `top:var(--hdr-h); margin-top:var(--hdr-h)` and `.vhead.on{top:64px}`,
     and remove the padding-top from .cases above. */
  .vhead{
    position:sticky; top:0; z-index:40; padding:22px 0;
    border-bottom:1px solid transparent;
    transition:background .35s ease, padding .35s ease, border-color .35s ease;
  }
  .vhead.on{
    background:rgba(23,19,17,.88); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
    padding:13px 0; border-bottom-color:var(--line);
  }
  /* 25 Aug: with the slide-out panel open the secondary bar must be GONE, not merely
     underneath it. .menu is 97% opaque, not 100%, so a bar sitting behind it still ghosted
     faintly through and read as a stacking bug. site.js sets body.menu-open.
     visibility, not display, so nothing reflows and the sticky offset is untouched. */
  body.menu-open .vhead{visibility:hidden;}
  @media (max-width:560px){
    .vhead{padding:16px 0;}
    .vhead.on{padding:11px 0;}
  }
  .vhead-in{display:flex; align-items:center; justify-content:space-between; gap:20px; max-width:1240px; margin:0 auto; padding:0 34px;}
  .vlock{font-size:clamp(30px,3.1vw,42px); font-weight:700; letter-spacing:-0.028em; line-height:1; white-space:nowrap;}
  /* The lockups previously rendered "We areIgnite" and "IgniteCase Studies" — 4 instances, in
     40px type, at the top of both subviews and in both subview footers. Fixed with a real space
     BETWEEN the two spans in the markup, not a margin: a margin would fix the visual gap but
     leave the accessible name as one run-together word for screen readers. The space is safe
     because it belongs to .vlock, not to the gradient-clipped child span (a space inside that
     child would be clipped away). white-space:nowrap prevents wrapping, it does not eat the
     space. Do not "tidy" the whitespace out of those tags. */
  .vlock .i{color:var(--off);}
  .vnav{display:flex; align-items:center; gap:clamp(14px,1.8vw,26px); flex-wrap:wrap; justify-content:flex-end;}
  .vnav a, .vback{font-family:'IBM Plex Mono',monospace; font-size:11.5px; letter-spacing:.11em; text-transform:uppercase; color:var(--muted-2); transition:color .25s ease;}
  /* --v1 was never defined anywhere in the file, so these three hovers were no-ops
     and both subviews had no nav hover feedback at all. */
  .vnav a:hover, .vnav a:focus-visible{color:var(--orange);}
  .vnav .vback{color:var(--muted-2); opacity:.72;}
  .vnav .vback:hover{opacity:1;}
  .vback:hover{color:var(--orange);}
  

  .vfoot{padding:52px 0 38px; border-top:1px solid var(--line);}
  .vfoot-in{display:flex; justify-content:space-between; gap:26px; flex-wrap:wrap; align-items:flex-end;
            max-width:1300px; margin:0 auto; padding:0 30px;}
  .vfoot p{margin:0; font-family:'IBM Plex Mono',monospace; font-size:12.5px; color:var(--muted-2); line-height:1.9;}
  .vfoot a{color:var(--muted);}
  .vfoot a:hover{color:var(--orange);}

  
  
  @media (max-width:640px){
    .vhead-in, .vfoot-in{padding:0 20px;}
  }


  /* ===== SPORTS — scoreboard: uppercase, mono numerals, ruled rows =====
     NOTE (theme re-cut, Aug 2026): this rule was inherited from v1.1.0 with no
     selector — invalid CSS with no effect. No sports-scoreboard markup exists
     anywhere in the current templates, so there was nothing to reattach it to. */

/* ═══════════════════════════════════════════════════════════════════
   Ported from the mock, Aug 13 2026: awards, pending logo slots, About Us.
   ═══════════════════════════════════════════════════════════════════ */
/* ══ AWARDS (homepage) & ABOUT US (We are Ignite) ══════════════════════
     Added Aug 2026. Both sections reuse the existing .grad class for
     gradient text on purpose — .grad is already listed in the forced-colors
     and print fallback blocks, so no new fallback entries are needed.       */
  .awards{padding:118px 0 112px; border-top:1px solid var(--line); position:relative;}
  .aw-lead{color:var(--muted); font-size:17px; line-height:1.72; max-width:56ch; font-weight:400; margin:22px 0 0;}
  /* ---------- AWARDS (24 Aug) ----------
     The placeholder slots were removed, which left three real awards. A 2x3 hairline
     table with half its cells empty became a row of cards in the same idiom as the
     Engine and Clients cards: rounded, a gradient rule that draws in on hover, a
     cursor spotlight, and siblings dimming. The year is now the display element.
     .aw-yr is gradient-clipped text, so it is also listed in the no-background-clip
     fallbacks (@supports, forced-colors, print).
     Dimming targets the CHILDREN, not .aw-item: `.js .rv.in{opacity:1}` (0,3,0)
     outranks any rule written against the card itself. ---------- */
  .aw-grid{list-style:none; margin:52px 0 0; padding:0;
    display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:18px;}
  .aw-item{position:relative; overflow:hidden; display:flex; flex-direction:column;
    background:var(--bg-2); border:1px solid var(--line); border-radius:20px;
    padding:26px 24px 22px; min-height:226px;
    transition:border-color .35s ease, background .35s ease, transform .35s cubic-bezier(.2,.8,.2,1);}
  .aw-item::before{content:""; position:absolute; left:24px; right:24px; top:0; height:2px;
    background:var(--grad); transform:scaleX(0); transform-origin:left;
    transition:transform .5s cubic-bezier(.2,.8,.2,1);}
  .aw-item::after{content:""; position:absolute; inset:0; pointer-events:none; opacity:0;
    transition:opacity .4s ease;
    background:radial-gradient(300px circle at var(--mx,50%) var(--my,50%),
      rgba(255,106,61,.13), rgba(255,77,141,.05) 42%, transparent 68%);}
  .aw-item > *{position:relative; z-index:1; transition:opacity .3s ease;}
  .aw-item:hover{border-color:rgba(255,106,61,.45); background:var(--bg-3); transform:translateY(-4px);}
  .aw-item:hover::before{transform:scaleX(1);}
  .aw-item:hover::after{opacity:1;}
  .aw-grid:hover .aw-item:not(:hover) .aw-yr,
  .aw-grid:hover .aw-item:not(:hover) .aw-name,
  .aw-grid:hover .aw-item:not(:hover) .aw-cat,
  .aw-grid:hover .aw-item:not(:hover) .aw-org,
  .aw-grid:hover .aw-item:not(:hover) .aw-cred{opacity:.4;}
  .aw-yr{font-family:'Space Grotesk',sans-serif; font-size:clamp(38px,4.2vw,52px);
    font-weight:700; line-height:.95; letter-spacing:-.038em; margin:0 0 12px;
    background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent;
    font-variant-numeric:tabular-nums; font-feature-settings:'tnum' 1;}
  .aw-name{font-size:20px; line-height:1.22; letter-spacing:-.018em; font-weight:700; margin:0 0 6px; max-width:none;}
  .aw-cat{color:var(--muted-2); font-size:13.5px; line-height:1.55; margin:10px 0 20px; font-weight:400;}
  .aw-org{margin:auto 0 0; padding-top:20px; border-top:1px solid var(--line-2);
    font-family:'IBM Plex Mono',monospace;
    font-size:10.5px; letter-spacing:.11em; text-transform:uppercase; color:var(--muted-2);}
  /* ---------- AWARD CREDENTIAL ROW (25 Aug) ----------
     Replaces the plain text org name with the awarding body's own wordmark plus the rank.

     Inc supplies this as a badge: a boxed rank, two rules, a vertical year strip and a
     microtype legend reading "AMERICA'S FASTEST-GROWING PRIVATE COS". Measured at 40 / 54 /
     72 / 96 / 130px, that legend does not resolve below ~90px — far more height than a
     credential row has — so at usable sizes the badge reads as grey noise. The badge also
     repeats the year this card already sets in 52px gradient type.

     So the artwork is reduced to the official Inc.5000 WORDMARK (lifted from Inc's own SVG,
     paths untouched — see logos/awards/inc5000-wordmark.svg) and the two facts the badge
     carried, the rank and the year, are set in the site's own type where they stay legible.
     The wordmark is byte-identical between the 2021 and 2022 files, so one asset serves both.

     .aw-org is left defined above: nothing uses it now, but it is the fallback if an award
     ever has no wordmark to show. */
  /* 27 Aug: min-height added so the three credential rules land on ONE horizontal line.
     Without it the rule sits directly above whatever the card's credential happens to be,
     so the Inc badge cards (84px tall) put their rule 19px higher than the Asure card
     (38px), and the row read as three unrelated cards rather than one band.
     The arithmetic: tallest credential 84px + this row's 18px padding-top = 102, plus 2px
     of slack for the border and sub-pixel rounding = 104. Measured: at 102 the third rule
     still sat 1px low; at 104 all three read 630. IF YOU CHANGE A BADGE HEIGHT ('lh' in
     ignite_awards), re-derive this number or the rules drift apart again.
     Scoped to the multi-column layout on purpose — see the 760px block, where the grid
     goes single-column and the extra band would just be dead space. */
  .aw-cred{margin:auto 0 0; padding-top:18px; border-top:1px solid var(--line-2);
    display:flex; align-items:center; justify-content:space-between; gap:16px;}
  /* Scoped away from the logos-only card on purpose: that card has no hairline to align,
     so the 104px band would only pad the bottom of a centred logo. Flip
     IGNITE_AWARD_LOGOS_ONLY off and this rule is back in force unchanged. */
  @media (min-width:761px){ .aw-item:not(.aw-item-logo) .aw-cred{min-height:104px;} }
  .aw-cred img{display:block; height:var(--alh,21px); width:auto; flex:0 0 auto;}
  .aw-rank{font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:.11em;
    text-transform:uppercase; color:var(--muted-2); white-space:nowrap;
    font-variant-numeric:tabular-nums; font-feature-settings:'tnum' 1;}

  /* ---------- LOGOS-ONLY AWARD CARD (28 Aug) ----------
     IGNITE_AWARD_LOGOS_ONLY in functions.php. front-page.php stops rendering .aw-yr /
     .aw-name / .aw-cat / .aw-rank, so the card's only child is the credential row and
     everything that positioned text around it has to come off: the auto top margin that
     pinned the row to the bottom of a tall card, the hairline that separated it from the
     name above it, and the 226px min-height sized for four stacked text elements.
     The card keeps its border, radius, gradient rule, spotlight and sibling dimming —
     the frame is unchanged, only its contents are fewer.
     Logo heights are NOT set here; they come from 'lh' in ignite_awards() via --alh
     (96 / 96 / 44), so a swapped badge is a one-number data edit, not a CSS edit. */
  /* A fixed height, not min-height:0. The badges are different shapes (Inc is 96px tall,
     Asure's lockup 44px), and at 1080px the grid drops to two columns and leaves the third
     card alone on its own row — where a card sized to its own logo came out 52px shorter
     than the two above it. 166 = the tallest badge (96) + this padding (34 + 34) + the card's 1px border top and bottom.
     Re-derive it if a badge's 'lh' goes above 96. */
  .aw-item-logo{min-height:166px; padding:34px 24px; justify-content:center;}
  .aw-item-logo .aw-cred{margin:0; padding-top:0; border-top:0; min-height:0;
    justify-content:center;}
  /* placeholder state — deliberately loud so an unfilled slot cannot ship by accident */
  .aw-item.slot{background:transparent; border:1px dashed rgba(255,180,61,.42);
    margin:-1px; align-items:flex-start; justify-content:center;}
  .aw-item.slot:hover{background:rgba(255,180,61,.045);}
  .slot-tag{font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:.16em;
    text-transform:uppercase; color:var(--amber); margin:0 0 12px;}
  .slot-txt{color:var(--muted-2); font-size:13.5px; line-height:1.6; font-weight:400; margin:0; max-width:30ch;}

  /* ── About Us ── */
  .abt-lead{color:var(--muted); font-size:18px; line-height:1.72; max-width:58ch; font-weight:400; margin:24px 0 42px;}
  /* .abt-facts (Based/Discipline/How-we-work/What-we-answer-to) and .abt-slots/.abt-block/
     .abt-slot/.abt-txt/.abt-todo (the old Founded + "Who you'd be working with" 3-up) were
     REMOVED (theme re-cut, 18 Aug 2026): page-we-are-ignite.php no longer renders that markup,
     replaced by the team roster below (.team-h/.team-lead/.team/.tm-*). */

  @media (max-width:1080px){
    .aw-grid{grid-template-columns:repeat(2,1fr);}
  }
  @media (max-width:760px){
    .awards{padding:74px 0 70px;}
    .aw-grid{grid-template-columns:1fr;}
    /* a floor, not 0 — the Asure card has no .aw-cat, and without slack the auto
       margin collapsed and the org hairline sat 6px under the wrapped name. */
    .aw-item{min-height:212px; padding:26px 22px 28px;}
    /* single column, one logo per card: 212px of height around a 96px badge reads as
       three empty boxes on a phone. The card shrinks to its logo plus padding. */
    .aw-item-logo{min-height:158px; padding:30px 22px;}   /* 96 + 30 + 30 + 2px border */
  }
  @media print{
    .aw-item.slot{display:none !important;}
    .awards{padding:24px 0 !important;}
  }

  /* ══ PENDING LOGO SLOTS — REMOVED (theme re-cut, 18 Aug 2026) ═══════════════
     This was the toggleable placeholder system for the old scrolling proof band
     (.mq figure.pending / .pend), gated behind the now-deleted
     ignite_show_pending_logos filter. The showcase grid that replaced the band
     is permanent and un-toggled — see ignite_showcase_logos() in functions.php —
     so there is no longer a "pending slot" state to style. */

  .abt-quote{margin:0 0 42px; padding:0 0 0 22px; border-left:2px solid var(--orange); max-width:62ch;}
  /* 25 Aug: curly quotes were added to the testimonial. hanging-punctuation pulls the
     opening quote into the margin so the first line still starts flush with the orange
     rule instead of sitting a glyph-width inside it. Safari-only today; everywhere else
     simply ignores it and the quote sits inline, which is fine. */
  .abt-quote blockquote{font-size:clamp(18px,2.1vw,23px); line-height:1.5; letter-spacing:-.018em;
    color:var(--off); font-weight:400; margin:0; hanging-punctuation:first last;}
  .abt-quote figcaption{margin-top:16px; font-family:'IBM Plex Mono',monospace; font-size:11px;
    letter-spacing:.11em; text-transform:uppercase; color:var(--off);}
  .abt-quote figcaption span{display:block; margin-top:6px; color:var(--muted-2); letter-spacing:.09em;}

  /* ---------- LOGO SHOWCASE (replaces the retired scrolling .band/.mq proof band) ---------- */
  .show{border-top:1px solid var(--line); border-bottom:1px solid var(--line); padding:78px 0 82px;}
  /* This heading used to be styled DOWN to a small centred grey mono label — a holdover
     from the scrolling proof band this section replaced, where a quiet caption over a
     moving strip was the right call. It is a section heading now, so it takes the same
     treatment as every other section on the page: left-aligned, Space Grotesk display
     size off the global h2 rule, gradient on the payoff, closing period. Deliberately
     no kicker — that matches The Engine directly above it rather than the kicker+h2
     pattern used further down in Clients, Recognition and Let's talk. */
  .show-h{margin:0 0 40px;}
  @media (max-width:620px){ .show-h{margin:0 0 30px;} }
  .show-g{display:grid; grid-template-columns:repeat(4,1fr); gap:26px 22px; align-items:center;}
  /* 88px, not 76: DBH sits at lh 71 (see ignite_showcase_logos) and 71 + 16px padding = 87,
     which would have pushed row 1 alone 11px taller than the other three. Raising the floor
     keeps all four rows equal. Anything up to lh 72 now fits without changing the rhythm. */
  .show-i{display:flex; align-items:center; justify-content:center; min-height:88px; padding:8px 10px; margin:0;}
  .show-i a{display:flex; align-items:center; justify-content:center; width:100%; height:100%; transition:opacity .25s ease;}
  .show-i a:hover, .show-i a:focus-visible{opacity:.62;}
  .show-i img{display:block; width:auto; max-width:100%; object-fit:contain;
    /* PER-LOGO OPTICAL SIZING (ported from the mock, 24 Aug — the theme had been holding
       every logo at one clamped height). --lh comes from the 'lh' key on each row of
       ignite_showcase_logos(); the fallback only applies to a row that forgot one. */
    height:var(--lh, 42px);
    /* WHITE TREATMENT (19 Aug) — brightness(0) crushes every colour to black, invert(1)
       lifts it to white, and alpha is untouched, so a transparent-background mark becomes
       a clean white silhouette. Works on 14 of the 16; the two exceptions opt out below. */
    filter:brightness(0) invert(1);}
    /* KNOCKOUT LOGOS CANNOT GO SINGLE-COLOUR WHITE. Refuel and Love's are both a solid
       coloured container with their name knocked OUT of it — the letterforms are the
       absence of ink, not ink. Invert the container to white and the white letters have
       nothing left to contrast against, so the mark collapses into a blank blob. Measured:
       Refuel went to 74% coverage at 97% near-white, Love's to 95% at 97%.
       grayscale(1) with a lift keeps the container light and the knockout readable, so the
       row still reads as monochrome without either logo turning to mush.
       THE REAL FIX is a reversed one-colour file from the brand; remove this rule then. */
    /* 27 Aug: no logo currently carries .show-i-ko — Refuel was the last one and now ships
       as a reversed file from the brand. Kept for the next knockout mark. */
    .show-i-ko img{filter:grayscale(1) brightness(1.25) contrast(1.05);}
    /* Love's was exempted here on the belief its yellow card was baked in as opaque
     pixels. Wrong — the corners are transparent, so the card is a shape and separates
     cleanly. assets/img/loves.png is now a reversed white silhouette derived from the
     original; the box in it is the logo's own keyline, kept deliberately. */
  .wm{font-family:'Space Grotesk',system-ui,sans-serif; font-weight:500; font-size:clamp(13.5px,1.32vw,19px);
    letter-spacing:-.012em; line-height:1.16; text-align:center; color:rgba(245,240,234,.80);
    max-width:100%; text-wrap:balance;}
  @media (max-width:900px){ .show-g{grid-template-columns:repeat(3,1fr); gap:22px 16px;} }
  @media (max-width:620px){ .show-g{grid-template-columns:repeat(2,1fr); gap:20px 12px;} .show-i{min-height:64px;} }
  @media (max-width:620px){ .show{padding:52px 0 56px;} }
  @media print{ .show{padding:16px 0 !important;} .show-g{grid-template-columns:repeat(4,1fr) !important;} }

  /* About Us body paragraphs (18 Aug — the lead is now one para, followed by two body paras) */
  .abt-body{color:var(--muted); font-size:16.5px; line-height:1.74; max-width:62ch;
    font-weight:400; margin:0 0 20px;}
  .abt-body:last-of-type{margin-bottom:42px;}
  @media (max-width:620px){ .abt-body{font-size:15.5px; line-height:1.7;} }

  /* ---------- WHO YOU'D BE WORKING WITH (18 Aug) ---------- */
  .team-h{font-size:clamp(19px,2vw,24px); font-weight:700; letter-spacing:-.02em; color:var(--off);
    margin:6px 0 8px;}
  .team-lead{color:var(--muted-2); font-size:15px; line-height:1.65; font-weight:400;
    max-width:56ch; margin:0 0 30px;}
  .team{list-style:none; display:grid; grid-template-columns:repeat(4,1fr); gap:30px 22px;
    margin:0; padding:0;}
  .tm{margin:0;}
  .tm-ph{aspect-ratio:4/5; border-radius:10px; background:var(--bg-2); border:1px solid var(--line);
    display:grid; place-items:center; margin-bottom:14px; overflow:hidden;}
  .tm-ph img{width:100%; height:100%; object-fit:cover; display:block;}
  .tm-ph span{font-family:'IBM Plex Mono',monospace; font-size:9.5px; letter-spacing:.14em;
    text-transform:uppercase; color:var(--muted-2);}
  .tm-empty .tm-ph{border:1px dashed rgba(255,180,61,.46); background:transparent;}
  .tm-empty .tm-ph span{color:var(--amber);}
  .tm-n{font-size:15.5px; font-weight:500; color:var(--off); margin:0; letter-spacing:-.01em;}
  .tm-r{font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:.12em;
    text-transform:uppercase; color:var(--orange); margin:5px 0 0;}
  .tm-b{font-size:14px; line-height:1.6; color:var(--muted); font-weight:400; margin:8px 0 0;}
  .tm-empty .tm-n, .tm-empty .tm-r, .tm-empty .tm-b{color:var(--muted-2);}
  @media (max-width:900px){ .team{grid-template-columns:repeat(3,1fr); gap:26px 18px;} }
  @media (max-width:620px){ .team{grid-template-columns:repeat(2,1fr); gap:22px 14px;} }
  @media print{ .tm-empty{display:none !important;} }

  /* ── classes introduced by the theme templates (no mock equivalent) ── */
  .cb-sd{font-style:normal; opacity:.72;}
  .cb-vert{margin:18px 0 0; display:flex; align-items:baseline; gap:10px; flex-wrap:wrap;
    font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:.12em; text-transform:uppercase;}
  .cb-vert span{color:var(--muted-2);}
  .cb-vert a{color:var(--orange); border-bottom:1px solid rgba(255,106,61,.4);}
  .cb-vert a:hover{border-bottom-color:var(--orange);}
  .cb-vert em{color:var(--muted); font-style:normal;}
  .cases-filter{display:flex; gap:9px; flex-wrap:wrap; margin:30px 0 6px;}
  .cases-filter a{display:inline-flex; align-items:baseline; gap:8px;
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--muted); border:1px solid var(--line); border-radius:99px; padding:9px 16px;
    transition:border-color .25s cubic-bezier(.2,.8,.2,1), color .25s cubic-bezier(.2,.8,.2,1);}
  .cases-filter a:hover{color:var(--off); border-color:var(--line-2);}
  .cases-filter a[aria-current]{color:var(--orange); border-color:rgba(255,106,61,.55);}
  .cases-filter a span{font-size:10px; color:var(--muted-2);}
  .cases-filter a[aria-current] span{color:var(--orange);}
  @media (max-width:640px){ .cases-filter a{font-size:10px; padding:7px 12px;} }

  /* ══════════════════════════════════════════════════════════════════════════
     BLOG INDEX ROWS — 3 Sept 2026
     archive.php. Sits below .cases-hero/.cases-filter (reused as-is, no new
     rules needed for either). Modeled on the Claude Design canvas mockup Alex
     picked ("Editorial List" direction), which itself borrowed .cases-index's
     numbered-row DNA — this is that DNA with the extra fields a blog row needs
     that a case-study index row doesn't: category, excerpt, date, read time.
     ══════════════════════════════════════════════════════════════════════════ */
  .blog-list{margin:40px 0 0; border-top:1px solid var(--line);}
  .blog-row{
    display:flex; gap:clamp(20px,2.6vw,44px); align-items:flex-start;
    padding:34px 0; border-bottom:1px solid var(--line);
  }
  .blog-row:nth-child(even){background:var(--bg-2); margin:0 -34px; padding:34px 34px; border-bottom:1px solid var(--line);}
  .blog-row-n{font-size:11.5px; letter-spacing:.1em; color:var(--muted-2); flex-shrink:0; width:64px; padding-top:8px;}
  .blog-row-body{flex:1 1 auto; min-width:0;}
  .blog-row-cat{
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.13em; text-transform:uppercase;
    color:var(--orange); margin:0 0 12px;
  }
  .blog-row-title{font-size:clamp(22px,2.4vw,30px); font-weight:600; letter-spacing:-0.015em; line-height:1.12; margin:0 0 12px; max-width:34ch;}
  .blog-row-title a{color:var(--off); transition:color .25s ease;}
  .blog-row-title a:hover, .blog-row-title a:focus-visible{color:var(--orange);}
  .blog-row-ex{font-size:15px; color:var(--muted); line-height:1.7; font-weight:400; max-width:64ch; margin:0 0 18px;}
  .blog-row-meta{display:flex; flex-wrap:wrap; align-items:center; gap:18px;}
  .blog-row-date{font-size:11px; letter-spacing:.08em; color:var(--muted-2);}
  .blog-row-more{
    display:flex; align-items:center; gap:8px;
    font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:.12em; text-transform:uppercase;
    color:var(--muted-2); transition:color .25s ease;
  }
  .blog-row-more:hover, .blog-row-more:focus-visible{color:var(--orange);}
  .blog-chev{
    width:8px; height:8px; flex-shrink:0; border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
    transform:rotate(-45deg); transition:transform .3s cubic-bezier(.2,.8,.2,1);
  }
  .blog-row-more:hover .blog-chev, .blog-row-more:focus-visible .blog-chev{transform:rotate(-45deg) translate(3px,3px);}
  @media (max-width:640px){
    .blog-row{flex-direction:column; gap:10px; padding:26px 0;}
    .blog-row-n{width:auto; padding-top:0;}
    .blog-row:nth-child(even){margin:0 -22px; padding:26px 22px;}
  }

  /* ══════════════════════════════════════════════════════════════════════════
     MOBILE POLISH — 27 Aug 2026
     Every rule below is inside `@media screen and (max-width:760px)` on purpose.
     The desktop layout is deliberately untouched; this block only exists to fix
     defects that appear on phones. Verified by pixel-diffing full-page desktop
     renders at 1440 / 1024 / 768 before and after: zero changed pixels.

     `screen and` is not decoration. A bare (max-width:760px) query also applies
     when printing, because it defaults to media type `all`, and a narrow paper
     size would pull these rules into the print stylesheet. Scoping to `screen`
     keeps the print rules further up this file authoritative.

     Placed at the END of the stylesheet on purpose: it has to win over the
     earlier (max-width:640px) block, which is later in source order than the
     760px one and would otherwise override the type floor on .cases-filter.
     ────────────────────────────────────────────────────────────────────────── */
@media screen and (max-width:760px){

  /* ── 1. iOS INPUT ZOOM ──────────────────────────────────────────────────
     iOS Safari force-zooms the whole page when a focused form control is under
     16px, then leaves the user pinching back out. 14.5px triggered it on all
     three fields of the audit form. 16px is the documented threshold, not a
     preference — do not lower it. Desktop keeps 14.5px. */
  .f input, .f select, .f textarea{font-size:16px;}

  /* ── 2. TYPE FLOOR, 12px ────────────────────────────────────────────────
     Everything the audit found below 11.5px, lifted to 12px. The 11.5px mono
     label family is deliberately left alone — it is legible in IBM Plex Mono at
     that size, and rescaling it would move a lot of layout for no gain.
     Side effect worth knowing: a handful of former-11px labels now sit 0.5px
     ABOVE their 11.5px neighbours. Imperceptible, but if you would rather the
     whole small-label family matched, add 11.5px to this list.
     The 10px a[href]::after rule is NOT here on purpose — it is print-only. */
  .tm-ph span{font-size:12px;}            /* was 9.5px  — team photo placeholders */
  .c-pend{font-size:12px;}                /* was 9px    — pending card tag (staging) */
  .aw-org, .aw-rank, .slot-tag{font-size:12px;}   /* was 10.5px — award meta */
  .tm-r{font-size:12px;}                  /* was 10.5px — team roles */
  .cb-vert{font-size:12px;}               /* was 10.5px — case-study verticals */
  .c-cat{font-size:12px;}                 /* was 11px   — work card category */
  .sys h3::before{font-size:12px;}        /* was 11px   — engine system number */
  .cb-cat, .cb-stats span, .cb-body h3, .cb-ch li{font-size:12px;}  /* was 11px */
  .menu-h, .menu-views a em{font-size:12px;}      /* was 11px — nav panel labels */
  .abt-quote figcaption{font-size:12px;}  /* was 11px   — testimonial attribution */
  .form .wpcf7-not-valid-tip{font-size:12px;}     /* was 11px — CF7 validation text */
  .cases-filter a{font-size:12px;}        /* was 11px, and 10px under 640 */
  .cases-filter a span{font-size:12px;}   /* was 10px   — filter counts */

  /* ── 3. TAP TARGETS TO 44px, WITHOUT MOVING ANYTHING ────────────────────
     Apple's minimum is 44x44. The audit found 31 controls under it. These fixes
     are all invisible: a min-height inside a box that is already taller, or an
     absolutely-positioned transparent ::after that grows the hit area without
     participating in layout. Nothing shifts by a pixel.

     NOT FIXED, deliberately: the five ICARE letters. They are already 45px tall,
     but 17-40px wide, and they sit adjacent inside one word. Widening their hit
     areas would either overlap the neighbouring letter — so a tap near an edge
     would fire the wrong value — or require letter-spacing, which is a visible
     change. Left as they are. */

  /* Showcase logo links took their height from the logo image, so the short
     wordmarks (Domino's 34px, Travel+Leisure 33px, Clemson 30px) had short hit
     areas. The figure is 88px tall and the anchor is centred in it, so a
     min-height is free. */
  .show-i a{min-height:44px;}

  /* "Read the case study" was 32px tall. The ::after reaches into the card's own
     padding above and below — .c-client above it is not interactive, so nothing
     is stolen. .card-ph .c-more is already position:relative; this covers the
     non-photo cards too. */
  .c-more{position:relative;}
  .c-more::after{content:''; position:absolute; left:0; right:0; top:-6px; bottom:-6px;}

  /* Header wordmark was 52x21. Expanding it also puts real distance between the
     logo and the hero headline for mis-taps. No conflict with the burger, which
     is at the opposite end of the header. */
  .logo{position:relative;}
  .logo::after{content:''; position:absolute; left:-8px; right:-8px; top:-12px; bottom:-12px;}


  /* Footer link lists. `.f-col a` is display:inline at 14px, so each of the eight
     links was a 16px-tall target in a 33px row pitch. The ::after fills the 17px
     gap between adjacent links — 8px above and below — which doubles each target
     to 32px with a 1px sliver left between neighbours, so a tap can never land on
     the wrong link. NOT 44px: that needs the row pitch to grow to 44, which is a
     visible spacing change and was explicitly not wanted. 32px is the most that
     fits inside the existing layout. */
  /* 31 Aug: was `.f-col li a`. footer.php renders these as <a> inside <p> separated by
     <br> — there is NOT ONE <li> in the footer — so this matched nothing and every footer
     link, including the phone number, was a 16px target on a phone. Measured:
     document.querySelectorAll('.f-col li a').length === 0. Selector corrected to `p a`.
     The comment above describes the mock's footer, which does use lists and has eight
     links; footer.php has six. See deploy/AUDIT-2026-08-31.md. */
  .f-col p a{position:relative;}
  .f-col p a::after{content:''; position:absolute; left:0; right:0; top:-8px; bottom:-8px;}
  /* Rail prev/next and the filter chips are already at or above 44px — measured,
     not assumed. */
}
