/* Stylesheet entry. Native CSS only: no build step, served as written.
   Layers decide what wins, regardless of order: later layers beat earlier ones. */
@layer reset, tokens, base, layout, components, utilities;

/* Registered custom properties. Non-inheriting, so a nested .grid's children don't pick up their parent's span. */
@property --col-span { syntax: "*"; inherits: false; }
@property --col-start { syntax: "*"; inherits: false; }

/* Avenir Next (Avenir Next LT Pro), served from this project: src/fonts, copied to /fonts on build.
   Weights: 400 Regular, 500 Medium, 600 Demi (the design's 600), 700 Bold.
   was: loaded from transmissionagency.com/wp-content/themes/transmission/assets/fonts/ (same files), with
   Medium mapped to 600, which looked lighter than the design's Demi. */
@font-face {
  font-family: "AvenirNext";
  src: url("../fonts/AvenirNextRegular/font.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "AvenirNext";
  src: url("../fonts/AvenirNextMedium/font.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "AvenirNext";
  src: url("../fonts/AvenirNextDemiBold/font.woff2") format("woff2"); /* was: font.woff (woff) */
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "AvenirNext";
  src: url("../fonts/AvenirNextBold/font.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@layer reset {
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: none; text-size-adjust: none; }
body { min-block-size: 100svh; line-height: 1.5; -webkit-font-smoothing: antialiased; }
img, picture, video, canvas, svg { display: block; max-inline-size: 100%; }
img, video { block-size: auto; }
input, button, textarea, select { font: inherit; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
h1, h2, h3, h4 { text-wrap: balance; }
p, li, figcaption { text-wrap: pretty; }
ul[role="list"], ol[role="list"] { list-style: none; padding: 0; }

}
@layer tokens {
:root {
  /* Colour */
  --colour-text: #141414;
  --colour-bg: #ffffff;
  --colour-accent: #df2080;
  --colour-focus: #1063ff;
  --colour-muted: color-mix(in oklab, var(--colour-text) 60%, var(--colour-bg));
  --colour-surface: color-mix(in oklab, var(--colour-text) 6%, var(--colour-bg));

  /* Fonts */
  --font-body: system-ui, sans-serif;
  --font-heading: var(--font-body);

  /* Type: 16px @ 320px (ratio 1.2) → 20px @ 1600px (ratio 1.25) */
  --step--1: clamp(0.8333rem, 0.7917rem + 0.2083vw, 1rem);
  --step-0: clamp(1rem, 0.9375rem + 0.3125vw, 1.25rem);
  --step-1: clamp(1.2rem, 1.1094rem + 0.4531vw, 1.5625rem);
  --step-2: clamp(1.44rem, 1.3117rem + 0.6414vw, 1.9531rem);
  --step-3: clamp(1.728rem, 1.5496rem + 0.8918vw, 2.4414rem);
  --step-4: clamp(2.0736rem, 1.8291rem + 1.2227vw, 3.0518rem);
  --step-5: clamp(2.4883rem, 2.1567rem + 1.658vw, 3.8147rem);

  /* Space: multiples of the step-0 size */
  --space-3xs: clamp(0.25rem, 0.2344rem + 0.0781vw, 0.3125rem);
  --space-2xs: clamp(0.5rem, 0.4688rem + 0.1562vw, 0.625rem);
  --space-xs: clamp(0.75rem, 0.7031rem + 0.2344vw, 0.9375rem);
  --space-s: clamp(1rem, 0.9375rem + 0.3125vw, 1.25rem);
  --space-m: clamp(1.5rem, 1.4062rem + 0.4688vw, 1.875rem);
  --space-l: clamp(2rem, 1.875rem + 0.625vw, 2.5rem);
  --space-xl: clamp(3rem, 2.8125rem + 0.9375vw, 3.75rem);
  --space-2xl: clamp(4rem, 3.75rem + 1.25vw, 5rem);
  --space-3xl: clamp(6rem, 5.625rem + 1.875vw, 7.5rem);

  /* Layout */
  --content-width: 46rem;
  --wide-width: 90rem;
  --gutter: var(--space-m); /* page side margin: the content grid's outer columns */
  --columns: 12;
  --gap: var(--space-m);
  --scroll-offset: var(--space-l);
  --radius: 4px;

  /* Motion */
  --duration: 300ms;
  --reveal-duration: var(--duration); /* scroll reveals: .animate and .stagger pieces (base/motion.css) */
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* Shell colours (progress bar, floating CTA) */
  --progress-start: var(--colour-accent);
  --progress-end: var(--colour-focus);
  --cta-bg: var(--colour-text);
  --cta-text: var(--colour-bg);
  --cta-hover: var(--colour-accent);

  /* Stacking */
  --z-cta: 200;
  --z-progress: 400;
}

/* Section themes: `theme: dark` on a block in page.yaml sets data-theme="dark" on its <section>. */
[data-theme="dark"] {
  --colour-text: #ffffff;
  --colour-bg: #141414;
}

}
@layer tokens {
/* PROJECT TOKENS: override any token from base/tokens.css here. Values only, not structure. */
:root {
  /* --colour-accent: #df2080; */
  --font-body: "AvenirNext", system-ui, sans-serif;

  /* Section body copy (every block's __body): 16px on small screens, scaling to a max of 18px.
     Middle value = 18 ÷ Figma frame width × 100 (1.125vw assumes a 1600px frame). */
  --body-size: clamp(1rem, 1.125vw, 1.125rem);

  /* Stat box width, the same in every section: 208px minimum, 20% of the window, 416px maximum.
     Sized so three boxes fit side by side in the content column. */
  --stat-width: clamp(13rem, 20vw, 26rem);

  /* Layout: content stays within 1600px (the content grid's `wide` column), centred on wider screens.
     One side margin for every section: 24px on small screens, 4.4% of the window, 80px max. */
  --wide-width: 100rem; /* was: 90rem (1440px, from base) */
  --gutter: clamp(1.5rem, 4.4vw, 5rem);

  /* Scroll reveals (.animate and piece-by-piece .stagger): a little slower than the base 300ms. */
  --reveal-duration: 0.6s;

  /* --progress-start: #df2080;  --progress-end: #1063ff; */
  --cta-bg: #000000;
  --cta-text: #ffffff;
  --cta-hover: #2b2b2b;
}

/* Section colour themes: `theme: <name>` on a block in longform.yaml. Colours approximate the design;
   swap in the exact brand values. */
[data-theme="dark"]   { --colour-bg: #303031; --colour-text: #ffffff; }
[data-theme="green"]  { --colour-bg: #6C9484; --colour-text: #ffffff; }
[data-theme="blue"]   { --colour-bg: #1C5EA7; --colour-text: #ffffff; }
[data-theme="pink"]   { --colour-bg: #A76072; --colour-text: #ffffff; }
[data-theme="purple"] { --colour-bg: #7B5AB1; --colour-text: #ffffff; }

}
@layer base {
html {
  color-scheme: light;

  @media (prefers-reduced-motion: no-preference) {
    scroll-behavior: smooth;
  }
}

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  color: var(--colour-text);
  background: var(--colour-bg);
}

h1, h2, h3, h4 { font-family: var(--font-heading); line-height: 1.1; }
h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

a { color: inherit; text-underline-offset: 0.15em; }

:focus-visible { outline: 3px solid var(--colour-focus); outline-offset: 3px; }

.skip-link {
  position: absolute;
  inset-block-start: var(--space-s);
  inset-inline-start: var(--space-s);
  z-index: calc(var(--z-progress) + 1);
  padding: var(--space-2xs) var(--space-s);
  background: var(--colour-bg);
  translate: 0 -200%;

  &:focus { translate: 0 0; }
}

.button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-s);
  border-radius: 999px;
  background: var(--colour-accent);
  color: var(--colour-bg);
  font-weight: 700;
  text-decoration: none;
}

.container {
  max-width: var(--wide-width);
  margin-inline: auto;
  padding-inline: var(--space-s);
}
}
@layer layout {
/* Content grid: every section is one. Children sit in the `content` column by default;
   .breakout-wide / .breakout-full span the wider tracks. */
.content-grid {
  /* --gutter comes from tokens (was set here as var(--space-m), so projects couldn't change it) */
  --breakout: calc((var(--wide-width) - var(--content-width)) / 2);

  display: grid;
  grid-template-columns:
    [full-start] minmax(var(--gutter), 1fr)
    [wide-start] minmax(0, var(--breakout))
    [content-start] min(100% - var(--gutter) * 2, var(--content-width)) [content-end]
    minmax(0, var(--breakout)) [wide-end]
    minmax(var(--gutter), 1fr) [full-end];
  row-gap: var(--space-m);
}

.content-grid > * { grid-column: content; }
.content-grid > .breakout-wide { grid-column: wide; }
.content-grid > .breakout-full { grid-column: full; }

.panel {
  container-type: inline-size;
  padding-block: var(--section-space, var(--space-2xl));
  scroll-margin-block-start: var(--scroll-offset);
}

.panel[data-padding="false"] { padding-block: 0; }

[data-theme] {
  background: var(--colour-bg);
  color: var(--colour-text);
}

}
@layer layout {
/* 12-column grid. Children span every column by default (mobile first).
   .col-{n} / .col-{bp}-{n} set the span; .col-start-{n} / .col-{bp}-start-{n} set the start line.
   Written out statically on purpose; update by hand if --columns ever changes. */

/* --col-span / --col-start are registered as non-inheriting in properties.css.
   Breakpoints: sm 640, md 960, lg 1280, xl 1600 (min-width). */

.grid {
  display: grid;
  grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
  gap: var(--gap-y, var(--gap)) var(--gap);
}

.grid > * {
  grid-column: var(--col-start, auto) / span var(--col-span, var(--columns));
}

.subgrid {
  display: grid;
  grid-template-columns: subgrid;
}

.row-span-2 { grid-row: span 2; }
.row-span-3 { grid-row: span 3; }
.row-span-4 { grid-row: span 4; }

/* Base (all widths) */
.col-1 { --col-span: 1; }
.col-2 { --col-span: 2; }
.col-3 { --col-span: 3; }
.col-4 { --col-span: 4; }
.col-5 { --col-span: 5; }
.col-6 { --col-span: 6; }
.col-7 { --col-span: 7; }
.col-8 { --col-span: 8; }
.col-9 { --col-span: 9; }
.col-10 { --col-span: 10; }
.col-11 { --col-span: 11; }
.col-12 { --col-span: 12; }
.col-start-1 { --col-start: 1; }
.col-start-2 { --col-start: 2; }
.col-start-3 { --col-start: 3; }
.col-start-4 { --col-start: 4; }
.col-start-5 { --col-start: 5; }
.col-start-6 { --col-start: 6; }
.col-start-7 { --col-start: 7; }
.col-start-8 { --col-start: 8; }
.col-start-9 { --col-start: 9; }
.col-start-10 { --col-start: 10; }
.col-start-11 { --col-start: 11; }
.col-start-12 { --col-start: 12; }

@media (width >= 640px) {
  .col-sm-1 { --col-span: 1; }
  .col-sm-2 { --col-span: 2; }
  .col-sm-3 { --col-span: 3; }
  .col-sm-4 { --col-span: 4; }
  .col-sm-5 { --col-span: 5; }
  .col-sm-6 { --col-span: 6; }
  .col-sm-7 { --col-span: 7; }
  .col-sm-8 { --col-span: 8; }
  .col-sm-9 { --col-span: 9; }
  .col-sm-10 { --col-span: 10; }
  .col-sm-11 { --col-span: 11; }
  .col-sm-12 { --col-span: 12; }
  .col-sm-start-1 { --col-start: 1; }
  .col-sm-start-2 { --col-start: 2; }
  .col-sm-start-3 { --col-start: 3; }
  .col-sm-start-4 { --col-start: 4; }
  .col-sm-start-5 { --col-start: 5; }
  .col-sm-start-6 { --col-start: 6; }
  .col-sm-start-7 { --col-start: 7; }
  .col-sm-start-8 { --col-start: 8; }
  .col-sm-start-9 { --col-start: 9; }
  .col-sm-start-10 { --col-start: 10; }
  .col-sm-start-11 { --col-start: 11; }
  .col-sm-start-12 { --col-start: 12; }
}

@media (width >= 960px) {
  .col-md-1 { --col-span: 1; }
  .col-md-2 { --col-span: 2; }
  .col-md-3 { --col-span: 3; }
  .col-md-4 { --col-span: 4; }
  .col-md-5 { --col-span: 5; }
  .col-md-6 { --col-span: 6; }
  .col-md-7 { --col-span: 7; }
  .col-md-8 { --col-span: 8; }
  .col-md-9 { --col-span: 9; }
  .col-md-10 { --col-span: 10; }
  .col-md-11 { --col-span: 11; }
  .col-md-12 { --col-span: 12; }
  .col-md-start-1 { --col-start: 1; }
  .col-md-start-2 { --col-start: 2; }
  .col-md-start-3 { --col-start: 3; }
  .col-md-start-4 { --col-start: 4; }
  .col-md-start-5 { --col-start: 5; }
  .col-md-start-6 { --col-start: 6; }
  .col-md-start-7 { --col-start: 7; }
  .col-md-start-8 { --col-start: 8; }
  .col-md-start-9 { --col-start: 9; }
  .col-md-start-10 { --col-start: 10; }
  .col-md-start-11 { --col-start: 11; }
  .col-md-start-12 { --col-start: 12; }
}

@media (width >= 1280px) {
  .col-lg-1 { --col-span: 1; }
  .col-lg-2 { --col-span: 2; }
  .col-lg-3 { --col-span: 3; }
  .col-lg-4 { --col-span: 4; }
  .col-lg-5 { --col-span: 5; }
  .col-lg-6 { --col-span: 6; }
  .col-lg-7 { --col-span: 7; }
  .col-lg-8 { --col-span: 8; }
  .col-lg-9 { --col-span: 9; }
  .col-lg-10 { --col-span: 10; }
  .col-lg-11 { --col-span: 11; }
  .col-lg-12 { --col-span: 12; }
  .col-lg-start-1 { --col-start: 1; }
  .col-lg-start-2 { --col-start: 2; }
  .col-lg-start-3 { --col-start: 3; }
  .col-lg-start-4 { --col-start: 4; }
  .col-lg-start-5 { --col-start: 5; }
  .col-lg-start-6 { --col-start: 6; }
  .col-lg-start-7 { --col-start: 7; }
  .col-lg-start-8 { --col-start: 8; }
  .col-lg-start-9 { --col-start: 9; }
  .col-lg-start-10 { --col-start: 10; }
  .col-lg-start-11 { --col-start: 11; }
  .col-lg-start-12 { --col-start: 12; }
}

@media (width >= 1600px) {
  .col-xl-1 { --col-span: 1; }
  .col-xl-2 { --col-span: 2; }
  .col-xl-3 { --col-span: 3; }
  .col-xl-4 { --col-span: 4; }
  .col-xl-5 { --col-span: 5; }
  .col-xl-6 { --col-span: 6; }
  .col-xl-7 { --col-span: 7; }
  .col-xl-8 { --col-span: 8; }
  .col-xl-9 { --col-span: 9; }
  .col-xl-10 { --col-span: 10; }
  .col-xl-11 { --col-span: 11; }
  .col-xl-12 { --col-span: 12; }
  .col-xl-start-1 { --col-start: 1; }
  .col-xl-start-2 { --col-start: 2; }
  .col-xl-start-3 { --col-start: 3; }
  .col-xl-start-4 { --col-start: 4; }
  .col-xl-start-5 { --col-start: 5; }
  .col-xl-start-6 { --col-start: 6; }
  .col-xl-start-7 { --col-start: 7; }
  .col-xl-start-8 { --col-start: 8; }
  .col-xl-start-9 { --col-start: 9; }
  .col-xl-start-10 { --col-start: 10; }
  .col-xl-start-11 { --col-start: 11; }
  .col-xl-start-12 { --col-start: 12; }
}

}
@layer layout {
/* Vertical rhythm between direct children. Set --stack-space to change the gap. */
.stack { display: flex; flex-direction: column; justify-content: flex-start; }
.stack > * + * { margin-block-start: var(--stack-space, var(--space-s)); }

/* Wrapping inline group: tags, buttons, logos. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cluster-space, var(--space-s));
  align-items: var(--cluster-align, center);
  justify-content: var(--cluster-justify, flex-start);
}

/* Prose spacing for rendered markdown. */
.flow > * + * { margin-block-start: var(--flow-space, 1em); }
.flow > :where(h2, h3, h4) { --flow-space: 1.6em; }
.flow > :where(h2, h3, h4) + * { --flow-space: 0.5em; }

}
@layer components {
/* SHARED: progress bar and floating CTA. */

/* Progress bar */
.progress {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-progress);
  block-size: 10px;
  background: color-mix(in oklab, var(--colour-text) 15%, transparent);
}

.progress__bar {
  block-size: 100%;
  background: var(--progress-start);
  transform-origin: 0 50%;
  transform: scaleX(var(--progress, 0));
}

/* Scroll-driven where supported (no JS); js/base/progress.js covers other browsers. */
@supports (animation-timeline: scroll()) {
  .progress__bar {
    animation: progress-grow linear both;
    animation-timeline: scroll(root block);
  }
}

@keyframes progress-grow {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* Floating CTA */
.floating-cta {
  display: none;
  position: fixed;
  inset-block-end: var(--space-m);
  inset-inline-end: var(--space-m);
  right: 40px;
  z-index: var(--z-cta);
  padding: var(--space-xs) var(--space-s);
  border-radius: 999px;
  background: var(--cta-bg, var(--colour-text));
  color: var(--cta-text, var(--colour-bg));
  font-size: var(--step--1);
  font-weight: 700;
  text-decoration: none;
  text-transform: uppercase;
  transition:
    background-color var(--duration) var(--ease-out),
    opacity var(--duration) var(--ease-out),
    translate var(--duration) var(--ease-out),
    visibility 0s linear 0s;
}

.floating-cta:hover,
.floating-cta:focus-visible { background: var(--cta-hover, var(--colour-accent)); }

/* Hidden while the section it links to is on screen (js/base/cta.js). visibility also takes it out of the tab
   order; it switches off only once the fade has finished. */
.floating-cta.is-hidden {
  opacity: 0;
  translate: 0 1rem;
  visibility: hidden;
  pointer-events: none;
  transition-delay: 0s, 0s, 0s, var(--duration);
}

@media (prefers-reduced-motion: reduce) {
  .floating-cta { transition: none; }
}

@media (width >= 1280px) {
  .floating-cta { display: inline-flex; }
}

}
@layer components {
/* PROJECT: footer styles (markup in src/templates/footer.njk).
   was: padding-block: var(--space-xl) calc(var(--space-xl) + 3.125rem); background: var(--colour-surface);
        font-size: var(--step--1); logo 2.5rem tall; links in a cluster, right-aligned from 960px */
/* A content grid (templates/footer.njk): logo and links sit in its `wide` column, so the side margins and the
   1600px max width come from --gutter and --wide-width, as in the sections. */
.site-footer {
  row-gap: clamp(2rem, 3.2vw, 3.25rem); /* row-gap only: a column gap would shift the content grid's tracks */
  /* Extra space at the bottom keeps the floating button clear of the text on small screens.
     was: padding: … clamp(1.5rem, 6.25vw, 6.25rem) … (own side margins) */
  padding: clamp(3rem, 5.8vw, 6rem) 0 clamp(6rem, 6.7vw, 7rem);
  background: #222222;
  color: #ffffff;
  font-size: 1rem;
  line-height: 1.4;
}

.site-footer__logo { justify-self: start; }

.site-footer__logo img {
  display: block;
  block-size: clamp(1.5rem, 2vw, 2rem); /* 32px tall (200px wide) on wide screens */
  inline-size: auto;
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s) var(--space-l);
  justify-content: space-between;
  align-items: baseline;
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-m);
  padding: 0;
}

/* Mobile: copyright, privacy and cookie links one per line. */
@media (width < 640px) {
  .site-footer__links { flex-direction: column; }
}

.site-footer a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

/* Hover: the shared link highlight in project.css. was: .site-footer a:hover { text-decoration-thickness: 2px; } */

}
@layer components {
/* PROJECT CSS: global, project-specific styles. Block styles belong in css/blocks/<type>.css.
   Breakpoints: sm 640, md 960, lg 1280, xl 1600, e.g. @media (width >= 960px) { … } */

/* Outlined text in headings: wrap words in _underscores_ in longform.yaml titles. */
:is(h1, h2, h3) em {
  font-style: normal;
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke: 0.03em currentColor;
}

/* Floating CTA, as in the design: black with a pink border, square, flush to the right edge. */
.floating-cta {
  inset-inline-end: 0;
  padding: var(--space-xs) var(--space-m);
  border: 2px solid var(--colour-accent);
  border-inline-end: 0;
  border-radius: 0;
  letter-spacing: 0.06em;
}

.floating-cta:is(button) {
  font: inherit;
  font-size: var(--step--1);
  font-weight: 700;
  cursor: pointer;
}

/* Video popup (js/video-modal.js), opened by the floating CTA: the video fills as much of the screen as fits at 16:9,
   on a near-black backdrop, with a pink close button top right. */
.video-modal {
  inline-size: 100%;
  max-inline-size: none;
  block-size: 100%;
  max-block-size: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
}

.video-modal[open] {
  display: grid;
  place-items: center;
}

.video-modal::backdrop { background: rgb(0 0 0 / 0.95); }

.video-modal__frame {
  inline-size: min(95vw, calc(88svh * 16 / 9), 1500px);
  aspect-ratio: 16 / 9;
}

.video-modal__frame iframe {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  border: 0;
}

.video-modal__close {
  position: absolute;
  inset-block-start: var(--space-s);
  inset-inline-end: var(--space-s);
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  aspect-ratio: 1;
  padding: 0.6rem;
  border: 0;
  background: var(--colour-accent);
  color: #ffffff;
  cursor: pointer;
}

.video-modal__close svg { inline-size: 100%; }

/* Stop the page scrolling behind the popup. */
html:has(.video-modal[open]) { overflow: hidden; }

/* Buttons, as in the design: black with a pink border, square, uppercase. */
.button {
  padding: 1em 1.6em;
  border: 2px solid var(--colour-accent);
  border-radius: 0;
  background: var(--cta-bg);
  color: var(--cta-text);
  font-size: clamp(0.9rem, 1vw, 1.25rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: background-color var(--duration) var(--ease-out);
}

.button:hover,
.button:focus-visible { background: var(--cta-hover); }

/* Text links (in the copy, stat sources and footer): on hover or keyboard focus, black text on a white highlight.
   a:not([class]) leaves out styled links such as the logo, the CTA and buttons. The box-shadow extends the white
   a little either side without moving the text, and box-decoration-break keeps it on every line of a link that
   wraps. */
a:not([class]) {
  border-radius: 0.1em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  transition:
    background-color var(--duration) var(--ease-out),
    box-shadow var(--duration) var(--ease-out),
    color var(--duration) var(--ease-out),
    text-decoration-color var(--duration) var(--ease-out);
}

a:not([class]):hover,
a:not([class]):focus-visible {
  background-color: #fff;
  box-shadow: 0 0 0 0.15em #fff;
  color: #000;
  text-decoration-color: transparent;
}

/* Scroll snap (desktop) is now handled by js/snap.js, which glides more slowly and smoothly than the browser's
   built-in snap (CSS gives no control over its speed). Previous CSS version, kept for reference:
@media (width >= 960px) {
  html { scroll-snap-type: y proximity; }

  .panel {
    scroll-snap-align: start;
    scroll-margin-block-start: 0;
  }

  .site-footer { scroll-snap-align: end; }
}
*/

}

/* Partials: shared pieces included by several blocks */
@layer components {
/* Character videos (partials/character.njk). Square by default; set --character-ratio (e.g. 3 / 4) and
   --character-size on a block to change their shape and maximum size. */
.character {
  display: block;
  inline-size: 100%;
  max-inline-size: var(--character-size, 28rem);
  block-size: auto;
  aspect-ratio: var(--character-ratio, 1);
  object-fit: contain;
  margin-inline: auto;
  background: transparent;
  rotate: var(--character-rotate, 0deg);
}

}
@layer components {
/* Stat boxes (partials/stats.njk): square outlined boxes with a big outlined number; wrap on small screens. */
.stats {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1rem, 2.6vw, 3.5rem);
  padding: 0;
}

/* Wide screens: keep a row of boxes on one line, shrinking them to fit rather than wrapping. */
@media (width >= 960px) {
  .stats { flex-wrap: nowrap; }
}

.stat {
  display: flex;
  /* Every box is the same width in every section (--stat-width in css/tokens.css), except that a box grows to
     fit a wider value (e.g. "40-60%"). Boxes only shrink, all equally, if a row would otherwise overflow a narrow
     window.
     was: flex: 1 1 0; min-inline-size: 13rem; max-inline-size: 28rem; (stretched to fill the row)
     before that: flex: 0 1 clamp(14rem, 21vw, 28rem); */
  flex: 0 1 var(--stat-width, clamp(13rem, 20vw, 26rem));
  flex-direction: column;
  min-block-size: clamp(12rem, 16.8vw, 22rem);
  padding: clamp(0.75rem, 0.9vw, 1.25rem);
  border: 1.5px solid currentColor;
}

.stat__value {
  /* Figma "V26 Stat": 100px, weight 700, line-height 120%, letter-spacing 2px, 2px white outline.
     Size: 84px rather than Figma's 100px, so a wide value ("40-60%") doesn't stretch its box too far.
     Middle value = 84 ÷ Figma frame width × 100 (5.25vw assumes a 1600px frame).
     was: font-size: clamp(3.5rem, 6.25vw, 6.25rem); (Figma's 100px)
     before that: clamp(3.5rem, 7vw, 9rem); font-weight: 400; line-height: 1; -webkit-text-stroke: 0.012em currentColor; */
  font-family: var(--font-heading);
  font-size: clamp(3.5rem, 5.25vw, 5.25rem);
  /* One line, never broken (e.g. after the hyphen of "40-60%"): a value wider than the box widens its box. */
  white-space: nowrap;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.02em; /* 2px at 100px; scales with the text */
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke: 2px currentColor; /* white: follows the section's text colour */
}

/* Words in a value, e.g. the "in" of "1 in 5": smaller, with tighter spaces either side of it. */
.stat__word {
  font-size: 0.5em;
  word-spacing: -0.12em;
  /* Solid, not outlined, like value_side. */
  -webkit-text-fill-color: currentColor;
  -webkit-text-stroke: 0;
}

/* The heading font's figures are all one width, so a "1" has ~0.13em more empty space on its right than other
   digits (0.26em at this half size). Pull a word after it in by that much so both gaps match. */
.stat__word--after-1 { margin-inline-start: -0.26em; }

/* value_side, e.g. "top domains" beside a "3": smaller, one word per line, the last line level with the base of
   the number (an inline-block sits on its last line's baseline). */
.stat__side {
  display: inline-block;
  inline-size: min-content;
  margin-inline-start: 0.35em;
  white-space: normal; /* undo the value's nowrap, so the words can stack */
  font-size: 0.35em;
  line-height: 1.1;
  letter-spacing: 0.02em;
  /* Solid: a 2px outline fills in small letters. */
  -webkit-text-fill-color: currentColor;
  -webkit-text-stroke: 0;
}

/* Label + source, kept together so they can sit beside the number on mobile. Fills the rest of the box, so the
   source can sit at the bottom. */
.stat__text {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.stat__label {
  /* Sits directly under the number (same position in every box); spare height ends up at the bottom.
     was: margin-block-start: auto; (pushed labels to the bottom of the box) */
  margin-block-start: clamp(0.75rem, 1.6vw, 1.75rem);
  /* Figma "V26 Stat text": 24px, weight 600, line-height 120%.
     Middle value = 24 ÷ Figma frame width × 100 (1.5vw assumes a 1600px frame).
     was: font-size: clamp(1.1rem, 1.6vw, 2rem); line-height: 1.25; */
  font-size: clamp(1.125rem, 1.5vw, 1.5rem);
  font-weight: 600;
  line-height: 1.2;
}

.stat__source {
  /* Pinned to the bottom of the box, so sources line up across a row however long the labels are; the padding
     keeps at least the old gap under the label. (On phones the box is only as tall as its content, so the source
     sits straight under the label.)
     was: margin-block-start: 0.9em; */
  margin-block-start: auto;
  padding-block-start: 0.9em;
  /* Figma "V26 Stat source": 16px, weight 400, line-height 120%.
     Fixed rather than scaling: 16px is already the smallest comfortable reading size.
     was: font-size: clamp(0.85rem, 1vw, 1.25rem); */
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.2;
}

/* Mobile: full-width boxes, one under another, each with the number above the label + source (as on wider
   screens), only as tall as their content.
   was: number on the left and label + source on the right, the boxes sharing a subgrid so the text lined up
   (.stats: grid-template-columns: auto 1fr; .stat: display: grid; grid-template-columns: subgrid;), except a
   group with a range ("40-60%"), which stacked like this. */
@media (width < 640px) {
  .stats { display: grid; }

  .stat { min-block-size: 0; }
}

}
@layer components {
/* Characters placed against an edge of their section or split panel (partials/peek.njk), pushed partly past it
   so the edge crops them. The section/panel must be position: relative with overflow: hidden. */
.peek {
  grid-area: auto; /* in a content grid, still positioned against the section edges, not a grid column */
  position: absolute;
  z-index: 0;
  inline-size: max(var(--peek-size, 30%), 12rem);
  translate: var(--peek-x, var(--peek-x-default, 0%)) var(--peek-y, var(--peek-y-default, 0%));
  pointer-events: none;
}

.peek .character { max-inline-size: none; }

.peek--top          { inset-block-start: 0; inset-inline-start: 50%; --peek-x-default: -50%; --peek-y-default: -35%; }
.peek--bottom       { inset-block-end: 0;   inset-inline-start: 50%; --peek-x-default: -50%; --peek-y-default: 30%; }
.peek--left         { inset-block-start: 50%; inset-inline-start: 0; --peek-x-default: -30%; --peek-y-default: -50%; }
.peek--right        { inset-block-start: 50%; inset-inline-end: 0;   --peek-x-default: 30%;  --peek-y-default: -50%; }
.peek--top-left     { inset-block-start: 0; inset-inline-start: 0;   --peek-x-default: -20%; --peek-y-default: -35%; }
.peek--top-right    { inset-block-start: 0; inset-inline-end: 0;     --peek-x-default: 20%;  --peek-y-default: -35%; }
.peek--bottom-left  { inset-block-end: 0;   inset-inline-start: 0;   --peek-x-default: -20%; --peek-y-default: 30%; }
.peek--bottom-right { inset-block-end: 0;   inset-inline-end: 0;     --peek-x-default: 20%;  --peek-y-default: 30%; }

/* Small screens: characters would cover the text, so each gets its own strip at the top or bottom of its
   section/panel instead (the section adds matching padding: blocks/feature.css and blocks/split.css).
   Each character keeps its corner and its desktop size relative to the page, scaled down by
   --peek-mobile-scale, but ignores the desktop x/y nudges. left/right positions move to the bottom on that side.
   The section/panel sets --peek-scale (character_size) and --peek-span (its share of the page width on desktop:
   1 for a full-width section, 0.5 for a split panel), so the padding there can use the same size.
   was: every character a fixed --peek-mobile-size: 10rem; */
@media (width < 960px) {
  :root {
    --peek-mobile-scale: 1.25; /* 1 = the same share of the screen width as on desktop. was: 1, before that 0.7 */
    --peek-mobile-crop: 30%; /* how much of the character the edge cuts off */
  }

  :has(> .peek) {
    --peek-mobile-size: calc(var(--peek-scale, 30) * var(--peek-span, 1) * var(--peek-mobile-scale) * 1vw);
    --peek-mobile-strip: calc(var(--peek-mobile-size) * 0.7 + 1rem); /* space the section reserves for it */
  }

  .peek {
    inline-size: var(--peek-mobile-size);
    translate: var(--peek-mobile-x, 0%) var(--peek-mobile-y);
  }

  .peek--top,
  .peek--top-left,
  .peek--top-right {
    inset-block: 0 auto;
    --peek-mobile-y: calc(var(--peek-mobile-crop) * -1);
  }

  .peek--bottom,
  .peek--bottom-left,
  .peek--bottom-right,
  .peek--left,
  .peek--right {
    inset-block: auto 0;
    --peek-mobile-y: var(--peek-mobile-crop);
  }

  .peek--top-left,
  .peek--bottom-left,
  .peek--left { --peek-mobile-x: -12%; }

  .peek--top-right,
  .peek--bottom-right,
  .peek--right { --peek-mobile-x: 12%; }

  .peek--top,
  .peek--bottom { --peek-mobile-x: -50%; }
}

}

/* Blocks: one line per block type */
@layer components {
/* Hero: logo top left, the title block right-aligned, the character large in the bottom left,
   cropped by the bottom of the section. */
.hero {
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr;
  min-block-size: 100svh;
  /* A content grid (templates/blocks/hero.njk): logo and text sit in its `wide` column, so the side margins and
     the 1600px max width come from --gutter and --wide-width. The background and character stay full width.
     was: padding: var(--space-l) var(--space-m) var(--space-2xl); */
  padding: var(--space-l) 0 var(--space-2xl);
  overflow: hidden;
}

/* Logo (inline SVG): smaller on mobile, back to its 32px height from about 1600px wide.
   was: .hero__logo img { block-size: clamp(1.75rem, 2.8vw, 3rem); } (no longer matched: the logo is an svg,
   so it showed at its fixed 200 × 32 everywhere) */
.hero__logo { justify-self: start; } /* link only as wide as the logo, not the whole row */

.hero__logo svg {
  display: block;
  block-size: clamp(1.5rem, 2vw, 2rem); /* same as the footer logo (css/footer.css). was: clamp(1.25rem, 2vw, 2rem) */
  inline-size: auto;
}

.hero__text {
  position: relative;
  z-index: 1;
  align-self: center;
  justify-self: end;
  max-inline-size: 100%;
  text-align: end;
}

.hero__title {
  display: grid;
  font-weight: 400;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
}

.hero__eyebrow {
  font-size: clamp(1.25rem, 3.2vw, 3.5rem);
  font-style: italic;
}

.hero__main {
  margin-block: 0.08em 0.12em;
  font-size: clamp(3.5rem, 13.5vw, 15rem);
  font-weight: 700;
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke: 0.016em currentColor;
}

.hero__subtitle {
  font-size: clamp(2rem, 6.5vw, 7rem);
}

.hero__intro {
  margin-block-start: var(--space-l);
  font-size: clamp(1rem, 1.4vw, 1.5rem);
}

.hero__character {
  grid-area: auto; /* positioned against the section edges, not a grid column */
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: -4vw;
  inline-size: clamp(16rem, 46vw, 56rem);
  translate: 0 24%; /* legs run off the bottom edge, as in the design */
}

.hero__character .character {
  max-inline-size: none;
}

/* Small screens: title left-aligned and centred vertically, character smaller so it doesn't run into the text.
   was: .hero__text { align-self: start; margin-block-start: var(--space-2xl); } (right-aligned, near the top) */
@media (width < 960px) {
  .hero__text {
    align-self: center;
    justify-self: start;
    text-align: start;
  }

  /* Same mobile scale as the section characters (--peek-mobile-scale, css/partials/peek.css), from its 46vw
     desktop size, so all characters stay in step. Capped at 26rem so on a wide tablet it stays clear of the intro.
     was: inline-size: calc(46 * var(--peek-mobile-scale, 0.7) * 1vw); (no cap)
     before that: min(60vw, 18rem) */
  .hero__character { inline-size: min(calc(46 * var(--peek-mobile-scale, 0.7) * 1vw), 26rem); }
}

}
@layer components {
.example {
  container-type: inline-size;
  align-items: center;
}

.example__media img {
  inline-size: 100%;
  block-size: auto;
  border-radius: var(--radius);
}

@container (inline-size < 40rem) {
  .example__text { text-align: center; }
}

@media (width >= 960px) {
  .example { min-block-size: 60vh; }
}

}
@layer components {
/* Feature: a text column on one side; the character sits against a section edge (partials/peek.njk). */
.feature.panel {
  position: relative;
  display: grid;
  align-content: start;
  /* At least one full screen tall (it still grows if the content needs more room).
     was: min-block-size: min(clamp(36rem, 50vw, 60rem), 100svh); (never forced taller than the screen)
     before that: clamp(36rem, 50vw, 60rem) */
  min-block-size: 100svh;
  /* A content grid (templates/blocks/feature.njk): the text sits in its `wide` column, so the side margins and
     the 1600px max width come from --gutter and --wide-width. The background and character stay full width.
     was: padding: clamp(4rem, 7.5vw, 10rem) 4.4vw; */
  padding: clamp(4rem, 7.5vw, 10rem) 0;
  overflow: hidden;
}

.feature__content {
  position: relative;
  z-index: 1;
  --stack-space: clamp(1.5rem, 3.4vw, 4.5rem);
}

/* Text max width: headings, lead and body stay a comfortable line length while the stats below run wider. */
.feature__title,
.feature__lead,
.feature__body {
  max-inline-size: var(--feature-text-max, 52rem);
}

.feature__title {
  font-size: clamp(2rem, 3vw, 5rem);
  line-height: 1.08;
  text-transform: uppercase;
}

.feature__lead {
  /* was: max-inline-size: 36em; (now --feature-text-max, above) */
  /* Figma "V26 Stat text": 24px, weight 600, line-height 120%.
     Middle value = 24 ÷ Figma frame width × 100 (1.5vw assumes a 1600px frame).
     was: font-size: clamp(1.2rem, 1.6vw, 2rem); line-height: 1.25; */
  font-size: clamp(1.125rem, 1.5vw, 1.5rem);
  font-weight: 600;
  line-height: 1.2;
}

.feature__lead + .feature__body { margin-block-start: clamp(1rem, 1.8vw, 2.5rem); }

.feature__body {
  /* was: max-inline-size: 52em; (now --feature-text-max, above) */
  /* was: font-size: clamp(1rem, 1.1vw, 1.4rem); */
  font-size: var(--body-size);
  line-height: 1.5;
}

.feature__body ul { padding-inline-start: 2.2em; }
.feature__body li + li { margin-block-start: 0.6em; }

/* Small screens: make room for the character above or below the text (strip size: css/partials/peek.css). */
@media (width < 960px) {
  .feature:has(> :is(.peek--top, .peek--top-left, .peek--top-right)) {
    padding-block-start: calc(var(--peek-mobile-strip) + 1.5rem);
  }

  .feature:has(> :is(.peek--bottom, .peek--bottom-left, .peek--bottom-right, .peek--left, .peek--right)) {
    padding-block-end: calc(var(--peek-mobile-strip) + 1.5rem);
  }
}

/* Content area (text + stats): its width is set on the 12-column grid in templates/blocks/feature.njk
   (9 columns on the left, or 7 ending at the right), so the stats can stretch across it.
   was: inline-size: min(72%, 84rem) (left) and min(58%, 84rem) with justify-self: end (right);
   before that 60% and 50%. */
@media (width >= 960px) {
  /* Top/bottom padding follows the screen height, so the section's content fits within one screen.
     was: clamp(4rem, 7.5vw, 10rem) (still used on small screens) */
  .feature.panel { padding-block: clamp(3rem, 8svh, 8rem); }

  .feature--content-right .stats { justify-content: flex-end; }
}

}
@layer components {
/* Split: two full-bleed colour panels side by side. Characters sit against a panel edge (partials/peek.njk). */
.split.panel {
  padding-block: 0;
}

.split__inner {
  display: grid;
  /* At least one full screen tall: the panels stretch to fill it (side by side on desktop, stacked on mobile). */
  min-block-size: 100svh;
}

.split__panel {
  position: relative;
  display: grid;
  /* No min height on small screens: the panel is as tall as its content (+ character strip).
     was: min-block-size: 32rem; (desktop min height is set below) */
  /* Side margins: --gutter, the same as every other section. was: clamp(1.5rem, 4.2vw, 5.5rem) */
  padding: clamp(4rem, 7vw, 9rem) var(--gutter);
  overflow: hidden;
  --peek-span: 0.5; /* half the page wide on desktop: keeps characters' mobile size in step (partials/peek.css) */
}

/* Full-bleed panels can't sit in the content grid, so their outer edges match its `wide` column instead:
   the text lines up with the other sections and stays within --wide-width (1600px), centred on wider screens.
   100cqi = the section's width (.panel is a container). */
.split__panel:first-child {
  padding-inline-start: max(var(--gutter), (100cqi - var(--wide-width)) / 2);
}

.split__panel:last-child {
  padding-inline-end: max(var(--gutter), (100cqi - var(--wide-width)) / 2);
}

.split__panel--top .split__content { align-self: start; }
.split__panel--bottom .split__content { align-self: end; }

.split__content {
  position: relative;
  z-index: 1;
  max-inline-size: 46rem;
  --stack-space: clamp(1rem, 2vw, 2.5rem);
}

.split {
  --split-title-size: clamp(2rem, 3vw, 5rem); /* same as .feature__title. was: clamp(2rem, 3.8vw, 4.5rem) */
  --split-title-line-height: 1.08;
}

.split__title {
  font-size: var(--split-title-size);
  line-height: var(--split-title-line-height);
  text-transform: uppercase;
}

.split__lead {
  /* Figma "V26 Stat text": 24px, weight 600, line-height 120%.
     Middle value = 24 ÷ Figma frame width × 100 (1.5vw assumes a 1600px frame).
     was: font-size: clamp(1.2rem, 1.6vw, 2rem); line-height: 1.25; */
  font-size: clamp(1.125rem, 1.5vw, 1.5rem);
  font-weight: 600;
  line-height: 1.2;
}

.split__body {
  /* was: font-size: clamp(1rem, 1.1vw, 1.4rem); */
  font-size: var(--body-size);
  line-height: 1.5;
}

.split__body ol { padding-inline-start: 1.8em; }
.split__body li + li { margin-block-start: 0.7em; }

.split__cta { margin-block-start: clamp(1.5rem, 3.4vw, 4.5rem); }

/* Small screens: make room for the character above or below the text (strip size: css/partials/peek.css). */
@media (width < 960px) {
  .split__panel:has(> :is(.peek--top, .peek--top-left, .peek--top-right)) {
    padding-block-start: calc(var(--peek-mobile-strip) + 1.5rem);
  }

  .split__panel:has(> :is(.peek--bottom, .peek--bottom-left, .peek--bottom-right, .peek--left, .peek--right)) {
    padding-block-end: calc(var(--peek-mobile-strip) + 1.5rem);
  }
}

@media (width >= 960px) {
  .split__inner { grid-template-columns: 1fr 1fr; }

  /* A top-aligned panel without a title, next to one with a title: leave the title's space at the top, so both
     panels' text starts level below it (as in the design's last section). Assumes a two-line title; a
     section can set --split-title-lines (e.g. via a project style) if its title is longer or shorter. */
  .split__inner:has(.split__title) .split__panel--top:not(:has(.split__title)) .split__content {
    padding-block-start: calc(
      var(--split-title-lines, 2) * var(--split-title-size) * var(--split-title-line-height) + var(--stack-space)
    );
  }
  /* Panel height: full screen, from .split__inner above.
     was: .split__panel { min-block-size: min(clamp(36rem, 62vw, 72rem), 100svh); }
     before that: clamp(36rem, 62vw, 72rem) */

  /* Top/bottom padding follows the screen height, so the panel's content fits within one screen.
     was: clamp(4rem, 7vw, 9rem) (still used on small screens) */
  .split__panel { padding-block: clamp(3rem, 8svh, 8rem); }
}

}

@layer utilities {
/* Reveal on scroll (js/base/observers.js adds .in-view). Only applies when JS runs (html.js), so content never
   stays hidden. Two ways in:
   - .animate: the element reveals as a whole.
   - .stagger: each child reveals on its own as it scrolls into view, one after another. Body copy (.flow),
     stats (.stats) and any .stagger-group (e.g. the lines of a heading) reveal per child: per paragraph, per
     stat, per line. Keep these selectors in step with STAGGER_PIECES in observers.js.
   was: .animate only, timed with var(--duration) */
@media (prefers-reduced-motion: no-preference) {
  :root.js :is(.animate, .stagger > :not(.flow, .stats, .stagger-group), .stagger > :is(.flow, .stats, .stagger-group) > *) {
    opacity: 0;
    translate: 0 1.5rem;
    transition: opacity var(--reveal-duration) var(--ease-out), translate var(--reveal-duration) var(--ease-out);
  }

  :root.js :is(.animate, .stagger > :not(.flow, .stats, .stagger-group), .stagger > :is(.flow, .stats, .stagger-group) > *).in-view {
    opacity: 1;
    translate: 0 0;
  }

  /* Opt-in parallax driven by the element's own scroll position. No JS. */
  @supports (animation-timeline: view()) {
    .parallax {
      animation: parallax linear both;
      animation-timeline: view();
    }
  }
}

@keyframes parallax {
  from { translate: 0 calc(var(--parallax-distance, 10%) * -1); }
  to { translate: 0 var(--parallax-distance, 10%); }
}

}
@layer utilities {
.visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.text-start { text-align: start; }
.text-center { text-align: center; }
.text-end { text-align: end; }

.mt-s { margin-block-start: var(--space-s); }
.mt-m { margin-block-start: var(--space-m); }
.mt-l { margin-block-start: var(--space-l); }
.mt-xl { margin-block-start: var(--space-xl); }
.mb-s { margin-block-end: var(--space-s); }
.mb-m { margin-block-end: var(--space-m); }
.mb-l { margin-block-end: var(--space-l); }
.mb-xl { margin-block-end: var(--space-xl); }

/* .hide-{bp}: hidden from that breakpoint up. .show-{bp}: hidden below it. */
@media (width >= 640px) { .hide-sm { display: none; } }
@media (width >= 960px) { .hide-md { display: none; } }
@media (width >= 1280px) { .hide-lg { display: none; } }
@media (width >= 1600px) { .hide-xl { display: none; } }
@media (width < 640px) { .show-sm { display: none; } }
@media (width < 960px) { .show-md { display: none; } }
@media (width < 1280px) { .show-lg { display: none; } }
@media (width < 1600px) { .show-xl { display: none; } }

}
