/* ================================================================
   css/pages/home.css — the home route's own sections.
   Load order: fonts -> tokens -> base -> sections/* -> THIS.

   GEOMETRY MODEL
   Section roots (from the reference's own root rules):
     >=1440      viewport-derived / clamped -> interiors cannot move the
                 measured height, so no band sizing is needed there
     810-1439.98 height:min-content, max-height:1000px still clamping the
                 tall sections to exactly 1000
     <=809.98    max-height:unset -> every height is the sum of its bands

   Below 1440 the reference lays each section out as a vertical stack of
   fixed-height BANDS separated by 1px hairlines. Every band height in this
   file was measured off the raw capture rendered at the capture viewport
   (scratchpad/probe.mjs), not guessed. Capture viewports: desktop 1440x900,
   laptop 1280x832, tablet 810x1080, phone 390x844.

   Only `her` keeps its hairline at phone; every other section drops it.
   ================================================================ */

/* ---------------------------------------------------------------
   0. Section / band primitives
   --------------------------------------------------------------- */
.hm-sec {
  display: flex;
  flex-flow: column;
  flex: none;
  gap: 0;
  padding: 0;
  position: relative;
  overflow: var(--overflow-clip-fallback, clip);
}

.hm-band {
  flex: none;
  width: 100%;
  display: flex;
  position: relative;
  overflow: var(--overflow-clip-fallback, clip);
}

/* content container: page inset + max width, fills its band */
.hm-cc {
  width: 100%;
  /* live's 1520px max-width is the CONTENT box (the reference pads a separate
     outer root, cf. .menu-line-root) — the 32px inset sits OUTSIDE it. Folding
     the padding into the same border-box clamped the line grid at 1456px and
     drifted every line once the viewport passed 1440. */
  max-width: calc(var(--page-max) + var(--page-pad-desktop) * 2);
  margin: 0 auto;
  padding: 0 var(--page-pad-desktop);
  display: flex;
  align-items: center;
  gap: 24px;
  position: relative;
}
@media (max-width: 809.98px) {
  .hm-cc { padding: 0 var(--page-pad-phone); gap: 16px; }
}

/* hairlines
   The reference's "Vert line" divs sit at the SAME x as the content they
   precede (measured: Subheader part's line and its container are both x=32) —
   i.e. they overlay the column edge and consume no horizontal space. Laying
   them out as ordinary flex items pushed every heading/badge on the page ~25px
   right of the reference. They are absolute here for that reason. */
.hm-hline {
  height: 1px;
  width: 100%;
  flex: none;
  background: var(--c-hairline);
}
.hm-vline {
  width: 1px;
  align-self: stretch;
  flex: none;
  background: var(--c-hairline);
}
/* The orange rules are DASHED in the reference (visible as a dashed rail at
   x=491 running the whole page, and at the left inset on phone) — not solid. */
.hm-vline--orange {
  background: none;
  border-left: 1px dashed var(--c-orange);
}

.hm-cc > .hm-vline {
  position: absolute; top: 0; bottom: 0; left: var(--page-pad-desktop);
  width: 1px; height: auto; align-self: auto;
}
.hm-cc > .hm-vline:last-child { left: auto; right: var(--page-pad-desktop); }
@media (max-width: 809.98px) {
  .hm-cc > .hm-vline { left: var(--page-pad-phone); }
  .hm-cc > .hm-vline:last-child { left: auto; right: var(--page-pad-phone); }
}

/* THE 1/3 RAIL.  process / projects / allstack / testimonials / help put their
   badge + heading (and their orange rule) one third of the way across the
   content container, not at its left edge — measured x=491 @1440, 437 @1280,
   281 @810, all exactly `inset + containerWidth/3`. areas / results /
   environments / value / annual keep theirs at the left edge. At phone every
   section is left-aligned. */
@media (min-width: 810px) {
  .hm-cc--rail > :not(.hm-vline) { margin-left: 33.3333%; }
  .hm-cc--rail > .hm-vline--orange {
    left: calc(var(--page-pad-desktop) + (100% - var(--page-pad-desktop) * 2) / 3);
  }
}

/* numbered section badge — always a 31px-tall pill (num 31x31 + label),
   bottom-aligned in its band with a 24px gap under it. */
.hm-sechead { align-items: flex-end; }
.hm-sechead > .hm-badge { margin-bottom: 24px; }
.hm-sechead > [class$="__headc"],
.hm-sechead > [class$="__illbody"] { align-self: stretch; }
.hm-badge { display: flex; align-items: stretch; flex: none; height: 31px; }
.hm-badge__num {
  display: flex; align-items: center; justify-content: center;
  width: 31px; flex: none;
  background: var(--c-orange); color: var(--c-white);
}
.hm-badge__label {
  display: flex; align-items: center; padding: 0 10px;
  background: var(--c-stone-cool-50); color: var(--c-black);
}
/* on-dark sections use the graphite-light label chip */
.hm-projects .hm-badge__label,
.hm-annual .hm-badge__label { background: var(--c-graphite-lt); color: var(--c-white); }

/* At phone the reference renders NO numbered section badges at all — a probe
   of research/raw/phone/home.html finds only the 57x57 process/value step
   numbers, and reference/phone/home.jpeg shows bare headings with no chip
   above them. The first build showed the chip at every breakpoint, which also
   pushed each heading down by the chip's height. */
@media (max-width: 809.98px) {
  .hm-sec .hm-badge { display: none; }
}

/* ---------------------------------------------------------------
   1. Section roots — the rules that make >=1440 exact
   --------------------------------------------------------------- */
/* Section background colours are the reference's own root rules, read out of
   research/_stylesheet.css (the root class of each research/fragments/home/*.html)
   and re-confirmed against the rendered raw capture (scratchpad/bands.mjs):
     her #f2f0ee  areas #fff     process #f2f0ee  results #dedcda(stone-light)
     projects #202020(graphite)  environments #f2f0ee  allstack #fff
     value #f2f0ee  testimonials #dedcda  *-annual #202020  help #fff  footer #f2f0ee
   Do not swap these — six of them were inverted in the first build. */
.hm-her { height: 100vh; background: var(--c-cream); }
.hm-results { height: 75vh; max-height: 600px; background: var(--c-stone-light); }
.hm-areas, .hm-process, .hm-projects, .hm-envs,
.hm-stack, .hm-value, .hm-testi {
  height: 100vh;
  max-height: 1000px;
}
.hm-areas   { background: var(--c-white); }
.hm-process { background: var(--c-cream); }
.hm-projects{ background: var(--c-graphite); }
.hm-envs    { background: var(--c-cream); }
.hm-stack   { background: var(--c-white); }
.hm-value   { background: var(--c-cream); }
.hm-testi   { background: var(--c-stone-light); }

@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-areas, .hm-projects, .hm-stack, .hm-value, .hm-testi {
    height: min-content;            /* max-height:1000px clamps -> exactly 1000 */
  }
  .hm-process { height: min-content; max-height: unset; }   /* 751 */
  .hm-envs    { height: min-content; max-height: unset; }   /* 750 / 899 */
}
@media (max-width: 809.98px) {
  .hm-her, .hm-results,
  .hm-areas, .hm-process, .hm-projects, .hm-envs,
  .hm-stack, .hm-value, .hm-testi {
    height: min-content;
    max-height: unset;
  }
}

/* ---------------------------------------------------------------
   1b. Band heights — DESKTOP TIER (>=1440)
   Measured off research/raw/desktop/home.html rendered at 1440x900
   (scratchpad/bands.mjs), exactly as the tiers below were. Without these the
   bands collapse to their content and every interior crowds into the top
   third of its 900px section — the single largest source of visual drift in
   the first build. The roots are viewport-derived + overflow:clip at this
   tier, so band heights can never move a measured section height.
   --------------------------------------------------------------- */
@media (min-width: 1440px) {
  .hm-areas__b1 { height: 225px; }
  .hm-areas__b2 { height: 450px; }
  .hm-areas__b3 { height: 225px; }

  .hm-process__b1 { height: 225px; }
  .hm-process__b2 { height: 225px; }
  .hm-process__b3 { height: 450px; }

  .hm-results__b1 { height: 120px; }
  .hm-results__b2 { height: 480px; }

  /* Projects is viewport-derived until its 1000px cap. Keeping these rows
     proportional is essential above 1440px: the live section grows from
     225/674 at 900px tall to 250/749 at the cap. */
  .hm-projects__b1 { height: 25%; }
  .hm-projects__b2 { height: calc(75% - 1px); }

  .hm-envs__b1 { height: 135px; }
  .hm-envs__b2 { height: 675px; }
  .hm-envs__b3 { height: 90px; }

  .hm-stack__b1 { height: 225px; }
  .hm-stack__b2 { height: 450px; }
  .hm-stack__b3 { height: 225px; }

  .hm-value__b1 { height: 135px; }
  .hm-value__b2, .hm-value__b3, .hm-value__b4 { height: 225px; }
  .hm-value__b5 { height: 90px; }
  .hm-value__gradient { height: 339px; }

  .hm-testi__b1 { height: 225px; }
  .hm-testi__b2 { height: 674px; }

  .hm-annual__b1 { height: 135px; }
  .hm-annual__b2 { height: 135px; }
  .hm-annual__b3 { height: 189px; }
  .hm-annual__b4 { height: 225px; }
  .hm-annual__b5 { height: 225px; }
}

/* `her`'s three bands are 50%/25%/25% of the (viewport-derived) root at every
   tier >=810 — 450/225/225 @900, 416/208/208 @832, 540/270/270 @1080. The
   first build hard-coded the tablet 270 across the whole 810-1439.98 range,
   which put the hairline 125px low at laptop. */
@media (min-width: 810px) {
  .hm-her__b1 { height: 50%; }
  .hm-her__b2, .hm-her__b3 { height: 25%; }
}

/* ---------------------------------------------------------------
   2. Band heights — TABLET TIER (810-1439.98)
   --------------------------------------------------------------- */
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-areas__b1 { height: 250px; }
  .hm-areas__b2 { height: 500px; }
  .hm-areas__b3 { height: 250px; }

  .hm-process__b1, .hm-process__b2, .hm-process__b3 { height: 250px; }

  .hm-results__b1 { height: 120px; }
  .hm-results__b2 { height: 480px; }

  .hm-projects__b1 { height: 250px; }
  .hm-projects__b2 { height: 800px; }      /* > clamp, section pins to 1000 */

  .hm-envs__b1 { height: 150px; }
  .hm-envs__b2 { height: 648px; }          /* 810-1199 */
  .hm-envs__b3 { height: 100px; }

  .hm-stack__b1 { height: 250px; }
  .hm-stack__b2 { height: 499px; }
  .hm-stack__b3 { height: 250px; }

  .hm-value__b1 { height: 150px; }
  .hm-value__b2, .hm-value__b3, .hm-value__b4 { height: 250px; }
  .hm-value__b5 { height: 100px; }

  .hm-testi__b1 { height: 250px; }
  .hm-testi__b2 { height: 800px; }         /* > clamp, section pins to 1000 */

  .hm-annual__b1 { height: 150px; }
  .hm-annual__b2 { height: 150px; }
  .hm-annual__b3 { height: 210px; }
  .hm-annual__b4 { height: 250px; }
  .hm-annual__b5 { height: 239px; }
}

/* environments reflows narrower at the laptop type tier */
@media (min-width: 1200px) and (max-width: 1439.98px) {
  .hm-envs__b2 { height: 499px; }          /* -> 150+1+499+100 = 750 */
}

/* ---------------------------------------------------------------
   3. Band heights — PHONE (<=809.98)
   --------------------------------------------------------------- */
@media (max-width: 809.98px) {
  .hm-her__b1 { height: 338px; }
  .hm-her__b2 { height: 295px; }
  .hm-her__b3 { height: 68px; }

  .hm-areas__b1 { height: 100px; }
  .hm-areas__b2 { height: 502px; }
  .hm-areas__b3 { height: 157px; }

  .hm-process__b1 { height: 133px; }
  .hm-process__b2 { height: 484px; }

  .hm-results__b2 { height: 445px; }

  .hm-projects__b1 { height: 133px; }
  .hm-projects__b2 { height: 759px; }

  .hm-envs__b2 { height: 758px; }
  .hm-envs__b3 { height: 60px; }

  .hm-stack__b1 { height: 133px; }
  .hm-stack__b2 { height: 400px; }
  .hm-stack__b3 { height: 120px; }

  .hm-value__b2 { height: 342px; }
  .hm-value__b3 { height: 200px; }
  .hm-value__b5 { height: 60px; }

  .hm-testi__b1 { height: 140px; }
  .hm-testi__b2 { height: 1079px; }

  .hm-annual__b2 { height: 150px; }
  .hm-annual__b4 { height: 396px; }
  .hm-annual__b5 { height: 158px; }
}

/* ---------------------------------------------------------------
   4. Interior styling
   --------------------------------------------------------------- */

/* --- her --------------------------------------------------------------
   GRID MODEL (research/raw/desktop/home.html + _stylesheet.css)

   Every hero band is `padding: 0 32px` around a content container that splits
   into a LEFT part (`flex:1 0 0`) and a RIGHT part (`flex:2 0 0`) — a 1/3 : 2/3
   split. Both left parts ("Left part of ill" .framer-1lgvd6o, "Left part"
   .framer-1ypvrw9) carry `hidden-1ebz3up hidden-ovi0ti`, i.e. they exist ONLY
   at >=1440, so the slogan / description / buttons hang off the 1/3 rail at
   desktop and start at the container edge at every smaller tier. The first
   build left-aligned them at all four, which put the headline 459px left of
   the reference at 1440.

   The right part is itself four equal columns, each carrying a 1px "Vert line"
   (#cfcecc80) on its left edge; together with the left part's two that is a
   plain 6-column rule grid across the container, reproduced here as one
   .hm-her__grid gradient rather than six real elements.
   ---------------------------------------------------------------------- */
/* "Gradient top" .framer-1g3zr2f is `z-index:3; height:449px;
   background: linear-gradient(#f2f0ee 39%, #f2f0ee00 100%)` — SOLID CREAM
   fading to transparent, whose whole job is to mask the halftone strip's
   upper overhang (strip z-index:1 inside a z-index:2 band; band 1 above it at
   z-index:4 is transparent, so the fade is what you actually see through it).
   The clone had it as a stone-40 GREY wash, which tinted the entire top 449px
   of the page — including the fixed menu line — a half-shade dark. */
.hm-her__gradient {
  position: absolute; inset: 0 0 auto 0; height: 449px;
  background: linear-gradient(#f2f0ee 39%, #f2f0ee00 100%);
  pointer-events: none;
  z-index: 3;
}

/* the 1/3 rail, DESKTOP ONLY (cf. .hm-cc--rail, which starts at 810).
   `.hm-rail-off` marks the one child that carries the offset — the bands with
   two columns (areas' logo band) must not offset both. */
@media (min-width: 1440px) {
  .hm-cc--rail-lg > .hm-rail-off { margin-left: 33.3333%; }
  .hm-cc--rail-lg > .hm-vline--orange {
    left: calc(var(--page-pad-desktop) + (100% - var(--page-pad-desktop) * 2) / 3);
  }
}

/* the six column rules + the closing right edge */
.hm-her__grid {
  position: absolute; top: 0; bottom: 0;
  left: var(--page-pad-desktop); right: var(--page-pad-desktop);
  pointer-events: none; z-index: 0;
  background-image: repeating-linear-gradient(
    to right, var(--c-stone-cool-50) 0 1px, transparent 1px calc(100% / 6));
}
.hm-her__grid::after {
  content: ""; position: absolute; top: 0; bottom: 0; right: 0;
  width: 1px; background: var(--c-stone-cool-50);
}
/* tablet keeps the grid but at THREE columns (measured live 810: lines at
   32 / 280.7 / 529.3 / 777 — even (W-64)/3 spacing); phone drops it. */
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-her__grid {
    background-image: repeating-linear-gradient(
      to right, var(--c-stone-cool-50) 0 1px, transparent 1px calc(100% / 3));
  }
}
@media (max-width: 809.98px) { .hm-her__grid { display: none; } }

.hm-her__ill { align-items: stretch; }
.hm-her__illbody {
  flex: 1 1 auto; min-width: 0;      /* without min-width:0 the headline's
                                        max-content width wins and it overflows
                                        the viewport instead of wrapping */
  align-self: stretch; position: relative;
  display: flex; flex-direction: column; justify-content: flex-start;
  gap: 0; padding: 0;
}
/* "Subheader container" .framer-pizonr is `padding: 30px 0 0` */
.hm-her__illbody > .hm-badge { margin-top: 30px; margin-bottom: 0; }
/* the h1 is `position:absolute; bottom:-10px; left:1px; max-width:540px` — it
   deliberately overhangs its band's bottom edge by 10px. Flowing it instead
   (the first build) let a six-line wrap push the "01 intro" badge out of the
   clipped band entirely. */
.hm-her__headline {
  position: absolute; left: 0; bottom: -10px;
  width: 100%; max-width: 540px;
}
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-her__headline { max-width: 440px; bottom: -9px; }
}

/* --- her: the illustration ---------------------------------------------
   Two separate Framer components, on different breakpoint schedules:

   "Left part of ill" (.framer-1lgvd6o) is `flex:1 0 0` inside the hero's
   content container — the LEFT THIRD — and is hidden-1ebz3up hidden-ovi0ti,
   so it only exists at >=1440. It carries three 1px dashed rules
   (.framer-1jdd32l/-zhqew1/-gln5l7: `width:150%; left:72.6281%;
   bottom:143/127/111px`) and the "Step 4" graphic
   (.framer-11wf69e-container: `width:146px; bottom:68px; left:57%;
   translate(-50%)`, min-height 120 from .framer-8hm42d).

   "Step 6" (.framer-swka40-container) hangs off the RIGHT part
   (.framer-7zyi6w, `flex:2 0 0`) at `bottom:-38px; left:76%` (>=1440) /
   `bottom:-67px; left:75%` (810-1439), and is hidden-ovi0ti — so it renders
   at desktop, laptop and tablet but never at phone.

   The clone has no real left/right flex split (it fakes the reference's 1/3
   with `margin-left:33.3333%` on .hm-rail-off), so the left part is an
   absolute box over the same third of .hm-cc, and Step 6 is anchored inside
   .hm-her__illbody, which occupies exactly the reference's right part.

   Checks against reference/desktop/home.jpeg, band 1 = y0..450:
     step 4 tiles      x233-352  y262-381   (container 220.4..366.4, bottom 68)
     dashed rules      y306/322/338         (= 450 - 143/127/111 - 1)
     orange square     x1133-1260 y258-385  (128x128 @ top103 left158)
     sheet 1 (top)     x1177-1216 y155-204  (@ top0   left202)
     sheet 2 (right)   x1315-1354 y296-346  (@ top141 left340)
     sheet 3 (bottom)  x1177-1216 y438-488  (@ top283 left202)
   ---------------------------------------------------------------------- */
.hm-her__illleft {
  position: absolute; top: 0; bottom: 0;
  left: var(--page-pad-desktop);
  width: calc((100% - var(--page-pad-desktop) * 2) / 3);
  pointer-events: none; z-index: 1;
}
@media (max-width: 1439.98px) { .hm-her__illleft { display: none; } }

/* the three dashed rules run right OUT of the left third (width:150%) to meet
   the "Arrows to" glyph at the orange square's left edge (x1133). */
.hm-her__illrule {
  position: absolute; left: 72.6281%; width: 150%;
  height: 0; border-top: 1px dashed rgba(210, 206, 202, 0.85);
}
.hm-her__illrule--1 { bottom: 143px; }
.hm-her__illrule--2 { bottom: 127px; }
.hm-her__illrule--3 { bottom: 111px; }

.hm-her__step4 {
  position: absolute; bottom: 68px; left: 57%;
  transform: translateX(-50%);
  width: 146px; height: 120px;
}
.hm-her__step4-base { position: absolute; top: 0; left: 13px; width: 120px; height: 120px; }
.hm-her__step4-chip { position: absolute; top: 22px; left: 16px; width: 106.162px; height: 94.162px; }

.hm-her__step6 {
  position: absolute; bottom: -38px; left: 76%;
  transform: translateX(-50%);
  width: 426px; height: 333px;
  overflow: hidden;             /* .framer-swfo5s is overflow:clip */
  pointer-events: none; z-index: 1;
}
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-her__step6 { bottom: -67px; left: 75%; }
}
@media (max-width: 809.98px) { .hm-her__step6 { display: none; } }
/* live REMOVES the hero "01 intro" badge below 1440 (probed: in DOM at 1440,
   gone at 810) — without this it lands on top of the nav logo at tablet. */
@media (max-width: 1439.98px) {
  .hm-her__illbody > .hm-badge { display: none; }
}

/* every piece is absolutely placed against the 426x333 box; DOM order is the
   reference's own paint order (square, angles, lines, logo, sheets, arrows). */
.hm-her__step6 .s6 { position: absolute; }
.s6-square { top: 103px; left: 158px; width: 128px; height: 128px; }
.s6-angles { top: 112px; left: 168px; width: 109px; height: 109px; }
/* "Lines" is the one non-absolute child (`position:relative`, 427x162) in a
   `place-content:center` flex row, i.e. centred in the 426x333 box. */
.s6-lines  { top: 85.5px; left: -0.5px; width: 427px; height: 162px; }
.s6-logoblock {
  position: absolute; top: 50%; left: 52%;
  transform: translate(-50%, -50%);
  width: 90px; height: 90px;
}
.s6-biege { position: absolute; top: 0; left: 0; width: 90px; height: 90px; }
.s6-logo  { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 44px; height: 44px; }
.s6-sheet1 { top: 0;     left: 202px; width: 40px; height: 50px; }
.s6-icon1  { top: 18px;  left: 214px; width: 14px; height: 17px; }
.s6-sheet2 { top: 141px; left: 340px; width: 40px; height: 50px; }
.s6-icon2  { top: 161px; left: 353px; width: 15px; height: 14px; }
.s6-sheet3 { top: 283px; left: 202px; width: 40px; height: 50px; }
.s6-icon3  { top: 302px; left: 212px; width: 18px; height: 13px; }
.s6-arrup    { top: 52px;  left: 218px; width: 8px;  height: 55px; }
.s6-arrto    { top: 147px; left: 90px;  width: 68px; height: 40px; }
.s6-arrright { top: 163px; left: 283px; width: 56px; height: 8px; }
.s6-arrdown  { top: 227px; left: 218px; width: 8px;  height: 55px; }

/* her's two CTAs are a LIGHT button then a dark one (reference/<bp>/home.jpeg);
   `btn-dark` alone paints both graphite. */
.hm-her__cta .btn-dark--light { background-color: var(--c-white); }
.hm-her__cta .btn-dark--light .btn-dark__text .t-mono { color: var(--c-black); }
.hm-her__cta .btn-dark--light:hover .btn-dark__text .t-mono,
.hm-her__cta .btn-dark--light:focus-visible .btn-dark__text .t-mono { color: var(--c-white); }
/* description band: the note is pinned 40px from the band top and the button
   row is pinned to the band's bottom edge — "Description text" .framer-16dg38w
   is `position:absolute; top:40px; left:1px; max-width:340px` and "Buttons"
   .framer-4c1t1j is `position:absolute; bottom:0; left:1px; right:0`. Laying
   the two out as one centred flex row instead (the first build) gave
   `.btn-dark`'s `flex:1 0 0; width:1px` no definite width to grow into, so
   both buttons rendered 1px wide and were invisible at every tier >=810. */
.hm-her__desc { align-items: stretch; }
.hm-her__descbody {
  flex: 1 1 auto; min-width: 0; align-self: stretch; position: relative;
}
/* the hero's standfirst is mono UPPERCASE in the reference at every
   breakpoint, not sentence-case body copy */
.hm-her__note {
  position: absolute; top: 40px; left: 0;
  width: 100%; max-width: 340px;
}
.hm-her__note .t-mono { text-transform: uppercase; }
.hm-her__cta {
  position: absolute; bottom: 0; left: 0; right: 0;
  display: flex; flex-direction: row; align-items: center; gap: 0;
}
.hm-her__cta .btn-dark { flex: 1 0 0; width: 1px; height: 57px; }

/* --- her: the "Advantages" strip ---
   three equal columns on the same grid. Each holds an absolutely positioned
   stack ("Content container" .framer-zuscu: `position:absolute; top:0;
   width:100%; padding:50px 0 0; gap:12px`) of an 8x8 orange angle over a
   160px-wide label. That label is the 15px mono preset (w45aii), not mono-xs,
   and the 160px cap is what wraps each one onto two lines. */
.hm-her__stats { align-items: stretch; }
.hm-her__stat { flex: 1 0 0; min-width: 0; align-self: stretch; position: relative; }
.hm-her__statbody {
  position: absolute; top: 0; left: 0; width: 100%;
  padding-top: 50px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
}
/* .framer-19lwfk4 carries `--framer-text-wrap-override: balance`; without it
   "CUT ADMIN TIME BY / UP TO 50%" breaks a word early against the
   reference's "CUT ADMIN TIME / BY UP TO 50%". */
.hm-her__statbody .t-mono {
  max-width: 160px; text-transform: uppercase; text-wrap: balance;
}
.hm-her__angle {
  width: 8px; height: 8px; flex: none;
  border-top: 1px solid var(--c-orange);
  border-left: 1px solid var(--c-orange);
}
/* "→ → →" .framer-1gjxxb: absolute, 33x20, bottom:6px, left:-16px of the
   SECOND advantage, so it straddles that column's rule near the band foot. */
.hm-her__arrows {
  position: absolute; bottom: 6px; left: -16px;
  width: 33px; height: 20px; color: var(--c-orange);
}

/* --- her: the "background header" halftone strip ---
   .framer-ayz784-container is `height:793px; bottom:-63px; left:-1017px;
   right:-1017px` inside the DESCRIPTION band, marqueeing
   iEh0WlD2mo4i3VmbpP52rJl0.png (the same plate the footer uses) under a
   scale(1.07664) wrapper. It overhangs both neighbours: band 1 is transparent
   so the strip shows through its lower third, band 3 is opaque cream and
   clips it. The first build omitted it, leaving flat cream where the
   reference has ~250px of dither across the full viewport width. */
.hm-her__dither {
  position: absolute; left: -1017px; right: -1017px; bottom: -63px;
  height: 793px; z-index: 1; pointer-events: none; overflow: hidden;
}
.hm-her__dither-scale {
  position: relative; width: 100%; height: 100%; overflow: hidden;
  transform: scale(1.07664);
}
.hm-her__dither .marquee { left: -73.65px; }
/* the strip has to escape its band, and the content has to stay above it */
.hm-her__b1, .hm-her__b2 { overflow: visible; }
/* The reference stacks the hero as: strip 1 < band2/band3 2 < "Gradient top" 3
   < band1 4 (.framer-ar1e17 is z-index:4, .framer-1g3zr2f is z-index:3). The
   clone had band 1's content at z-index:2 — i.e. UNDER the gradient — so the
   solid-cream half of that 449px fade was washing the whole top of the hero:
   the headline read grey-on-cream instead of black, and the illustration was
   ghosted. The gradient still masks the halftone strip, which is below it. */
.hm-her__b1 { z-index: 4; }
.hm-her__b2 { z-index: 2; }
.hm-her__b1 > .hm-cc, .hm-her__b2 > .hm-cc { z-index: 2; }
.hm-her__b3 { background: var(--c-cream); z-index: 2; }
@media (max-width: 809.98px) {
  /* .framer-7iowuh at <=809.98 is `width:90%; max-width:440px; bottom:-6px`.
     Letting the headline use the full 338px column is what pulls "AI" up onto
     line 2 — the clone read "Automate client / operations with AI / systems"
     against the reference's "Automate client / operations with / AI systems". */
  .hm-her__headline { width: 90%; max-width: 440px; bottom: -6px; }
  /* .framer-16dg38w at phone is `width:338px` (the full column) */
  .hm-her__note { max-width: 338px; }
  /* "Buttons" .framer-4c1t1j goes `flex-direction:column` and each button
     container becomes `flex:none; width:100%`. */
  /* measured on reference/phone/home.jpeg: the two buttons are 57px each and
     butt directly against one another (white 520..576, dark 577..633) — the
     container's `gap` stays 0 through the direction change. */
  .hm-her__cta { flex-direction: column; align-items: stretch; gap: 0; }
  /* live's phone buttons start at x27 — the rail's dash runs uncovered at
     x26 (sampled 2026-08-23; the DOM's orange edge stubs never paint at
     rest) */
  .hm-her__cta .btn-dark { flex: none; width: calc(100% - 1px); margin-left: 1px; height: 57px; }
  /* The whole Advantages strip is rules-only at phone: "1st item"
     (.framer-1njrm1u), "Advantage 3" (.framer-1txwl8h) and Advantage 2's own
     content container (.framer-xlsvdy) are ALL hidden-ovi0ti, so the band
     renders empty. The clone was printing the two stat lines there, in the
     slot the reference gives to the halftone strip. */
}

/* --- areas ---
   LOGO BAND. "Title and logos" (.framer-1hill7q, flex:2 0 0) is the right 2/3
   at >=1440 and splits into a `flex:1` subheader ("trusted by:") and a
   `flex:3` marquee ("Logos" .framer-saor2u). At phone BOTH become `flex:1 0 0`
   and the subheader is dropped from the DOM entirely — the clone was printing
   "TRUSTED BY:" there with an empty strip beside it, so the phone capture had
   the label and none of the logos.

   The strip itself is .framer-ocwbgi-container: 48px tall, sitting under the
   "Logos line"'s `padding: 20px 0 0`, scrolling five 100x25-ish marks with a
   60px gap. Those five are inline <svg> symbols in the reference; they are
   extracted verbatim to /assets/images/logo-{1..5}.svg. */
/* band-1 columns: [Subheader 1/3][Title 1/4 of the rest][Logos 3/4 of the
   rest] at >=1440 -> badge at 32, "trusted by:" at 492, marquee from 721.
   Below 1440 "Title" drops out, so the marquee starts at the 1/3 rail; at
   phone the Subheader goes too and the marquee is full-bleed. */
.hm-areas__logos { align-items: flex-start; gap: 0; }
/* ratios: 2 : 1 : 3 at >=1440 gives 1/3 : 1/6 : 1/2 exactly; with "Title"
   hidden below 1440 the remaining 2 : 3 would be wrong, so the subheader is
   re-weighted to 1 : 2 there. */
.hm-areas__sub    { flex: 2 0 0; min-width: 0; position: relative; align-self: stretch; }
.hm-areas__logohead { flex: 1 0 0; min-width: 0; position: relative; align-self: stretch; }
.hm-areas__logoline { flex: 3 0 0; }
@media (max-width: 1439.98px) { .hm-areas__sub { flex: 1 0 0; } .hm-areas__logoline { flex: 2 0 0; } }
.hm-areas__sub > .hm-vline,
.hm-areas__logohead > .hm-vline { position: absolute; left: 0; top: 0; bottom: 0; }
/* "Subheader container" .framer-1bn6r1e is `position:absolute; bottom:24px;
   left:0` — the badge sits at the FOOT of the logo band, not its top. */
.hm-areas__sub > .hm-badge { position: absolute; left: 0; bottom: 24px; }
/* "trusted by:" container .framer-egxjgk: `max-width:180px; padding:34px 0 0` */
.hm-areas__logohead .t-mono { text-transform: uppercase; max-width: 180px; padding-top: 34px; }
.hm-areas__logoline {
  flex: 3 0 0; min-width: 0;
  margin-top: 20px; height: 48px;
  position: relative; overflow: hidden;
}
.hm-areas__logorow { align-items: center; }
.hm-logoset { display: flex; align-items: center; gap: 60px; padding-right: 60px; height: 100%; }
.hm-logoset .hm-logo { display: block; flex: none; }
.hm-logo--1 { width: 101px; height: 25px; }
.hm-logo--2 { width: 101px; height: 23px; }
.hm-logo--3 { width: 102px; height: 22px; }
.hm-logo--4 { width: 99px;  height: 29px; }
.hm-logo--5 { width: 100px; height: 23px; }
@media (max-width: 809.98px) {
  .hm-areas__logoline { flex: 1 0 0; }
}
/* Header (1/3) beside Items (2/3), both full height */
.hm-areas__main { align-items: stretch; gap: 0; }
.hm-areas__headc { flex: 1 0 0; min-width: 0; position: relative; }
/* "Text container" .framer-hkvn6x: `position:absolute; top:-7px; left:-1px;
   max-width:370px` (250 at 810-1439.98, 280 at phone). That 370px cap is what
   breaks the h2 to "What we / can automate"; the clone let it run the full
   458px column and set it on one centred line. */
.hm-areas__head {
  position: absolute; top: -7px; left: 0;
  width: 100%; max-width: 370px;
}
@media (min-width: 810px) and (max-width: 1439.98px) { .hm-areas__head { max-width: 250px; } }
@media (max-width: 809.98px) { .hm-areas__head { max-width: 280px; } }
.hm-areas__items {
  flex: 2 0 0; min-width: 0; align-self: stretch;
  display: flex; flex-direction: column;
}
/* each row is one flex line of cells; the two rows split the band evenly */
.hm-areas__row { flex: 1 0 0; min-height: 0; display: flex; align-items: stretch; }
/* "Hor line" .framer-1trffoh: 3px DASHED #d2cecaa6 (2px at phone), not a
   1px solid hairline */
.hm-areas__hline {
  flex: none; height: 0; width: 100%;
  border-top: 3px dashed var(--c-stone-65);
}
/* "Area N header" .framer-1mem6ti / "Area N text" .framer-ukg2sh:
   `flex:1 0 0; align-items:flex-end` — the cell's content is BOTTOM-aligned,
   with the icon pinned to the top by the inner column's
   `padding:32px 0 0; justify-content:space-between`. */
.hm-card {
  flex: 1 0 0; min-width: 0; position: relative;
  display: flex; align-items: flex-end;
  background: none; padding: 0;
}
.hm-card > .hm-vline { position: absolute; left: 0; top: 0; bottom: 0; }
.hm-card__body {
  flex: 1 0 0; min-width: 0; align-self: stretch;
  display: flex; flex-direction: column; justify-content: space-between;
  align-items: flex-start;
  padding: 32px 0 0;
}
.hm-card__icon { display: block; width: 51px; height: 51px; flex: none; }
.hm-card__icon img { display: block; width: 100%; height: 100%; }
.hm-card__body .t-mono { max-width: 170px; padding-bottom: 26px; text-transform: uppercase; }
.hm-card--text { align-items: flex-end; }
.hm-card--text .t-body-sm { max-width: 180px; padding: 0 0 26px; }

/* --- areas band 3: message | +more | button --- */
.hm-areas__msg { align-items: stretch; gap: 0; }
/* "Message container" .framer-1ww4v96 is `align-items:flex-start` inside its
   full-height row, so the avatar sits flush with the band's top edge
   (measured: avatar top = band top + 1), not centred. */
.hm-areas__quote { flex: 1 0 0; min-width: 0; position: relative; display: flex; align-items: flex-start; }
.hm-areas__right { flex: 2 0 0; min-width: 0; display: flex; align-items: stretch; }
.hm-areas__more,
.hm-areas__btncell { flex: 1 0 0; min-width: 0; position: relative; display: flex; }
.hm-areas__quote > .hm-vline,
.hm-areas__more > .hm-vline,
.hm-areas__btncell > .hm-vline { position: absolute; left: 0; top: 0; bottom: 0; }
.hm-areas__quotebody { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.hm-areas__who { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.hm-areas__ava { display: block; width: 32px; height: 32px; overflow: hidden; }
.hm-areas__ava img, .hm-areas__ava picture { display: block; width: 100%; height: 100%; }
/* [CONFIRM] founder-photo stand-in: neutral Autnex-mark tile (same pattern as
   /consulting's --mark modifiers). */
.hm-areas__ava--mark {
  display: flex; align-items: center; justify-content: center;
  background-color: var(--c-stone-light);
}
.hm-areas__ava--mark img { width: 18px; height: 18px; object-fit: contain; }
.hm-areas__quotetxt { max-width: 230px; text-transform: uppercase; }
/* "+More" .framer-cvhwo5: `max-width:180px; height:50%; align-items:flex-end;
   padding:0 0 20px` */
/* "+More" .framer-cvhwo5 is `height:50%` bottom-aligned, so the label lands
   mid-band (~y 1657 at desktop) rather than on the band's floor. */
.hm-areas__more { align-items: flex-end; align-self: flex-start; height: 50%; }
.hm-areas__more .t-mono { max-width: 180px; padding-bottom: 20px; text-transform: uppercase; }
.hm-areas__plus { color: var(--c-orange); }
.hm-areas__btncell { align-items: flex-start; padding-top: 64px; }
/* btn-dark is `flex:1 0 0`, so left alone it eats the whole band — the
   reference's button is one third of the content container wide, right-aligned
   (measured x 943..1371 of 32..1408 at 1440). */
/* The button now lives in its own grid cell (.hm-areas__btncell, the last
   third of the container), so it fills that cell. The old `width: 33.3333%`
   was measured against the WHOLE content container in the pre-grid layout and
   collapsed the button to 152px once the cell wrapper was introduced. */
@media (min-width: 810px) {
  .hm-areas__msg .hm-areas__btn { flex: none; width: 100%; }
}
@media (max-width: 809.98px) {
  /* phone: Header and Items both go `flex:none; width:100%` and stack, the
     rows become `max-height:200px`, and the body-copy halves are already gone
     (hidden-ovi0ti), leaving the 2x2 icon+label grid the reference shows. */
  .hm-areas__main { flex-direction: column; align-items: stretch; }
  /* measured on reference/phone/home.jpeg: inside the 502px band the heading
     occupies the first 100px and the two rows are 201px each (100 + 201 + 201
     = 502 exactly). Letting the rows size to their content instead collapsed
     the pitch to 146px and pulled the whole second row ~55px up. */
  .hm-areas__headc { flex: none; height: 100px; }
  .hm-areas__items { flex: none; }
  .hm-areas__row { flex: none; height: 201px; }
  /* re-measured live 2026-08-23: icon 32px under the row top, label foot
     26px above the row bottom (was 24/33 off the old capture) */
  .hm-card__body { padding: 32px 0 0; }
  .hm-card__body .t-mono { padding-bottom: 26px; }
  .hm-areas__btncell { padding-top: 41px; }
  /* live phone renders the items rules 1px high with a 6px-dash / 4px-gap
     pitch (#D2CECA @65%), and adds a rule ABOVE the first card row too */
  .hm-areas__items { position: relative; }
  .hm-areas__items::before,
  .hm-areas__hline {
    height: 1px; border-top: 0;
    background: repeating-linear-gradient(
      to right, rgba(210, 206, 202, .65) 0 6px, transparent 6px 10px);
  }
  .hm-areas__items::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0;
  }
  /* live phone: the stacked cards all hang the orange rail at x26, and the
     heading cell above them carries the same rail (its plain vline collapses
     to 0 height otherwise) */
  .hm-areas__row--caps .hm-card--cap + .hm-card--cap > .hm-vline,
  .hm-areas__headc > .hm-vline {
    background: repeating-linear-gradient(
      to bottom, var(--c-peach-95) 0 6px, transparent 6px 10px);
  }
  .hm-areas__headc > .hm-vline { position: absolute; left: 0; top: 0; bottom: 0; }
  /* phone shows only the full-width CTA in this band; btn-dark's row sizing
     (`flex:1 0 0; width:1px`) collapses it to a hairline in a column. */
  .hm-areas__msg { flex-direction: column; align-items: stretch; justify-content: flex-end; padding-bottom: 30px; }
  .hm-areas__btn { flex: none; width: calc(100% - 1px); margin-left: 1px; height: 57px; }  /* x27, rail clear (live) */
}

/* --- process --- */
.hm-process__headc { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: flex-end; gap: 18px; padding: 0 0 42px; }
.hm-process__steps {
  list-style: none; margin: 0; padding: 0; width: 100%;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--c-hairline); border: 1px solid var(--c-hairline);
}
.hm-step { background: var(--c-cream); padding: 20px; display: flex; flex-direction: column; gap: 10px; }
.hm-step__num { color: var(--c-orange); }
.hm-process__info { justify-content: space-between; }
@media (min-width: 810px) and (max-width: 1439.98px) { .hm-process__steps { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 809.98px) {
  .hm-process__steps { grid-template-columns: 1fr; }
  .hm-step { padding: 0; background: none; display: flex; flex-direction: row; align-items: center; gap: 12px; height: 120px; }
  .hm-step__body { display: none; }     /* reference collapses to a title row at phone */
  .hm-process__steps { border: 0; gap: 0; background: none; }
  .hm-step + .hm-step { border-top: 1px solid var(--c-hairline); }
}

/* --- results --- */
.hm-results__main { flex-direction: column; align-items: stretch; justify-content: center; gap: 20px; }
.hm-results__grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
  background: var(--c-hairline); border: 1px solid var(--c-hairline);
}
.hm-stat { background: var(--c-stone-light); padding: 20px; display: flex; flex-direction: column; gap: 8px; }
.hm-stat .t-body-sm { color: var(--c-body); }
/* phone measured live 2026-08-23 @390: NO body copy — a 140px heading zone
   (h2 max 250px, bottom-aligned 26px off its foot), then three value|label
   rows under 1px dashed rules (#C5C2BD, 6/4 pitch; above rows 1-3, none after
   the last): value 48px/48 Inter 500 ls -.05em in the left 169px column,
   label 15px mono at x195 (left-aligned, max 120px wide), both bottom-aligned
   with 26px padding. Rows 92+92+121 = 305; 140+305 = 445 = the band.
   (AUTNEX: the figs are the plan §3.5 metric-free 01/02/03 — the body
   sentences only render at >=810, exactly as live hides its own.) */
@media (max-width: 809.98px) {
  .hm-results__main { justify-content: flex-start; gap: 0; }
  .hm-results__head {
    flex: none; height: 140px; max-width: 250px;
    justify-content: flex-end;      /* .rtc is a column flex box */
    padding-bottom: 26px; box-sizing: border-box;
  }
  .hm-results__grid { display: block; background: none; border: 0; }
  .hm-stat {
    background: none; padding: 1px 0 0; gap: 0;
    display: flex; flex-direction: row; align-items: stretch;
    height: 92px; box-sizing: border-box;
    position: relative;
  }
  .hm-stat:last-child { height: 121px; padding-bottom: 29px; }
  .hm-stat::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
    background: repeating-linear-gradient(
      to right, rgb(197, 194, 189) 0 6px, transparent 6px 10px);
  }
  .hm-stat__fig {
    flex: none; width: 169px; margin: 0;
    display: flex; align-items: flex-end;
    padding: 0 0 26px 1px;   /* live digits start x27, clear of the rail */
    box-sizing: border-box;
    line-height: 48px;
  }
  .hm-stat h3 {
    flex: 1 1 auto; min-width: 0; max-width: 120px;
    align-self: flex-end; padding-bottom: 26px; margin: 0;
  }
  .hm-stat .t-body-sm { display: none; }
}

/* --- projects --- */
/* Full-bleed film-grain wash. The clone had none at all; the reference carries
   the same layer it puts over the pricing band — measured live 2026-08-18 at
   1440x900: a 5760x3600 box (400% of the section) at inset -200%, background
   rR6HYXBrMmX4cRpXfXUOvpvpB0.png repeated, opacity .05, z-index 7 (over the
   copy), walking the shared 90-step / 8000ms grain path IN PHASE with the
   pricing one — both are plain page-load-anchored CSS loops, so they stay in
   sync here too. Keyframes + measurement notes in sections/footer.css.
   `.hm-sec` is overflow:clip and this is absolute, so height is untouched. */
.hm-projects::before {
  content: ""; position: absolute; inset: -200%; width: 400%; height: 400%;
  z-index: 7; pointer-events: none;
  background-image: url("/assets/images/rR6HYXBrMmX4cRpXfXUOvpvpB0.png");
  opacity: .05;
  will-change: transform;
  animation: grain-drift 8s step-end infinite;
}
.hm-projects__headc { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: flex-end; gap: 18px; padding: 0 0 42px; }
.hm-projects__headc .t-h2 { color: var(--c-white); }
.hm-projects__grid {
  list-style: none; margin: 0; padding: 0; width: 100%; height: 100%;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
  background: var(--c-hairline-dark); border: 1px solid var(--c-hairline-dark);
}
.hm-proj { background: var(--c-graphite); display: flex; }
.hm-proj__link {
  display: flex; flex-direction: column; justify-content: space-between;
  gap: 16px; padding: 20px; width: 100%;
  transition: background-color 250ms linear;
}
.hm-proj__link:hover, .hm-proj__link:focus-visible { background: var(--c-graphite); }
.hm-proj__info { display: flex; flex-direction: column; gap: 10px; }
.hm-proj .t-mono { color: var(--c-white); }
.hm-proj .t-body-sm { color: var(--c-stone-75); }
.hm-proj__foot { display: flex; gap: 20px; }
.hm-proj__more { color: var(--c-orange); }
@media (max-width: 809.98px) {
  .hm-projects__grid { grid-template-columns: 1fr; }   /* single card, siblings hidden */
  .hm-proj__link { padding: 0; gap: 0; justify-content: space-between; }
  .hm-proj__info { flex: 1 0 auto; justify-content: center; }
  .hm-proj__foot { height: 157px; align-items: center; }
}

/* --- environments --- */
.hm-envs__main { flex-direction: column; align-items: stretch; justify-content: center; gap: 20px; }
.hm-envs__grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--c-hairline); border: 1px solid var(--c-hairline);
}
.hm-env { background: var(--c-cream); padding: 20px; display: flex; flex-direction: column; gap: 12px; }
.hm-env__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.hm-envs__gap { justify-content: space-between; }
@media (min-width: 810px) and (max-width: 1439.98px) { .hm-envs__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 809.98px) {
  .hm-envs__grid { grid-template-columns: 1fr; }
  .hm-env { padding: 14px; }
  .hm-envs__gap { flex-direction: column; align-items: flex-start; justify-content: center; }
}

/* --- allstack --- */
.hm-stack__headc { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: flex-end; gap: 18px; padding: 0 0 42px; }
.hm-stack__strip { align-items: center; overflow: hidden; height: 100%; }

/* --- allstack: the radial "Scheme" -------------------------------------
   .framer-gqyepk-container is `position:absolute; top:49%; left:50%;
   translate(-50%,-50%); width:1376px` (100% at <=1439), and the component
   inside (.framer-135o74h) is a fixed 1376px at every tier >=810, dropping to
   338px for the phone variant (.framer-v-yk127e). Its only in-flow child is
   .framer-1kd1qlp (`width:100%; min-height:392px`), so the whole thing is a
   1376x392 stage that the band simply clips at narrower tiers.

   Everything below is that component's own geometry. Tile centres on the
   1376x392 stage: top (688,35) upper-left (494,104) upper-right (882,104)
   left (385,212) right (993,212) lower-left (494,315) lower-right (884,315)
   bottom (688,382).
   ---------------------------------------------------------------------- */
/* The stage is always exactly the CONTENT box: Framer bakes it as
   `width:1376px` at 1440 and `width:100%` below, and 1376 == 1440 - 2*32, so
   the one rule that reproduces every tier is "span the padding inset".
   That is what makes the tiers diverge the way the reference does — the
   px-placed parts (square/angles at left:641/653, the side and corner tiles at
   left:958/849/847 and right:956/847) are measured from the stage's LEFT edge,
   while the logo, the spokes and the top/bottom tiles are placed in percent
   and so track its CENTRE. At 1440/1280 the stage is wide enough to hold all
   eight tiles; at 810 the same offsets throw six of them past the viewport and
   the band clips them, leaving only n8n/logo/slack plus the dot fields — which
   is exactly what reference/tablet/home.jpeg shows. Centring a fixed 1376px
   stage instead put all eight on screen at every tier. */
.hm-stack__scheme {
  position: absolute; top: 49%;
  left: var(--page-pad-desktop); right: var(--page-pad-desktop);
  transform: translateY(-50%);
  height: 392px;
}
@media (max-width: 809.98px) {
  .hm-stack__scheme { left: var(--page-pad-phone); right: var(--page-pad-phone); }
}
.hm-stack__core { position: absolute; inset: 0; z-index: 1; }
.hm-stack__dots, .hm-stack__sq, .hm-stack__ang { position: absolute; }
.hm-stack__dots--orange { top: 67px; left: 560px; width: 258px; height: 284px; }
.hm-stack__dots--dark   { top: 22px; left: 486px; width: 400px; height: 355px; }
.hm-stack__dots--grey   { top: 10px; left: 526px; width: 325px; height: 357px; }
.hm-stack__sq  { top: 165px; left: 641px; width: 95px; height: 95px; }
.hm-stack__ang { top: 177px; left: 653px; width: 71px; height: 71px; }
/* .framer-1zaf6 is `top:54%; left:50%` + an inline translate(-50%,-50%) */
.hm-stack__logo {
  position: absolute; top: 54%; left: 50%;
  transform: translate(-50%, -50%);
  width: 38px; height: 38px; display: block;
}
.hm-stack__logo img { display: block; width: 38px; height: 38px; }

/* the seven dashed spokes (z-index:0, 1px dashed #9e9e9e). The ".6" pair are
   the visible axes; the ".2" ones are the faint rotated duplicates. */
.hm-stack__spoke {
  position: absolute; z-index: 0; height: 0;
  border-top: 1px dashed rgb(158, 158, 158);
}
.hm-stack__spoke--h   { top: calc(53.5714% - .5px); left: 31.5%; width: 37%; opacity: .6; }
.hm-stack__spoke--ht  { top: calc(53.5714% - .5px); left: 38%;   width: 24%; opacity: .2; transform: rotate(-15deg); }
.hm-stack__spoke--d1  { top: calc(53.5714% - .5px); left: 36.5%; width: 27%; opacity: .6; transform: rotate(-30deg); }
.hm-stack__spoke--d1t { top: calc(53.5714% - .5px); left: 44%;   width: 12%; opacity: .2; transform: rotate(-60deg); }
.hm-stack__spoke--d2  { top: calc(53.5714% - .5px); left: 36.5%; width: 27%; opacity: .6; transform: rotate(30deg); }
/* the two vertical spokes are 1px-wide columns, so they take a left border */
.hm-stack__spoke--v, .hm-stack__spoke--vt {
  height: auto; width: 0; border-top: 0;
  border-left: 1px dashed rgb(158, 158, 158);
  left: calc(50% - .5px);
}
.hm-stack__spoke--v  { top: 15.5714%; height: 76%; opacity: .6; }
.hm-stack__spoke--vt { top: 20.0714%; height: 67%; opacity: .2; transform: rotate(-30deg); }

/* .framer-9rigdc: a 70x70 pill clipping a 54x24 contained image
   (.framer-tse2bu) that the reference desaturates. */
.hm-stack__tile {
  position: absolute; z-index: 3;
  width: 70px; height: 70px;
  border-radius: 240px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.hm-stack__tile img {
  width: 54px; height: 24px; object-fit: contain; object-position: center;
  filter: brightness(0.83) grayscale(1);
}
.hm-stack__tile--top   { left: 50%; transform: translateX(-50%); bottom: 322px; }
.hm-stack__tile--bot   { left: 50%; transform: translateX(-50%); top: 347px; }
.hm-stack__tile--ul    { right: 847px; bottom: 253px; }
.hm-stack__tile--ur    { left: 847px;  bottom: 253px; }
.hm-stack__tile--left  { right: 956px; top: 54%; transform: translateY(-50%); }
.hm-stack__tile--right { left: 958px;  top: 54%; transform: translateY(-50%); }
.hm-stack__tile--ll    { right: 847px; top: 280px; }
.hm-stack__tile--lr    { left: 849px;  top: 280px; }

/* phone runs the .framer-v-yk127e variant: a 338px stage with its own
   offsets, and .framer-1kd1qlp widened to 107%. */
@media (max-width: 809.98px) {
  /* .framer-1kd1qlp goes `width:107%` inside a `place-content:center` column,
     i.e. it overhangs the 338px stage by 3.5% on EACH side. Anchoring it at
     left:0 instead pushed the whole scheme ~12px right of the reference. */
  .hm-stack__core { left: -3.5%; width: 107%; right: auto; }
  .hm-stack__dots--orange { left: 52px; }
  .hm-stack__dots--dark   { left: -22px; }
  .hm-stack__dots--grey   { left: 18px; }
  .hm-stack__sq  { top: 170px; left: 141px; width: 81px; height: 81px; }
  .hm-stack__ang { top: 180px; left: 151px; width: 61px; height: 61px; }
  .hm-stack__spoke--h, .hm-stack__spoke--ht { width: 60%; left: 20%; }
  .hm-stack__spoke--d1, .hm-stack__spoke--d1t, .hm-stack__spoke--d2 { width: 57%; left: 21.5%; }
  .hm-stack__spoke--v, .hm-stack__spoke--vt { top: 33.5714%; height: 40%; }
  .hm-stack__tile--right { left: 274px; }
  .hm-stack__tile--left  { right: 277px; }
  .hm-stack__tile--lr    { top: 232px; left: 237px; }
  .hm-stack__tile--ll    { top: 232px; right: 242px; }
  .hm-stack__tile--ur    { bottom: 210px; left: 236px; }
  .hm-stack__tile--ul    { bottom: 212px; right: 241px; }
  .hm-stack__tile--bot   { top: 277px; }
  .hm-stack__tile--top   { bottom: 252px; }
}
/* The reference caption is the mono uppercase preset in a 300px box with
   balanced wrap, sitting at the 1/3 rail (Alignment container max-width:300,
   RichTextContainer --framer-text-wrap-override:balance). */
.hm-stack__msg p { max-width: 300px; text-wrap: balance; }

/* --- value --- */
/* Scrolling halftone dither strip behind the whole "Why choose us" section.
   The clone had flat cream here. MEASURED live 2026-08-18 (Playwright), per
   breakpoint, as an offset from the section box — the reference parents it to
   its 2nd content line, but pinning it to the section reproduces the same
   rect and keeps it out of the band flow:

     >=1440   left -1012  right -1013  top -35  height 622   5 tiles 1544x622
     810-1439 left -1012  right -1013  top   5  height 647   5 tiles 1606x647
     <810     left -1012  right -1013  top -54  height 597   4 tiles 1484x597

   (left/right are the same -1012/-1013 at every width; only top+height move.)
   Five tiles are emitted at every breakpoint — that over-covers the narrow
   ones, which costs nothing since it is one cached asset, and guarantees the
   loop never runs out of strip. Motion is the shared `.marquee` from
   sections/footer.css at the standard ~30px/s (live measured 29.7px/s), so it
   also inherits the reduced-motion opt-out and js/main.js `sizeMarquee`.
   Absolutely positioned inside the overflow:clip `.hm-sec` => height-neutral.
   (Dormant on the Autnex home — the value section moved off this page — kept
   alongside the other hm-value rules so the section can be lifted verbatim.) */
.hm-value__texture {
  position: absolute;
  left: -1012px; right: -1013px;
  top: -35px; height: 622px;
  pointer-events: none;
}
.hm-value__texture-clip { position: relative; width: 100%; height: 100%; overflow: hidden; }
.hm-value__texture-strip img { height: 100%; width: auto; display: block; }
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-value__texture { top: 5px; height: 647px; }
}
@media (max-width: 809.98px) {
  .hm-value__texture { top: -54px; height: 597px; }
}

.hm-value__gradient {
  position: absolute; inset: 0 0 auto 0; height: 400px;
  background: linear-gradient(180deg, var(--c-stone-40) 0%, transparent 100%);
  pointer-events: none;
}
.hm-value__main { flex-direction: column; align-items: stretch; justify-content: center; gap: 20px; }
.hm-value__grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px;
  background: var(--c-hairline); border: 1px solid var(--c-hairline);
}
.hm-vitem { background: var(--c-cream); padding: 20px; display: flex; flex-direction: column; gap: 10px; }
.hm-vitem__num { color: var(--c-orange); }
.hm-value__msg { justify-content: space-between; }
@media (max-width: 809.98px) {
  .hm-value__grid { grid-template-columns: 1fr; }
  .hm-vitem { padding: 14px; }
}

/* ---------------------------------------------------------------
   4b. The two canvas-halftone photo compositions (projects carousel,
   testimonials portrait wall).

   In the reference these are <canvas> elements that Framer paints
   client-side with a dot-screen/dither effect; the source <img> next to each
   canvas is opacity:0 and only feeds it. Those source images ARE vendored
   locally (research/assets-map.json), so the images themselves are the real
   ones — what is approximated is the dither, reproduced here as a hard
   grayscale/contrast crush that reads the same two-tone way at page scale.
   The first build omitted these regions entirely, leaving flat background
   where the reference has a ~450px-tall photograph; that was the largest
   remaining band error after the section backgrounds were fixed.

   Every rect below is measured, not guessed: the site lays both compositions
   out on its global column grid (6 x 229px @1440, 3 x 405 @1280, 3 x 248
   @810, 1-2 col @390) in 225/250/225/179px rows, and each image is a
   `object-fit: cover` cell on it. Cross-checked two ways — the canvas rects
   read off research/raw/<bp>/home.html, and the visible plate edges detected
   in reference/<bp>/home.jpeg. Both agree.

   All of this is position:absolute inside the section root, so it cannot
   move any measured height.
   --------------------------------------------------------------- */
.hm-projects__stage,
.hm-testi__stage { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.hm-projects__stage a,
.hm-projects__stage img { pointer-events: auto; }

/* The dither is two-tone, not a continuous grey: measured off
   reference/desktop/home.jpeg the projects plate is ~#d3d3d3 ground with
   ~#070707 marks, and the testimonials plates ~#f3f3f3 with ~#494949. So the
   image is thresholded to black/white with a hard contrast, then multiplied
   onto a cell painted the light tone — `opacity` sets how dark the dark tone
   lands. `brightness` is the threshold control and starts from the
   reference's own pre-canvas filter value (brightness 203% / contrast 221%). */
/* The dither is a real dot screen — a regular, phase-locked grid of dots whose
   radius tracks luminance. The previous approximation (grayscale + a
   brightness/contrast(24) crush, multiplied onto a flat plate) is a THRESHOLD,
   not a screen: it collapses every midtone into solid black or solid white, so
   the plates read as posterised blobs where the reference reads as texture.
   No CSS filter chain produces a dot screen, and Framer paints these on a
   <canvas> at runtime.

   So each plate is instead the reference's own pixels: the exact rect is cut
   out of reference/<bp>/home.jpeg and stored as PNG (never JPEG — chroma
   subsampling smears a 1px dot grid into mush) at
   /assets/images/ht-<slot>-<bp>.png, and picked per breakpoint by <picture>.
   The rects come straight from the measured geometry below and were verified
   against the reference: e.g. the desktop plate detects at y 3526..3977 x
   492..1408, exactly `left:492; top:226; 916x452` once the 45px fixed
   menu-line is discounted from the height oracle's offsets. */
.hm-projects__plate,
.hm-testi__portrait,
.hm-testi__face { background: none; }

.hm-projects__plate img,
.hm-testi__stage img,
.hm-projects__plate picture,
.hm-testi__stage picture {
  width: 100%; height: 100%; display: block;
}
.hm-projects__plate img,
.hm-testi__stage img { object-fit: cover; }

/* --- projects carousel --- */
.hm-projects__plate { position: absolute; display: block; overflow: hidden; }
.hm-projects__nav { position: absolute; display: flex; }
.hm-projects__arrow {
  width: 45px; height: 45px; position: relative;
  /* real <button> now (working carousel): strip UA chrome */
  border: 0; padding: 0; margin: 0; display: block; cursor: pointer;
  border-radius: 0; appearance: none; -webkit-appearance: none;
}
/* Two-tone variants, pixel-sampled from the live carousel (2026-08-20):
   prev is ALWAYS a white box (glyph black, or stone-grey when disabled);
   next is ALWAYS a dark box rgb(32,32,32) (glyph white, or grey when
   disabled). The BOX never fades — only the glyph changes; the glyph color
   rides on a custom property so the pseudo-element shaft+chevron follow. */
.hm-projects__arrow--prev { background: var(--c-white); --pj-arrow: var(--c-black); }
.hm-projects__arrow--next { background: rgb(32, 32, 32); --pj-arrow: var(--c-white); }
.hm-projects__arrow--prev.is-disabled { --pj-arrow: rgb(210, 206, 202); cursor: default; }
.hm-projects__arrow--next.is-disabled { --pj-arrow: rgb(120, 119, 118); cursor: default; }
/* shaft + chevron head. The previous single-bar-plus-two-box-shadows trick
   rendered as a bare dash: a box-shadow of a 12x1 bar is another 12x1 bar, so
   the two "head" copies just extended the shaft instead of angling off it. */
.hm-projects__arrow::before,
.hm-projects__arrow::after { content: ""; position: absolute; top: 50%; left: 50%; }
.hm-projects__arrow::before {
  width: 13px; height: 1px; background: var(--pj-arrow, var(--c-black));
  transform: translate(-50%, -50%);
}
.hm-projects__arrow::after {
  width: 6px; height: 6px;
  border-top: 1px solid var(--pj-arrow, var(--c-black));
  border-right: 1px solid var(--pj-arrow, var(--c-black));
  transform: translate(-50%, -50%) translateX(3.5px) rotate(45deg);
}
.hm-projects__arrow--prev::after {
  transform: translate(-50%, -50%) translateX(-3.5px) rotate(225deg);
}
.hm-projects__stat { position: absolute; color: var(--c-white); }
.hm-projects__cta {
  position: absolute; display: flex; align-items: center; justify-content: center;
  height: 57px; background: var(--c-orange); color: var(--c-white);
  transition: background-color 200ms linear;
}
.hm-projects__cta .t-mono { color: inherit; }
.hm-projects__cta:hover, .hm-projects__cta:focus-visible { background: var(--c-peach); }

/* Projects follows the same centered, capped 1520px grid as `.hm-cc`.
   Earlier rules baked the coordinates measured at 1440/1280/810 directly
   into the stage. That happened to match those exact capture widths, but at
   every intermediate width—and especially on displays wider than 1440—the
   carousel stayed pinned to the left. These variables express the live
   layout law instead: 32px minimum gutters, a 1520px cap, and three equal
   columns. */
@media (min-width: 810px) {
  .hm-projects {
    --pj-inset: max(var(--page-pad-desktop), calc((100vw - var(--page-max)) / 2));
    --pj-width: min(calc(100vw - var(--page-pad-desktop) * 2), var(--page-max));
    --pj-col: calc(var(--pj-width) / 3);
  }
}

/* The three case-text cards are carousel slides. In the reference NONE of
   them is ever visible on the home page — the carousel parks its text track
   off-canvas at every breakpoint (verified against reference/desktop and
   reference/tablet: the column left of the plate, and the strip under it, are
   both bare graphite). Leaving them in flow printed "INTERLOCK INDUSTRIES" +
   body copy in the empty left third at desktop and a row of stray
   "PROBLEM > RESULT >" links under the plate at tablet/phone. Parked the same
   way .hm-testi__grid is, so the copy stays in the DOM for assistive tech. */
.hm-projects__grid {
  position: absolute; left: -9999px; top: 0;
  width: 66%; z-index: 0;
}

/* --- testimonials portrait wall --- */
.hm-testi__portrait, .hm-testi__face {
  position: absolute; margin: 0; overflow: hidden;
}
.hm-testi__rating { position: absolute; display: flex; }
.hm-testi__score { flex: none; }
.hm-testi__of { font-size: .42em; }
.hm-testi__basis { text-transform: uppercase; }
.hm-testi__mark {
  position: absolute; width: 16px; height: 12px; background: var(--c-orange);
  clip-path: polygon(0 0,42% 0,42% 100%,28% 100%,28% 42%,0 42%,
                     58% 0,100% 0,100% 100%,86% 100%,86% 42%,58% 42%);
}
.hm-testi__grid { position: relative; z-index: 0; }
.hm-testi__stage ~ .hm-band .hm-quote:nth-child(n+2) { display: none; }

@media (min-width: 1440px) {
  .hm-projects__plate {
    left: calc(var(--pj-inset) + var(--pj-col) + 1px);
    top: calc(25% + 1px);
    width: calc(var(--pj-width) - var(--pj-col) - 1px);
    height: calc(50.25% - .67px);
  }
  .hm-projects__nav {
    left: calc(var(--pj-inset) + var(--pj-width) - 90px);
    top: calc(25% + 1px);
  }
  .hm-projects__stat {
    left: calc(var(--pj-inset) + var(--pj-width) / 2);
    top: calc(87.625% - 62.535px);
  }
  .hm-projects__cta {
    left: calc(var(--pj-inset) + var(--pj-width) - var(--pj-col) + 1px);
    top: auto;
    bottom: calc(12.375% + .335px);
    width: calc(var(--pj-col) - 2px);
  }

  .hm-testi__portrait { left: 492px; top: 226px; width: 229px; height: 225px; }
  .hm-testi__face     { top: 451px; width: 229px; height: 225px; }
  .hm-testi__face--1  { left: 492px; }
  .hm-testi__face--2  { left: 720px; }
  .hm-testi__face--3  { left: 949px; }
  .hm-testi__face--4  { left: 1179px; }
  .hm-testi__rating   { left: 492px; top: 690px; width: 916px; }
  .hm-testi__score    { width: 229px; }
  .hm-testi__mark     { left: 950px; top: 232px; }
}
@media (min-width: 1200px) and (max-width: 1439.98px) {
  .hm-projects__plate {
    left: calc(var(--pj-inset) + var(--pj-col) + 1px);
    top: 251px;
    width: calc(var(--pj-width) - var(--pj-col) - 1px);
    height: 500px;
  }
  .hm-projects__nav {
    left: calc(var(--pj-inset) + var(--pj-width) - 90px);
    top: 251px;
  }
  .hm-projects__stat { left: calc(var(--pj-inset) + var(--pj-col) + 1px); top: 762px; }
  .hm-projects__cta {
    left: calc(var(--pj-inset) + var(--pj-col) + 1px);
    top: 819px;
    width: calc(var(--pj-width) - var(--pj-col) - 2px);
  }

  .hm-testi__portrait { left: 438px; top: 251px; width: 405px; height: 250px; }
  .hm-testi__face     { top: 501px; width: 405px; height: 250px; }
  .hm-testi__face--1  { left: 438px; }
  .hm-testi__face--2  { left: 843px; }
  .hm-testi__face--3, .hm-testi__face--4 { display: none; }
  .hm-testi__rating   { left: 438px; top: 790px; width: 810px; }
  .hm-testi__score    { width: 405px; }
  .hm-testi__mark     { left: 858px; top: 257px; }
}
@media (min-width: 810px) and (max-width: 1199.98px) {
  .hm-projects__plate {
    left: calc(var(--pj-inset) + var(--pj-col) + 1px);
    top: 251px;
    width: calc(var(--pj-width) - var(--pj-col) - 1px);
    height: 500px;
  }
  .hm-projects__nav {
    left: calc(var(--pj-inset) + var(--pj-width) - 90px);
    top: 251px;
  }
  .hm-projects__stat { left: calc(var(--pj-inset) + var(--pj-col) + 1px); top: 762px; }
  .hm-projects__cta {
    left: calc(var(--pj-inset) + var(--pj-col) + 1px);
    top: 819px;
    width: calc(var(--pj-width) - var(--pj-col) - 2px);
  }

  .hm-testi__portrait { left: 282px; top: 251px; width: 248px; height: 250px; }
  .hm-testi__face     { top: 501px; width: 248px; height: 250px; }
  .hm-testi__face--1  { left: 282px; }
  .hm-testi__face--2  { left: 529px; }
  .hm-testi__face--3, .hm-testi__face--4 { display: none; }
  .hm-testi__rating   { left: 282px; top: 790px; width: 496px; }
  .hm-testi__score    { width: 248px; }
  .hm-testi__mark     { left: 544px; top: 257px; }
}
@media (max-width: 809.98px) {
  .hm-projects__plate {
    left: calc(var(--page-pad-phone) + 1px);
    right: calc(var(--page-pad-phone) + 1px);
    top: 374px;
    width: auto;
    height: 360px;
  }
  .hm-projects__nav {
    left: auto;
    right: var(--page-pad-phone);
    top: 133px;
  }   /* above the plate; live buttons sit at x274/319 @390 */
  .hm-projects__stat  { display: none; }             /* absent from the phone reference */
  .hm-projects__cta {
    left: calc(var(--page-pad-phone) + 1px);
    right: calc(var(--page-pad-phone) + 1px);
    top: 774px;
    width: auto;
  }
  /* each 45px arrow carries a 1px ORANGE divider on its left edge at phone
     (live: #ED4F00 slivers at x273 and x318, both carousels) */
  .hm-projects__arrow { box-shadow: -1px 0 0 var(--c-orange); }
  /* white 12px arrow glyph left of the CTA label (live: icon at x79, text
     block centred at x195) */
  .hm-projects__cta-ico {
    position: absolute; left: 52px; top: 50%; width: 13px; height: 13px;
    transform: translateY(-50%);
  }
  .hm-projects__cta-ico::before {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 12px; height: 1px; background: var(--c-white);
    transform: translate(-50%, -50%);
  }
  .hm-projects__cta-ico::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 6px; height: 6px;
    border-top: 1px solid var(--c-white); border-right: 1px solid var(--c-white);
    transform: translate(-50%, -50%) translateX(3px) rotate(45deg);
  }
  /* solid dark rule down the right page edge of the whole dark section
     (live 390: rgb(61,59,59) at x363, under the plate/CTA) */
  .hm-projects__stage::after {
    content: ""; position: absolute; right: 26px; top: 0; bottom: 0;
    width: 1px; background: rgb(61,59,59); z-index: -1;
  }

  .hm-testi__portrait { left: 26px; top: 240px; width: 338px; height: 271px; }
  .hm-testi__face     { width: 169px; height: 179px; }
  .hm-testi__face--1  { left: 26px;  top: 701px; }
  .hm-testi__face--2  { left: 195px; top: 701px; }
  .hm-testi__face--3  { left: 26px;  top: 880px; }
  .hm-testi__face--4  { left: 195px; top: 880px; }
  .hm-testi__rating   { left: 26px; top: 1075px; width: 338px; }
  .hm-testi__score    { width: 169px; }
  .hm-testi__mark     { display: none; }
}

/* ---------------------------------------------------------------
   Case-studies carousel — left card, foot cells, decorations.
   Ported from the clone; geometry measured on the live template
   (2026-08-20 probe, section-relative). Everything is
   position:absolute inside the inset:0 stage, so section heights
   cannot move. The live template shows the name + description at
   EVERY breakpoint, but the foot row (problem / what we did /
   result) exists ONLY at >=1440. The hairline above the description
   exists at >=810 and is absent at phone.

   AUTNEX ADAPTATION: no numeric "%" stat — the result cell holds the
   case's text caption ([NEEDS-METRIC] until real numbers exist), so
   the result label sits inside a normal cell instead of beside a
   counter, and its value gets the 170px caption measure the /work
   page already uses.
   --------------------------------------------------------------- */
.hm-projects__stage button { pointer-events: auto; }
.hm-projects__card { position: absolute; inset: 0; pointer-events: none; }
.hm-projects__name { position: absolute; margin: 0; }
.hm-projects__desc { position: absolute; margin: 0; color: var(--c-grey); }
.hm-projects__rule {
  position: absolute; height: 0;
  border-top: 1px dashed var(--c-hairline); opacity: .45;
}
.hm-projects__plus { position: absolute; width: 15px; height: 15px; }
.hm-projects__plus svg { display: block; width: 100%; height: 100%; }
.hm-projects__cell { position: absolute; }
.hm-projects__cell-label { display: block; color: var(--c-grey); }
.hm-projects__cell-label--result { color: var(--c-orange); }
.hm-projects__cell-value {
  display: block; margin-top: 10px; color: var(--c-white);
}

@media (min-width: 1440px) {
  .hm-projects__plus {
    left: calc(var(--pj-inset) - 7px);
    top: calc(25% - 7px);
  }
  .hm-projects__name {
    left: calc(var(--pj-inset) + 1px);
    top: calc(25% + 1px);
    width: 330px;
  }
  .hm-projects__rule {
    left: calc(var(--pj-inset) + 1px);
    top: calc(50.125% + .665px);
    width: calc(var(--pj-col) - 1px);
  }
  .hm-projects__desc {
    left: calc(var(--pj-inset) + 1px);
    top: calc(50.125% + 1.665px);
    width: 330px;
  }
  .hm-projects__cell--problem {
    left: calc(var(--pj-inset) + 1px);
    top: calc(87.625% - 69.535px);
  }
  .hm-projects__cell--did {
    left: calc(var(--pj-inset) + var(--pj-col) + 1px);
    top: calc(87.625% - 69.535px);
  }
  .hm-projects__cell--result {
    left: calc(var(--pj-inset) + var(--pj-width) / 2 + 1px);
    top: calc(87.625% - 70.535px);
  }
  .hm-projects__cell-value    { width: 140px; }
  .hm-projects__cell--result .hm-projects__cell-value { width: 170px; }
}
@media (min-width: 1200px) and (max-width: 1439.98px) {
  .hm-projects__plus  { left: calc(var(--pj-inset) - 7px); top: 243px; }
  .hm-projects__name  { left: calc(var(--pj-inset) + 1px); top: 251px; width: 330px; }
  .hm-projects__rule  { left: calc(var(--pj-inset) + 1px); top: 501px; width: calc(var(--pj-col) - 1px); }
  .hm-projects__desc  { left: calc(var(--pj-inset) + 1px); top: 502px; width: 180px; }
  /* foot row does not exist below 1440 on the live template */
  .hm-projects__cell { display: none; }
}
@media (min-width: 810px) and (max-width: 1199.98px) {
  .hm-projects__plus  { left: calc(var(--pj-inset) - 7px); top: 243px; }
  .hm-projects__name  { left: calc(var(--pj-inset) + 1px); top: 251px; width: calc(var(--pj-col) - 1px); }
  .hm-projects__rule  { left: calc(var(--pj-inset) + 1px); top: 501px; width: calc(var(--pj-col) - 1px); }
  .hm-projects__desc  { left: calc(var(--pj-inset) + 1px); top: 502px; width: 180px; }
  .hm-projects__cell { display: none; }
}
@media (max-width: 809.98px) {
  .hm-projects__plus  { display: none; }   /* not painted at 390 (pixel-scanned 2026-08-23) */
  .hm-projects__name  { left: calc(var(--page-pad-phone) + 1px); top: 133px; width: 240px; }
  /* AUTNEX ADAPTATION: autnex case names run to three lines; at 42px they
     would collide with the description (which starts at y243). 32px keeps
     three lines inside the 110px name slot, and the 240px measure keeps the
     name clear of the nav arrows at x274 (live's 336 fits its 1-line names). */
  .hm-projects__name  { font-size: 32px; }
  .hm-projects__rule  { display: none; }   /* absent from the live phone layout */
  .hm-projects__desc  {
    left: calc(var(--page-pad-phone) + 1px);
    top: 243px;
    width: 296px;                          /* live wraps at 296 */
  }
  .hm-projects__cell { display: none; }
}

/* the projects (Case studies) section's own 15x15 "+" (live DOM at 390:
   SVG box 19,2647.5, centred on the rail x the list's top rule; section
   top offset => +124.5). The symbol's strokes are hardcoded #E75800 — the
   white fill token on its wrapper never applies to the stroked lines. */
@media (max-width: 809.98px) {
  .hm-projects__cross {
    position: absolute; z-index: 1;
    left: calc(var(--page-pad-phone) - 7px);
    top: 124.5px;
    width: 15px; height: 15px;
  }
  .hm-projects__cross svg { display: block; width: 100%; height: 100%; }
}

/* --- testimonials --- */
.hm-testi__headc { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: flex-end; gap: 18px; padding: 0 0 42px; }
.hm-testi__grid {
  list-style: none; margin: 0; padding: 0; width: 100%; height: 100%;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px;
  background: var(--c-hairline); border: 1px solid var(--c-hairline);
}
.hm-quote { background: var(--c-stone-light); padding: 24px; display: flex; flex-direction: column; gap: 14px; }
.hm-quote__foot { margin-top: auto; display: flex; flex-direction: column; gap: 4px; }
.hm-quote__rate { display: none; }
@media (max-width: 809.98px) {
  /* The stage now supplies the rating, and the reference's phone carousel
     parks its text slide off-canvas (measured x=-743 in
     research/raw/phone/home.html) rather than stacking it under the photos.
     Mirroring that keeps the copy in the DOM and out of the picture. */
  .hm-testi__grid {
    grid-template-columns: 1fr; background: none; border: 0;
    position: absolute; left: -9999px; top: 0; width: 338px;
  }
  .hm-quote { padding: 0; background: none; justify-content: space-between; }
  .hm-quote__rate { display: none; }
}

/* ---------------------------------------------------------------
   5. PRICING — three variant wrappers, one visible per range
   --------------------------------------------------------------- */
/* Reference root is `background-color: rgb(32,32,32)` (inline on the fragment root)
   plus a full-bleed grain wash: url(rR6HYXBrMmX4cRpXfXUOvpvpB0.png) at opacity .05,
   inset -200%/400%, drifting. The earlier "reproduced statically" note is now
   obsolete: the drift is reproduced exactly — see the `grain-drift` keyframes and
   the measurement write-up in sections/footer.css. Measured live 2026-08-18 at
   1440x900: layer 5760x3600 (= 400% of the 1440x900 section) at z-index 7, i.e.
   ABOVE the copy, not behind it — the old `z-index: 0` put it in the wrong plane.
   `.hm-sec` is overflow:clip and the layer is absolute, so height is untouched. */
.hm-annual { background: var(--c-graphite); }
.hm-annual::before {
  content: ""; position: absolute; inset: -200%; width: 400%; height: 400%;
  z-index: 7; pointer-events: none;
  background-image: url("/assets/images/rR6HYXBrMmX4cRpXfXUOvpvpB0.png");
  opacity: .05;
  will-change: transform;
  animation: grain-drift 8s step-end infinite;
}
/* Covers BOTH grain layers on this page (.hm-projects::before is declared
   earlier in this file). Must live here, not in footer.css: this stylesheet
   loads later and would otherwise win the cascade over a reduced-motion rule
   declared there, leaving the loop running for users who asked for no motion. */
@media (prefers-reduced-motion: reduce) {
  .hm-projects::before,
  .hm-annual::before { animation: none; }
}
.hm-annual > * { position: relative; z-index: 1; }
.hm-annual--desktop { height: 100vh; }
.hm-annual--tablet  { height: min-content; max-height: 1000px; }
.hm-annual--phone   { height: min-content; }

.hm-annual--desktop, .hm-annual--tablet, .hm-annual--phone { display: none; }
@media (min-width: 1440px)                           { .hm-annual--desktop { display: flex; } }
@media (min-width: 810px) and (max-width: 1439.98px) { .hm-annual--tablet  { display: flex; } }
@media (max-width: 809.98px)                         { .hm-annual--phone   { display: flex; } }

/* All four pricing bands sit on the reference's 6-column grid: the content
   container is split into 6 equal columns (229px @1440) each carrying a 1px
   rule on its left edge, and each of the three tiers spans two of them —
   odd column = name/price, even column = feature list. Every offset below was
   read off research/raw/<bp>/home.html rendered at the capture viewport
   (scratchpad/leaves.mjs), not eyeballed. */
.hm-annual .hm-cc { align-items: stretch; gap: 0; }
.hm-annual .t-h2 { color: var(--c-white); }

.hm-annual__headc { flex: 1 0 auto; display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; }
.hm-annual__toggle { display: flex; align-items: stretch; flex: none; width: max-content; height: 45px; }
.hm-toggle {
  width: 115px; display: flex; align-items: center; justify-content: center;
  background: var(--c-graphite);
  transition: background-color 200ms linear, color 200ms linear;
}
.hm-toggle .t-mono { color: var(--c-grey); font-size: 12px; }
/* The ACTIVE period is the graphite chip that blends into the section; the
   INACTIVE one is the white chip you click to switch. Not the other way round
   — verified against reference/<bp>/home.jpeg, where "annual" (the live state)
   is dark and "monthly" is the white pill. */
.hm-toggle:not(.is-active) { background: var(--c-white); }
.hm-toggle:hover.is-active,
.hm-toggle:focus-visible.is-active { background: var(--c-graphite-lt); }
.hm-toggle__abbr { display: none; }

/* --- descriptions band (icon + mono caps, columns 1/3/5) --- */
.hm-annual__descs { display: flex; width: 100%; height: 100%; }
.hm-annual__desc {
  flex: 1 0 0; min-width: 0; display: flex; flex-direction: column;
  border-left: 1px solid var(--c-graphite-lt);
  padding-left: 1px;                /* the rule overlays the column edge */
}
.hm-annual__ico { width: 57px; height: 57px; flex: none; background: var(--c-graphite-lt); }
.hm-annual__desctxt {
  margin-top: 26px; max-width: 170px;
  color: var(--c-white); text-transform: uppercase;
}

/* --- tier band --- */
.hm-annual__tiers { display: flex; width: 100%; height: 100%; align-items: stretch; }
.hm-tier {
  flex: 1 0 0; min-width: 0; display: flex; align-items: stretch;
  border-bottom: 1px solid var(--c-graphite-lt);
}
.hm-tier__num,
.hm-tier__list {
  flex: 1 0 0; min-width: 0;
  border-left: 1px solid var(--c-graphite-lt);
  padding-left: 1px;
}
.hm-tier__num { display: flex; flex-direction: column; position: relative; padding-top: 93px; }
.hm-tier__name { color: var(--c-white); text-transform: uppercase; font-size: 12px; }
.hm-tier__pop {
  position: absolute; top: 93px; left: 59px;
  color: var(--c-orange); text-transform: uppercase; font-size: 12px;
}
.hm-tier__fig { margin-top: 16px; color: var(--c-white); }
.hm-tier__per { margin-top: 5px; color: var(--c-white); font-size: 16px; line-height: 22px; }
.hm-tier__list {
  list-style: none; margin: 0; padding: 90px 0 0 1px;
  display: flex; flex-direction: column;
}
.hm-tier__feat { display: flex; gap: 10px; height: 28.7px; }
.hm-tier__mk { color: var(--c-orange); flex: none; }
.hm-tier__feat .t-body-sm { color: var(--c-grey); }

/* --- bottom CTA band: three 57px buttons, 56px down from the band top --- */
.hm-annual__bottom { display: flex; width: 100%; height: 100%; align-items: flex-start; }
.hm-annual__btncell {
  flex: 1 0 0; min-width: 0; padding-top: 56px;
  border-left: 1px solid var(--c-graphite-lt);
}
.hm-pcta {
  display: flex; align-items: center; justify-content: center;
  height: 57px; margin-left: 1px;
  background: var(--c-white); color: var(--c-black);
  position: relative;
  overflow: var(--overflow-clip-fallback, clip);
}
.hm-pcta .t-mono { color: inherit; }
.hm-pcta--orange { background: var(--c-orange); color: var(--c-white); }

/* ---- hover (mouse only) -------------------------------------------------
   These three are the reference's «Whiteone/Orangeone - Start» .framer-fSAj6
   pills, which this page renders as a deliberately simplified single-span
   button (no `__edge` sliver, no <svg> child — see the section note above).
   Reconstruct the same sweep out of pseudo-elements so the simplification
   costs nothing at rest: ::before is the fill layer, and the label's own
   ::before is the arrow, painted from `--arrow-mask` in `currentColor`.
   Both are invisible at rest (scaleX(0) / opacity 0), so the resting pixels
   are exactly what they were.

   Measured live 2026-08-18 — the two variants INVERT, which the previous
   rule missed (it swept both to orange, so the already-orange one changed
   nothing on hover):
     «Whiteone»  face white  — fill ORANGE, label black -> white
     «Orangeone» face orange — fill WHITE,  label white -> black
   Geometry and spring are the shared CTA ones; see help.css and
   base.css § 5b.
   ------------------------------------------------------------------------ */
@media (hover: hover) and (pointer: fine) {
  .hm-pcta::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    background: var(--c-orange);
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: transform var(--hov-cta-dur-out) var(--hov-cta-ease-out);
  }
  .hm-pcta--orange::before { background: var(--c-white); }
  .hm-pcta:hover::before,
  .hm-pcta:focus-visible::before {
    transform: scaleX(1);
    transition-duration: var(--hov-cta-dur-in);
    transition-timing-function: var(--hov-cta-ease-in);
  }

  .hm-pcta .t-mono {
    position: relative;
    z-index: 1;
    transition: padding-left var(--hov-cta-dur-out) var(--hov-cta-ease-out);
  }
  .hm-pcta:hover .t-mono,
  .hm-pcta:focus-visible .t-mono {
    padding-left: 22px;
    transition-duration: var(--hov-cta-dur-in);
    transition-timing-function: var(--hov-cta-ease-in);
  }

  .hm-pcta .t-mono::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 0;
    width: 12px;
    height: 12px;
    background: currentColor;
    -webkit-mask: var(--arrow-mask) center / contain no-repeat;
            mask: var(--arrow-mask) center / contain no-repeat;
    opacity: 0;
    transform: translate(-26px, -50%);
    transition: transform var(--hov-cta-dur-out) var(--hov-cta-ease-out),
                opacity   var(--hov-cta-dur-out) linear;
  }
  .hm-pcta:hover .t-mono::before,
  .hm-pcta:focus-visible .t-mono::before {
    opacity: 1;
    transform: translate(0, -50%);
    transition-duration: var(--hov-cta-dur-in);
    transition-timing-function: var(--hov-cta-ease-in), linear;
  }

  .hm-pcta:hover, .hm-pcta:focus-visible                 { color: var(--c-white); }
  .hm-pcta--orange:hover, .hm-pcta--orange:focus-visible { color: var(--c-black); }
}


/* right-hand edge rule closing the 6-column grid */
.hm-annual__descs, .hm-annual__tiers, .hm-annual__bottom {
  border-right: 1px solid var(--c-graphite-lt);
}

/* period switching — main.js sets data-price-state on [data-price-group].
   The swap used to be an instant display:none. MEASURED live 2026-08-18
   (Playwright real mouse click on the "monthly" pill, computed style sampled
   every rAF): the price does NOT cross-fade. The outgoing panel slides out to
   the RIGHT by one panel width (416px at 1440) while the incoming one enters
   from the left, over ~423ms, with a ~1.5% overshoot at ~60% of the travel.
   The dark chip in the toggle slides one pill width (114.7px) over ~438ms.
   Reproduced in pure CSS off the existing attribute swap — no extra JS and no
   markup change. Easing: the measured curve is very front-loaded (62% of the
   travel is done in the first 17% of the time) and then settles, so an
   expo-style ease-out tracks it far better than the site's --ease-spring0;
   the 1.6px overshoot is below the perceptual floor and is not modelled.

   HEIGHT: the two prices share ONE grid cell, so both stay in flow and the
   line is still exactly one price high — identical to the display:none
   version. Nothing here is absolutely positioned and nothing changes size. */
.hm-tier__fig {
  display: grid;
  grid-template-columns: 100%;
  overflow-x: clip;               /* clip sideways only: descenders stay whole */
}
.hm-tier__fig > [data-price-period] {
  grid-area: 1 / 1;
  transition: transform 423ms cubic-bezier(0.16, 1, 0.3, 1);
}
[data-price-group][data-price-state="annual"]  .hm-tier__fig > [data-price-period="monthly"] { transform: translateX(-100%); }
[data-price-group][data-price-state="monthly"] .hm-tier__fig > [data-price-period="annual"]  { transform: translateX(100%); }
[data-price-group][data-price-state="annual"]  [data-price-period="monthly"],
[data-price-group][data-price-state="monthly"] [data-price-period="annual"] { pointer-events: none; }

/* The toggle's dark chip becomes a sliding indicator instead of a per-button
   background swap: the track carries the white, `::before` carries the
   graphite and translates by exactly one pill. Rest state is pixel-identical
   to the old two-background version (2 x 115px pills, indicator 50%). */
.hm-annual__toggle { position: relative; background: var(--c-white); }
.hm-annual__toggle::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 50%;
  background: var(--c-graphite);
  transition: transform 438ms cubic-bezier(0.16, 1, 0.3, 1), background-color 200ms linear;
}
[data-price-group][data-price-state="monthly"] .hm-annual__toggle::before { transform: translateX(100%); }
/* keep the reference's hover tint on the active (dark) chip — it now lives on
   the indicator, so it follows the chip as it slides */
.hm-annual__toggle:has(.hm-toggle.is-active:hover)::before,
.hm-annual__toggle:has(.hm-toggle.is-active:focus-visible)::before { background: var(--c-graphite-lt); }
.hm-toggle { background: none; position: relative; z-index: 1; }
.hm-toggle:not(.is-active) { background: none; }
.hm-toggle:hover.is-active,
.hm-toggle:focus-visible.is-active { background: none; }

@media (prefers-reduced-motion: reduce) {
  .hm-tier__fig > [data-price-period],
  .hm-annual__toggle::before { transition: none; }
}


/* TABLET/LAPTOP: three single-column tiers, no feature lists (the reference
   drops them below 1440 — Part info 3 has only "Title and numbers" cells). */
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-tier__list { display: none; }
  .hm-tier__num { padding-top: 100px; }
  .hm-annual__desctxt { margin-top: 20px; }
}

/* PHONE: heading + toggle, three stacked 131px tier rows, one orange CTA. */
@media (max-width: 809.98px) {
  .hm-toggle { width: 66px; }
  .hm-toggle__full { display: none; }
  .hm-toggle__abbr { display: inline; }
  /* the heading + period toggle are CENTRED in their 150px band, not pinned to
     its top — measured on reference/phone/home.jpeg, "Pricing" sits 53px into
     the band where the clone put it at 1px. */
  .hm-annual .hm-annual__headc { align-items: center; }
  .hm-annual__tiers { flex-direction: column; border-right: 0; }
  .hm-tier {
    flex: none; height: 131px; border-left: 0; border-bottom: 0;
    border-top: 1px dashed var(--c-graphite-lt);
  }
  .hm-tier__num { border-left: 0; padding: 12px 0 0; }
  /* "popular" sits INLINE to the right of the plan name at phone (measured
     x=78 against the name's x=27, both on the row's first line). The shared
     `top:93px; left:59px` desktop rect dropped it under "/month". */
  .hm-tier__pop { top: 12px; left: 52px; }
  .hm-tier__fig { margin-top: 6px; }
  .hm-tier__list { display: none; }
  .hm-annual__bottom { border-right: 0; }
  .hm-annual__btncell { border-left: 0; padding-top: 26px; }
  .hm-pcta { margin-left: 0; }
}

/* ---------------------------------------------------------------
   6. Remove Me (Remix Button) — vendor chrome, position:fixed,
   contributes 0 to every measured height.
   --------------------------------------------------------------- */
.hm-remix { position: fixed; right: 20px; bottom: 20px; z-index: 20; }
.hm-remix__btn {
  display: flex; align-items: stretch;
  border-right: 1px solid var(--c-stone-65);
  border-bottom: 1px solid var(--c-stone-65);
  background: var(--c-white);
}
.hm-remix__bar { width: 4px; flex: none; background: var(--c-orange); }
.hm-remix__body { display: flex; align-items: center; padding: 8px 14px; }
.hm-remix__text .t-mono-xs { color: var(--c-black); }
.hm-remix__btn:hover .hm-remix__text .t-mono-xs,
.hm-remix__btn:focus-visible .hm-remix__text .t-mono-xs { color: var(--c-orange); }

/* ================================================================
   BELOW-HERO WORD-REVEAL TIMING TIERS  (measured live 2026-08-19)
   ----------------------------------------------------------------
   The reference fades nearly every below-hero caption/body text
   word-by-word as it scrolls into view, but the per-word stagger is
   NOT one global value — it was measured per element class on the
   live reference @1440x900 (50-frame opacity sampling of each word
   span, fresh scroll-in per section):

     ~30ms   project-card paragraphs, testimonial quote bodies
     ~50ms   process step bodies
     ~80ms   FAQ question lines
     ~100ms  areas/results body copy, stack message, pricing tier descs
     ~130ms  "we offer …" captions, footer menu labels, credits
     ~160ms  card/step/stat/env titles, env list items, pricing
             features, quote-attribution captions, service links
     ~250ms  the two "+ much more" lines
     (per-word fade ~50-80ms — 0.1s here; unmeasured captions keep
      the 0.12s/0.15s word-mode default from text-reveal.css)

   Mechanics stay 100% in js/text-reveal.js + css/text-reveal.css —
   these classes only retune its two custom properties, so all of the
   armed/revealed/reduced-motion behaviour (and the "transition lives
   on .sr-in" rule) is inherited unchanged. Opacity-only: no height
   can move. The same tier classes exist in css/sections/help.css and
   css/sections/footer.css for the shared partials.
   ================================================================ */
[data-split-text].w03 { --sr-stagger: .03s; --sr-dur: .1s; }
[data-split-text].w05 { --sr-stagger: .05s; --sr-dur: .1s; }
[data-split-text].w08 { --sr-stagger: .08s; --sr-dur: .1s; }
[data-split-text].w10 { --sr-stagger: .10s; --sr-dur: .1s; }
[data-split-text].w13 { --sr-stagger: .13s; --sr-dur: .1s; }
[data-split-text].w16 { --sr-stagger: .16s; --sr-dur: .1s; }
[data-split-text].w25 { --sr-stagger: .25s; --sr-dur: .1s; }

/* ===============================================================
   7. AUTNEX ADAPTATION — page-scoped overrides for the content-plan
   rework (oberon_autnex-content-plan.md §3). Everything below is
   additive: the template rules above are untouched so the removed
   sections can be lifted verbatim onto /software and /consulting.
   =============================================================== */

/* --- areas -> "Two capabilities" (plan §3.3) ------------------------------
   Band 1 carries the "trusted by:" logo strip again (restored 2026-08-19 on
   Rúben's request — placeholder logos, see the [CONFIRM] note in index.html),
   so it keeps the template's 225/250/100 heights; band 2 carries two
   capability cards instead of a 2x2 icon grid.
   The template pinned the section to 100vh / 1000px because the 2x2 icon grid
   and the logo strip filled it. Two capability cards do not, and stretching
   them left a ~300px void above the founder bubble, so the section now sizes
   to its bands at every breakpoint. */
.hm-areas { height: min-content; max-height: unset; }
@media (min-width: 1440px) {
  /* b1 height comes from the base rule (225px, template value) */
  .hm-areas__b2 { height: 360px; }   /* 225 + 1 + 360 + 225 = 811 */
}
@media (min-width: 810px) and (max-width: 1439.98px) {
  /* b1 height comes from the base rule (250px, template value) */
  .hm-areas__b2 { height: 450px; }   /* 250 + 1 + 450 + 250 = 951 */
}
@media (max-width: 809.98px) {
  /* the two cards stack, so the band can no longer be a fixed 502px */
  .hm-areas__b2 { height: auto; min-height: 502px; }
}

/* section sub, sitting under the h2 in the left third */
.hm-areas__sublede { margin-top: 18px; color: var(--c-grey); }
@media (max-width: 809.98px) {
  .hm-areas__sublede { margin-top: 12px; }
  /* the template's -7px optical overhang clips the 32px phone h2 against the
     band's `overflow: clip` */
  .hm-areas__head { top: 0; }
  /* the template's 100px heading cell fits its bare h2; the autnex head adds
     the sublede, which was overflowing into the items' new top dashed rule */
  .hm-areas__headc { height: 140px; }
}

/* two equal capability cards; at <=809 they stack into one column */
.hm-areas__row--caps { align-items: stretch; }
.hm-card--cap { text-decoration: none; }
/* the template card is bottom-aligned (icon pinned top, label pinned bottom).
   The capability card is a top-aligned stack instead: label, one-sentence
   body, then the ">"-prefixed list. */
.hm-card--cap { align-items: flex-start; }
.hm-card--cap .hm-card__body {
  justify-content: flex-start; gap: 26px;
  padding: 40px 24px 0 0;
}
.hm-card__lede { display: flex; flex-direction: column; gap: 12px; max-width: 330px; }
.hm-card--cap .hm-card__body .t-mono { max-width: none; padding-bottom: 0; }
.hm-card--cap:hover .hm-card__body .t-mono,
.hm-card--cap:focus-visible .hm-card__body .t-mono { color: var(--c-orange); }
/* the ">"-prefixed list, lifted from the deleted environments section
   (.hm-env__list) so the pattern survives that section's removal */
.hm-card__list {
  list-style: none; margin: 0; padding: 0; max-width: 330px;
  display: flex; flex-direction: column; gap: 6px;
}
@media (min-width: 810px) and (max-width: 1199.98px) {
  .hm-card--cap .hm-card__body { padding: 32px 16px 0 0; gap: 20px; }
  .hm-card__lede, .hm-card__list { max-width: none; }
}
@media (max-width: 809.98px) {
  .hm-areas__row--caps { flex-direction: column; height: auto; flex: none; }
  .hm-card--cap { flex: none; }
  .hm-card--cap .hm-card__body { padding: 24px 0 28px; gap: 16px; }
  .hm-card__lede, .hm-card__list { max-width: none; }
  /* keep the rule the template draws between the two card rows — restyled to
     the live phone pitch (1px, 6px dash / 4px gap, #D2CECA @65%; a native 2px
     dashed border rendered a different dash rhythm than live's) */
  .hm-areas__row--caps .hm-card--cap + .hm-card--cap {
    border-top: 0;
    background:
      repeating-linear-gradient(
        to right, rgba(210, 206, 202, .65) 0 6px, transparent 6px 10px)
      0 0 / 100% 1px no-repeat;
    padding-top: 1px;
  }
  /* AUTNEX ADAPTATION: live centres the areas "+" cross where this rule meets
     the x195 mid separator of its 2x2 grid; the capability cards stack
     full-width with no mid separator, so the cross sits on the orange rail
     instead — the placement every other section's cross uses. */
  .hm-areas__cross {
    position: absolute; z-index: 1;
    left: -7px; top: -8px;
    width: 15px; height: 15px;
  }
  .hm-areas__cross svg { display: block; width: 100%; height: 100%; }
}

/* --- projects: the corner stat is now "4 / case studies" (plan §3.6) ------
   The template shipped a single `30%` figure; the replacement is a numeral
   over a mono caption, so the positioned box becomes a small column. */
.hm-projects__stat { display: flex; flex-direction: column; gap: 8px; }
.hm-projects__stat .t-h3-caps,
.hm-projects__stat .t-mono { color: var(--c-white); }
/* Below 1440 the stat sits directly above the full-width CTA with only 57px of
   clearance (it used to hold a one-line "30%"), so the caption goes inline. */
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-projects__stat { flex-direction: row; align-items: baseline; gap: 14px; }
}
/* the phone reference has no corner stat at all — restated because the block
   above re-declares `display` after the template's own phone rule. */
@media (max-width: 809.98px) { .hm-projects__stat { display: none; } }

/* --- results -> proof band (plan §3.5) ------------------------------------
   The old phone override (auto-height band + 36px padding so the body
   sentences could render) is superseded by the 2026-08-23 phone parity pass:
   live hides the stat body copy at <=809.98 and runs the fixed 445px band of
   fig|label rows, so the template's phone rules apply unmodified. The body
   sentences still render at >=810. */

/* --- engagements (plan §3.11) --------------------------------------------
   The annual/monthly control is hidden rather than deleted so js/main.js's
   price-toggle handler keeps a group to bind to and stays inert. */
.hm-annual__toggle { display: none; }
/* durations, not prices: 48px display type overflows a 229px column at
   "4-8 WEEKS", so the figure drops to a size that still reads as the card's
   headline number. */
.hm-annual .hm-tier__fig { font-size: 32px; line-height: 110%; }
@media (max-width: 809.98px) { .hm-annual .hm-tier__fig { font-size: 28px; } }
/* the template's feature rows were a fixed 28.7px because every bullet was two
   or three words; the engagement bullets are full phrases that wrap, so the row
   has to grow instead of overlapping its neighbour. */
.hm-annual .hm-tier__feat { height: auto; min-height: 28.7px; align-items: baseline; }
.hm-annual .hm-tier__list { gap: 6px; }
/* ...and the tier band, which was cut to the template's four short bullets,
   grows with them. Only >=1440 renders the lists at all. */
@media (min-width: 1440px) {
  .hm-annual--desktop { height: min-content; max-height: unset; }
  .hm-annual__b4 { height: 280px; }
}
/* projects (graphite) now runs straight into the engagements band (graphite);
   without a rule the two read as one 1900px dark block. */
.hm-annual { border-top: 1px solid var(--c-graphite-lt); }

/* --- her: badge clearance below 1440 --------------------------------------
   The hero's badge only clears the fixed menu-line at >=1440, where
   .hm-cc--rail-lg pushes .hm-her__illbody into the middle third. Below that
   the rail offset drops away and the badge lands under the wordmark, so it
   moves down past the 45px menu (which sits 13px from the top). The badge is
   inside a 50%-height band whose h1 is absolutely bottom-pinned, so nothing
   measured moves. Hidden entirely at <=809. */
@media (min-width: 810px) and (max-width: 1439.98px) {
  .hm-her__illbody > .hm-badge { margin-top: 78px; }
}

/* ================================================================
   HERO INTRO BUILD  (measured on the live reference, 2026-08-18)
   ----------------------------------------------------------------
   After load the reference assembles the hero illustration:
     - Step-6 orange square springs in from scale 0 (~420ms, ~8%
       overshoot), then the biege logo block (~360ms), then the corner
       angles (~400ms); the three small sheets + their icons pop in
       ~200ms apart; the four arrows join last.
     - The Step-4 sheet stack fades in (01 chip first, stack second)
       and settles with two springy horizontal shunts — on the live
       site that wiggle is the stack re-centering as its columns pop
       in one by one; with the stack baked into one SVG the two
       shunts reproduce the same perceived assembly kick.
     - The "01 intro" badge pops in and its number/label slide out
       (measured: number -6px, label -22px, slight overshoot).
   Armed by html.js-appear (added by js/main.js before first paint),
   so with JS off nothing here applies and the hero renders at rest.
   Only transform/opacity are animated — heights never move.
   ================================================================ */
html.js-appear .hm-her .s6-square    { animation: her-intro-pop  .42s cubic-bezier(.3, 1.36, .5, 1) .40s both; }
html.js-appear .hm-her .s6-logoblock { animation: her-intro-popc .36s cubic-bezier(.3, 1.36, .5, 1) .58s both; }
html.js-appear .hm-her .s6-angles    { animation: her-intro-pop  .40s cubic-bezier(.3, 1.2,  .5, 1) .80s both; }
html.js-appear .hm-her .s6-sheet1, html.js-appear .hm-her .s6-icon1 { animation: her-intro-fade .12s linear .82s both; }
html.js-appear .hm-her .s6-sheet2, html.js-appear .hm-her .s6-icon2 { animation: her-intro-fade .12s linear 1.04s both; }
html.js-appear .hm-her .s6-sheet3, html.js-appear .hm-her .s6-icon3 { animation: her-intro-fade .12s linear 1.22s both; }
html.js-appear .hm-her .s6-arrup,
html.js-appear .hm-her .s6-arrto,
html.js-appear .hm-her .s6-arrright,
html.js-appear .hm-her .s6-arrdown   { animation: her-intro-fade .15s linear 1.35s both; }

/* Step-4 stack: the live component assembles COLUMN BY COLUMN
   (01 -> 02/03/04 -> 05/06/07, ~150ms apart) and re-centers as it
   grows. The sheets and their number labels are baked into two SVGs,
   so the columns are revealed with stepped clip-path insets (cuts at
   the gaps between sheet columns: base 36/83 of 120, chip 33/80 of
   106) while the group glides ~18px left into place as the last
   column lands — no whole-block fade, no lurch. */
html.js-appear .hm-her__step4-base {
  animation: her-intro-fade .10s linear .70s both,
             her-intro-s4cols-base .30s linear .70s both;
}
html.js-appear .hm-her__step4-chip {
  animation: her-intro-fade .10s linear .70s both,
             her-intro-s4cols-chip .30s linear .70s both;
}
html.js-appear .hm-her__step4 { animation: her-intro-s4settle .35s cubic-bezier(.22, 1, .36, 1) 1.0s both; }

html.js-appear .hm-her .hm-badge        { animation: her-intro-fade .12s linear .80s both; }
html.js-appear .hm-her .hm-badge__num   { animation: her-intro-num   .30s cubic-bezier(.34, 1.3, .46, 1) .85s both; }
html.js-appear .hm-her .hm-badge__label { animation: her-intro-label .30s cubic-bezier(.34, 1.3, .46, 1) .85s both; }

@keyframes her-intro-pop  { from { transform: scale(0); } to { transform: scale(1); } }
@keyframes her-intro-popc { from { transform: translate(-50%, -50%) scale(.2); } to { transform: translate(-50%, -50%) scale(1); } }
@keyframes her-intro-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes her-intro-num   { from { transform: translateX(-6px); }  to { transform: translateX(0); } }
@keyframes her-intro-label { from { transform: translateX(-22px); } to { transform: translateX(0); } }
@keyframes her-intro-s4cols-base {
  0%, 49%  { clip-path: inset(0 70% 0 0); }
  50%, 99% { clip-path: inset(0 31% 0 0); }
  100%     { clip-path: inset(0 0 0 0); }
}
@keyframes her-intro-s4cols-chip {
  0%, 49%  { clip-path: inset(0 69% 0 0); }
  50%, 99% { clip-path: inset(0 25% 0 0); }
  100%     { clip-path: inset(0 0 0 0); }
}
@keyframes her-intro-s4settle {
  from { transform: translateX(calc(-50% + 18px)); }
  to   { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  html.js-appear .hm-her .s6,
  html.js-appear .hm-her .s6-logoblock,
  html.js-appear .hm-her__step4,
  html.js-appear .hm-her__step4-base,
  html.js-appear .hm-her__step4-chip,
  html.js-appear .hm-her .hm-badge,
  html.js-appear .hm-her .hm-badge__num,
  html.js-appear .hm-her .hm-badge__label { animation: none !important; }
}

/* ================================================================
   PHONE ORANGE RAIL — whole-page dashed line continuity
   Measured live 2026-08-23 at 390x844: a 1px vertical dash runs at x=26
   through EVERY section with no gaps (each band carries its own
   "Vert line orange" div; Framer paints it as a 1px box whose ::after has a
   2px dashed border -> renders 1px wide, ~6px dashes / 4px gaps).
   Colour is PEACH #E68C55 (not the pure orange #ED4F00 the clone's
   1px-dashed border rendered): full alpha on cream/stone sections, 95% on
   white sections, 75% on the dark ones (sampled 180,113,71 over #202020 and
   231,145,93 over #fff).  The right page edge keeps a faint SOLID grey rule
   at x=363 in the areas/process/results bands.
   (AUTNEX: envs/stack/value/testi selectors kept for parity with the clone
   even though those sections are off this home — they cost nothing and let
   the sections be lifted back verbatim.)
   ================================================================ */
@media (max-width: 809.98px) {
  /* phone-only hard line break: live splits several headings/labels across
     two text blocks at 390 — breaks no width clamp reproduces. The wrapped
     words are autnex's own copy, broken where they read right at 390.
     Inline (no-op) at >=810. */
  .lnp { display: block; }

  .hm-vline--orange {
    border-left: 0;
    background: repeating-linear-gradient(
      to bottom, var(--phone-dash, var(--c-peach)) 0 6px, transparent 6px 10px);
  }
  /* white-bg sections dash at 95%, dark sections at 75% (live tokens) */
  .hm-areas, .hm-envs, .hm-stack { --phone-dash: var(--c-peach-95); }
  .hm-projects, .hm-annual       { --phone-dash: var(--c-peach-75); }

  /* orange rails always hang at the LEFT page inset, even when the vline is
     its band's only (thus :last-child) cc child */
  .hm-cc > .hm-vline.hm-vline--orange { left: var(--page-pad-phone); right: auto; }

  /* faint solid right-edge rules at x363 (live alphas differ per section) */
  .hm-vline--pr40  { background: rgba(210, 206, 202, .4); }
  .hm-vline--pr50  { background: rgba(207, 206, 204, .5); }
  .hm-vline--pr100 { background: rgb(210, 206, 202); }

  /* the phone-only secheads collapse to 0 height because their badge is
     hidden; pin their rail to the whole band */
  .hm-sechead:not(.hm-cc) > .hm-vline {
    position: absolute; left: var(--page-pad-phone); top: 0; bottom: 0;
    width: 1px; height: auto;
  }

  /* testi: dormant on the Autnex home (section removed) — kept so the
     section can be lifted verbatim. The rail runs BEHIND the stacked quote
     cards; it lives in the stage, before the cards. Skips b1's own 140px. */
  .hm-testi__stage-vline {
    position: absolute; left: var(--page-pad-phone); top: 140px; bottom: 0;
    width: 1px;
    background: repeating-linear-gradient(
      to bottom, var(--c-peach) 0 6px, transparent 6px 10px);
  }

  /* NOTE: live's DOM has 1x57 white "edge" divs beside the projects/pricing
     CTAs but pixel-sampling shows they never render at rest — the rail's
     dash runs uninterrupted — so nothing is added there. */
}
