/* =========================================================================
   Ludic Advisory — foundation
   Tokens, reset, typography, page chrome (header / footer / skip link).

   This is the ARCHIVED SITE'S design system, not a new one, and it is the
   same one the Ludic Group site uses: the two share a :root, a container
   width, Archivo, black chrome and cream bands. Colours, fonts and layout
   dimensions were read off the Webflow build in _Webflow Archive/ rather than
   eyeballed — the value each token replaces is noted beside it.

   What is deliberately different from the original, and only this:
     * ONE spacing ladder instead of ad-hoc paddings.
     * ONE type scale. The original mixes 0.8 / 0.9 / 1 / 1.2 / 1.25 / 1.3 /
       1.5 / 2 / 3rem with no relationship between them; the sizes below are
       the same design rounded onto a scale, so headings match across pages.
     * The h1 was 2rem on the homepage and 3rem on Contact. Every page h1 is
       now the same size.

   BREAKPOINT LADDER — the only four widths this site uses. Custom properties
   do not work inside @media (a CSS restriction, not an oversight), so the
   numbers are written out and this comment is the single source of truth.

       36rem   576px   small phone  -> large phone
       48rem   768px   phone        -> tablet
       64rem  1024px   tablet       -> laptop
       80rem  1280px   laptop       -> desktop

   NAMING — block__element--modifier. No ID selectors. No !important outside
   @media print, the reduced-motion block, and `[hidden]` — see the note in
   the reset for why that one has to win.
   ========================================================================= */

/* ---------- fonts -------------------------------------------------------
   Self-hosted so no third-party request fires before the visitor has made a
   consent choice. The original pulled both from Google Fonts, which is a
   third-party request on page load. Same two families, same weights.
   ----------------------------------------------------------------------- */
@font-face {
  font-family: "Archivo";
  src: url("../assets/fonts/archivo-latin.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Roboto Slab";
  src: url("../assets/fonts/roboto-slab-latin.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ---------- tokens ------------------------------------------------------ */
:root {
  /* Brand values, straight off the live site's :root. Components read the
     semantic aliases below, never these, which is what makes [data-theme] a
     five-line override instead of a rewrite. */
  --black: #000000;
  --white: #ffffff;
  --cream: #f2f2f2;          /* section background, the site's workhorse */
  --header-cream: #f9fbf7;   /* the hero card, and only the hero card */
  --black-hover: #1b1b1b;
  --dark-grey: #494949;
  --mid-grey: #929292;
  --light-grey: #e9f0f1;

  --blue: #44597b;           /* also Deep Blue in the 2026 brand kit */
  --bold-blue: #2c6eed;      /* Ludic Advisory tile */
  --smartlab-blue: #5b8edb;  /* SmartLab tile */
  --yellow: #ffd728;         /* Media Studio tile */
  --dh-purple: #865aa1;
  --curious-red: #ec6a54;
  /* Deep Blue opened up for use on the black chrome. #44597b itself measures
     2.96:1 on black — unusable for a link. Same hue, lightened to 9.87:1. */
  --blue-on-dark: #9fb3d4;

  /* Advisory's own accent, from the archive's :root. Black still carries
     every button, border and rule — the archive uses it for all of them and
     reserves colour for the sub-brand marks — so --accent stays black and
     Bold Blue is a separate alias, used for the quote bands, the active
     filter chip, the breadcrumb's current crumb and link hover on light
     surfaces. Measured: #2c6eed is 4.60:1 on white and 4.11:1 on cream — so
     it carries body copy on white but NOT on cream, and never small print;
     --blue-ink is the same hue deepened for both of those.
     Every number in this block is the one checks.py::PAIRS prints on every
     build, not an estimate: the four values that used to be here (4.62, 4.24,
     7.02, 8.10) were all wrong, in the direction that flatters the palette.
     Components read these aliases and never the brand values above, which is
     what makes [data-theme] a five-line override instead of a rewrite. */
  --advisory-blue: #2c6eed;
  --advisory-blue-hover: #273448;   /* white on it is 12.57:1 */
  --blue-ink: #1f4fae;              /* 7.53:1 on white, 6.73:1 on cream */

  /* ---- the band palette -------------------------------------------------
     THE ARCHIVE'S SIGNATURE, and the thing the first pass at this rebuild
     lost. Its service pages are not cream-and-white: they are a rotation of
     saturated brand bands, one per offer. Measured out of the live pages with
     a browser (`_build/migration/probe.py`) rather than read off the
     stylesheet — the archive paints a band from a NESTED div, so the
     section's own background-color computes as transparent on a page that is
     visibly pink, and reading the rule gives you cream every time.

     Sixteen distinct band colours across the site; Learning alone uses eight.

     Every one of the bright bands carries BLACK, which is what the archive
     does and what the arithmetic supports — the darkest of them, mid-blue, is
     still 8.3:1 against black. The dark bands carry white. There is no band on
     this site where the choice is close; checks.py asserts every pair. */
  --band-light-green: #ecfc95;      /* black 18.92:1 */
  --band-light-lime: #e2ff70;       /* black 18.77:1 */
  --band-lime: #cbff00;             /* black 17.84:1 */
  --band-lime-deep: #b5e205;        /* black 13.85:1 */
  --band-turquoise: #30fbff;        /* black 16.37:1 */
  --band-aqua: #82e5ce;             /* black 14.05:1 */
  --band-pink: #ff49b0;             /* black  6.83:1 — the tightest band on the site */
  --band-mid-blue: #85a4d7;         /* black  8.29:1 */
  --band-yellow: #ffd728;           /* black 15.00:1 */
  --band-creatives-yellow: #fdc727; /* black 13.38:1 */
  --band-lightest-blue: #eefbfc;    /* black 19.84:1 */
  --band-off-white: #fdfdfd;        /* black 20.65:1 */
  /* Two dark bands the archive puts WHITE on, and one it puts white on that
     cannot carry it. Deep Blue is 7.09:1 with white and Digital Humans purple
     5.26:1, so both keep the archive's ink. Curious Red is 3.11:1 with white
     and 6.76:1 with black — a real failure, not a near miss — so the BAND
     KEEPS ITS COLOUR and only the ink changes. That is the smallest edit that
     makes it legible, and it preserves the thing that is actually the design. */
  /* SMARTLAB'S OWN BLUE, DEEPENED UNTIL WHITE COPY CLEARS AA. The 2026 kit's
     SmartLab Accent Blue is #5B8EDB and is the brand's "main accent" — but
     white on it measures 3.31:1, which carries a 2rem heading (3:1) and fails
     every other line on the band (4.5:1). SmartLab's own guidelines are
     explicit about this: "verify that text and logo meet WCAG AA ... never
     assume a colour combination works without checking. Accessibility is
     non-negotiable." So the hue (216deg) and the saturation (64%) are the
     brand's exactly and only the lightness moves, 60.8% -> 51.8%, which is the
     least change that clears it. Black on the untouched swatch would be
     6.34:1, so that is the other honest option and it is Ludic's call. */
  --band-smartlab-blue: #3574d3;    /* white  4.57:1 */
  --band-deep-blue: #44597b;        /* white  7.09:1 */
  --band-dh-purple: #865aa1;        /* white  5.26:1 */
  --band-curious-red: #ec6a54;      /* BLACK  6.76:1 — white would be 3.11:1 */

  /* Semantic aliases. The accent is black: the archive uses black for
     every button, border and rule, and reserves colour for the sub-brand
     marks and the publication pages. */
  --accent: var(--black);
  --accent-hover: var(--black-hover);
  --accent-on: var(--white);
  --ink: var(--black);
  --ink-muted: var(--dark-grey);   /* 9.00:1 on white, 8.04:1 on cream */
  --surface: var(--white);
  --surface-alt: var(--cream);
  --ink-on-invert: var(--white);
  --line: #d4d4d4;
  --control-line: var(--black);    /* the original's 2px black input border */

  /* Layout, from the live site: .container-large is 80rem with 2.5rem of
     side padding; section paddings are 7 / 5 / 3rem. */
  --container: 80rem;
  --container-small: 60rem;
  --container-pad: 2.5rem;
  --header-h: 68px;

  /* Spacing ladder. The original had no ladder; these are its own values
     rounded onto one, so vertical rhythm is decided in a single place. */
  --space-2xs: 0.5rem;
  --space-xs: 1rem;
  --space-sm: 1.5rem;
  --space-md: 2rem;
  --space-lg: 3rem;
  --space-xl: 5rem;
  --space-2xl: 7rem;

  /* Type scale. Left column is the live site value each one replaces.
       0.80rem  nav             -> --text-xs   0.875rem
       0.90rem  small           -> --text-sm   0.9375rem
       1.00rem  body            -> --text-base 1rem
       1.20rem  card title      -> --text-md   1.25rem
       1.25rem  lede            -> --text-md   1.25rem
       1.30rem  filter label    -> --text-lg   1.5rem  (it was set larger
                                   than the card titles beneath it)
       1.50rem  h3              -> --text-lg   1.5rem
       2.00rem  h1 / h2         -> --text-xl   2rem
       3.00rem  Contact h1      -> --text-xl   2rem  (now consistent) */
  --text-nav: 0.8125rem;   /* nav only — one step below --text-xs */
  --text-xs: 0.875rem;
  --text-sm: 0.9375rem;
  --text-base: 1rem;
  --text-md: 1.25rem;
  --text-lg: 1.5rem;
  --text-xl: 2rem;

  --leading-tight: 1.2;
  --leading-snug: 1.4;
  --leading-body: 1.75;

  --duration: 250ms;   /* the original's .25s transition */
  --ease: ease;
}

/* Publication pages tint the accent, as the live site does with its own
   --dh-purple and --curious-red. Both darkened to carry white button text:
   the source hues measure 4.0:1 and 3.1:1 on white and fail as UI fills. */
[data-theme="digital-humans"] { --accent: #6b4482; --accent-hover: #543468; }
[data-theme="curious-advantage"] { --accent: #b8402a; --accent-hover: #932f1d; }

/* ---------- reset ------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

/* `hidden` MEANS HIDDEN, AND IT HAS TO OUTRANK A CLASS.
   ------------------------------------------------------------------------
   The UA stylesheet's `[hidden] { display: none }` is an element-level rule,
   so ANY class that sets `display` beats it. `.entry-card { display: flex }`
   did, and that is what broke the case-study filter: clicking a chip set
   `hidden` on twenty cards, the count updated to "Showing 6 of 26", and all
   twenty-six stayed on screen. The script was working perfectly and the page
   ignored it.

   `!important` is right here and almost nowhere else. There is no state in
   which an element marked hidden should be painted, so nothing downstream
   ever needs to win this. Anything that wants to hide something without
   removing it from the accessibility tree uses `opacity` instead — the hover
   reveals do exactly that, on purpose. */
[hidden] { display: none !important; }

* {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

html {
  -webkit-text-size-adjust: 100%;
  /* Anchors must clear the sticky header or every in-page link lands under it. */
  scroll-padding-top: calc(var(--header-h) + 20px);
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: var(--text-base);
  line-height: var(--leading-body);
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
ul[role="list"], ol[role="list"] { list-style: none; margin: 0; padding: 0; }
img, svg, video { display: block; max-width: 100%; height: auto; }
button { font: inherit; color: inherit; }

a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { color: var(--dark-grey); }

/* One global focus ring, and never `outline: none` anywhere else. The
   outline is kept rather than swapped for a box-shadow: box-shadows are
   discarded in Windows High Contrast mode, a silent WCAG 2.4.7 failure you
   cannot see on your own machine. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
@media (forced-colors: active) { :focus-visible { outline-color: Highlight; } }

/* A black ring is invisible on the black chrome. */
.site-header :focus-visible,
.footer :focus-visible,
.section[data-tone="black"] :focus-visible,
.section[data-tone="purple"] :focus-visible { outline-color: var(--white); }

::selection { background: var(--black); color: var(--white); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- utilities --------------------------------------------------- */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 0; left: 50%;
  transform: translate(-50%, -110%);
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--white);
  color: var(--black);
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--duration) var(--ease);
}
.skip-link:focus-visible { transform: translate(-50%, 0); color: var(--black); }

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 1.25rem;
}
.container--small { max-width: var(--container-small); }
.container--narrow { max-width: 46rem; }
@media (min-width: 48rem) { .container { padding-inline: 2rem; } }
@media (min-width: 64rem) { .container { padding-inline: var(--container-pad); } }

/* Same 80rem measure, but at desktop the content lines up with the OUTER edge
   of the container rather than with the text inside it. The live brand-tile
   row is 1280px wide at 1440 — the container's full width, no inner gutter.
   Below 64rem it keeps the normal gutter, which is what the live site does
   too: the tiles are inset by the page margin on a phone. Declared after the
   base rules above so it wins without !important. */
@media (min-width: 64rem) { .container--flush { padding-inline: 0; } }

/* ---------- typography -------------------------------------------------- */
/* Archivo carries body, UI and communications. Roboto Slab is the editorial
   accent, used exactly where the live site uses it: the Insights header, the
   filter labels, insight card titles and article titles. Never body copy. */

.hero__title,
.page-title {
  font-family: "Archivo", sans-serif;
  font-size: clamp(1.625rem, 3.2vw, var(--text-xl));
  font-weight: 400;
  line-height: var(--leading-tight);
}

.section__title {
  font-family: "Archivo", sans-serif;
  font-size: clamp(1.5rem, 2.8vw, var(--text-xl));
  font-weight: 400;
  line-height: var(--leading-tight);
}

.subsection__title {
  font-family: "Archivo", sans-serif;
  font-size: var(--text-lg);
  font-weight: 400;
  line-height: var(--leading-snug);
}

.eyebrow {
  font-family: "Archivo", sans-serif;
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--dark-grey);
  margin-bottom: var(--space-2xs);
}

/* The live statement runs the full 60rem container and lands on three lines
   at 32px. A 40ch cap here pushed it to four narrow lines. */
.statement--center { margin-inline: auto; text-align: center; max-width: 56ch; }

.statement {
  font-family: "Archivo", sans-serif;
  font-size: clamp(1.5rem, 2.8vw, var(--text-xl));
  font-weight: 400;
  line-height: var(--leading-tight);
}

.prose__p {
  margin-bottom: var(--space-xs);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  max-width: 62ch;
}
.prose__p:last-child { margin-bottom: 0; }

.section__head { max-width: 52rem; margin-bottom: var(--space-md); }
.section__lede { margin-top: var(--space-2xs); font-size: var(--text-md); line-height: 1.6; }

@media (min-width: 64rem) {
  .section__head--row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-md);
    max-width: none;
  }
}

/* ---------- section rhythm ---------------------------------------------- */
/* Three paddings, and only three: the live site's 7 / 5 / 3rem made into a
   ladder, and stepped down on small screens rather than staying at 112px. */
.section { padding-block: var(--space-xl); }
.section--tight { padding-block: var(--space-lg); }
.section--loose { padding-block: var(--space-xl); }

@media (min-width: 64rem) {
  .section--loose { padding-block: var(--space-2xl); }
}
@media (max-width: 47.999rem) {
  .section, .section--loose { padding-block: var(--space-lg); }
  .section--tight { padding-block: var(--space-md); }
}

/* EVERY TONE DECLARES `--band` AS WELL AS PAINTING IT. Almost every band is
   painted on the section itself, which is right: a band runs the full width
   of the page. The service tile is the exception — its panel sits inset with
   the page colour showing around it — so it needs the colour applied one
   level down, and `--band` is what lets it do that without a second copy of
   sixteen colours living in components.css. */
.section[data-tone="cream"] { --band: var(--surface-alt); background: var(--band); }
.section[data-tone="black"] { --band: var(--black); background: var(--band); color: var(--white); }
.section[data-tone="black"] .eyebrow { color: var(--mid-grey); }
/* The Digital Humans podcast band. White on #865aa1 is 5.26:1, so body copy
   carries. The eyebrow was white at 85%, which was chosen over a grey because
   a grey on this hue drops under AA — and then composited to #ede6f1, which
   is 4.31:1 and drops under AA as well. Full white, like the blue band. */
.section[data-tone="purple"] { --band: var(--dh-purple); background: var(--band); color: var(--white); }
/* THE EYEBROW ON A DARK BAND. `.eyebrow` is `--dark-grey` (#494949), which is
   1.32:1 on Deep Blue — the label above "What we build is ART" was very nearly
   invisible. `purple` had this rule already because the podcast band needed it;
   the two dark tones added later never got it, and until Ludic Leadership V2
   no band with an eyebrow used one. Same fix, same reason: full white, 7.09:1
   on Deep Blue and 5.26:1 on the purple. */
.section[data-tone="purple"] .eyebrow,
.section[data-tone="deep-blue"] .eyebrow,
.section[data-tone="dh-purple"] .eyebrow,
.section[data-tone="smartlab-blue"] .eyebrow { color: var(--white); }

/* Two bands of the same tone in a row read as one; drop the seam. */
.section[data-tone="cream"] + .section[data-tone="cream"],
.section[data-tone="purple"] + .section[data-tone="purple"],
.section[data-tone="black"] + .section[data-tone="black"] { padding-top: 0; }

/* ---------- buttons ----------------------------------------------------- */
/* The live site's button: 2px solid black, black fill, white label, square.
   Only the vertical padding changes — 0.5rem left the label sitting high in
   the box; 0.75rem centres it at the same overall height. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  border: 2px solid var(--accent);
  background: var(--accent);
  color: var(--accent-on);
  font-family: "Archivo", sans-serif;
  font-size: var(--text-base);
  font-weight: 400;
  line-height: 1.5;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--duration) var(--ease),
              border-color var(--duration) var(--ease),
              color var(--duration) var(--ease);
}
/* Every button inverts on hover and keeps its 2px border, so the shape does
   not move a pixel between states — the fill and the label swap, the border
   stays put. The border is already on the resting state above, which is what
   makes the inversion possible without a layout shift. */
.button:hover,
.button:focus-visible {
  background: transparent;
  border-color: var(--accent);
  color: var(--accent);
}

.button--secondary { background: transparent; color: var(--accent); }
.button--secondary:hover,
.button--secondary:focus-visible { background: var(--accent); color: var(--accent-on); }

.button--sm { padding: 0.5rem 1rem; font-size: var(--text-xs); }

/* On a dark band the resting button is white-on-dark, so inverting means the
   label goes white and the fill drops out — the border keeps the hit area
   and the outline visible against the band. */
.section[data-tone="black"] .button,
.section[data-tone="purple"] .button {
  border-color: var(--white);
  background: var(--white);
  color: var(--black);
}
.section[data-tone="black"] .button:hover,
.section[data-tone="black"] .button:focus-visible,
.section[data-tone="purple"] .button:hover,
.section[data-tone="purple"] .button:focus-visible {
  background: transparent;
  border-color: var(--white);
  color: var(--white);
}
.section[data-tone="black"] .button--secondary,
.section[data-tone="purple"] .button--secondary { background: transparent; color: var(--white); }
.section[data-tone="black"] .button--secondary:hover,
.section[data-tone="black"] .button--secondary:focus-visible,
.section[data-tone="purple"] .button--secondary:hover,
.section[data-tone="purple"] .button--secondary:focus-visible { background: var(--white); color: var(--black); }

.button-group { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-top: var(--space-sm); }

.link-button {
  background: none; border: 0; padding: 0;
  font: inherit; color: inherit;
  text-decoration: underline; text-underline-offset: 0.18em;
  cursor: pointer;
}

/* ---------- header ------------------------------------------------------ */
/* Black bar, white wordmark left, nav right — as the live site. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--black);
  color: var(--white);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  width: 100%;
  max-width: var(--container);
  min-height: var(--header-h);
  margin-inline: auto;
  padding-inline: 1.25rem;
}
@media (min-width: 48rem) { .site-header__inner { padding-inline: 2rem; } }
@media (min-width: 64rem) { .site-header__inner { padding-inline: var(--container-pad); } }

.site-header__logo { display: flex; align-items: center; margin-right: auto; }
/* The wordmark is the supplied SVG, never typeset — brand rule.
   1rem tall, matching .nav4_logo on the live site. */
.site-header__logo img { width: auto; height: 1rem; }

.site-header__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  margin-right: -0.625rem;
  background: none;
  border: 0;
  color: var(--white);
  cursor: pointer;
}
.site-header__toggle-bars,
.site-header__toggle-bars::before,
.site-header__toggle-bars::after {
  display: block;
  width: 22px; height: 2px;
  background: currentColor;
  transition: transform var(--duration) var(--ease), opacity var(--duration) var(--ease);
}
.site-header__toggle-bars { position: relative; }
.site-header__toggle-bars::before,
.site-header__toggle-bars::after { content: ""; position: absolute; left: 0; }
.site-header__toggle-bars::before { top: -7px; }
.site-header__toggle-bars::after { top: 7px; }
[aria-expanded="true"] .site-header__toggle-bars { background: transparent; }
[aria-expanded="true"] .site-header__toggle-bars::before { transform: translateY(7px) rotate(45deg); }
[aria-expanded="true"] .site-header__toggle-bars::after { transform: translateY(-7px) rotate(-45deg); }

.site-nav {
  position: fixed;
  inset: var(--header-h) 0 auto 0;
  max-height: calc(100dvh - var(--header-h));
  overflow-y: auto;
  background: var(--black);
  transform: translateY(-8px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease),
              visibility var(--duration) var(--ease);
}
.site-nav[data-open] { transform: none; opacity: 1; visibility: visible; }

.site-nav__list {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0 1.25rem var(--space-sm);
  list-style: none;
}

.site-nav__link {
  display: block;
  width: 100%;
  padding: 0.75rem 0;
  background: none;
  border: 0;
  border-bottom: 1px solid rgb(255 255 255 / 0.2);
  color: var(--white);
  font-family: "Archivo", sans-serif;
  font-size: var(--text-base);
  font-weight: 400;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--duration) var(--ease);
}
/* Hover is Ludic Deep Blue from the brand kit. On the black bar it has to be
   lightened to stay legible: #44597b on black measures 2.96:1, well under the
   4.5:1 a nav link needs. --blue-on-dark is the same hue opened up until it
   passes. */
.site-nav__link:hover,
.site-nav__sublink:hover { color: var(--blue-on-dark); }
.site-nav__link[aria-current="page"],
.site-nav__toggle[data-nav-current] { font-weight: 600; }

.site-nav__toggle { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.site-nav__caret { flex: none; transition: transform var(--duration) var(--ease); }
[aria-expanded="true"] > .site-nav__caret { transform: rotate(180deg); }

.site-nav__submenu { display: grid; margin: 0; padding: 0 0 0 var(--space-xs); list-style: none; }

/* THE THREE EVENT FORMATS, INDENTED UNDER LUDIC EVENTS. A nested <ul> inside
   the parent's <li>, in the same panel — the client's "inline style" — rather
   than a flyout, which would need its own focus management and would be
   unreachable on touch. The rule on the left is what says "these belong to
   the one above" without needing a second panel to say it. */
/* `ul[role="list"]` in the reset is 0,1,1 and a class is 0,1,0, so a plain
   class selector here loses its margin and padding to the reset and the
   nesting comes out flush. Matching the attribute is the honest way to win
   it — no !important, and the selector says exactly what it is competing
   with. */
ul.site-nav__subsubmenu[role="list"] {
  display: grid;
  margin: 0.15rem 0 0.35rem;
  padding: 0 0 0 var(--space-sm);
  list-style: none;
  border-left: 1px solid rgb(255 255 255 / 0.25);
}
.site-nav__subsubmenu .site-nav__sublink {
  font-size: var(--text-nav);
  opacity: 0.85;
}
.site-nav__subsubmenu .site-nav__sublink:hover,
.site-nav__subsubmenu .site-nav__sublink[aria-current="page"] { opacity: 1; }

.site-nav__sublink {
  display: block;
  padding: 0.625rem 0;
  color: var(--white);
  font-family: "Archivo", sans-serif;
  font-size: var(--text-sm);
  text-decoration: none;
  border-bottom: 1px solid rgb(255 255 255 / 0.12);
  transition: color var(--duration) var(--ease);
}
.site-nav__sublink[aria-current="page"] { font-weight: 600; }

@media (min-width: 64rem) {
  .site-header__toggle { display: none; }
  .site-nav {
    position: static;
    max-height: none;
    overflow: visible;
    background: none;
    transform: none;
    opacity: 1;
    visibility: visible;
  }
  .site-nav__list { flex-direction: row; align-items: center; gap: 0; padding: 0; }
  .site-nav__item { position: relative; }
  .site-nav__link {
    width: auto;
    padding: 0.5rem 0.875rem;
    border: 0;
    font-size: var(--text-nav);
  }
  .site-nav__link[aria-current="page"] { font-weight: 600; }

  /* The panel opens on hover, as asked — but hover is applied in JS, not
     with `:hover` here, and that is deliberate. With a CSS `:hover` rule the
     panel stays visible for as long as the pointer sits on the group, which
     means Escape cannot close it and a keyboard user watching the same
     screen sees a menu that ignores them. Driving visibility from
     [data-open] alone gives one source of truth that hover, click, Enter and
     Escape all write to, and keeps aria-expanded honest.

     No border on the panel; it reads as a continuation of the black bar.
     It starts flush at top:100% so the pointer never crosses a dead stripe
     on the way down and the menu does not flicker shut.

     Collapsed only when the document is scripted (`html[data-js]`, set by an
     inline script in the head). With scripting off nothing can reopen it, so
     it stays on show and the links remain reachable. */
  .site-nav__submenu {
    position: absolute;
    top: 100%;
    left: 0.375rem;
    z-index: 60;
    min-width: 14rem;
    padding: 0.375rem 0;
    background: var(--black);
    border: 0;
    transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease),
                visibility var(--duration) var(--ease);
  }
  [data-js] .site-nav__submenu {
    opacity: 0;
    visibility: hidden;
    transform: translateY(-0.25rem);
  }
  [data-js] .site-nav__item--group[data-open] > .site-nav__submenu {
    opacity: 1;
    visibility: visible;
    transform: none;
  }

  /* THE LAST DROPDOWN HANGS OFF ITS ITEM'S RIGHT EDGE, NOT ITS LEFT.
     "Insights & News" is the second-from-last nav item, so a 14rem panel
     starting at its left edge ran 53px past the viewport at 1024px — the exact
     width where the nav becomes a row. That is a real horizontal scrollbar on
     every page, present whether or not the menu is open: `visibility: hidden`
     hides a box, it does not remove it from the scrollable overflow. It is
     invisible in a screenshot and invisible at 1440px, where there is room.

     `:nth-last-of-type(2)` counts `li`, so this is "the second-from-last nav
     item, if it is a group" — which is Insights & News and nothing else. If
     the nav is reordered and some other group lands near the right edge,
     browser_checks.py::check_overflow reports it at 1024px on every page. */
  .site-nav__item--group:nth-last-of-type(1) > .site-nav__submenu,
  .site-nav__item--group:nth-last-of-type(2) > .site-nav__submenu {
    left: auto;
    right: 0.375rem;
  }
  .site-nav__sublink {
    padding: 0.5rem 0.875rem;
    border: 0;
    font-size: var(--text-nav);
    white-space: nowrap;
  }

  /* The nested list inside the desktop panel. The parent's own padding is
     on the LINK rather than the list here, so the indent and the rule have
     to be set again at this width or the three formats sit flush with their
     siblings and the nesting is invisible. */
  ul.site-nav__subsubmenu[role="list"] {
    margin: 0 0 0.25rem 1.5rem;
    padding-left: 0.75rem;
  }
  .site-nav__subsubmenu .site-nav__sublink { padding-block: 0.35rem; }
}

/* ---------- footer ------------------------------------------------------ */
.footer {
  background: var(--black);
  color: var(--white);
  padding-top: var(--space-xl);
}

.footer__inner {
  display: grid;
  gap: var(--space-md);
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 1.25rem;
}
@media (min-width: 48rem) {
  .footer__inner { padding-inline: 2rem; }
}
/* The live footer is a wide left column and a right-aligned block of link
   lists — measured at 1440: left column 224px, menu block 325px hard against
   the right edge. Not four equal columns. */
@media (min-width: 64rem) {
  .footer__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    padding-inline: var(--container-pad);
  }
}

.footer__logo { width: auto; height: 1.0625rem; }

.footer__details { margin-top: var(--space-md); display: grid; gap: var(--space-sm); }
.footer__label { font-weight: 700; }

/* THE MENU COLUMNS ARE AS WIDE AS THEIR LONGEST ENTRY, not a fixed 146px.
   Measured on the live footer every link is shrink-to-fit — 107, 133, 80, 92,
   238px — and the two columns sit 270px apart, so nothing wraps. A fixed
   9.125rem column broke "Ludic Communications & Engagement" and three others
   over two lines, which is what the client saw. Below 64rem the columns go
   back to equal fractions and labels wrap, because there the width belongs to
   the screen and a max-content column would push the footer sideways. */
.footer__menu { display: grid; gap: var(--space-md); }
@media (min-width: 36rem) { .footer__menu { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64rem) {
  .footer__menu { grid-template-columns: repeat(2, max-content); gap: var(--space-lg); }
  .footer__menu .footer__link { white-space: nowrap; }
}

.footer__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-top: var(--space-md);
  padding: 0;
  list-style: none;
}
.footer__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem; height: 2rem;
  color: var(--white);
  transition: color var(--duration) var(--ease);
}
.footer__social-link:hover { color: var(--blue-on-dark); }

.footer__heading {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--white);
  margin-bottom: var(--space-2xs);
}

.footer__text { color: var(--white); font-size: var(--text-xs); line-height: 1.6; }

.footer__list { display: grid; gap: 0.5rem; margin: 0; padding: 0; list-style: none; align-content: start; }

.footer__link {
  color: var(--white);
  font-size: var(--text-xs);
  line-height: 1.5;
  text-decoration: none;
  transition: color var(--duration) var(--ease);
}
/* Same hover as the header nav: Ludic Deep Blue opened up for the black
   background, no underline. */
.footer__link:hover { color: var(--blue-on-dark); text-decoration: none; }

.footer__link--button { background: none; border: 0; padding: 0; cursor: pointer; text-align: left; font-family: inherit; }

.footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
  width: 100%;
  max-width: var(--container);
  margin: var(--space-lg) auto 0;
  padding: var(--space-sm) 1.25rem var(--space-md);
  border-top: 1px solid rgb(255 255 255 / 0.25);
}
@media (min-width: 48rem) { .footer__legal { padding-inline: 2rem; } }
@media (min-width: 64rem) { .footer__legal { padding-inline: var(--container-pad); } }

.footer__credit { color: var(--white); font-size: var(--text-xs); }

.footer__legal-list { display: flex; flex-wrap: wrap; gap: 0.5rem var(--space-sm); margin: 0; padding: 0; list-style: none; }
/* The legal row keeps its underline at rest — it is a run of small links
   in a crowded strip and needs the affordance — but drops it on hover along
   with everything else in the footer. */
.footer__legal-list .footer__link { text-decoration: underline; }
.footer__legal-list .footer__link:hover { text-decoration: none; color: var(--blue-on-dark); }

/* ---------- print ------------------------------------------------------- */
@media print {
  .site-header, .footer, .consent, .skip-link, .filters { display: none !important; }
  body { color: #000; font-size: 11pt; }
  a::after { content: " (" attr(href) ")"; font-size: 9pt; }
}

/* ---------- breadcrumbs -------------------------------------------------
   On every page except the home page, between the header and the first
   band. A trail whose only entry is the page you are on is furniture, so the
   home page opts out in its own config.

   The current page is a <span>, never a link: linking a page to itself is a
   dead target for a pointer and a trap for a screen reader. `aria-current`
   marks it instead.

   The separator is a CSS ::before on a decorative pseudo-element rather than
   a character in the markup, so it is not read out 120 times a visit.
   ----------------------------------------------------------------------- */
.breadcrumb {
  background: var(--surface);
  /* NO RULE, and equal air above and below. It used to sit tight under the
     nav with a 1px line beneath it and then a large gap before the hero,
     which read as three separate things: the crumb belonged to the header,
     the line divided nothing, and the hero floated. It is one band now, and
     the trail is centred in it. */
}

.breadcrumb__list {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.5rem;
  margin: 0;
  /* Equal top and bottom, so the trail is vertically centred between the nav
     above it and the band below. */
  padding-block: 1.25rem;
  list-style: none;
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}

.breadcrumb__item { display: flex; align-items: baseline; gap: 0.5rem; }

.breadcrumb__item + .breadcrumb__item::before {
  content: "/";
  color: var(--mid-grey);
  /* Not in the markup: a separator repeated on every crumb of every page is
     120 characters of noise a screen reader would read aloud. */
}

.breadcrumb__link {
  color: var(--ink-muted);
  text-decoration: underline;
  text-decoration-color: var(--line);
}
.breadcrumb__link:hover { color: var(--blue-ink); text-decoration-color: currentColor; }

/* A crumb with no page — the "Services" nav group, which is a dropdown and
   not a route. Rendering it as a link to nowhere would be the same mistake
   the archive makes fourteen times on the Events page. */
.breadcrumb__label { color: var(--ink-muted); }
.breadcrumb__item--current .breadcrumb__label { color: var(--ink); font-weight: 600; }

/* Long item titles: the last crumb truncates rather than wrapping to three
   lines and pushing the page down. The full title is the h1 immediately
   below it, so nothing is lost. */
@media (min-width: 48rem) {
  .breadcrumb__item--current .breadcrumb__label {
    display: inline-block;
    max-width: 32rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
  }
}

@media print {
  .breadcrumb { display: none; }
}

/* The footer wordmark is a link. The archive's points at "#" — it goes
   nowhere, on every page. */
.footer__logo-link { display: inline-block; }

/* ---------- band tones --------------------------------------------------
   One rule per measured band colour. A block asks for a tone by name and gets
   the background AND the ink that belongs on it, so no caller can put white
   copy on lime by forgetting.

   `--ink` and `--accent-on` are re-pointed inside the band rather than every
   component being taught about tones: a button, a rule, an eyebrow and a
   heading inside a pink band all read the same two variables they read
   everywhere else.
   ----------------------------------------------------------------------- */
.section[data-tone="light-green"],
.section[data-tone="light-lime"],
.section[data-tone="lime"],
.section[data-tone="lime-deep"],
.section[data-tone="turquoise"],
.section[data-tone="aqua"],
.section[data-tone="pink"],
.section[data-tone="mid-blue"],
.section[data-tone="yellow"],
.section[data-tone="creatives-yellow"],
.section[data-tone="lightest-blue"],
.section[data-tone="off-white"],
.section[data-tone="curious-red"] {
  color: var(--black);
  --ink: var(--black);
  --ink-muted: #3a3a3a;
  --line: rgb(0 0 0 / 0.22);
  --control-line: var(--black);
}

.section[data-tone="light-green"]     { --band: var(--band-light-green); background: var(--band); }
.section[data-tone="light-lime"]      { --band: var(--band-light-lime); background: var(--band); }
.section[data-tone="lime"]            { --band: var(--band-lime); background: var(--band); }
.section[data-tone="lime-deep"]       { --band: var(--band-lime-deep); background: var(--band); }
.section[data-tone="turquoise"]       { --band: var(--band-turquoise); background: var(--band); }
.section[data-tone="aqua"]            { --band: var(--band-aqua); background: var(--band); }
.section[data-tone="pink"]            { --band: var(--band-pink); background: var(--band); }
.section[data-tone="mid-blue"]        { --band: var(--band-mid-blue); background: var(--band); }
.section[data-tone="yellow"]          { --band: var(--band-yellow); background: var(--band); }
.section[data-tone="creatives-yellow"]{ --band: var(--band-creatives-yellow); background: var(--band); }
.section[data-tone="lightest-blue"]   { --band: var(--band-lightest-blue); background: var(--band); }
.section[data-tone="off-white"]       { --band: var(--band-off-white); background: var(--band); }
.section[data-tone="curious-red"]     { --band: var(--band-curious-red); background: var(--band); }

/* The two dark bands. White ink, and the focus ring goes white with it. */
.section[data-tone="deep-blue"],
.section[data-tone="dh-purple"],
.section[data-tone="smartlab-blue"] {
  color: var(--white);
  --ink: var(--white);
  --ink-muted: rgb(255 255 255 / 0.84);
  --line: rgb(255 255 255 / 0.3);
  --control-line: var(--white);
}
.section[data-tone="deep-blue"] { --band: var(--band-deep-blue); background: var(--band); }
.section[data-tone="dh-purple"] { --band: var(--band-dh-purple); background: var(--band); }
.section[data-tone="smartlab-blue"] { --band: var(--band-smartlab-blue); background: var(--band); }
/* FULL WHITE FOR THE MUTED INK ON THIS ONE. The shared dark-band rule above
   sets `--ink-muted: rgb(255 255 255 / 0.84)`, which composites to #DFE9F8 on
   this band and measures 3.74:1 — under AA, and it is the colour the column
   sub-lines and ordinals are set in. The SmartLab band is the lightest of the
   three dark tones, so the alpha that works on Deep Blue (5.57:1) does not
   work here. Hierarchy on this band comes from size, not from fade — which is
   the same conclusion the purple podcast band reached about its eyebrow. */
.section[data-tone="smartlab-blue"] { --ink-muted: var(--white); }
.section[data-tone="deep-blue"] :focus-visible,
.section[data-tone="dh-purple"] :focus-visible,
.section[data-tone="smartlab-blue"] :focus-visible { outline-color: var(--white); }

/* A button on a coloured band: the archive keeps it black with white copy on
   every one of them, and at 6.8:1 or better against each band it reads as an
   object rather than a hole. Hover inverts, as everywhere else. */
.section[data-tone="light-green"] .button,
.section[data-tone="light-lime"] .button,
.section[data-tone="lime"] .button,
.section[data-tone="lime-deep"] .button,
.section[data-tone="turquoise"] .button,
.section[data-tone="aqua"] .button,
.section[data-tone="pink"] .button,
.section[data-tone="mid-blue"] .button,
.section[data-tone="yellow"] .button,
.section[data-tone="creatives-yellow"] .button,
.section[data-tone="lightest-blue"] .button,
.section[data-tone="off-white"] .button,
.section[data-tone="curious-red"] .button {
  border-color: var(--black);
  background: var(--black);
  color: var(--white);
}
.section[data-tone="light-green"] .button:hover,
.section[data-tone="light-lime"] .button:hover,
.section[data-tone="lime"] .button:hover,
.section[data-tone="lime-deep"] .button:hover,
.section[data-tone="turquoise"] .button:hover,
.section[data-tone="aqua"] .button:hover,
.section[data-tone="pink"] .button:hover,
.section[data-tone="mid-blue"] .button:hover,
.section[data-tone="yellow"] .button:hover,
.section[data-tone="creatives-yellow"] .button:hover,
.section[data-tone="lightest-blue"] .button:hover,
.section[data-tone="off-white"] .button:hover,
.section[data-tone="curious-red"] .button:hover {
  background: transparent;
  color: var(--black);
}

.section[data-tone="deep-blue"] .button,
.section[data-tone="dh-purple"] .button {
  border-color: var(--white);
  background: var(--white);
  color: var(--black);
}
.section[data-tone="deep-blue"] .button:hover,
.section[data-tone="dh-purple"] .button:hover {
  background: transparent;
  color: var(--white);
}
