/* ── DM Sans — self-hosted (Google's own variable woff2: opsz 9–40, wght 100–1000) ────────────
   One file per script/style; unicode-range lets the browser fetch latin-ext
   only when a page actually uses those glyphs. The upright latin file is
   preloaded from functions.php. Keep the opsz axis — headings pin "opsz" 14. */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 100 1000;
  font-display: swap;
  src: url('../../fonts/dm-sans-latin-normal.woff2') format('woff2');
  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: 'DM Sans';
  font-style: normal;
  font-weight: 100 1000;
  font-display: swap;
  src: url('../../fonts/dm-sans-latin-ext-normal.woff2') format('woff2');
  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;
}
@font-face {
  font-family: 'DM Sans';
  font-style: italic;
  font-weight: 100 1000;
  font-display: swap;
  src: url('../../fonts/dm-sans-latin-italic.woff2') format('woff2');
  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: 'DM Sans';
  font-style: italic;
  font-weight: 100 1000;
  font-display: swap;
  src: url('../../fonts/dm-sans-latin-ext-italic.woff2') format('woff2');
  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;
}

/* ==========================================================================
   Base: Design tokens, reset, typography, layout utilities
   ========================================================================== */

/* ── Figma Design Tokens — Desktop ───────────────────────────────────────── */
/* ── Animatable page background ────────────────────────────────────
   A custom property can only be TRANSITIONED once it is registered with a
   type — that is the whole trick behind a background that fades between light
   and dark as you scroll (AKQA does the same, with its entire token set).
   Registration has to be global, because @property is a top-level at-rule;
   the rules that use it are gated on .has-bgfade, which main.js adds on the
   front page only. Where @property is missing the variable still works, the
   colour just changes in one step — exactly today's behaviour. */
@property --page-bg {
  syntax: '<color>';
  inherits: true;
  initial-value: #F0F1FA;
}

:root {

  --font: 'DM Sans', sans-serif;
  /* Background — Background.* */
  --bg-primary:     #F0F1FA;   /* Background.Primary   */
  --bg-secondary:   #1C1024;   /* Background.Secondary */
  --bg-white:       #FFFFFF;   /* Background.Tertiary  */
  --bg-dark:        #1C1B1F;   /* Background.Dark      */
  --bg-black: #000;
  --bg-diamond-gradient:
    linear-gradient(to bottom right, #F6F6F6 0%, #FFDFF6 24%, #E5DAFF 50%) bottom right / 50% 50% no-repeat,
    linear-gradient(to bottom left,  #F6F6F6 0%, #FFDFF6 24%, #E5DAFF 50%) bottom left  / 50% 50% no-repeat,
    linear-gradient(to top left,     #F6F6F6 0%, #FFDFF6 24%, #E5DAFF 50%) top left     / 50% 50% no-repeat,
    linear-gradient(to top right,    #F6F6F6 0%, #FFDFF6 24%, #E5DAFF 50%) top right    / 50% 50% no-repeat;

  /* Text colours — Text.Color.* */
  --text-title:     #1C1B1F;   /* Text.Color.Title     */
  --text-body:      #4F4F4F;   /* Text.Color.Body-color */
  --text-light:     #FFFFFF;   /* Text.Color.Light     */
  --text-muted:     #C0C0C0;   /* Text.Color.Grey      */

  /* Icons / Buttons — IconsButton.* */
  --dragster-blue:  #3645FD;   /* IconsButton.Dragster-Blue */
  --btn-dark:       #1C1B1F;   /* IconsButton.Dark          */
  --btn-light:      #FFFFFF;   /* IconsButton.Light         */

  --icon-light: var(--bg-primary);

  /* SVG storke/swirl/wave */
  --svg-stroke-width: 58px;

  /* Title sizes — Text.Size.Title.* (Desktop) */
  --title-xl:       100px;     /* Title.XL     */
  --title-lg:       80px;      /* Title.Large  */
  --title-md:       48px;      /* Title.Medium */
  --title-sm:       40px;      /* Title.Small  */
  --title-xs:       32px;      /* Title.XS     */

  /* Title line-heights — Text.Size.Title.LineHeight.* (Desktop) */
  --title-xl-lh:    110px;
  --title-lg-lh:    86px;
  --title-md-lh:    60px;
  --title-sm-lh:    50px;
  --title-xs-lh:    45px;

  /* Letter spacing — a PERCENTAGE of the size, so one value holds at every
     breakpoint and never has to be restated per tier. (The old px values had
     to be, and had drifted: mobile --body-md-ls was positive, and mobile
     --title-xs-ls/--body-lg-ls were missing so a desktop px sat on a smaller
     mobile size.) Titles track -2%, body copy -1%. */
  --title-xl-ls: -0.02em;
  --title-lg-ls: -0.02em;
  --title-md-ls: -0.02em;
  --title-sm-ls: -0.02em;
  --title-xs-ls: -0.01em;   /* Title/XS tracks at -1%, like body copy */

  /* Card title step — Figma "Dragster 2.0/Desktop/H2 Small": 36/48, -2%.
     It falls between --title-sm (40) and --title-xs (32), so it is named for
     its job instead of being squeezed into the numbered scale. Used only by
.large-link__title. */
  --title-card:    36px;
  --title-card-lh: 48px;
  --title-card-ls: -0.02em;

  /* Impact-card LARGE figure (the 152px 9.2): the only size the scale has no step for, so it is named for its job like --title-card. The small and wide cards use the existing --title-lg / --title-xl. Mobile value, the fluid ramp and the large-screen growth are in the blocks below. */
  --figure-xl:      152px;   --figure-xl-lh:   156px;    /* large card  */

  /* Body sizes — Text.Size.Body.* (Desktop) */
  --body-lg:        24px;      /* Body.Large  */
  --body-md:        20px;      /* Body.Medium */
  --body-sm:        16px;      /* Body.Small  */
  --body-xs:        14px;      /* Body.XS     */
  --body-xxs:       12px;      /* theme extra */

  /* Body line-heights — Text.Size.Body.LineHeight.* (Desktop) */
  --body-lg-lh:     36px;
  --body-md-lh:     30px;
  --body-sm-lh:     24px;
  --body-xs-lh:     22px;      /* Figma Body/XS 14/22 — every 22px line-height on the site is this */

  /* Body letter-spacing */
  --body-lg-ls: -0.01em;
  --body-md-ls: -0.01em;
  --body-sm-ls: -0.01em;

  /* Sizes — Sizes.* */
  --gap-sm:         10px;      /* Sizes.Gap.Small               */
  --gap-md:         12px;      /* Sizes.Gap.Medium              */
  --radius-image:   20px;      /* Sizes.Border Radius.Images    */
  --radius-btn:     30px;      /* Sizes.Border Radius.Buttons   */
  --margin-primary: 60px;      /* Sizes.Margins.Primary         */

  /* Layout — theme-specific */
  --container-max: 100vw;
 /* --container-max:  1340px;*/
  --section-py:     120px;
  /* Rhythm steps named after their 1440px value (Figma). Same value everywhere up
     to 1440px; above it they grow like the titles (1.5x at 2560px, see the
     min-width: 1441px block). Use these instead of a bare 60/100/200px. */
  /* Contact band padding (section-contact.css). 60/80 at <=1440px (Figma), then it grows
     faster than --section-py so the band keeps pace with its 120px-tall neighbours. */
  --contact-pt:     60px;
  --contact-pb:     80px;
  --space-60:       60px;
  --space-100:      100px;
  --space-200:      200px;
  --header-h:       86px;

  /* Section top/bottom padding — reusable for titled sections (e.g. the
     Expertise carousel). Follows --section-py per breakpoint until a tier
     overrides it (see the mobile block below). Sections pinned at the top of
     the viewport add the fixed header on top:
     padding-top: calc(var(--header-h) + var(--section-pt)) */
  --section-pt:     var(--section-py);
  --section-pb:     var(--section-py);
}

/* ── Design Tokens — Tablet (768–1024px) ─────────────────────────────────── */
/* Bounded range so it can never leak into the mobile tier below. RULE: all
   --token values (every breakpoint) are defined in THIS file only — a token
   redefined in a later-loading file wins the cascade and breaks the tiers. */
@media (min-width: 768px) and (max-width: 1024px) {
  :root {
    --title-lg:    64px;   /* tablet mid-point between desktop 80px and mobile 40px */
    --title-lg-lh: 69px;   /* ≈ the desktop 86/80 ratio — was inheriting 86px (1.34, too airy) */
    --title-md:    40px;
    --title-md-lh: 50px;   /* pairs with 40px like --title-sm/-lh (was desktop 60px) */
    --section-py:  80px;
  }
}

/* ── Figma Design Tokens — Mobile (max-width: 767px) ─────────────────────── */
@media (max-width: 767px) {
  :root {
    /* Title sizes */
    --title-xl:     48px;
    --title-lg:     40px;
    --title-md:     32px;
    --title-sm:     24px;
    --title-xs:     20px;

    /* Title line-heights */
    --title-xl-lh:  50px;
    --title-lg-lh:  46px;
    --title-md-lh:  42px;
    --title-sm-lh:  30px;
    --title-xs-lh:  24px;



    /* Body sizes */
    /* The card title keeps its current mobile size — Figma's 36/48 is desktop. */
    --title-card:    var(--title-sm);
    --title-card-lh: var(--title-sm-lh);

    /* Impact-card figures: one mobile size for all three cards. */
    --figure-xl:      64px;  --figure-xl-lh:   70px;

    --body-lg:      20px;
    --body-md:      18px;
    --body-sm:      14px;
    --body-xs:      14px;

    /* Body line-heights */
    --body-lg-lh:   28px;
    --body-md-lh:   26px;
    --body-sm-lh:   24px;

    /* Body letter spacing */



    /* Spacing */
    --margin-primary: 16px;
    --section-py:     60px;

    /* Phone heroes take a fixed PROPORTION of the screen instead of all of it.
       Figma's mobile hero is 574 tall at 375 wide (Kajsa 2026-10-05); before
       this every hero was 100svh, so the whole first screen was image and the
       page looked like it started below the fold. Used as a FLOOR, so a long
       title grows the hero instead of being clipped; a short one lands exactly
       on the ratio. Defined only here, because only the phone rules use it. */
    --hero-h: calc(100vw * 574 / 375);

    /* Reusable section top/bottom padding — mobile */
    --section-pt:     40px;
    --section-pb:     40px;


        /* Total header height: 46px content row + 20px above/below (Figma 3190:6939) */
    --header-h:       86px;
  }
}

/* ── Fluid type — clamp() tokens (Kajsa 2026-10-13) ───────────────────────────
   Every size grows linearly from its MOBILE value at 375px to its DESKTOP value
   at 1440px; above 1440 the next block takes over. The fixed px values above, and the tablet and mobile
   blocks, are all still in the file untouched; this block comes LAST in source
   order, so on equal specificity it wins everywhere and nothing is overwritten.
   To fall back to the stepped scale, delete this block.

   Formula: clamp( min, intercept + slope * vw, max ), where
   slope = (max - min) / (1440 - 375) and intercept = min - slope * 375.
   Line-heights use the same anchors so size and leading move together.
   --body-xs (14px) and --body-xxs (12px) are the same everywhere and stay fixed. */
:root {
  /* Title sizes */
  --title-xl:      clamp(48px, 29.69px + 4.883vw, 100px);
  --title-lg:      clamp(40px, 25.92px + 3.756vw, 80px);
  --title-md:      clamp(32px, 26.37px + 1.502vw, 48px);
  --title-sm:      clamp(24px, 18.37px + 1.502vw, 40px);
  --title-xs:      clamp(20px, 15.78px + 1.127vw, 32px);
  --title-card:    clamp(24px, 19.78px + 1.127vw, 36px);

  /* Title line-heights */
  --title-xl-lh:   clamp(50px, 28.87px + 5.634vw, 110px);
  --title-lg-lh:   clamp(46px, 31.92px + 3.756vw, 86px);
  --title-md-lh:   clamp(42px, 35.66px + 1.690vw, 60px);
  --title-sm-lh:   clamp(30px, 22.96px + 1.878vw, 50px);
  --title-xs-lh:   clamp(24px, 16.61px + 1.972vw, 45px);
  --title-card-lh: clamp(30px, 23.66px + 1.690vw, 48px);

  /* Impact-card figures: 64px at 375 -> Figma size at 1440, same ramp as the titles. */
  --figure-xl:      clamp(64px, 33.01px + 8.263vw, 152px);
  --figure-xl-lh:   clamp(70px, 39.72px + 8.075vw, 156px);

  /* Body sizes */
  --body-lg:       clamp(20px, 18.59px + 0.376vw, 24px);
  --body-md:       clamp(18px, 17.30px + 0.188vw, 20px);
  --body-sm:       clamp(14px, 13.30px + 0.188vw, 16px);

  /* Body line-heights (--body-sm-lh is 24px at every width up to 1440) */
  --body-lg-lh:    clamp(28px, 25.18px + 0.751vw, 36px);
  --body-md-lh:    clamp(26px, 24.59px + 0.376vw, 30px);
}

/* ── Fluid type above 1440 — large screens (Kajsa 2026-10-13) ──────────────────
   Starts exactly where the block above ends: each token is its 1440px desktop
   value (Figma's) plus a growth term, clamp(0px, (100vw - 1440px) * slope, extra).
   Titles reach 1.5x their desktop size at 2560px, body 1.25x, then stop.
   slope = extra / 1120 (1120 = 2560 - 1440). Change `extra` to change the
   ceiling; the same block is the place for other large-screen overrides
   (container, margins, section rhythm). */
@media (min-width: 1441px) {
  :root {
    --title-xl:      calc(100px + clamp(0px, (100vw - 1440px) * 0.0446, 50px));
    --title-lg:      calc(80px  + clamp(0px, (100vw - 1440px) * 0.0357, 40px));
    --title-md:      calc(48px  + clamp(0px, (100vw - 1440px) * 0.0214, 24px));
    --title-sm:      calc(40px  + clamp(0px, (100vw - 1440px) * 0.0179, 20px));
    --title-xs:      calc(32px  + clamp(0px, (100vw - 1440px) * 0.0143, 16px));
    --title-card:    calc(36px  + clamp(0px, (100vw - 1440px) * 0.0161, 18px));

    --title-xl-lh:   calc(110px + clamp(0px, (100vw - 1440px) * 0.0491, 55px));
    --title-lg-lh:   calc(86px  + clamp(0px, (100vw - 1440px) * 0.0384, 43px));
    --title-md-lh:   calc(60px  + clamp(0px, (100vw - 1440px) * 0.0268, 30px));
    --title-sm-lh:   calc(50px  + clamp(0px, (100vw - 1440px) * 0.0223, 25px));
    --title-xs-lh:   calc(45px  + clamp(0px, (100vw - 1440px) * 0.0201, 22.5px));
    --title-card-lh: calc(48px  + clamp(0px, (100vw - 1440px) * 0.0214, 24px));

    /* Figures reach 1.5x at 2560px, like the titles. */
    --figure-xl:      calc(152px + clamp(0px, (100vw - 1440px) * 0.0679, 76px));
    --figure-xl-lh:   calc(156px + clamp(0px, (100vw - 1440px) * 0.0696, 78px));

    --body-lg:       calc(24px + clamp(0px, (100vw - 1440px) * 0.0054, 6px));
    --body-md:       calc(20px + clamp(0px, (100vw - 1440px) * 0.0045, 5px));
    --body-sm:       calc(16px + clamp(0px, (100vw - 1440px) * 0.0036, 4px));

    /* Spacing grows with the screen, like the type. Without it the type gets 1.5x
       bigger at 2560px while sections and gutters stay put, so the page reads
       cramped. 1.5x at 2560px, same slope rule: extra / 1120. */
    --section-py:     calc(120px + clamp(0px, (100vw - 1440px) * 0.0536, 60px));
    --margin-primary: calc(60px  + clamp(0px, (100vw - 1440px) * 0.0268, 30px));
    --space-60:       calc(60px  + clamp(0px, (100vw - 1440px) * 0.0268, 30px));
    --space-100:      calc(100px + clamp(0px, (100vw - 1440px) * 0.0446, 50px));
    --space-200:      calc(200px + clamp(0px, (100vw - 1440px) * 0.0893, 100px));
    --contact-pt:     calc(60px + clamp(0px, (100vw - 1440px) * 0.0804, 90px));
    --contact-pb:     calc(80px + clamp(0px, (100vw - 1440px) * 0.0982, 110px));

    --body-lg-lh:    calc(36px   + clamp(0px, (100vw - 1440px) * 0.0080, 9px));
    --body-md-lh:    calc(30px   + clamp(0px, (100vw - 1440px) * 0.0067, 7.5px));
    --body-sm-lh:    calc(24px   + clamp(0px, (100vw - 1440px) * 0.0054, 6px));
  }
}

/* ── Reset ───────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html  { scroll-behavior: smooth; }

/* Hide the native page scrollbar (showcase-style, like the reference sites).
   Scrolling itself still works exactly as normal — wheel, touch, keys. */
html { scrollbar-width: none; -ms-overflow-style: none; }
html::-webkit-scrollbar { width: 0; height: 0; display: none; }
ul    { list-style: none; }
a     { color: inherit; text-decoration: none; }
img   { max-width: 100%; height: auto; display: block; }
/* `clip`, not `hidden`: still prevents horizontal scroll, but does NOT turn
   html/body into a scroll container — `overflow-x: hidden` here silently forces
   `overflow-y: auto`, which breaks `position: sticky` (the Expertise carousel
   pin, and any other sticky). `clip` leaves overflow-y visible. */
html, body {
  overflow-x: clip;
  width: 100%;
}
body {
  font-family: var(--font);
  font-size: var(--body-sm);
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-body);
  background-color: var(--bg-primary);
}

input, textarea, select, button {
  font: inherit;
}

/* iOS paints a gray semi-transparent overlay on tapped links/buttons by
   default — it read as the header CTA "fading" on touch. Our components
   provide their own press feedback (:active states, .is-pressed), so the
   built-in wash is pure noise. */
a, button {
  -webkit-tap-highlight-color: transparent;
}


/* ── Typography ──────────────────────────────────────────────────────────── */
/* Bare headings: the FALLBACK for unclassed markup — wysiwyg bodies, mainly.
   102 of the site's 105 headings carry a utility class, and a class always
   beats an element selector, so these almost never fire. They are still worth
   getting right: the moment an editor types a heading into one of the six
   wysiwyg fields, this is what they get.
   Fixed 2026-10-02: h1 used to be --title-md (48px) while h2 was --title-lg
   (80px), i.e. a bare h1 rendered SMALLER than a bare h2; the line-heights were
   hand-rolled ratios that missed the designed leading; and h3 tracked at
   -0.03em, off the scale. Now derived from the tokens and ordered h1>h2>h3>h4. */
h1 { font-size: var(--title-lg); font-weight: 400; letter-spacing: var(--title-lg-ls); line-height: var(--title-lg-lh); color: var(--text-title); }
h2 { font-size: var(--title-md); font-weight: 400; letter-spacing: var(--title-md-ls); line-height: var(--title-md-lh); color: var(--text-title); }
h3 { font-size: var(--title-sm); font-weight: 400; letter-spacing: var(--title-sm-ls); line-height: var(--title-sm-lh); color: var(--text-title); }
h4 { font-size: var(--title-xs); font-weight: 400; letter-spacing: var(--title-xs-ls); line-height: var(--title-xs-lh); color: var(--text-title); }
p  { line-height: 1.7; }

/*-- Headings ---*/ 
.title-xl{font-size: var(--title-xl); font-weight: 400; letter-spacing: var(--title-xl-ls); line-height: var(--title-xl-lh); color: var(--text-title); }
.title-lg{font-size: var(--title-lg); font-weight: 400; letter-spacing: var(--title-lg-ls); line-height: var(--title-lg-lh); color: var(--text-title); }
.title-md{font-size: var(--title-md); font-weight: 400; letter-spacing: var(--title-md-ls); line-height: var(--title-md-lh); color: var(--text-title); }
.title-s{ font-size: var(--title-sm); font-weight: 400; letter-spacing: var(--title-sm-ls); line-height: var(--title-sm-lh); color: var(--text-title); }
.title-xs{font-size: var(--title-xs); font-weight: 400; letter-spacing: var(--title-xs-ls); line-height: var(--title-xs-lh); color: var(--text-title); }

.text-lg{ font-size: var(--body-lg); line-height: var(--body-lg-lh); letter-spacing: var(--body-lg-ls); color: var(--text-body);}  /* Figma Body/Large: -1% tracking */
.text-m{ font-size: var(--body-md); line-height: var(--body-md-lh); letter-spacing: var(--body-md-ls); color: var(--text-body);}
.text-s{ font-size: var(--body-sm); line-height: var(--body-sm-lh); letter-spacing: var(--body-sm-ls); color: var(--text-body);}

/* ── Layout ──────────────────────────────────────────────────────────────── */
/* .container is the HORIZONTAL gutter and the max width - nothing else. It
   carried padding-bottom: var(--margin-primary) site-wide until 2026-10-09, and
   eleven places across ten files had to switch it off again, almost every one
   commented "would double up" / "would double the rhythm". A default that nearly
   every section fights is the wrong default: vertical rhythm belongs to the
   SECTION (.section / --section-py), not to the gutter.
   An audit of the whole theme found exactly two places that had no other bottom
   spacing of their own; both now declare it explicitly (page-all-case-studies.css
   and page-styleguide.css). The old padding-bottom: 0 overrides are now no-ops
   and are harmless - they can be swept whenever those files are next touched. */
.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--margin-primary);
  width: 100%;
}



.section { padding-block: var(--section-py); }

.section--dark  { background-color: var(--bg-secondary); }
.section--white { background-color: var(--bg-white); }

/* Responsive <picture> that fills its (position:relative) container — replaces
   inline background-image on heroes so the right size loads per breakpoint. */
.media-fill {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  pointer-events: none;
}
.media-fill__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}


/* Render text the way Figma does (grayscale antialiasing) — the browser's
   'auto' smoothing makes light-on-dark text look a notch bolder than design. */
body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Balanced heading rag — no lonely last words; manual breaks (textarea
   newlines → <br>) still win where an exact break is wanted. */
h1, h2, h3 { text-wrap: balance; }

/* DM Sans optical size — match Figma, which pins every text layer to the text
   cut ("opsz" 14). Left on auto, browsers pick the tighter display cut at big
   sizes and headlines render ~11% narrower than the design (measured: the same
   100px line is 839px auto vs 934px at opsz 14). */
h1, h2, h3,
.case-next__title {
  font-optical-sizing: none;
  font-variation-settings: "opsz" 14;
}


/* -- Scroll-driven background fade (front page) -----------------------------
   The dark bands stop painting themselves and the PAGE colour fades between
   light and dark instead, so there is no edge left to see: the background
   simply changes while you scroll. The sections between them were already
   transparent, so the whole page is one continuous surface.
   main.js sets --page-bg on the BODY, which is also where the transition
   lives: a registered custom property animates on the element whose own
   computed value changes, so setting it on <html> instead would inherit down
   already-finished and never fade. */
body.has-bgfade {
  background-color: var(--page-bg);
  transition: --page-bg 0.7s ease;
}
body.has-bgfade #effect,
body.has-bgfade #always-on { background-color: transparent; }

/* While the page is dark, the strip of normally light-ground content still on
   screen has to come along, or dark text sits on dark purple (Kajsa
   2026-10-05). Only #work needs it: the hero ends in its media CARD, so the
   prompt and its text are on the card's own surface, not on the page.
   The colours run on the SAME clock as the background so the two move as one
   piece — that pairing is what AKQA transitions alongside its background. */
body.has-bgfade #work .tw-heading,
body.has-bgfade #work .tw-heading .title-lg,
body.has-bgfade #work .tw-text,
body.has-bgfade #work .tw-text p,
body.has-bgfade #work .large-link__label,
body.has-bgfade #work .large-link__text { transition: color 0.7s ease; }

body.has-bgfade.is-dark #work .tw-heading,
body.has-bgfade.is-dark #work .tw-heading .title-lg,
body.has-bgfade.is-dark #work .tw-text,
body.has-bgfade.is-dark #work .tw-text p { color: var(--text-light); }
/* The case cards flip to the light mode the component already has — one
   variable flip, never a rule on the card's internals. */
body.has-bgfade.is-dark #work .large-link {
  --ll-label: var(--text-light);
  --ll-title: #fff;
}
/* Same for the CTA: a dark pill on dark purple reads as a hole. */
body.has-bgfade.is-dark #work .btn--dark {
  --btn-bg: #fff;
  --btn-fg: #000;
  --btn-icon: #000;
}

@media (prefers-reduced-motion: reduce) {
  body.has-bgfade,
  body.has-bgfade #work .tw-heading,
  body.has-bgfade #work .tw-heading .title-lg,
  body.has-bgfade #work .tw-text,
  body.has-bgfade #work .tw-text p,
  body.has-bgfade #work .large-link__label,
  body.has-bgfade #work .large-link__text { transition: none; }
}


/* -- The dark bands need a LIGHT mode too ------------------------------------
   Mirror of the #work rules above. #effect and #always-on are drawn for a dark
   ground, so while the page is still light their white text and glass sit on
   near-white and vanish. The heading starts only 80px into the section and the
   first card 376px, so both are well inside the viewport before the colour
   turns (Kajsa 2026-10-05).
   Making the colour turn earlier is NOT the fix - that was the 0.8 trigger
   that felt too eager. The band simply has to carry both modes.
   ID selectors, so these beat the components' own [data-theme="dark"] rules. */
body.has-bgfade #effect .dragster-effect__title,
body.has-bgfade #effect .dragster-effect__lead,
body.has-bgfade #effect .impact-card,
body.has-bgfade #effect .impact-card p,
body.has-bgfade #always-on .tw-heading,
body.has-bgfade #always-on .tw-heading h2,
body.has-bgfade #always-on .tw-text,
body.has-bgfade #always-on .large-link__label,
body.has-bgfade #always-on .large-link__text {
  transition: color 0.7s ease, background-color 0.7s ease, -webkit-text-fill-color 0.7s ease;
}

/* The glow title is a gradient clipped to the glyphs. On a light ground the
   gradient is dropped altogether rather than swapped for a dark one: a solid
   colour is guaranteed readable, and the glow is the dark band's signature
   anyway, so it belongs to the dark half. */
body.has-bgfade:not(.is-dark) #effect .dragster-effect__title {
  background-image: none;
  -webkit-text-fill-color: var(--text-title);
  color: var(--text-title);
}
body.has-bgfade:not(.is-dark) #effect .dragster-effect__lead { color: var(--text-body); }

/* White-on-white glass is invisible: the card keeps its shape with a dark tint
   instead, and its type goes dark with it. */
body.has-bgfade:not(.is-dark) #effect .impact-card { background-color: rgba(28, 27, 31, 0.04); }
body.has-bgfade:not(.is-dark) #effect .impact-card,
body.has-bgfade:not(.is-dark) #effect .impact-card__eyebrow,
body.has-bgfade:not(.is-dark) #effect .impact-card__number,
body.has-bgfade:not(.is-dark) #effect .impact-card__title { color: var(--text-title); }
body.has-bgfade:not(.is-dark) #effect .impact-card__note { color: var(--text-body); }

/* Always On is the same situation, through the text widget and the cards. */
/* The h2 inside sets its OWN colour, so inheriting from .tw-heading never
   reaches it - the heading stayed white on the light ground (Kajsa
   2026-10-06). Same pair the #work rules above already name. */
body.has-bgfade:not(.is-dark) #always-on .tw-heading,
body.has-bgfade:not(.is-dark) #always-on .tw-heading h2 { color: var(--text-title); }
body.has-bgfade:not(.is-dark) #always-on .tw-text { color: var(--text-body); }
body.has-bgfade:not(.is-dark) #always-on .large-link {
  --ll-label: var(--text-title);
  --ll-title: var(--text-title);
}
