/* ============================================================
   DOTMATRIX DIAL-BACK — layered over sp-dotmatrix.css
   ------------------------------------------------------------
   NOT COMMITTED. Load this AFTER sp-dotmatrix.css on any themed page.
   Reverting = remove the <link> and the inline arming script.

   Principle (Wilfredo, 2026-07-22): the dot-matrix is a DESIGN ELEMENT,
   not the reading surface, and not a filter over the work.

     · sprocket feed margins   — gone
     · tractor feed banding    — gone, flat surface
     · below the header        — one light sheet, dark plates for the work
     · images                  — straight photos, no dot reveal (JS side)
     · display type            — leading that clears Doto's descender rows
     · document counters       — gone

   The header/hero of every page stays dark: it holds the photography and
   brackets the light below it. Footer stays dark to close the page.
   ============================================================ */

/* ============================================================
   1 — SURFACE
   ============================================================ */

/* no punched feed margins anywhere */
.theme-dotmatrix body::before,
.theme-dotmatrix body::after { display: none; }

/* flat: no 64px feed banding — every page, header or not */
.theme-dotmatrix body { background-image: none; }

/* The light sheet applies ONLY to pages that have a dark header to bracket
   it. Pages without one (404, /clients gate, /special-projects/motion) were
   authored dark, with their own page-scoped token blocks; lighting the body
   under them left dark ink on a dark design and light ink on a light sheet.
   No header → the page stays dark, and only the printer furniture goes. */
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) {
  background-color: #e6e9ed;      /* painted on body so it bleeds full width;
                                     .dm-doc is capped at 1320px and would
                                     otherwise leave dark strips either side */
}

/* with the bands gone, content no longer needs the printable-area floor
   that kept it clear of them (see --dm-edge in sp-dotmatrix.css) */
.theme-dotmatrix { --dm-edge: 24px; }

/* ---- light tokens for everything below the header ----
   ONE surface, not three. The stock light-sister palette steps
   #d8dbe1 → #e5e8ec → #ffffff, which reads as dark grey, light grey and
   white at once. These sit within ~4% of each other, so the light zone is
   a single sheet and the only real tonal contrast left is the dark plates.
   Pure white is never used. */
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) {
  color-scheme: light;

  --dm-bg:        #e6e9ed;
  --dm-board:     #e3e6ea;
  --dm-well:      #e1e4e9;
  --dm-panel:     #eef0f3;
  --dm-overlay:   #eef0f3;

  --dm-ink:       #17181c;
  --dm-body:      #40424a;
  --dm-body-2:    #2a2c32;
  /* Greys are set against the SHEET (#e6e9ed), which is the darker of the two
     light surfaces and therefore the binding constraint for dark ink. The
     light-sister values these came from were tuned for a different surface
     and landed at 2.0–3.4:1 here — they were failing on timeline dates, card
     kickers, prose h3s and audit card meta across the site.
     label/muted are text roles → 4.5:1. label-2 is a de-emphasised second
     line → 3.5:1. faint/numeral are decorative rules and numerals, never
     body text, so they stay light on purpose. */
  --dm-muted:     #676970;   /* was #6c6e76 — 4.18:1 */
  --dm-muted-2:   #676970;   /* was #7a7c84 — 3.42:1 */
  --dm-label:     #676970;   /* was #8a8c93 — 2.76:1 */
  --dm-label-2:   #787a81;   /* was #a2a4ab — 2.04:1 */
  --dm-faint:     #b6b8be;   /* hairlines and rules — never text */
  /* NOT decorative, despite the token name: --dm-numeral is the colour of
     .dm-section-num, the large "02 / 03 / 04" section numerals, which are
     real visible content. At #cbcdd3 they sat at 1.31:1 on the sheet and
     effectively vanished. They are deliberately quiet, and at 34-68px they
     are large text, so AA large (3:1) is the right bar, not 4.5. */
  --dm-numeral:   #83858b;   /* was #cbcdd3 — 1.31:1 → 3.03:1 */

  --dm-accent:      #2f6fe0;    /* deeper blue holds contrast on light */
  /* accent-2 is the "step away from accent" tone. On dark that means LIGHTER;
     on light it has to mean DARKER. The light-sister palette kept it light
     (#5a8ee8), which lands at 2.67:1 on this sheet — invisible for the
     behind-the-build annotation tags. Inverted here. */
  --dm-accent-2:    #1f4fa8;
  --dm-accent-line: #bcd0ee;

  --dm-line:   #dcdee3;
  --dm-line-2: #c9cbd1;
  --dm-btn:    #b6b8be;

  --dm-dot:    rgba(28,32,48,0.10);
  --dm-glow:   none;
  --dm-glow-2: none;

  color: var(--dm-ink);
}

/* ---- dark stages: header, featured plates, footer ----
   A directly-matching rule beats an inherited one, so these re-assert the
   dark palette for their own subtree and everything inside them (labels,
   copy, hairlines, accent) flips back automatically. */
.theme-dotmatrix .dm-hero,
.theme-dotmatrix .dm-page-hero,
.theme-dotmatrix .dm-featured,
.theme-dotmatrix .ds-hero,          /* /design-system letterhead band */
.theme-dotmatrix .eve-panel,        /* Eve's surface is dark on a light page */
.theme-dotmatrix .eve-launcher,
.theme-dotmatrix .site-footer {
  color-scheme: dark;

  --dm-bg:        #16171b;
  --dm-board:     #15161a;
  --dm-well:      #0c0d10;
  --dm-panel:     #23252e;
  --dm-overlay:   #121317;

  --dm-ink:       #f3f4f6;
  --dm-body:      #c7c9cf;
  --dm-body-2:    #e0e2e7;
  --dm-muted:     #9a9ca3;
  --dm-muted-2:   #8e9099;
  --dm-label:     #7c7e85;
  /* was #5a5c63 → 2.68:1, which is what the footer fine print ("A practice of
     Forge Ventures LLC.", the copyright line) rendered at on every page.
     Pre-existing from v3, not a v4 change, but it fails AA site-wide and it
     is one value. #7e8087 → 4.54:1. */
  --dm-label-2:   #7e8087;
  --dm-faint:     #4d4f55;
  --dm-numeral:   #3f4147;

  --dm-accent:      #67a0e8;
  --dm-accent-2:    #8fbcf2;
  --dm-accent-line: #2f4a6b;

  --dm-line:   #26272c;
  --dm-line-2: #40424b;
  --dm-btn:    #4d4f55;

  --dm-dot:    rgba(150,156,168,0.20);
  --dm-glow:   none;      /* the LED bloom went with the flat surface */
  --dm-glow-2: none;

}

/* The surface is applied separately from the tokens above, because Eve
   paints her own glass (var(--eve-glass) plus a backdrop-filter) and must
   keep it — she needs the dark INK, not a dark background. Her --eve-* set
   maps onto --dm-*, so on the light sheet her ink resolved to near-black on
   her own dark panel: "Privacy & data" in her footer measured 1.03:1. Same
   failure as the meters, the design system and the back-to-top arrow —
   a dark surface with a token-driven foreground. */
.theme-dotmatrix .dm-hero,
.theme-dotmatrix .dm-page-hero,
.theme-dotmatrix .dm-featured,
.theme-dotmatrix .ds-hero,
.theme-dotmatrix .site-footer {
  background-color: var(--dm-bg);
  color: var(--dm-ink);
}
.theme-dotmatrix .eve-panel,
.theme-dotmatrix .eve-launcher { color: var(--dm-ink); }

.theme-dotmatrix .dm-hero { background-color: #0e0f12; }
.theme-dotmatrix .dm-featured { background-color: var(--dm-panel); }

/* the design-system header paints its own tractor bands (design-system.css),
   separate from the body ones — clear those too */
.theme-dotmatrix .ds-hero {
  background-image: none;
  background-color: var(--dm-panel);
}

/* /design-system remaps --ds-* onto --dm-* on .ds-main. Custom properties
   resolve at the element that DECLARES them, so --ds-ink froze to .ds-main's
   light value and the dark header/stages inherited near-black ink on a dark
   panel — the headline was invisible. Re-declare the mapping inside each dark
   stage so it recomputes against that stage's own dark --dm-* values. */
.theme-dotmatrix .ds-hero,
.theme-dotmatrix .ds-stage {
  --ds-bg:     var(--dm-bg);
  --ds-ink:    var(--dm-ink);
  --ds-body:   var(--dm-body);
  --ds-muted:  var(--dm-muted);
  --ds-faint:  var(--dm-label);
  --ds-line:   var(--dm-line);
  --ds-line-2: var(--dm-line-2);
  --ds-panel:  var(--dm-panel);
  --ds-accent: var(--dm-accent);
}

/* full-bleed section tone zones: with one light surface there is nothing
   left for them to tint, so they only produced faint banding */
.theme-dotmatrix .dm-doc > section::before { display: none; }

/* ============================================================
   2 — DISPLAY TYPE
   Doto sits on a fixed dot grid, so a glyph fills its whole em box,
   descender rows included. Sub-1.0 leading doesn't close up optical air
   the way it does in a proportional face — it overlaps the rows outright
   (the "g" of "Engagements" landing on the "R" below it). Everything
   shipped under 1.0. Floor is 1.1 for anything that can wrap.
   Tracking goes slightly positive: adjacent dot grids need a gap between
   them or the last column of one letter reads as the first of the next.
   ============================================================ */
.theme-dotmatrix .dm-section-title,
.theme-dotmatrix .dm-abstract-h,
.theme-dotmatrix .dm-featured-h,
.theme-dotmatrix .dm-page-hero-h,
.theme-dotmatrix .dm-contact-h,
.theme-dotmatrix .ds-h1 {           /* /design-system, geometry-matched to dm-page-hero-h */
  line-height: 1.1;
  letter-spacing: 0.012em;
}
.theme-dotmatrix .dm-hero-h {
  line-height: 1.0;
  letter-spacing: 0.012em;
}
.theme-dotmatrix .dm-section-num { line-height: 1.0; }
.theme-dotmatrix .dm-abstract-h .dm-h-line { line-height: 1.1; }

/* ============================================================
   1b — AMBIENT WAVE STACKING (sp-ribbon.js)
   The canvas is fixed at z-index 0. Everything the visitor reads has to sit
   above it, so the page chrome is lifted to z-index 1. Without this the wave
   would paint over the content instead of behind it.
   ============================================================ */
/*
   ONLY in-flow content goes in this list. Anything already positioned is
   both above the canvas already and BROKEN by a position override:
     .nav          sticky, top 0, z-index 80   → relative kills the sticky
     .eve-launcher fixed, bottom-right          → relative drops her into flow
     .dm-totop     fixed, bottom-right          → same
   None of them need lifting; all of them outrank the canvas at z-index 0. */
.theme-dotmatrix main,
.theme-dotmatrix .site-footer {
  position: relative;
  z-index: 1;
}

/* ---- back-to-top on the light sheet ----
   The button hardcodes background: rgba(18,19,23,0.82) but takes its arrow
   from var(--dm-ink) — which flipped to near-black here, giving a near-black
   arrow on a near-black chip. Same failure as the LED meters: a fixed dark
   surface paired with a token-driven foreground.
   A light chip reads on the sheet AND stays legible over the dark footer it
   floats across at the bottom of the page. */
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .dm-totop {
  background: rgba(238, 240, 243, 0.94);
  color: #17181c;
  border-color: var(--dm-line-2);
}
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .dm-totop:hover {
  background: #ffffff;
  border-color: var(--dm-accent);
  color: var(--dm-accent);
}

/* ---- back-to-top vs the Eve launcher ----
   Both are pinned bottom-right, and Eve (136×52, z-index 2147483000) sat
   directly on top of the 46×46 button on every viewport — it was there but
   unclickable. Stack the button above her on pages where she exists.
   The offsets mirror her own clamp() so the pair stays in step, and the
   right edges align instead of sitting 8px apart. */
.theme-dotmatrix body:has(.eve-launcher) .dm-totop {
  right: clamp(16px, 3vw, 30px);
  bottom: calc(clamp(16px, 3vw, 30px) + 66px);   /* her 52px + 14px gap */
}

/* ============================================================
   2a — NAV
   The nav overlays the header but is a SIBLING of it, not a child, so it
   never picked up the dark-stage tokens — the light sheet gave it dark ink
   sitting on a dark hero photo, and the wordmark and Book a Time all but
   disappeared. Two states, explicitly:

     at rest, over a dark header  → dark-stage tokens, light ink
     scrolled, over the sheet     → light surface, dark ink

   Link colour also moves off --dm-muted. Over photography that token was
   never strong enough; nav links are the primary wayfinding on the page.
   ============================================================ */

/* --- at rest, sitting on a dark header --- */
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .nav:not(.is-scrolled) {
  --dm-ink:    #f3f4f6;
  --dm-muted:  #9a9ca3;
  --dm-accent: #67a0e8;
  --dm-bg:     #16171b;
}
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .nav:not(.is-scrolled) .nav-sp-wordmark {
  color: #f8f9fb;
}
/* full-strength ink, not muted — and a shadow so it survives a light patch
   of photography underneath */
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .nav:not(.is-scrolled) .nav-links a {
  color: #e8eaee;
  text-shadow: 0 1px 3px rgba(0,0,0,0.55);
}
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .nav:not(.is-scrolled) .nav-sp-wordmark {
  text-shadow: 0 1px 3px rgba(0,0,0,0.55);
}
html.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .nav:not(.is-scrolled) .nav-links a.nav-book {
  color: #f8f9fb;
  border-color: #8fbcf2;
}
.theme-dotmatrix body:has(.dm-hero, .dm-page-hero, .ds-hero) .nav:not(.is-scrolled) .nav-hamburger span {
  background: #f3f4f6;
}

/* --- scrolled, sitting on the light sheet --- */
.theme-dotmatrix .nav.is-scrolled {
  background: rgba(230,233,237,0.92);
  border-bottom-color: var(--dm-line-2);
}
.theme-dotmatrix .nav.is-scrolled .nav-sp-wordmark {
  color: #17181c;
  text-shadow: none;
}
.theme-dotmatrix .nav.is-scrolled .nav-links a {
  color: #3c3e46;          /* was --dm-muted; too weak for wayfinding */
  text-shadow: none;
}
.theme-dotmatrix .nav.is-scrolled .nav-links a:hover,
.theme-dotmatrix .nav.is-scrolled .nav-links a.active { color: #17181c; }
html.theme-dotmatrix .nav.is-scrolled .nav-links a.nav-book {
  color: #17181c;
  border-color: var(--dm-accent);
}
.theme-dotmatrix .nav.is-scrolled .nav-hamburger span { background: #17181c; }

/* ============================================================
   2b — LED METERS
   The fill was near-white dots (#eef3fb) plus a glow — engineered for a
   dark board and invisible on a light sheet. Accent dots instead (the
   light-sister theme already solved this), on a tinted track so empty
   vs filled reads at a glance, and a denser duty cycle (50% vs 31%)
   because a sparse dot row disappears at small sizes on light.
   ============================================================ */
.theme-dotmatrix .dm-meter-track {
  background: #dcdfe5;
  border-color: var(--dm-line-2);
}
.theme-dotmatrix .dm-meter-fill {
  background: repeating-linear-gradient(90deg,
    var(--dm-accent) 0 3.5px, transparent 3.5px 7px);
  box-shadow: none;
}
/* dark stages keep a track that reads against their own surface */
.theme-dotmatrix .dm-hero .dm-meter-track,
.theme-dotmatrix .dm-featured .dm-meter-track {
  background: rgba(255,255,255,0.05);
}

/* ============================================================
   2c — PAGE HEADER SMALL COPY
   Two components were doing the same job: .dm-page-hero-desc (sentence
   case, 14.5px — services + audits) and .dm-page-meta (uppercase 11px at
   0.14em — the other seven pages). The uppercase version is the harder
   read, and its source copy is ALREADY sentence case; it was only being
   capitalised by text-transform. So .dm-page-meta adopts the readable
   treatment and the existing copy reads as written. Structure — the
   stacked lines, the rule above them — is untouched.
   ============================================================ */
.theme-dotmatrix .dm-page-meta {
  font-size: 14.5px;
  line-height: 1.68;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--dm-body);
  /* 60ch, not 56 — "Analytics · Accessibility · Discoverability · Performance"
     is exactly 56 characters, so a 56ch measure dropped "Performance" onto a
     line of its own. Still inside the ~58ch body-copy target. */
  max-width: 60ch;
  text-wrap: pretty;   /* no orphans when it does wrap, e.g. on a phone */
}
.theme-dotmatrix .dm-page-meta > * { margin-bottom: 2px; }

/* ============================================================
   3 — DOCUMENT COUNTERS — dropped
   ============================================================ */
.theme-dotmatrix .dm-section-index,   /* "INDEX 03 / 04" */
.theme-dotmatrix .dm-abstract-tag,    /* "ABSTRACT — 01"  */
.theme-dotmatrix .dm-hero-index {     /* "01 / 11"        */
  display: none;
}

/* ============================================================
   4 — HEADLINE FOUC
   The bloom was armed by JS on DOMContentLoaded, i.e. AFTER the browser
   had already painted the headline — a visible flash of "AI-native.
   Design-led." on every load. html.dm-armed is set by an inline <head>
   script so it is hidden before the first paint instead of after it.
   Scoped so that with JS off nothing is ever hidden; the inline script
   drops the class after 3s as a failsafe (the keyframes use fill both,
   so an animation that already ran is unaffected).
   ============================================================ */
html.dm-armed .dm-abstract-h .dm-h-line { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  html.dm-armed .dm-abstract-h .dm-h-line { opacity: 1; }
}

/* ============================================================
   5 — LOADER
   Real text plus a progress hairline tied to the actual page load. No
   canvas, so there is nothing to misrender at any size or on any
   font-load timing. Behaviour lives in sp-figure-matrix.js.
   ============================================================ */
.dm-intro--simple { display: block; }
.dm-intro--simple,
.dm-intro { background-image: none; }
.dm-intro::before,
.dm-intro::after { display: none; }

.dm-intro--simple .dm-intro-job {
  top: 50%;
  transform: translateY(-50%);
  left: 50%;
  margin-left: -140px;
  width: 280px;
}
.dm-intro-bar {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: 48px 0 0 -140px;   /* clears the 3-line job ticket above it */
  width: 280px;
  height: 2px;
  background: var(--dm-line-2);
}
.dm-intro-bar i {
  display: block;
  width: 0;
  height: 100%;
  background: var(--dm-accent);
  transition: width 0.24s cubic-bezier(.3,.7,.3,1);
}
@media (max-width: 560px) {
  .dm-intro--simple .dm-intro-job { left: 24px; margin-left: 0; width: calc(100% - 48px); }
  .dm-intro-bar { left: 24px; margin-left: 0; width: calc(100% - 48px); }
}
