/* ============================================================
   TECHHOLDEN — the corporate site
   Rebuilt 2026-08-18 on four rulings:
     · Paper ground with accent bands, not black throughout
     · the WebGL load field is cut, not quietened
     · conventional corporate section order, our own substance in it
     · homepage first, inner pages behind it in this same system

   Retheme, 2026-09-07: brand v2 replaces Graphite & Azure with the
   three colours the brand sheet names (black, grey, blue) and the
   Archivo + Inter pair with Montserrat alone. Layout, copy and page
   structure are untouched.

   What survives: the seven-step type scale, the eleven drawn marks,
   the published engagement model, and the rule that nothing on the
   page claims something nobody has confirmed.
   ============================================================ */

/* ---- ONE FAMILY. Montserrat, self-hosted, weight 100-900.
   The brand sheet of 7 September 2026 names one typeface and sets the wordmark
   in it too, so the Archivo + Inter pair the kinetic build ran on is retired
   and with it the wordmark's font exception: mark and body copy are now the
   same face at different weights. Montserrat carries NO width axis, so every
   'wdth' setting the old scale used is gone; weight, size and tracking do that
   work instead. Two subsets, latin and latin-ext, both variable. ---- */
@font-face{
  font-family:'Montserrat';
  src:url('./fonts/montserrat-var-latin.woff2') format('woff2-variations');
  font-weight:100 900; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Montserrat';
  src:url('./fonts/montserrat-var-latin-ext.woff2') format('woff2-variations');
  font-weight:100 900; font-display:swap;
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,
    U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,
    U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* ============================================================
   1 · GROUND TOKENS
   Paper is the page. Three bands sit on it — wash (pale blue),
   ink (black), and azure (the brand blue) — and each re-points the same six tokens so
   every element inside inherits the right value without a single
   band-specific colour rule.
   ============================================================ */
:root{
  --fg:        var(--th-black);
  --muted:     var(--th-grey-deep);
  --surface:   #FFFFFF;
  --hair:      color-mix(in srgb, var(--th-black) 13%, var(--th-paper));
  --accent:    var(--th-blue);
  --ground:    var(--th-paper);

  --wash:      var(--th-wash);
  --wash-hair: var(--th-mist);

  --shadow:    0 1px 2px rgba(0,0,0,.045), 0 10px 28px -14px rgba(0,0,0,.14);
  --shadow-up: 0 2px 4px rgba(0,0,0,.05), 0 20px 42px -18px rgba(0,0,0,.20);

  --gap:       clamp(16px, 1.6vw, 24px);
  --sec:       clamp(64px, 8vw, 118px);
}

.band--wash{ --ground:var(--wash); --hair:var(--wash-hair); background:var(--wash); }
.band--ink{
  --fg:var(--th-paper); --muted:var(--th-grey); --surface:var(--th-raised);
  --hair:var(--th-line); --accent:var(--th-blue-lift); --ground:var(--th-black);
  --shadow:none; --shadow-up:none;
  background:var(--th-black); color:var(--th-paper);
}
.band--azure{
  --fg:#fff; --muted:#F2F6FC; --surface:rgba(255,255,255,.10);  /* 4.70:1 on the blue */
  --hair:rgba(255,255,255,.28); --accent:#fff; --ground:var(--th-blue);
  --shadow:none; --shadow-up:none;
  background:var(--th-blue); color:#fff;
}

/* ============================================================
   2 · RESET AND THE ONE CONTAINER
   Every band is full-bleed; every line of content sits inside the
   same .page. One left edge on the whole site, nothing opts out.
   ============================================================ */
*,*::before,*::after{ box-sizing:border-box; }
html{ scroll-behavior:smooth; scroll-padding-top:88px; }
html,body{ margin:0; padding:0; }
body{
  background:var(--th-paper);
  color:var(--th-black);
  font-family:var(--th-sans);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img,svg{ max-width:100%; }
.page{ width:min(100% - 2*var(--gap), 1180px); margin-inline:auto; }
section.band{ padding-block:var(--sec); }
.skip{
  position:absolute; left:-9999px; top:0; z-index:60;
  background:var(--th-black); color:var(--th-paper);
  padding:10px 16px; border-radius:8px; text-decoration:none;
}
.skip:focus{ left:var(--gap); top:10px; }
:where(a,button,summary):focus-visible{
  outline:2px solid var(--th-blue); outline-offset:3px; border-radius:4px;
}

/* ============================================================
   3 · TYPE — seven steps, carried over from the kinetic build.
   Nothing may sit between them.
   ============================================================ */
/* ---- The spacing scale, 4pt based, published 2026-08-18 ----
   Values were previously picked ad hoc: 22, 26, 30, 34, 52, 82 and 118px all
   appeared alongside the 4pt-friendly ones, so there was no set to check a new
   value against. These are the set. A 4pt base rather than 8pt, because 8pt is
   too coarse — 12px between 8 and 16 is needed constantly.

   Documented exceptions, deliberately NOT snapped: 1-3px hairlines and borders;
   the 5/6/9px optical nudges inside marks and tick bullets; and 13/17px, which
   are single-purpose optical corrections on the button and the beam lockup.
   Snapping those would move ink, not air. */
:root{
  --sp-1:  4px;   --sp-2:  8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 20px;   --sp-6: 24px;   --sp-8: 32px;  --sp-10: 40px;
  --sp-12: 48px;  --sp-14: 56px;  --sp-16: 64px; --sp-18: 72px;
  --sp-20: 80px;  --sp-24: 96px;  --sp-30: 120px;
}

:root{
/* The brand sheet names four steps — display 48/52, heading 36/40, body 16/24,
   small 12/16. Those are the anchors; label, small and sub fill the gaps the
   site actually needs and nothing sits between them. --t-head tops out at 36px
   (2.25rem) and --t-display at 48px (3rem) so a desktop page renders the sheet
   at its stated sizes rather than a third larger. */
  --t-label:   12px;
  --t-small:   14px;
  --t-body:    16px;
  --t-lead:    19px;
  --t-sub:     22px;
  --t-head:    clamp(1.75rem, 3vw, 2.25rem);
  --t-display: clamp(2.25rem, 4.4vw, 3rem);
}
h1,h2,h3,p,ul,ol,dl,dd,figure{ margin:0; }
/* Additive leading, not a ratio. --t-display is fluid (40px on a phone, 64px
   on a desktop) and a single ratio cannot serve both: 1.03 leaves ~2px between
   a descender and the next cap-line at 64px, and the same ratio at 40px — where
   the headline runs to three lines — is tighter still, because small display
   type needs MORE relative leading, not the same. calc(em + rem) gives ~1.16 at
   64px and ~1.22 at 40px from one declaration.

   Montserrat's ascender runs 0.968em and its descender 0.251em against a
   1000-unit em, so 1.22em of every line box is potential ink — considerably
   more than the face this scale was first solved for, and a tight ratio here
   collides sooner. The brand sheet asks for 48/52, a ratio of 1.083, which is
   right at 48px and far too tight at the 36px a phone renders. The additive
   form gives 1.085 at 48px, matching the sheet, and 1.12 at 36px, which is
   what the smaller size needs. */
h1{ font-size:var(--t-display); font-variation-settings:'wght' 700;
    line-height:calc(1.02em + 0.19rem); letter-spacing:-.021em; }
h2{ font-size:var(--t-head);    font-variation-settings:'wght' 600;
    line-height:1.12; letter-spacing:-.016em; }
h3{ font-size:var(--t-sub);     font-variation-settings:'wght' 600;
    line-height:1.25; letter-spacing:-.009em; }
p{ font-size:var(--t-body); font-variation-settings:'wght' 400; line-height:1.5; }
.deck{ font-size:var(--t-lead); font-variation-settings:'wght' 400;
       line-height:1.5; color:var(--muted); max-width:62ch; margin-top:var(--gap); }
.lede{ font-size:var(--t-lead); font-variation-settings:'wght' 400;
       line-height:1.55; color:var(--fg); max-width:60ch; }
.label{
  font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; text-transform:uppercase; line-height:1.4;
  color:var(--accent); font-variant-numeric:tabular-nums;
}
.small{ font-size:var(--t-small); font-variation-settings:'wght' 500; color:var(--muted); }
.muted{ color:var(--muted); }
a{ color:var(--accent); }

/* Section heads: label, rule, heading, standfirst — one pattern, every band.

   The max-width is in rem, not ch, and that is deliberate. `ch` resolves
   against the element's OWN font-size, so `.sechead{max-width:64ch}` at 16px
   computed to 586px while the `.deck` inside it, declared NARROWER at 58ch but
   set at 19.4px, wanted 631px. The parent won, and the same standfirst rendered
   631px under a page hero and 586px under a section head — the width
   inconsistency read across the site. A rem cap is font-size-independent, so
   the container can no longer be accidentally narrower than its own child. */
.sechead{ max-width:41.25rem; }   /* 660px — comfortably clear of the 631px deck */
.sechead .label{ display:block; margin-bottom:var(--gap); }
.sechead h2 + .deck{ margin-top:var(--gap); }
/* Unused since 2026-08-18: the blue conviction band was the only thing centred
   on the site, and it broke the one-left-edge rule §1.3 rests on. Kept as an
   available utility, not applied anywhere. */
.sechead--mid{ margin-inline:auto; text-align:center; }
.sechead--mid .deck{ margin-inline:auto; }

/* ============================================================
   4 · CONTROLS
   ============================================================ */
.btn{
  display:inline-flex; align-items:center; gap:.5em;
  font-size:var(--t-body); font-variation-settings:'wght' 600;
  letter-spacing:-.004em; text-decoration:none;
  padding:13px 24px; border-radius:999px; border:1px solid transparent;
  transition:background-color .18s ease, border-color .18s ease,
             transform .18s cubic-bezier(.2,.7,.2,1), box-shadow .18s ease;
}
.btn::after{ content:"→"; transition:transform .18s cubic-bezier(.2,.7,.2,1); }
.btn:hover::after{ transform:translateX(3px); }
.btn--primary{ background:var(--th-blue); color:#fff; box-shadow:var(--shadow); }
.btn--primary:hover{ background:var(--th-blue); transform:translateY(-2px);
                     box-shadow:var(--shadow-up); }
.btn--ghost{ color:var(--fg); border-color:var(--hair); background:var(--surface); }
.btn--ghost:hover{ border-color:var(--th-blue); color:var(--accent); transform:translateY(-2px); }
.band--azure .btn--primary{ background:#fff; color:var(--th-blue); }
.band--azure .btn--primary:hover{ background:#fff; }
.band--azure .btn--ghost{ background:transparent; color:#fff; border-color:rgba(255,255,255,.5); }
.band--azure .btn--ghost:hover{ border-color:#fff; color:#fff; }
.band--ink .btn--ghost{ background:transparent; }
.cta-row{ display:flex; flex-wrap:wrap; gap:12px; margin-top:calc(var(--gap) * 1.4); }
.textlink{
  font-size:var(--t-small); font-variation-settings:'wght' 600;
  text-decoration:none; letter-spacing:.005em;
}
.textlink::after{ content:" →"; }
.textlink:hover{ text-decoration:underline; }

/* ============================================================
   5 · HEADER
   ============================================================ */
.site-head{
  position:sticky; top:0; z-index:50;
  background:color-mix(in srgb, var(--th-paper) 88%, transparent);
  backdrop-filter:saturate(150%) blur(10px);
  border-bottom:1px solid transparent;
  transition:border-color .2s ease, box-shadow .2s ease;
}
.site-head[data-stuck]{ border-bottom-color:var(--hair); box-shadow:0 6px 20px -18px rgba(11,14,17,.5); }
.head-in{ display:flex; align-items:center; gap:var(--gap); padding-block:14px; }
/* ---- THE LOGO, 2026-09-07 ----
   The mark is drawn, not set: `img/logo.svg` holds the paths from the brand
   pack's own file as one <symbol>, and colour arrives through three inherited
   custom properties because CSS selectors cannot reach into the shadow tree a
   <use> builds. Sizing is by HEIGHT — the aspect ratio is fixed at the mark's
   measured ink box (622.843 x 79.908, i.e. 7.795:1) so a width would have to be
   restated every time the height changed. */
.th-logo-link{ display:inline-flex; text-decoration:none; }
.th-logo{
  --lm-a:var(--fg); --lm-b:var(--th-grey); --lm-dot:var(--th-blue);
  display:block; height:22px; width:calc(22px * 7.795);
  width:auto; aspect-ratio:622.843 / 79.908;
}
/* On the blue band the accent dot would vanish into the ground, and the grey
   drops to 1.48:1. Everything goes paper except `holden`, which keeps a tint
   so the two halves of the mark still read as two. */
.band--azure .th-logo{ --lm-a:#fff; --lm-b:#C6D8EF; --lm-dot:#fff; }
/* The beam is as wide as `tech` because the ghost copy of `tech` sets the
   lockup's width. The ghost must therefore be in the SAME face and weight as
   the mark; measured in anything else it produces a beam that fits nothing. */
.th-beamlock .th-ghost{ font-family:var(--th-sans); }
.site-nav{ margin-left:auto; display:flex; gap:calc(var(--gap) * 1.1); }
.site-nav a{
  font-size:var(--t-small); font-variation-settings:'wght' 500;
  color:var(--th-grey-deep); text-decoration:none; padding-block:6px;
  border-bottom:1.5px solid transparent; transition:color .15s ease, border-color .15s ease;
}
/* --fg, not --th-ink. Both resolve to Ink on a light ground, but --th-ink is
   also the dark page ground, so hovering blacked the item out entirely. The
   underline stays --th-blue: it measures 4.12:1 on the dark header, past the
   3:1 a non-text graphic needs, so it did not need touching. */
.site-nav a:hover{ color:var(--fg); border-bottom-color:var(--th-blue); }
.head-cta{ margin-left:var(--gap); padding:9px 17px; font-size:var(--t-small); }
.navtoggle{ display:none; }

/* ============================================================
   6 · HERO
   ============================================================ */
.hero{ padding-block:clamp(48px, 6.5vw, 92px) clamp(40px, 5vw, 72px); }
.hero-grid{
  display:grid; gap:clamp(28px, 4vw, 64px);
  grid-template-columns:minmax(0, 1.02fr) minmax(0, .98fr);
  align-items:center;
}
.hero h1{ margin-top:18px; }
.hero .deck{ font-size:clamp(1.05rem, 1.35vw, 1.24rem); max-width:52ch; }
.th-beamlock.lockup{ font-size:56px; }
.th-beamlock.lockup .th-beam{ background:var(--th-blue); }
.herofig{ width:100%; height:auto; color:color-mix(in srgb, var(--th-black) 46%, var(--th-paper)); }

/* ============================================================
   7 · MARKS — the drawn illustration set
   Paint arrives from outside the sprite: stroke is currentColor,
   the dot reads --mk-az, the one occluding panel reads --mk-ground,
   and the stroke weight reads --mk-sw. CSS rules cannot reach inside
   the shadow tree a <use> builds; custom properties inherit into it.
   ============================================================ */
body{ --mk-az:var(--th-blue); --mk-ground:var(--th-paper); }
.band--ink{ --mk-az:var(--th-blue-lift); --mk-ground:var(--th-black); }
.band--azure{ --mk-az:#fff; --mk-ground:var(--th-blue); }
.mark{
  display:block; flex:none; width:84px; height:84px;
  color:color-mix(in srgb, var(--fg) 62%, var(--ground));
  transition:color .18s ease;
}
.mark--sm{ width:44px; height:44px; --mk-sw:2.1; }
.mark--xs{ width:32px; height:32px; --mk-sw:3.2; }

/* ============================================================
   8 · CARDS
   ============================================================ */
.cards{
  display:grid; gap:var(--gap); align-items:stretch;
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 268px), 1fr));
  margin-top:clamp(32px, 3.6vw, 52px);
}
.cards--4{ grid-template-columns:repeat(auto-fit, minmax(min(100%, 230px), 1fr)); }
.card{
  position:relative;
  --mk-ground:var(--surface);
  background:var(--surface);
  border:1px solid var(--hair);
  border-radius:var(--th-radius);
  padding:clamp(24px, 2.2vw, 32px);
  display:flex; flex-direction:column; align-items:flex-start; gap:14px;
  box-shadow:var(--shadow);
  transition:border-color .18s ease, transform .18s cubic-bezier(.2,.7,.2,1), box-shadow .18s ease;
}
.card:hover{ border-color:color-mix(in srgb, var(--th-blue) 45%, var(--hair));
             transform:translateY(-3px); box-shadow:var(--shadow-up); }
.card:hover .mark{ color:var(--fg); }
.card h3{ margin:0; }
.card p{ margin:0; color:var(--muted); }
.card .textlink{ margin-top:auto; padding-top:4px; }
.card--lead{ border-color:color-mix(in srgb, var(--th-blue) 52%, transparent); }
.card--lead .mark{ color:var(--accent); }
.card__tag{
  position:absolute; top:clamp(22px, 2.2vw, 30px); right:clamp(22px, 2.2vw, 30px);
  font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--accent);
}
.card--span{ grid-column:1 / -1; flex-direction:row; align-items:center; gap:clamp(20px,2.4vw,32px); }
.card--span .card__body{ display:flex; flex-direction:column; gap:8px; }

/* ============================================================
   9 · THE COMPARISON — hire it / rent it / us
   ============================================================ */
.compare{ display:grid; gap:0; margin-top:clamp(28px, 3vw, 44px);
  border-top:1px solid var(--hair); }
.compare__row{
  display:grid; grid-template-columns:minmax(140px, 200px) 1fr;
  gap:var(--gap); padding-block:20px; border-bottom:1px solid var(--hair);
  align-items:baseline;
}
.compare__k{ font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
.compare__row--us .compare__k{ color:var(--accent); }
.compare__row--us .compare__v{ font-variation-settings:'wght' 500; }
.compare__v{ margin:0; max-width:62ch; }

/* ============================================================
   10 · THE SPECIFICATION MATRIX
   ============================================================ */
.spec{ margin-top:clamp(32px, 3.4vw, 48px); border-top:1px solid var(--hair);
  font-variant-numeric:tabular-nums; }
.spec__head, .spec__row{
  display:grid; grid-template-columns:minmax(120px, 1fr) repeat(3, minmax(0, 2fr));
  gap:var(--gap); padding-block:18px; border-bottom:1px solid var(--hair);
  align-items:start;
}
.spec__head span{ font-size:var(--t-sub); font-variation-settings:'wght' 600;
  letter-spacing:-.012em; }
.spec__head .is-lead{ color:var(--accent); }
.spec__head em{ display:block; font-style:normal; font-size:var(--t-label);
  font-variation-settings:'wght' 600; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent); margin-top:4px; }
.spec__k{ font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
.spec__row span:not(.spec__k){ font-size:var(--t-body); color:var(--muted); }
.spec__row .is-lead{ color:var(--fg); font-variation-settings:'wght' 500; }

/* ============================================================
   11 · PRODUCTS — the one Ink band
   ============================================================ */
.prod-grid{ display:grid; gap:clamp(20px, 2.4vw, 32px);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  margin-top:clamp(32px, 3.6vw, 52px); }
.shot{ margin:0; }
.shot img{ display:block; width:100%; height:auto;
  border:1px solid var(--th-line); border-radius:10px; }
.shot figcaption{ margin-top:12px; font-size:var(--t-small); color:var(--muted); }
.shot figcaption b{ color:var(--th-paper); font-variation-settings:'wght' 600; }
.statusrow{ display:flex; flex-wrap:wrap; gap:calc(var(--gap) * 1.6);
  margin-top:clamp(32px, 3.2vw, 44px); padding-top:24px; border-top:1px solid var(--hair); }
.statusrow div{ min-width:190px; }
.statusrow dt{ font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
.statusrow dd{ margin:5px 0 0; font-size:var(--t-body); }

/* ============================================================
   12 · WORKED PROBLEMS
   ============================================================ */
.cases{ display:grid; gap:clamp(28px, 3.4vw, 56px);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 400px), 1fr));
  margin-top:clamp(32px, 3.4vw, 48px); }
.case__head{ display:flex; align-items:center; gap:16px; }
.steps{ list-style:none; margin:var(--gap) 0 0; padding:0; }
.steps li{
  display:grid; grid-template-columns:34px 132px 1fr; gap:var(--gap);
  padding-block:15px; border-top:1px solid var(--hair); align-items:baseline;
}
.steps li:last-child{ border-bottom:1px solid var(--hair); }
.steps__n{ font-size:var(--t-label); font-variation-settings:'wght' 600;
  color:var(--accent); font-variant-numeric:tabular-nums; }
.steps__t{ font-size:var(--t-body); font-variation-settings:'wght' 600; }
.steps__d{ font-size:var(--t-body); color:var(--muted); }
.tag{
  display:inline-block; margin-top:var(--gap);
  font-size:var(--t-small); font-variation-settings:'wght' 500; color:var(--muted);
  border:1px dashed var(--hair); border-radius:999px; padding:5px 13px;
}

/* ============================================================
   13 · CONTACT + FOOTER
   ============================================================ */
.mailplain{ margin-top:var(--gap); color:var(--muted); font-size:var(--t-body); }
.sel{ color:var(--fg); font-variation-settings:'wght' 600; user-select:all; }
.site-foot{ background:var(--th-black); color:var(--th-paper);
  --fg:var(--th-paper); --muted:var(--th-grey); --hair:var(--th-line); --accent:var(--th-blue-lift);
  padding-block:clamp(48px, 5vw, 76px) 32px; }
.foot-grid{ display:grid; gap:var(--gap);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 190px), 1fr)); }
.foot-mark{ display:block; margin-bottom:10px; }
.foot-mark .th-logo{ height:26px; }
.foot-h{ font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin-bottom:12px; }
.site-foot nav{ display:flex; flex-direction:column; gap:9px; align-items:flex-start; }
.site-foot a{ color:var(--th-paper); text-decoration:none; font-size:var(--t-small);
  font-variation-settings:'wght' 500; }
.site-foot a:hover{ color:var(--th-blue-lift); }
.foot-legal{ display:flex; flex-wrap:wrap; gap:8px var(--gap);
  justify-content:space-between; margin-top:clamp(36px, 4vw, 56px);
  padding-top:24px; border-top:1px solid var(--hair); }
.foot-legal p{ margin:0; font-size:var(--t-small); color:var(--muted); }

/* ============================================================
   14 · RESPONSIVE
   ============================================================ */
@media (max-width:960px){
  .hero-grid{ grid-template-columns:1fr; }
  .herofig{ max-width:560px; }
  .site-nav{ display:none; }
  .navtoggle{
    display:inline-flex; margin-left:auto; align-items:center; gap:8px;
    background:none; border:1px solid var(--hair); border-radius:999px;
    padding:8px 15px; font:inherit; font-size:var(--t-small);
    font-variation-settings:'wght' 500; color:var(--fg); cursor:pointer;
  }
  .site-head[data-open] .site-nav{
    display:flex; flex-direction:column; gap:0; width:100%; margin:0;
    order:3; border-top:1px solid var(--hair); padding-block:8px;
  }
  .site-head[data-open] .site-nav a{ padding-block:12px; border-bottom:0; }
  .head-in{ flex-wrap:wrap; }
  .head-cta{ margin-left:12px; }
}
@media (max-width:760px){
  .spec__head, .spec__row{ grid-template-columns:1fr; gap:6px; padding-block:16px; }
  .spec__head span{ font-size:var(--t-body); }
  .spec__head .is-lead{ font-size:var(--t-sub); }
  .spec__row span:not(.spec__k)::before{
    content:attr(data-col) " — "; font-variation-settings:'wght' 600; color:var(--fg);
  }
  .steps li{ grid-template-columns:34px 1fr; }
  .steps__d{ grid-column:2; }
  .card--span{ flex-direction:column; align-items:flex-start; }
  .compare__row{ grid-template-columns:1fr; gap:4px; }
  .mark{ width:64px; height:64px; }
}
@media (max-width:420px){ .head-cta{ display:none; } }

/* ============================================================
   15 · REDUCED MOTION — the base state, not an afterthought
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{ transition:none !important; animation:none !important; }
  .card:hover, .btn:hover{ transform:none; }
}

/* ---- Print: the page as a document ---- */
@media print{
  .site-head, .cta-row, .btn{ display:none; }
  body{ background:#fff; }
  .band--ink, .band--azure{ background:#fff; color:#000; --fg:#000; --muted:#333; }
}

/* ============================================================
   16 · CORRECTIONS FROM THE FIRST RENDER
   ============================================================ */

/* The hero headline broke as "Software built to / hold", which strands the one
   word the whole positioning rests on. Balanced wrapping fixes it without
   hard-coding a break that would be wrong at another width. */
h1{ text-wrap:balance; }

/* The hero figure needs a block to sit in, or a line drawing floats in white
   space and reads as an afterthought. Wash panel, same family as the bands. */
.herofig-wrap{
  background:var(--wash);
  border:1px solid var(--wash-hair);
  border-radius:20px;
  padding:clamp(18px, 2.4vw, 32px);
  --mk-az:var(--th-blue);
}
.herofig{ color:color-mix(in srgb, var(--th-black) 52%, var(--wash)); }

.lede--after{ margin-top:clamp(24px, 2.6vw, 36px); }
.cta-row--mid{ justify-content:center; }
.pname{ color:var(--th-paper); font-variation-settings:'wght' 600; }

/* The status row was a flex line, so the first long definition claimed the whole
   width and pushed the other two onto a second row. Three columns, always. */
.statusrow{
  display:grid; gap:var(--gap) calc(var(--gap) * 1.6);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 240px), 1fr));
}
.statusrow div{ min-width:0; }

/* "Leave the gauge" and "Share the on-call" wrapped in a column sized for
   shorter titles. */
.steps li{ grid-template-columns:34px 152px 1fr; }

/* Measured against the painted ground, not guessed. Re-solved 2026-09-07 for
   the new accent, which is darker than the old one and therefore easier: on the
   blue band the deck at #EAF1FA reached 4.48:1, just under AA for 19px body,
   and #F2F6FC clears it at 4.70. White on the blue is 5.10:1, so the usable
   range for secondary text here is narrow and any future value has to be
   measured rather than picked. The token lives in §1, not here. */

/* ============================================================
   17 · THE REWRITE — 2026-08-18
   Rulings behind this pass: plain benefit-led copy · no hero
   illustration · no proof sections, because there is no proof
   yet · anonymous, so every "named engineer" promise is gone ·
   generic product names · Techholden LLC, New York, in the foot.
   ============================================================ */

/* The hero carries no figure now. A quiet blue wash does the work the
   illustration was doing, which is what Intellectsoft — the closest
   comparable read in a browser on 2026-08-18 — runs behind its headline. */
.hero--plain{
  position:relative;
  padding-block:clamp(72px, 9vw, 148px) clamp(56px, 6.5vw, 104px);
  background:
    radial-gradient(90% 120% at 78% -10%,
      color-mix(in srgb, var(--th-blue) 13%, transparent) 0%, transparent 62%),
    radial-gradient(70% 90% at 4% 108%,
      color-mix(in srgb, var(--th-blue) 7%, transparent) 0%, transparent 60%);
}
.hero--plain h1{ margin-top:20px; max-width:21ch; }
.hero--plain .hero-deck{ max-width:56ch; margin-top:calc(var(--gap) * 1.2); }
.hero--plain .th-beamlock.lockup{ font-size:64px; }

/* ---- Industries: TNG's numbered 01–05 full-width pattern.
   Their five sectors, our sentences — lifting a named competitor's copy
   verbatim is a different thing from following their structure. ---- */
.inds{ margin-top:clamp(32px, 3.6vw, 52px); border-top:1px solid var(--hair); }
.ind{
  display:grid; grid-template-columns:minmax(64px, 92px) 1fr;
  gap:var(--gap); padding-block:clamp(24px, 2.4vw, 32px);
  border-bottom:1px solid var(--hair);
  transition:background-color .18s ease;
}
.ind:hover{ background:color-mix(in srgb, var(--th-blue) 4%, transparent); }
.ind__n{
  font-size:clamp(1.6rem, 2.4vw, 2.1rem);
  font-variation-settings:'wght' 600;
  letter-spacing:-.02em; line-height:1; color:var(--accent);
  font-variant-numeric:tabular-nums;
}
.ind__b h3{ margin-bottom:8px; }
.ind__b p{ color:var(--muted); max-width:68ch; }

/* ---- Products: text one side, the interface the other, alternating ---- */
.prod{
  display:grid; gap:clamp(24px, 3.2vw, 56px);
  grid-template-columns:minmax(0, .82fr) minmax(0, 1.18fr);
  align-items:center;
  margin-top:clamp(40px, 4.4vw, 68px);
}
.prod--alt{
  margin-top:clamp(56px, 6vw, 96px);
  /* the columns swap with the order, or the second product renders smaller
     than the first for no reason a reader could name */
  grid-template-columns:minmax(0, 1.18fr) minmax(0, .82fr);
}
.prod--alt .prod__t{ order:2; }
.prod__t h3{ margin-bottom:12px; }
.prod__t p{ color:var(--muted); max-width:46ch; }
.prod .shot img{
  display:block; width:100%; height:auto;
  border:1px solid var(--hair); border-radius:14px;
  box-shadow:var(--shadow-up);
}

/* ---- Footer address ---- */
.site-foot address{ font-style:normal; display:flex; flex-direction:column; gap:10px; }
.site-foot address span{
  font-size:var(--t-small); color:var(--muted); line-height:1.6;
  font-variation-settings:'wght' 400;
}

@media (max-width:900px){
  .prod, .prod--alt{ grid-template-columns:1fr; }
  .prod--alt .prod__t{ order:0; }
  .hero--plain h1{ max-width:none; }
}
@media (max-width:640px){
  .ind{ grid-template-columns:1fr; gap:6px; }
  .ind__n{ font-size:1.2rem; }
}

/* ============================================================
   18 · TAGLINE AND THE SIX-STAGE MODEL — 2026-08-18
   "Concept to Continuity." locked to the wordmark in the header
   and the footer, on the owner's ruling — not as the hero
   headline, because a firm nobody has heard of still needs the
   headline to say what it sells.

   The section beneath it was measured before this pass: 19 text
   blocks on the page carried delivery language against 11 that
   carried continuity, and How we work ran four delivery stages
   to one. A tagline promising a span cannot sit above a section
   that only describes the first half of it, so the section is
   now six numbered stages running concept → continuity. The
   tagline and the model are the same claim.
   ============================================================ */
.lockline{
  font-size:var(--t-small);
  font-variation-settings:'wght' 500;
  letter-spacing:.005em;
  color:var(--muted);
  padding-left:14px;
  margin-left:2px;
  border-left:1px solid var(--hair);
  white-space:nowrap;
}
.lockline--foot{
  margin:10px 0 0; padding:0; border:0;
  color:var(--muted);
}

/* Six stages read as a sequence, so they hold a fixed three-across
   grid rather than reflowing to a ragged four-plus-two. */
.cards--6{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
.card__n{
  font-size:var(--t-label);
  font-variation-settings:'wght' 600;
  letter-spacing:.1em; color:var(--accent);
  font-variant-numeric:tabular-nums;
}
.card__n + .mark{ margin-top:-4px; }

@media (max-width:1020px){ .cards--6{ grid-template-columns:repeat(2, minmax(0, 1fr)); } }
@media (max-width:960px){ .lockline{ display:none; } }
@media (max-width:620px){ .cards--6{ grid-template-columns:1fr; } }

/* ============================================================
   19 · A SITE, NOT A PAGE — 2026-08-18
   The audit that prompted this: 0 links to another page, 0 Open
   Graph tags, 0 structured data, no canonical, no manifest, no
   robots, no sitemap, no legal pages, no 404, 7 footer links.
   Against Intellectsoft's 25-plus footer links and a dozen
   service pages. Nothing about the design read as unfinished —
   the fact that it was one file did.

   Twelve pages now build from build.py. The patterns below are
   the ones the inner pages need and the homepage did not.
   ============================================================ */

/* ---- Page hero: smaller than the homepage's, same furniture ---- */
.pagehero{
  padding-block:clamp(56px, 6.5vw, 104px) clamp(36px, 4vw, 60px);
  background:radial-gradient(80% 120% at 82% -20%,
    color-mix(in srgb, var(--th-blue) 11%, transparent) 0%, transparent 60%);
}
.pagehero .label{ display:block; margin-bottom:var(--gap); }
.pagehero h1{ font-size:clamp(2.1rem, 4vw, 3.4rem); max-width:26ch; text-wrap:balance; }
.pagehero .deck{ max-width:58ch; }

/* ---- Service and industry detail rows ---- */
.svc, .indp{
  display:grid; gap:clamp(24px, 3.4vw, 56px);
  grid-template-columns:minmax(0, 1fr) minmax(0, 1fr);
  align-items:start;
}
/* Single column since the decorative 01-05 numerals were dropped (2026-08-18):
   an industries list is not a sequence, so the numbers were scaffolding, and the
   column they sat in was pushing every industry heading 150px right of the left
   edge every other block on the page shares. */
.indp{ grid-template-columns:minmax(0, 1fr); }
.svc__t .mark{ margin-bottom:var(--gap); }
.svc__t h2{ margin-bottom:12px; }
.pricing{
  margin-top:var(--gap); font-size:var(--t-label);
  font-variation-settings:'wght' 600; letter-spacing:.1em;
  text-transform:uppercase; color:var(--accent);
}
.indp h2{ margin-bottom:12px; }

/* ---- Tick lists: the "what you get" pattern every firm uses ---- */
.ticks{ list-style:none; margin:var(--gap) 0 0; padding:0; }
.ticks li{
  position:relative; padding-left:32px; padding-block:9px;
  border-bottom:1px solid var(--hair); color:var(--muted);
  font-size:var(--t-body);
}
.ticks li:first-child{ border-top:1px solid var(--hair); }
.ticks li::before{
  content:""; position:absolute; left:2px; top:16px;
  width:13px; height:13px; border-radius:50%;
  border:1.5px solid var(--accent);
  background:radial-gradient(circle at 50% 50%, var(--accent) 0 3px, transparent 3px);
}
.ticks--2{ columns:2; column-gap:var(--gap); }
.ticks--2 li{ break-inside:avoid; }

/* ---- The six stages, one per band ---- */
.stage{
  display:grid; gap:clamp(20px, 3vw, 48px);
  grid-template-columns:minmax(72px, 120px) minmax(0, 1fr);
  align-items:start;
}
.stage__n span{
  display:block; font-size:clamp(1.8rem, 2.8vw, 2.4rem);
  font-variation-settings:'wght' 600; letter-spacing:-.02em;
  line-height:1; color:var(--accent); font-variant-numeric:tabular-nums;
}
.stage__n .mark{ margin-top:var(--gap); }
.stage__b h2{ margin-bottom:12px; }
.stage__b p + p{ margin-top:var(--gap); color:var(--muted); max-width:66ch; }

/* ---- Running prose, for About and the legal pages ---- */
.prose{ max-width:68ch; }
.prose p + p{ margin-top:var(--gap); }
.prose p{ color:var(--muted); }
.prose--legal h2{
  font-size:var(--t-sub); margin-top:clamp(28px, 3vw, 44px); margin-bottom:10px; color:var(--fg);
}
.prose--legal h2:first-child{ margin-top:0; }
.draftnote{
  border:1px dashed var(--hair); border-radius:var(--th-radius);
  padding:14px 18px; margin-bottom:clamp(24px, 3vw, 40px);
  font-size:var(--t-small); color:var(--muted); max-width:68ch;
}
.draftnote b{ color:var(--fg); font-variation-settings:'wght' 600; }

/* ---- Company facts ---- */
.facts{ margin-top:clamp(24px, 3vw, 40px); border-top:1px solid var(--hair); }
.facts > div{
  display:grid; grid-template-columns:minmax(140px, 220px) 1fr; gap:var(--gap);
  padding-block:16px; border-bottom:1px solid var(--hair); align-items:baseline;
}
.facts dt{
  font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted);
}
.facts dd{ margin:0; }

/* ---- Contact ---- */
.contact-grid{
  display:grid; gap:clamp(24px, 4vw, 64px);
  grid-template-columns:minmax(0, 1.3fr) minmax(0, .7fr);
}
.contact-big{ margin:10px 0 var(--gap); }
.contact-big a{
  font-size:clamp(1.3rem, 2.4vw, 1.9rem);
  font-variation-settings:'wght' 600;
  letter-spacing:-.015em; text-decoration:none;
}
.contact-big a:hover{ text-decoration:underline; }
.contact-addr{ font-style:normal; margin-top:10px; color:var(--muted); line-height:1.75; }
.cards--3{ grid-template-columns:repeat(3, minmax(0, 1fr)); }

/* ---- The deep footer ---- */
.foot-grid--deep{ grid-template-columns:1.5fr repeat(3, 1fr); align-items:start; }
.foot-brand address{ margin-top:var(--gap); }
.foot-legal__links{ display:flex; flex-wrap:wrap; gap:8px; }
.foot-legal__links a{ font-size:var(--t-small); }

@media (max-width:1020px){
  .foot-grid--deep{ grid-template-columns:repeat(2, 1fr); }
  .cards--3{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
}
@media (max-width:820px){
  .svc, .contact-grid{ grid-template-columns:1fr; }
  .ticks--2{ columns:1; }
}
@media (max-width:620px){
  .indp, .stage{ grid-template-columns:1fr; gap:10px; }
  .cards--3, .foot-grid--deep{ grid-template-columns:1fr; }
  .facts > div{ grid-template-columns:1fr; gap:4px; }
}

/* ============================================================
   20 · REVEAL ON SCROLL
   Hidden only when JavaScript is present — the `js` class is set
   by an inline script in the head, so with scripting off nothing
   is ever hidden and the page reads exactly as it does now.
   Switched off entirely under prefers-reduced-motion.
   ============================================================ */
.js .sechead, .js .card, .js .prod, .js .ind, .js .svc,
.js .stage, .js .indp, .js .shot, .js .prose, .js .facts,
.js .contact-grid, .js .draftnote, .js .cta-row{
  opacity:0; transform:translateY(12px);
}
.js .is-in{
  opacity:1; transform:none;
  transition:opacity .55s ease, transform .55s cubic-bezier(.2,.7,.2,1);
}
@media (prefers-reduced-motion:reduce){
  .js .sechead, .js .card, .js .prod, .js .ind, .js .svc,
  .js .stage, .js .indp, .js .shot, .js .prose, .js .facts,
  .js .contact-grid, .js .draftnote, .js .cta-row{ opacity:1; transform:none; }
  .js .is-in{ transition:none; }
}

/* ============================================================
   21 · THE HOMEPAGE, REBUILT — 2026-08-18
   Measured before this pass: the first image on the homepage sat
   4,362px down, and the page ran six bands alternating between
   two pale colours with no dark or saturated moment anywhere.
   Every firm homepage read in a browser has both — Netguru is
   near-black throughout, Simform dark purple, Intellectsoft a
   blue gradient, Net Solutions a full accent band.

   Now: hero with the product alongside the headline, a strip, an
   blue conviction band, a compact model, a compact industries
   row, and the products on Ink — where light product shots have
   something to sit against. First image at roughly 240px.
   ============================================================ */

.hero--split{
  padding-block:clamp(48px, 5.5vw, 84px) clamp(32px, 4vw, 56px);
  background:radial-gradient(70% 110% at 88% -18%,
    color-mix(in srgb, var(--th-blue) 13%, transparent) 0%, transparent 58%);
}
.hero--split .hero-grid{
  display:grid; gap:clamp(28px, 4vw, 60px);
  grid-template-columns:minmax(0, .92fr) minmax(0, 1.08fr);
  align-items:center;
}
.hero--split h1{ font-size:clamp(2.3rem, 4.2vw, 3.6rem); max-width:15ch; margin-top:18px; }
.hero--split .hero-deck{ max-width:46ch; font-size:clamp(1rem, 1.25vw, 1.16rem); }
.hero--split .th-beamlock.lockup{ font-size:52px; }

/* The shot runs wider than its column and is clipped by the wrapper, so it
   reads as a window onto something larger without ever crossing the viewport. */
.hero-shot{
  border-radius:var(--th-radius);
  overflow:hidden;
  border:1px solid var(--hair);
  box-shadow:var(--shadow-up);
  background:var(--wash);
  aspect-ratio:16 / 11;
}
/* Zoomed and offset so the application fills the frame and its floating panels
   crop against the edges. Shown at natural size the app sits small inside its
   own canvas margins and reads as a picture of a picture. */
.hero-shot img{
  display:block; width:172%; max-width:none; height:auto;
  margin-left:-13.5%; margin-top:-7%;
}

/* ---- The compact model: six stages as a scannable list ---- */
.mini{
  list-style:none; margin:clamp(24px, 3vw, 40px) 0 0; padding:0;
  display:grid; grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:0 var(--gap); border-top:1px solid var(--hair);
}
.mini li{
  display:grid; grid-template-columns:38px 1fr; align-items:baseline;
  gap:4px var(--gap); padding-block:16px; border-bottom:1px solid var(--hair);
}
.mini__n{
  grid-row:span 2; font-size:var(--t-label); font-variation-settings:'wght' 600;
  letter-spacing:.1em; color:var(--accent); font-variant-numeric:tabular-nums;
}
.mini b{ font-size:var(--t-body); font-variation-settings:'wght' 600; }
.mini span:not(.mini__n){ font-size:var(--t-small); color:var(--muted); line-height:1.5; }
.textlink--big{ display:inline-block; margin-top:var(--gap); font-size:var(--t-body); }

/* ---- Industries as one scannable row ---- */
.indrow{
  display:grid; grid-template-columns:repeat(5, minmax(0, 1fr));
  margin-top:clamp(24px, 3vw, 40px); border-top:1px solid var(--hair);
}
.indrow a{
  display:block; text-decoration:none; color:inherit;
  padding:24px var(--gap) 24px 0; border-bottom:2px solid transparent;
  transition:border-color .18s ease, color .18s ease;
}
.indrow a + a{ padding-left:var(--gap); border-left:1px solid var(--hair); }
.indrow a:hover{ border-bottom-color:var(--th-blue); }
.indrow b{
  display:block; font-size:var(--t-sub);
  font-variation-settings:'wght' 600; letter-spacing:-.012em; line-height:1.2;
}

/* ---- The three product links under the featured one ---- */
.prodrow{
  display:grid; grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:var(--gap); margin-top:clamp(32px, 3.4vw, 48px);
}
.prodcard{
  --mk-ground:var(--surface);
  display:flex; flex-direction:column; align-items:flex-start; gap:12px;
  background:var(--surface); border:1px solid var(--hair);
  border-radius:var(--th-radius); padding:clamp(20px, 2vw, 24px);
  text-decoration:none; color:inherit;
  transition:border-color .18s ease, transform .18s cubic-bezier(.2,.7,.2,1);
}
.prodcard:hover{ border-color:var(--th-blue); transform:translateY(-3px); }
.prodcard b{ font-size:var(--t-body); font-variation-settings:'wght' 600; }
.prodcard span{ font-size:var(--t-small); color:var(--muted); line-height:1.55; }
.prodcard::after{ content:"→"; color:var(--accent); margin-top:auto; padding-top:6px; }

/* The Ink band's product figure needs a lighter frame than the Paper one */
.band--ink .shot img{ border-color:var(--th-line); }

@media (max-width:1020px){
  .mini{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .indrow{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
  .prodrow{ grid-template-columns:1fr; }
}
@media (max-width:900px){
  .hero--split .hero-grid{ grid-template-columns:1fr; }
  .hero--split h1{ max-width:none; }
  .hero-shot{ aspect-ratio:16 / 10; }
  .hero-shot img{ width:150%; margin-left:-11%; margin-top:-6%; }
}
@media (max-width:640px){
  .mini, .indrow{ grid-template-columns:1fr; }
  .indrow a + a{ padding-left:0; border-left:0; }
}

/* ============================================================
   22 · COLOUR — rewritten 2026-09-07 for brand v2
   The brand sheet names three colours for the website: black,
   grey and blue. The six-hue sector set the kinetic build ran on
   is therefore retired — not toned down, retired — and every
   --c-* token resolves to the ground-matched accent.

   The tokens and the .h-* classes stay, because the pages set
   them per concept and losing them would mean editing nine
   pages to say the same thing. They now carry one value.

   WHAT CARRIES CONCEPT NOW. Colour never was the only signifier:
   every sector and service already has its own drawn mark and a
   text label, which is what made the set safe for colour vision
   in the first place. Drawing and label do the whole job now.
   ============================================================ */
:root{
  --c-azure:var(--th-blue); --c-teal:var(--th-blue); --c-violet:var(--th-blue);
  --c-amber:var(--th-blue); --c-green:var(--th-blue); --c-rust:var(--th-blue);
}
.band--ink{
  --c-azure:var(--th-blue-lift); --c-teal:var(--th-blue-lift); --c-violet:var(--th-blue-lift);
  --c-amber:var(--th-blue-lift); --c-green:var(--th-blue-lift); --c-rust:var(--th-blue-lift);
}
/* On the blue band nothing else may compete, so every hue resolves to white */
.band--azure{
  --c-azure:#fff; --c-teal:#fff; --c-violet:#fff;
  --c-amber:#fff; --c-green:#fff; --c-rust:#fff;
}

.h-azure { --accent:var(--c-azure);  --mk-az:var(--c-azure);  }
.h-teal  { --accent:var(--c-teal);   --mk-az:var(--c-teal);   }
.h-violet{ --accent:var(--c-violet); --mk-az:var(--c-violet); }
.h-amber { --accent:var(--c-amber);  --mk-az:var(--c-amber);  }
.h-green { --accent:var(--c-green);  --mk-az:var(--c-green);  }
.h-rust  { --accent:var(--c-rust);   --mk-az:var(--c-rust);   }

/* The mark takes the hue; the dot inside it is already reading --mk-az. */
.tinted .mark{ color:var(--accent); }
.tinted:hover .mark{ color:var(--accent); }
.card.tinted:hover,
.prodcard.tinted:hover{ border-color:var(--accent); }
.indrow a.tinted:hover{ border-bottom-color:var(--accent); }
.mini li.tinted .mini__n{ color:var(--accent); }
.card.tinted .card__n,
.card.tinted .card__tag{ color:var(--accent); }
.svc.tinted .pricing,
.stage.tinted .stage__n span{ color:var(--accent); }
.ticks li::before{ border-color:var(--accent);
  background:radial-gradient(circle at 50% 50%, var(--accent) 0 3px, transparent 3px); }

/* Run keeps its lead-card outline. It reads --accent, which since the sector
   set was retired is the one accent on every band. */
.card--lead.tinted{ border-color:color-mix(in srgb, var(--accent) 52%, transparent); }

/* ---- the hero returns to one column ---- */
.hero--plain .hero-t{ max-width:none; }

/* ---- Colour on surfaces, not just on numerals.
   A hue on a 12.5px numeral is technically present and visually absent. The
   same hue at 5% across a whole card reads as a coloured card while leaving
   the text on effectively the same ground — every value below was re-measured
   against the tinted ground rather than the untinted one. ---- */
.card.tinted{
  background:color-mix(in srgb, var(--accent) 5%, var(--surface));
  border-color:color-mix(in srgb, var(--accent) 24%, var(--hair));
  --mk-ground:color-mix(in srgb, var(--accent) 5%, var(--surface));
}
.prodcard.tinted{
  background:color-mix(in srgb, var(--accent) 9%, var(--surface));
  border-color:color-mix(in srgb, var(--accent) 30%, var(--hair));
  --mk-ground:color-mix(in srgb, var(--accent) 9%, var(--surface));
}
.card.tinted:hover, .prodcard.tinted:hover{
  border-color:color-mix(in srgb, var(--accent) 62%, transparent);
}

/* A coloured cap on each column, which is the clearest signal at this size */
.indrow a.tinted{ border-top:3px solid var(--accent); margin-top:-1px; }
/* No side stripe. A >1px coloured left border on list items is the single most
   reliable "AI made this" tell, and here it was the third decorative system on
   the same six items, stacked on the numerals and a six-colour rainbow. The
   numeral carries the sequence; the hairline rule carries the grouping. */
.mini li.tinted{ padding-left:0; }

/* The stage numerals carry the hue at a size where it registers. The industries
   row had these too until its numbering was dropped as decorative. */
.mini__n{ font-size:var(--t-small); letter-spacing:.06em; }

/* Detail pages: a coloured rule beside each stage and each industry */
/* Same removal as `.mini` — the stage numeral is the marker, not a stripe. */
.stage.tinted{ padding-left:0; }
.svc.tinted .mark{ color:var(--accent); }

/* ============================================================
   23 · NEGATIVE SPACE — 2026-08-18
   Measured before this pass: 54.9% of the homepage's vertical
   space was air, section padding was 115px, and the H1 sat 230px
   from the top of the document. Against the offsets recorded from
   the real firm homepages — Netguru puts its H1 at 381px, Net
   Solutions runs 244px between a section heading and the first
   card beneath it — that is tight everywhere at once.

   Everything below widens the same rhythm rather than adding air
   in one place: the band, the gap between a heading and what it
   introduces, the inside of a card, the height of a list row, and
   the leading inside a paragraph. Air added in only one of those
   reads as a gap; added across all of them it reads as space.
   ============================================================ */
:root{
  --gap:clamp(18px, 1.9vw, 28px);
  --sec:clamp(88px, 11vw, 168px);
}

/* ---- Heroes get the most, because the first screen sets the pace ---- */
.hero--plain{ padding-block:clamp(96px, 12vw, 196px) clamp(72px, 8vw, 128px); }
.pagehero{ padding-block:clamp(80px, 9vw, 148px) clamp(48px, 5.5vw, 84px); }
.hero--plain h1{ margin-top:24px; }
.hero--plain .hero-deck{ margin-top:calc(var(--gap) * 1.35); }
.hero .cta-row{ margin-top:calc(var(--gap) * 1.9); }

/* ---- A heading needs room before what it introduces ---- */
.sechead .label{ margin-bottom:calc(var(--gap) * 1.1); }
.sechead h2 + .deck, .sechead h1 + .deck{ margin-top:calc(var(--gap) * 1.15); }
.cards, .inds, .spec, .compare, .cases, .indrow, .mini, .ticks{
  margin-top:clamp(44px, 5.2vw, 80px);
}
.prod{ margin-top:clamp(52px, 6vw, 96px); }
.prod--alt{ margin-top:clamp(64px, 7.4vw, 120px); }
.prodrow{ margin-top:clamp(40px, 4.6vw, 72px); }
.facts, .contact-grid{ margin-top:clamp(36px, 4.2vw, 64px); }

/* ---- Inside the components ---- */
.card{ padding:clamp(24px, 2.9vw, 40px); gap:18px; }
.prodcard{ padding:clamp(24px, 2.6vw, 32px); gap:15px; }
.mini li{ padding-block:24px; }
.indrow a{ padding:32px var(--gap) 32px 0; }
.ticks li{ padding-block:14px; }
.spec__head, .spec__row{ padding-block:24px; }
.facts > div{ padding-block:24px; }
.stage{ gap:clamp(24px, 3.4vw, 56px); }
.stage__b p + p{ margin-top:calc(var(--gap) * 1.15); }
.svc, .indp{ gap:clamp(28px, 4vw, 64px); }

/* ---- Air inside the type, not only around it ---- */
body, p, li, dd{ line-height:1.68; }
.deck, .hero-deck, .lede{ line-height:1.58; max-width:58ch; }
.prose p + p{ margin-top:calc(var(--gap) * 1.15); }
.ticks li, .card p, .prodcard span{ line-height:1.6; }

/* ---- The footer gets the same treatment ---- */
.site-foot{ padding-block:clamp(64px, 7vw, 108px) 32px; }
.foot-grid{ gap:calc(var(--gap) * 1.4); }
.foot-legal{ margin-top:clamp(48px, 5.4vw, 80px); padding-top:28px; }

@media (max-width:640px){
  .indrow a{ padding:24px 0; }
  .card{ padding:24px; }
}

/* ============================================================
   24 · THE HOMEPAGE PASS — 2026-08-18
   Owner's rulings: the hero fills the viewport · a fourth
   engagement (Modernise) joins Build/Run/Augment, and the cards
   run four across on one row · digital
   forensics retired, leaving four industries · the three
   products each get their own zigzag section · the hero CTA
   pair removed.
   ============================================================ */

/* ---- The hero fills the first screen ----
   svh, not vh: on mobile the browser chrome collapses on scroll, and vh
   measures the tallest state, so a vh hero is cut off on arrival — which is
   the one moment the hero has to be whole. The header is sticky and sits
   above, so its height comes off the top. */
/* `section.hero--full`, not `.hero--full`: §2 sets the band padding as
   `section.band`, an element-plus-class selector that outspecifies a bare class
   no matter how late it is declared. Matching its shape is what makes this
   override actually land — the first attempt did not, and the hero stayed 83px
   past the fold while the stylesheet looked correct. */
/* `section.hero--full`, matching §2's `section.band` shape — see the note
   below. The hero is one screen of headline and nothing else. The four
   engagements used to be pinned to its bottom edge; that ate the height the
   hero had been given, so the headline was squeezed into whatever was left
   and the screen read as a hero plus a crammed footer rather than a hero.
   They now open the page below the fold, in their own band. */
section.hero--full{
  min-height:calc(100svh - var(--head-h, 62px));
  display:flex; align-items:center;
  /* .hero--plain's padding is sized for a band that ends where its content
     ends. Here the height is the screen and the centring supplies the air. */
  padding-block:clamp(24px, 3vw, 56px);
}
.hero--full .hero-stack{ width:min(100% - 2*var(--gap), 1180px); }

/* Short viewports — a laptop at 1440x720 with the chrome open, or a phone in
   landscape — get the hero's natural height instead of a squeezed screen. */
@media (max-height:600px){
  section.hero--full{ min-height:0; padding-block:clamp(32px, 5vw, 64px); }
}


/* ---- Four across, the full width of the row ----
   Explicit 4 x 1fr, not auto-fit: auto-fit would drop to three-plus-one at
   some widths. The base `.indrow` is still `repeat(5, 1fr)` from when there
   were five industries, so this override is what keeps the row full-width —
   without it four items sit in a five-column grid and the row stops 236px
   short of the right edge. */
.cards--row4{ grid-template-columns:repeat(4, minmax(0, 1fr)); }
.indrow--4{ grid-template-columns:repeat(4, minmax(0, 1fr)); }

/* Four cards in the width three used to have leaves less room for the measure,
   so the type steps down one notch rather than the padding collapsing. */
.cards--row4 .card{ padding:clamp(24px, 2.2vw, 32px); }
.cards--row4 .card p{ font-size:var(--t-small); }

@media (max-width:1080px){
  .cards--row4, .indrow--4{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .indrow--4 a:nth-child(odd){ padding-left:0; border-left:0; }
}
@media (max-width:620px){
  .cards--row4, .indrow--4{ grid-template-columns:1fr; }
  .indrow--4 a + a{ padding-left:0; border-left:0; border-top:1px solid var(--hair); }
}

/* ---- Three consecutive Ink bands read as one dark region ----
   Left alone they would stack two full section paddings between each product,
   which opens a gap wide enough to look like a mistake. Collapse the touching
   edges and keep the outer two. */
/* `section.` prefix required: §2 sets the band padding as `section.band`, an
   element-plus-class selector, so a bare `.band--ink-*` never wins however late
   it is declared. Without it these three bands each kept a full 158px top AND
   bottom, putting 316px of dead air between products that the comment above
   claims is collapsed. Measured, not assumed: section padding across the site
   was (158,158) on 51 of 52 sections. */
section.band--ink-open{ padding-bottom:clamp(28px, 3vw, 48px); }
section.band--ink-mid{ padding-block:clamp(28px, 3vw, 48px); }
section.band--ink-close{ padding-top:clamp(28px, 3vw, 48px); }

/* The first product follows a section head; the other two open their band, so
   they do not want the head's top margin. */
.band--ink-mid .prod, .band--ink-close .prod{ margin-top:0; }
.band--ink-close .textlink--big{ margin-top:clamp(32px, 3.6vw, 52px); display:inline-block; }

/* ============================================================
   25 · THE CRITIQUE PASS — 2026-08-18
   From the impeccable critique. Rulings taken: a CTA returns to
   the hero (34) · response times published (35) · industries go
   monochrome (36) · the blue band earns its emphasis through
   scale rather than centring (37). The products band was
   explicitly left alone.
   ============================================================ */

/* ---- 37 · The page's one change of pace ----
   Every band ran the same rhythm: label, 44px h2, deck, grid. The blue band
   used to break it by being centred, and centring was removed because it was
   the only block off the shared left edge. Emphasis now comes from scale, which
   costs nothing structurally: this heading steps up to the display size while
   staying on the same left edge as everything else.

   The container max-width is in rem, NOT ch. `ch` resolves against the
   container's own 16px while the heading inside it is 64px — the same inversion
   that made a standfirst 586px in one place and 631px in another (§24). Setting
   22ch here produced a ~200px column and wrapped this heading over six lines.
   The `ch` cap belongs on the h2, where the unit and the type size agree. */
.sechead--turn{ max-width:56rem; }          /* 896px — two lines at 64px */
.sechead--turn h2{
  font-size:var(--t-display);
  line-height:calc(0.98em + 0.42rem);
  letter-spacing:-.026em;
  font-variation-settings:'wght' 700;
  max-width:26ch;                            /* on the h2 itself, where ch is the right unit */
}
.sechead--turn .deck{ max-width:34rem; }

/* ---- 35 · Published response times ----
   A definition list, not cards: three short promises are a table of facts, and
   wrapping each in a card would be the reflex the register warns about. Reuses
   `.facts` from the about page so the pattern is the same one a reader has
   already met there. */
.facts--times{ margin-top:clamp(32px, 3.6vw, 52px); max-width:41.25rem; }
.facts--times dd{ font-variation-settings:'wght' 500; }
.band--wash .facts--times{ border-top-color:var(--hair); }

/* The hero CTA sits under the standfirst, on the same left edge. */
.hero--full .cta-row{ margin-top:clamp(24px, 2.6vw, 36px); }

/* ============================================================
   26 · DARK MODE — 2026-08-28
   Follows the system and nothing else. No toggle, no stored
   preference, no inline theme script: this site has no other
   state, and a switch would be the one thing on it that has to
   be remembered, plus a blocking script on twelve pages to stop
   the wrong theme flashing before first paint. The visitor has
   already told their OS what they want.

   The page is not one ground, it is four, and the alternation is
   the rhythm. Ink is ALREADY the dark contrast event, so simply
   darkening everything would flatten the ladder into one flat
   surface. Each band moves one step instead and the order of
   lightness is preserved: page, then wash, then the old ink band
   as a RAISED panel rather than a sunken one. The blue band keeps
   its colour in both themes — restated below, because the blanket
   `.band` rule here would otherwise paint over it, which is exactly
   what happened silently under the v1 theme.

   Inverting the ink band to Paper was the alternative. A light
   band on a dark page is a glare bomb, so it was not taken.
   ============================================================ */
@media (prefers-color-scheme: dark){
  :root{
    color-scheme: dark;

    --fg:        var(--th-paper);
    --muted:     var(--th-grey);
    --surface:   #141518;
    --hair:      var(--th-line);
    /* Not --th-blue-lift: that is solved against pure black and falls to
       4.31:1 on the lifted band. This is the lift raised until it clears AA
       on the LIGHTEST dark ground, which is where it has to survive. */
    --accent:    #6592CD;
    --ground:    #000000;

    --wash:      #0D0E10;
    --wash-hair: #202329;

    --shadow: none; --shadow-up: none;
  }

  body{
    background:#000000; color:var(--th-paper);
    --mk-az:var(--th-blue-lift); --mk-ground:#000000;
  }

  .band{ background:#000000; }

  /* `.band` and `.band--azure` are the same specificity, so the blanket rule
     above wins on order and the accent band went black in dark mode — the one
     loud band on the site, silently lost. It was lost in the v1 theme too;
     found and fixed 2026-09-07. The blue is 5.10:1 against white and needs no
     dark variant, so this is the light value restated, not a new one. */
  .band--azure{ background:var(--th-blue); --ground:var(--th-blue);
                --accent:#fff; --muted:#F2F6FC; }

  .band--wash{
    --ground:#0D0E10; --hair:#202329; --mk-ground:#0D0E10;
    background:#0D0E10;
  }

  /* The former dark band becomes the lifted one, keeping its job as the
     page's one contrast event without turning into a glare panel. */
  .band--ink{
    --fg:var(--th-paper); --muted:#A2AAB5; --surface:#262930;
    --hair:#343841; --accent:#6592CD; --ground:#1A1C21;
    --mk-az:#6592CD; --mk-ground:#1A1C21;
    background:#1A1C21; color:var(--th-paper);
  }

  .site-head{ background:color-mix(in srgb, #000000 88%, transparent); }

  /* The nav reaches past --muted straight to --th-grey-deep, which is the
     "secondary text on light" token. On the dark ground it measures 3.09:1
     and fails AA. Route it through --muted, which the block above has
     already re-pointed. */
  .site-nav a{ color:var(--muted); }

  /* One accent, one value, raised for the dark theme. The light-theme blue
     is 4.12:1 on black and the -lift value falls to 4.31:1 on the lifted
     band at #1A1C21, which is the LIGHTEST dark ground and therefore the one
     that has to be solved for. #6592CD measures 4.99:1 there, 6.31:1 on the
     wash and 6.55:1 on the page. Lightness moved; hue and saturation did not.
  */
  :root, .band, .band--wash, .band--ink{
    --c-azure:#6592CD; --c-teal:#6592CD; --c-violet:#6592CD;
    --c-amber:#6592CD; --c-green:#6592CD; --c-rust:#6592CD;
  }

  /* `tech` follows --fg and needs nothing here. The dot does: the core blue
     is 4.12:1 on black, which is marks-and-display only, and at 20px the dot
     is neither. */
  .th-logo{ --lm-dot:var(--th-blue-lift); }
  .th-wordmark--light .th-a{ color:var(--th-paper); }
  .th-wordmark .th-dot{ color:var(--th-blue-lift); }
}
