/* ==========================================================================
   TAIB Advisory — design system
   Tokens first, then primitives. No build step; edit this file directly.
   ========================================================================== */

:root {
  /* — Type families ----------------------------------------------------- */
  --display: "Schibsted Grotesk", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --sans:    "Hanken Grotesk", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* — Surfaces ---------------------------------------------------------- */
  --bg:        #ffffff;
  --bg-alt:    #f7f5f4;   /* warm stone — alternating bands */
  --bg-deep:   #150f0e;   /* deep panel */
  --ivory:     #f2efed;   /* text on deep panel */

  /* — Ink --------------------------------------------------------------- */
  --ink:       #1a1413;   /* warm near-black, body + display */
  --ink-soft:  #48423f;   /* secondary copy */
  --muted:     #6b6461;   /* captions, meta */

  /* — Accent — Chili Red ------------------------------------------------ */
  --accent:    #cd1c18;   /* fills, rules, numerals; 5.56:1 on white   (AA) */
  --accent-2:  #ff6f6b;   /* text on deep panel;     6.99:1 on deep    (AA) */
  --glow:      rgba(205, 28, 24, .20);
  /* Solid fills must NOT follow the dark-band inversion: white text on
     --accent-2 is only 2.71:1, while on the base red it is 5.56:1. This
     token is deliberately never redefined in .band--deep. */
  --fill-accent: #cd1c18;

  /* — Rules ------------------------------------------------------------- */
  --rule:      rgba(26, 20, 19, .12);
  --rule-soft: rgba(26, 20, 19, .055);
  --rule-inv:  rgba(255, 255, 255, .14);

  /* — Interaction ------------------------------------------------------- */
  --cell-bg:    var(--bg);
  --hover-mix:  5%;   /* NB: never precompute the mix into a token here — a custom
                         property resolves its var()s where it is DECLARED, so a
                         band redefining --cell-bg would not re-evaluate it. The
                         mix happens at point of use, in .cell:hover. */
  --ease:       cubic-bezier(.22, 1, .36, 1);
  --dur:        .45s;

  /* — Type scale (fluid) ------------------------------------------------ */
  --fs-display: clamp(2.75rem, 1.2rem + 6.4vw, 6rem);
  --fs-h2:      clamp(2rem, 1.1rem + 3.6vw, 3.5rem);
  --fs-h3:      clamp(1.125rem, 1rem + .5vw, 1.4375rem);
  --fs-title-md: clamp(1.5rem, 1rem + 1.6vw, 2.125rem);   /* 24 -> 34px */
  --fs-quote:   clamp(1.375rem, .9rem + .95vw, 1.875rem);  /* 22 -> 30px */
  --fs-lead:    clamp(1.0625rem, 1rem + .4vw, 1.25rem);
  --fs-body:    1rem;
  --fs-small:   .875rem;
  --fs-mono:    .75rem;     /* 12px. The reference sets its mono eyebrows at 11px
                               but carries most other small text in 14-17px sans;
                               this site leans on mono far more heavily, so its
                               floor sits one step up. */

  /* — Space scale ------------------------------------------------------- */
  --space-1: .5rem;  --space-2: 1rem;   --space-3: 1.5rem;
  --space-4: 2rem;   --space-5: 3rem;   --space-6: 4rem;
  --space-7: 6rem;   --space-8: 9rem;

  --gutter: 1.375rem;   /* 22px */
}

@media (min-width: 64em)  { :root { --gutter: 4rem } }   /* 64px */

/* ==========================================================================
   Base
   ========================================================================== */

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

html { -webkit-text-size-adjust: 100% }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block }

a { color: inherit; text-decoration: none }

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--bg);
  padding: var(--space-2) var(--space-3);
  font-family: var(--mono); font-size: var(--fs-mono); letter-spacing: .12em;
}
.skip:focus { left: 0 }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ==========================================================================
   Layout — shell and bands
   ========================================================================== */

/* Full-bleed with fixed gutters: content sits --gutter from the viewport edge
   at every width, rather than a centred column whose margins grow with the
   screen. Line length is held by per-element ch caps instead. */
.shell {
  width: 100%;
  padding-inline: var(--gutter);
}

.band { padding-block: var(--space-7) }

@media (min-width: 64em) { .band { padding-block: var(--space-8) } }

.band--alt {
  background: var(--bg-alt);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  --cell-bg: var(--bg-alt);
}

.band--deep {
  background: var(--bg-deep);
  color: var(--ivory);
  --cell-bg: var(--bg-deep);
  --rule: var(--rule-inv);
  --ink: var(--ivory);
  --ink-soft: rgba(242, 239, 237, .72);
  --muted: rgba(242, 239, 237, .55);
  --accent: var(--accent-2);
  --hover-mix: 10%;   /* dark surfaces need more delta to read the same lift */
  --glow: rgba(255, 111, 107, .28);
}

/* Asymmetric section head — mono eyebrow left, display heading right */
.sec {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

@media (min-width: 56em) {
  /* 11rem holds "COMMERCIAL ADVISORY" (the longest single word-pair in any
     eyebrow) on one line at --fs-mono with .16em tracking, so the hero eyebrow
     wraps to exactly two lines, breaking after the ampersand. */
  .sec { grid-template-columns: 11rem 1fr; gap: 4rem }
}

/* ==========================================================================
   Type
   ========================================================================== */

.eyebrow {
  font-family: var(--mono);
  font-size: var(--fs-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
  line-height: 1.6;
}

.eyebrow--accent { color: var(--accent) }

/* Optical top alignment for labels sitting in the margin column.
   Text does not start at the top of its box: the cap sits roughly
   (line-height / 2 - 0.346 x font-size) below it, so a 96px heading pushes its
   cap ~16px down while the fixed 11px mono eyebrow only drops 4.8px. Aligning
   the boxes therefore leaves the eyebrow visibly high. Nudging it by the
   difference puts the two cap-heights on one line. The coefficient is
   (line-height / 2 - 0.346) for Schibsted Grotesk, per heading class. */
@media (min-width: 56em) {
  .sec > .eyebrow                     { padding-top: max(0px, calc(0.179 * var(--fs-h2) - 0.436 * var(--fs-mono))) }
  .sec:has(.display) > .eyebrow       { padding-top: max(0px, calc(0.164 * var(--fs-display) - 0.436 * var(--fs-mono))) }
  /* The founder's note now leads with the picture, so there is no cap height to
     match -- the eyebrow aligns to the image's top edge instead. */
  .sec:has(.fnote) > .eyebrow         { padding-top: 0 }
}

.display {
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--fs-display);
  line-height: 1.02;
  letter-spacing: -.035em;
  margin: 0;
  text-wrap: balance;
}

.h2 {
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.05;
  letter-spacing: -.03em;
  margin: 0;
  text-wrap: balance;
}

.h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.2;
  letter-spacing: -.015em;
  margin: 0;
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: 46ch;
  margin: 0;
}

.body { color: var(--ink-soft); max-width: 68ch; margin: 0 }

/* A lead run at the body measure. Used where a section argues at length and a
   46ch column would stretch it down the page; scoped so every other lead on
   the site keeps the tighter measure. */
.lead--wide { max-width: 68ch }

/* A lead whose clauses each take their own line. The ch cap is dropped so a
   clause is never split, and the spans only go block where there is room for
   the longest one — below 40em they stay inline and wrap naturally. */
.lead--lines { max-width: none }
@media (min-width: 40em) { .lead--lines > span { display: block } }

/* A headline whose breaks are editorial rather than incidental: each span is a
   line above the breakpoint and stays inline below it, so the headline falls
   back to wrapping on its own instead of stranding a word on a narrow screen.
   80em is where the longest forced line still fits the content column -- "and
   why it matters." measures 813px at the 96px display size against a 912px
   column there. Below that the headline wraps as it did before. A headline with
   a longer line than that needs a higher breakpoint, so measure before reusing
   this on one. */
@media (min-width: 80em) { .display--lines > span { display: block } }

.small { font-size: var(--fs-small); color: var(--muted); margin: 0 }

.accent { color: var(--accent) }

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

/* ==========================================================================
   Cells — hairline grid with accent hover
   The 1px gap over a rule-coloured container draws every divider, at any
   column count, with no nth-child bookkeeping.
   ========================================================================== */

.cells {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--rule);
  border-top: 1px solid var(--rule);
}

@media (min-width: 40em) { .cells { grid-template-columns: repeat(2, 1fr) } }
@media (min-width: 64em) { .cells--3 { grid-template-columns: repeat(3, 1fr) } }
@media (min-width: 64em) { .cells--4 { grid-template-columns: repeat(4, 1fr) } }
/* 3 items must skip the 2-column band entirely — 3 is not divisible by 2, so
   the tablet range would leave one slot showing the container rule. */
@media (min-width: 40em) { .cells--trio { grid-template-columns: 1fr } }
@media (min-width: 64em) { .cells--trio { grid-template-columns: repeat(3, 1fr) } }

/* The column count must divide the item count. The 1px gaps expose the
   container's --rule background, so any slot the content does not fill paints
   as a visible block — most obvious on --deep, where --rule is a light inverse.
   6 items -> --3, 4 items -> --4 or the 2-col default, 3 items -> --3. */

.cell {
  position: relative;
  background: var(--cell-bg);
  padding: var(--space-3) var(--space-3) var(--space-5);
  transition: background var(--dur) var(--ease);
}

.cell::before {
  content: "";
  position: absolute; inset-block-start: 0; inset-inline: 0;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .5s var(--ease);
}

.cell:hover, .cell:focus-within {
  background: color-mix(in srgb, var(--accent) var(--hover-mix), var(--cell-bg));
}
.cell:hover::before, .cell:focus-within::before { transform: scaleX(1) }

/* ==========================================================================
   Browsable blocks — the Why TAIB hover, reused
   Every block a reader scans and can open behaves the same way: the accent
   rule wipes in along its top edge and a 5% wash lifts its background. The
   cells already had it; the sector rows, the featured note and the field-note
   cards now share it, so the affordance means one thing across the site.
   ========================================================================== */

.srow, .feat, .icard { position: relative }

.srow::before,
.feat::before,
.icard::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .5s var(--ease);
  z-index: 1;
}
/* The rows and the featured note carry their own 1px rule, so the accent sits
   on top of it rather than below. */
.srow::before, .feat::before { inset-block-start: -1px }

.srow:hover::before, .srow:focus-within::before,
.feat:hover::before, .feat:focus-within::before,
.icard:hover::before, .icard:focus-within::before { transform: scaleX(1) }

.srow, .feat { transition: background var(--dur) var(--ease) }
.srow:hover, .srow:focus-within,
.feat:hover, .feat:focus-within {
  background: color-mix(in srgb, var(--accent) var(--hover-mix), var(--cell-bg));
}

/* The cards sit in a gapped grid with no padding of their own, so the wash is
   carried by a spread box-shadow rather than by padding: it bleeds 20px into
   the gap without moving anything, and unlike a negative z-index layer it
   paints above the band's own background. The rule sits at the top of that
   bleed, where the wash starts. */
.icard {
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.icard::before { inset-block-start: -1.25rem }
.icard:hover, .icard:focus-within {
  background: color-mix(in srgb, var(--accent) var(--hover-mix), var(--cell-bg));
  box-shadow: 0 0 0 1.25rem color-mix(in srgb, var(--accent) var(--hover-mix), var(--cell-bg));
}

.cell__n {
  font-family: var(--mono);
  font-size: var(--fs-mono);
  letter-spacing: .14em;
  color: var(--accent);
  display: block;
  margin-bottom: var(--space-2);
}

.cell__body { margin: var(--space-1) 0 0; color: var(--ink-soft); font-size: 1.0625rem; max-width: 46ch }

/* Roomier cells: in a 2x2 grid each cell is wide enough that the default 23px
   heading reads as lost. Steps up to the mandate rows' 34px title and their
   17px body, via the shared token so the two stay in step. */
.cells--lg .h3 {
  font-size: var(--fs-title-md);
  line-height: 1.12;
  letter-spacing: -.029em;
}
.cells--lg .cell__body {
  font-size: 1.125rem;
  line-height: 1.6;
  margin-top: var(--space-2);
  max-width: 42ch;
}
.cells--lg .cell { padding-block: var(--space-4) var(--space-5) }

/* ==========================================================================
   Links and buttons
   ========================================================================== */

.linkline {
  display: inline-flex;
  align-items: center;
  gap: .625rem;
  position: relative;
  font-family: var(--mono);
  font-size: .8125rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
  padding-block: .625rem;
}

.linkline::before {
  content: "";
  position: absolute; inset-block-end: 0; inset-inline: 0;
  height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--dur) var(--ease);
}

.linkline:hover::before, .linkline:focus-visible::before { transform: scaleX(1) }
.linkline .ar { transition: transform var(--dur) var(--ease) }
.linkline:hover .ar { transform: translateX(5px) }

.btn {
  display: inline-flex;
  align-items: center;
  gap: .625rem;
  font-family: var(--mono);
  font-size: .8125rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding: 1.0625rem 1.75rem;
  border: 1px solid var(--ink);
  min-height: 44px;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}

.btn--solid {
  background: var(--fill-accent);
  border-color: var(--fill-accent);
  color: #fff;
}
.btn--solid:hover { box-shadow: 0 12px 30px -10px var(--glow) }

.btn--ghost { background: transparent; color: var(--ink) }
.btn--ghost:hover { background: var(--ink); color: var(--bg) }

/* Text-only CTA, as the reference uses in its hero and header: no fill, caps,
   sitting on a rule. On hover it takes the same treatment as the tile grids —
   the 5% accent wash plus a hairline wiping in from the left. */
.btn--line {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--ink);
  color: var(--ink);
  padding: 1.125rem 0;
  position: relative;
  overflow: hidden;
  justify-content: space-between;
}
.btn--line::before {
  content: "";
  position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .45s var(--ease);
}
.btn--line:hover { background: color-mix(in srgb, var(--accent) 5%, var(--bg)) }
.btn--line:hover::before { transform: scaleX(1) }

/* Secondary: lighter rule and muted text until hover, as the reference does. */
.btn--line-soft { border-bottom-color: var(--rule); color: var(--ink-soft) }
.btn--line-soft:hover { color: var(--ink) }

/* On a deep band the fill takes the lighter red, so the button matches the
   accent text beside it. White on that fill is only 2.71:1, so the label flips
   to the band's own near-black instead — 6.99:1, comfortably AA. */
.band--deep .btn--solid {
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: var(--bg-deep);
}

/* Stacked in the hero, both the same width so the two rules line up, and
   capped so they do not run to the page edge. Full width in the mobile panel. */
.hero__sub .hero__actions { flex-direction: column; gap: .75rem; align-items: start }
.hero__sub .hero__actions .btn { width: min(20rem, 100%) }
.nav__panel .btn--line { width: 100% }

.btn .ar { transition: transform var(--dur) var(--ease) }
.btn:hover .ar { transform: translateX(5px) }

/* ==========================================================================
   Specs — term left, description right, hairline between
   ========================================================================== */

.specs { border-top: 1px solid var(--rule) }

.spec {
  display: grid;
  grid-template-columns: 1fr;
  gap: .25rem var(--space-4);
  padding-block: var(--space-3);
  border-bottom: 1px solid var(--rule);
}

/* Fallback width for browsers without subgrid. */
@media (min-width: 40em) {
  .spec { grid-template-columns: minmax(0, 18rem) minmax(0, 1fr); align-items: baseline }
}

/* The term column sizes itself to the longest term in the list rather than to
   a guessed width. A fixed 12rem was 50px short of "info@taib-advisory.com"
   (242px at the old 22px) and 86px short of "GCC · India · Africa · Europe",
   so both broke mid-word. max-content on a subgrid cannot be outgrown. */
@supports (grid-template-columns: subgrid) {
  @media (min-width: 40em) {
    .specs { display: grid; grid-template-columns: max-content minmax(0, 1fr) }
    .spec { grid-template-columns: subgrid; grid-column: 1 / -1 }
  }
}

.spec__t {
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.1875rem;
  line-height: 1.3;
  letter-spacing: -.015em;
}

/* Was 15px against a 22px term — that gap read as a mismatch rather than a
   hierarchy. 17px against 19px reads as one pair. */
/* A standalone link in this list is a target in its own right, not one inline
   in a sentence, so the WCAG 2.5.8 inline exception does not apply to it: the
   19px line box alone measures 23.5px, just under the 24px minimum. */
.spec__t a { padding-block: .25rem }

.spec__d { color: var(--ink-soft); font-size: 1.0625rem; line-height: 1.55; max-width: 52ch }

/* ==========================================================================
   Stat
   ========================================================================== */

.stat__v {
  font-family: var(--display);
  font-weight: 600;
  /* 36 -> 52px. Capped at 52 because "industry" measures 4.0x the font size
     in this face, and the widest it may be is a quarter of the centred strip. */
  font-size: clamp(2.25rem, 4.2vw, 3.25rem);
  line-height: 1;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}

.stat__l {
  font-family: var(--mono);
  font-size: var(--fs-mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-top: .5rem;
}

/* Third tier under a figure: the one-line note the metric strip needs and a
   lone .stat does not. */
.stat__d {
  font-size: 1rem;
  line-height: 1.5;
  color: var(--ink-soft);
  margin: .625rem 0 0;
  max-width: 26ch;
}

/* METRIC STRIP — four figures across one hairline, following the deck's own
   art direction: wide, borderless, generous whitespace, left-aligned copy, no
   cards or icons. Two details are load-bearing:

   1. It breaks out of the content column. Like the reference, the hairline and
      the first figure start at the page gutter while the heading above stays
      indented. That buys back the 240px the eyebrow column reserves, which is
      what makes four readable columns possible at all -- inside the content
      column, "industry" (224px at the figure size) does not fit a quarter
      column until ~1700px wide.
   2. The hairline is a single top border, not a ruled grid container, so
      changing the number of figures can never paint an empty cell the way a
      gap-over-rule grid does.

   Rows are subgrid, so the labels and notes sit on shared baselines even
   though "Cross-industry" wraps to two lines while the numerals take one. */
.stats {
  border-top: 1px solid var(--rule);
  padding-top: var(--space-4);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
}

@media (min-width: 34em) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5) var(--space-4) }
}

/* Four across, and centred: the left edge is the content column like every
   headline on the site, and the right margin mirrors that same offset, so the
   figures sit as one centred band instead of running out to the page gutter.
   100em is the first width where that narrower strip still gives four columns
   room for the longest value -- "industry" is 4.0x the font size in this face,
   208px at the 52px cap, against a 224px column at 1600. */
/* Centred: the left edge is the content column, like every headline on the
   site, and the right margin mirrors that same offset, so the figures sit as
   one centred band instead of running out to the page gutter. Applied from
   64em, below which mirroring would leave the strip under 400px wide. */
@media (min-width: 64em) {
  .stats { margin-right: calc(11rem + 4rem) }
}

/* Four across from 100em. That is the first width at which the narrower,
   centred strip still gives four columns room for the longest value --
   "industry" is 4.0x the font size in this face, so 208px at the 52px cap,
   against a 224px column at 1600. */
@media (min-width: 90em) {
  /* Not four equal columns. The fourth value is a two-word phrase where the
     other three are short tokens -- "Cross-industry" needs 313px on one line at
     46px (353px at 52px) while "10+", "15+" and "P&L" need at most 83px. Equal
     columns give every cell 202px at 1512, so the phrase broke after the hyphen
     and sat on two lines while its neighbours sat on one. The last column takes
     exactly what the phrase needs and the other three share what is left, which
     is still more than double what they use. */
  .stats {
    grid-template-columns: repeat(3, minmax(0, 1fr)) max-content;
    gap: 0 var(--space-4);
  }
}

/* The cap drops to 46px between 1440 and 1600, and returns to 52px above it.

   It first went in to stop "industry" overflowing a 184px cell, which the
   content-sized fourth column has since made impossible. It stays for a second
   reason: the fourth column takes what the phrase needs (313px at 46px, 353px
   at 52px) and the other three share the rest, so the value size directly sets
   how wide they are. At 1512, 46px leaves them 165px and every description
   holds two lines; 52px leaves 152px and all four descriptions go to three,
   making the strip 30px taller. The smaller numerals are the better trade.

   Measure overflow here with a Range's client rects, not scrollWidth: a word
   longer than its box paints outside it without reporting any scroll overflow,
   so a scrollWidth check reports a broken layout as fine. */
@media (min-width: 90em) and (max-width: 99.99em) {
  .stat__v { font-size: clamp(2.25rem, 4.2vw, 2.875rem) }
}

/* Hover: an accent line above the figure, in every layout. The rule itself
   stays on the container, so the grey line is continuous across the gaps and
   only the hovered span of it changes colour.

   Where the line sits depends on whether the figure has that rule above it.
   In the four-column layout all four do, so the line reaches back up over the
   container's padding and lands on the rule. When the figures wrap, only the
   first row sits under the rule; the rows below it get their line centred in
   the space above them instead, which reads as the divider for that row
   rather than as a stray mark. */
.stats > .stat { position: relative }
.stats > .stat::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: calc(-1 * var(--space-4) - 1px);
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur) var(--ease);
}
.stats > .stat:hover::before { transform: scaleX(1) }

/* Two columns: figures 3 and 4 are a wrapped row. */
@media (max-width: 89.9375em) {
  .stats > .stat:nth-child(n+3)::before { top: calc(-1 * var(--space-5) / 2) }
}
/* One column: everything after the first figure is a wrapped row. */
@media (max-width: 33.9375em) {
  .stats > .stat:nth-child(n+2)::before { top: calc(-1 * var(--space-5) / 2) }
}

@supports (grid-template-rows: subgrid) {
  @media (min-width: 34em) {
    .stats { grid-template-rows: repeat(2, max-content max-content auto); row-gap: 0 }
    .stats > .stat { display: grid; grid-template-rows: subgrid; grid-row: span 3 }
    .stats > .stat > .stat__v { align-self: end }
    /* row-gap is 0 so the subgrid tracks stay tight; the break between the two
       rows of figures rides on the first row's notes instead. */
    .stats > .stat:nth-child(-n+2) .stat__d { margin-bottom: var(--space-5) }
  }
  @media (min-width: 90em) {
    .stats { grid-template-rows: max-content max-content auto }
    .stats > .stat:nth-child(-n+2) .stat__d { margin-bottom: 0 }
  }
}

/* ==========================================================================
   Founder's note — the picture on top, centred, with the quote beneath it.
   Side by side, the quote was squeezed into whatever the 1050px picture left
   over; stacked, both get their full width. The picture is capped at its
   source width, so the stack is centred rather than left-aligned -- nothing
   sits beside it to align to.
   ========================================================================== */

.fnote {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  justify-items: center;
}

/* Both children share the picture's width, so the quote beneath starts on the
   picture's left edge instead of floating free of it. */
.fnote > * { width: 100%; max-width: 1050px }

/* Centred on the page, not on the content column. The content column is inset
   by the eyebrow column plus its gap (240px), so its midpoint sits 120px right
   of the page's -- pulling the box left by 240px moves the centred block the
   120px needed to land on the page axis.

   The pull is clamped because the eyebrow column ends at 240px: without the
   clamp, a page-centred 1050px block would start left of that below ~1610px
   wide and run underneath the label. The clamp holds the block's left edge at
   280px once that point is reached, so it stops centring rather than
   colliding. 1002px is the content-column width at which the two coincide. */
@media (min-width: 56em) {
  .fnote { margin-left: calc(-1 * clamp(0px, 100% - 1002px, 15rem)) }
}

@media (min-width: 62em) {
  .fnote { gap: var(--space-5) }
}

.fnote__q {
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--fs-quote);
  line-height: 1.22;
  letter-spacing: -.02em;
  color: var(--ink);
  margin: 0;
  max-width: none;    /* the picture no longer sits beside it */
  text-wrap: pretty;
}

.fnote__by {
  font-family: var(--mono);
  font-size: var(--fs-mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: var(--space-4) 0 0;
}

/* Stacked, the image would otherwise run the full content width and tower over
   the quote; capped, it reads as a companion to it. */
.fnote .ph,
.fnote__img { aspect-ratio: 2 / 1; max-width: 1050px }
/* 1050px is the cap at every width: the source is 1050px across, so this is
   the largest the picture can be drawn without upscaling it. */

/* The source is 3:2 and the frame 2:1, so 25% of the height is cropped. The
   width is the source's own 1050px, which is the widest it can be drawn
   without upscaling -- hence the max-width below, and hence the height being
   the only dimension left to tune.
   center bottom pins the bottom edge only, so the whole crop is taken off the
   top: the field and the tree stay in frame and nothing is lost from the
   sides. A 3:2 source in a 16:9 frame crops vertically only, so the
   horizontal half of the keyword never comes into play. */
.fnote__img {
  display: block;
  width: 100%;
  object-fit: cover;
  object-position: center bottom;
}

/* ==========================================================================
   Motion preferences
   Transitions collapse to instant state changes — the hover affordance
   survives, the movement does not.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .cell::before, .linkline::before { transform: scaleX(1) }
  .cell::before { opacity: 0 }
  .cell:hover::before, .cell:focus-within::before { opacity: 1 }
}

/* ==========================================================================
   Sticky navigation
   scroll-padding-top keeps the sticky bar from covering a focused anchor
   target (WCAG 2.2 focus-not-obscured).
   ========================================================================== */

html { scroll-padding-top: 6rem; scroll-behavior: smooth }

.nav {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--rule);
}

.nav__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3);
  /* 80px, the reference's bar height; 81px total with the hairline below. */
  min-height: 5rem;
}

/* The logo lockup now sits in both the bar and the footer. The type
   properties below are kept deliberately: if the image fails to load, the alt
   text renders in them, so the fallback still looks like the wordmark it
   replaced. 22px was the size matched to the reference's own wordmark. */
.wordmark {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.375rem;
  letter-spacing: -.04em;
  white-space: nowrap;
}
.wordmark .dot { color: var(--accent) }

/* 133px puts the lockup's cap height at 15.70px, which is what the 22px type
   it replaced measured -- so the bar keeps the rhythm it was tuned to rather
   than growing by the 16% a width-for-width swap would have cost. ("Cap
   height" here is the red TAIB, which is all caps with no descender; the black
   Advisory rises above it on the d and the i, so overall height is the wrong
   thing to match on.)

   aspect-ratio carries the artwork's exact 251.586:40.375 so the box is
   correct before the file loads -- the integer width/height attributes on the
   <img> can only express 252:40, which is 1% out. */
.wordmark img {
  display: block;
  width: 133px;
  aspect-ratio: 251.586 / 40.375;
}

.nav__links { display: none; gap: var(--space-3); align-items: center }

.nav__link {
  position: relative;
  /* 15px, one step above the reference's 14px, at its 500 weight and 0.2px of
     tracking. The weight was the original mismatch -- at 400 the nav read
     lighter than Tingis's at an identical size. */
  font-size: .9375rem;
  font-weight: 500;
  letter-spacing: .0143em;
  color: var(--ink-soft);
  padding: .375rem 0;
  transition: color var(--dur) var(--ease);
}
.nav__link::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: 0;
  height: 1px; background: var(--accent);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--dur) var(--ease);
}
.nav__link:hover { color: var(--ink) }
.nav__link:hover::after { transform: scaleX(1) }
.nav__link[aria-current="page"] { color: var(--ink) }
.nav__link[aria-current="page"]::after { transform: scaleX(1) }

.nav__cta { display: none; padding-block: .8125rem }

.nav__toggle {
  display: inline-flex; align-items: center; gap: .5rem;
  background: none; border: 0; cursor: pointer;
  font-family: var(--mono); font-size: var(--fs-mono); letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink);
  min-height: 44px; min-width: 44px; justify-content: flex-end;
}

.nav__bars { display: grid; gap: 4px; width: 20px }
.nav__bars i { display: block; height: 1.5px; background: currentColor }

/* The panel is an in-flow dropdown inside the sticky bar, so the page behind
   it stays scrollable by design -- no scroll lock wanted. But that also means
   the panel travels with the bar: anything taller than the viewport can never
   be scrolled into view. On a phone in landscape (360-375px tall) the panel
   runs 445px and the last two items were unreachable at any scroll position.
   Capping it and scrolling inside fixes that. dvh tracks the visible viewport
   on iOS, where 100vh is the taller "large" viewport; vh is the fallback. */
.nav__panel {
  display: none;
  border-top: 1px solid var(--rule);
  background: var(--bg);
  padding-block: var(--space-2) var(--space-4);
  max-height: calc(100vh - 5.25rem);
  max-height: calc(100dvh - 5.25rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.nav__panel[data-open="true"] { display: block }

.nav__panel a {
  display: block;
  padding: .875rem 0;
  border-bottom: 1px solid var(--rule-soft);
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.25rem;
  letter-spacing: -.02em;
}
.nav__panel a { transition: color var(--dur) var(--ease) }
.nav__panel a:hover { color: var(--accent) }
.nav__panel a[aria-current="page"] { color: var(--accent) }

@media (min-width: 62em) {
  .nav__links { display: flex }
  .nav__cta { display: inline-flex }
  .nav__toggle { display: none }
  .nav__panel { display: none !important }
}

/* ==========================================================================
   Hero, proof strip, CTA band
   ========================================================================== */

.hero { padding-block: var(--space-6) var(--space-7) }
@media (min-width: 64em) { .hero { padding-block: var(--space-7) var(--space-8) } }

.hero__actions {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3);
  margin-top: var(--space-4);
}

/* Lead copy and the CTAs sit side by side in two equal columns, as the
   reference does — which shortens the hero and lifts everything below it.
   The row gap handles the stacked case, so the actions drop their own margin. */
.hero__sub {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  margin-top: var(--space-4);
  /* Grid items stretch by default, which would make the actions block as tall
     as the paragraph beside it and stretch the buttons with it. */
  align-items: start;
}
.hero__sub .lead { max-width: 46ch }
.hero__sub .hero__actions { margin-top: 0 }
/* 75em: with the buttons now stacked the column only has to hold the widest
   one (~249px), so the lead and CTAs can sit side by side sooner than 85em
   without the lead dropping below a readable measure. */
@media (min-width: 75em) {
  .hero__sub { grid-template-columns: 1fr 1fr; gap: 6rem }
  /* The CTAs end where the hero image ends. The image insets from the shell by
     min(15rem, (shellW - 45rem) / 2); shellW is 100vw - 8rem at these widths,
     so the same number is min(15rem, (100vw - 53rem) / 2). Shifting only this
     block keeps the paragraph's column at full width -- padding the whole row
     instead cost the paragraph ~100px at laptop widths. The inset tapers below
     ~1330px exactly as the image's does, so the two stay locked together. */
  .hero__sub .hero__actions {
    align-items: end;
    margin-right: min(15rem, max(0px, (100vw - 53rem) / 2));
  }
}

.proof {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .625rem var(--space-3);
  padding-block: var(--space-3);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: var(--fs-mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
/* The Foundation's brand line carries real weight in the section, so it is set
   up from the 11px utility size; the other .proof rows stay as they were. */
.proof--lg {
  font-size: .875rem;
  letter-spacing: .12em;
  color: var(--ink-soft);
  gap: .625rem var(--space-4);
  padding-block: var(--space-4);
}

.proof b { font-weight: 500; color: var(--ink) }
.proof .sep { color: var(--accent) }

.cta-band__actions {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3);
  margin-top: var(--space-4);
}

/* ==========================================================================
   Image placeholders
   PLACEHOLDER — every .ph swaps for a real <img>. Keep the wrapper's
   aspect-ratio so nothing reflows when the picture lands (CLS).
   ========================================================================== */

.ph {
  display: grid; place-items: center;
  aspect-ratio: 16 / 9;
  background: var(--bg-alt);
  border: 1px solid var(--rule);
  background-image: repeating-linear-gradient(
    -45deg, transparent 0 11px, var(--rule-soft) 11px 12px);
  color: var(--muted);
  text-align: center;
  padding: var(--space-3);
}

/* A full-width figure sitting between two padded sections. Left alone, the
   section above contributes its bottom padding and the one below its top
   padding, so the image ends up marooned — 144px above and 240px below at
   desktop. These collapse both sides to one shared step, kept symmetric.
   If :has() is unsupported the spacing simply stays at the roomier default. */
.figure-band { padding-block: 0 }
.hero:has(+ .figure-band) { padding-bottom: var(--space-6) }
.figure-band + .band { padding-top: var(--space-6) }
@media (min-width: 64em) {
  .hero:has(+ .figure-band) { padding-bottom: var(--space-7) }
  .figure-band + .band { padding-top: var(--space-7) }
}

/* Hero photograph. Inset to start where the content column starts (the eyebrow
   column plus its gap = 15rem), mirrored on the right so it stays centred.
   That also stops the 1467px source being upscaled on a wide screen. */
.hero-img-wrap { padding-inline: 0 }
@media (min-width: 56em) {
  /* The full 15rem inset lands the image exactly on the content column, but a
     fixed inset shrinks it to a thumbnail on a 1024 laptop. The floor keeps it
     at least 45rem wide, so the inset tapers below ~1330px instead. */
  .hero-img-wrap { padding-inline: min(15rem, max(0px, (100% - 45rem) / 2)) }
}

/* The source is 4:3; the 16/9 crop keeps the reserved space identical to the
   placeholder it replaced, so nothing reflows (CLS). */
.hero-img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  /* Anchored to the top edge: the 16:9 crop takes its whole 25% off the
     bottom, so nothing is ever trimmed from the skyline. */
  object-position: center top;
}

.band--deep .ph {
  background-color: rgba(255, 255, 255, .03);
  border-color: var(--rule-inv);
}

.ph__label {
  font-family: var(--mono);
  font-size: var(--fs-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  line-height: 1.7;
}
.ph__label .dot { color: var(--accent) }

/* ==========================================================================
   Method — Frame / Diagnose / Prioritize / Mobilise
   ========================================================================== */

.flow {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .5rem .75rem;
  font-family: var(--mono);
  font-size: .8125rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.flow span { color: var(--ink) }
.flow .ar { color: var(--accent) }

/* ==========================================================================
   Sectors
   ========================================================================== */

/* Text beside a portrait — the founder section on Home and the Bio hero.
   Previously called .sector__grid, which coupled it to the mandate rows; when
   those were rebuilt its CSS went with them and the portraits blew up to full
   width. Renamed so the two cannot be entangled again. */
.split { display: grid; grid-template-columns: 1fr; gap: var(--space-4) }
/* Stacked, a 4:5 portrait at full width becomes 905px tall on a tablet. Cap it
   above phone width; at 375 full width is only 414px tall, which is fine. */
/* The founder portrait drops into the frame the placeholder held: same 4:5 box
   and same 20rem cap, so nothing reflows. The source is square, so the 4:5
   frame crops ~10% from each side and nothing from the top -- the head stays
   fully in shot. */
.portrait {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--bg-alt);
}

@media (min-width: 30em) { .split .portrait { max-width: 20rem } }

@media (min-width: 30em) { .split .ph { max-width: 20rem } }
/* 68em, not 56em: beside a 20rem portrait the text column is only 288px at
   1024, and "Ibrahim." is a single unbreakable word 321px wide at this size —
   it overflowed its column rather than wrapping. Below this the two stack. */
@media (min-width: 68em) {
  .split {
    /* The copy column is capped, not 1fr. As 1fr it grew with the viewport
       while the portrait stayed 20rem pinned to the far edge, so the hole
       between them widened 1:1 with the screen -- 1357px at 2560. Capped, the
       portrait stays beside the copy it belongs to at every width, and the
       rule above the proof row stops stretching across empty space. */
    grid-template-columns: minmax(0, 48rem) minmax(0, 20rem);
    justify-content: start;
    gap: var(--space-5);
    align-items: start;
  }
  /* Fill that column rather than leaving the 46ch default stranded inside it. */
  .split .lead { max-width: 68ch }
}

/* Mandate rows, on the reference's "step" architecture: an oversized accent
   numeral, a mid-size title, the description and the capability list, all
   sharing one baseline. The rows live inside .steps so they begin on the
   content column — that way the hover gradient starts there too, rather than
   washing across the empty margin. */
.sector {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2);
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--rule);
  transition: background .4s var(--ease);
}
.sector:first-of-type { border-top: 1px solid var(--rule) }

@media (min-width: 56em) {
  /* The numeral takes the margin column, right-aligned so it sits tight to the
     content edge; 11rem + 4rem gap matches .sec, so the title lands flush with
     the section headline. Everything else shifts one column left, which is
     where the width for the capability list comes from. */
  .sector {
    grid-template-columns: 11rem minmax(0, 1fr);
    column-gap: 4rem;
    align-items: baseline;
    padding-block: 3.25rem;
  }
  .sector__n { text-align: right }
  .sector__d, .sector .caps { grid-column: 2 }
}

/* Fades out by 40% of the row, as the reference does. Deliberately outside the
   layout query above -- it was swept in there by accident, which switched the
   hover off below 56em even though the gradient works on a stacked row. */
.sector:hover, .sector:focus-within {
  background: linear-gradient(90deg, var(--glow), transparent 40%);
}

@media (min-width: 90em) {
  /* Four columns only once the capability list can hold single lines — at
     80em it fits, but the longest capability wraps, which is what the
     four-column layout was meant to stop.

     Widths are measured, not guessed: the title column is 25.5rem because
     "Commercial Performance" needs 396px at 34px/-1px and must break after it,
     and the capability column floors at 18rem because its longest line needs
     280px. The gap drops to 3rem and the margin column grows to 12rem to fund
     that — 12rem + 3rem still equals 240px, so the title stays flush with the
     section headline. */
  .sector {
    grid-template-columns: 12rem 25.5rem minmax(0, 1fr) minmax(18rem, .85fr);
    column-gap: 3rem;
  }
  .sector__d, .sector .caps { grid-column: auto }
}

@media (min-width: 100em) {
  /* Above 1600px the capability column is far wider than its longest line
     (280px), so the surplus reads as dead space at the right edge. Capping it
     at 20rem and widening the title column spends that surplus on the gap
     after the title instead, which shifts the description and capability
     columns right and pulls the row's right edge back in. */
  .sector { grid-template-columns: 12rem 30rem minmax(0, 1fr) minmax(18rem, 20rem) }
  .sector__d { max-width: 62ch }
}

.sector__n {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(2.5rem, 1.6rem + 2.4vw, 3.75rem);
  line-height: 1;
  letter-spacing: -.05em;
  color: var(--accent);
  margin: 0;
}

.sector__h {
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--fs-title-md);
  line-height: 1.12;
  letter-spacing: -.029em;
  margin: 0;
}

.sector__d {
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0;
}

.caps { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem }
.caps li {
  display: grid; grid-template-columns: 1.25rem 1fr; gap: .25rem;
  font-size: 1rem; color: var(--ink-soft);
}
.caps li::before { content: "—"; color: var(--accent) }

/* ==========================================================================
   Bio timeline
   ========================================================================== */

/* The timeline is a sibling of .sec inside the shell, so by default it starts
   at the page gutter while the headline that introduces it starts on the
   content column. The same 15rem offset .sec reserves puts the two in line. */
.tl { border-top: 1px solid var(--rule) }
@media (min-width: 56em) { .tl { margin-inline-start: calc(11rem + 4rem) } }

.tl__item {
  position: relative;
  display: grid; grid-template-columns: 1fr; gap: .5rem var(--space-5);
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--rule);
  transition: background var(--dur) var(--ease);
}

/* The Why TAIB treatment: the accent rule wipes in along the top edge and a 5%
   wash lifts the background. Every row already has a rule directly above it --
   the container's border-top for the first, the previous row's border-bottom
   for the rest -- so a single -1px offset lands on it at every width, with no
   media query needed. The wash mixes against --cell-bg, which each band
   redefines, so it resolves to the stone of this band rather than to white. */
.tl__item::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: -1px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .5s var(--ease);
  z-index: 1;
}
.tl__item:hover::before, .tl__item:focus-within::before { transform: scaleX(1) }
.tl__item:hover, .tl__item:focus-within {
  background: color-mix(in srgb, var(--accent) var(--hover-mix), var(--cell-bg));
}
@media (min-width: 56em) {
  /* 16rem, not 14: at the 22px company size it pulls the ampersand up onto the
     first line ("Porsche Middle East &" / "Africa") instead of stranding it. */
  .tl__item { grid-template-columns: 16rem 1fr; align-items: start }
}
@media (min-width: 90em) {
  /* 23rem clears the longest name outright -- "Mercedes-Benz Cars Middle East"
     measures 339px at 22px -- so wide screens get no break at all. Held back
     to 90em because a column this wide leaves the description too narrow on a
     laptop. */
  .tl__item { grid-template-columns: 23rem 1fr }
}

/* margin-top 0, so the company name's box starts level with the role title's
   in the next column -- it was inheriting the UA default 1em (22px at this
   size) while .tl__role sets its own margin, which pushed the two out of line
   by exactly that much. The bottom margin is stated explicitly to hold the
   gap down to the date, which previously came from the same UA default. */
.tl__org { font-family: var(--display); font-weight: 600; font-size: 1.375rem;
           letter-spacing: -.015em; margin: 0 0 1rem }
.tl__when { font-family: var(--mono); font-size: .875rem; letter-spacing: .14em;
            text-transform: uppercase; color: var(--accent); margin-top: .375rem }
/* Location sits under the dates in the same mono line, but in ink rather than
   the accent, so the accent stays reserved for the date. */
.tl__where { font-family: var(--mono); font-size: .875rem; letter-spacing: .14em;
             text-transform: uppercase; color: var(--ink); margin-top: .25rem }
.tl__role { margin: 0 0 .5rem; font-weight: 500; font-size: 1.25rem }

/* ==========================================================================
   Form
   ========================================================================== */

.form { display: grid; gap: var(--space-3); max-width: 46rem }

.grid-2 { display: grid; grid-template-columns: 1fr; gap: var(--space-3) }
@media (min-width: 40em) { .grid-2 { grid-template-columns: 1fr 1fr } }

.field { display: grid; gap: .5rem }

.field > label {
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft);
}
.field .req { color: var(--accent) }

.field input, .field select, .field textarea {
  font: inherit; font-size: 1rem;      /* 16px — stops iOS zoom-on-focus */
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 0;
  padding: .8125rem .875rem;
  min-height: 48px;
  width: 100%;
  transition: border-color var(--dur) var(--ease);
}
.field textarea { min-height: 8rem; resize: vertical; line-height: 1.6 }

.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--ink-soft) }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}

.field [aria-invalid="true"] { border-color: var(--accent); border-width: 2px }

.field__hint { font-size: .875rem; color: var(--muted); max-width: 66ch }

.field__err {
  font-size: .875rem; color: var(--accent); font-weight: 500;
  display: none;
}
.field__err[data-show="true"] { display: block }

.consent { display: grid; grid-template-columns: 1.5rem 1fr; gap: .75rem; align-items: start }
.consent input { width: 1.5rem; height: 1.5rem; min-height: 0; margin-top: .0625rem; accent-color: var(--accent) }
.consent label { font-size: .9375rem; color: var(--ink-soft) }
/* Honeypot. Moved off-screen rather than display:none -- some bots skip fields
   they can tell are not rendered, and this one needs to look fillable. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.consent label a { padding-block: .3rem }

.form__summary {
  display: none;
  border: 2px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 5%, var(--bg));
  padding: var(--space-3);
}
.form__summary[data-show="true"] { display: block }
.form__summary h2 { font-family: var(--display); font-size: 1.0625rem; margin: 0 0 .5rem }
.form__summary ul { margin: 0; padding-left: 1.125rem }
.form__summary a { color: var(--accent); text-decoration: underline }

.form__ok {
  display: none;
  border: 1px solid var(--rule); border-left: 2px solid var(--accent);
  padding: var(--space-3);
}
.form__ok[data-show="true"] { display: block }

/* ==========================================================================
   Footer
   ========================================================================== */

.footer { background: var(--bg-deep); color: var(--ivory); padding-block: var(--space-6) var(--space-4) }

.footer__grid {
  display: grid; grid-template-columns: 1fr; gap: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--rule-inv);
}
@media (min-width: 48em) { .footer__grid { grid-template-columns: 1.6fr 1fr 1fr } }

.footer__h {
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .16em; text-transform: uppercase;
  color: rgba(242, 239, 237, .55); margin: 0 0 var(--space-2);
}

.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .125rem }
/* inline-block + padding lifts these to a 24px+ target (WCAG 2.2 target-size)
   without changing the visual rhythm — the gap comes down to compensate. */
.footer__list a {
  display: block;            /* full-column target, not just the word */
  padding-block: .3125rem;
  color: rgba(242, 239, 237, .82);
  font-size: 1rem;
  transition: color var(--dur) var(--ease);
}
.footer__list a:hover { color: var(--accent-2) }

/* Plain text in the contact list, styled to match the links beside it. */
.footer__loc {
  padding-block: .3125rem;
  font-size: 1rem;
  color: rgba(242, 239, 237, .82);
}

.footer__base {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  justify-content: space-between;
  padding-top: var(--space-3);
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .12em; text-transform: uppercase;
  color: rgba(242, 239, 237, .5);
}
.footer__base a { color: inherit; display: inline-block; padding-block: .3125rem }
.footer__base a:hover { color: var(--accent-2) }

/* ==========================================================================
   Sprezzatura-pattern pages (Sectors, Insights)
   Stacked page header, then rows that alternate between the two columns.
   Each entry owns a full hairline-separated row rather than sitting in a
   card grid — the stagger is what gives the page its editorial rhythm.
   ========================================================================== */

.pagehead { padding-block: var(--space-6) var(--space-5) }
@media (min-width: 64em) { .pagehead { padding-block: var(--space-7) var(--space-6) } }

.srow {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  border-top: 1px solid var(--rule);
  padding-block: var(--space-5);
}
.srow:last-child { border-bottom: 1px solid var(--rule) }

/* The rows sit on the content column, not the page gutter: the left edge lines
   up with the lead above them and the right margin mirrors it, so the list
   reads as one indented block instead of each row spanning gutter to gutter
   while the copy that introduces it starts 240px further in. The offset is the
   eyebrow column plus its gap, the same figure .sec reserves. */
@media (min-width: 56em) {
  .srow { margin-inline: calc(11rem + 4rem) }
}

/* Two columns only from 100em. Indenting the row by the eyebrow column on both
   sides costs it 480px, so the old 62em split left a 416px row at 1024 -- a
   200px column of copy beside a 101px picture. Below 100em the row stacks. */
/* 1440px, not the 1600px this was first set to. A 14" laptop is 1512 CSS px
   and a 13" is 1440, so at 1600 the alternating layout never appeared on the
   machines most visitors use -- it only showed up if you zoomed the browser
   out, which is how the discrepancy was found. At 1512 the text column is
   453px against 500px at 1600; tighter, but the structure is the same. */
@media (min-width: 90em) {
  .srow { grid-template-columns: 1.17fr 1fr; gap: 4rem; padding-block: 4.375rem }
  /* Even-numbered entries sit in the right column. The template is mirrored
     rather than the child being moved, so the content column keeps exactly the
     same width on both sides — only its side of the page changes. */
  .srow--right { grid-template-columns: 1fr 1.17fr }
  .srow--right > .srow__c { grid-column: 2 }
}

.srow__n {
  font-family: var(--mono);
  font-size: .8125rem;
  letter-spacing: .1em;
  color: var(--muted);
  margin: 0 0 var(--space-2);
}
.srow__n b { color: var(--accent); font-weight: 400 }

.srow__h {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.625rem, 1rem + 2.1vw, 2.5rem);
  line-height: 1.05;
  letter-spacing: -.025em;
  margin: 0;
  /* pretty, not balance: balance evens the two lines, which breaks a long
     headline early and leaves a short first line stranded beside the picture.
     pretty fills the line and only steps in to prevent a one-word last line. */
  text-wrap: pretty;
}

/* 68ch, the site's body measure. At 52ch the description wrapped ~210px short
   of its column, which read as a hole between the copy and the picture. */
.srow__d { margin: var(--space-2) 0 0; color: var(--ink-soft); font-size: 1.0625rem; max-width: 68ch }

.srow__caps { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: .625rem }
.srow__caps li {
  display: grid; grid-template-columns: 1.5rem 1fr;
  font-size: 1rem; color: var(--ink-soft);
}
.srow__caps li::before {
  content: "\2014";
  font-family: var(--mono);
  color: var(--accent);
}

/* Sector images fill the column the copy leaves empty. One ratio for all seven
   and one fixed column per side, so the pictures keep a single rhythm down the
   page while the rows alternate. Cropping is done here rather than in the files
   so the originals stay intact and the ratio can change without re-cutting. */
.srow__img {
  display: block;
  width: 80.5%;   /* 70% + 15% */
  aspect-ratio: 3 / 2;
  object-fit: cover;
  background: var(--bg-alt);
}

/* Stacked, 70% of a full-width row still outgrows the copy above it, so the
   picture is also held to a fixed ceiling. */
@media (max-width: 89.99em) {
  .srow__img { max-width: 39rem }   /* 34rem + 15%, so the ceiling scales with the picture */
}

@media (min-width: 90em) {
  /* 70% of the column, set on the base rule so it holds when stacked too. The
     outer edge stays pinned to the row's own edge, so the images share one left
     edge and one right edge down the page and the extra room falls between
     picture and text. Stacked, the image keeps the copy's left edge. */
  /* Flush with the column rather than 80.5% of it. That 80.5% was tuned when
     this layout only appeared above 1600px, where the column is wide; once the
     breakpoint dropped to 1440 the same percentage left a 312px picture at
     1512. Filling the column restores it to 387px -- within a few pixels of
     what the old 1600 breakpoint produced -- and pins both edges to the column,
     so the pictures share one left and one right edge down the page. */
  .srow__img                { align-self: center; width: 100% }
  .srow > .srow__img        { grid-column: 2; grid-row: 1; justify-self: end }
  .srow--right > .srow__img { grid-column: 1; grid-row: 1; justify-self: start }
}

/* ==========================================================================
   Insights — featured entry, then a card grid
   ========================================================================== */

.feat {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  border-top: 1px solid var(--rule);
  padding-block: var(--space-4);
}
@media (min-width: 62em) {
  .feat { grid-template-columns: 1.1fr 1fr; gap: 3.5rem; align-items: center; padding-block: 2.5rem }
}

.feat__h {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.75rem, 1rem + 2.4vw, 2.5rem);
  line-height: 1.05;
  letter-spacing: -.025em;
  margin: var(--space-2) 0 0;
  text-wrap: balance;
}
.feat__d { margin: var(--space-2) 0 0; color: var(--ink-soft); font-size: 1.0625rem; max-width: 46ch }

.cardgrid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  padding-top: var(--space-5);
}
@media (min-width: 40em) { .cardgrid { grid-template-columns: repeat(2, 1fr); gap: 3rem 2.5rem } }
@media (min-width: 62em) { .cardgrid { grid-template-columns: repeat(3, 1fr) } }

/* A card that has a real image instead of the placeholder frame: same 3:2 box,
   so the grid keeps its rhythm whichever a card carries.

   The six card pictures are held back in saturation. Seen together in a grid
   their blues and greens competed with the accent and sat oddly against the
   warm neutral palette; dimmed, they read as one set and sit under the type
   rather than in front of it. The featured picture above is deliberately left
   alone -- it is the one image meant to carry colour.

   --img-sat is the knob: 0.6 by default, raised inline on the individual
   pictures that lose too much at that level. Set it on the <img>, not on a new
   class, so which pictures are tuned is visible in the markup. */
.icard > img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  background: var(--bg-alt);
  --img-sat: .6;
  filter: saturate(var(--img-sat)) contrast(.97);
}

.icard__h {
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.3125rem;
  line-height: 1.18;
  letter-spacing: -.015em;
  margin: var(--space-2) 0 0;
}
.icard__d { margin: .5rem 0 0; color: var(--ink-soft); font-size: 1rem; max-width: 46ch }

/* Shared by featured and cards: the mono topic label and the date/read-time
   line. Topic takes the accent, meta stays muted. */
.tag {
  display: flex; flex-wrap: wrap; gap: .5rem 1rem;
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .1em; text-transform: uppercase;
  margin: var(--space-3) 0 0;
}
.feat .tag { margin-top: 0 }
.tag__topic { color: var(--accent) }
.tag__flag { color: var(--ink); font-weight: 500 }

.meta {
  display: flex; flex-wrap: wrap; gap: .5rem 1rem;
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted);
  margin: var(--space-2) 0 0;
}

/* ==========================================================================
   Article page — mirrors the reference's own article layout: a single 47.5rem
   measure column, oversized title, dek, byline, then body at 19px with 25px
   subheads. Source markers render as endnote links, per the brief's note that
   the public article should not show raw [1] markers.
   ========================================================================== */

.art { padding-block: var(--space-5) var(--space-7) }

/* The reference centres a 760px column, which strands the article in white
   space. This one is centred but considerably wider: a 52rem measure plus a
   gutter of page padding on each side, so the block is symmetric at every
   width. At 1440 the auto margins resolve to 304px -- the same offset as the
   content column on every other page -- and beyond that width the margins
   grow evenly on both sides rather than the measure running away. The cap is
   on the block, so the title, figure and body all share one edge. */
.art-wrap {
  width: 100%;
  max-width: calc(52rem + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.art-back {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--mono); font-size: .8125rem;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted);
  padding-block: .5rem;
  transition: color var(--dur) var(--ease);
}
.art-back:hover { color: var(--accent) }
.art-back .ar { transition: transform var(--dur) var(--ease) }
.art-back:hover .ar { transform: translateX(-4px) }

.art-meta {
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--accent);
  margin: var(--space-4) 0 var(--space-3);
}

.art-title {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(2rem, 1.2rem + 2.6vw, 3.25rem);
  line-height: 1.06;
  letter-spacing: -.03em;
  margin: 0;
  text-wrap: balance;
}

.art-dek {
  font-size: clamp(1.125rem, 1rem + .6vw, 1.375rem);
  line-height: 1.5;
  color: var(--ink-soft);
  margin: var(--space-3) 0 0;
}

.art-by {
  font-family: var(--mono); font-size: .8125rem;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted);
  margin: var(--space-4) 0 0;
}

.art-fig { margin: var(--space-5) 0 0 }
.art-fig img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block }
.art-fig figcaption {
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .1em; color: var(--muted);
  margin-top: var(--space-2);
}
.art-fig figcaption a { color: var(--muted); text-decoration: underline }
.art-fig figcaption a:hover { color: var(--accent) }

.art-rule { height: 1px; background: var(--rule); border: 0; margin: var(--space-5) 0 0 }

.art-body > p {
  font-size: clamp(1.125rem, 1rem + .3vw, 1.25rem);
  line-height: 1.7;
  color: var(--ink-soft);
  margin: var(--space-3) 0 0;
}
.art-body > p:first-child {
  color: var(--ink);
  font-size: clamp(1.1875rem, 1.05rem + .35vw, 1.375rem);
  line-height: 1.6;
}

.art-body h2 {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.375rem, 1.1rem + .7vw, 1.5625rem);
  line-height: 1.2;
  letter-spacing: -.02em;
  margin: var(--space-5) 0 0;
}

/* Endnote markers: small, accent, and they do not disturb the line box. */
.art-body sup { font-size: max(.75rem, .625em); line-height: 0; vertical-align: super }
/* The marker is the smallest target on the site -- 7px wide unpadded. It is
   exempt from WCAG 2.5.8 as a link inline in a sentence, but 7px is still hard
   to hit on a phone, so the hit area is padded on both axes. The horizontal
   padding does double duty: consecutive markers used to render as "12", which
   reads as twelve rather than as one and two. */
.art-body sup a {
  color: var(--accent);
  font-family: var(--mono);
  padding: .4rem .3rem;
}
.art-body sup a:hover { text-decoration: underline }

/* ==========================================================================
   Prose lists, inline links and emphasis inside .art-body
   The legal and privacy notices are the only long-form prose carrying bullets
   and inline links -- the Insights articles have neither. The marker mirrors
   .srow__caps so the em-dash bullet reads the same everywhere.

   The link rules match a DIRECT child deliberately: a citation marker is
   p > sup > a and carries its own rule above, so a descendant selector here
   would capture it and undo the mono/padding treatment.
   ========================================================================== */

/* The Privacy Notice is the only prose deep enough to need a third level. */
.art-body h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.125rem, 1.05rem + .3vw, 1.25rem);
  line-height: 1.3;
  letter-spacing: -.01em;
  color: var(--ink);
  margin: var(--space-4) 0 0;
}

.art-body ul {
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0;
  display: grid;
  gap: .625rem;
}
.art-body ul li {
  display: grid;
  grid-template-columns: 1.5rem 1fr;
  font-size: clamp(1.0625rem, 1rem + .25vw, 1.1875rem);
  line-height: 1.6;
  color: var(--ink-soft);
}
.art-body ul li::before {
  content: "\2014";
  font-family: var(--mono);
  color: var(--accent);
}

.art-body p > a,
.art-body li > a,
.art-body .spec__d a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: .15em;
}
/* The email and website values in the legal pages' particulars blocks are
   standalone links in a term/value row, not links inside a sentence, so WCAG
   2.5.8's inline exception does not cover them. At 22px they were just under
   the 24px minimum. Vertical padding on an inline box grows the hit area
   without moving the line, so nothing reflows. */
.art-body .spec__d a { padding-block: .25rem }
.art-body p > a:hover,
.art-body li > a:hover,
.art-body .spec__d a:hover { text-decoration-thickness: 2px }

.art-body strong { color: var(--ink); font-weight: 600 }

.art-body .specs { margin-top: var(--space-4) }

.art-sources { margin-top: var(--space-6); border-top: 1px solid var(--rule); padding-top: var(--space-4) }
.art-sources h2 {
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted); font-weight: 400; margin: 0 0 var(--space-3);
}
.art-sources ol { margin: 0; padding-left: 1.5rem; display: grid; gap: .75rem }
.art-sources li { font-size: .9375rem; line-height: 1.55; color: var(--ink-soft) }
.art-sources li a { color: var(--accent); overflow-wrap: anywhere }
.art-sources li a:hover { text-decoration: underline }
.art-sources li:target { background: color-mix(in srgb, var(--accent) 8%, transparent) }

/* ==========================================================================
   "More field notes" rows at the foot of an article
   ========================================================================== */

.ins-rows { border-top: 1px solid var(--rule) }

.ins-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: .5rem;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--rule);
  position: relative;
  transition: background var(--dur) var(--ease);
}
.ins-row::before {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: 0;
  height: 1px; background: var(--accent);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .5s var(--ease);
}
.ins-row:hover { background: color-mix(in srgb, var(--accent) 5%, var(--bg)) }
.ins-row:hover::before { transform: scaleX(1) }
.ins-row:hover .ar { transform: translateX(5px) }

@media (min-width: 56em) {
  .ins-row { grid-template-columns: 11rem minmax(0, 1fr) 3rem; gap: 0 var(--space-4); align-items: baseline }
}

.ins-row-cat {
  font-family: var(--mono); font-size: var(--fs-mono);
  letter-spacing: .14em; text-transform: uppercase; color: var(--accent);
}
.ins-row-t {
  font-family: var(--display); font-weight: 600;
  font-size: 1.1875rem; line-height: 1.25; letter-spacing: -.015em;
  margin: 0;
}
.ins-row-d { margin: .375rem 0 0; font-size: 1rem; color: var(--ink-soft); max-width: 62ch }
.ins-row-ar { font-size: 1.25rem; color: var(--accent); justify-self: end }
.ins-row-ar .ar { display: inline-block; transition: transform var(--dur) var(--ease) }

/* The featured card is a single link, so its "read" affordance is a span —
   a nested <a> inside an <a> is invalid and breaks keyboard navigation. */
.feat { transition: background var(--dur) var(--ease) }
/* Hover is the shared treatment below; see "Browsable blocks". */
.feat__read {
  display: inline-flex; align-items: center; gap: .625rem;
  position: relative;
  font-family: var(--mono); font-size: .8125rem;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent);
  margin-top: var(--space-3);
  padding-block: .5rem;
}
.feat__read::before {
  content: ""; position: absolute; inset-block-end: 0; inset-inline: 0;
  height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--dur) var(--ease);
}
.feat:hover .feat__read::before { transform: scaleX(1) }
.feat:hover .feat__read .ar { transform: translateX(5px) }
.feat__read .ar { transition: transform var(--dur) var(--ease) }
.feat img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block }
