@charset "utf-8";
/* ==========================================================================
   Pixel Perfect Websites — main.css
   Design system + components. No frameworks, no build step.
   Order: 1 Fonts · 2 Tokens · 3 Reset · 4 Type · 5 Layout · 6 Components
   ========================================================================== */

/* 1 · FONTS =============================================================== */

@font-face {
  font-family: "Archivo";
  src: url("../fonts/archivo-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Google Sans";
  src: url("../fonts/googlesans-var.woff2") format("woff2-variations");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* 2 · TOKENS ============================================================== */

:root {
  /* Ink — the site's resting state is near-black. */
  --ink-900: #08090a;
  --ink-800: #0d0f11;
  --ink-700: #141619;
  --ink-600: #1c1f23;

  /* Paper — pure white, used as punctuation rather than background. */
  --paper: #ffffff;
  --paper-100: #f0f1f1;
  --paper-200: #e3e4e4;

  /* Signature */
  --flare: #e8501e;        /* on dark surfaces */
  --flare-ink: #c1400f;    /* on light surfaces — AA at small sizes */
  --flare-wash: rgba(232, 80, 30, 0.14);
  --btn-orange: #d0450e;   /* white text: 4.63:1 */
  --btn-orange-dark: #b03a0b;   /* hover; white text: 6.08:1 */

  /* Text roles (dark surfaces) */
  --t-1: #f4f5f5;
  --t-2: rgba(244, 245, 245, 0.66);
  --t-3: rgba(244, 245, 245, 0.55);
  --rule: rgba(244, 245, 245, 0.14);
  --rule-soft: rgba(244, 245, 245, 0.08);

  /* Text roles (light surfaces) */
  --t-1-inv: #0d0f11;
  --t-2-inv: rgba(13, 15, 17, 0.72);
  --t-3-inv: rgba(13, 15, 17, 0.58);
  --rule-inv: rgba(13, 15, 17, 0.16);

  /* Type */
  --sans: "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --text: "Google Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --fs-hero: clamp(2.6rem, 6.35vw, 6.2rem);
  --fs-display: clamp(2rem, 4.05vw, 3.6rem);
  --fs-h2: clamp(1.75rem, 3.3vw, 2.9rem);
  --fs-h3: clamp(1.2rem, 1.7vw, 1.55rem);
  --fs-deck: clamp(1.02rem, 0.94rem + 0.38vw, 1.22rem);
  --fs-body: clamp(0.97rem, 0.94rem + 0.16vw, 1.04rem);
  --fs-small: 0.925rem;
  --fs-meta: 0.7rem;

  /* Space */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4rem;
  --s-9: 6rem;
  --s-10: 8rem;

  --gutter: clamp(1.25rem, 4.2vw, 4rem);
  --band-y: clamp(4.5rem, 9vw, 9rem);
  --measure: 62ch;
  --shell: 1560px;

  /* Motion */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-1: 0.18s;
  --dur-2: 0.36s;
  --dur-3: 0.72s;

  --header-h: 76px;
  color-scheme: dark;
}

@media (max-width: 640px) {
  :root { --header-h: 64px; }
}

/* 3 · RESET =============================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1.5rem);
}

body {
  margin: 0;
  background: var(--ink-900);
  color: var(--t-1);
  font-family: var(--text);
  font-size: var(--fs-body);
  font-optical-sizing: auto;
  font-weight: 400;
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, video, iframe { display: block; max-width: 100%; }
img, video { height: auto; }

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

h1, h2, h3, h4, p, figure, blockquote, dl, dd, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }

a { color: inherit; }

::selection { background: var(--flare); color: #fff; }

:focus-visible {
  outline: 2px solid var(--flare);
  outline-offset: 3px;
}
.t-invert :focus-visible { outline-color: var(--flare-ink); }

.u-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  top: 0; left: 0;
  z-index: 200;
  transform: translateY(-120%);
  background: var(--flare);
  color: #fff;
  padding: 0.85rem 1.35rem;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
}
.skip-link:focus { transform: translateY(0); }

/* Film grain — kills flatness and banding on the large dark fields. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  background-image: url("../img/grain.svg");
  background-size: 200px 200px;
  opacity: 0.04;
}

/* 4 · TYPE ================================================================ */

.d-hero, .d-1, .d-2, .d-3 {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 116%;
  line-height: 0.98;
  letter-spacing: -0.028em;
  text-wrap: balance;
}

.d-hero { font-size: var(--fs-hero); line-height: 0.93; letter-spacing: -0.036em; }
.d-1 { font-size: var(--fs-display); }
.d-2 { font-size: var(--fs-h2); line-height: 1.02; letter-spacing: -0.024em; }
.d-3 {
  font-size: var(--fs-h3);
  font-stretch: 108%;
  font-weight: 620;
  line-height: 1.14;
  letter-spacing: -0.012em;
}

.deck {
  font-size: var(--fs-deck);
  line-height: 1.58;
  color: var(--t-2);
  max-width: 46ch;
}
/* Inside a two-column split the supporting column already sets the measure,
   so the paragraph fills it rather than stopping short of the edge. */
.split > .deck, .split > * > .deck { max-width: none; }

.prose p + p { margin-top: 1.15em; }
.prose { max-width: var(--measure); color: var(--t-2); }
.prose strong { color: var(--t-1); font-weight: 600; }
.prose em { font-style: normal; color: var(--t-1); }

.meta {
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  font-stretch: 100%;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--t-3);
  line-height: 1.4;
}

.label {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--t-2);
  margin-bottom: var(--s-6);
}
/* The eyebrow is prefixed with the brand's orange pixel - the same square as
   the logo and the button tick - rather than the ruled line every template
   reaches for. Sized in em so it tracks the label; sat on the baseline, so it
   spans the cap height of the uppercase text beside it. */
.label::before {
  content: "";
  flex: none;
  width: 0.62em;
  height: 0.62em;
  background: var(--flare);
}

.t-invert .label { color: var(--t-2-inv); }
.t-invert .label::before { background: var(--flare); }

.num {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.foot {
  font-family: var(--sans);
  font-size: 0.7rem;
  font-weight: 450;
  line-height: 1.55;
  letter-spacing: 0.01em;
  color: var(--t-3);
  max-width: 68ch;
}
.t-invert .foot { color: var(--t-3-inv); }

/* Inline link */
.link {
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 1px;
  padding-bottom: 2px;
  transition: background-size var(--dur-2) var(--ease), color var(--dur-1) linear;
}
.link:hover { background-size: 100% 2px; color: var(--flare); }
.t-invert .link:hover { color: var(--flare-ink); }

/* 5 · LAYOUT ============================================================== */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band {
  position: relative;
  padding-block: var(--band-y);
}
.band--tight { padding-block: clamp(3rem, 6vw, 5.5rem); }
.band--flush-top { padding-top: 0; }

.t-invert {
  background: var(--paper);
  color: var(--t-1-inv);
}
.t-invert .deck, .t-invert .prose { color: var(--t-2-inv); }
.t-invert .meta { color: var(--t-3-inv); }
.t-invert .prose strong { color: var(--t-1-inv); }

.t-charcoal { background: var(--ink-700); }

/* Editorial two-column: heading rail + content */
.split {
  display: grid;
  gap: var(--s-6) var(--gutter);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .split {
    grid-template-columns: minmax(0, 40%) minmax(0, 47%);
    gap: var(--s-8) clamp(2rem, 5vw, 5rem);
    justify-content: space-between;
  }
  .split--wide {
    grid-template-columns: minmax(0, 38%) minmax(0, 46%);
    column-gap: clamp(2rem, 5vw, 5rem);
  }
  .split--even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.stack > * + * { margin-top: var(--s-5); }
/* The supporting column starts level with the heading, not with the label
   above it, and never drops to the bottom of the row. */
@media (min-width: 900px) {
  .u-self-end { align-self: start; padding-top: 2.7rem; }
  .split > .u-self-end:first-child { padding-top: 0; }
}
.stack-lg > * + * { margin-top: var(--s-7); }

.hr {
  height: 1px;
  border: 0;
  background: var(--rule);
  margin: 0;
}
.t-invert .hr { background: var(--rule-inv); }

/* 6 · COMPONENTS ========================================================== */

/* --- Header ------------------------------------------------------------- */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: transform var(--dur-2) var(--ease), background-color var(--dur-2) linear,
              border-color var(--dur-2) linear;
  border-bottom: 1px solid transparent;
}
.header.is-scrolled {
  background: rgba(8, 9, 10, 0.82);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom-color: var(--rule-soft);
}
.header.is-hidden { transform: translateY(-101%); }

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  width: 100%;
}

.wordmark { display: inline-flex; align-items: center; text-decoration: none; }
.wordmark img {
  height: clamp(26px, 2.4vw, 32px);
  width: auto;
  display: block;
}

.footer .wordmark img { height: clamp(32px, 3.2vw, 40px); }
.wordmark__mark {
  position: relative;
  width: 15px; height: 15px;
  flex: none;
  border: 1.5px solid currentColor;
}
.wordmark__mark::after {
  content: "";
  position: absolute;
  inset: 3px 3px auto auto;
  width: 5px; height: 5px;
  background: var(--flare);
  transition: transform var(--dur-2) var(--ease);
}
.wordmark:hover .wordmark__mark::after { transform: translate(-4px, 4px); }
.wordmark__b { font-weight: 400; font-stretch: 100%; opacity: 0.62; }

@media (max-width: 400px) { .wordmark__b { display: none; } }

.nav { display: none; }
@media (min-width: 940px) {
  .nav {
    display: flex;
    align-items: center;
    gap: clamp(1.4rem, 2.4vw, 2.6rem);
  }
}
.nav__link {
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--t-2);
  padding-block: 0.4rem;
  position: relative;
  transition: color var(--dur-1) linear;
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--flare);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-2) var(--ease);
}
.nav__link:hover, .nav__link[aria-current="page"] { color: var(--t-1); }
.nav__link:hover::after, .nav__link[aria-current="page"]::after { transform: scaleX(1); }

.header .header__cta { display: none; }
@media (min-width: 940px) { .header .header__cta { display: inline-flex; } }

/* Menu toggle */
.burger {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 46px; height: 40px;
  padding: 0 11px;
  background: none;
  border: 1px solid var(--rule);
  cursor: pointer;
}
@media (min-width: 940px) { .burger { display: none; } }
.burger span {
  display: block;
  height: 1.5px;
  background: var(--t-1);
  transition: transform var(--dur-2) var(--ease), opacity var(--dur-1) linear;
}
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* Mobile menu */
.menu {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--ink-900);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: calc(var(--header-h) + var(--s-7)) var(--gutter) var(--s-7);
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--dur-2) var(--ease), visibility 0s linear var(--dur-2);
}
.menu.is-open { visibility: visible; opacity: 1; transition-delay: 0s; }
.menu__list { display: flex; flex-direction: column; }
.menu__item { border-top: 1px solid var(--rule-soft); }
.menu__item:last-child { border-bottom: 1px solid var(--rule-soft); }
.menu__link {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  padding: clamp(0.85rem, 2.6vw, 1.15rem) 0;
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 112%;
  font-size: clamp(1.7rem, 8vw, 2.6rem);
  letter-spacing: -0.03em;
  line-height: 1;
  text-decoration: none;
}
.menu__link span {
  font-size: var(--fs-meta);
  font-weight: 600;
  font-stretch: 100%;
  letter-spacing: 0.14em;
  color: var(--t-3);
}
.menu__foot { display: grid; gap: var(--s-4); }

body.is-locked { overflow: hidden; }

/* --- Buttons ------------------------------------------------------------ */

.btn {
  /* White plate, near-black label, orange square. On hover the plate turns
     brand orange and the label stays near-black: 5.19:1, which passes.
     Do not switch the hover label to white - that combination is 3.75:1. */
  --btn-fg: var(--ink-900);
  --btn-bg: var(--t-1);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  padding: 1.05rem 1.5rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bg);
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  transition: color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--flare);
  transform: translateY(101%);
  transition: transform var(--dur-2) var(--ease);
  z-index: 0;
}
.btn > * { position: relative; z-index: 1; }
.btn:hover { color: var(--ink-900); border-color: var(--flare); }
.btn:hover::before { transform: translateY(0); }

.btn__tick {
  width: 9px; height: 9px;
  flex: none;
  background: var(--flare);
  transition: background-color var(--dur-2) var(--ease);
}
.btn:hover .btn__tick { background: var(--paper); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--t-1);
  border-color: var(--rule);
}
.btn--ghost .btn__tick { background: var(--flare); }
.btn--ghost:hover { color: var(--ink-900); }
.t-invert .btn--ghost { --btn-fg: var(--t-1-inv); border-color: var(--rule-inv); }
.t-invert .btn--ghost .btn__tick { background: var(--flare-ink); }

.btn--sm { padding: 0.75rem 1.05rem; }
.btn--lg { padding: 1.3rem 2rem; font-size: 0.76rem; }

/* Text link with arrow */
.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--rule);
  transition: border-color var(--dur-2) var(--ease), color var(--dur-1) linear;
}
.arrow-link svg { flex: none; transition: transform var(--dur-2) var(--ease); }
.arrow-link:hover { border-bottom-color: var(--flare); color: var(--flare); }
.arrow-link:hover svg { transform: translateX(5px); }
.t-invert .arrow-link { border-bottom-color: var(--rule-inv); }
.t-invert .arrow-link:hover { border-bottom-color: var(--flare-ink); color: var(--flare-ink); }

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4) var(--s-5);
}

/* --- Hero --------------------------------------------------------------- */

.hero {
  position: relative;
  padding-top: calc(var(--header-h) + clamp(1.75rem, 4.6vw, 4.25rem));
  padding-bottom: clamp(3rem, 7vw, 6rem);
}
.hero__grid {
  display: grid;
  gap: clamp(2.25rem, 4.5vw, 3.5rem) var(--gutter);
  align-items: start;
  margin-top: clamp(2rem, 4.5vw, 3.75rem);
}
@media (min-width: 1040px) {
  .hero__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); align-items: start; }
}
.hero__head { max-width: 22ch; }
.hero__deck { max-width: 42ch; }
.hero__actions { margin-top: var(--s-7); }
.hero__eyebrow {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.75rem;
  margin-bottom: clamp(1.5rem, 2.6vw, 2.25rem);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--rule-soft);
}
.hero__aside {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

/* --- Seam (before / after) ---------------------------------------------- */

.seam {
  --pos: 52%;
  margin: 0;
}
.seam__stage {
  position: relative;
  isolation: isolate;
  border: 1px solid var(--rule);
  background: var(--ink-700);
  overflow: hidden;
  touch-action: pan-y;
}
.t-invert .seam__stage { border-color: var(--rule-inv); background: var(--paper-100); }

.seam__plate { display: block; width: 100%; height: auto; }
.seam__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  clip-path: inset(0 calc(100% - var(--pos)) 0 0);
}
.seam__layer .seam__plate { height: 100%; object-fit: cover; object-position: left top; }

.seam__rule {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--pos);
  width: 1px;
  background: var(--flare);
  transform: translateX(-0.5px);
  pointer-events: none;
  z-index: 3;
}
.seam__grip {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  width: 46px; height: 46px;
  border-radius: 50%;
  background: var(--flare);
  display: grid;
  place-items: center;
  box-shadow: 0 6px 26px rgba(0, 0, 0, 0.45);
}
.seam__grip svg { fill: #fff; }

.seam__range {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: ew-resize;
  -webkit-appearance: none;
  appearance: none;
}
.seam__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 46px;
  height: 100%;
  background: transparent;
  cursor: ew-resize;
}
.seam__range::-moz-range-thumb {
  width: 46px;
  height: 400px;
  border: 0;
  background: transparent;
  cursor: ew-resize;
}
.seam__range:focus-visible { outline-offset: -4px; }

.seam__tag {
  position: absolute;
  z-index: 3;
  top: var(--s-4);
  font-family: var(--sans);
  font-size: 0.62rem;
  font-weight: 640;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.4rem 0.6rem;
  background: rgba(8, 9, 10, 0.88);
  color: var(--t-1);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  pointer-events: none;
}
.seam__tag--before { left: var(--s-4); }
.seam__tag--after { right: var(--s-4); }

/* Faded out, not hidden: the tag has to keep its width so the script can go on
   measuring it, and a fade reads as the label stepping aside rather than
   flickering off. */
.seam__tag { transition: opacity var(--dur-1) linear; }
.seam__tag.is-gone { opacity: 0; }

.seam__cap {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-2) var(--s-5);
  margin-top: var(--s-4);
}

.no-js .seam__range { display: none; }
.no-js .seam__grip { display: none; }

/* --- Fit / not-fit lists ------------------------------------------------ */

.checklist > li {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: 0.9rem;
  padding-block: 0.85rem;
  border-top: 1px solid var(--rule);
}
.t-invert .checklist > li { border-top-color: var(--rule-inv); }
.checklist > li:last-child { border-bottom: 1px solid var(--rule); }
.t-invert .checklist > li:last-child { border-bottom-color: var(--rule-inv); }
.checklist svg { margin-top: 0.42em; flex: none; }
.checklist--yes svg { stroke: var(--flare); }
.t-invert .checklist--yes svg { stroke: var(--flare-ink); }
.checklist--no svg { stroke: currentColor; opacity: 0.4; }
/* A plain point rather than a tick: for lists of duties, not qualities. */
.checklist--point svg { fill: var(--flare); }
.t-invert .checklist--point svg { fill: var(--flare-ink); }

/* --- Ledger (outcome table) --------------------------------------------- */

.ledger { border-top: 1px solid var(--rule); }
.t-invert .ledger { border-top-color: var(--rule-inv); }
.ledger__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.35rem var(--gutter);
  padding-block: clamp(1.1rem, 2.4vw, 1.6rem);
  border-bottom: 1px solid var(--rule);
}
.t-invert .ledger__row { border-bottom-color: var(--rule-inv); }
@media (min-width: 760px) {
  .ledger__row { grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); align-items: baseline; }
}
.ledger__term {
  font-family: var(--sans);
  font-weight: 620;
  font-stretch: 108%;
  font-size: clamp(1.05rem, 1.5vw, 1.32rem);
  letter-spacing: -0.015em;
  line-height: 1.2;
}
.ledger__def { color: var(--t-2); }
.t-invert .ledger__def { color: var(--t-2-inv); }

/* --- Programme (sequence of disciplines) -------------------------------- */

.programme { border-top: 1px solid var(--rule); }
.stage { border-bottom: 1px solid var(--rule); }
.stage__summary {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--s-4) clamp(1rem, 3vw, 2.5rem);
  padding-block: clamp(1.2rem, 2.6vw, 1.9rem);
  cursor: pointer;
  list-style: none;
  transition: color var(--dur-2) var(--ease);
}
.stage__summary::-webkit-details-marker { display: none; }
.stage__summary:hover { color: var(--flare); }
.stage__n {
  width: 2.4rem;
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.12em;
  color: var(--t-3);
  transition: color var(--dur-2) var(--ease);
}
.stage:hover .stage__n, .stage[open] .stage__n { color: var(--flare); }
.stage__title {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 114%;
  font-size: clamp(1.5rem, 3.6vw, 2.5rem);
  letter-spacing: -0.028em;
  line-height: 1;
}
.stage__sign {
  position: relative;
  width: 16px; height: 16px;
  flex: none;
}
.stage__sign::before, .stage__sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--dur-2) var(--ease);
}
.stage__sign::after { transform: rotate(90deg); }
.stage[open] .stage__sign::after { transform: rotate(0deg); }

.stage__body {
  display: grid;
  gap: var(--s-5) var(--gutter);
  padding: 0 0 clamp(1.75rem, 3.5vw, 2.75rem);
}
@media (min-width: 860px) {
  .stage__body {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    /* Exactly the number column plus its gap, so the body starts on the
       same vertical as the title above it. */
    padding-left: calc(2.4rem + clamp(1rem, 3vw, 2.5rem));
  }
}
.spec > li {
  display: flex;
  gap: 0.75rem;
  padding-block: 0.5rem;
  border-top: 1px solid var(--rule-soft);
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: 450;
  color: var(--t-2);
}
.spec > li::before {
  content: "";
  flex: none;
  width: 5px; height: 5px;
  margin-top: 0.65em;
  background: var(--flare);
}

/* --- Work index --------------------------------------------------------- */

.index { border-top: 1px solid var(--rule); }
.t-invert .index { border-top-color: var(--rule-inv); }

.entry { border-bottom: 1px solid var(--rule); }
.t-invert .entry { border-bottom-color: var(--rule-inv); }

.entry__link {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.4rem var(--s-5);
  padding: clamp(1.4rem, 3vw, 2.1rem) 0;
  text-decoration: none;
  transition: background-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease),
              padding-inline var(--dur-2) var(--ease);
}
@media (min-width: 860px) {
  .entry__link {
    grid-template-columns: minmax(0, 6fr) minmax(0, 4fr) auto;
    align-items: baseline;
  }
}
/* The studio's product is transformation — so the row inverts on approach. */
.entry__link:hover, .entry__link:focus-visible {
  background: var(--paper);
  color: var(--ink-900);
  padding-inline: clamp(0.75rem, 2vw, 1.5rem);
}
.t-invert .entry__link:hover, .t-invert .entry__link:focus-visible {
  background: var(--ink-900);
  color: var(--paper);
}
.entry__link:hover .meta, .entry__link:focus-visible .meta { color: rgba(13, 15, 17, 0.62); }
.t-invert .entry__link:hover .meta { color: rgba(244, 245, 245, 0.62); }

.entry__name {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 114%;
  font-size: clamp(1.55rem, 3.9vw, 2.7rem);
  letter-spacing: -0.03em;
  line-height: 1.02;
}
.entry__meta { display: flex; flex-wrap: wrap; gap: 0.3rem 1.1rem; }
.entry__go { display: none; }
@media (min-width: 860px) { .entry__go { display: block; } }
.entry__link:hover .entry__go { transform: translateX(5px); }
.entry__go { transition: transform var(--dur-2) var(--ease); }

/* --- Case study --------------------------------------------------------- */

.chapter { border-top: 1px solid var(--rule); padding-top: var(--s-6); }
.t-invert .chapter { border-top-color: var(--rule-inv); }
.chapter + .chapter { margin-top: clamp(2.5rem, 5vw, 4.5rem); }
.chapter__n {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.16em;
  color: var(--flare);
  display: block;
  margin-bottom: var(--s-3);
}
.t-invert .chapter__n { color: var(--flare-ink); }

/* Metrics — presented as a record, not as floating stat cards. */
.record {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--rule);
  border-left: 1px solid var(--rule);
}
.t-invert .record { border-color: var(--rule-inv); }
@media (min-width: 860px) { .record { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.record__cell {
  padding: clamp(1.1rem, 2.4vw, 1.75rem);
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.t-invert .record__cell { border-color: var(--rule-inv); }
.record__fig {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-stretch: 104%;
  font-size: clamp(2rem, 4.2vw, 3.1rem);
  letter-spacing: -0.04em;
  line-height: 1;
  display: block;
  margin-bottom: 0.6rem;
}
.record__fig sup { font-size: 0.34em; vertical-align: super; color: var(--flare); letter-spacing: 0; }

/* Same green rise arrow as the case study figures, so a reader who has seen
   one recognises the other. Green, not orange: orange is the brand accent and
   would say nothing about direction. */
.record__cell--up .record__fig { display: flex; align-items: baseline; gap: 0.3rem; }
.record__arrow {
  width: 0.62em; height: 0.62em;
  flex: none;
  color: var(--rise);
  align-self: center;
}
.t-invert .record__arrow { color: var(--rise-ink); }
.record__arrow svg { width: 100%; height: 100%; fill: currentColor; }
.t-invert .record__fig sup { color: var(--flare-ink); }

/* --- Quote -------------------------------------------------------------- */

.quote { margin: 0; }
.quote__text {
  font-family: var(--text);
  font-size: clamp(1.3rem, 2.6vw, 2.05rem);
  font-weight: 400;
  line-height: 1.34;
  letter-spacing: -0.018em;
  text-wrap: pretty;
}
.quote__text::before { content: "\201C"; margin-left: -0.42em; }
.quote__text::after { content: "\201D"; }
.quote__by {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
}
.t-invert .quote__by { border-top-color: var(--rule-inv); }

/* --- Media frames ------------------------------------------------------- */

.frame {
  position: relative;
  border: 1px solid var(--rule);
  background: var(--ink-700);
  overflow: hidden;
}
.t-invert .frame { border-color: var(--rule-inv); background: var(--paper-100); }
.frame img { width: 100%; }
.frame--portrait img { aspect-ratio: 4 / 5; object-fit: cover; }

.frame__cap {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.4rem 1rem;
  margin-top: var(--s-3);
}

/* Video facade: nothing third-party loads until the visitor asks for it. */
.play {
  position: absolute;
  inset: 0;
  width: 100%;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}
.play__disc {
  width: clamp(64px, 9vw, 92px);
  height: clamp(64px, 9vw, 92px);
  border-radius: 50%;
  background: var(--flare);
  display: grid;
  place-items: center;
  transition: transform var(--dur-2) var(--ease);
}
.play__disc svg { fill: #fff; margin-left: 4px; }
.play:hover .play__disc { transform: scale(1.07); }
.play__label {
  position: absolute;
  left: var(--s-5);
  bottom: var(--s-5);
  right: var(--s-5);
  text-align: left;
}

/* --- Forms -------------------------------------------------------------- */

.form { max-width: 940px; }
.fieldset { border: 0; padding: 0; margin: 0; }
.fieldset + .fieldset { margin-top: clamp(2.5rem, 5vw, 4rem); }
.fieldset__legend {
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
  width: 100%;
  padding: 0 0 var(--s-5);
  margin-bottom: var(--s-5);
  border-bottom: 1px solid var(--rule);
}
.fieldset__legend .num { color: var(--flare); font-size: var(--fs-meta); letter-spacing: 0.16em; font-weight: 640; }

.grid-fields {
  display: grid;
  gap: var(--s-5) var(--gutter);
  grid-template-columns: 1fr;
}
@media (min-width: 720px) { .grid-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.field--full { grid-column: 1 / -1; }

.field label, .field__label {
  display: block;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--t-2);
  margin-bottom: 0.7rem;
}
.field__hint {
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--t-3);
  display: block;
  margin-top: 0.35rem;
}

.input, .textarea, .select {
  width: 100%;
  padding: 0.95rem 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  color: var(--t-1);
  font-family: var(--text);
  font-size: 1.02rem;
  border-radius: 0;
  transition: border-color var(--dur-2) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: rgba(244, 245, 245, 0.28); }
.input:hover, .textarea:hover { border-bottom-color: var(--t-3); }
.input:focus, .textarea:focus { outline: 0; border-bottom-color: var(--flare); }
.input:focus-visible, .textarea:focus-visible { outline: 2px solid var(--flare); outline-offset: 4px; }
.textarea { resize: vertical; min-height: 7.5rem; line-height: 1.55; }

.input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-bottom-color: #ff6b4a; }
.error {
  display: block;
  font-family: var(--sans);
  font-size: 0.76rem;
  color: #ff8163;
  margin-top: 0.5rem;
  min-height: 1px;
}

/* Selectable options — rectangular, deliberately not pills. */
.opts { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.opt { position: relative; }
.opt input {
  position: absolute;
  inset: 0;
  opacity: 0;
  width: 100%; height: 100%;
  margin: 0;
  cursor: pointer;
}
.opt span {
  display: block;
  padding: 0.7rem 1rem;
  border: 1px solid var(--rule);
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--t-2);
  transition: border-color var(--dur-1) linear, color var(--dur-1) linear,
              background-color var(--dur-1) linear;
}
.opt input:hover + span { border-color: var(--t-3); color: var(--t-1); }
.opt input:checked + span {
  border-color: var(--flare);
  background: var(--flare-wash);
  color: var(--t-1);
}
.opt input:focus-visible + span { outline: 2px solid var(--flare); outline-offset: 3px; }

.form__submit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-5);
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: var(--s-6);
  border-top: 1px solid var(--rule);
}

.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.note {
  padding: var(--s-5);
  border-left: 2px solid var(--flare);
  background: var(--ink-800);
}
.form__status { margin-top: var(--s-5); }
.form__status:empty { display: none; }

/* --- Callout / availability --------------------------------------------- */

.availability {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.85rem 0.5rem 0.7rem;
  border: 1px solid var(--rule);
}
.availability__dot {
  width: 7px; height: 7px;
  background: var(--flare);
  flex: none;
}
.t-invert .availability { border-color: var(--rule-inv); }

/* --- Footer ------------------------------------------------------------- */

/* One grid, four columns, no internal dividers: who we are and how to reach
   us, then Site, Website services, and where we are. */
.footer {
  border-top: 1px solid var(--rule);
  padding-block: clamp(4rem, 7vw, 6.5rem) var(--s-6);
}
.footer__grid {
  display: grid;
  gap: var(--s-8) clamp(2rem, 4vw, 4.5rem);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 760px) {
  .footer__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
}
@media (min-width: 1100px) {
  .footer__grid { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.25fr); }
  .footer__brand { grid-column: auto; }
}
.footer__head { margin-bottom: var(--s-5); }
.footer__list > li + li { margin-top: 0.8rem; }
.footer__list a { text-decoration: none; color: var(--t-2); transition: color var(--dur-1) linear; }
.footer__list a:hover { color: var(--flare); }

.footer__address {
  display: grid;
  margin-top: var(--s-7);
  font-style: normal;
  color: var(--t-2);
  line-height: 1.6;
}
.footer__address .footer__head { margin-bottom: var(--s-4); }
.footer__address:first-child { margin-top: 0; }
.footer__contact { margin-top: var(--s-7); }
.footer__legalese { display: grid; gap: 0.4rem; }

.footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-3) var(--s-5);
  margin-top: var(--s-8);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule-soft);
}

/* --- Placeholder marker ------------------------------------------------- */

.ph {
  display: inline-block;
  font-family: var(--sans);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--t-3);
  border: 1px dashed var(--rule);
  padding: 0.2rem 0.45rem;
  vertical-align: middle;
}
.t-invert .ph { color: var(--t-3-inv); border-color: var(--rule-inv); }

/* --- Motion ------------------------------------------------------------- */

.js [data-rise] {
  opacity: 0;
  transform: translateY(18px);
}
.js [data-rise].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.85s var(--ease), transform 0.85s var(--ease);
  transition-delay: var(--delay, 0s);
}

.js [data-wipe] > span {
  display: block;
  transform: translateY(102%);
}
/* The mask has to clear the descenders or it crops the tail of g, y and p.
   Padding opens the box; the negative margin keeps the line rhythm intact. */
.js [data-wipe] {
  overflow: hidden;
  padding-bottom: 0.16em;
  margin-bottom: -0.16em;
}
.js [data-wipe].is-in > span {
  transform: none;
  transition: transform 1s var(--ease);
  transition-delay: var(--delay, 0s);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .js [data-rise], .js [data-wipe] > span { opacity: 1; transform: none; }
}

/* --- Print -------------------------------------------------------------- */

@media print {
  .header, .menu, .grain, .burger, .seam__range { display: none !important; }
  body { background: #fff; color: #000; }
  .t-invert { background: #fff; }
}

/* 7 · UTILITIES =========================================================== */

.line { display: block; }
.dly-1 { --delay: 0.07s; }
.dly-2 { --delay: 0.14s; }
.dly-3 { --delay: 0.21s; }
.dly-4 { --delay: 0.30s; }
.dly-5 { --delay: 0.40s; }
.dly-6 { --delay: 0.52s; }

.u-flare { color: var(--flare); }
.t-invert .u-flare { color: var(--flare-ink); }
.u-t1 { color: var(--t-1); }
.t-invert .u-t1 { color: var(--t-1-inv); }
.u-wide { max-width: 78ch; }
.u-narrow { max-width: 52ch; }
.u-mt-4 { margin-top: var(--s-4); }
.u-mt-5 { margin-top: var(--s-5); }
.u-mt-6 { margin-top: var(--s-6); }
.u-mt-7 { margin-top: var(--s-7); }
.u-mt-8 { margin-top: var(--s-8); }
.u-mb-5 { margin-bottom: var(--s-5); }
.u-mb-6 { margin-bottom: var(--s-6); }
.u-mb-7 { margin-bottom: var(--s-7); }
.u-nowrap { white-space: nowrap; }

/* 8 · INTERIOR PAGES ====================================================== */

.page-head {
  padding-top: calc(var(--header-h) + clamp(2.25rem, 5.5vw, 5rem));
  padding-bottom: clamp(2.25rem, 4.5vw, 4rem);
}
.head-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.75rem;
  padding-bottom: var(--s-4);
  margin-bottom: clamp(1.5rem, 2.6vw, 2.25rem);
  border-bottom: 1px solid var(--rule-soft);
}
.t-invert .head-meta { border-bottom-color: var(--rule-inv); }

@media (min-width: 900px) {
  .split--form { grid-template-columns: minmax(0, 7fr) minmax(0, 4fr); }
  .split--half { grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); }
}

/* Engagement summary blocks — alternating emphasis, never a card grid. */
.engagement { border-top: 1px solid var(--rule); padding-top: clamp(1.75rem, 3.5vw, 3rem); }
.engagement + .engagement { margin-top: clamp(2.5rem, 5vw, 4.5rem); }
.t-invert .engagement { border-top-color: var(--rule-inv); }

.pair { display: grid; gap: var(--s-5) var(--gutter); }
@media (min-width: 760px) { .pair { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .pair--three { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.pair__term {
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--flare);
  display: block;
  margin-bottom: var(--s-3);
}
.t-invert .pair__term { color: var(--flare-ink); }

.discipline { border-top: 1px solid var(--rule); padding-top: var(--s-6); }
.discipline + .discipline { margin-top: clamp(3rem, 6vw, 5.5rem); }
.t-invert .discipline { border-top-color: var(--rule-inv); }
.discipline__n {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.16em;
  color: var(--flare);
}

.next {
  display: grid;
  gap: var(--s-4);
  padding: clamp(2rem, 4vw, 3.5rem) 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
}
.next:hover .d-2 { color: var(--flare); }
.next .d-2 { transition: color var(--dur-2) var(--ease); }

/* Full-bleed comparison plates get a ceiling so they never dominate a
   large viewport; the asymmetry that leaves is deliberate. */
.seam--wide { max-width: 1120px; }
.split--form aside .ledger__row { grid-template-columns: 1fr; }


/* 9 · REVIEWS, DEVICES, DATA, TEAM ======================================== */

/* --- Google reviews ----------------------------------------------------- */

.reviews__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4) var(--s-6);
  padding-bottom: var(--s-5);
  border-bottom: 1px solid var(--rule);
}
.t-invert .reviews__head { border-bottom-color: var(--rule-inv); }

.score {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-stretch: 106%;
  font-size: clamp(2.4rem, 4.4vw, 3.4rem);
  letter-spacing: -0.04em;
  line-height: 1;
}
.stars { display: inline-flex; gap: 3px; }
.stars svg { fill: var(--flare); }
.t-invert .stars svg { fill: var(--flare); }

.reviews__grid {
  display: grid;
  gap: 0;
  border-left: 1px solid var(--rule);
}
.t-invert .reviews__grid { border-left-color: var(--rule-inv); }
@media (min-width: 820px) { .reviews__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.review {
  padding: clamp(1.4rem, 2.6vw, 2rem);
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.t-invert .review { border-color: var(--rule-inv); }
.review__stars { margin-bottom: var(--s-4); }
.review__body { color: var(--t-2); }
.t-invert .review__body { color: var(--t-2-inv); }
.review__by {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule-soft);
}
.t-invert .review__by { border-top-color: var(--rule-inv); }
.review__avatar {
  width: 38px; height: 38px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
}

/* --- Device mockups ----------------------------------------------------- */

.devices { position: relative; }
.devices__laptop { width: 100%; }
.devices__phone {
  position: absolute;
  right: 2%;
  bottom: 7%;
  width: 19%;
  max-width: 190px;
  filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.55));
}
@media (max-width: 600px) {
  .devices__phone { position: static; width: 46%; margin: var(--s-5) 0 0 auto; }
}

/* --- Data ---------------------------------------------------------------- */

.chart {
  border: 1px solid var(--rule);
  background: var(--ink-800);
  padding: clamp(1rem, 2.2vw, 1.75rem);
}
.t-invert .chart { border-color: var(--rule-inv); }
.t-invert .chart .meta { color: var(--t-3); }
.chart__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.4rem 1rem;
  margin-bottom: var(--s-5);
}

/* --- Team --------------------------------------------------------------- */

.team {
  display: grid;
  gap: var(--s-6) var(--gutter);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.team__name { margin-top: var(--s-4); }

/* --- Header telephone --------------------------------------------------- */

.header__end { display: flex; align-items: center; gap: clamp(0.75rem, 1.6vw, 1.5rem); }
.header .header__tel { display: none; }
@media (min-width: 1180px) {
  .header .header__tel {
    display: inline-block;
    font-family: var(--sans);
    font-size: var(--fs-meta);
    font-weight: 600;
    letter-spacing: 0.12em;
    text-decoration: none;
    color: var(--t-2);
    white-space: nowrap;
    transition: color var(--dur-1) linear;
  }
  .header .header__tel:hover { color: var(--flare); }
}

/* --- Style guide -------------------------------------------------------- */

.swatches { display: grid; gap: var(--s-5); grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.swatch__chip { height: 108px; border: 1px solid var(--rule); }
.swatch__meta { margin-top: var(--s-3); }
.specimen { border-top: 1px solid var(--rule); padding-block: var(--s-6); }
.specimen__label { margin-bottom: var(--s-4); }

.sw-ink { background: var(--ink-900); }
.sw-ink2 { background: var(--ink-700); }
.sw-paper { background: var(--paper); }
.sw-flare { background: var(--flare); }
.sw-flare-ink { background: var(--flare-ink); }
.sw-t2 { background: rgba(244, 245, 245, 0.66); }
code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88em;
  padding: 0.12em 0.36em;
  /* The chip darkens its band rather than tinting it orange. An orange wash
     under orange text raised the background towards the text and dropped the
     ratio to 4.29:1 on the charcoal band, which fails AA. Darkening moves the
     two apart instead: 5.15:1 at worst, on every dark surface in use. */
  background: rgba(8, 9, 10, 0.55);
  color: var(--flare);
}
/* On white the wash has to lighten, so it stays orange - but at 10% rather
   than 12%, which was landing exactly on the 4.5:1 line with nothing spare. */
.t-invert code { color: var(--flare-ink); background: rgba(232, 80, 30, 0.1); }

/* Four figures need four columns' worth of room; in a half-width column
   they wrap into unreadable stacks, so this variant stays two-up. */
.record--half { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 860px) { .record--half { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.reviews__score { display: flex; align-items: center; gap: var(--s-4); }
.reviews__score .stars { margin-bottom: 4px; }

/* 10 · LIGHT-BAND OVERRIDES ==============================================
   Every component that sets its own colour needs a counterpart for white
   bands. Missing these is how light-on-light text gets shipped. */

.t-invert .spec > li { color: var(--t-2-inv); border-top-color: var(--rule-inv); }
/* Decorative squares, not text, so they take the brand orange on light bands
   too: 3.77:1 on white clears the 3:1 needed for a graphic. */
.t-invert .spec > li::before { background: var(--flare); }
.t-invert .stage__n { color: var(--t-3-inv); }
.t-invert .stage:hover .stage__n,
.t-invert .stage[open] .stage__n { color: var(--flare-ink); }
.t-invert .stage__summary:hover { color: var(--flare-ink); }
.t-invert .stage,
.t-invert .programme { border-color: var(--rule-inv); }
.t-invert .fieldset__legend { border-bottom-color: var(--rule-inv); }
.t-invert .fieldset__legend .num { color: var(--flare-ink); }
.t-invert .field label,
.t-invert .field__label { color: var(--t-2-inv); }
.t-invert .field__hint { color: var(--t-3-inv); }
.t-invert .input,
.t-invert .textarea,
.t-invert .select { color: var(--t-1-inv); border-bottom-color: var(--rule-inv); }
.t-invert .input:focus,
.t-invert .textarea:focus { border-bottom-color: var(--flare-ink); }
.t-invert .opt span { color: var(--t-2-inv); border-color: var(--rule-inv); }
.t-invert .opt input:checked + span { border-color: var(--flare-ink); color: var(--t-1-inv); }
.t-invert .form__submit { border-top-color: var(--rule-inv); }
.t-invert .seam__cap .meta { color: var(--t-3-inv); }
.t-invert .next { border-color: var(--rule-inv); }
.t-invert .next:hover .d-2 { color: var(--flare-ink); }
.t-invert .swatch__chip { border-color: var(--rule-inv); }
.t-invert .specimen { border-top-color: var(--rule-inv); }

/* The note panel keeps its own surface, so it flips with the band rather
   than inheriting inverted text onto a dark background. */
.t-invert .note {
  background: var(--paper-100);
  border-left-color: var(--flare-ink);
}

/* White on the accent only reaches 3.75:1; the deeper tone clears AA. */
.skip-link { background: var(--flare-ink); }

/* 11 · HERO, PROOF BADGE, LOGOS, MEGA MENU ================================ */

/* --- Hero with video sales letter --------------------------------------- */

/* Near-black like every other dark band, with a faint grid laid over it. The
   grid is the same lattice the video posters carry, drawn in CSS so it costs
   no request, and masked so it fades out towards the edges rather than
   stopping at them. It sits below the content on its own layer. */
.hero--vsl {
  position: relative;
  isolation: isolate;
  background: var(--ink-900);
  padding-top: calc(var(--header-h) + clamp(1.5rem, 3.2vw, 2.75rem));
  padding-bottom: clamp(2.5rem, 5vw, 4.5rem);
  overflow: hidden;
}
.hero--vsl::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(244, 245, 245, 0.04) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(244, 245, 245, 0.04) 1px, transparent 1px);
  background-size: 64px 64px;
  background-position: 50% 0;
  -webkit-mask-image: radial-gradient(ellipse 90% 80% at 60% 35%, #000 20%, transparent 100%);
  mask-image: radial-gradient(ellipse 90% 80% at 60% 35%, #000 20%, transparent 100%);
}

/* Source order is the mobile order: film, headline, intro, actions,
   proof. From 720px the film moves into its own column beside the text. */
.hero--vsl .hero__inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "vsl" "head" "deck" "actions" "proof";
  width: 100%;
}
.hero--vsl .hero__head    { grid-area: head; max-width: 17ch; }
.hero--vsl .hero__deck    { grid-area: deck; max-width: 46ch; margin-top: var(--s-6); }
.hero--vsl .hero__actions { grid-area: actions; }
.hero--vsl .hero__proof   { grid-area: proof; }

/* The film frame: 16:9, the same frame, poster and play button as every other
   video on the site. On narrow screens it leads the hero at full width; from
   720px it takes the right-hand column, centred against the text beside it. */
.hero__vsl {
  grid-area: vsl;
  width: 100%;
  margin: 0 0 var(--s-6);
}
.frame--vsl { aspect-ratio: 16 / 9; }
.frame--vsl > img { height: 100%; object-fit: cover; }

@media (min-width: 720px) {
  .hero--vsl .hero__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    /* The empty flexible row takes up any height the film adds, so the text
       stays together and the proof row settles at the foot of the column. */
    grid-template-rows: auto auto auto 1fr auto;
    grid-template-areas:
      "head    vsl"
      "deck    vsl"
      "actions vsl"
      ".       vsl"
      "proof   vsl";
    column-gap: clamp(2rem, 5vw, 6rem);
  }
  .hero__vsl {
    align-self: center;
    margin: 0;
    width: clamp(18rem, 40vw, 38rem);
  }
  .hero--vsl .hero__proof { align-self: end; }
}

.hero__proof {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-5) var(--s-7);
  margin-top: clamp(1.5rem, 2.8vw, 2.25rem);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
}

/* --- Review score badge -------------------------------------------------- */

.gbadge {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.7rem 1rem;
  border: 1px solid var(--rule);
  background: rgba(8, 9, 10, 0.5);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  text-decoration: none;
}
.gbadge__score {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 1.35rem;
  letter-spacing: -0.03em;
  line-height: 1;
}
.gbadge__text { line-height: 1.35; }

/* Prestige Awards accolade (white artwork), inline beside the review badge. */
.hero__award {
  display: block;
  width: auto;
  height: 3.75rem;
}
/* The British Agency Award emblem: a laurel with room above and below the text,
   so it sits a little taller than the Prestige lockup to read at the same size. */
.hero__award--baa { height: 4.5rem; }
/* The award emblem under the eyebrow on its blog post. */
.post-award { display: block; width: auto; height: clamp(5rem, 8vw, 7rem); margin-top: var(--s-5); }
.t-invert .gbadge { border-color: var(--rule-inv); background: transparent; }

/* --- Client logos -------------------------------------------------------- */

.logos { margin-top: clamp(1.25rem, 2.4vw, 1.75rem); }
.logos__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3.25rem);
  margin-top: var(--s-4);
}
.logos__list li { color: #ffffff; opacity: 0.92; transition: opacity var(--dur-2) var(--ease); }
.logos__list li:hover { opacity: 1; }
.logos__list svg { height: clamp(24px, 3vw, 30px); width: auto; }
.t-invert .logos__list li { color: var(--t-1-inv); opacity: 0.7; }

/* --- Mega menu ----------------------------------------------------------- */

.nav__group { position: static; }

.mega {
  position: fixed;
  left: 0;
  right: 0;
  top: var(--header-h);
  z-index: 98;
  border-top: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease),
              visibility 0s linear var(--dur-2);
}
@media (min-width: 940px) {
  .nav__group:hover .mega,
  .nav__group:focus-within .mega,
  .mega:hover {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
  }
}
@media (max-width: 939px) { .mega { display: none; } }
.mega.is-shut { opacity: 0 !important; visibility: hidden !important; }

.mega__inner { padding-block: clamp(2.25rem, 3.5vw, 3.25rem); }
/* Six items, one row. The column count follows the number of links, so a
   seventh discipline needs no change here. */
.mega__list {
  display: grid;
  gap: 0 clamp(1.25rem, 2.2vw, 2.25rem);
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
}
/* Never reflows to a second row: the type steps down instead. */
@media (min-width: 940px) and (max-width: 1279px) {
  .mega__list { gap: 0 clamp(0.9rem, 1.6vw, 1.4rem); }
  .mega__title { font-size: 0.98rem; letter-spacing: -0.02em; }
  .mega__desc { font-size: 0.82rem; line-height: 1.5; }
  .mega__link { padding: var(--s-4) var(--s-3) var(--s-5) 0; }
}
.mega__link {
  display: block;
  padding: var(--s-5) var(--s-4) var(--s-6) 0;
  text-decoration: none;
  border-top: 1px solid var(--rule);
  transition: color var(--dur-1) linear, border-color var(--dur-2) var(--ease);
}
.mega__link:hover { border-top-color: var(--flare); }
.mega__link:hover { color: var(--flare); }
.mega__title {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 108%;
  font-size: 1.12rem;
  letter-spacing: -0.015em;
  display: block;
  margin-bottom: 0.55rem;
}
.mega__desc { font-size: 0.88rem; line-height: 1.55; color: var(--t-2); }
.mega__link:hover .mega__desc { color: var(--t-2); }
.mega__aside {
  border-left: 1px solid var(--rule);
  padding-left: var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--s-5);
}

/* Sub-navigation inside the mobile panel */
/* The mobile menu no longer lists the five disciplines under Website Services:
   the page itself opens with a table of contents, so repeating them here made
   the menu long enough to scroll on a small phone for no gain.

   The phone number and email address carry the meta label treatment, taken
   from the .meta class itself rather than restated here, so they cannot drift
   away from the style guide. */
.menu__contact {
  text-decoration: none;
  transition: color var(--dur-1) linear;
}
.menu__contact:hover, .menu__contact:focus-visible { color: var(--flare); }


/* 12 · WORK CARDS ========================================================= */

.work-grid {
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem) var(--gutter);
  /* Two up, not auto-fit. `minmax(300px, 1fr)` resolved to three columns at
     desktop widths, which left the fourth project stranded on a row of its
     own. Four projects in a 2x2 is balanced, and the extra width lets a real
     screenshot be read rather than just recognised. */
  grid-template-columns: 1fr;
}
@media (min-width: 760px) {
  .work-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.project { display: flex; flex-direction: column; text-decoration: none; }
.project__shot {
  border: 1px solid var(--rule);
  background: var(--ink-700);
  overflow: hidden;
}
.t-invert .project__shot { border-color: var(--rule-inv); background: var(--paper-100); }
.project__shot img {
  width: 100%;
  aspect-ratio: 8 / 5;
  object-fit: cover;
  transition: transform var(--dur-3) var(--ease), opacity var(--dur-2) linear;
}
.project:hover .project__shot img { transform: scale(1.03); }
.project__name {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 110%;
  font-size: clamp(1.15rem, 1.7vw, 1.45rem);
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-top: var(--s-5);
  transition: color var(--dur-1) linear;
}
.project:hover .project__name { color: var(--flare); }
.t-invert .project:hover .project__name { color: var(--flare-ink); }
.project__what { color: var(--t-2); margin-top: 0.6rem; font-size: 0.95rem; line-height: 1.55; }
.t-invert .project__what { color: var(--t-2-inv); }
.project__go {
  margin-top: var(--s-4);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.project:hover .project__go { color: var(--flare); }
.t-invert .project:hover .project__go { color: var(--flare-ink); }
/* Blog listing: a text-only project row, so there is no screenshot above the name.
   The ledger sets its column to the muted tone; the title itself stays full white. */
.ledger__def > .project .project__name { margin-top: 0; color: var(--t-1); }
.ledger__def > .project:hover .project__name { color: var(--flare); }

/* Alternating illustration beside each discipline */
.discipline__art { margin-top: var(--s-6); }
@media (min-width: 900px) {
  .discipline--art .split { align-items: start; }
}

/* Legal: each accreditation's mark sits in front of its name. */
.ledger__term--mark { display: flex; align-items: center; gap: 1.1rem; }
/* A fixed box, so every name starts on the same line whatever the mark's shape. */
.ledger__term--mark img { flex: none; width: 3.25rem; height: 3rem; object-fit: contain; object-position: left center; }
@media (min-width: 760px) {
  .ledger__row:has(.ledger__term--mark) { align-items: center; }
}

/* --- Hosting accreditations ------------------------------------------- */
/* The marks themselves: shown exactly as supplied, at one height, never
   recoloured or cropped. Rules: /legal#hosting. */
.accred-logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  padding: 0;
}
.accred-logos img {
  display: block;
  width: auto;
  height: clamp(4.5rem, 6vw, 5.5rem);
}

.footer__legal { display: flex; flex-wrap: wrap; gap: 0.4rem 1.75rem; }
/* Plain in the footer base: colour alone marks the hover. */
.footer__legal .link { background-image: none; padding-bottom: 0; }

/* 13 · MOBILE HEADER ====================================================== */

@media (max-width: 939px) {
  .header {
    background: rgba(8, 9, 10, 0.9);
    -webkit-backdrop-filter: saturate(140%) blur(14px);
    backdrop-filter: saturate(140%) blur(14px);
    border-bottom-color: var(--rule-soft);
  }
  .header__inner { gap: var(--s-4); }
  .wordmark img { height: 24px; }
}

.header__end { display: flex; align-items: center; gap: clamp(0.5rem, 1.6vw, 1.5rem); }


.burger { width: 44px; height: 40px; }

.menu { padding-top: calc(var(--header-h) + var(--s-6)); }
.menu__link { padding: clamp(0.7rem, 2.2vw, 1rem) 0; font-size: clamp(1.6rem, 7.2vw, 2.4rem); }
.menu__foot { display: grid; gap: var(--s-4); padding-top: var(--s-5); }
.menu__cta { justify-content: center; width: 100%; }

/* 14 · MOBILE HERO ======================================================== */

@media (max-width: 760px) {
  .hero--vsl {
    padding-top: calc(var(--header-h) + 1.5rem);
    padding-bottom: 2rem;
  }
  .hero--vsl .hero__head { max-width: none; }
  .hero__eyebrow { gap: 0.35rem 1.1rem; margin-bottom: 1.25rem; padding-bottom: 0.85rem; }
  .hero__deck, .hero--vsl .hero__deck { margin-top: 1.5rem; }
  .hero__actions { margin-top: 1.6rem; gap: 1rem; }
  .hero__actions .btn { width: 100%; justify-content: center; }
  .hero__proof { margin-top: 1.5rem; padding-top: 1.1rem; gap: 1rem 1.25rem; }
  .hero__award { height: 2.6rem; }
  .hero__award--baa { height: 3.8rem; }
}
@media (max-width: 420px) {
  .gbadge { padding: 0.6rem 0.8rem; gap: 0.6rem; }
  .gbadge__score { font-size: 1.15rem; }
}

/* Client logos now sit in their own band beneath the hero. */
.logo-band { padding-block: clamp(1.75rem, 3.5vw, 2.75rem); border-bottom: 1px solid var(--rule-soft); }
.logo-band__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2.75rem);
}
.logo-band .logos__list { margin-top: 0; }
.logo-band .logos__label { flex: none; }

/* 15 · ICONS ============================================================== */

.ico { width: 26px; height: 26px; flex: none; stroke: currentColor; fill: none;
       stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.ico--lg { width: 32px; height: 32px; }

.mega__link { display: flex; flex-direction: column; gap: 0.9rem; }
.mega__icon { color: var(--flare); transition: transform var(--dur-2) var(--ease); }
.mega__link:hover .mega__icon { transform: translateY(-2px); }

/* 16 · CAPABILITY GRID ==================================================== */

.cap-grid {
  display: grid;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  grid-template-columns: 1fr;
}
@media (min-width: 620px) { .cap-grid { grid-template-columns: repeat(2, 1fr); } }
/* Six services: three across, so no row is left with a single straggler. */
@media (min-width: 1040px) { .cap-grid { grid-template-columns: repeat(3, 1fr); } }
.t-invert .cap-grid { background: var(--rule-inv); border-color: var(--rule-inv); }

.cap {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(1.5rem, 2.6vw, 2rem);
  background: var(--ink-900);
  text-decoration: none;
  transition: background-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.t-invert .cap { background: var(--paper); }
.cap:hover, .cap:focus-visible { background: var(--paper); color: var(--ink-900); }
.t-invert .cap:hover, .t-invert .cap:focus-visible { background: var(--ink-900); color: var(--paper); }
.cap__icon { color: var(--flare); }
.t-invert .cap__icon { color: var(--flare-ink); }
.cap:hover .cap__icon { color: var(--flare-ink); }
.t-invert .cap:hover .cap__icon { color: var(--flare); }
.cap__title {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 108%;
  font-size: 1.06rem;
  letter-spacing: -0.018em;
  line-height: 1.2;
}
.cap__text { font-size: 0.9rem; line-height: 1.55; color: var(--t-2); flex: 1; }
.t-invert .cap__text { color: var(--t-2-inv); }
.cap:hover .cap__text { color: rgba(13, 15, 17, 0.72); }
.t-invert .cap:hover .cap__text { color: rgba(244, 245, 245, 0.7); }
.cap__go {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--t-2);
  transition: color var(--dur-1) linear, transform var(--dur-2) var(--ease);
}
.cap__go svg { flex: none; transition: transform var(--dur-2) var(--ease); }
.cap:hover .cap__go { color: var(--flare-ink); }
.cap:hover .cap__go svg { transform: translateX(4px); }
.t-invert .cap__go { color: var(--t-2-inv); }
.t-invert .cap:hover .cap__go { color: var(--flare); }

/* 17 · STANDARDS WITH ICONS =============================================== */

.creed { display: grid; gap: 1px; background: var(--rule-inv); grid-template-columns: 1fr; }
@media (min-width: 700px) { .creed { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .creed { grid-template-columns: repeat(3, 1fr); } }
.creed__item {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(1.5rem, 2.6vw, 2.1rem);
  background: var(--paper);
  color: var(--t-1-inv);
}
.creed__icon { color: var(--flare-ink); }
.creed__title {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 108%;
  font-size: 1.08rem;
  letter-spacing: -0.018em;
}
.creed__text { font-size: 0.94rem; line-height: 1.6; color: var(--t-2-inv); }

/* 18 · CASE SECTIONS ====================================================== */

.case { padding-block: clamp(3.5rem, 8vw, 7rem); }
.case__grid {
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem) clamp(3rem, 6vw, 6rem);
  align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 940px) {
  .case { min-height: 78vh; display: flex; align-items: center; }
  .case .shell { width: 100%; }
  .case__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6.5fr); }
  .case--flip .case__body { order: 2; }
}
.case__media { margin: 0; }

.stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--rule);
}
.t-invert .stats { border-top-color: var(--rule-inv); }
.stat { padding: var(--s-5) var(--s-4) 0 0; }
.stat__fig {
  display: block;
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-stretch: 104%;
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
  letter-spacing: -0.04em;
  line-height: 1;
  margin-bottom: 0.5rem;
}
.t-invert .stat__fig { color: var(--t-1-inv); }

.project__shot--ask {
  display: grid;
  place-items: center;
  aspect-ratio: 8 / 5;
  border: 1px dashed var(--rule);
  background: transparent;
}
.t-invert .project__shot--ask { border-color: var(--rule-inv); }

/* The full stop in a heading picks up the accent. Applied by hand in the
   markup so it is opt-in, never automatic. */
.hl-dot { color: var(--flare); }
.t-invert .hl-dot { color: var(--flare); }

.stage__title--sm { font-size: clamp(1.15rem, 2.2vw, 1.55rem); font-stretch: 108%; }

/* A grid of disciplines rather than a headcount. */
@media (min-width: 620px) { .cap-grid--four { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .cap-grid--four { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1240px) { .cap-grid--four { grid-template-columns: repeat(4, 1fr); } }
.cap-grid--four { width: 100%; }
.cap--static { cursor: default; }
.cap--static:hover { background: var(--ink-900); color: inherit; }
.t-invert .cap--static:hover { background: var(--paper); color: inherit; }
.cap--static:hover .cap__icon { color: var(--flare); }
.t-invert .cap--static:hover .cap__icon { color: var(--flare-ink); }
.cap--static:hover .cap__text { color: var(--t-2); }
.t-invert .cap--static:hover .cap__text { color: var(--t-2-inv); }

/* 19 · IMPROVEMENT INDICATOR ============================================== */

:root {
  --rise: #1bdc9c;        /* on dark surfaces */
  --rise-ink: #0b7a55;    /* on light surfaces: 5.3:1 against white */
}
.stat--up .stat__fig { display: flex; align-items: baseline; gap: 0.3rem; }
.stat__arrow {
  width: 0.62em; height: 0.62em;
  flex: none;
  color: var(--rise);
  align-self: center;
}
.t-invert .stat__arrow { color: var(--rise-ink); }
.stat__arrow svg { width: 100%; height: 100%; fill: currentColor; }

/* 20 · CASE MEDIA ========================================================= */

.case__media .frame img,
.case__media .frame video { width: 100%; display: block; }
.media-note {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: var(--s-3);
}
.media-note::before {
  content: "";
  width: 6px; height: 6px;
  background: var(--flare);
  flex: none;
}
.t-invert .media-note::before { background: var(--flare-ink); }

/* Per-case testimonial: a disclosure, so it works without JavaScript. */
.vid { margin-top: var(--s-6); }
.vid__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  background: none;
  color: inherit;
  padding: 0.7rem 1rem 0.7rem 0.7rem;
  border: 1px solid var(--rule);
  cursor: pointer;
  list-style: none;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  transition: border-color var(--dur-2) var(--ease), color var(--dur-1) linear;
}
.vid__toggle::-webkit-details-marker { display: none; }
.t-invert .vid__toggle { border-color: var(--rule-inv); }
.vid__toggle:hover { border-color: var(--flare); color: var(--flare); }
.t-invert .vid__toggle:hover { border-color: var(--flare-ink); color: var(--flare-ink); }
.vid__disc {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--flare);
  display: grid;
  place-items: center;
  flex: none;
}
.vid__disc svg { fill: #fff; margin-left: 2px; }
.vid[open] .vid__toggle { margin-bottom: var(--s-5); }

/* The case-study video trigger as a small poster card: prominent enough to be
   noticed next to the scrolling mockup, without taking more room from it. */
.vid__toggle--thumb {
  gap: 1.1rem;
  padding: 0.5rem 1.4rem 0.5rem 0.5rem;
  text-align: left;
}
.vid__thumb {
  position: relative;
  flex: none;
  width: clamp(7.5rem, 11vw, 9.5rem);
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--ink-700);
}
.vid__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-3) var(--ease);
}
.vid__thumb .vid__disc {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 34px; height: 34px;
  transition: transform var(--dur-2) var(--ease);
}
.vid__toggle--thumb:hover .vid__thumb img { transform: scale(1.05); }
.vid__toggle--thumb:hover .vid__disc { transform: scale(1.08); }
.vid__text { display: grid; gap: 0.4rem; }
.vid__sub {
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--t-3);
}
.t-invert .vid__sub { color: var(--t-3-inv); }
@media (prefers-reduced-motion: reduce) {
  .vid__thumb img, .vid__thumb .vid__disc { transition: none; }
}
.vid__panel { max-width: 620px; }

/* 21 · REFINEMENTS ======================================================== */

/* Team portraits were running too tall in a two-up grid. */
.team { grid-template-columns: repeat(auto-fit, minmax(200px, 300px)); }
.frame--portrait img { aspect-ratio: 1 / 1; }

/* Discipline eyebrows match every other eyebrow on the site. */
.discipline__n { text-transform: uppercase; }

/* Section imagery sits under the heading rather than full-bleed below. */
.discipline__art { margin-top: var(--s-6); max-width: 460px; }
@media (min-width: 900px) { .discipline__art { margin-top: var(--s-7); max-width: none; } }

.footer .gbadge { margin-top: var(--s-5); }

/* 22 · VIDEO MODAL ======================================================== */

.modal {
  width: min(1040px, 92vw);
  max-height: 88vh;
  padding: 0;
  border: 1px solid var(--rule);
  background: var(--ink-800);
  color: var(--t-1);
  overflow: visible;
}
.modal::backdrop { background: rgba(4, 5, 6, 0.86); }
.modal[open] { animation: modal-in 0.28s var(--ease); }
@keyframes modal-in { from { opacity: 0; transform: translateY(10px); } }
@media (prefers-reduced-motion: reduce) { .modal[open] { animation: none; } }

.modal__inner { padding: clamp(1rem, 2.5vw, 1.75rem); }
.modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}
.modal__close {
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  background: none;
  border: 1px solid var(--rule);
  color: var(--t-1);
  cursor: pointer;
  transition: border-color var(--dur-1) linear, color var(--dur-1) linear;
}
.modal__close:hover { border-color: var(--flare); color: var(--flare); }
.modal__close svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 1.7; }
body.is-locked { overflow: hidden; }

/* Without JavaScript the disclosure still opens inline; with it, the panel
   is moved into the dialog above and this collapses away. */
.vid__panel { max-width: 620px; }

/* Inside the dialog the panel fills the width; the cap only applies to the
   inline no-JavaScript fallback. */
.modal .vid__panel { max-width: none; }

/* A full heading in the dialog, used when the trigger sets data-vid-title. */
.modal__head:has(.modal__titles) { align-items: flex-start; }
.modal__titles { min-width: 0; }
.modal__kicker { margin: 0 0 0.45rem; }
.modal__title { margin: 0; color: var(--t-1); }
.t-invert .modal .modal__title { color: var(--t-1); }

/* Corner play buttons, for films whose subject sits centre-frame: the
   button would otherwise land on the interviewee's face. */
.vid__toggle--corner .vid__thumb .vid__disc {
  inset: auto auto 6px 6px;
  margin: 0;
  width: 26px; height: 26px;
}
.play--corner { place-items: end start; padding: var(--s-5); }
.play--corner .play__disc {
  width: clamp(48px, 6vw, 64px);
  height: clamp(48px, 6vw, 64px);
}

/* A full-sentence caption reads better in sentence case than as .meta. */
.frame__lede {
  margin: 0;
  color: var(--t-2);
  font-size: 0.95rem;
  line-height: 1.5;
}
.t-invert .modal .frame__lede { color: var(--t-2); }

/* The dialog carries its own dark surface, so it must not inherit the
   inverted text colours of whichever band it happens to sit inside. */
.t-invert .modal,
.t-invert .modal .u-t1 { color: var(--t-1); }
.t-invert .modal .meta,
.t-invert .modal .foot { color: var(--t-3); }
.t-invert .modal .modal__close { color: var(--t-1); border-color: var(--rule); }
.t-invert .modal .frame { border-color: var(--rule); background: var(--ink-700); }

/* 23 · FORM REQUIRED MARKER =============================================== */

.req {
  color: var(--flare);
  text-decoration: none;
  border: 0;
  margin-left: 0.15em;
  font-weight: 700;
}
.t-invert .req { color: var(--flare-ink); }

/* 24 · LOGO STRIP ========================================================= */

/* Client logos arrive in every colour under the sun. Knocking them to a flat
   white (or flat black on light bands) means any supplied file works, and it
   also fixes currentColor, which an <img> cannot inherit from the page. */
.logos__list img { filter: brightness(0) invert(1); }
.t-invert .logos__list img { filter: brightness(0); }

/* 25 · MEGA MENU ALIGNMENT ================================================ */

/* Matches the header exactly, so there is no seam where the two meet. */
/* Solid: translucency over a moving hero made the menu hard to read. */
.mega { background: var(--ink-800); }
/* While the menu is open the header is opaque too, even at the top of the page. */
/* The header goes solid too while the menu is open, so the two match. */
.header:has(.nav__group:hover),
.header:has(.nav__group:focus-within) {
  background: var(--ink-800);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-bottom-color: transparent;
}
/* Every mega title now fits on one line, so no second line is reserved. If you
   ever add a title long enough to wrap, restore `min-height: 2.5em` here to keep
   the five descriptions on a shared baseline. */
.mega__title { line-height: 1.25; }

/* Case loop videos fill their frame at the same ratio as a screenshot. */
.case__media .frame video { width: 100%; height: auto; aspect-ratio: 8 / 5; object-fit: cover; }

.case__visit { margin-top: var(--s-4); }

/* 26 · MOBILE MENU REFINEMENTS ============================================ */

/* No rule above the first item, and no index numbers. */
.menu__item:first-child { border-top: 0; }
/* One per line, and no underline: these are the phone number and email
   address, not links inside a sentence. */
.menu__foot .menu__contact { display: block; }
/* No lowercase override: the phone number and email address are set as meta
   labels, which means uppercase, exactly like the nav links above them. */

/* 27 · ORANGE ON LIGHT SURFACES =========================================== */

/* Decorative marks can carry the full brand orange; small orange TEXT on
   white cannot (3.75:1), so it uses the lightest tone that still clears
   4.5:1. Two values, two jobs. */
:root { --flare-text: #d0450e; }   /* 4.63:1 on white */

.t-invert .cap__icon,
.t-invert .creed__icon,
.t-invert .mega__icon { color: var(--flare); }
.t-invert .discipline__n,
.t-invert .pair__term,
.t-invert .chapter__n,
.t-invert .fieldset__legend .num { color: var(--flare-text); }

/* Review badge: the stars and the label share a baseline. */
.gbadge > span:last-child { display: flex; flex-direction: column; gap: 2px; }
.gbadge .stars { display: flex; align-items: center; line-height: 1; }
.reviews__score { align-items: center; }

/* Mega menu: description sits closer to its title. */
.mega__title { margin-bottom: 0.3rem; }

/* 28 · TABLE OF CONTENTS ================================================== */

.toc { border-top: 1px solid var(--rule); padding-top: var(--s-5); max-width: 560px; }
.t-invert .toc { border-top-color: var(--rule-inv); }
.toc__label { margin-bottom: var(--s-4); }
.toc__list { display: grid; gap: 1px; }
.toc__list a {
  display: grid;
  grid-template-columns: 2.4rem 1fr;
  align-items: baseline;
  column-gap: 0.6rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--rule-soft);
  text-decoration: none;
  transition: color var(--dur-1) linear, padding-left var(--dur-2) var(--ease);
}
.t-invert .toc__list a { border-bottom-color: var(--rule-inv); }
.toc__list a:hover { color: var(--flare); padding-left: 0.4rem; }
.t-invert .toc__list a:hover { color: var(--flare-text); }
.toc__n {
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.14em;
  color: var(--flare);
  flex: none;
}
.t-invert .toc__n { color: var(--flare-text); }


/* The legal page head runs long; tighten the space before the first section. */
.page-head--legal { padding-bottom: clamp(1.5rem, 3vw, 2.5rem); }

/* 29 · ENGAGEMENT TIMELINE ================================================ */

.timeline { position: relative; display: grid; gap: clamp(2.5rem, 5vw, 4rem); }

.phase {
  position: relative;
  display: grid;
  gap: var(--s-5) clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: 34px minmax(0, 1fr);
}
@media (min-width: 900px) {
  .phase { grid-template-columns: 34px minmax(0, 6fr) minmax(0, 5fr); align-items: start; }
}

/* Marker column: a dot per phase, joined by a line that draws on reveal. */
.phase__marker { position: relative; display: block; width: 34px; }
.phase__dot {
  position: absolute;
  top: 0.45rem; left: 10px;
  width: 13px; height: 13px;
  border: 1.5px solid var(--flare);
  background: var(--ink-900);
  transition: background-color 0.4s var(--ease) 0.15s;
}
.t-invert .phase__dot { border-color: var(--flare-text); background: var(--paper); }
.phase.is-in .phase__dot { background: var(--flare); }
.t-invert .phase.is-in .phase__dot { background: var(--flare-text); }

.phase__marker::before {
  content: "";
  position: absolute;
  top: 1.6rem; left: 16px;
  width: 1px;
  height: calc(100% + clamp(2.5rem, 5vw, 4rem) - 1.6rem);
  background: var(--flare);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.7s var(--ease);
}
.t-invert .phase__marker::before { background: var(--flare-text); opacity: 0.5; }
.phase.is-in .phase__marker::before { transform: scaleY(1); }
.phase:last-child .phase__marker::before { display: none; }

@media (prefers-reduced-motion: reduce) {
  .phase__marker::before { transform: scaleY(1); }
  .phase__dot { background: var(--flare); }
}

.phase__when { margin-bottom: 0.5rem; }
.phase__title {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 110%;
  font-size: clamp(1.3rem, 2.4vw, 1.8rem);
  letter-spacing: -0.025em;
  line-height: 1.1;
}
.phase__gets {
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  font-size: 0.95rem;
  line-height: 1.55;
}
.t-invert .phase__gets { border-top-color: var(--rule-inv); }
.phase__gets-label {
  display: block;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 640;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--flare);
  margin-bottom: 0.4rem;
}
.t-invert .phase__gets-label { color: var(--flare-text); }

.phase__media { margin: 0; grid-column: 2 / -1; }
@media (min-width: 900px) { .phase__media { grid-column: auto; } }
.phase__media img { aspect-ratio: 4 / 3; object-fit: cover; }
.phase__media figcaption { margin-top: var(--s-3); }

/* 30 · CASE STATS (rebuilt) =============================================== */

/* Three narrow columns of tracked-out uppercase wrapped into a mess on a
   phone. Below 620px each figure sits on its own row beside its label. */
.stats { display: grid; grid-template-columns: 1fr; border-top: 1px solid var(--rule); }
.t-invert .stats { border-top-color: var(--rule-inv); }

.stat {
  display: grid;
  grid-template-columns: minmax(4.5rem, auto) 1fr;
  align-items: baseline;
  gap: 0.2rem 1.1rem;
  padding: 0.95rem 0;
  border-bottom: 1px solid var(--rule-soft);
}
.t-invert .stat { border-bottom-color: var(--rule-inv); }
/* The labels use the same treatment as the primary nav links: tracked-out
   uppercase Archivo at meta size. Sentence case at 0.78rem read as body copy
   and made the figures look unlabelled. */
/* Tight. These are tracked-out uppercase labels with no descenders, so the
   generous body line-height left obvious daylight between the two lines of
   something like "Developer hours to update" and it read as two labels rather
   than one wrapped one. */
.stat .meta {
  /* Block, not inline. An inline span sits in a line box whose height is set
     by the tallest thing in it - including the parent's own strut, which is
     body copy at 1.68. So the label's own line-height was being ignored on the
     stacked layout and two lines sat 27px apart instead of 13. */
  display: block;
  line-height: 1.2;
}
.stat__fig {
  display: block;
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-stretch: 104%;
  font-size: clamp(1.45rem, 2.6vw, 2rem);
  letter-spacing: -0.035em;
  line-height: 1;
  white-space: nowrap;
}
.t-invert .stat__fig { color: var(--t-1-inv); }

@media (min-width: 620px) {
  .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 clamp(1.25rem, 2.5vw, 2.25rem); }
  .stat {
    display: block;
    padding: var(--s-5) 0 0;
    border-bottom: 0;
  }
  .stat__fig { margin-bottom: 0.55rem; }
}

.stat--up .stat__fig { display: flex; align-items: baseline; gap: 0.28rem; }
@media (min-width: 620px) { .stat--up .stat__fig { display: flex; } }

/* 31 · CAROUSEL =========================================================== */

.carousel { position: relative; }
.carousel__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 86%;
  gap: var(--s-5);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: thin;
  padding-bottom: var(--s-4);
}
@media (min-width: 760px) { .carousel__track { grid-auto-columns: 46%; } }
@media (min-width: 1200px) { .carousel__track { grid-auto-columns: 32%; } }
@media (prefers-reduced-motion: reduce) { .carousel__track { scroll-behavior: auto; } }

/* Looping variant. The scrollbar is hidden because the track never reaches an
   end, so a bar would sit permanently mid-trough and mean nothing. Dragging and
   the arrow buttons are the affordances instead, and a partial image is always
   left visible at each edge so it reads as continuing. */
.carousel--loop .carousel__track {
  scroll-snap-type: none;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding-bottom: 0;
  cursor: grab;
  /* Movement here is written to scrollLeft directly - by the hand-rolled
     animation, by the drag, and by the wrap. Native smooth scrolling would
     intercept every one of those writes and animate it, so an "instant" step
     would crawl and the wrap would be visible. */
  scroll-behavior: auto;
  /* Stops the browser claiming a horizontal drag for back/forward navigation. */
  overscroll-behavior-x: contain;
}
.carousel--loop .carousel__track::-webkit-scrollbar { display: none; }
.carousel--loop .carousel__track.is-dragging {
  cursor: grabbing;
  scroll-behavior: auto;
  user-select: none;
}
/* Set by the script while it jumps the scroll position back to the middle. */
.carousel__track.is-warping { scroll-behavior: auto !important; }
.carousel--loop .carousel__item img { pointer-events: none; }
.carousel--loop .carousel__nav { margin-top: var(--s-5); }

/* Full-bleed variant. The track spans the whole viewport rather than stopping
   at the page margin, so the photographs visibly continue past both edges. The
   nav is put back inside a .shell in the markup so it still lines up. */
.carousel--bleed .carousel__track { padding-inline: 0; }
.carousel--bleed .carousel__nav { margin-top: var(--s-5); }

/* Portrait. 2:3 is the standard portrait frame - the shape a 35mm camera gives
   you turned on its end - so supplied photography needs no cropping. */
.carousel--portrait .carousel__track { grid-auto-columns: min(58vw, 280px); }
@media (min-width: 760px) {
  .carousel--portrait .carousel__track { grid-auto-columns: min(30vw, 320px); }
}
@media (min-width: 1200px) {
  .carousel--portrait .carousel__track { grid-auto-columns: min(22vw, 380px); }
}
.carousel--portrait .carousel__item img { aspect-ratio: 2 / 3; }

/* Staggered. Every other frame drops by half a step, so the row reads as a
   contact sheet rather than a ruled line. Desktop only: on a phone you see
   roughly one and a half frames at a time, so the offset would look like a
   misalignment rather than a rhythm.

   The offset is a transform, not a margin, so it changes nothing about the
   grid - the scroll maths, the clone widths and the wrap point are all
   untouched. The track gains matching bottom padding because a track with
   overflow-x also clips vertically, and the dropped frames would be cut off.

   Parity survives cloning because each set holds an even number of figures.
   Drop to five and every other copy would invert, so keep the count even. */
@media (min-width: 760px) {
  .carousel--stagger { --stagger: clamp(1.25rem, 3.2vw, 2.75rem); }
  .carousel--stagger .carousel__track { padding-bottom: var(--stagger); }
  .carousel--stagger .carousel__item:nth-child(even) {
    transform: translateY(var(--stagger));
  }
}

.carousel__item { scroll-snap-align: start; margin: 0; }
.carousel__item img {
  width: 100%;
  aspect-ratio: 7 / 5;
  object-fit: cover;
  border: 1px solid var(--rule);
}
.t-invert .carousel__item img { border-color: var(--rule-inv); }
.carousel__item figcaption { margin-top: var(--s-3); }

.carousel__nav { display: flex; gap: 0.6rem; margin-top: var(--s-4); }
.carousel__btn {
  width: 46px; height: 42px;
  display: grid;
  place-items: center;
  background: none;
  border: 1px solid var(--rule);
  color: inherit;
  cursor: pointer;
  transition: border-color var(--dur-1) linear, color var(--dur-1) linear;
}
.t-invert .carousel__btn { border-color: var(--rule-inv); }
.carousel__btn:hover:not(:disabled) { border-color: var(--flare); color: var(--flare); }
.t-invert .carousel__btn:hover:not(:disabled) { border-color: var(--flare-text); color: var(--flare-text); }
.carousel__btn:disabled { opacity: 0.35; cursor: default; }
.carousel__btn svg { width: 15px; height: 11px; }

/* 32 · IMAGE CALL TO ACTION =============================================== */

.cta-cards { display: grid; gap: var(--s-6) var(--gutter); }
@media (min-width: 760px) { .cta-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.cta-card { position: relative; display: block; overflow: hidden; text-decoration: none; }
.cta-card__shot { overflow: hidden; border: 1px solid var(--rule); display: block; }
.t-invert .cta-card__shot { border-color: var(--rule-inv); }
.cta-card__shot img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  display: block;
  transition: transform 0.75s var(--ease);
}
.cta-card:hover .cta-card__shot img,
.cta-card:focus-visible .cta-card__shot img { transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) {
  .cta-card__shot img { transition: none; }
  .cta-card:hover .cta-card__shot img { transform: none; }
}
.cta-card__body {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  margin-top: var(--s-4);
}
.cta-card__title {
  font-family: var(--sans);
  font-weight: 640;
  font-stretch: 110%;
  font-size: clamp(1.2rem, 2vw, 1.55rem);
  letter-spacing: -0.022em;
  transition: color var(--dur-1) linear;
  /* The subtitle sits on its own line under the title, not beside it. */
  display: block;
}
.cta-card__sub { display: block; margin-top: 0.35rem; }
.cta-card:hover .cta-card__title { color: var(--flare); }
.t-invert .cta-card:hover .cta-card__title { color: var(--flare-text); }
/* The image is the only thing that moves on hover. An arrow that slides as
   well makes the card feel busy, and the movement says nothing the zoom and
   the colour change have not already said. */

/* 33 · LOGO SPECIMENS (style guide only) ================================== */

.logos { display: grid; gap: var(--s-5); grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.logo-tile {
  display: grid;
  place-items: center;
  padding: var(--s-6) var(--s-5);
  min-height: 132px;
  border: 1px solid var(--rule);
}
.t-invert .logo-tile { border-color: var(--rule-inv); }
/* Each tile carries its own background, because the whole point is to show
   which version survives on which surface. */
.logo-tile--dark { background: var(--ink-900); }
.logo-tile--light { background: var(--paper); }
.logo-tile img { width: 100%; height: auto; display: block; }
.logo-tile--mark img { width: 68px; }
.logo-tile__cap { margin-top: var(--s-3); }

/* Download pair. SVG leads because it is the format to reach for; the PNG is
   the fallback, so it is drawn as the quieter of the two. */
.logo-dl { display: flex; gap: 0.5rem; margin-top: var(--s-4); }
.logo-dl__link {
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--t-1);
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--flare);
  transition: background-color var(--dur-1) linear, color var(--dur-1) linear;
}
.logo-dl__link:hover, .logo-dl__link:focus-visible { background: var(--flare); color: #fff; }
.logo-dl__link--alt { border-color: var(--rule); color: var(--t-2); }
.logo-dl__link--alt:hover, .logo-dl__link--alt:focus-visible {
  background: none;
  border-color: var(--flare);
  color: var(--t-1);
}
.t-invert .logo-dl__link { color: var(--t-1-inv); border-color: var(--flare-ink); }
.t-invert .logo-dl__link:hover, .t-invert .logo-dl__link:focus-visible {
  background: var(--flare-ink); color: #fff;
}
.t-invert .logo-dl__link--alt { border-color: var(--rule-inv); color: var(--t-2-inv); }
.t-invert .logo-dl__link--alt:hover, .t-invert .logo-dl__link--alt:focus-visible {
  background: none; border-color: var(--flare-ink); color: var(--t-1-inv);
}

/* Clear space: the mark's own orange square, repeated as a margin on all four
   sides. The square is 300 units wide in the lockup's 5087-unit viewBox, so the
   margin is 5.9% of whatever width the lockup is drawn at - which keeps the
   diagram honest at every screen size instead of only at one. */
.logo-clear {
  --logo-w: clamp(180px, 40vw, 440px);
  --logo-pad: calc(var(--logo-w) * 0.059);
  display: grid;
  place-items: center;
  padding: clamp(1.75rem, 5vw, 3.5rem);
  border: 1px solid var(--rule);
  background: var(--ink-900);
}
.t-invert .logo-clear { border-color: var(--rule-inv); }
.logo-clear__box {
  display: block;
  width: calc(var(--logo-w) + var(--logo-pad) * 2);
  padding: var(--logo-pad);
  border: 1px dashed var(--flare);
}
.logo-clear__box img { width: 100%; height: auto; display: block; }

/* 34 · MEGA MENU ALIGNMENT ================================================ */

/* The five descriptions should sit tight under their titles AND line up with
   each other. Those two goals conflict as soon as one title wraps, which
   "Web development" does at narrow desktop widths.

   Reserving a blank second line under every title solves the alignment but
   pushes all five descriptions down, which is the thing we are trying to
   avoid. Subgrid solves both: each link borrows the list's rows, so every
   icon, title and description shares a row with its neighbours and the
   spacing stays tight. */
@supports (grid-template-rows: subgrid) {
  .mega__list { grid-template-rows: auto auto auto; }
  .mega__link {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 3;
    row-gap: 0;
  }
  /* The flex gap is gone with display:grid, so the icon carries its own space. */
  .mega__icon { margin-bottom: 0.9rem; }
}

/* Older engines keep the previous behaviour: reserve the second line so the
   row still reads straight, at the cost of a little extra space. */
@supports not (grid-template-rows: subgrid) {
  .mega__title { min-height: 2.5em; }
}

/* 35 · THREE-FIGURE RECORD ================================================ */

/* The homepage result block carries three figures, not four. Without this the
   fourth column sits empty and the row reads as a missing statistic. */
@media (min-width: 860px) {
  .record--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* 36 · BARE LINK ========================================================== */

/* .link draws a permanent 1px rule under itself. On the contact panel the
   email address and telephone number are the only two items in the block, so
   the underline added nothing and read as clutter. The colour change on hover
   still marks them as links. */
.link--bare { background-size: 0 1px; padding-bottom: 0; }
.link--bare:hover, .link--bare:focus-visible { background-size: 100% 1px; }

/* 37 · BROWSER MOCKUP ===================================================== */

/* A macOS browser window, drawn in CSS. It scales to any card width, costs no
   extra request, and never needs re-exporting when a screenshot is replaced.

   THE RADIUS. Everything the site builds is square - see the style guide. This
   is the exception, alongside the comparison handle, and for the same kind of
   reason: the frame is a picture of somebody else's interface, not a piece of
   ours. macOS traffic lights are circles and its address bar is a rounded
   pill; drawn square they stop reading as a Mac and start reading as a mistake.
   Our own card keeps its square corners - only the window inside is rounded. */
.browser__chrome {
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 1.4vw, 0.9rem);
  padding: clamp(0.5rem, 1.1vw, 0.7rem) clamp(0.6rem, 1.3vw, 0.85rem);
  background: #2f3033;
  border-bottom: 1px solid rgba(255, 255, 255, 0.09);
}
.t-invert .browser__chrome { background: #dedfe1; border-bottom-color: rgba(0, 0, 0, 0.12); }

/* --- Traffic lights ------------------------------------------------------ */

.browser__lights { display: flex; gap: clamp(4px, 0.5vw, 6px); flex: none; }
.browser__lights span {
  width: clamp(8px, 0.95vw, 11px);
  aspect-ratio: 1;
  border-radius: 50%;
}
.browser__lights span:nth-child(1) { background: #ff5f57; }
.browser__lights span:nth-child(2) { background: #febc2e; }
.browser__lights span:nth-child(3) { background: #28c840; }

/* --- Address bar --------------------------------------------------------- */

/* Centred and narrow, the way Safari draws it. Deliberately empty: writing a
   URL here would mean inventing one per client, and a wrong domain on a case
   study is worse than no domain. */
.browser__omni {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  flex: 0 1 clamp(120px, 44%, 320px);
  margin-inline: auto;
  height: clamp(14px, 1.7vw, 20px);
  border-radius: clamp(3px, 0.4vw, 5px);
  background: rgba(255, 255, 255, 0.1);
}
.t-invert .browser__omni { background: rgba(0, 0, 0, 0.07); }

/* The padlock: a body with a shackle above it, six pixels tall in total. */
.browser__lock {
  position: relative;
  width: clamp(5px, 0.55vw, 7px);
  height: clamp(4px, 0.45vw, 6px);
  background: rgba(255, 255, 255, 0.42);
  border-radius: 1px;
}
.t-invert .browser__lock { background: rgba(0, 0, 0, 0.38); }
.browser__lock::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: 60%;
  height: 45%;
  transform: translateX(-50%);
  border: 1px solid currentColor;
  border-bottom: 0;
  border-radius: 40% 40% 0 0;
  color: rgba(255, 255, 255, 0.42);
}
.t-invert .browser__lock::before { color: rgba(0, 0, 0, 0.38); }

/* 38 · RESULTS CHART ====================================================== */

/* Only the plot is SVG. Every label is HTML sitting outside or over it,
   because text inside a scaled SVG scales with it: an axis sized to look right
   on a desktop becomes specks on a phone. As HTML the labels take their size
   from the meta scale in section 3 and stay legible, and on-brand, at any
   width. Regenerate the markup with build/chart.py. */

.plot {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(0.5rem, 1.4vw, 0.9rem);
  row-gap: 0.5rem;
}

/* --- Axes --------------------------------------------------------------- */

/* The four values are evenly spaced, so the column can distribute them rather
   than position each one. Pulling it half a line taller at each end centres
   the first and last labels on the gridlines they belong to. */
/* Placed explicitly. Left to flow, the x-axis row dropped into the narrow
   first column beside the y labels, and every month label resolved its left
   percentage against that column's width instead of the plot's. */
.plot__y { grid-column: 1; grid-row: 1; }
.plot__area { grid-column: 2; grid-row: 1; }
.plot__x { grid-column: 2; grid-row: 2; }

.plot__y {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  text-align: right;
  margin-block: -0.7em;
  font-variant-numeric: tabular-nums;
}
.plot__y span,
.plot__month {
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--t-3);
  line-height: 1.4;
  white-space: nowrap;
}
.t-invert .plot__y span,
.t-invert .plot__month { color: var(--t-3-inv); }

.plot__x { position: relative; height: 1.6em; }
.plot__month {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
}
/* Every horizontal position is generated into the block at the end of this
   file by build/chart.py, including the two outermost, which are pinned to the
   ends rather than centred so they cannot hang off the plot. They cannot be
   inline styles: the site's Content-Security-Policy is `style-src 'self'`
   with no 'unsafe-inline', so the browser discards style attributes outright
   and every label would collapse onto the left edge. */


/* On a phone the month axis is dropped altogether. Four names is the most that
   fits without collisions below 700px - measured: with the meta tracking left
   intact they clear each other by 20px at 430, 8px at 390, 2px at 375 and
   overlap outright by 360 - and four widely spaced months earn less than the
   height they cost. The chart head still names the measure and the marker
   still names the turning point, which is what the chart is there to show.

   The markup keeps the labels rather than the generator dropping them, so
   raising this breakpoint is a one-line change if you want them back. */
@media (max-width: 700px) {
  .plot__x { display: none; }
}

/* --- Plot --------------------------------------------------------------- */

/* preserveAspectRatio="none" lets the plot take whatever height the layout
   gives it, so it can stand taller on a phone where a wide, shallow band would
   flatten the very rise the chart exists to show. Nothing inside it is
   distorted by that: the strokes are non-scaling and every label is HTML. */
.plot__area { position: relative; aspect-ratio: 1000 / 420; }
@media (max-width: 700px) { .plot__area { aspect-ratio: 1000 / 720; } }

.chartline { display: block; width: 100%; height: 100%; }
.chartline__grid {
  stroke: var(--t-1);
  stroke-opacity: 0.09;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.t-invert .chartline__grid { stroke: var(--t-1-inv); }
.chartline__mark {
  stroke: var(--flare);
  stroke-width: 1;
  stroke-dasharray: 4 5;
  vector-effect: non-scaling-stroke;
}
.chartline__area { fill: var(--flare); opacity: 0.1; }
.chartline__path {
  fill: none;
  stroke: var(--flare);
  stroke-width: 2.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* The reveal sweeps a clip rectangle across the plot rather than animating a
   dashed stroke. A dash cannot work here: the line needs
   vector-effect: non-scaling-stroke, because preserveAspectRatio="none"
   stretches the plot and would otherwise stretch the pen with it - but
   non-scaling-stroke measures dashes in screen space while pathLength
   normalises user space. The two disagreed, so the line began part-way along
   and stopped short of the end. The wipe is immune: it is a plain scaleX. */
.chartline__wipe {
  fill: #fff;                      /* colour is irrelevant inside a clipPath */
  transform-origin: 0 0;
}

/* The marker label is white, not orange: ::selection paints an orange
   background and orange text on it disappeared. The dashed rule stays orange,
   so the marker keeps its accent. */
.plot__marker {
  position: absolute;
  top: 0.35em;
  margin-left: 0.6em;
  white-space: nowrap;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--t-1);
  white-space: nowrap;
}
.t-invert .plot__marker { color: var(--t-1-inv); }

/* Flipped to the left of the rebuild line on a phone. To its right the label
   ran past the edge of the plot at the narrowest widths; to its left there is
   room, because the line sits just under halfway across. */
@media (max-width: 700px) {
  .plot__marker { margin-left: -0.6em; transform: translateX(-100%); }
}
/* Below about 390px even the left side is too narrow for the label, so it is
   pinned to the edge of the plot instead. The top left corner is empty there -
   traffic is at its lowest before the rebuild - so it sits in clear space. */
@media (max-width: 399px) {
  /* Specificity has to beat the generated `.plot__marker { left: ... }` at the
     end of this file - a media query adds none, and that block comes later. */
  .plot .plot__marker { left: 0; margin-left: 0; transform: none; }
}

/* The end point is HTML too, so it stays a circle however the plot stretches. */
.plot__dot {
  position: absolute;
  width: 11px;
  height: 11px;
  margin: 0 0 -5.5px -5.5px;
  background: var(--flare);
  border-radius: 50%;
}
.plot__dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--flare);
}

/* --- Reveal ------------------------------------------------------------- */

/* The resting state is scoped to .js, so with scripting off the chart is
   simply drawn complete rather than stuck mid-animation. */
.js [data-rise].plot .chartline__wipe { transform: scaleX(0); }
.js [data-rise].plot .chartline__mark { transform: scaleY(0); transform-origin: 50% 0; }
.js [data-rise].plot .plot__marker { opacity: 0; }
.js [data-rise].plot .plot__dot { opacity: 0; }

.js [data-rise].plot.is-in .chartline__wipe {
  transform: scaleX(1);
  transition: transform 2.4s cubic-bezier(0.37, 0, 0.32, 1) 0.25s;
}
.js [data-rise].plot.is-in .chartline__mark {
  transform: scaleY(1);
  transition: transform 0.6s var(--ease) 0.5s;
}
.js [data-rise].plot.is-in .plot__marker {
  opacity: 1;
  transition: opacity 0.5s linear 0.9s;
}
.js [data-rise].plot.is-in .plot__dot {
  opacity: 1;
  transition: opacity 0.45s linear 2.35s;
}

/* A slow halo once the line has arrived, so the last reading reads as current
   rather than as a full stop. */
@keyframes chart-pulse {
  0%   { transform: scale(1);   opacity: 0.55; }
  70%  { transform: scale(2.6); opacity: 0; }
  100% { transform: scale(2.6); opacity: 0; }
}
.js [data-rise].plot.is-in .plot__dot::after {
  animation: chart-pulse 2.8s ease-out 2.9s infinite;
}

@media (prefers-reduced-motion: reduce) {
  .js [data-rise].plot .chartline__wipe { transform: none; }
  .js [data-rise].plot .chartline__mark { transform: none; }
  .js [data-rise].plot .plot__marker,
  .js [data-rise].plot .plot__dot { opacity: 1; }
  .js [data-rise].plot.is-in .chartline__wipe,
  .js [data-rise].plot.is-in .chartline__mark,
  .js [data-rise].plot.is-in .plot__marker,
  .js [data-rise].plot.is-in .plot__dot { transition: none; }
  .js [data-rise].plot.is-in .plot__dot::after { animation: none; opacity: 0; }
}

/* 39 · THREE-FIGURE RECORD ON NARROW SCREENS ============================== */

/* Two columns is right for three figures on a phone, but it leaves the third
   alone in a half-width cell next to a gap. Letting it run the full width
   makes the row read as finished rather than cut short.

   This block was lost once when the chart section above it was rewritten by
   truncating the file; keep new sections above the generated block below, not
   appended after it. */
@media (max-width: 859px) {
  .record--three .record__cell:last-child { grid-column: 1 / -1; }
}
/* One figure per row on a phone. Two-up leaves labels like "Student enrolments
   since we took over" running to four cramped lines beside a much shorter
   neighbour, which reads as a layout accident rather than a set. */
@media (max-width: 700px) {
  .record--three { grid-template-columns: minmax(0, 1fr); }
}

/* 40 · GENERATED CHART POSITIONS ========================================== */

/* Written by build/chart.py. Do not edit by hand - rerun the script instead.
   Nothing should be appended below this block. */

/* chart:positions:start */
/* Generated by build/chart.py. Do not edit. */
.plot__x .plot__month:nth-child(1) { left: 0; transform: none; }
.plot__x .plot__month:nth-child(2) { left: 15.7895%; }
.plot__x .plot__month:nth-child(3) { left: 31.5789%; }
.plot__x .plot__month:nth-child(4) { left: 47.3684%; }
.plot__x .plot__month:nth-child(5) { left: 63.1579%; }
.plot__x .plot__month:nth-child(6) { left: 78.9474%; }
.plot__x .plot__month:nth-child(7) { left: auto; right: 0; transform: none; }
.plot__marker { left: 47.3684%; }
.plot__dot { left: 100%; bottom: 100%; }
/* chart:positions:end */

/* 41 · CASE STUDIES ON NARROW SCREENS ===================================== */

/* Below 940px the case grid stacks, and stacking in source order puts the
   whole write-up between the heading and the screenshot. The screenshot is the
   evidence, so it belongs directly under the name.
   `display: contents` on the body lets its children take their own place in
   the stack, which is the only way to slot the figure into the middle of them
   without duplicating markup. The body carries no box of its own - no
   background, border or padding - so dissolving it costs nothing. */
@media (max-width: 939px) {
  /* align-items: center is inherited from the two-column layout, where it
     centres the columns vertically. In a column flexbox it means the cross
     axis instead, so every child shrank to its content width and sat centred -
     which is why the stats blocks started at six different left edges down the
     page rather than on the page margin. */
  .case__grid { display: flex; flex-direction: column; align-items: stretch; }
  .case__body { display: contents; }
  .case__body > h2 { order: 1; }
  .case__body > .chips { order: 2; }
  .case__media { order: 3; }
  .case__body > .prose { order: 4; }
  .case__body > .stats { order: 5; }
  .case__body > .vid { order: 6; }

  /* Spacing is set here rather than left to the grid gap plus each element's
     own margin. Those compounded: the gap is 32px at this width, the label
     adds 32px below itself and the prose and stats carry u-mt-5 and u-mt-6, so
     the steps came out at 80, 64, 56, 64 and 64px - on a 390px screen that is
     most of a viewport of air inside one case study. The gap is zeroed and
     each step set once, so the sequence reads as one block. */
  .case__grid { row-gap: 0; }
  .case__body > h2 { margin-top: 0; }
  .case__body > .chips { margin-top: var(--s-4); }
  .case__media,
  .case__body > .prose,
  .case__body > .stats,
  .case__body > .vid { margin-top: var(--s-5); }
}

/* Below 620px each stat is a two-column row, figure beside label. Centring
   them on each other keeps the row reading as a pair: baseline alignment sat
   a one-line label level with the foot of a figure twice its size, and left a
   two-line label looking like it had slipped. */
@media (max-width: 619px) {
  .stat {
    grid-template-columns: clamp(7rem, 14vw, 10.5rem) minmax(0, 1fr);
    align-items: center;
  }
  /* The figure keeps a 0.5rem bottom margin from the stacked layout, which
     centring counts as part of its box and so lifted it 4px above its label. */
  .stat__fig { margin-bottom: 0; }
}



/* 42 · BREADCRUMBS ======================================================== */

/* A quiet strip above the footer. It is here for orientation and for the
   BreadcrumbList that mirrors it - Google wants the markup to reflect
   something the page actually shows, and a crumb trail at the top would
   compete with the page heading for the first thing you read.

   The home page has none: a trail reading only "Home" tells nobody anything,
   and the noindex pages have none because nothing should be indexing them. */
.crumbs {
  border-top: 1px solid var(--rule);
  padding-block: var(--s-5);
  background: var(--ink-900);
}
.crumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.7rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.crumbs__item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--t-3);
}
/* The separator is generated, so it is never read out as content.

   It also has to be nudged left, because two things pushed it right of centre
   and made the gap before it look wider than the one after:

   1. letter-spacing puts a trailing space after the final letter of "HOME",
      adding 0.16em to the gap in front of the chevron and nothing behind it;
   2. a square with only its top and right borders, rotated 45deg, draws no ink
      in the left half of its own box - the mark spans from the box's centre to
      0.207 of a side past its right edge.

   So the ink sits noticeably further right than the box suggests. The
   geometry puts the correction at about 0.24em; measured against the rendered
   pixels it balances at 0.173em, because the visible edge of a hairline border
   falls inside its geometric one once antialiased. Verified by scanning the
   rendered strip: 13.0px before the chevron against 12.5px after, which is
   half a pixel and below the threshold of noticing. Both terms are in em, so
   this holds if the size or the type scale changes. */
.crumbs__item + .crumbs__item::before {
  content: "";
  width: 0.45em;
  height: 0.45em;
  flex: none;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.55;
  margin-left: -0.173em;
  margin-right: 0.173em;
}
.crumbs__item a {
  color: var(--t-2);
  text-decoration: none;
  transition: color var(--dur-1) linear;
}
.crumbs__item a:hover, .crumbs__item a:focus-visible { color: var(--flare); }
.crumbs__item[aria-current="page"] { color: var(--t-1); }

/* 43 · CHIPS ============================================================== */

/* Short facts about a piece of work - sector, place - set as a row of small
   bordered tags under its heading. They replace the uppercase eyebrow that
   used to sit above the heading: sentence case, no orange, no tracking, so
   they read as information rather than decoration. Square like everything
   else; the only radii on the site are the seam handle and the browser
   mockup. Keep each chip to a word or two. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: var(--s-4) 0 0;
  padding: 0;
  list-style: none;
}
.chip {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--rule);
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: 450;
  line-height: 1.3;
  color: var(--t-2);
}
.t-invert .chip { border-color: var(--rule-inv); color: var(--t-2-inv); }

/* The publish date on a blog post, now that the strip above the title has
   gone. Muted, under the headline, before the standfirst. */
.post-date { color: var(--t-2); }
.t-invert .post-date { color: var(--t-2-inv); }
