/*
Theme Name:  Maverick TMG
Theme URI:   https://maverick-group.com/
Author:      The Maverick Group
Description: Custom theme for The Maverick Group website, built from the approved v28 prototype. Charcoal base with Green (Inside), Periwinkle (Outside) and Mustard (neutral) accents, Teal as a bounded secondary. Kanit display, Archivo body.
Version:     1.28.18
Requires PHP: 7.4
License:     Proprietary
Text Domain: maverick-tmg
*/

/* ---------------------------------------------------------------------------
   Colour tokens.

   RULE: a token is named for its ROLE, not its colour. --in is whatever the
   Inside door speaks today; --out is whatever Outside speaks. Change the hex
   here and the whole build follows. Nothing outside this block holds a colour
   literal, and nothing outside this block needs renaming when the palette moves
   again. That is the point of the v1.26.0 rename below — do not undo it by
   reintroducing colour-named tokens.

   RENAME HISTORY. Two passes, for anyone meeting an old name in a branch,
   screenshot or backup.

   v1.13.0 — the original names had drifted from the brand book. --teal held a
   charcoal, --blue and --pink both held the real Teal, --plum held Charcoal,
   --violet duplicated --plum-soft, and --serif held Kanit, which is a sans:

     --plum        -> --charcoal          --gold        -> --mustard
     --plum-deep   -> --charcoal-deep     --blue        -> --teal
     --plum-soft   -> --charcoal-soft     --pink        -> (dupe of --teal)
     --teal        -> --charcoal-mid      --violet      -> (dupe of -soft)
     --teal-mid    -> --charcoal-shade    --sage-deep   -> --teal-deep
     --teal-deep   -> (dupe of -deep)     --sage-lite   -> --teal-lite
     --dove-soft   -> (dupe of --paper)   --sage-onsoft -> --teal-onsoft
     --serif       -> --display           --sans        -> --body

   v1.26.0 — the Creative Director signed off Green for Inside; Periwinkle
   stays Outside. Rather than paste a green into a token called --teal and
   recreate the exact problem v1.13.0 was written to kill, the door accents
   were renamed to their ROLE. This pass was a rename AND a retune of the
   Inside family: Outside kept every value it had, Inside moved to Green.

     --teal        -> --in          (VALUE CHANGED: #0FA3B1 -> #42B677)
     --teal-deep   -> --in-deep     (VALUE CHANGED: #09626A -> #1F6E45)
     --teal-lite   -> --in-lite     (VALUE CHANGED: #58C5D1 -> #5CCB8C)
     --teal-onsoft -> --in-onsoft   (VALUE CHANGED: #7FDCE6 -> #7ADCA5)
     --teal-rgb    -> --in-rgb      (VALUE CHANGED)
     --periwinkle* -> --out*        (values unchanged)
     .btn-teal     -> .btn-in-solid (class rename, same reason)

   The v1.25.0 palette lab was removed in the same version. The pair is chosen;
   the harness has no job left, and tmg_lab_permitted() no longer exists.

   Brand reference (Logo_Lockups_and_Colourways_CHARCOAL, plus the Green
   supplied by James on 2026-08-20):
   Charcoal #413E45 · Mustard #FFCE26 · Green #42B677 · Periwinkle #2667FF
   Teal #0FA3B1 · Dipse #D4D4D2 · Dove #FBFAF7
   --------------------------------------------------------------------------- */
:root{
    /* Charcoal family — the base. Named for what they are: greys, not plums. */
    --charcoal:#413E45;        /* brand Charcoal, the primary */
    --charcoal-mid:#4A4751;    /* lighter step, used in the Inside gradient */
    --charcoal-shade:#3A373F;  /* mid step of that gradient */
    --charcoal-deep:#2B2930;   /* darkest, used for the nav and footer grounds */
    --charcoal-soft:#54515A;   /* the card grey on Our Work and News */

    /* Grounds */
    --dove:#FBFAF7; --paper:#FFFFFF; --dipse:#D4D4D2; --ink:#2A282E;

    /* INSIDE speaks Green (#42B677, signed off 2026-08-20, replacing Teal).

       Green as ink measures 2.56:1 on white — the same trap Teal had — so light
       grounds take --in-deep and dark grounds take --in-lite. The steps below
       were tuned to land on the SAME contrast ratios the Teal family carried,
       so every existing rule keeps the score it was checked at:

         --in         #42B677  the brand green. As a FILL it takes --in-ink
                               (5.68:1); never white, which is 2.56:1.
         --in-deep    #1F6E45  6.22:1 on white, 6.08:1 on Dove. Inside text on
                               light sections. (Teal-deep was 7.08:1.)
         --in-lite    #5CCB8C  7.09:1 on --charcoal-deep, 5.19:1 on --charcoal.
                               Inside text on dark sections. Teal-lite measured
                               7.05:1 and 5.19:1 — a deliberate match, so the
                               two doors stay symmetrical on dark grounds.
         --in-onsoft  #7ADCA5  4.86:1 on the --charcoal-soft (#54515A) cards,
                               where --in-lite reaches only 4.0:1. */
    --in:#42B677;
    --in-deep:#1F6E45;
    --in-lite:#5CCB8C;
    --in-onsoft:#7ADCA5;

    /* TEAL is retained as a BOUNDED secondary accent, at Jamie's direction
       ("teal may be used as a secondary accent alongside the green"). It is
       NOT a door colour and must never label Inside or Outside. It has exactly
       two jobs, and adding a third needs a decision, not a guess:

         1. The globe block on Who we are — .globe-glow, .earth and the
            .mb-stats figures beside it. This one is load-bearing: the globe
            iframe (assets/globe/globe.html) is a generated bundle carrying a
            hand edit that draws the office pins in Teal, and it cannot be
            re-exported without losing that edit. The surrounding CSS stays
            Teal so the globe reads as one object.
         2. Card metadata on the dark --charcoal-soft cards — the result line
            on Our Work cards, and the date and client on News cards. A second,
            cooler tone separates data from label without competing with the
            Inside green on the door badges of the same card.

       Values are unchanged from when Teal was the Inside lead. */
    --teal:#0FA3B1;
    --teal-lite:#58C5D1;       /* Teal for text on dark grounds */
    --teal-onsoft:#7FDCE6;     /* Teal that clears 4.5:1 on --charcoal-soft */

    /* MUSTARD is the neutral voice: the conversion CTA, Who we are, ESG,
       Join us, Contact, and the site's own words on the homepage, scoped via
       body.tmg-neutral. 7.05:1 on Charcoal and 9.64:1 on Charcoal-deep; as a
       FILL it takes --ink text, never white (white on it is 1.49:1).

       v1.19.0 removed --mustard-deep (#8A6A00) and --mustard-ondipse
       (#6F5500), the darkened golds that carried the accent on white, Dove and
       Dipse. They were legible — 5.07:1 and 4.75:1 — but read as a muddy olive
       rather than the brand yellow, and James rejected them outright: the
       accent is #FFCE26 on every ground.

       The consequence is deliberate and known: brand yellow as ink measures
       1.49:1 on white, 1.43:1 on Dove and 1.00:1 on Dipse, so the neutral
       accent on light sections is decorative rather than readable. James has
       accepted this and will address it by moving those sections onto dark
       grounds. Do not "fix" it by reintroducing a darkened gold. */
    --mustard:#FFCE26; --mustard-shade:#E8BC0F;

    /* OUTSIDE speaks Periwinkle, used as brand #2667FF on every ground, light
       or dark — James's explicit instruction, restated after two attempts to
       substitute a derived tone. Do not swap in a lightened or darkened variant
       to win a contrast check. --out-deep is now the .btn-out hover; --out-lite
       is for Periwinkle on a dark ground, where base Periwinkle cannot clear the
       3:1 boundary — the homepage Outside door's .go button (3.05:1 on
       --charcoal-deep) and, from v1.28.7, .btn-out-lite on the Inside CTA, where
       raw Periwinkle against --charcoal-mid is only 1.93:1.
       --out-onsoft added v1.28.7 purely as .btn-out-lite's hover, mirroring what
       --in-onsoft does for Green. Both hovers go LIGHTER, not darker. */
    --out:#2667FF; --out-deep:#1B4FCC; --out-lite:#85A9FF; --out-onsoft:#A8C3FF;

    /* Channel triplets, so a translucent wash can follow the accent instead of
       repeating its hex. Keep these in step with the values above. */
    --in-rgb:66,182,119; --out-rgb:38,103,255; --mustard-rgb:255,206,38;
    --teal-rgb:15,163,177;

    /* Text sitting ON an Inside or Outside fill. This is the one value that is
       allowed to move when an accent changes: the brand colour itself is fixed,
       but the ink on top of it has to follow the fill's luminance or the label
       disappears. White on Green is 2.56:1; --in-ink on Green is 5.68:1, so
       Inside fills take ink and Outside fills (Periwinkle, much darker) take
       white. --in-ink-door is the door hover's near-black; it was a teal-black
       (#0C2B2E) until v1.26.0 and is now a green-black, 5.75:1 on Green. */
    --in-ink:#2A282E; --in-ink-door:#0B2E1E; --in-paper:#FFFFFF;
    --out-paper:#FFFFFF;

    /* Neutral metadata that still clears 4.5:1 on the --charcoal-soft cards,
       where the door colours manage only about 4:1 and a plain grey only
       2.31:1. */
    --mute-onsoft:#CFCBD4;

    /* Type. Kanit is a SANS-serif display face — the old --serif name was
       simply wrong and led to it being treated as a serif. */
    --display:'Kanit', 'Helvetica Neue', Arial, sans-serif;
    --body:'Archivo', 'Helvetica Neue', Arial, sans-serif;
  }
  *{margin:0;padding:0;box-sizing:border-box;}

  /* The [hidden] attribute has to actually hide things.
     The browser's own [hidden]{display:none} lives in the UA stylesheet, which
     ANY author rule outranks — so .filters{display:flex} was quietly winning and
     a hidden service chip stayed on screen. main.js uses .hidden for filtered
     cards and the hidden attribute for the door-scoped service chips; this makes
     the second one work. */
  [hidden]{display:none !important;}

  /* Visually hidden, but still read by screen readers and still focusable.
     Used for the skip link and for section headings that the design carries
     visually but doesn't mark up as headings. */
  .screen-reader-text{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}
  .skip-link:focus{position:fixed;top:10px;left:10px;z-index:9999;width:auto;height:auto;
    clip:auto;margin:0;padding:12px 20px;background:var(--mustard);color:#2A282E;
    font-weight:700;text-decoration:none;white-space:normal;}
  html{scroll-behavior:smooth;}
  body{font-family:var(--body);color:var(--ink);background:var(--paper);line-height:1.6;font-size:17px;}
  img{max-width:100%;display:block;}
  a{color:inherit;}

  /* Scroll build. Was 34px/800ms with up to 360ms stagger, which put the last
     card in a row 1.16s behind the first — you scrolled, then waited for the
     page. Shorter travel and a tighter stagger keep the gesture but land it
     while the reader is still looking. Same easing curve. */
  .reveal{opacity:0;transform:translateY(18px);transition:opacity .45s cubic-bezier(.22,.61,.36,1), transform .45s cubic-bezier(.22,.61,.36,1);}
  .reveal.visible{opacity:1;transform:none;}
  .reveal.d1{transition-delay:.06s;} .reveal.d2{transition-delay:.12s;} .reveal.d3{transition-delay:.18s;}
  @keyframes floaty{0%,100%{transform:translateY(0) rotate(0deg);}50%{transform:translateY(-16px) rotate(1.2deg);}}
  @keyframes marquee{to{transform:translateX(-50%);}}
  @media (prefers-reduced-motion: reduce){
    html{scroll-behavior:auto;}
    *,*::before,*::after{animation:none!important;transition:none!important;}
    .reveal{opacity:1;transform:none;}
  }

  /* Prototype page switching removed — each template renders one page. */
  .page{display:block;}
  .page.active{display:block;animation:fadeIn .45s ease;}
  @keyframes fadeIn{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:none;}}

  /* ---------- nav ---------- */
  header{position:sticky;top:0;z-index:100;background:rgba(43,41,48,.94);backdrop-filter:blur(10px);color:var(--dove);}
  .nav-inner{max-width:1240px;margin:0 auto;padding:16px 32px;display:flex;align-items:center;gap:34px;}
  /* 75px, up 50% from 50. The wordmark is ~75% of the lockup (the rhino only
     24%), so scaling the whole image is what enlarges "THE MAVERICK GROUP"
     without splitting the baked-in artwork or re-setting the type. */
  .navlogo{height:75px;width:auto;cursor:pointer;}
  nav.main{display:flex;gap:26px;margin-left:auto;align-items:center;}
  nav.main > a, .dd > a{color:var(--dove);text-decoration:none;font-size:15px;font-weight:500;
    border-bottom:2px solid transparent;padding-bottom:2px;transition:border-color .2s,color .2s;cursor:pointer;display:inline-block;}
  /* The masthead belongs to the site, not to a door, so its hover marker is the
     neutral colour — which since v1.18.0 is the brand yellow. (This comment used
     to describe a Periwinkle tint, from when Periwinkle was the neutral voice.) */
  nav.main > a:hover, .dd > a:hover{color:#fff;border-color:var(--mustard);}
  .dd{position:relative;}
  .dd > a::after{content:" ▾";font-size:11px;opacity:.7;}
  .dd-menu{display:none;position:absolute;top:calc(100% + 12px);left:-14px;z-index:5;}
  .dd-menu::before{content:"";position:absolute;top:-14px;left:0;right:0;height:14px;}
  /* :focus-within as well as :hover — display:none takes the submenu links out
     of the tab order, so on hover alone Inside/Outside are unreachable without
     a mouse. Opening on focus puts them back in the keyboard path. */
  /* .dd.open is toggled by main.js so the parent also opens on click/tap and
     keyboard, not hover/focus alone — the fix for "What we do" going nowhere. */
  .dd:hover .dd-menu, .dd:focus-within .dd-menu, .dd.open .dd-menu{display:block;}
  .dd-trigger{cursor:pointer;}
  .dd-menu .dd-card{display:block;background:#2B2930;border-radius:0;padding:8px;min-width:180px;
    box-shadow:0 18px 44px rgba(0,0,0,.55);border:1px solid rgba(232,237,235,.14);}
  .dd-menu a{display:block;padding:12px 18px;border-radius:0;text-decoration:none;font-size:15.5px;font-weight:600;color:#fff;cursor:pointer;}
  .dd-menu a.dd-in:hover{background:var(--in);color:#2A282E;}
  .dd-menu a.dd-out:hover{background:var(--out);color:#fff;}
  /* Neutral fills. The text on them is --ink, NOT white: white on Mustard is
     1.49:1 and unreadable, where --ink is 9.78:1. This is the single most
     important consequence of the Periwinkle -> Mustard swap. */
  .dd-menu a.dd-neutral:hover{background:var(--mustard);color:var(--ink);}
  .nav-cta{background:var(--mustard);color:var(--ink)!important;border-radius:0;padding:9px 20px!important;
    font-weight:600!important;border-bottom:none!important;transition:transform .15s, background .2s;}
  .nav-cta:hover{background:var(--mustard-shade);transform:translateY(-1px);}
  .burger{display:none;margin-left:auto;background:transparent;border:none;cursor:pointer;width:42px;height:42px;
    flex-direction:column;justify-content:center;align-items:center;gap:6px;}
  .burger span{display:block;width:24px;height:2px;background:var(--dove);border-radius:0;transition:transform .25s,opacity .25s;}
  body.menu-open .burger span:nth-child(1){transform:translateY(8px) rotate(45deg);}
  body.menu-open .burger span:nth-child(2){opacity:0;}
  body.menu-open .burger span:nth-child(3){transform:translateY(-8px) rotate(-45deg);}
  .mob-menu{display:none;position:fixed;top:58px;left:0;right:0;z-index:99;background:var(--charcoal-deep);color:var(--dove);
    padding:18px 26px 28px;box-shadow:0 24px 50px rgba(20,12,25,.45);max-height:calc(100vh - 58px);overflow:auto;}
  body.menu-open .mob-menu{display:block;}
  .mob-menu a{display:block;padding:13px 6px;font-size:17px;font-weight:500;text-decoration:none;cursor:pointer;border-bottom:1px solid rgba(232,237,235,.12);}
  .mob-menu a.sub{padding-left:26px;font-size:15.5px;opacity:.85;}
  /* Non-link group label, for "What we do", which has no page of its own. Set
     to match the weight of the real top-level links so the menu reads as two
     labelled groups rather than a flat list. */
  .mob-menu .mob-label{display:block;padding:13px 6px 9px;font-size:17px;font-weight:500;
    opacity:.6;letter-spacing:.01em;}
  .mob-menu a:hover{color:#fff;}
  /* Tapping a mobile menu item showed the browser's own tap highlight, a light
     blue wash that belongs to no part of the palette. Suppressed, and replaced
     with the colour of the section being tapped, exactly as the desktop
     dropdown already does on hover: Teal for Inside, Periwinkle for Outside,
     Mustard for everything else. Tokens only, so these follow any palette
     change rather than needing to be found again. */
  .mob-menu a{-webkit-tap-highlight-color:transparent;transition:background .15s,color .15s;}
  .mob-menu a:active{background:var(--mustard);color:var(--ink);}
  .mob-menu a.mob-in:active{background:var(--in);color:#2A282E;}
  .mob-menu a.mob-out:active{background:var(--out);color:#fff;}
  /* The CTA is already a Mustard fill, so a Mustard tap would be invisible. */
  .mob-menu .mob-cta:active{background:var(--mustard-shade);color:var(--ink);}
  /* Ink, not white: white on Mustard measures 1.49:1. */
  /* The mobile twin of .nav-cta, so it matches it: the global CTA is neutral on
     every page, including Inside and Outside. It was Mustard. */
  .mob-menu .mob-cta{margin-top:18px;border:none;background:var(--mustard);color:var(--ink);border-radius:0;text-align:center;font-weight:600;}
  @media(max-width:980px){
    nav.main{display:none;}
    .burger{display:flex;}
  }
  @media(max-width:560px){.navlogo{height:54px;}}

  /* ---------- shared ---------- */
  .wrap{max-width:1240px;margin:0 auto;padding:0 32px;}
  /* 20px, up from 15px on 2026-08-20, so the section labels carry across the
     page instead of reading as captions. At .2em tracking a 20px uppercase line
     is wide, so phones step back to 15px rather than wrapping the label onto a
     second line above every heading. */
  .eyebrow{font-size:20px;font-weight:700;letter-spacing:.2em;text-transform:uppercase;display:inline-flex;align-items:center;gap:10px;}
  @media(max-width:640px){ .eyebrow{font-size:15px;letter-spacing:.16em;} }
  .eyebrow::before{content:"";width:26px;height:2px;background:currentColor;display:inline-block;}
  h1,h2,h3{font-family:var(--display);font-weight:800;line-height:1.02;letter-spacing:-.01em;}
  h1,h2{font-weight:600;text-transform:uppercase;letter-spacing:0;}
  h1 em,h2 em,h3 em{font-style:normal;}
  /* border-color is transitioned alongside background. Without it, buttons that
     change both (.btn-out, .btn-in, .btn-peri) snapped their border to the new
     colour instantly while the fill faded in over .2s — which read as the button
     briefly outlining, then filling. Michelle spotted this on Outside. */
  .btn{display:inline-block;font-family:var(--body);font-weight:600;font-size:15px;text-decoration:none;
    border-radius:0;padding:13px 28px;cursor:pointer;border:none;
    transition:transform .15s,background .2s,border-color .2s,color .2s;}
  .btn:hover{transform:translateY(-2px);}
  /* .btn-gold removed in v1.13.0: unused in every template, and its name was a
     trap — it was Dipse grey with dark ink, no gold anywhere in it. */
  /* The neutral conversion CTA. Only for cross-door pages (home, contact, and
     the Who we are / ESG / Join us set) — on Inside or Outside use that door's
     own colour instead. White label, per Periwinkle rule 1. */
  /* .btn-peri keeps its name so no template has to change; it is the neutral
     button, and the neutral colour is now Mustard. */
  .btn-peri{background:var(--mustard);color:var(--ink);border:1px solid var(--mustard);}
  .btn-peri:hover{background:var(--mustard-shade);border-color:var(--mustard-shade);color:var(--ink);}
  .btn-ghost{background:transparent;border:1.5px solid rgba(232,237,235,.55);color:var(--dove);}
  .btn-ghost:hover{border-color:var(--mustard);color:#fff;}
  .btn-in-solid{background:var(--in);color:var(--in-ink);} .btn-in-solid:hover{background:var(--in-deep);color:var(--in-paper);}
  /* .btn-plum-ghost removed in v1.13.0: unused, and doubly misnamed — it was a
     solid Mustard button, neither plum nor a ghost. */
  /* Door buttons. Ink on the fill, per the palette: dark ink on light accents.
     Inside uses --in-lite rather than raw Green because on a dark ground the
     button-vs-section boundary needs 3.0 and the raw accent does not clear it.

     v1.28.7 — these are now the CROSS-DOOR buttons as well as a door's own
     secondary actions. The door CTA's primary button is .btn-peri (Mustard),
     because "Start a conversation" goes to Contact, which is neutral. A button
     wears the colour of WHERE IT TAKES YOU, not the page it sits on. */
  .btn-in{background:var(--in-lite);color:var(--in-ink);border:1px solid var(--in-lite);}
  .btn-in:hover{background:var(--in-onsoft);border-color:var(--in-onsoft);color:var(--in-ink);}
  /* Raw Periwinkle on white or on a light-ish dark ground. On the Outside page's
     flat charcoal this is fine; do NOT use it on the Inside gradient — see below. */
  .btn-out{background:var(--out);color:var(--out-paper);border:1px solid var(--out);}
  /* v1.28.7 FIX: this hover was #FFD84A, a Mustard left behind when Outside moved
     off yellow onto Periwinkle. Hovering a blue button turned it yellow. It now
     deepens, and white keeps its label at 6.91:1. */
  .btn-out:hover{background:var(--out-deep);border-color:var(--out-deep);color:var(--out-paper);}
  /* Periwinkle for a DARK ground, mirroring what --in-lite does for Green. Raw
     --out on the Inside page's gradient scores just 1.93:1 against charcoal-mid —
     worse than the .go button failure already logged in CLAUDE.md. This tint
     clears the boundary at 3.94:1 and reads its label at 6.32:1. */
  .btn-out-lite{background:var(--out-lite);color:var(--ink);border:1px solid var(--out-lite);}
  .btn-out-lite:hover{background:var(--out-onsoft);border-color:var(--out-onsoft);color:var(--ink);}
  .section-head{max-width:760px;}
  .section-head .eyebrow{color:var(--in-deep);}
  .section-head h2{font-size:clamp(40px,5.2vw,66px);line-height:1.0;letter-spacing:-.01em;color:var(--charcoal);margin-top:20px;}
  .section-head h2 em{font-style:normal;color:var(--in);}
  .crumbs{font-size:13px;font-weight:600;letter-spacing:.06em;margin-bottom:30px;opacity:.75;position:relative;z-index:1;}
  .crumbs a{cursor:pointer;text-decoration:none;border-bottom:1px solid currentColor;}
  .note{font-size:12.5px;opacity:.6;margin-top:18px;font-style:normal;}

  /* ---------- HOME hero ---------- */
  .hero{background:var(--charcoal);color:var(--dove);position:relative;overflow:hidden;min-height:78vh;display:flex;align-items:center;}
  .hero-bg{position:absolute;inset:0;pointer-events:none;}
  .hero-bg iframe{position:absolute;top:50%;left:50%;width:100vw;height:56.25vw;min-height:100%;min-width:177.78vh;transform:translate(-50%,-50%);border:0;}
  .hero-bg::after{content:"";position:absolute;inset:0;background:linear-gradient(100deg, rgba(43,41,48,.9) 25%, rgba(43,41,48,.58) 65%, rgba(43,41,48,.38));}
  .hero-rhino{position:absolute;left:-130px;top:-30px;width:520px;opacity:.10;pointer-events:none;z-index:1;
    filter:brightness(0) invert(1);animation:floaty 9s ease-in-out infinite;}
  /* The side padding matters: this element is <div class="wrap hero-inner">, and
     the shorthand below overrode .wrap's "0 32px" with a horizontal 0 — which is
     why the headline ran to within 1px of the screen edge on a 412px phone. */
  .hero-inner{position:relative;z-index:2;padding:124px 32px 116px;max-width:1160px;text-align:center;margin:0 auto;}
  .hero .eyebrow{color:var(--mustard);font-size:23px;letter-spacing:.22em;}
  .hero .eyebrow::before{display:none;}
  .hero h1{font-size:clamp(54px,7.2vw,112px);color:#fff;margin:20px 0 30px;line-height:.95;}
  .hero h1 em{font-style:normal;}
  .hero h1 .in{color:var(--in);} .hero h1 .out{color:var(--out);} .hero h1 .amp{color:#fff;}
  .hero p.global{font-size:23px;font-weight:300;max-width:680px;color:#EAEDF4;line-height:1.5;}
  .hero p.global b{font-weight:600;color:#fff;}
  /* Phones. The h1's clamp floor of 50px never scaled down, so on every handset
     the longest forced line ("brands matter") stayed 50px and filled the width.
     Below 560px it scales with the viewport instead, keeping a clear margin at
     every common width from 320px up. Verified 320-430px. */
  @media(max-width:560px){
    .hero-inner{padding:74px 22px;}
    .hero h1{font-size:clamp(32px,10.5vw,50px);}
    .hero p.global{font-size:19px;}
    /* The base .eyebrow phone step can't reach this one: .hero .eyebrow is the
       more specific selector, so it needs its own. */
    .hero .eyebrow{font-size:16px;letter-spacing:.16em;}
  }

  /* White background. Door words in their door colours, plain text, no boxes:
     your people = Teal, your customers = Mustard. */
  .intro{background:#fff;padding:96px 0 80px;text-align:center;}
  .intro .eyebrow{color:var(--in-deep);}
  .intro p.lede{font-family:var(--display);font-size:clamp(28px,3.6vw,46px);font-weight:600;text-transform:uppercase;letter-spacing:-.01em;line-height:1.1;max-width:980px;margin:26px auto 30px;color:var(--charcoal);}
  .intro p.lede .ld-in{color:var(--in);} .intro p.lede .ld-out{color:var(--out);}
  .intro p.lede b{font-weight:600;color:var(--charcoal);}
  /* The commercial line under the big statement. Body face, not display, so it
     reads as the argument rather than a second headline competing with it. */
  .intro p.lede-sub{font-size:clamp(18px,1.9vw,21px);font-weight:300;line-height:1.55;
    max-width:760px;margin:0 auto 34px;color:#3C4354;}
  .intro p.lede-sub b{font-weight:600;color:var(--charcoal);}
  .intro-actions{display:flex;gap:14px;flex-wrap:wrap;justify-content:center;}
  .intro-detail{display:flex;flex-direction:column;gap:14px;max-width:880px;margin:0 auto 36px;}
  .intro-detail p{font-size:clamp(18px,2vw,22px);font-weight:300;color:#3C4354;line-height:1.5;}
  .intro-detail p b{font-weight:600;color:var(--charcoal);}

  /* ---------- showreel ---------- */
  .reel{background:#fff;padding:10px 0 96px;}
  /* Showreel hidden (home_show_reel off): .intro inherits the bottom padding
     .reel used to carry, so the white band still clears the dark .clients
     section by the same amount. 80 + 10 + 96 = 186. */
  .intro-noreel{padding-bottom:186px;}
  @media(max-width:880px){ .intro-noreel{padding-bottom:120px;} }
  .reel .frame{position:relative;border-radius:0;overflow:hidden;box-shadow:0 26px 60px rgba(14,19,30,.3);
    aspect-ratio:16/9;background:var(--charcoal-deep);}
  .reel iframe{position:absolute;inset:0;width:100%;height:100%;border:0;}
  /* ---------- client logos ----------
     Moved up from the .voices band on 2026-08-20 so credibility lands early.
     Dark ground, because the logo files are knocked to white — see the note on
     .marquee below. The band butts straight up under the showreel, which sits
     on white, so the tonal step is the separator and no rule is needed. */
  .clients{background:var(--charcoal-deep);color:var(--dove);padding:56px 0 60px;text-align:center;}
  .clients .eyebrow{color:var(--mustard);}
  @media(max-width:880px){ .clients{padding:42px 0 46px;} }
  /* The .marquee-clients size overrides live down with .marquee itself, not
     here: they are modifiers of it and have the same specificity, so declared
     up here they would simply be overwritten by the base rules below. */

  .reel .reel-tag{position:absolute;top:20px;left:22px;z-index:2;background:rgba(14,19,30,.72);color:var(--dove);
    backdrop-filter:blur(6px);font-size:12px;font-weight:700;letter-spacing:.22em;text-transform:uppercase;border-radius:0;padding:8px 16px;}

  /* ---------- doors ----------
     v1.18.0: the intro and the two cards sit on ONE charcoal block, approved
     from the palette review. Previously the Inside door was a white card on a
     white ground and the Outside door was charcoal, so the pair read as two
     unrelated things rather than one choice. Now the ground is shared, the gap
     closes to a single hairline, and each door is told apart by its accent
     alone — which is the point the section is making. */
  .doors-intro{background:var(--charcoal-deep);padding:84px 0 50px;text-align:center;}
  .doors-intro .section-head{margin:0 auto;}
  .doors-section{background:var(--charcoal-deep);padding:0 0 100px;}
  .doors{display:grid;grid-template-columns:1fr 1fr;gap:0;max-width:1240px;margin:0 auto;padding:0 32px;}
  @media(max-width:880px){.doors{grid-template-columns:1fr;}}
  .door{border-radius:0;padding:64px 52px 56px;min-height:560px;
    display:flex;flex-direction:column;align-items:center;text-align:center;justify-content:space-between;gap:32px;
    position:relative;overflow:hidden;transition:transform .3s, box-shadow .3s, filter .25s;cursor:pointer;text-decoration:none;}
  .door:hover{transform:translateY(-8px);box-shadow:0 24px 56px rgba(14,19,30,.22);filter:brightness(1.03);}
  .door .door-rhino{position:absolute;right:-70px;bottom:-40px;width:300px;opacity:.07;pointer-events:none;}
  /* A single hairline frame set in from each edge — the one quiet cue that makes
     each panel read as a door. No mouldings, shadows or handle; it just reads as
     a door edge, and brightens a touch on hover. Sits in the empty padding, well
     clear of the text. */
  .door::before{content:"";position:absolute;inset:22px;border:1px solid rgba(251,250,247,.14);
    pointer-events:none;transition:border-color .25s;}
  .door:hover::before{border-color:rgba(251,250,247,.28);}
  @media(max-width:560px){.door::before{inset:14px;}}
  .door .tag{font-size:12px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;padding:7px 16px;border-radius:0;width:max-content;margin:0 auto;}
  .door h2{font-size:clamp(32px,3.4vw,48px);margin:18px 0 12px;}
  .door p.who{font-size:18px;font-weight:600;margin-bottom:8px;}
  .door p.desc{font-size:16px;max-width:420px;margin:0 auto;}
  .door ul{list-style:none;margin:24px auto 0;display:grid;grid-template-columns:auto auto;gap:9px 30px;
    font-size:14.5px;font-weight:500;text-align:left;width:max-content;max-width:100%;}
  .door ul li::before{content:"•";margin-right:10px;}
  /* Was #09626A, which was Teal darkened for the old white Inside card. On the
     shared charcoal ground that is 1.70:1 — the bullets would vanish. */
  .door-in ul li::before{color:var(--in-lite);}
  .door-out ul li::before{color:var(--out);}
  .door .go{font-weight:700;font-size:15px;display:inline-flex;align-items:center;gap:10px;position:relative;z-index:1;
    border:1.5px solid currentColor;border-radius:0;padding:13px 30px;
    transition:background .2s,border-color .2s,color .2s;}
  .door .go::after{content:"→";transition:transform .2s;}
  .door:hover .go::after{transform:translateX(6px);}
  /* Both doors are now transparent on the shared charcoal ground, separated by
     a hairline rather than a gutter. Every accent below is a LIGHT tone,
     because everything here sits on Charcoal-deep: Teal-lite 6.15:1 and brand
     Mustard 9.64:1. The old Inside values (#09626A on white) would be 1.7:1. */
  .door-in, .door-out{background:transparent;color:var(--dove);}
  .door-in h2, .door-out h2{color:#fff;}
  .door-out{border-left:1px solid rgba(251,250,247,.20);}
  @media(max-width:880px){
    .door-out{border-left:0;border-top:1px solid rgba(251,250,247,.20);}
  }
  .door-in .tag{background:var(--in);color:#0C2B2E;}
  .door-in h2 em{color:var(--in-lite);} .door-in .go{color:var(--in-lite);}
  .door-in:hover .go{background:var(--in);border-color:var(--in);color:var(--in-ink-door);}
  .door-out .tag{background:var(--out);color:#fff;}
  /* The .go label is 15px/700 on the charcoal-deep ground, which WCAG counts as
     normal text, so it needs 4.5:1. Base --out gave only 3.05:1 and
     failed; --out-lite gives 6.23:1. This is the rule stated in :root,
     that --out is ink for light grounds and --out-lite is required
     on dark ones. The Inside door already did this with --in-lite on the line
     above, at 7.06:1, so this also makes the two doors consistent.
     The h2 em stays on base --out: it is large text, where the 3:1
     threshold applies and 3.05:1 passes. */
  .door-out h2 em{color:var(--out);} .door-out .go{color:var(--out-lite);}
  .door-out:hover .go{background:var(--out);border-color:var(--out);color:var(--out-paper);}
  /* The watermark rhino is knocked out to white on both sides now that both
     sides are dark; on the old white Inside card it had to stay dark. */
  .door-in .door-rhino, .door-out .door-rhino{filter:brightness(0) invert(1);opacity:.07;}
  /* The lift needs no shadow on a dark ground — a drop shadow on charcoal is
     invisible, and brightness() on a transparent card does nothing. */
  .door:hover{box-shadow:none;filter:none;}
  /* Mobile. The service list's two "auto" tracks give it a min-content width
     wider than a phone, and a grid item won't shrink below its min-content —
     so the card forced itself past its own 1fr track and scrolled the whole
     page sideways (nothing sets overflow-x, so it was a real scroll, not a
     clip). One track fixes the cause; the padding, which took 104px out of a
     390px screen, and the 560px min-height are just desktop values that never
     had a mobile counterpart. */
  @media(max-width:880px){
    .door{padding:44px 24px 40px;min-height:0;gap:24px;}
    /* "Step through the Outside door" was wrapping to two lines. Full width and
       nowrap keeps it on one line and gives a bigger tap target; the font scales
       so it still fits the card down to 320px. */
    .door .go{display:flex;width:100%;justify-content:center;white-space:nowrap;
      padding:14px 12px;font-size:clamp(12.5px,3.5vw,15px);gap:8px;}
    .door ul{grid-template-columns:1fr;width:100%;margin:20px 0 0;}
  }

  /* ---------- proof ---------- */
  .proof{background:#fff;padding:96px 0;}
  .proof-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:48px;margin-top:54px;}
  @media(max-width:880px){.proof-grid{grid-template-columns:1fr;}}
  .stat{border-top:3px solid var(--charcoal-mid);padding-top:24px;}
  .stat:nth-child(2){border-color:var(--mustard);} .stat:nth-child(3){border-color:var(--in);}
  .stat .num{font-family:var(--display);font-size:64px;line-height:1;color:var(--charcoal);}
  .stat .num small{font-size:26px;}
  .stat h3{font-family:var(--body);font-size:16px;font-weight:700;margin:14px 0 8px;line-height:1.4;}
  .stat p{font-size:15px;color:#575E6D;}

  /* ---------- how ---------- */
  .how{background:var(--dipse);padding:96px 0;}
  .how-grid{display:grid;grid-template-columns:1.1fr 1fr;gap:72px;align-items:start;}
  @media(max-width:880px){.how-grid{grid-template-columns:1fr;}}
  .how h2{font-size:clamp(40px,5.2vw,66px);line-height:1.0;letter-spacing:-.01em;color:var(--charcoal);}
  .how h2 em{font-style:normal;color:var(--in);}
  .how .eyebrow{color:var(--charcoal-soft);}
  .how p.big{font-size:20px;font-weight:300;color:#3C4354;margin-top:22px;}
  .how p.big b{font-weight:600;color:var(--charcoal);}
  .pillars{display:grid;gap:14px;}
  .pillar{background:#fff;border-radius:0;padding:20px 24px;display:flex;gap:18px;align-items:baseline;box-shadow:0 2px 10px rgba(43,41,48,.06);}
  .pillar .side{font-size:11px;font-weight:700;letter-spacing:.2em;text-transform:uppercase;min-width:90px;}
  .pillar.in .side{color:var(--in-deep);} .pillar.out .side{color:var(--out);}
  .pillar p{font-size:15px;} .pillar p b{font-weight:600;}

  /* ---------- work grids ---------- */
  .work{padding:96px 0;background:var(--charcoal);color:var(--dove);}
  .work .section-head .eyebrow{color:var(--mustard);}
  .work .section-head h2{color:#fff;} .work .section-head h2 em{color:var(--mustard);}
  .work-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;margin-top:54px;}
  @media(max-width:880px){.work-grid{grid-template-columns:1fr;}}
  .case{border-radius:0;overflow:hidden;background:var(--charcoal-soft);color:var(--dove);display:flex;flex-direction:column;
    min-height:400px;text-decoration:none;transition:transform .25s, box-shadow .25s;position:relative;cursor:pointer;}
  .case:hover{transform:translateY(-7px);box-shadow:0 22px 50px rgba(20,12,25,.45);}
  .case.hidden{display:none;}
  .case .visual{height:190px;position:relative;overflow:hidden;background:var(--charcoal-deep);}
  .case .visual img{width:100%;height:100%;object-fit:cover;transition:transform .6s cubic-bezier(.22,.61,.36,1);}
  .case:hover .visual img{transform:scale(1.06);}
  .case .body{padding:24px 26px 28px;display:flex;flex-direction:column;gap:11px;flex:1;}
  /* Client name (Our Work) and category tag (News) are metadata, not a door
     signal — so neutral, letting the Inside/Outside badge be the only door
     colour on the card. --mute-onsoft is 4.87:1 on the #54515A cards, where the
     door colours can't safely go anyway. */
  .case .client{font-size:12px;font-weight:700;letter-spacing:.22em;text-transform:uppercase;color:var(--mute-onsoft);}
  .case h3{font-family:var(--display);font-weight:600;font-size:21px;line-height:1.24;color:#fff;}
  .case .result{margin-top:auto;font-size:14px;color:var(--teal-onsoft);font-weight:600;}
  .badges{display:flex;gap:8px;position:absolute;top:14px;left:14px;z-index:2;}
  .badge{font-size:10.5px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;border-radius:0;padding:5px 12px;}
  .badge.bin{background:rgba(245,244,240,.95);color:var(--in-deep);}
  .badge.bout{background:rgba(43,41,48,.88);color:var(--out);}
  .badge.bview{background:var(--charcoal);color:#fff;}
  .filters{display:flex;gap:10px;margin-top:44px;flex-wrap:wrap;}
  .filters button{font-family:var(--body);font-size:14px;font-weight:600;letter-spacing:.04em;cursor:pointer;
    background:transparent;border:1.5px solid rgba(232,237,235,.4);color:var(--dove);border-radius:0;padding:10px 24px;transition:all .2s;}
  .filters button:hover{border-color:var(--mustard);color:#fff;}
  .filters button.on{background:var(--charcoal);border-color:var(--charcoal);color:#fff;}
  .news-card .visual{height:200px;}
  .news-card h3{font-size:20px;}
  .news-card .date{font-size:13px;color:var(--teal-onsoft);font-weight:600;margin-top:auto;}

  /* ---------- voices ---------- */
  /* Separated from the doors block above by a step in tone, not a rule.
     Since v1.18.0 the doors sit on Charcoal-deep, and this section was on the
     same value — so the two ran together as one endless dark slab with no edge.
     Charcoal (#413E45) against Charcoal-deep (#2B2930) is a quiet but real
     step, and it leaves the page reading darkest -> dark -> white into the CTA.

     Why not move this block to Dipse, which would have separated them far more
     strongly: the client logos below are knocked out to white
     (.marquee img{filter:brightness(0) invert(1)}) so they need a dark ground,
     and the yellow accent measures 1.00:1 on Dipse. Both would have had to be
     re-treated. Kept dark; the tone step does the job. */
  .voices{background:var(--charcoal);color:var(--dove);padding:96px 0 86px;}
  .voices .eyebrow{color:var(--mustard);}
  .voices h2{font-size:clamp(40px,5.2vw,66px);line-height:1.0;letter-spacing:-.01em;color:#fff;margin-top:20px;}
  .voices h2 em{font-style:normal;color:var(--mustard);}
  .quote-grid{display:grid;grid-template-columns:1fr 1fr;gap:28px;margin-top:54px;}
  @media(max-width:880px){.quote-grid{grid-template-columns:1fr;}}
  .quote{background:var(--charcoal-soft);border-radius:0;padding:34px 36px;}
  .quote p.q{font-family:var(--body);font-weight:400;font-style:normal;font-size:22px;line-height:1.4;color:#fff;}
  .quote .who{margin-top:22px;font-size:14px;} .quote .who b{display:block;font-size:15px;color:var(--mustard);font-weight:600;}
  .marquee{overflow:hidden;margin-top:70px;-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);}
  /* 40s read as static — the eye filed it as furniture and the client names
     never announced themselves. 26s is still calm but reads as alive. */
  .marquee .track{display:flex;gap:110px;width:max-content;align-items:center;animation:marquee 26s linear infinite;}
  .marquee:hover .track{animation-play-state:paused;}
  .marquee img{height:138px;width:auto;filter:brightness(0) invert(1);opacity:.65;transition:opacity .25s;}
  .marquee img:hover{opacity:1;}
  .marquee-light{margin-top:56px;-webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);}
  .marquee-light .track{animation-duration:28s;gap:44px;}
  .marquee-light img{filter:none;opacity:1;height:180px;background:#fff;border-radius:0;padding:20px 32px;box-shadow:0 2px 14px rgba(43,41,48,.09);}
  /* The homepage strip, in its new home under the showreel. 180px, up from the
     138px it ran at when it was buried at the foot of the page: Owen's note was
     that the client list has to carry weight this high up, and at 138px on a
     wide viewport it read as a footnote. Opacity lifted from .65 to .8 for the
     same reason, and the gap widened with the height so the scroll keeps its
     rhythm. Treatment is unchanged — still knocked to white on a dark ground. */
  .marquee-clients{margin-top:34px;}
  /* SPEED IS SET PER BREAKPOINT HERE, not inherited from .marquee's 26s.
     James, 2026-10-21: the strip was running too fast. Measured rather than
     eyeballed — at 1440px the track is 12,588px wide, so a 26s cycle is
     6,294px in 26s = 242px/sec, and a logo crossed the screen in 5.9s.
     The 26s base was chosen when these logos were 138px tall; they are now
     180px with 130px gaps, which widened the track by roughly a third and
     made the same duration read far quicker. The old note on .marquee about
     40s "reading as static" was a judgement made at that narrower width and
     does not transfer.
     45s puts it at 140px/sec. Mobile needs its own number or it would crawl:
     the track there is only 4,093px, so 45s would be 91px/sec. 32s holds it
     at 128px/sec, so the strip feels the same speed on a phone as on a laptop.
     To retune, change the duration and keep an eye on px/sec, not the seconds. */
  .marquee-clients .track{gap:130px;animation-duration:45s;}
  .marquee-clients img{height:180px;opacity:.8;}
  @media(max-width:880px){
    .marquee-clients .track{gap:80px;animation-duration:32s;}
    .marquee-clients img{height:120px;}
  }

  /* ---------- CTA / footer ---------- */
  .cta{padding:110px 0;background:#fff;text-align:center;position:relative;overflow:hidden;}
  .cta h2{font-size:clamp(36px,5vw,60px);color:var(--charcoal);position:relative;z-index:1;}
  .cta h2 em{font-style:normal;color:var(--in);}
  .cta p{max-width:540px;margin:22px auto 34px;font-size:18px;color:#575E6D;position:relative;z-index:1;}
  .cta-rhino{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:520px;opacity:.05;pointer-events:none;}
  .cross{font-size:15px;margin-top:30px;opacity:.85;}
  .cross a{cursor:pointer;font-weight:600;}
  footer{background:var(--charcoal-deep);color:rgba(232,237,235,.7);padding:54px 0;font-size:14px;}
  /* Two columns: the brand block (logo, address, registration) on the left, and a
     right-hand column that stacks the nav above the legal line — so the copyright
     and Privacy Policy sit up under the nav rather than stranded at the bottom
     right. Both columns are top-aligned, so any slack falls to the bottom. */
  /* stretch, not flex-start: the right column has to fill the row's height for the
     Switchboard link's margin-top:auto to have any slack to push into. The left column
     is the taller of the two, so the bottom of the row IS the bottom of the registration
     line, which is what the link lines up against. */
  .foot-grid{display:flex;justify-content:space-between;align-items:stretch;gap:40px 60px;}
  .foot-brand{max-width:360px;}
  .footlogo{height:36px;width:auto;}
  .foot-right{display:flex;flex-direction:column;align-items:flex-end;gap:24px;text-align:right;}
  footer nav{display:flex;gap:22px;flex-wrap:wrap;justify-content:flex-end;}
  footer nav a{text-decoration:none;cursor:pointer;}
  footer nav a:hover{color:#fff;}
  .foot-reg{margin-top:12px;max-width:340px;font-size:12.5px;line-height:1.5;color:rgba(232,237,235,.5);}
  .foot-legal{text-align:right;}
  .foot-legal-links{margin-top:14px;}
  .foot-legal-links a{color:rgba(232,237,235,.7);text-decoration:none;}
  .foot-legal-links a:hover{color:#fff;}
  /* Switchboard: the in-house tool index. It stays in the right column, under Privacy Policy,
     but margin-top:auto drops it to the foot of that column so it sits level with the bottom
     of the registration line opposite. It takes the footer's own 14px and Privacy Policy's .7
     alpha (6.73:1) rather than .foot-reg's 12.5px/.5 — that small print blends to 4.21:1,
     which fails AA for a link, and at two different sizes the two links read as a mistake
     rather than a hierarchy. It belongs to neither door, so Mustard on hover is the neutral
     voice: 9.65:1 here, and only ever safe on a dark ground. */
  /* top:-3px is a real nudge, not a fudge. margin-top:auto pins the BOX bottom to the row
     bottom, but the eye reads the TEXT bottom, and this link's line box is 22.4px against the
     registration line's 18.75px — so identical box bottoms leave the text sitting 2.9px low.
     Relative positioning is the one offset that does not feed back into layout: a margin here
     would make the right column taller, push the row bottom down by the same amount, and
     cancel itself out. Re-measure if either font size or line-height changes. */
  .foot-switchboard{margin-top:auto;padding-top:16px;position:relative;top:-3px;}
  .foot-switchboard a{color:rgba(232,237,235,.7);text-decoration:none;}
  .foot-switchboard a:hover{color:var(--mustard);}
  /* Hierarchy on smaller screens: the two columns become one, reading top to
     bottom as brand -> nav -> legal, and the right column flips to left-aligned
     so it all runs down the left edge in a natural order. */
  @media(max-width:820px){
    .foot-grid{flex-direction:column;}
    .foot-right{align-items:flex-start;text-align:left;}
    footer nav{justify-content:flex-start;}
    .foot-legal{text-align:left;}
  }

  /* ---------- Legal / document page (Privacy Policy) ---------- */
  .legal-page .legal-head{background:#fff;padding:64px 0 6px;}
  .legal-page .legal-head .crumbs{color:#8A8F9A;font-size:14px;margin:0 0 14px;}
  .legal-page .legal-head .crumbs a{color:var(--charcoal);text-decoration:none;}
  .legal-page .legal-head h1{font-size:clamp(32px,5vw,50px);line-height:1.05;color:var(--charcoal);margin:0;}
  .legal-wrap{background:#fff;padding:18px 0 90px;}
  .legal-wrap .wrap{max-width:860px;}
  .legal-wrap h2{font-size:22px;line-height:1.25;color:var(--charcoal);margin:38px 0 12px;}
  .legal-wrap h3{font-size:17px;line-height:1.3;color:var(--charcoal);margin:26px 0 8px;}
  .legal-wrap p{margin:0 0 15px;line-height:1.7;color:#3C4354;}
  .legal-wrap ul{margin:0 0 18px;padding-left:22px;}
  .legal-wrap li{margin:0 0 9px;line-height:1.6;color:#3C4354;}
  .legal-wrap a{color:var(--charcoal-deep);word-break:break-word;}
  .legal-wrap .legal-meta{background:var(--paper);border-left:3px solid var(--charcoal-mid);padding:16px 20px;margin:0 0 26px;font-size:15px;}
  .legal-wrap .legal-meta p{margin:0 0 4px;}

  /* ---------- page heroes / themes ---------- */
  .page-hero{padding:96px 0 80px;position:relative;overflow:hidden;}
  .page-hero .hero-rhino{top:-30px;left:-110px;width:440px;}
  .page-hero h1{font-size:clamp(40px,5.4vw,68px);margin:24px 0 24px;max-width:900px;position:relative;z-index:1;}
  .page-hero p.lede{font-size:20px;font-weight:300;max-width:660px;position:relative;z-index:1;}
  .t-charcoal{background:var(--charcoal);color:var(--dove);}
  .t-charcoal .eyebrow{color:var(--mustard);}
  .t-charcoal h1,.t-charcoal h2{color:#fff;}
  .t-charcoal h1 em,.t-charcoal h2 em{font-style:normal;color:var(--mustard);}

  /* ---------- the neutral voice ----------
     Scoped to body.tmg-neutral (see maverick_tmg_neutral_body_class), NOT to
     .t-charcoal, which single case studies and news articles also use.

     The eyebrows (the small dash-led kickers) are deliberately NOT the accent
     colour: they read back to Charcoal on light grounds and white on dark. The
     accent is reserved for the big heading accents (the <em> words) and the
     CTAs, so it stays a highlight rather than colouring every label.

     The hero eyebrow is the deliberate exception and is NOT overridden here —
     .hero .eyebrow stays brand Mustard on the film, which is the one line
     James asked to keep yellow as the site's central colour.

     v1.18.0 swapped the accent Periwinkle -> Mustard, mapping each rule by the
     ground it sits on. v1.19.0 collapsed that: the accent is brand yellow on
     EVERY ground, per James. Only the fills still vary, because they must —
     a yellow fill takes --ink text, never white.

     So the light-ground rules below are now decorative rather than legible
     (1.49:1 on white, 1.43:1 on Dove, 1.00:1 on Dipse). That is a known,
     accepted trade being handled separately; see the --mustard note in :root
     before changing any of them back. */
  body.tmg-neutral .t-charcoal .eyebrow{color:#fff;}
  body.tmg-neutral .t-charcoal h1 em,
  body.tmg-neutral .t-charcoal h2 em{color:var(--mustard);}
  /* Big heading accent on light sections. */
  body.tmg-neutral .section-head .eyebrow{color:var(--charcoal);}
  body.tmg-neutral .section-head h2 em{color:var(--mustard);}
  body.tmg-neutral .cta h2 em{color:var(--mustard);}
  /* The per-section accents. These carry their own colours rather than
     inheriting, so each needs naming. All on white.
     .belief in particular MUST stay scoped — Inside and Outside use it too. */
  body.tmg-neutral .belief .big em,
  body.tmg-neutral .who-act-h em{color:var(--mustard);}
  /* .mb-info lives inside .map-band, which is now Charcoal (v1.24.0): white text
     with the Mustard accent, which is 9.64:1 on Charcoal and reads clearly — the
     old Dipse ground was what made the same Mustard unreadable at 1.00:1. */
  body.tmg-neutral .mb-info h2 em{color:var(--mustard);}
  /* Small eyebrows -> Charcoal (see the note at the top of this block). The
     Global reach eyebrow is the exception: its band is dark, so it goes light. */
  body.tmg-neutral .intro .eyebrow{color:var(--charcoal);}
  body.tmg-neutral .mb-info .eyebrow{color:#C6CCDA;}
  /* .how is the one section on Dipse, not white — the worst ground for yellow
     (1.00:1). Its eyebrow is left alone: --charcoal-soft is a grey, so it was
     never wearing a door's colour to begin with. */
  /* No accent colour at all — the same --charcoal as the rest of the
     heading, so the line reads as one sentence. Yellow was 1.00:1 on Dipse. */
  body.tmg-neutral .how h2 em{color:var(--charcoal);}
  /* .voices is dark, so brand Mustard goes straight on at 9.64:1 — no tint
     needed, unlike Periwinkle which could not survive a dark ground at all.
     Eyebrow stays white (small kicker). */
  body.tmg-neutral .voices .eyebrow{color:#fff;}
  body.tmg-neutral .voices h2 em{color:var(--mustard);}
  /* .t-in-alt is a white band used on Join us and Who we are. Its h2 em beat
     .roles-h em on specificity, so "Maverick role?" was still Teal. Named here
     rather than relying on the .section-head rule, which this h2 sits outside. */
  body.tmg-neutral .t-in-alt h2 em{color:var(--mustard);}
  /* .roles is a dark --charcoal card sitting INSIDE that white band, so the rule
     directly above would reach it too. Same specificity as that rule (0,2,3),
     so this must stay below it to win. */
  body.tmg-neutral .roles h2 em{color:var(--mustard);}
  body.tmg-neutral .role-line a{color:var(--mustard);}
  /* Homepage Proof carousel heading — white ground. */
  body.tmg-neutral .proof h2 em{color:var(--mustard);}
  /* The rest of the Proof block. The heading alone wasn't enough — its eyebrow,
     arrows and dots were all still in the Teal family, which is why the section
     still read as Inside. All on white. */
  body.tmg-neutral .proof .eyebrow{color:var(--charcoal);}
  body.tmg-neutral .proof .car-dots{color:var(--mustard);}
  body.tmg-neutral .proof .pc-nav button{color:var(--mustard);}
  body.tmg-neutral .proof .pc-nav button:hover{background:var(--mustard);color:var(--ink);border-color:var(--mustard);}
  /* The doors intro moved onto Charcoal-deep in v1.18.0, so the two
     .section-head rules above — Charcoal eyebrow and accent em, both written
     for a white ground — would be near-invisible on it. This sits below them at
     the same specificity so it wins on order. */
  body.tmg-neutral .doors-intro .eyebrow{color:#fff;}
  body.tmg-neutral .doors-intro h2{color:#fff;}
  body.tmg-neutral .doors-intro h2 em{color:var(--mustard);}
  /* Contact's stat figures sit on Dipse — same reasoning as .how above. */
  body.tmg-neutral .mb-stats .num{color:var(--mustard);}
  /* Quote author on the dark .voices band. */
  body.tmg-neutral .quote-slide .who{color:var(--mustard);}
  /* .case .client and .read went to --mute-onsoft (see those rules) — neutral
     metadata, not a door colour. Periwinkle can't live on the #54515A cards
     (1.65:1), so the neutral grey does the job there at 4.87:1. */
  /* The homepage hero is deliberately excluded: INSIDE&OUT and the door cards
     name the doors, so they keep the doors' colours. Same for .intro's
     .ld-in / .ld-out, which are the words "Inside" and "Outside" themselves. */
  .t-charcoal .hero-rhino{filter:brightness(0) invert(1);opacity:.09;}
  .t-in{background:linear-gradient(145deg,var(--charcoal-deep) 0%,var(--charcoal-shade) 55%,var(--charcoal-mid) 100%);color:var(--dove);}
  .t-in .eyebrow{color:var(--in-lite);}
  .t-in h1,.t-in h2{color:#fff;}
  .t-in h1 em,.t-in h2 em{font-style:normal;color:var(--in);}
  .t-in p.lede{color:#E3E9F2;}
  .t-in .hero-rhino{filter:brightness(0) invert(1);opacity:.10;}
  .t-in-solid{background:var(--charcoal-deep);color:var(--dove);}
  .t-in-solid .eyebrow{color:var(--in-lite);}
  .t-in-solid h2{color:#fff;} .t-in-solid h2 em{font-style:normal;color:var(--in);}
  .t-in-alt{background:var(--paper);color:var(--ink);}
  .t-out{background:var(--charcoal);color:var(--dove);}
  .t-out .eyebrow{color:#fff;}
  .t-out h1,.t-out h2{color:#fff;}
  .t-out h1 em,.t-out h2 em{font-style:normal;color:var(--out);}
  .t-out p.lede{color:#E3E9F2;}
  .t-out .hero-rhino{filter:brightness(0) invert(1);opacity:.10;}
  .t-out-alt{background:var(--charcoal-deep);color:var(--dove);}
  .t-out-alt .eyebrow{color:#fff;}

  /* ---------- door hero background image (placeholder) ---------- */
  .page-hero{isolation:isolate;}
  .page-hero .wrap{position:relative;z-index:2;}
  /* A <picture>, not a background-image: background-image can't carry a srcset,
     so phones were downloading the full desktop file. object-fit:cover
     reproduces what background-size:cover did, and the optional mobile <source>
     changes the crop rather than the fit. */
  .hero-photo{position:absolute;inset:0;z-index:0;display:block;pointer-events:none;}
  /* Optional header film. Same cover-fill technique as the homepage hero: size
     to the wider of 100vw / 177.78vh so the 16:9 player always overfills the
     box, then centre it. It sits above the poster image and below .hero-scrim,
     so the readability wash stays the editor-controlled one. */
  .hero-film{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;}
  .hero-film iframe{position:absolute;top:50%;left:50%;width:100vw;height:56.25vw;
    min-height:100%;min-width:177.78vh;transform:translate(-50%,-50%);border:0;}
  /* Respect a reduced-motion preference: fall back to the still poster. */
  @media (prefers-reduced-motion: reduce){ .hero-film{display:none;} }
  .hero-photo img{width:100%;height:100%;object-fit:cover;object-position:center;}
  /* Give heroes that carry background media more height, so wide images
     (e.g. the team grid) aren't cropped so tightly. Content stays vertically
     centred. Plain colour heroes are unaffected.
     .hero-film is matched as well as .hero-photo: a page with a film but no
     poster image (Our work) renders no .hero-photo at all, so keying on the
     poster alone left it with no min-height and a header ~200px short. */
  .page-hero:has(.hero-photo), .page-hero:has(.hero-film){min-height:640px;display:flex;flex-direction:column;justify-content:center;}
  /* The flex container above changes what .wrap's "margin:0 auto" means: in
     block layout auto margins fill to max-width then centre, but on a flex
     item they make it SHRINK TO FIT its content and centre that. The wrap
     collapsed to ~964px, pushing the hero copy ~138px right of the logo and of
     every section below. width:100% restores block-like sizing so the hero
     lines up with the masthead again. */
  .page-hero:has(.hero-photo) > .wrap, .page-hero:has(.hero-film) > .wrap{width:100%;}
  @media(max-width:880px){ .page-hero:has(.hero-photo), .page-hero:has(.hero-film){min-height:460px;} }
  @media(max-width:560px){ .page-hero:has(.hero-photo), .page-hero:has(.hero-film){min-height:380px;} }

  /* Readability scrim over any header image; its opacity is editor-controlled
     via the "Header image overlay" field so the heading stays legible. */
  .hero-scrim{position:absolute;inset:0;z-index:0;pointer-events:none;
    background:linear-gradient(100deg, rgba(43,41,48,.98) 12%, rgba(43,41,48,.72) 52%, rgba(43,41,48,.32) 100%);}
  @media(max-width:880px){
    .hero-scrim{background:linear-gradient(180deg, rgba(43,41,48,.68) 0%, rgba(43,41,48,.92) 100%);}
  }

  /* ---------- pains carousel ---------- */
  .pains{padding:90px 0;}
  .pains h2{font-size:clamp(30px,3.6vw,44px);margin-top:20px;max-width:680px;}
  .pc-head{display:flex;justify-content:space-between;align-items:flex-end;gap:24px;flex-wrap:wrap;}
  .pc-nav{display:flex;gap:10px;}
  /* Square, not round, and actually centred.
     These were 46px circles with the glyph positioned by the button's default
     baseline, which sat it low and slightly left — it read as clunky because it
     genuinely was off-centre. inline-flex plus line-height:1 centres the arrow
     on both axes regardless of the font's metrics, and the square corners match
     the rest of the site, which has border-radius:0 on every other control. */
  .pc-nav button{width:46px;height:46px;border-radius:0;border:1.5px solid currentColor;background:transparent;
    color:inherit;font-size:18px;line-height:1;cursor:pointer;transition:all .2s;
    display:inline-flex;align-items:center;justify-content:center;padding:0;}
  /* Arrows are a desktop affordance: a mouse can't swipe. On a phone they
     duplicate a gesture the reader already has, and they sit up in .pc-head
     detached from the cards they move. The dots below are real buttons with
     labels and keyboard focus (see carouselDots in main.js), so nothing is
     lost by dropping the arrows here — touch and the dots both still work. */
  @media(max-width:880px){ .pc-nav{display:none;} }
  /* padding-top buys headroom for the .stat-card hover lift. overflow-x:auto
     forces overflow-y to compute to auto, so a card flush with the top edge
     gets its lift clipped. margin-top drops by the same 14px, so nothing on
     any of the three carousels using this class actually moves. */
  .pain-carousel{display:flex;gap:24px;overflow-x:auto;scroll-snap-type:x mandatory;margin-top:32px;
    padding-top:14px;padding-bottom:10px;scrollbar-width:none;}
  .pain-carousel::-webkit-scrollbar{display:none;}

  /* Position dots for the scroll-snap carousels (Sound familiar? and Proof).
     These have arrows but nothing said how many cards there are or where you
     are in them. Built by main.js from the real card count, and driven by
     scroll position rather than a counter, so dragging, arrows, keyboard and
     trackpad all stay in step. */
  .car-dots{display:flex;gap:8px;justify-content:center;margin-top:26px;}
  /* color:inherit matters — a <button> does NOT inherit colour (the UA sets
     color:buttontext), so without it currentColor resolves to black instead of
     the section's accent. */
  .car-dot{width:26px;height:3px;padding:0;border:none;border-radius:0;cursor:pointer;
    color:inherit;background:currentColor;opacity:.22;transition:opacity .2s;}
  .car-dot:hover{opacity:.5;}
  .car-dot.is-active{opacity:1;}
  .car-dot:focus-visible{outline:2px solid currentColor;outline-offset:4px;}
  /* Colour follows the section it sits in, like the arrows above it do. */
  .t-in-alt .car-dots{color:var(--charcoal-deep);}
  .t-out-alt .car-dots{color:var(--dove);}
  .proof .car-dots{color:var(--in);}
  /* One card per view on mobile, so the dots matter more there, not less. */
  @media(max-width:880px){ .car-dots{margin-top:22px;} }
  .pain{border-radius:0;padding:28px 30px;font-size:16.5px;line-height:1.55;
    flex:0 0 calc((100% - 48px)/3);scroll-snap-align:start;}
  @media(max-width:880px){.pain{flex:0 0 86%;}}
  .pain b{display:block;font-family:var(--display);font-weight:400;font-size:21px;margin-bottom:10px;line-height:1.25;}
  .t-out-alt .pain{background:var(--charcoal-soft);} .t-out-alt .pain b{color:#fff;}
  .t-out-alt .pc-nav button{color:var(--dove);} .t-out-alt .pc-nav button:hover{background:var(--dove);color:var(--ink);border-color:var(--dove);}
  .t-in-alt .pain{background:#fff;box-shadow:0 2px 12px rgba(43,41,48,.07);} .t-in-alt .pain b{color:var(--charcoal-deep);}
  .t-in-alt .pc-nav button{color:var(--charcoal-deep);} .t-in-alt .pc-nav button:hover{background:var(--charcoal-deep);color:#fff;}
  .t-in-alt .eyebrow{color:var(--charcoal-deep);}
  .t-in-alt h2{color:var(--charcoal);} .t-in-alt h2 em{font-style:normal;color:var(--in);}

  /* ---------- services ---------- */
  .services{padding:90px 0;}
  .svc-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin-top:50px;}
  @media(max-width:1020px){.svc-grid{grid-template-columns:repeat(2,1fr);}}
  @media(max-width:560px){.svc-grid{grid-template-columns:1fr;}}
  .svc{border-radius:0;padding:24px 22px;font-weight:600;font-size:15.5px;line-height:1.4;display:flex;flex-direction:column;gap:8px;min-height:130px;transition:transform .15s;}
  .svc:hover{transform:translateY(-3px);}
  .svc small{font-weight:400;font-size:13.5px;opacity:.78;line-height:1.5;}
  .svc .ico{width:46px;height:46px;border-radius:0;display:flex;align-items:center;justify-content:center;margin-bottom:6px;}
  .svc .ico svg{width:24px;height:24px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;}
  .t-out .svc{background:rgba(255,255,255,.07);color:var(--dove);border:1px solid rgba(255,255,255,.14);}
  .t-out .svc:hover{border-color:var(--out);}
  .t-out .svc .ico{background:rgba(var(--out-rgb),.20);color:var(--out);}
  .t-in-solid .svc{background:rgba(255,255,255,.07);color:var(--dove);border:1px solid rgba(255,255,255,.14);}
  .t-in-solid .svc:hover{border-color:var(--in);}
  .t-in-solid .svc .ico{background:rgba(var(--in-rgb),.20);color:var(--in);}

  /* ---------- door proof / cta ---------- */
  .door-proof{padding:90px 0;}
  .door-proof .two-col{display:grid;grid-template-columns:1.15fr .85fr;gap:34px;}
  @media(max-width:880px){.door-proof .two-col{grid-template-columns:1fr;}}

  /* ---------- proof carousel (Inside / Outside) ----------
     Three case studies rotating in place, added 2026-08-20. Slides are stacked
     in a single grid cell and cross-faded, the same mechanic as the homepage
     quote rotator, so the section height is set by the tallest slide and never
     jumps as it advances. Driven by fadeRotator() in main.js, which finds
     .fade-slide, .fade-dot, .fade-prev and .fade-next inside .proof-carousel. */
  .proof-carousel{margin-top:50px;}
  .proof-track{display:grid;}
  .proof-slide{grid-area:1 / 1;opacity:0;transition:opacity .9s ease;pointer-events:none;}
  .proof-slide.is-active{opacity:1;pointer-events:auto;}
  /* The lift belongs to the card, not the slide: hovering a fading slide should
     not move the whole row. */
  .proof-slide .case-feature{transition:transform .25s;}

  .proof-controls{display:flex;align-items:center;justify-content:center;gap:20px;margin-top:34px;}
  .proof-controls .fade-prev,.proof-controls .fade-next{
    width:46px;height:46px;border-radius:0;border:1.5px solid currentColor;background:transparent;
    color:inherit;font-size:18px;line-height:1;cursor:pointer;transition:all .2s;
    display:inline-flex;align-items:center;justify-content:center;padding:0;}
  .proof-dots{display:flex;gap:8px;}
  .proof-carousel .fade-dot{width:26px;height:3px;}

  /* Inside sits on a light ground and Outside on a dark one, so the controls
     take their colour from the section theme rather than being fixed. */
  .t-in-alt .proof-controls .fade-prev,.t-in-alt .proof-controls .fade-next{color:var(--charcoal-deep);}
  .t-in-alt .proof-controls .fade-prev:hover,.t-in-alt .proof-controls .fade-next:hover{background:var(--charcoal-deep);color:#fff;}
  .t-in-alt .proof-carousel .fade-dot{background:rgba(43,41,48,.20);}
  .t-in-alt .proof-carousel .fade-dot:hover{background:rgba(43,41,48,.42);}
  .t-in-alt .proof-carousel .fade-dot.is-active::after{background:var(--in-deep);}
  .t-out-alt .proof-controls .fade-prev,.t-out-alt .proof-controls .fade-next{color:var(--dove);}
  .t-out-alt .proof-controls .fade-prev:hover,.t-out-alt .proof-controls .fade-next:hover{background:var(--dove);color:var(--ink);}
  .t-out-alt .proof-carousel .fade-dot.is-active::after{background:var(--out-lite);}

  /* The dot fill is a progress bar for the auto-advance, so its duration has to
     match the interval fadeRotator was given. The quote rotator runs at 7s and
     owns the 7s default; these run at 9s. */
  .proof-carousel .fade-dot.is-active::after{animation-duration:9s;}
  .proof-carousel:hover .fade-dot.is-active::after{animation-play-state:paused;}
  @media(prefers-reduced-motion:reduce){
    .proof-carousel .fade-dot.is-active::after{animation:none;transform:scaleX(1);}
  }
  .mini-quote{border-radius:0;padding:34px 36px;}
  .mini-quote p.q{font-family:var(--body);font-weight:400;font-style:normal;font-size:22px;line-height:1.4;}
  .mini-quote .who{margin-top:20px;font-family:var(--body);font-weight:400;font-size:14px;opacity:.9;}
  .case-feature{border-radius:0;overflow:hidden;display:flex;flex-direction:column;cursor:pointer;transition:transform .25s;text-decoration:none;color:inherit;}
  .case-feature:hover{transform:translateY(-5px);}
  .case-feature .cf-img{height:220px;overflow:hidden;}
  .case-feature .cf-img img{width:100%;height:100%;object-fit:cover;}
  .case-feature .cf-body{padding:32px 36px 36px;display:flex;flex-direction:column;gap:13px;flex:1;}
  .case-feature .client{font-size:12px;font-weight:700;letter-spacing:.22em;text-transform:uppercase;}
  .case-feature h3{font-family:var(--display);font-size:28px;line-height:1.2;}
  .case-feature p{font-size:16px;}
  .case-feature .result{font-weight:700;font-size:15px;margin-top:6px;}
  .door-cta{padding:96px 0;text-align:center;}
  .door-cta h2{font-size:clamp(34px,4.6vw,56px);}
  .door-cta p{max-width:560px;margin:20px auto 32px;font-size:18px;}
  /* Cross-link: question on one line, the link on its own line beneath it,
     rather than letting the two run together and wrap mid-phrase.
     opacity is deliberately lifted here and the dimming moved onto the text
     colour instead: opacity composites the whole subtree, which would drag the
     link down with it and push it under the WCAG AA contrast threshold. The
     rgba below renders the question identically to the old opacity:.85. */
  .door-cta .cross{margin-top:30px;opacity:1;color:rgba(251,250,247,.85);}
  /* v1.28.7: the cross-link became a button, so it is inline-block rather than a
     block link, and the gap grew to give the two buttons room to read as a pair.
     The destination's colour is carried by .btn-in / .btn-out-lite on the anchor
     itself — see the door-CTA colour rule above .btn-peri. */
  .door-cta .cross a{display:inline-block;margin-top:14px;}
  /* The conversion CTA speaks the NEUTRAL voice even inside a door section, so this
     overrides .t-in h2 em / .t-out h2 em for this band only. 7.06:1 on Outside's flat
     charcoal, 6.10:1 at the lightest end of Inside's gradient. */
  .door-cta h2 em{color:var(--mustard);}

  /* ---------- detail pages ---------- */
  .detail-hero{padding:80px 0 56px;}
  .detail-hero .meta{display:flex;gap:22px;font-size:14px;font-weight:600;opacity:.85;flex-wrap:wrap;margin-top:20px;}
  .detail-img{border-radius:0;overflow:hidden;margin:0 auto;max-width:1176px;box-shadow:0 24px 60px rgba(14,19,30,.25);aspect-ratio:16/9;}
  .detail-img img{width:100%;height:100%;object-fit:cover;object-position:center;display:block;}
  @media(max-width:640px){.detail-img{aspect-ratio:4/3;}}
  .detail-pull{margin-top:-70px;position:relative;z-index:2;padding:0 32px;}
  article.body{max-width:1176px;margin:0 auto;padding:80px 32px 30px;font-size:18px;color:#3c3343;}
  article.body p{margin-bottom:26px;font-weight:300;line-height:1.75;}
  article.body h2{font-size:30px;color:var(--charcoal);margin:0 0 18px;}
  article.body h2 em{font-style:normal;color:var(--in);}
  article.body h3{font-family:var(--display);font-weight:600;text-transform:uppercase;font-size:23px;line-height:1.1;color:var(--charcoal);margin:34px 0 14px;}
  article.body h3 em{font-style:normal;color:var(--in);}
  article.body h4{font-family:var(--display);font-weight:600;font-size:20px;color:var(--charcoal);margin:28px 0 12px;}
  article.body h4 a{color:var(--charcoal);text-decoration-color:rgba(62,48,69,.4);}
  article.body h5,article.body h6{font-family:var(--display);font-weight:700;font-size:17px;color:var(--charcoal);margin:24px 0 10px;text-transform:none;}
  article.body ul,article.body ol{margin:0 0 26px 22px;font-weight:300;line-height:1.75;}
  article.body li{margin-bottom:10px;}
  /* --in-deep, not --in. These are normal-size body links, so the bar is 4.5:1.
     Base green on white is 2.56:1; --in-deep is 6.22:1. (Under Teal this rule
     was 3.05:1 and also failed - the green made an existing miss worse rather
     than creating a new one, but a link is functional text and is the one place
     the accent cannot be decorative.) The display-heading em accents elsewhere
     still use base --in and still miss 3:1 - that is a live decision for James,
     not something to change quietly here. */
  article.body a{color:var(--in-deep);text-decoration:underline;}
  article.body img{border-radius:0;}
  /* Article builder blocks (Image / Video / Quote) */
  .body .article-img{margin:8px 0 30px;}
  .body .article-img img{width:100%;height:auto;display:block;}
  .body .article-img figcaption{font-size:14px;color:#8A8F9A;margin-top:10px;font-weight:300;line-height:1.5;}
  .body .article-video{position:relative;margin:14px 0 32px;aspect-ratio:16/9;background:var(--charcoal-deep);overflow:hidden;}
  .body .article-video iframe{position:absolute;inset:0;width:100%;height:100%;border:0;}
  .body .article-quote{margin:34px 0;padding:2px 0 2px 26px;border-left:3px solid var(--charcoal-mid);}
  .body .article-quote p{font-family:var(--display);font-weight:400;font-size:clamp(21px,2.2vw,27px);line-height:1.35;color:var(--charcoal);margin:0 0 12px;}
  .body .article-quote cite{font-style:normal;font-size:15px;color:#575E6D;font-weight:600;}
  .chip-row{display:flex;gap:10px;flex-wrap:wrap;margin:10px 0 30px;}
  .chip{font-size:13px;font-weight:600;letter-spacing:.05em;border:1.5px solid rgba(43,41,48,.25);border-radius:0;padding:7px 18px;color:var(--charcoal);}
  .body-cols{display:grid;grid-template-columns:1fr 1fr;gap:48px;}
  @media(max-width:880px){.body-cols{grid-template-columns:1fr;gap:0;}}
  .io-split{display:grid;grid-template-columns:1fr 1fr;gap:26px;max-width:1176px;margin:30px auto 0;padding:0 32px;}
  @media(max-width:880px){.io-split{grid-template-columns:1fr;}}
  .io-block{border-radius:0;padding:36px 38px;}
  .io-block h3{font-family:var(--body);font-size:13px;font-weight:700;letter-spacing:.24em;text-transform:uppercase;margin-bottom:14px;}
  .io-block p{font-size:16px;line-height:1.65;}
  .io-in{background:linear-gradient(150deg,var(--charcoal-deep),var(--charcoal-shade));color:var(--dove);} .io-in h3{color:var(--in-lite);}
  .io-out{background:var(--charcoal-deep);color:var(--dove);} .io-out h3{color:var(--out);}
  .img-duo{display:grid;grid-template-columns:1fr 1fr;gap:26px;max-width:1176px;margin:26px auto 0;padding:0 32px;}
  @media(max-width:880px){.img-duo{grid-template-columns:1fr;}}
  .img-duo img,.img-duo .vid{border-radius:0;width:100%;height:100%;object-fit:cover;}
  /* Case-study gallery images are square tiles. Pinned rather than inherited:
     previously the row took its height from the FIRST image's natural aspect and
     cropped the second to match, so a mixed-ratio gallery rendered unpredictably.
     Targets img only — a .vid in a pair keeps its own 16:9 below. */
  .img-duo img{aspect-ratio:1/1;height:auto;}
  .vid{aspect-ratio:16/9;overflow:hidden;border-radius:0;background:var(--charcoal-deep);}
  .vid iframe{width:100%;height:100%;border:0;}
  .results-band{background:var(--paper);padding:80px 0;margin-top:80px;}
  .results-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:34px;margin-top:44px;}
  @media(max-width:880px){.results-grid{grid-template-columns:repeat(2,1fr);}}
  .r-stat .num{font-family:var(--display);font-size:50px;line-height:1;color:var(--charcoal);}
  .r-stat .num small{font-size:22px;}
  .r-stat p{font-size:14.5px;color:#575E6D;margin-top:10px;line-height:1.45;}

  /* ---------- who we are flip cards ---------- */
  .belief{padding:90px 0;background:#fff;}
  /* Selector is class-only so it holds whether the element is a <p> or the <h2>
     it now is; every declaration below still wins over the global h1,h2 rules. */
  .belief .big{font-family:var(--display);text-transform:uppercase;font-weight:600;letter-spacing:0;font-size:clamp(26px,3.2vw,42px);line-height:1.12;color:var(--charcoal);max-width:980px;margin-top:26px;}
  .belief .big em{font-style:normal;color:var(--in);}
  .belief-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:40px;margin-top:56px;}
  @media(max-width:880px){.belief-grid{grid-template-columns:1fr;}}
  /* The rule colour is set inline per card from the "Rule colour" field (with
     the approved per-position default), so it survives adding/reordering
     beliefs. The colour here is only a fallback. */
  .bel{border-top:3px solid var(--mustard);padding-top:22px;}
  .bel .n{font-family:var(--display);font-size:38px;color:var(--charcoal);line-height:1;}
  .bel h3{font-family:var(--body);font-size:18px;font-weight:700;color:var(--charcoal);margin:12px 0 8px;}
  .bel p{font-size:15.5px;color:#575E6D;}
  .flip-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;margin-top:54px;}
  @media(max-width:880px){.flip-grid{grid-template-columns:repeat(2,1fr);}}
  @media(max-width:560px){.flip-grid{grid-template-columns:1fr;}}
  .flip{perspective:1100px;cursor:pointer;}
  .flip-inner{position:relative;width:100%;aspect-ratio:380/536;transform-style:preserve-3d;transition:transform .7s cubic-bezier(.2,.7,.3,1);}
  .flip:hover .flip-inner,.flip.flipped .flip-inner{transform:rotateY(180deg);}
  .flip-face{position:absolute;inset:0;backface-visibility:hidden;-webkit-backface-visibility:hidden;border-radius:0;overflow:hidden;box-shadow:0 10px 30px rgba(43,41,48,.18);}
  .flip-front img{width:100%;height:100%;object-fit:cover;}
  .flip-back{transform:rotateY(180deg);display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;padding:34px;gap:14px;}
  .flip-back h3{font-weight:600;font-size:28px;line-height:1.15;}
  .flip-back p{font-family:var(--display);font-weight:400;font-size:16px;line-height:1.6;}
  .poster{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;}
  .poster .shape{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:72%;height:auto;}
  .poster .qmark{position:absolute;left:50%;top:48%;transform:translate(-50%,-50%);font-family:var(--display);font-size:min(15vw,210px);line-height:1;color:var(--in);}
  .poster .p-rhino{position:absolute;right:-14%;top:50%;transform:translateY(-50%);width:115%;opacity:.45;}
  .poster h3{font-family:var(--display);font-style:normal;font-weight:800;font-size:clamp(30px,2.9vw,42px);
    line-height:1.08;color:#F4EFE6;position:relative;z-index:1;text-align:center;padding:0 20px;
    text-shadow:0 2px 18px rgba(0,0,0,.18);}

  /* ---------- ESG ---------- */
  .esg-block{display:grid;grid-template-columns:1fr 1fr;gap:46px;align-items:center;padding:50px 0;}
  @media(max-width:880px){.esg-block{grid-template-columns:1fr;}}
  .esg-block h3{font-size:30px;color:var(--charcoal);margin-bottom:14px;}
  .esg-block p{font-size:16.5px;color:#3C4354;}
  .esg-block p b{color:var(--charcoal);}
  .esg-stack{display:grid;gap:18px;}
  .esg-stack img{border-radius:0;width:100%;}
  .esg-results{display:flex;gap:30px;flex-wrap:wrap;margin-top:22px;}
  .esg-results div{font-size:13.5px;color:#575E6D;line-height:1.4;}
  .esg-results b{display:block;font-family:var(--display);font-size:30px;color:var(--charcoal-deep);font-weight:400;}

  /* ---------- join ---------- */
  .benefit-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:50px;}
  @media(max-width:880px){.benefit-grid{grid-template-columns:1fr;}}
  .benefit{background:#fff;border-radius:0;padding:30px 30px;box-shadow:0 2px 12px rgba(43,41,48,.07);}
  .benefit h3{font-size:21px;color:var(--charcoal);margin-bottom:8px;}
  .benefit p{font-size:15px;color:#575E6D;}
  .roles{background:var(--charcoal);color:var(--dove);border-radius:0;padding:52px 54px;margin-top:30px;}
  .roles h2{color:#fff;font-size:34px;}
  .role-line{display:flex;justify-content:space-between;align-items:center;gap:20px;padding:20px 0;border-bottom:1px solid rgba(232,237,235,.18);font-size:16px;}
  .role-line b{font-weight:600;color:#fff;}
  .role-line a{color:var(--mustard);font-weight:700;text-decoration:none;cursor:pointer;}

  /* ---------- contact + globe ---------- */
  .contact-grid{display:grid;grid-template-columns:1fr 1.2fr 1fr;gap:28px;align-items:stretch;}
  @media(max-width:980px){.contact-grid{grid-template-columns:1fr;}}
  .map-card{padding:0;overflow:hidden;min-height:340px;display:flex;}
  .map-card iframe{width:100%;min-height:340px;border:0;flex:1;}
  .social-row{display:flex;gap:12px;margin-top:24px;}
  .social-row a{width:46px;height:46px;border-radius:50%;background:var(--charcoal);display:flex;align-items:center;justify-content:center;border-bottom:none!important;transition:background .2s, transform .15s;}
  .social-row a:hover{background:var(--charcoal-mid);transform:translateY(-2px);}
  .social-row svg{width:21px;height:21px;fill:#fff;}
  .contact-card{background:#fff;border-radius:0;padding:44px 46px;box-shadow:0 2px 16px rgba(43,41,48,.08);}
  .contact-card h3{font-size:26px;color:var(--charcoal);margin-bottom:18px;}
  .contact-card p{font-size:17px;color:#3C4354;margin-bottom:8px;}
  .contact-card a{color:var(--charcoal);font-weight:600;text-decoration:none;border-bottom:2px solid var(--mustard);}
  .map-band{background:var(--charcoal);color:var(--dove);padding:96px 0;overflow:hidden;}
  .mb-grid{display:grid;grid-template-columns:1.05fr 1fr;gap:60px;align-items:center;}
  @media(max-width:980px){.mb-grid{grid-template-columns:1fr;gap:40px;}}
  .mb-info .eyebrow{color:#C6CCDA;}
  .mb-info h2{color:#fff;font-size:clamp(30px,3.6vw,46px);}
  .mb-info h2 em{font-style:normal;color:var(--mustard);}
  .mb-info p.lede{font-size:18px;font-weight:300;max-width:540px;margin-top:18px;color:var(--dove);}
  .mb-stats{display:flex;gap:40px;flex-wrap:wrap;margin-top:40px;}
  .mb-stats .num{font-family:var(--display);font-size:clamp(38px,3.6vw,50px);color:var(--teal-lite);line-height:1;}
  .mb-stats p{font-size:13.5px;margin-top:8px;color:#C6CCDA;max-width:160px;line-height:1.4;}
  .mb-globe{background:var(--charcoal);padding:30px 28px 22px;box-shadow:0 26px 60px rgba(20,12,25,.28);}
  .globe-stage{width:100%;max-width:430px;aspect-ratio:1/1;margin:0 auto;position:relative;}
  .globe-frame{width:100%;height:100%;border:0;display:block;background:transparent;}
  /* aura sits BEHIND the globe and is masked to a ring so no land shows in it */
  .globe-glow{position:absolute;inset:-16%;border-radius:50%;z-index:0;
    background:radial-gradient(circle at 50% 46%,rgba(var(--teal-rgb),.36),rgba(var(--mustard-rgb),.18) 52%,rgba(var(--mustard-rgb),0) 70%);}
  .earth{position:absolute;inset:0;border-radius:50%;overflow:hidden;z-index:1;isolation:isolate;
    background:radial-gradient(circle at 30% 26%,#F4E4D2 0%,var(--mustard) 33%,var(--teal) 60%,#5A4450 83%,#2B2930 100%);
    box-shadow:0 26px 70px rgba(0,0,0,.55),inset 0 0 56px rgba(0,0,0,.42);}
  .earth .land{position:absolute;inset:0;background-image:url("assets/img/earth-land.png");
    background-size:200% 100%;background-repeat:repeat-x;background-position-x:0;opacity:.92;mix-blend-mode:multiply;}
  .earth .shade{position:absolute;inset:0;border-radius:50%;background:radial-gradient(circle at 50% 50%,rgba(0,0,0,0) 56%,rgba(0,0,0,.5) 88%,rgba(0,0,0,.85) 100%);}
  .earth .gloss{position:absolute;inset:0;border-radius:50%;background:radial-gradient(circle at 30% 22%,rgba(255,255,255,.30),rgba(255,255,255,0) 40%);}
  /* pins ride on a layer above the globe; each travels with the rotation and drops in */
  .pinlayer{position:absolute;inset:0;z-index:2;pointer-events:none;}
  .epin{position:absolute;transform:translate(-50%,-100%);opacity:0;will-change:transform,opacity;}
  .epin .drop{animation:pindrop .7s cubic-bezier(.2,1.4,.4,1) both;transform-origin:bottom center;}
  .epin svg{display:block;}
  @keyframes pindrop{0%{transform:translateY(-26px) scale(.2);opacity:0;}60%{opacity:1;}100%{transform:translateY(0) scale(1);opacity:1;}}
  .globe-legend{display:flex;gap:26px;justify-content:center;flex-wrap:wrap;margin-top:30px;font-size:13px;color:#C6CCDA;}
  .globe-legend span{display:inline-flex;align-items:center;gap:8px;}
  .globe-legend i{width:14px;height:14px;border-radius:50%;display:inline-block;}
  .globe-caption{text-align:center;font-size:13px;color:#AFB7C8;margin-top:14px;}

  /* --- rhino: white stamp bottom-right of top panels; remove watermarks --- */
  .door-rhino, .cta-rhino{display:none !important;}
  .hero-rhino, .page-hero .hero-rhino, .t-charcoal .hero-rhino, .t-in .hero-rhino, .t-out .hero-rhino{
    left:auto !important; right:30px !important; top:auto !important; bottom:26px !important;
    width:78px !important; height:auto !important; opacity:.9 !important; transform:none !important;
    filter:brightness(0) invert(1) !important; z-index:2 !important; mix-blend-mode:normal !important;
  }

  /* centre the homepage hero lede block under the centred headline */
  .hero-inner p.global{margin-left:auto !important;margin-right:auto !important;}
  /* What We Do two columns */
  .intro-cols{display:grid;grid-template-columns:1fr 1fr;gap:26px;max-width:1000px;margin:42px auto 0;text-align:center;}
  @media(max-width:760px){.intro-cols{grid-template-columns:1fr;}}
  .intro-col{background:#fff;border-top:3px solid;padding:30px 32px;box-shadow:0 2px 16px rgba(43,41,48,.07);}
  .intro-in{border-color:var(--in);} .intro-out{border-color:var(--out);}
  .intro-col .ic-tag{font-family:var(--display);font-size:13px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;display:block;margin-bottom:12px;}
  .intro-in .ic-tag{color:var(--in-deep);} .intro-out .ic-tag{color:var(--out);}
  .intro-col p{font-size:17px;font-weight:300;color:#3C4354;line-height:1.55;margin:0;}
  /* Proof carousel (clickable, mirrors the pain carousel) */
  .proof .eyebrow{color:var(--in-deep);}
  .proof h2{font-family:var(--display);font-size:clamp(40px,5.2vw,66px);line-height:1.0;letter-spacing:-.01em;color:var(--charcoal);margin-top:14px;}
  .proof h2 em{font-style:normal;color:var(--in);}
  /* The cards went dark on 2026-08-20, and the figures went gold.
     Owen asked for gold proof figures. On the white card they were sitting on,
     brand yellow measures 1.49:1 — it fails even the 3:1 large-text bar, so
     "gold on white" was not a thing that could be delivered legibly, and the
     standing rule in :root forbids darkening the yellow to get there. The other
     half of the same note was to make the figures more prominent. Moving the
     CARD to charcoal-deep does both at once: the gold lands at 9.64:1 and the
     figures become the loudest thing in the section.
     Note this is the card, not the section — .proof keeps its white ground, so
     the page's light/dark rhythm is unchanged and the cards read as objects
     sitting on it rather than as another dark band. */
  .stat-card{flex:0 0 calc((100% - 48px)/3);scroll-snap-align:start;background:var(--charcoal-soft);color:var(--dove);
    box-shadow:0 2px 16px rgba(43,41,48,.14);padding:32px 30px;border-top:3px solid var(--mustard);
    display:flex;flex-direction:column;text-decoration:none;
    transition:transform .28s ease, box-shadow .28s ease;}
  /* Clickable cards. Each figure links to the work that proves it, so the card
     is now an anchor and gets the site's "I am a link" affordance in full. The
     .sc-go line is the visible promise of a destination; it is pinned to the
     bottom so cards of different copy lengths still line their arrows up. */
  .stat-card.is-link{cursor:pointer;}
  .sc-go{margin-top:auto;padding-top:20px;font-size:13.5px;font-weight:700;letter-spacing:.1em;
    text-transform:uppercase;color:var(--mustard);opacity:.75;transition:opacity .28s;}
  .stat-card.is-link:hover .sc-go,.stat-card.is-link:focus-visible .sc-go{opacity:1;}
  /* Hover lift — approved by James 2026-07-23, replacing an earlier decision to
     leave these inert. The reasoning then was that a translateY is this site's
     "I am a link" gesture (.case, .door, .btn all lift, all are anchors), and a
     stat card is a div that goes nowhere. In practice that made the proof stats
     the only dead thing in a section where everything around them moves, and
     they are the most important content on the homepage.
     6px, not .case's 7px, and a softer shadow: close enough to feel alive,
     shallow enough that it reads as emphasis rather than a promised click.
     Shadow kept shallow (10/26, not 18/38) because the carousel only has 10px
     of bottom padding to spill into — the resting shadow is already trimmed
     there, and a denser one would be cut off as a hard line rather than a fade.
     No reduced-motion rule needed — the global block at the top of this file
     already kills every transition with !important. */
  .stat-card:hover{transform:translateY(-6px);box-shadow:0 10px 26px rgba(43,41,48,.16);}
  /* Card-hover accent. The figure rests at brand yellow and deepens a step on
     hover. Both sit on charcoal-deep now (9.64:1 and 8.2:1), so unlike the old
     white-card version this is a real, readable colour change rather than a
     wash that could only be sensed. */
  .stat-card:hover .num{color:var(--mustard-shade);}
  @media(max-width:880px){.stat-card{flex:0 0 84%;}}
  .stat-card .num{font-family:var(--display);font-size:clamp(58px,6vw,78px);line-height:1;color:var(--mustard);transition:color .28s;}
  .stat-card .num small{font-size:.4em;font-weight:400;}
  .stat-card p{font-size:15.5px;color:#C6CCDA;margin-top:18px;line-height:1.55;}
  .proof .pc-nav button{color:var(--in-deep);} .proof .pc-nav button:hover{background:var(--in-deep);color:#fff;border-color:var(--in-deep);}
  /* In Their Words carousel */
  /* Slides stack in one grid cell so the carousel is exactly as tall as the
     active quote — long quotes get room instead of overflowing onto the logos. */
  /* minmax(0,1fr): grid items default to min-width:auto, so the dots row (a
     non-wrapping flex line) held the column open at its min-content width and
     pushed the whole page into a horizontal scroll at 320px. */
  .quote-carousel{position:relative;max-width:900px;margin:54px auto 40px;display:grid;grid-template-columns:minmax(0,1fr);min-height:150px;}
  .quote-slide{grid-area:1 / 1;opacity:0;transition:opacity 1.1s ease;text-align:center;pointer-events:none;}
  .quote-slide.is-active{opacity:1;pointer-events:auto;}
  .quote-slide p.q{font-family:var(--body);font-weight:400;font-size:clamp(18px,1.9vw,25px);line-height:1.5;color:#fff;}
  .quote-slide .who{margin-top:26px;font-family:var(--body);font-weight:400;font-size:15px;letter-spacing:.02em;color:var(--mustard);}
  @media(max-width:640px){.quote-slide p.q{font-size:19px;}}

  /* Quote dots. The rotator in main.js has always looked for .fade-dot, but no
     dots were ever rendered — so six quotes rotated invisibly on a 15s timer
     with no way to know the others existed. The bar doubles as a progress
     indicator: it tells you there IS more, and how long you have. */
  .quote-dots{grid-area:2 / 1;display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-top:30px;}
  .fade-dot{width:26px;height:3px;padding:0;border:none;border-radius:0;cursor:pointer;
    background:rgba(232,237,235,.26);position:relative;overflow:hidden;transition:background .2s;}
  .fade-dot:hover{background:rgba(232,237,235,.5);}
  .fade-dot:focus-visible{outline:2px solid var(--mustard);outline-offset:4px;}
  .fade-dot.is-active{background:rgba(232,237,235,.34);}
  .fade-dot.is-active::after{content:"";position:absolute;inset:0;background:var(--mustard);
    transform-origin:left;animation:quotefill 7s linear forwards;}
  @keyframes quotefill{from{transform:scaleX(0);}to{transform:scaleX(1);}}
  /* Hovering the quotes pauses the timer (JS) and the bar with it. */
  .quote-carousel:hover .fade-dot.is-active::after{animation-play-state:paused;}
  @media(prefers-reduced-motion:reduce){
    .fade-dot.is-active::after{animation:none;transform:scaleX(1);}
  }

  /* Mask reveal for page headlines. Words are wrapped by main.js and rise from
     behind their own mask. The padding/margin pair gives descenders (g, y, p)
     room so overflow:hidden doesn't shave them.

     Deliberately a CSS animation rather than a JS-toggled class: an animation
     starts the moment the element exists, so it cannot strand the headline
     off-screen. A class toggled on requestAnimationFrame can — if rAF is
     throttled (background tab at load), the h1 would never appear at all.
     If the JS never runs, no .mw wrappers exist and the headline just renders. */
  .page-hero h1 .mw{display:inline-block;overflow:hidden;vertical-align:bottom;
    padding-bottom:.12em;margin-bottom:-.12em;}
  .page-hero h1 .mw > span{display:inline-block;
    animation:maskrise .62s cubic-bezier(.16,1,.3,1) both;}
  @keyframes maskrise{from{transform:translateY(110%);}to{transform:none;}}
  @media(prefers-reduced-motion:reduce){
    .page-hero h1 .mw > span{animation:none;}
  }

  /* ============================================================
     Website changes v1 — case-study & Our Work refinements
     ============================================================ */

  /* Case-study hero: featured image sits BEHIND the header panel */
  .detail-hero.has-photo{padding:118px 0 84px;}
  /* Case studies keep their own slightly softer gradient, but it now rides on the
     shared .hero-scrim element so its strength is editor-controlled via the
     "Header image overlay" field. At 100% this is the approved look. */
  .detail-hero .hero-scrim{
    background:linear-gradient(100deg, rgba(43,41,48,.95) 20%, rgba(43,41,48,.72) 55%, rgba(43,41,48,.46) 100%);}
  @media(max-width:880px){
    .detail-hero .hero-scrim{background:linear-gradient(180deg, rgba(43,41,48,.72) 0%, rgba(43,41,48,.93) 100%);}
  }
  /* Prominent client name, differentiated from the services line */
  .cs-client{display:block;position:relative;z-index:1;font-family:var(--display);font-weight:600;
    text-transform:uppercase;letter-spacing:-.01em;line-height:1;color:var(--mustard);
    font-size:clamp(26px,3.2vw,44px);margin:10px 0 6px;}
  .detail-hero .meta{margin-top:20px;}

  /* Our Work filters — Inside=teal, Outside=mustard, solid when active */
  .filters button.f-in:hover{border-color:var(--in);color:#fff;}
  /* --in-ink, not --in-paper. White on the Inside accent is 2.56:1 and fails
     AA outright; ink on it is 5.68:1. This is the rule :root states for every
     Inside fill, and this button was the one place still breaking it — it read
     as white-on-teal at 2.42:1 before the palette moved, so the bug predates
     the green and is simply fixed here. Outside is the mirror case and is
     already correct: Periwinkle is dark enough to take white, at 4.67:1. */
  .filters button.f-in.on{background:var(--in);border-color:var(--in);color:var(--in-ink);}
  .filters button.f-out:hover{border-color:var(--out);color:#fff;}
  .filters button.f-out.on{background:var(--out);border-color:var(--out);color:var(--out-paper);}
  /* Active "All work" is a reverse grey box with dark text — the same solid box
     the service and news filters use when active — so it reads as a proper button
     instead of vanishing into the charcoal ground. Deselected, it falls back to
     the outlined style, in line with Inside/Outside. */
  .filters button.f-all.on{background:var(--dipse);border-color:var(--dipse);color:#2A282E;}

  /* Inside and Outside lead; All work is the reset.
     The two door buttons are bigger and carry their door's colour, because
     picking a door is the decision the page wants you to make. "All work" is
     still there for anyone who wants the lot, but as a quiet text control set
     apart by a hairline divider rather than a third equal chip — the previous
     three-equal-chips row made "All" look like the recommended option, which
     is exactly what it should not be. It keeps its border and chip treatment
     while selected so the current state is never ambiguous. */
  .filters-door{gap:12px;align-items:center;}
  .filters-door button.f-in,.filters-door button.f-out{font-size:15px;padding:12px 30px;}
  .filters-door button.f-all{border-color:transparent;padding:12px 6px 12px 20px;opacity:.72;
    margin-left:4px;position:relative;}
  .filters-door button.f-all::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
    width:1px;height:20px;background:rgba(232,237,235,.28);}
  .filters-door button.f-all:hover{opacity:1;border-color:transparent;text-decoration:underline;text-underline-offset:4px;}
  .filters-door button.f-all.on{opacity:1;background:transparent;border-color:transparent;color:#fff;
    text-decoration:underline;text-underline-offset:4px;}
  @media(max-width:560px){
    .filters-door button.f-in,.filters-door button.f-out{font-size:14px;padding:10px 22px;}
  }
  /* Services filter row */
  /* #9aa0ab reached only 4.00:1 on the plum band; #b4b9c2 clears AA at 5.02:1. */
  .filters-label{font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:#b4b9c2;margin:22px 0 8px;}
  .filters-svc{margin-top:0;gap:8px;}
  .filters-svc button{font-size:12.5px;padding:7px 16px;border-color:rgba(232,237,235,.28);letter-spacing:.05em;}
  .filters-svc button:hover{border-color:var(--dipse);color:#fff;}
  .filters-svc button.on{background:var(--dipse);border-color:var(--dipse);color:#2A282E;}

  /* Case-study gallery — full-width film, then image pairs */
  .story-film{max-width:1176px;margin:26px auto 0;padding:0 32px;}
  .story-film .vid{aspect-ratio:16/9;overflow:hidden;background:var(--charcoal-deep);border-radius:0;}
  .story-film .vid iframe{width:100%;height:100%;border:0;display:block;}
  /* Single full-width image (odd one out in a gallery) */
  .img-solo{max-width:1176px;margin:26px auto 0;padding:0 32px;}
  /* A lone gallery image (odd-numbered galleries — six case studies have three)
     renders at the same tile size as one half of a pair and is centred, so every
     gallery image on the site is the same square. Full width at 1:1 would be a
     1112px monolith next to 543px tiles. */
  .img-solo img{width:100%;display:block;aspect-ratio:1/1;object-fit:cover;
    max-width:543px;margin-inline:auto;}
  /* Case-study client quote (optional, toggled per story) */
  /* Charcoal band with the wording reversed out, so the client quote stands out
     from the white sections above and below it (v1.24.1). */
  /* margin-top (not padding) so the gap above is white page, not more charcoal —
     the band must not butt straight up against the gallery image above it. */
  /* Bridging headline between the results band and the story. Deliberately
     quiet — it is a signpost, not a section: no ground of its own, generous
     space above and below, and it sits centred so the eye is handed down the
     page rather than across it. */
  .cs-bridge{text-align:center;padding:clamp(56px,7vw,88px) 0 clamp(10px,1.6vw,20px);}
  .cs-bridge .eyebrow{color:var(--in-deep);justify-content:center;}
  .cs-bridge h2{font-family:var(--display);font-size:clamp(34px,4.4vw,56px);line-height:1.02;
    color:var(--charcoal);margin-top:14px;}
  .cs-bridge h2 em{font-style:normal;color:var(--in);}

  .cs-quote{background:var(--charcoal);padding:74px 0;margin-top:clamp(48px,6vw,80px);text-align:center;}
  .cs-quote .q{font-family:var(--body);font-weight:400;font-style:normal;font-size:clamp(22px,2.6vw,34px);line-height:1.32;color:#fff;max-width:840px;margin:0 auto;}
  .cs-quote .who{margin-top:22px;font-family:var(--body);font-weight:400;font-size:16px;letter-spacing:.02em;color:#fff;}
  .cs-quote .who b{display:block;color:#fff;font-size:16px;margin-bottom:2px;}
  /* Outside "problems" heading accent stays gold when edited via a plain <em> */
  .pains.t-out-alt h2 em{color:var(--out);font-style:normal;}
  .who-act-h em{color:var(--in);font-style:normal;}
  .roles-h em{color:var(--mustard);font-style:normal;}
  .proof-h em{color:var(--out);font-style:normal;}
  /* Keep the last word + arrow of cross-links together (no orphaned arrow) */
  .nowrap{white-space:nowrap;}
  /* Who-we-are flip cards: front image fills the card */
  .poster-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
  /* Reduce single-word widows in headlines on supported browsers */
  h1, h2, h3{text-wrap:balance;}

  /* Lorem placeholder metric — full-strength (replace the lorem with a real figure) */

  /* Consistent boxed filter buttons (incl. All work) */
  .filters button.f-all,.filters button.f-in,.filters button.f-out{border-color:rgba(232,237,235,.6);}
  /* ...with one exception, restated here because this block sits after it and
     would otherwise put the box back: on Our work, "All work" is deliberately
     not a box. See .filters-door above. */
  .filters-door button.f-all{border-color:transparent;}

  /* Story standfirst — mega-short intro line */
  .cs-standfirst{max-width:940px;margin:58px auto 0;padding:0 32px;font-family:var(--display);font-weight:600;
    text-transform:uppercase;letter-spacing:-.01em;line-height:1.2;font-size:clamp(20px,2.4vw,30px);
    color:var(--charcoal);text-align:center;}
  .cs-standfirst em{font-style:normal;color:var(--in);}
  /* Tighten the space between the standfirst and the impact band */
  .cs-standfirst + .results-band{margin-top:26px;padding-top:46px;}

  /* News card meta: read time left, author right */
  .news-card .card-meta{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-top:auto;font-size:13px;padding-top:6px;}
  .news-card .card-meta .read{color:var(--mute-onsoft);font-weight:600;}
  /* News category label gets the case-study 'blue' (sage-onsoft, 4.92:1 on the
     #54515A card) rather than the neutral grey the Our Work client uses — a
     small lift that marks News as a slightly different context. Scoped to
     .news-card so Our Work client names stay grey. */
  .news-card .client{color:var(--teal-onsoft);}
  .news-card .card-meta .by{color:var(--mute-onsoft);font-weight:500;font-style:italic;white-space:nowrap;}
  /* Article meta: read time left, author right */
  .detail-hero .article-meta{display:flex;justify-content:space-between;align-items:center;gap:22px;max-width:640px;}
  .detail-hero .article-meta .by{font-style:italic;opacity:.85;}
  /* News load-more button */
  .news-more-wrap{text-align:center;margin-top:50px;}
  #newsMore{cursor:pointer;}

  /* News category filters (on the dark work section) */
  .filters-news{margin-top:0;margin-bottom:24px;}
  .filters button.f-news:hover{border-color:var(--mustard);color:#fff;}
  .filters button.f-news.on{background:var(--dipse);border-color:var(--dipse);color:#2A282E;}

  /* ---------- mobile filter select ----------
     Our Work renders 15 service chips and News 8 category chips. On a handset
     those wrapped into four or five rows of boxes that dominated the page before
     any work was visible. Below 880px the chip rows are swapped for one native
     <select>: a single control, and the OS picker handles the long list far
     better than a wall of chips. Desktop is untouched — chips there are good.
     Both controls drive the same filter functions (see main.js), so whichever
     one is on screen, the grid and the other control stay in step. */
  .filters-select{display:none;}
  @media(max-width:880px){
    .filters-svc, .filters-news{display:none;}
    .filters-select{
      display:block;width:100%;margin:0 0 4px;cursor:pointer;
      font-family:var(--body);font-size:15px;font-weight:600;letter-spacing:.02em;
      color:#fff;background-color:transparent;
      border:1.5px solid rgba(232,237,235,.6);border-radius:0;
      padding:14px 46px 14px 16px;
      -webkit-appearance:none;appearance:none;
      background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 8'%3E%3Cpath d='M1 1l6 6 6-6' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
      background-repeat:no-repeat;background-position:right 16px center;background-size:14px 8px;
    }
    .filters-select:focus-visible{outline:2px solid var(--mustard);outline-offset:2px;}
    /* The option list is drawn by the OS, not the page, so it needs its own
       readable pairing rather than inheriting the dark section. */
    .filters-select option{color:#2A282E;background:#fff;}
  }

  /* ---------- Our Work: search by client ----------
     Always-visible dropdown (desktop and phone), styled to match the dark filter
     controls. Its options are filled from the rendered cards by main.js, and it
     filters alongside the channel/service chips. */
  /* Top filter bar: channel buttons on the left, client search on the right, on
     one row on desktop. It carries the 44px top margin the channel row used to
     have. Wraps to stacked (client below, left-aligned) on narrow screens. */
  .work-filterbar{display:flex;justify-content:space-between;align-items:center;gap:16px 24px;flex-wrap:wrap;margin-top:44px;}
  .work-filterbar .filters{margin-top:0;}
  .work-client{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0;}
  .work-client label{font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
    color:rgba(232,237,235,.75);}
  #clientSelect{cursor:pointer;font-family:var(--body);font-size:15px;font-weight:600;color:#fff;
    background-color:transparent;border:1.5px solid rgba(232,237,235,.6);border-radius:0;
    padding:11px 44px 11px 15px;min-width:230px;-webkit-appearance:none;appearance:none;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 8'%3E%3Cpath d='M1 1l6 6 6-6' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat:no-repeat;background-position:right 15px center;background-size:14px 8px;}
  #clientSelect:hover{border-color:var(--mustard);}
  #clientSelect:focus-visible{outline:2px solid var(--mustard);outline-offset:2px;}
  #clientSelect option{color:#2A282E;background:#fff;}
  @media(max-width:560px){.work-filterbar{align-items:flex-start;}.work-client{gap:8px;width:100%;}#clientSelect{width:100%;min-width:0;}}

  /* ---------- News: spyglass search ----------
     Sits above the grid on the dark section; submits through the same AJAX the
     chips use so it searches the whole archive, not just the loaded batch. */
  .news-search{display:flex;align-items:center;gap:10px;max-width:340px;margin:4px 0 26px;
    border:1.5px solid rgba(232,237,235,.5);border-radius:0;padding:0 14px;background:transparent;
    transition:border-color .2s;}
  .news-search:focus-within{border-color:var(--mustard);}
  .news-search .ns-ico{display:flex;align-items:center;color:rgba(232,237,235,.7);flex:0 0 auto;}
  #newsSearchInput{flex:1;min-width:0;background:transparent;border:0;outline:0;color:#fff;
    font-family:var(--body);font-size:15px;padding:12px 0;}
  #newsSearchInput::placeholder{color:rgba(232,237,235,.55);}
  .news-empty{grid-column:1/-1;color:rgba(232,237,235,.8);font-size:16px;padding:24px 0;}
