/* ==========================================================================
   KREATED V2 — THE THEME SYSTEM
   Loaded on every one of the 19 routes, immediately after that route's base
   stylesheet and before footer.css. This file is the single definition of
   every colour that changes between the site's light territory and its dark
   territory. Nothing else on the site is allowed to hard-code a ground, an
   ink or a stroke.

   ---------------------------------------------------------------------------
   WHERE THE COLOURS COME FROM
   ---------------------------------------------------------------------------
   Measured off the live BX Studio stylesheet on 2026-09-01 by reading the
   computed values of their own --a-light-theme--* and --a-dark-theme--*
   custom properties. These are their numbers, not an interpretation:

     token                 light        dark
     primary-background    #f3f3f3      #020c2e
     primary-text          #181818      #ffffff
     secondary-text        #4f4f4f      #d1d1d1
     gradient-textp        #243260      #ffffff
     gradient-texts        #3467e5      #a9b0b7
     card-background       #ffffff99    #040e3080
     card-hover            #ffffff      #040e30
     card-stroke           #e7e7e7      #11245a
     card-stroke-hover     #b9dcff      #3467e5
     tag-background        #ffffff99    #11245a
     tag-stroke            #e7e7e7      #133995

   ⚠ FINDING, 2026-09-01: the live BX homepage no longer runs the flip. The
   dark tokens above are still declared in their stylesheet, but nothing on
   the page invokes them — the body carries element-theme="1" (light) for its
   whole 16,516px, no element paints a dark ground, and the theme values do
   not move at any scroll position. The transition measured a week earlier
   (dark territory from roughly y=3200 to y=6000) is gone. So the colour
   ARCHITECTURE below is verified current; the transition BEHAVIOUR is
   reconstructed from the earlier measurement of the same site.

   ---------------------------------------------------------------------------
   WHY THE INK STEPS AND THE GROUND DOES NOT
   ---------------------------------------------------------------------------
   BX interpolates ink and ground simultaneously and their body copy passes
   through 1.35:1 on the way down. That is not a tuning mistake that could be
   dialled out — it is unavoidable. Contrast between two colours is a ratio of
   luminances, so if both the ink and the ground move continuously from
   (dark ink, light ground) to (light ink, dark ground), their luminances must
   cross. At the crossing the contrast is exactly 1:1 and the text is
   invisible. There is no curve that avoids it.

   So the ink cannot travel. It has to change sides in one frame.

   That gives the second constraint. With ink #141414 on one side and #FFFFFF
   on the other:

     dark ink is readable  (4.5:1) only while ground luminance >= 0.2161
     white ink is readable (4.5:1) only while ground luminance <= 0.1833

   Those two ranges do not touch. There is a DEAD BAND 0.0328 wide in which
   neither ink reaches AA. So the ground cannot smoothly cross it either — it
   has to jump the band on the same frame the ink changes sides.

   That is the whole mechanism:

     --p1   the light half of the journey    #F4F5FA -> #6B80C5   (L .888 -> .225)
     ----   INVERSION: one frame, ground and ink change together
     --p2   the dark half of the journey     #5F72B0 -> #020C2E   (L .175 -> .005)

   The jump is #6B80C5 -> #5F72B0. Twelve, fourteen and twenty-one units on
   the three channels. It happens across the entire viewport on a single
   frame, so there is no horizontal edge anywhere — this is nothing like the
   three spatial seam attempts that failed in August, which were bands drawn
   ACROSS the page. A whole-screen value change of that size, in one frame,
   during scroll, is not perceptible as an event. What is perceptible is the
   type inverting, which is the effect being bought.

   ⚠ Measured across the full journey, every stop clears AA: primary ink
   never drops below 4.65:1, secondary never below 4.65:1. The worst pair is
   at the inversion itself, by construction. 🚫 Do not move --bx-dusk or
   --bx-dawn without re-running sweep.py — they sit either side of the dead
   band and there is no slack.

   ---------------------------------------------------------------------------
   WHY SECONDARY INK CONVERGES
   ---------------------------------------------------------------------------
   BX's secondary #4f4f4f is 7.38:1 on their light ground but only 3.06:1 on
   the pre-inversion ground, and their #d1d1d1 is 12.56:1 on the night ground
   but 2.95:1 just after the inversion. Held constant, both fail.

   So secondary converges toward primary as the room dims and settles back
   out once night has fallen: #4F4F4F -> #141414, invert, #FFFFFF -> #D1D1D1.
   It reads as the quiet voice speaking up while the light goes, then
   relaxing. It is also the only assignment that holds AA at every stop.
   ========================================================================== */

:root{
  /* ---- the journey, written by atmosphere.js on the homepage --------------
     Every other route leaves these at their defaults, which is full night.
     🚫 Do not default these to 0. Eighteen routes never load atmosphere.js
     and a 0 default would render them as unstyled light pages. */
  --p:1;    /* 0 = full day, 1 = full night. Drives glow and atmosphere only. */
  --p1:1;   /* progress through the LIGHT half.  0 -> 1 */
  --p2:1;   /* progress through the DARK half.   0 -> 1 */
  --k:1;    /* 0 = dark ink on light ground, 1 = light ink on dark ground.
               Only ever exactly 0 or 1. Never a fraction. */

  /* ---- BX's measured endpoints ------------------------------------------- */
  --bx-day:#F4F5FA;    /* Kreated's paper, 230deg — BX's #f3f3f3 is neutral and
                          read grey beside the cobalt. Same luminance (.888). */
  --bx-dusk:#6B80C5;   /* L .2250 — last ground before the inversion */
  /* ⚠ L .1600, NOT .1750. At .1750 the bare ground gives white ink 4.65:1,
     which passes — but any translucent surface sitting ON that ground lifts it
     and eats the margin. --panel is white at 3%, and .case__obs measured
     4.46:1 through it at 768 in the frames just after the inversion. Taking
     the dawn ground three hundredths of luminance darker restores 4.72:1
     through the same panel, and the only cost is that the inversion step grows
     from [12,14,21] to [16,19,29] on the three channels. Still one frame,
     still whole-screen, still nothing anyone sees.
     🚫 The floor is L .18333: above that, white ink fails on the bare ground. */
  --bx-dawn:#5B6DA8;   /* L .1600 — first ground after the inversion */
  --bx-night:#020C2E;  /* BX --a-dark-theme--dark-primary-background, verbatim */

  --bx-ink-day:#141414;    /* BX #181818 taken 4 units darker: at #181818 the
                              pre-inversion pair measures 4.65:1 and I am not
                              shipping AA with two hundredths of headroom */
  --bx-ink-night:#FFFFFF;  /* BX dark-primary-text, verbatim */
  --bx-sec-day:#4F4F4F;    /* BX light-secondary-text, verbatim */
  --bx-sec-night:#D1D1D1;  /* BX dark-secondary-text, verbatim */

  /* BX's light accent #3467e5 measures 4.49:1 on their own light ground —
     one hundredth under AA for body-size text. Kreated's day accent is two
     steps deeper so it passes as a link, and it deepens further as the room
     dims. At night it becomes the cobalt lift, which is the identity blue. */
  --bx-acc-day:#2148D8;
  --bx-acc-dusk:#0A1240;   /* #16267A measured 3.47:1 as 11.5px text on the
                              dusk ground. The accent all but merges into the ink
                              at the darkest point of the light half, which is the
                              same convergence --ink-2 and --ink-3 make. */
  --bx-acc-night:#5B86FF;

  /* ---- the ground --------------------------------------------------------
     Two segments, selected by --k. Because --k is only ever 0 or 1 the outer
     mix resolves to exactly one segment, so this is not an approximation of a
     branch — it IS a branch, written in a way that keeps the whole system in
     one token. */
  --ground:color-mix(in srgb,
    color-mix(in srgb, var(--bx-day),  var(--bx-dusk)  calc(var(--p1) * 100%)),
    color-mix(in srgb, var(--bx-dawn), var(--bx-night) calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  /* ---- the inks ---------------------------------------------------------- */
  --ink-1:color-mix(in srgb, var(--bx-ink-day), var(--bx-ink-night) calc(var(--k) * 100%));

  --ink-2:color-mix(in srgb,
    color-mix(in srgb, var(--bx-sec-day), var(--bx-ink-day)   calc(var(--p1) * 100%)),
    color-mix(in srgb, #FFFFFF,           var(--bx-sec-night) calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  /* the third voice: labels, meta, captions. Same convergence, one step
     quieter at each end, and it stops short of the extremes so it never
     becomes the 3.1:1 grey that the August audit found on four routes. */
  --ink-3:color-mix(in srgb,
    color-mix(in srgb, #5E5E5E, #1A1A1A calc(var(--p1) * 100%)),
    color-mix(in srgb, #FFFFFF, #B9BFD4 calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  /* the quietest voice: legal lines, timestamps, "optional", the footer's
     small print. BX has no fourth token — its dark end is borrowed from their
     gradient-texts (#a9b0b7, 8.75:1 on the night ground), which is the tone
     they use for exactly this kind of text.

     ⚠ --ink-3 and --ink-4 resolve to the SAME colour at the dusk end and that
     is not an oversight. On a ground at L .2260 the entire readable range for
     dark ink is L 0 to L .0113 — about four steps of 8-bit grey. A four-voice
     ladder cannot survive there, so the voices converge at the darkest moment
     of the light half and separate again either side of it. The alternative
     was to keep them apart and let the two quietest fail. */
  --ink-4:color-mix(in srgb,
    color-mix(in srgb, #6B6B6B, #1A1A1A calc(var(--p1) * 100%)),
    color-mix(in srgb, #FFFFFF, #A9B0B7 calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  --accent:color-mix(in srgb,
    color-mix(in srgb, var(--bx-acc-day), var(--bx-acc-dusk)  calc(var(--p1) * 100%)),
    color-mix(in srgb, #FFFFFF,           var(--bx-acc-night) calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  /* ---- strokes and surfaces ----------------------------------------------
     BX's card-stroke pair (#e7e7e7 / #11245a) is 1.11:1 and 1.30:1 against
     its own ground. Those are decorative hairlines, not boundaries a reader
     has to find, and WCAG 1.4.11 does not apply to them. Where a stroke IS
     the only thing defining a control, --stroke-hi is used instead, which
     clears 3:1 on both sides. */
  --stroke:color-mix(in srgb,
    color-mix(in srgb, #E7E7E7, #5A6894 calc(var(--p1) * 100%)),
    color-mix(in srgb, #4C5E97, #11245A calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  --stroke-hi:color-mix(in srgb,
    color-mix(in srgb, #9CA3B5, #2B3560 calc(var(--p1) * 100%)),
    color-mix(in srgb, #C6CEE4, #7D88AE calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  --stroke-focus:color-mix(in srgb, var(--bx-acc-day), var(--bx-acc-night) calc(var(--k) * 100%));

  --surface:color-mix(in srgb,
    color-mix(in srgb, #FFFFFF, #7C90D0 calc(var(--p1) * 100%)),
    color-mix(in srgb, #6E80BC, #040E30 calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  --surface-hi:color-mix(in srgb,
    color-mix(in srgb, #FFFFFF, #8698D6 calc(var(--p1) * 100%)),
    color-mix(in srgb, #7A8AC4, #0A1740 calc(var(--p2) * 100%))
    calc(var(--k) * 100%));

  /* ---- the two solid controls -------------------------------------------
     A filled pill has to invert with the room or it stops being the loudest
     thing on the page. Day: cobalt fill, white ink. Night: white fill, navy
     ink. Both ends measured over 8:1. */
  --cta-fill:color-mix(in srgb, var(--bx-acc-day), #FFFFFF calc(var(--k) * 100%));
  --cta-ink:color-mix(in srgb, #FFFFFF, var(--bx-night) calc(var(--k) * 100%));
  --cta-fill-hover:color-mix(in srgb, #123AC4, #E4E9FA calc(var(--k) * 100%));
}

/* ⚠ ROUTES THAT BEGIN IN DAY — A SEPARATE BLOCK, AFTER :root CLOSES.
   🚨 THIS OVERRIDES FOUR VALUES AND NOTHING ELSE. It was first written by
   inserting a closing brace after --k above, which ended :root early and left
   every token below it — --ground, --ink-1..4, --accent, --stroke, --surface,
   the lot — scoped to .day-start. The eighteen routes that do not carry that
   class lost their entire palette and rendered as white pages with no blue.
   The comment inside :root warns about exactly that outcome; the mistake was
   structural, not a wrong value, so nothing looked wrong in the diff.
   🚫 Never put anything but the four journey variables in here, and never
   reopen this block above the end of :root.

   The class is set in the markup, not by script, so there is no flash of the
   wrong theme on first paint. atmosphere.js then writes inline custom
   properties on scroll and an inline style beats a class rule, so the journey
   takes over from here. Under prefers-reduced-motion the script returns early
   and the page simply stays in day: a complete, readable light page rather
   than a dark one the visitor never asked to travel into. */
:root.day-start{
  --p:0; --p1:0; --p2:0; --k:0;
}

/* ---- THE THREE LEGACY LITERALS, RE-POINTED FOR DAY -----------------------
   services.css predates the k-aware ink ladder and still declares three fixed
   colours for text: --white (#FFFFFF), --warm (#EDE8DE) and --gray (#888FA3).
   Fourteen /services/ routes read them and every one of those routes is night,
   so the literals are correct there and MUST NOT be changed at :root — doing
   so would re-tone all fourteen pages for the sake of two.

   Instead they are re-pointed only inside day territory, at the same three
   voices the rest of the system already uses. A page that opens in day gets
   dark ink from the identical `color:var(--white)` declaration that gives a
   night page white ink, so not one rule in services.css or leaf.css had to be
   touched.

   ⚠ Only `var(--white)` moves. The four places that write a literal `#fff` —
   the skip link, .head__cta, the mobile drawer CTA and .btn--cobalt — are ink
   sitting ON cobalt, not on the ground, and they stay white in both rooms.
   That distinction is why this works as a token swap at all.
   🚫 Do not add --cobalt here. It is a fill, not a voice, and #0A47F0 carries
   white text on either ground. */
:root.day-start{
  --white:var(--ink-1);   /* #141414 in day */
  --warm: var(--ink-2);   /* #4F4F4F     */
  --gray: var(--ink-3);   /* #5E5E5E     */
}

/* ⚠ The reduced-motion rule below the atmosphere sets .atmos{opacity:1} on the
   assumption that a still page is a night page. A statically-day route breaks
   that assumption: full-strength blue field over #F4F5FA paper. Day territory
   keeps the daylight opacity whether or not the reader has asked for stillness.
   The selector needs the same specificity as the media-query rule to win, and
   it has one more class than that rule does. */
@media (prefers-reduced-motion: reduce){
  :root.day-start .atmos{opacity:.20}
}

/* ---- THREE HARDCODED rgba() LITERALS, GIVEN A DAY VALUE ------------------
   services.css and leaf.css each carry a few colours written as literal rgba()
   rather than as tokens, from before the ink ladder existed. Three of them are
   text on the page ground, so they invert with the room and these two routes
   are the first light pages to read them:

     .row__no   rgba(237,232,222,.52)  ->  1.12:1 on paper  (the ledger numeral)
     .meta      rgba(136,143,163,.90)  ->  2.97:1           (the ledger's instruction)
     .prov      rgba(136,143,163,.92)  ->  2.97:1           (provenance under a claim)

   ⚠ THE NIGHT VALUES ARE NOT TOUCHED. .row__no in particular carries a ruling
   — Skyler, 2026-08-28 contrast pass: it is a decorative glyph, leave it
   unchanged. That ruling was made about the dark ground and still holds there,
   so this is scoped to day rather than rewritten in place. Each day value is
   the same construction the night value uses — the room's own ink at the same
   alpha — so the numeral stays exactly as quiet relative to its ground as it
   was, and .meta and .prov land on --ink-3, which is where every other line of
   their kind on the site already sits.
   🚫 Do not "simplify" these by editing services.css/leaf.css directly. That
   changes fourteen night routes to fix two day ones. */
:root.day-start .row__no{color:color-mix(in srgb, var(--ink-1) 52%, transparent)}
:root.day-start .meta,
:root.day-start .prov{color:var(--ink-3)}

/* ⚠ THE GROUND IS PAINTED ONCE, ON THE DOCUMENT.
   Not on body, and not per-section. Painting it on html means the colour also
   fills the overscroll area at both ends of the document, so a rubber-band
   scroll on macOS or iOS does not expose a white strip above the header or
   below the footer. Every section on the site is transparent and this is the
   only thing under them.
   🚫 Do not give any section its own background-color. That is what produced
   every one of the seams fixed in August. */
html{background:var(--ground)}
body{background:transparent;color:var(--ink-1)}

/* ==========================================================================
   THE ATMOSPHERE
   One fixed layer, behind everything, carrying the blue. It is fixed rather
   than scrolled so the light does not slide past the content — the room dims
   around the reader instead of the reader travelling through a painted band.

   The geometry is NOT BX's. Theirs is a pair of large soft ellipses anchored
   to section corners. This is a single low field plus a high corner wash,
   which is the relationship their colour has to their ground, at Kreated's
   proportions.
   🚫 No teal, no green cast, no cyan, no visible circle, no gradient
   rectangle. Every stop below reaches true zero inside the layer.
   ========================================================================== */
.atmos{
  position:fixed;inset:0;z-index:-1;pointer-events:none;
  /* the blue is nearly absent in full day and full strength at night — the
     light does not travel across the page, it comes UP as the ground goes
     down, which is why the transition reads as dusk rather than as a wipe */
  opacity:calc(.20 + var(--p) * .80);
  background:
    radial-gradient(64% 46% at 50% 104%,
      rgba(45,74,168,.34) 0%, rgba(45,74,168,.09) 44%, rgba(45,74,168,0) 76%),
    radial-gradient(80% 44% at 106% -6%,
      rgba(10,71,240,.18) 0%, rgba(10,71,240,.04) 44%, rgba(10,71,240,0) 74%),
    radial-gradient(70% 42% at -10% 34%,
      rgba(91,134,255,.13) 0%, rgba(91,134,255,0) 70%);
}
/* In day the same field would tint the paper violet, so on the light side it
   is both weaker and warmer-neutral. The mix is on --k, so it swaps on the
   same frame as everything else. */
.atmos{
  filter:saturate(calc(.55 + var(--k) * .45));
}

@media (prefers-reduced-motion: reduce){
  /* atmosphere.js returns early under reduced motion, so --p/--p1/--p2/--k
     keep their :root defaults and the homepage renders as full night with no
     movement. Nothing here needs to change; this block exists so the next
     person does not go looking for the missing branch. */
  .atmos{opacity:1}
}

/* ==========================================================================
   CLIENT INDEX — lives HERE, in theme.css, because it appears on BOTH the
   homepage and /work/, and those two load completely different stylesheets:
   index.html gets styles.css, /work/ gets services.css + leaf.css + work.css.
   theme.css and footer.css are the only two either page shares.
   🚫 Do not move these rules into styles.css or work.css — whichever page did
   not load that file would render the index unstyled. This has already caught
   three separate changes in this codebase.
   ========================================================================== */
/* ==========================================================================
   CLIENT INDEX — scannable rows with a hover preview, 2026-09-05.
   ⚠ CSS-ONLY. The preview shows on :hover and :focus-within with no script at
   all. 🚫 Do not add JS to follow the cursor — it buys very little and costs a
   listener on every row plus a keyboard path that has to be rebuilt by hand.
   ⚠ THE PREVIEW IS PURELY DECORATIVE. It is aria-hidden, pointer-events:none
   and absent on touch and on reduced motion. Every row is complete without it:
   the client, the industry and the destination are all in the link itself.
   🚫 Never move information INTO the preview — it would become unreachable for
   touch and keyboard users.
   ⚠ Sits on the night ground; ink comes from the k-aware scale.
   ========================================================================== */
.cidx{margin:clamp(26px,3.4vw,48px) 0 clamp(34px,4.5vw,64px)}
.cidx__head{
  display:grid;grid-template-columns:1fr auto;gap:16px;
  padding:0 clamp(2px,.6vw,10px) 14px;
  border-bottom:1px solid color-mix(in srgb,
    rgba(20,28,60,.18), rgba(255,255,255,.20) calc(var(--k) * 100%));
  font:600 11px/1 'General Sans',system-ui;
  letter-spacing:.20em;text-transform:uppercase;color:var(--ink-3);
}
.cidx__list{list-style:none;margin:0;padding:0}
.cidx__row{position:relative}

/* ⚠ NO LOGO COLUMN, and that is deliberate. The four marks run from a 15:1
   wordmark to a 1:1 monogram; in a compact row they rendered at 5px, 8px, 11px
   and 46px tall — unreadable at one end and oversized at the other. The
   homepage marquee only manages it with per-client --mark-w and max-height
   tuning, which is not worth carrying here. The client NAME is the identifier,
   the tag carries the category, and the hover preview shows the actual brand.
   🚫 Do not add logos back without per-row sizing; a half-scaled logo column
   reads as a bug, not as branding. */
.cidx__link{
  display:grid;grid-template-columns:auto 1fr auto auto;
  align-items:center;gap:clamp(16px,2vw,30px);
  padding:clamp(16px,1.7vw,22px) clamp(2px,.6vw,10px);
  border:0;border-bottom:1px solid color-mix(in srgb,
    rgba(20,28,60,.12), rgba(255,255,255,.13) calc(var(--k) * 100%));
  border-radius:0;margin:0;
  text-decoration:none;
  transition:border-color var(--t-hover,.18s ease);
}
.cidx__list li:last-child .cidx__link{border-bottom:0}
.cidx__link:hover{
  border-bottom-color:color-mix(in srgb,
    rgba(20,28,60,.34), rgba(255,255,255,.38) calc(var(--k) * 100%));
}
.cidx__link:focus-visible{
  border-color:color-mix(in srgb,
    rgba(20,28,60,.30), rgba(255,255,255,.34) calc(var(--k) * 100%));
  background:color-mix(in srgb,
    rgba(20,28,60,.03), rgba(255,255,255,.045) calc(var(--k) * 100%));
}
.cidx__link:focus-visible{outline:2px solid var(--cobalt-lift,#5B86FF);outline-offset:3px}

.cidx__name{
  font:500 clamp(16px,1.5vw,20px)/1.25 'General Sans',system-ui;
  letter-spacing:-.01em;color:var(--ink-1);
}
/* ⚠ QUIET TEXT, NOT A PILL. This was an uppercase monospace pill with a
   border, which read as a SaaS dashboard rather than as Kreated. The industry
   is a quiet fact sitting beside the name — it earns no chrome.
   🚫 Do not put the pill, the border or the monospace back. */
.cidx__tag{
  justify-self:end;white-space:nowrap;
  font:400 14.5px/1 'General Sans',system-ui;
  letter-spacing:.01em;color:var(--ink-3);
}
.cidx__go{
  font-size:15px;color:var(--ink-3);
  transition:transform var(--t-hover,.18s ease),color var(--t-hover,.18s ease);
}
.cidx__link:hover .cidx__go{transform:translateX(3px);color:var(--cobalt-lift,#5B86FF)}

/* ---- the mark tile ----------------------------------------------------
   ⚠ A FIXED SQUARE, and the mark is contained inside it — that is the whole
   trick the reference uses, and it is why its column looks even. An earlier
   attempt put the FULL wordmarks in a flat cell and they rendered at 5px and
   8px tall; a square tile with object-fit does the work instead.
   ⚠ WHITE MARKS, NO FILTER. The client marks are already white-on-transparent
   and the tile is a raised navy surface, so they sit on it as drawn.
   🚫 Do not add brightness(0) here: flattening the marks destroyed the internal
   detail of the ones that have any.
   ⚠ LEAK LOCATORS HAS NO SEPARABLE MARK — its dish overlaps the wordmark and
   every crop of it reads as a white blob. That row uses a typographic tile with
   the client's own initials instead. It is an index device, NOT a logo, and
   🚫 must never be presented as their brand mark. If they supply a real mark,
   swap it in and delete .cidx__mono. */
.cidx__tile{
  width:52px;height:52px;flex:none;
  display:grid;place-items:center;overflow:hidden;
  border-radius:11px;
  background:color-mix(in srgb,
    rgba(20,28,60,.05), rgba(255,255,255,.06) calc(var(--k) * 100%));
  border:0;
}
.cidx__tile img{
  /* ⚠ NO FILTER. Every tile is now the client's own favicon — full colour, as
     they designed it. An earlier version flattened marks with brightness(0),
     which turned Leak Locators' red dartboard into a featureless white disc.
     🚫 Do not reintroduce a filter here. */
  max-width:72%;max-height:72%;width:auto;height:auto;object-fit:contain;
}

/* ---- the preview ------------------------------------------------------ */
/* ⚠ ABOVE THE ROW, NOT ACROSS IT. Centred on the row the preview sat straight
   over that row's own industry tag — you lost the field you were comparing at
   the exact moment you asked to see more. It now floats clear of the hovered
   row entirely; covering NEIGHBOURING rows is fine and is how the reference
   behaves. The first row flips below, since above would be off-screen.
   🚫 Do not re-centre this vertically on the row. */
.cidx__prev{
  position:absolute;z-index:5;pointer-events:none;
  bottom:calc(100% - 4px);right:clamp(16px,4vw,64px);transform:scale(.96);
  width:min(400px,32vw);margin:0;
  border-radius:12px;overflow:hidden;
  border:1px solid rgba(255,255,255,.14);
  box-shadow:0 22px 60px rgba(2,12,46,.45);
  opacity:0;visibility:hidden;
  transition:opacity .22s ease,transform .22s ease,visibility 0s linear .22s;
}
.cidx__prev img{display:block;width:100%;height:auto}
.cidx__row:hover .cidx__prev,
.cidx__row:focus-within .cidx__prev{
  opacity:1;visibility:visible;transform:scale(1);
  transition:opacity .22s ease,transform .22s ease;
}
/* the first row has nothing above it to float over */
.cidx__row:first-child .cidx__prev{bottom:auto;top:calc(100% - 4px)}

/* ⚠ .sr-only lives in styles.css, which /work/ does NOT load — it loads
   services.css + leaf.css + work.css. Without this the index's heading rendered
   as visible text. 🚫 Do not assume a global utility class exists on this page. */
.cidx .sr-only{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);
  white-space:nowrap;border:0;
}

/* ⚠ No hover on touch, and the preview would sit under a thumb anyway. */
@media (hover:none),(pointer:coarse){ .cidx__prev{display:none} }
@media (prefers-reduced-motion:reduce){
  .cidx__prev{transition:opacity .01s linear;transform:none}
  .cidx__row:hover .cidx__prev,.cidx__row:focus-within .cidx__prev{transform:none}
  .cidx__link:hover .cidx__go{transform:none}
}
@media (max-width:900px){
  .cidx__head{display:none}
  .cidx__link{grid-template-columns:auto 1fr auto;gap:12px;padding:12px 14px}
  .cidx__tag{grid-column:2/-1;justify-self:start;margin-top:8px;font-size:10.5px}
  .cidx__go{grid-row:1;grid-column:3}
  .cidx__tile{width:44px;height:44px;border-radius:10px}
  .cidx__prev{display:none}
}

/* the concept flag, shared by both places the index appears */
.cidx__flag{
  display:inline-block;vertical-align:middle;margin-left:10px;
  padding:4px 8px;border-radius:5px;
  font:600 10px/1 'General Sans',system-ui;letter-spacing:.14em;
  text-transform:uppercase;white-space:nowrap;color:var(--ink-3);
  border:1px solid color-mix(in srgb,
    rgba(20,28,60,.22), rgba(255,255,255,.26) calc(var(--k) * 100%));
}

/* ⚠ VISIBLE on the homepage, hidden on /work/. On the homepage the index is a
   standalone section and needs its own label; on /work/ it already sits under
   "Every business we've launched" and a second heading would just repeat it.
   🚫 Do not delete the element on /work/ — it is the section's accessible name. */
.cidx__h{
  margin:0 0 clamp(16px,1.8vw,24px);
  font:600 11px/1 'General Sans',system-ui;
  letter-spacing:.20em;text-transform:uppercase;color:var(--ink-3);
}

/* ⚠ The column captions are redundant where the section is already headed
   "Clients" — the homepage would read CLIENTS / CLIENT / INDUSTRY. On /work/
   the captions stay, because the heading there is "Every business we've
   launched" and the columns still need naming. */
.cidx--home .cidx__head{display:none}
.cidx--home .cidx__list li:first-child .cidx__link{padding-top:0}

/* ==========================================================================
   TRUSTED BY — the compact client strip for leaf pages, 2026-09-06.
   BX carries a `section-trusted-by` logo row high on every service page and
   every market page, not only the homepage. A visitor arriving on a service
   page from search currently sees no client evidence above the fold.

   ⚠ THIS IS A NEW COMPONENT, NOT THE HOMEPAGE STRIP MOVED. The audit called
   reusing `.clients` the cheapest item on the list and that was wrong: its CSS
   is 26 rules scattered from line 740 to line 2056 of styles.css, including
   `.is-marquee` variants left over from a carousel that was removed in August
   and a late `@media` override. Extracting that safely is a bigger and riskier
   job than writing the fifteen lines below, and the homepage would still need
   every one of those rules afterwards. The homepage strip is untouched.

   ⚠ THE THREE MARKS ARE DIFFERENT SHAPES and cannot share one size. The widths
   below are the homepage's own `--mark-w` values scaled to this smaller row,
   kept in the same proportion to each other so the marks stay optically equal.
   🚫 Do not replace them with a single width — the LearnSmart mark is nearly
   square and the LLEC mark is a 15:1 rail; equal widths make one shout.

   ✅ RIGHTS APPROVED — DECISION 023, Skyler, 2026-09-06. The three client
   wordmarks are cleared for display on Kreated's own marketing site.
   🚫 WORDMARKS ONLY. Client photography (DECISION 014) is a separate asset
   class, is not on the site, and its rights are still unconfirmed.
   ========================================================================== */
.tby{padding:clamp(26px,3vw,40px) 0;border-bottom:1px solid var(--stroke)}
.tby__lab{
  margin:0 0 clamp(14px,1.6vw,20px);
  font:600 11px/1 'General Sans',system-ui;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-3);
}
.tby__list{
  list-style:none;margin:0;padding:0;
  display:flex;align-items:center;gap:clamp(26px,4.5vw,64px);flex-wrap:wrap;
}
.tby__item{display:flex;align-items:center}
.tby__item img{
  width:var(--w);height:auto;
  /* the one-ink treatment the site already uses: flatten to a single value,
     then invert with the room. In day territory --k is 0, so the marks are
     black on paper; at night invert(1) makes them white. */
  filter:brightness(0) invert(var(--k));
  opacity:.72;transition:opacity .2s ease;
}
.tby__link:hover img,.tby__link:focus-visible img{opacity:1}
.tby__link:focus-visible{outline:2px solid var(--stroke-focus);outline-offset:6px;border-radius:3px}
.tby__item--llec{--w:172px}
.tby__item--ls{--w:126px}
.tby__item--rr{--w:140px}
@media (max-width:760px){
  .tby__list{gap:24px 30px}
  .tby__item--llec{--w:132px}
  .tby__item--ls{--w:98px}
  .tby__item--rr{--w:108px}
}

/* ---- DAY VALUES FOR THE TWO BUILT-OUT SERVICE PAGES ----------------------
   /services/web-design/ and /services/answer-engine-optimization/ carry
   page-specific components written before day territory existed, and a sweep
   of all 35 routes flagged exactly these on paper:

     .spec__rl .spec__sl .spec__cap  rgba(136,143,163,.90)  ->  2.97:1
     .spec__live                     rgba(237,232,222,.85)  ->  1.12:1
     .aeo__ans                       #fff                   ->  1.00:1

   ⚠ ONLY THE SPEC RAIL AND THE ANSWER CHIP. groundwork.css sets a literal text
   colour in nineteen rules, and the other fourteen are INSIDE the device mockup
   — .gw__apptitle, .gw__step, .gwchrome__url and the rest sit on the mockup's
   own dark chrome, not on the page ground, so they are correct as they are and
   are deliberately absent from this block.
   🚫 Do not "finish the job" by adding the .gw__* rules here. That would put
   dark text on the mockup's dark surface and break a component that currently
   renders correctly in both rooms.

   .aeo__ans keeps its cobalt-tinted panel; only the ink moves, because at 14%
   that panel is nearly the paper colour in day and white-on-it is invisible. */
:root.day-start .spec__rl,
:root.day-start .spec__sl,
:root.day-start .spec__cap{color:var(--ink-3)}
:root.day-start .spec__live{color:var(--ink-2)}
:root.day-start .aeo__ans{color:var(--ink-1)}
/* the two the first pass missed, found by naming the elements rather than
   guessing at the rule: the rail labels are bare <span> inside .spec__rails,
   and the price qualifier is a bare <i> inside .price__item — neither has a
   class of its own, so neither matched a selector above. */
:root.day-start .spec__rails > span,
:root.day-start .price__item i{color:var(--ink-3)}

/* ---- THE PRICING LEDGER LABEL ------------------------------------------
   The pricing page's main section had no label of its own, which the eyebrow
   sweep found; this names it.

   ⚠ A "Start here" eyebrow was briefly added above the closing CTA on 26 pages
   here, copying bx.studio's `GET STARTED`. It was REMOVED on owner instruction,
   2026-09-06: above a heading that already reads "Start a Project" it said the
   same thing twice, which BX's does not — theirs sits above a sentence, not
   above an imperative. 🚫 Do not re-add it.

   The one thing kept from that pass is the tracking below: .final__h tracks at
   -.03em and .close__go was at -.02em, which at 56px is a visible difference in
   colour between the homepage close and every other one. */
.close__go{letter-spacing:-.03em}

.invest__lab{
  margin:0 0 clamp(18px,2vw,28px);
  font:600 11px/1 'General Sans',system-ui;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-3);
}

/* ==========================================================================
   THE BLUE — accent and the hover glow, 2026-09-06.
   Owner: "The white pages need some color, make some of the words glow with
   the Kreated blue, and when you hover over important words / clickable links,
   it glows blue as well."

   ⚠ THE COLOUR COMES FROM --accent, WHICH IS K-AWARE. In day it resolves to
   #2148D8, which measures AA on the paper ground; at night it becomes #5B86FF,
   the identity blue. So these rules are correct on Home and About after the
   inversion as well as on the 34 paper routes, and nothing here needs a second
   value written by hand.
   🚫 Do not hardcode #2148D8 in this block. The two routes that still travel
   would then carry a day accent on a night ground at 2.3:1.

   ⚠ GLOW IS A SHADOW, NEVER A COLOUR CHANGE ON ITS OWN. The glyph keeps a solid
   --accent fill and the halo sits behind it, so measured contrast is unchanged
   by the effect — a glow built by lightening the text would have quietly failed
   the sweep while looking fine to me.
   ========================================================================== */
:root{
  /* one halo, defined once. 34% is the point where it reads as light coming
     off the word rather than as a blur or a printing error. */
  --glow: 0 0 18px color-mix(in srgb, transparent, var(--accent) 34%);
  --glow-soft: 0 0 12px color-mix(in srgb, transparent, var(--accent) 24%);
}

/* ---- 1. THE WORDS THAT CARRY EMPHASIS ----------------------------------
   Selective, not everything bold. The serif <em> inside a heading is already
   the site's designed emphasis point and was rendering in plain ink on the
   light pages; the hero keys are the three words the homepage is built around.
   🚫 Do not extend this to .prose b. That bold is a whole lead SENTENCE, and
   a blue sentence is a banner, not an emphasis. */
.h2 em,.sec__h em,.foot__h em,.hero__line em,.wkall__head em{
  color:var(--accent);text-shadow:var(--glow-soft);
}
.hero__key{color:var(--accent);text-shadow:var(--glow-soft)}

/* The heading <em> needs its serif treatment here too. styles.css carries it
   for the homepage, but the 34 leaf routes never load that file, so an <em> in
   a leaf heading was rendering as plain italic sans. */
.sec__h em,.wkall__head em{
  font-family:'Cormorant Garamond',Georgia,serif;
  font-style:italic;font-weight:500;font-size:1.14em;letter-spacing:-.01em;
}

/* ---- 1b. THE BOLD LEAD-IN, WHICH IS THE REAL COLOUR ON A PROSE PAGE -----
   A service page's body is two different kinds of bold and they must not look
   the same:

     <p><b>Whole sentence stating what the service is.</b></p>        the LEAD
     <p><b class="lin">The Google Business Profile.</b> Then the detail…</p>
                                                                   a LEAD-IN

   The lead is a paragraph wearing bold; colouring it blue makes a banner. A
   lead-in is a label naming the thing the paragraph describes — three or four
   words — and that is exactly the "some of the words" this was asked for.

   ⚠ THE CLASS IS NOT LAZINESS, IT IS THE ONLY WAY. The first attempt used
   `p > b:first-child:not(:only-child)` and silently matched almost nothing:
   :only-child counts ELEMENT children, and `<p><b>Label.</b> trailing text</p>`
   has exactly one element child, so every lead-in was excluded along with every
   lead. A trailing text node is invisible to a selector. The distinction is
   semantic anyway — label versus sentence — so it is marked in the markup.
   🚫 Do not "simplify" this back to a structural selector. */
.prose b.lin,.cs__col b.lin,.excl b.lin,.who b.lin,.steps b.lin,.lgrid b.lin{
  color:var(--accent);text-shadow:var(--glow-soft);
}
/* ---- 2. EVERY CLICKABLE THING, ON HOVER AND ON FOCUS -------------------
   ⚠ :focus-visible carries the identical treatment. A hover-only glow is a
   state a keyboard user never sees, and these are the same controls. */
.ilink,.tlink,.faqs__a a,.prose a,.cs__col a,.close__alt,.next a,
.cs__link,.close__go,.head__nav a,.cidx__name,.foot__cols a,.revs__all,
.faqs summary,.crumb a,.tby__link,.cs__live{
  transition:color .22s ease, text-shadow .22s ease;
}
.ilink:hover,.ilink:focus-visible,
.tlink:hover,.tlink:focus-visible,
.faqs__a a:hover,.faqs__a a:focus-visible,
.prose a:hover,.prose a:focus-visible,
.cs__col a:hover,.cs__col a:focus-visible,
.close__alt:hover,.close__alt:focus-visible,
.next a:hover,.next a:focus-visible,
.close__go:hover,.close__go:focus-visible,
.head__nav a:hover,.head__nav a:focus-visible,
.foot__cols a:hover,.foot__cols a:focus-visible,
.revs__all:hover,.revs__all:focus-visible,
.crumb a:hover,.crumb a:focus-visible,
.cs__live:hover,.cs__live:focus-visible{
  color:var(--accent);
}
/* the card title and the client-index row are hovered from the whole card or
   row, not from the text itself, so they hang off the parent's :hover */
.cs:hover .cs__link,.cs__link:focus-visible{color:var(--accent)}
.cidx__link:hover .cidx__name,.cidx__link:focus-visible .cidx__name{
  color:var(--accent);
}
/* a FAQ question is a control; it should answer to the pointer like one */
.faqs summary:hover,.faqs summary:focus-visible{color:var(--accent)}
/* the trusted-by marks are one-ink images, so their "glow" is a drop-shadow */
.tby__link:hover img,.tby__link:focus-visible img{
  filter:brightness(0) invert(var(--k));opacity:1;
}

@media (prefers-reduced-motion:reduce){
  .ilink,.tlink,.faqs__a a,.prose a,.cs__col a,.close__alt,.next a,
  .cs__link,.close__go,.head__nav a,.cidx__name,.foot__cols a,.revs__all,
  .faqs summary,.crumb a,.tby__link,.cs__live{transition:none}
}

/* ---- 2b. EVERYTHING ELSE THAT IS CLICKABLE -----------------------------
   The first pass covered prose links, nav, cards and the closing CTA, and
   missed the row components — which is what a reader on /services/ hovers
   first. Enumerating every <a>, <summary> and <button> inside <main> found
   these still inert.

   ⚠ FILLED BUTTONS ARE DELIBERATELY EXCLUDED FROM THE TEXT GLOW and given a
   halo around the button instead. .btn--cobalt is white text on cobalt; a blue
   text-shadow behind white text on a blue fill is invisible at best and muddy
   at worst. The glow belongs outside the shape, not behind the glyph.
   🚫 Do not add .btn--cobalt, .btn--solid or .head__cta to the text-shadow
   list. They already invert on hover; this only adds the halo.

   ⚠ Row components glow on the NAME, not on the whole row. .svc__row contains
   a number, a name and an arrow; lighting all three makes the row look selected
   rather than hovered.
   🚫 .row__a — the /services/ ledger — is deliberately NOT here. It was, and it
   was wrong: hovering a collapsed row opens it, so the glow flashed for about a
   tenth of a second and then the name faded to opacity 0 as the panel expanded.
   A highlight you only see while it is disappearing is a stutter, not feedback.
   Reverted on owner instruction 2026-09-06; the ledger keeps its own quiet
   hover from services.css and the expanded title carries the emphasis. */
.svc__row .svc__t,.svc__row .svc__n,
.fit__link,.hero__proof,.svc__more,.rev__case,.offer__cta,.offer__see,
.btn--quiet,.btn--ghost,.btn--line,.pswitch__tab,.g__btn,
.prose summary,.faqs summary,details > summary{
  transition:color .22s ease, text-shadow .22s ease;
}
.svc__row:hover .svc__t,.svc__row:focus-visible .svc__t,
.fit__link:hover,.fit__link:focus-visible,
.hero__proof:hover,.hero__proof:focus-visible,
.svc__more:hover,.svc__more:focus-visible,
.rev__case:hover,.rev__case:focus-visible,
.offer__see:hover,.offer__see:focus-visible,
.btn--quiet:hover,.btn--quiet:focus-visible,
.btn--ghost:hover,.btn--ghost:focus-visible,
.btn--line:hover,.btn--line:focus-visible,
.pswitch__tab:hover,.pswitch__tab:focus-visible,
.g__btn:hover,.g__btn:focus-visible,
details > summary:hover,details > summary:focus-visible,
main a:not([class]):hover,main a:not([class]):focus-visible{
  color:var(--accent);
}
/* the filled controls */
.btn--cobalt,.btn--solid,.head__cta,.offer__cta{transition:box-shadow .22s ease, background-color .2s ease}
/* the client marks on the homepage strip, same treatment as the trusted-by row */
.client:hover .client__logo,.client:focus-visible .client__logo{
  filter:brightness(0) invert(var(--k));opacity:1;
}
@media (prefers-reduced-motion:reduce){
  .svc__row .svc__t,.fit__link,.hero__proof,.svc__more,
  .rev__case,.offer__cta,.offer__see,.btn--quiet,.btn--ghost,.btn--line,
  .pswitch__tab,.g__btn,details > summary,
  .btn--cobalt,.btn--solid,.head__cta{transition:none}
}

/* ---- THE PRICING ROOM, MADE UNIFORM ------------------------------------
   styles.css gives .invest an edge-to-edge warm-paper room (#F2F0EA) — "the
   same paper stock the audit sheet and scope document are printed on". That
   was a deliberate tonal break when the rest of the page was navy: warm paper
   against a dark room reads as a considered shift.

   Now that the whole route is cool paper (#F4F5FA), the warm room stops being
   a break and becomes a mismatched off-white band two thirds of the way down
   the page. Owner call, 2026-09-06: the page should be one ground.

   ⚠ Only --room moves. --ink-on-room is #020C2E, the site's own navy, which is
   correct and high-contrast on the cool paper and is read by a dozen rules in
   pricing.css. --room-deep is untouched because nothing consumes it.
   🚫 Do not delete the room tokens from styles.css. The homepage sets
   --room:transparent for its own section and the same block is shared. */
/* ⚠ --room IS ALSO AN INK, WHICH IS WHY THIS IS NOT `transparent`. The first
   version of this rule set --room:transparent to let the page ground through,
   and that worked for the background — but styles.css also has
   `.offer__cta--dark{background:var(--ink-on-room); color:var(--room)}`: a navy
   button whose LABEL is the room colour, so the type matches the paper it sits
   on. Transparent made "Start a Project" invisible on fourteen buttons.
   Aliasing --room to the page ground gives both: the section paints the same
   colour as the page, and the button label is still paper on navy. */
:root.day-start .invest{--room:var(--ground)}

/* ---- THE EXPANDED SERVICE TITLE ----------------------------------------
   Owner, 2026-09-06: "only have the name turn blue+glow when it expands", and
   then "for all the services". Both halves of that instruction matter — the
   hover glow on the collapsed row was reverted above, and this is where the
   emphasis actually goes.

   .row__title lives inside .row__panel, which only opens on .row.is-on, so
   styling the element directly reaches all six services and needs no is-on
   qualifier. It took --white, which the day remap turns into dark ink; the
   accent replaces it in both rooms because --accent is k-aware.

   ⚠ The halo is wider and weaker than --glow. That token was tuned for 14-20px
   body links; at the 40-96px display scale these titles run, the same 18px blur
   sits inside the letterforms and reads as a print registration error rather
   than as light. Scaling the blur with the type and dropping the alpha keeps it
   reading as a glow at every size in the clamp.
   🚫 Do not reuse --glow here, and do not add this to .row__name — that is the
   collapsed label, and lighting it is the stutter that was just removed. */
.row__title{
  /* ⚠ A DEEPER BLUE THAN THE REST OF THE ACCENT, owner call 2026-09-06. At
     40-96px the plain accent is a lot of saturated blue at once and reads
     closer to a link than to a title. Mixing a third of the way toward the
     night navy keeps the same hue and drops the value, which is what "darker"
     wants — a deeper ink, not a duller one.
     ⚠ Written on --k so it is still correct if this page is ever given the
     journey: in day it resolves to the deeper mix, at night it falls back to
     the plain accent, because mixing toward navy ON navy would sink it into
     the ground. /services/ is a paper route today, so only the first half is
     ever painted — the second half is there so the rule cannot rot.
     🚫 NO GLOW HERE, AND IT CANNOT BE ADDED BACK. A text-shadow was tried and
     produced a soft haze that ended in a hard vertical line down the left of
     the title. The shadow itself was fine — the cause is .row__inner, which
     carries overflow:hidden so the expanding panel can animate its height. A
     52px halo spreads well past the glyphs, hits that clip and is cut off
     square, so a glow reads as a grey rectangle with a visible edge.
     Anything blurred inside this panel will do the same thing. The colour
     carries the emphasis on its own. */
  color:color-mix(in srgb,
    color-mix(in srgb, var(--accent), var(--bx-night) 34%),
    var(--accent) calc(var(--k) * 100%));
}

/* ==========================================================================
   THE GLISTEN — one sweep of light, left to right, 2026-09-06.
   Replaces the hover glow everywhere. Owner: "when you hover, it should just
   glisten one time from left to right."

   HOW IT WORKS. The text is painted by a gradient instead of a flat fill:
   currentColor across almost the whole width, with one narrow lighter band in
   it. background-clip:text clips that gradient to the glyphs, and a keyframe
   slides the gradient once so the band travels across the word. One pass per
   hover, because a CSS animation restarts every time the state is entered —
   that is what makes it glisten rather than pulse.

   ⚠ THE COLOUR IS NOT LOST, WHICH IS THE WHOLE TRICK. `color` is still set and
   still computes to --accent, so every contrast measurement and every tool that
   reads the cascade sees the real value; -webkit-text-fill-color only changes
   what is PAINTED, and what is painted is currentColor everywhere except the
   moving band. Text never becomes lighter than its declared colour for more
   than the width of that band.
   🚫 Do not "simplify" this by setting color:transparent. That is the version
   that looks identical and reports 1:1 to every checker.

   ⚠ THE @supports GUARD IS LOad-BEARING. -webkit-text-fill-color:transparent
   is honoured by browsers that do NOT support background-clip:text, and the
   result there is invisible text. The guard means such a browser gets a plain
   colour change and nothing else, which is a fine hover state.

   ⚠ Filled buttons are NOT in this list. Their label is white on cobalt, so a
   lighter band inside white type is invisible; they sweep a sheen across the
   BUTTON instead — see .btn--cobalt below.
   ========================================================================== */
@keyframes k-glisten{
  /* 100% -> 0% slides the oversized gradient rightward across the element, so
     the light band travels LEFT TO RIGHT. Verified rather than reasoned: frames
     captured at 0.18s and 0.26s put the band at "art a" then at "ject" of
     "Start a Project", and it has left the word by 0.34s.
     ⚠ TIMING IS linear ON PURPOSE. The first version used an ease that
     front-loads the travel, and because the band only occupies the middle third
     of the gradient it crossed the whole word in about 0.16s of a 0.62s
     animation — a flick rather than a glisten. At a constant rate the sweep
     reads as one continuous movement. */
  from{background-position:100% 0}
  to  {background-position:0% 0}
}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .ilink:hover,.ilink:focus-visible,
  .tlink:hover,.tlink:focus-visible,
  .faqs__a a:hover,.faqs__a a:focus-visible,
  .prose a:hover,.prose a:focus-visible,
  .cs__col a:hover,.cs__col a:focus-visible,
  .close__alt:hover,.close__alt:focus-visible,
  .next a:hover,.next a:focus-visible,
  .close__go:hover,.close__go:focus-visible,
  .head__nav a:hover,.head__nav a:focus-visible,
  .foot__cols a:hover,.foot__cols a:focus-visible,
  .revs__all:hover,.revs__all:focus-visible,
  .crumb a:hover,.crumb a:focus-visible,
  .cs__live:hover,.cs__live:focus-visible,
  .cs:hover .cs__link,.cs__link:focus-visible,
  .cidx__link:hover .cidx__name,.cidx__link:focus-visible .cidx__name,
  .faqs summary:hover,.faqs summary:focus-visible,
  .svc__row:hover .svc__t,.svc__row:focus-visible .svc__t,
  .fit__link:hover,.fit__link:focus-visible,
  .hero__proof:hover,.hero__proof:focus-visible,
  .svc__more:hover,.svc__more:focus-visible,
  .rev__case:hover,.rev__case:focus-visible,
  .offer__see:hover,.offer__see:focus-visible,
  .btn--quiet:hover,.btn--quiet:focus-visible,
  .btn--ghost:hover,.btn--ghost:focus-visible,
  .btn--line:hover,.btn--line:focus-visible,
  .pswitch__tab:hover,.pswitch__tab:focus-visible,
  .g__btn:hover,.g__btn:focus-visible,
  details > summary:hover,details > summary:focus-visible,
  main a:not([class]):hover,main a:not([class]):focus-visible{
    background-image:linear-gradient(100deg,
      currentColor 0%, currentColor 42%,
      color-mix(in srgb, currentColor, #FFFFFF 62%) 50%,
      currentColor 58%, currentColor 100%);
    background-size:300% 100%;
    background-repeat:no-repeat;
    -webkit-background-clip:text;
    background-clip:text;
    -webkit-text-fill-color:transparent;
    animation:k-glisten .72s linear 1;
  }
}

/* The filled controls sweep a sheen across the button, not through the label.
   ⚠ .btn--cobalt already uses ::before for its own hover fill, so this hangs
   off ::after, and the button needs a stacking context or the sheen paints
   over the text. */
.btn--cobalt,.btn--solid,.head__cta,.offer__cta:not(.offer__cta--text){
  position:relative;overflow:hidden;isolation:isolate;
}
.btn--cobalt::after,.btn--solid::after,.head__cta::after,
.offer__cta:not(.offer__cta--text)::after{
  content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:0;
  background:linear-gradient(100deg,
    transparent 0%, transparent 38%,
    rgba(255,255,255,.34) 50%,
    transparent 62%, transparent 100%);
  background-size:300% 100%;background-repeat:no-repeat;
}
.btn--cobalt:hover::after,.btn--cobalt:focus-visible::after,
.btn--solid:hover::after,.btn--solid:focus-visible::after,
.head__cta:hover::after,.head__cta:focus-visible::after,
.offer__cta:not(.offer__cta--text):hover::after,
.offer__cta:not(.offer__cta--text):focus-visible::after{
  opacity:1;animation:k-glisten .72s linear 1;
}

/* 🚫 A sweep is motion. Under reduced motion the hover is a colour change and
   nothing moves — the gradient paint is switched off entirely rather than just
   having its animation removed, because a static gradient would leave a light
   band frozen across the middle of the word. */
@media (prefers-reduced-motion:reduce){
  @supports ((-webkit-background-clip:text) or (background-clip:text)){
    .ilink:hover,.tlink:hover,.faqs__a a:hover,.prose a:hover,.cs__col a:hover,
    .close__alt:hover,.next a:hover,.close__go:hover,.head__nav a:hover,
    .foot__cols a:hover,.revs__all:hover,.crumb a:hover,.cs__live:hover,
    .cs:hover .cs__link,.cidx__link:hover .cidx__name,.faqs summary:hover,
    .svc__row:hover .svc__t,.fit__link:hover,.hero__proof:hover,.svc__more:hover,
    .rev__case:hover,.offer__see:hover,.btn--quiet:hover,.btn--ghost:hover,
    .btn--line:hover,.pswitch__tab:hover,.g__btn:hover,details > summary:hover,
    main a:not([class]):hover{
      background-image:none;-webkit-text-fill-color:currentColor;animation:none;
    }
  }
  .btn--cobalt::after,.btn--solid::after,.head__cta::after,
  .offer__cta:not(.offer__cta--text)::after{display:none}
}

/* ---- ONE MASTHEAD, EVERY ROUTE ----------------------------------------
   Owner, 2026-09-06: "the header changes size when going from home to a
   different page. It needs to stay the same throughout the entire site."

   It did, and the cause was inheritance rather than anything written about the
   header. .head__mark sets a font-family, weight, size and tracking in both
   stylesheets — but never a line-height, so it inherited one:

     styles.css     body line-height 1.55  ->  mark box 32.55px tall
     services.css   body line-height unset ->  mark box 25px    ("normal")

   The header is a flex row with align-items:center, so a 7.5px difference in
   the tallest item moved everything: the wordmark sat 3.8px higher and the nav
   5px lower on the four routes that load styles.css than on the thirty-one that
   load services.css. Everything the eye actually measures a header by — height,
   type size, padding, the mark's left edge — was already identical at every
   width from 390 to 1920. This was the whole difference.

   ⚠ Declared here, in the shared file, because the fault is that the two page
   systems each supplied their own value. Fixing it in one of them would leave
   the same class of bug in the other.
   🚫 Do not set this on body. The mark is the only thing in the header that
   inherits a line-height it should not. */
.head__mark{line-height:1}

/* The same divergence, twice more. The nav was spaced and padded differently
   by the two systems, which moved the links horizontally AND vertically:

     gap              styles.css clamp(20px,2.1vw,30px)  services.css clamp(26px,2.6vw,38px)
     a padding-block  styles.css none                    services.css 5px

   The 5px is why the nav sat 5px lower on thirty-one routes than on four. Both
   are settled on the services.css values because those are what 31 of the 35
   routes already render and what the header was last tuned against.
   ⚠ The homepage's tighter gap was itself a fix once — a fifth nav item was
   added and the four-item spacing no longer fit, so the gap was pulled in and
   checked at 1024/1200/1440. The nav markup is identical on every route, so the
   wider value has been re-checked at those widths here rather than assumed. */
.head__nav{gap:clamp(26px,2.6vw,38px)}
.head__nav a{padding-block:5px}

/* And the pill. styles.css padded it 0 18px, services.css 0 22px, so the
   "Start a Project" button was 133.3px wide on the homepage and 141.3px
   everywhere else — which also pushed the whole nav 8px right, since the nav is
   margin-left:auto and sits against the button. Settled on 22px, the value 31
   of the 35 routes already use.
   ⚠ This is the last of four separate divergences between the two page systems
   in one 91px bar: the mark's inherited line-height, the nav gap, the nav
   link's padding-block, and this. Each was small; together they moved every
   element in the header. 🚫 If a fifth appears, fix it here rather than in
   either page system, or the pair drifts apart again. */
.head__cta{
  padding:0 22px;
  /* ⚠ AND THE FILL — the fifth divergence. styles.css painted this with
     var(--cta-fill)/var(--cta-ink), services.css with var(--cobalt) and a
     literal #fff, so the same pill was #2148D8 on the homepage and #0A47F0 on
     the other thirty-one routes.
     Settled on the k-aware pair rather than on the majority literal, because
     --cta-fill is the token that INVERTS: cobalt with white type in day, a
     white pill with navy type at night. /#/ and /about/ still travel, and with
     a fixed --cobalt the masthead button would stay mid-blue on the night
     ground instead of becoming the loudest thing on the page, which is what
     the token was built for. The 31 static-day routes move from #0A47F0 to
     #2148D8 — the deeper blue, consistent with the service titles. */
  background:var(--cta-fill);
  color:var(--cta-ink);
}

/* ==========================================================================
   THE SPECIMEN + THE CLIENT PREVIEW, 2026-09-06.
   Two related blocks. .spec shows one piece of work large; .cprev shows the
   clients whose engagement actually included the service the page is about.

   ⚠ THE DIFFERENCE BETWEEN THEM IS EVIDENCE CLASS, AND IT IS THE POINT.
   .spec carries Morrow, which is self-initiated and says so. .cprev carries
   real engagements and links to their project records. They are styled apart
   on purpose — the specimen is a single wide plate, the previews are a row of
   records — so the two never read as one list of clients.
   🚫 Never put a concept in .cprev, and never drop the concept label from
   .spec. PROOF.md §9 is the authority for what may appear where.
   ========================================================================== */
.spec{padding:clamp(30px,4vw,58px) 0}
.spec__fig{margin:clamp(16px,2vw,26px) 0 0}
.spec__shot{
  display:block;overflow:hidden;border-radius:14px;
  border:1px solid var(--stroke);background:var(--surface);
}
.spec__shot img{width:100%;height:auto;display:block;transition:transform .55s cubic-bezier(.2,.7,.3,1)}
.spec__shot:hover img{transform:scale(1.02)}
.spec__shot:focus-visible{outline:2px solid var(--stroke-focus);outline-offset:4px}
.spec__cap{
  margin:clamp(14px,1.6vw,20px) 0 0;max-width:74ch;
  font-size:clamp(15px,1.2vw,16.5px);line-height:1.6;color:var(--ink-2);
}
@media (prefers-reduced-motion:reduce){ .spec__shot:hover img{transform:none} }

/* ---- the client preview -------------------------------------------------
   ⚠ One row per client, and the SCOPE LINE IS NOT DECORATION. It is the
   engagement's confirmed scope from PROJECTS.md, which is also what justifies
   the client appearing on this particular service page at all. If a scope does
   not name the service, the client does not belong here.
   ⚠ Sized deliberately smaller than the case cards on /work/: this is a
   pointer to the record, not the record. */
.cprev{display:grid;gap:clamp(16px,2vw,26px);margin:clamp(18px,2.2vw,30px) 0 0}
.cprev--two{grid-template-columns:repeat(2,minmax(0,1fr))}
.cprev__item{display:flex;flex-direction:column;min-width:0}
.cprev__shot{
  display:block;overflow:hidden;border-radius:12px;aspect-ratio:16/10;
  border:1px solid var(--stroke);background:var(--surface);
}
.cprev__shot img{width:100%;height:100%;object-fit:cover;object-position:top center;display:block;
  transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.cprev__item:hover .cprev__shot img{transform:scale(1.03)}
.cprev__body{padding:clamp(12px,1.3vw,16px) 2px 0}
.cprev__name{margin:0;font:500 clamp(16px,1.4vw,19px)/1.3 'General Sans',system-ui;color:var(--ink-1)}
.cprev__scope{
  margin:6px 0 0;font:400 13px/1.5 'General Sans',system-ui;color:var(--ink-3);
}
.cprev__go{
  display:inline-flex;align-items:center;gap:7px;margin-top:clamp(10px,1.1vw,14px);
  font:500 14.5px/1 'General Sans',system-ui;color:var(--accent);
  text-decoration:none;border-bottom:0;
}
.cprev__go i{font-style:normal;font-size:12px}
@media (prefers-reduced-motion:reduce){ .cprev__item:hover .cprev__shot img{transform:none} }
@media (max-width:800px){ .cprev--two{grid-template-columns:1fr} }
