/* ============================================================================
   SECTIONS — components for the spine.
   Left-aligned by default (DDB p.28). One accent only (both rulebooks).
   Square by default (SAB). Nothing here introduces a second colour.
   ============================================================================ */

.section > .inner > .t-eyebrow { display: block; margin-bottom: var(--space-sm); }
.section > .inner > .t-h2      { max-width: 20ch; }
.measure                       { max-width: 62ch; margin-top: var(--space-md); }

/* two-up layout used by the centenary block */
.split {
  display: grid; gap: var(--space-2xl);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  align-items: center;
}
.split img { width: 100%; border-radius: var(--radius-sm); }

/* ---- tinted section frames ----
   A wash of the section's DDB colour plus a hairline of it at full strength on
   the top edge. The tint is deliberately near-invisible — at 6% it reads as
   "this page has colour in it" rather than as a coloured panel, and white type
   grounds and SAB red both still behave normally on top of it.

   NEVER tint with DDB yellow. Yellow desaturates to cream long before it reads
   as colour, so at these percentages it looks like dirty white rather than a
   deliberate choice. Yellow earns its place at full strength only — the bands,
   the buttons, the mark. Tints use green, blue and grey. */
.section--tint {
  background: color-mix(in srgb, var(--sec, var(--sab-grey-100)) 22%, white);
  border-top: 3px solid var(--sec, var(--border-soft));
}

/* ---- the mantra, opposite the mark ----
   The fanned lockup is a supplied asset (img/ddb-b-fan.png), a transparent
   cutout — so it needs `contain`, not `cover`, or the fan gets clipped. */
.mantra-split {
  display: grid; gap: var(--space-2xl);
  grid-template-columns: minmax(0, 1fr) minmax(0, 300px);
  align-items: center;
}
.mantra-mark {
  width: 100%; height: auto; max-height: 460px;
  object-fit: contain; object-position: center;
  justify-self: end;
}
/* below two columns the mark would squash the copy — it steps down and out */
@media (max-width: 860px) {
  .mantra-split { grid-template-columns: 1fr; }
  .mantra-mark { max-height: 280px; justify-self: start; }
}

/* ---- stats ---- */
.stat-row {
  margin-top: var(--space-2xl);
  display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  border-top: 1px solid var(--border-soft);
  padding-top: var(--space-lg);
}
.stat-value {
  font-size: clamp(30px, 3.4vw, 44px); font-weight: 700;
  line-height: 1.05; letter-spacing: -.02em;
}
.stat p { margin-top: 10px; }
/* One stat carries more weight than the rest — it spans the row and sits on the
   accent, so it reads as the answer to "why you, here". Only ever one. */
.stat--wide {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; gap: var(--space-md); flex-wrap: wrap;
  margin-top: var(--space-sm);
  padding: var(--space-md) var(--space-lg);
  background: var(--accent); color: #fff;
}
.stat--wide .stat-value { color: #fff; }
.stat--wide p { margin-top: 0; color: rgba(255,255,255,.86); }

/* ---- methodology ---- */
/* <ol>, so list-style must be cleared explicitly — the base reset only does
   <ul>, which is what produced "6. 06" next to the step number. */
.steps {
  margin-top: var(--space-2xl);
  display: grid; gap: 0; list-style: none; padding: 0;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.step {
  position: relative;
  padding: var(--space-lg) var(--space-md) var(--space-xl) 0;
  border-top: 2px solid var(--border-soft);
  margin-right: var(--space-md);
}
/* The rule is the sequence made visible: it wipes in from the left on reveal,
   staggered by js/site.js, so the seven read as an order rather than a grid.
   clip-path, not width — width would relayout on every frame. */
.step::before {
  content: ""; position: absolute; inset: -2px 0 auto 0; height: 2px;
  background: var(--accent);
  clip-path: inset(0 100% 0 0);
  transition: clip-path 520ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.step.is-in::before { clip-path: inset(0 0 0 0); }

/* the number carries the sequence — set large and pale so it reads as position,
   not as a label competing with the stage name */
.step-n {
  display: block; margin-bottom: 6px;
  font-size: 30px; font-weight: 700; line-height: 1;
  letter-spacing: -.03em;
  color: color-mix(in srgb, var(--accent) 26%, transparent);
  transition: color 200ms ease;
}
.step h3 { margin-bottom: 8px; }

/* Hover is for scanning, not decoration: it tells you which column your eye is
   in across a dense seven-part grid. Gated — on touch this would fire on tap. */
@media (hover: hover) and (pointer: fine) {
  .step:hover .step-n { color: var(--accent); }
}

/* 07 is the payoff, not a seventh equal step. It spans the row and sits on the
   accent, which also resolves the orphaned two-card row the grid was leaving. */
.step--payoff {
  grid-column: 1 / -1;
  margin-right: 0; margin-top: var(--space-lg);
  padding: var(--space-lg);
  border-top: 0;
  background: var(--accent); color: #fff;
}
.step--payoff::before { display: none; }
.step--payoff .step-n { color: rgba(255,255,255,.55); }
.step--payoff h3 { font-size: clamp(24px, 2.6vw, 34px); }
.step--payoff .t-small { color: rgba(255,255,255,.82); max-width: 52ch; }

/* ---- people ---- */
.people-grid {
  margin-top: var(--space-2xl);
  display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
.person img, .person-ph {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  background: var(--bg-surface); border-radius: var(--radius-sm);
}
.person figcaption { margin-top: 12px; font-size: 15px; }
.person figcaption b { display: block; font-weight: 700; }
.person figcaption span { color: var(--text-muted); font-size: 13px; }

/* placeholder note while real content is outstanding */
.awaiting {
  margin-top: var(--space-xl); padding: var(--space-md);
  border: 1px dashed var(--border-default); color: var(--text-muted);
}

/* ---- work ---- */
.case-grid {
  margin-top: var(--space-2xl);
  display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
/* Plain rectangle. The B-shaped graphic device (guidelines p.39–45) was tried
   here and rejected — the DDB presence comes from colour, not from shape. */
.case-media {
  display: block; position: relative;
  width: 100%; aspect-ratio: 16 / 10;
  /* the DDB colour sits under the still, so it shows while the image loads and
     as a hairline along the top of every tile */
  background: var(--ddb, var(--sab-grey-150));
  border-top: 5px solid var(--ddb, var(--border-soft));
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-md);
  overflow: hidden;
}
.case-media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
}
/* client name sits behind a chip of the tile colour, so the palette reads down
   the whole grid and not just along the top edge */
.case-client {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 700;
  color: var(--text-primary); margin-bottom: 6px;
}
.case-client::before {
  content: ""; flex: none; width: 12px; height: 12px;
  background: var(--ddb, var(--accent));
}
.case h3 { margin-bottom: 8px; }
.case-tag {
  display: inline-block; margin-top: 12px;
  font-size: 12px; font-weight: 600; color: var(--text-muted);
  border: 1px solid var(--border-default);
  padding: 4px 10px; border-radius: var(--radius-0);
}

/* ---- solid CTA ----
   SAB's own button: filled accent, square, white bold label, no arrow. It is
   the one place on the site that carries a red fill, so it has to stay rare —
   two on the page body, one per person card. Adding a third use would turn
   the red from "act here" into decoration. */
.btn-solid {
  display: inline-block; align-self: start;
  padding: 13px 22px;
  background: var(--accent); color: #fff;
  font-size: 14px; font-weight: 700; line-height: 1;
  border: 0; border-radius: var(--radius-0);
  transition: background var(--dur-fast) var(--ease-out),
              transform 160ms var(--ease-out);
}
.btn-solid--sm { padding: 10px 16px; font-size: 13px; }
@media (hover: hover) and (pointer: fine) {
  .btn-solid:hover { background: var(--sab-red-logo); }
}
.btn-solid:active { transform: scale(.97); }

/* In the three DDB-coloured sections the button takes its block's colour
   instead of SAB red. The palette is pale, so the label flips to DDB black —
   white on any of these fails contrast badly. Red is not lost: it still owns
   every CTA outside these sections, and every link inside them. */
.btn-solid--ddb {
  background: var(--ddb, var(--accent));
  color: var(--ddb-black);
}
@media (hover: hover) and (pointer: fine) {
  /* darken the block's own colour rather than jumping to a different hue */
  .btn-solid--ddb:hover {
    background: color-mix(in srgb, var(--ddb, var(--accent)) 82%, var(--ddb-black));
  }
}

/* ============================================================================
   SECTION DIVIDER — full bleed, the word set as large as it will go.
   Modelled on ddb.com's own page breaks. The ground is a soft wash built from
   ONE palette colour (p.18) against white, so nothing outside the palette is
   introduced and each divider stays keyed to its section's colour.
   Marked aria-hidden: the real <h2> follows immediately, and a screen reader
   should not hear the section named twice.
   ============================================================================ */
.sec-divider {
  position: relative; isolation: isolate;
  display: grid; place-items: center;
  /* Measured off ddb.ae/about-us at a 1440 viewport: their band is 615px of
     900 = 68vh, and the word spans 84% of the width. Both numbers below are
     theirs, not estimates. */
  min-height: min(68vh, 660px);
  padding: var(--space-2xl) 0;
  overflow: hidden;
  /* Five overlapping lobes, one per DDB colour, bleeding into each other the
     way poured ink does. Each divider rotates which colour lands where, so the
     three are the same system in three moods.
     Every lobe is a palette colour at full strength — the blending happens by
     overlap, not by tinting, which is what keeps it looking mixed rather than
     washed out. */
  background:
    radial-gradient(58% 78% at 10% 16%, var(--m1) 0%, transparent 64%),
    radial-gradient(52% 70% at 88% 12%, var(--m2) 0%, transparent 62%),
    radial-gradient(64% 84% at 74% 92%, var(--m3) 0%, transparent 66%),
    radial-gradient(56% 74% at 24% 96%, var(--m4) 0%, transparent 64%),
    radial-gradient(70% 60% at 50% 46%, var(--m5) 0%, transparent 70%),
    #fff;
}
/* Grain. A STATIC data-URI raster, not a live filter — the hero taught us that
   every filtered element gets its own compositing surface. This one never
   animates and never rescales. */
.sec-divider::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  pointer-events: none; opacity: .95;
  /* Coarse and heavy — the reference reads as printed grain, not a faint
     dither. A finer baseFrequency disappears the moment the page is scaled. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
}
.sec-divider-word {
  position: relative;
  /* ONE line, edge to edge. Whichever is smaller: the display ceiling, or the
     size at which the whole string still fits the width. 0.60em is about the
     average advance of this grotesk at 700 weight, spaces included.
     94vw, not var(--gutter): that token is a clamp(), and multiplying a
     clamp() inside calc() collapses the whole declaration to 0 here. */
  font-size: max(36px, min(
    calc(84vw / (var(--chars, 6) * 0.60)),   /* their fill ratio, whatever the length */
    56vh                                      /* unless that would out-grow the band */
  ));
  font-weight: 700; line-height: .9; letter-spacing: -.045em;
  text-transform: uppercase; white-space: nowrap;
  color: var(--ddb-black);
  text-align: center;
}

/* ---- the mantra divider ----
   DDB's own saturated wash, not the p.18 palette. It exists once, for the
   mantra, which is the one moment the agency speaks at full volume. The other
   dividers stay on the guidelines' pale colours so this one keeps its weight. */
.sec-divider--hot {
  background:
    radial-gradient(58% 76% at 12% 14%, #FFB020 0%, transparent 62%),
    radial-gradient(54% 70% at 88% 10%, #4B3BC4 0%, transparent 60%),
    radial-gradient(66% 82% at 84% 88%, #FF7A18 0%, transparent 64%),
    radial-gradient(60% 76% at 16% 92%, #7A3BD6 0%, transparent 62%),
    radial-gradient(78% 66% at 46% 50%, #FF4FA3 0%, transparent 72%),
    #F0353B;
}
.sec-divider--hot .sec-divider-word {
  /* DDB black, same as every other divider. The ground is what makes this one
     the loud moment — the type stays consistent across all four. */
  color: var(--ddb-black);
}

/* ---- scope ---- */
.scope-list {
  margin-top: var(--space-2xl);
  display: grid; gap: 0;
  border-top: 1px solid var(--border-soft);
}
.scope-item {
  display: grid; gap: 6px;
  grid-template-columns: minmax(200px, 1fr) 2fr;
  padding-block: var(--space-md);
  border-bottom: 1px solid var(--border-soft);
}
.scope-item h3 { font-weight: 700; }
@media (max-width: 720px) { .scope-item { grid-template-columns: 1fr; } }

/* ---- pitch + footer ---- */
.pitch-band { background: var(--bg-invert); color: var(--text-inverse); }
.pitch-band .t-h2 { color: var(--text-inverse); }
.pitch-band .t-body { color: rgba(255,255,255,.66); }
.pitch-band .btn-row { margin-top: var(--space-lg); display: flex; gap: 12px; flex-wrap: wrap; }
.pitch-band .btn--ghost { color: #fff; border-color: rgba(255,255,255,.4); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }

.site-footer {
  padding-block: var(--space-lg);
  border-top: 1px solid var(--border-soft);
}
.site-footer .inner { padding-inline: var(--gutter); }

/* ============================================================================
   DDB MOMENTS
   Full-bleed yellow. DDB p.19 sanctions colour bleed "to create more impact",
   and yellow is the ONLY accent inside this block — so the one-accent law that
   both rulebooks share still holds. This is where the agency gets to speak.
   ============================================================================ */
.ddb-band {
  background: var(--signature);
  color: var(--ddb-black);
  padding-block: var(--space-2xl);
  padding-inline: var(--gutter);
}
.ddb-kicker {
  display: block; font-size: 13px; font-weight: 700;
  letter-spacing: .03em; margin-bottom: var(--space-sm);
  color: color-mix(in srgb, var(--ddb-black) 62%, transparent);
}
.ddb-line {
  font-size: clamp(26px, 3.6vw, 46px); font-weight: 300;
  line-height: 1.14; letter-spacing: -.02em; max-width: 22ch;
}
.ddb-line b { font-weight: 700; }

/* People photos run plain — the mark stays in the hero and the header, and
   repeating it as a crop was diluting it. */
.people-grid { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }

/* ---- methodology: The Power to Move ---- */
.step-q { margin-top: 10px; display: grid; gap: 4px; }
.step-q li {
  font-size: 13px; line-height: 1.5; color: var(--text-muted);
  padding-left: 12px; position: relative;
}
.step-q li::before {
  content: ''; position: absolute; left: 0; top: .62em;
  width: 4px; height: 4px; background: var(--accent);
}

/* ---- clients ---- */
.clients { margin-top: var(--space-2xl); }
.clients-label {
  display: block; font-size: 13px; font-weight: 700;
  color: var(--text-muted); margin-bottom: var(--space-sm);
}
.clients ul { display: flex; flex-wrap: wrap; gap: 10px 12px; }
.clients li {
  font-size: 14px; font-weight: 600;
  border: 1px solid var(--border-soft);
  padding: 7px 13px;
}

/* ---- service levels ----
   Scan layer (always visible): tier + turnaround + examples.
   Detail layer (folded): definition, quality standards, numbered process. */
.sla { margin-top: var(--space-xl); border-top: 1px solid var(--border-soft); }
.sla-row { border-bottom: 1px solid var(--border-soft); }

.sla-head {
  width: 100%; display: flex; align-items: baseline; gap: var(--space-md);
  padding: var(--space-md) 0 6px;
  background: none; border: 0; text-align: left; cursor: pointer;
  font: inherit; color: inherit;
}
.sla-n { font-size: 12px; font-weight: 700; color: var(--accent); }
.sla-tier { flex: 1 1 auto; font-size: 19px; font-weight: 700; }
/* the number is the answer — it gets the size and the accent */
.sla-days {
  font-size: clamp(20px, 2.2vw, 28px); font-weight: 700;
  color: var(--accent); white-space: nowrap; letter-spacing: -.01em;
}
.sla-chev {
  width: 9px; height: 9px; flex: none; align-self: center;
  border-right: 2px solid var(--sab-grey-400);
  border-bottom: 2px solid var(--sab-grey-400);
  transform: rotate(45deg); transform-origin: 60% 60%;
  transition: transform .28s var(--ease-out);
}
.sla-row.is-open .sla-chev { transform: rotate(-135deg); }
@media (hover: hover) and (pointer: fine) {
  .sla-head:hover .sla-chev { border-color: var(--accent); }
}
.sla-head:active { transform: scale(0.995); }

.sla-eg {
  margin: 0 0 var(--space-md);
  max-width: 74ch; font-size: 14px; line-height: 1.6; color: var(--text-muted);
}

/* minmax(0, 0fr) — a bare 0fr keeps the content's min-content height */
.sla-body {
  display: grid; grid-template-rows: minmax(0, 0fr);
  opacity: 0; transition: grid-template-rows .34s var(--ease-out), opacity .22s;
}
.sla-body-in { overflow: hidden; }
.sla-row.is-open .sla-body { grid-template-rows: minmax(0, 1fr); opacity: 1; }

.sla-meta {
  display: grid; gap: var(--space-md) var(--space-xl);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  padding-bottom: var(--space-md);
}
.sla-lbl {
  display: block; margin-bottom: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  color: var(--sab-grey-500);
}

/* <ol> — the base reset only clears <ul>, so browser markers would double up
   with the counter below */
.sla-steps {
  list-style: none; padding: 0; margin: 10px 0 var(--space-lg);
  counter-reset: s;
}
.sla-steps li {
  position: relative; padding: 0 0 14px 40px;
  font-size: 15px; line-height: 1.6; color: var(--text-muted);
}
.sla-steps li::before {
  counter-increment: s; content: counter(s);
  position: absolute; left: 0; top: -1px;
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 700; color: #fff; background: var(--accent);
}
/* the rail — connects the steps, stops short of the last marker */
.sla-steps li:not(:last-child)::after {
  content: ''; position: absolute; left: 11px; top: 26px; bottom: 4px;
  width: 2px; background: var(--border-soft);
}

/* case stills */
.case-media img { object-fit: cover; }

/* ============================================================================
   CLIENT MARQUEES
   Two rows travelling in opposite directions. The list is duplicated in the
   markup so a -50% translate loops with no seam. Pauses on hover so a name
   can actually be read, and stops entirely under reduced motion.
   ============================================================================ */
.clients { margin-top: var(--space-2xl); display: grid; gap: var(--space-lg); }
.mq { overflow: hidden; }
.mq-label {
  display: block; font-size: 13px; font-weight: 700;
  color: var(--text-muted); margin-bottom: 12px;
}
.mq-track { display: flex; width: max-content; animation: mq-l 46s linear infinite; }
.mq-track[data-dir="r"] { animation-name: mq-r; animation-duration: 38s; }
.mq-track ul { display: flex; gap: 10px; padding-right: 10px; }
.mq-track li {
  font-size: 15px; font-weight: 600; white-space: nowrap;
  border: 1px solid var(--border-soft); padding: 9px 16px;
}
@keyframes mq-l { to { transform: translateX(-50%); } }
@keyframes mq-r { from { transform: translateX(-50%); } to { transform: none; } }
@media (hover: hover) { .mq:hover .mq-track { animation-play-state: paused; } }
@media (prefers-reduced-motion: reduce) {
  .mq-track { animation: none; }
  .mq { overflow-x: auto; }
}

/* ---- case tiles are now buttons ---- */
.case { cursor: pointer; }
.case-cta {
  display: inline-block; margin-top: 12px;
  font-size: 13px; font-weight: 700; color: var(--accent);
}
@media (hover: hover) and (pointer: fine) {
  .case:hover .case-cta { text-decoration: underline; }
  .case:hover .case-media img { opacity: .9; }
}
.case-media img { transition: opacity var(--dur-fast) var(--ease-out); }

/* ---- scope / SLA launchers ---- */
.doc-cards {
  margin-top: var(--space-2xl);
  display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.doc-card {
  text-align: left; padding: var(--space-lg);
  border: 1px solid var(--border-default);
  border-top: 5px solid var(--ddb, var(--border-default));
  background: var(--bg-page);
  display: grid; gap: 10px;
  /* title, body, then a flexible row — so the CTA sits on the card's floor
     rather than wherever its paragraph happens to end. One card's copy wraps
     to two lines and the other's doesn't, which was knocking them out of line
     with each other. */
  grid-template-rows: auto auto 1fr;
  transition: border-color var(--dur-fast) var(--ease-out),
              transform 160ms var(--ease-out);
}
.doc-card:active { transform: scale(.99); }
@media (hover: hover) and (pointer: fine) {
  .doc-card:hover { border-color: var(--accent); }
}
.doc-card .btn-solid { margin-top: 6px; align-self: end; justify-self: start; }

/* ---- production houses ---- */
.house-grid {
  margin-top: var(--space-2xl);
  display: grid; gap: var(--space-xl);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.house-logo { height: 34px; width: auto; margin-bottom: var(--space-sm); }
.house h3 { margin-bottom: 8px; }
.house-reel {
  margin-top: var(--space-md); aspect-ratio: 16/9;
  background: #000; border-radius: var(--radius-sm); overflow: hidden;
}
.house-reel iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ============================================================================
   OVERLAY
   ============================================================================ */
.ov { position: fixed; inset: 0; z-index: 300; }
.ov-scrim {
  position: absolute; inset: 0; background: rgba(0,0,0,.55);
  opacity: 0; transition: opacity 240ms var(--ease-out);
}
.ov.is-open .ov-scrim { opacity: 1; }
.ov-panel {
  position: absolute; inset: 0 0 0 auto;
  width: min(880px, 100%); background: var(--bg-page);
  overflow-y: auto; overscroll-behavior: contain;
  padding: var(--space-2xl) clamp(24px, 5vw, 64px) var(--space-3xl);
  transform: translateX(3%); opacity: 0;
  transition: transform 320ms var(--ease-out), opacity 240ms var(--ease-out);
}
.ov.is-open .ov-panel { transform: none; opacity: 1; }
/* ---- full-bleed variant, work cases only ----
   A case is something you look at, so it takes the whole screen. Scope, SLA and
   bios keep the side panel — they are documents, and a reading column is right
   for them. Same dialog, same focus and escape rules; only the frame changes. */
.ov--full .ov-panel {
  inset: 0; width: 100%;
  padding: 0 0 var(--space-3xl);
}
.ov--full .ov-close {
  position: fixed; top: 14px; right: 18px; float: none;
  width: 44px; height: 44px; display: grid; place-items: center;
  color: #fff; background: rgba(20,18,18,.5); backdrop-filter: blur(6px);
  z-index: 3;
}
/* the writing below the hero still needs a reading measure — full bleed is for
   the imagery, not for 90-character lines of body copy */
.ov--full .ov-cols,
.ov--full .ov-film,
.ov--full .ov-stills {
  max-width: 1100px; margin-inline: auto;
  padding-inline: clamp(24px, 5vw, 64px);
}
.ov--full .ov-hero { margin: 0 0 var(--space-2xl); min-height: min(78vh, 760px); }
.ov--full .ov-hero-in { max-width: 100%; }
.ov--full .ov-hero-title { font-size: clamp(34px, 6.4vw, 86px); }

/* ---- moving between cases ----
   Sits at the foot of a case, full width in the full-bleed variant. Two targets
   rather than arrows alone: the title tells you where you are going. */
.case-nav {
  margin-top: var(--space-2xl);
  display: grid; gap: 1px;
  grid-template-columns: 1fr 1fr;
  background: var(--border-soft);
  border-block: 1px solid var(--border-soft);
}
.case-nav-btn {
  display: grid; gap: 6px; align-content: center;
  padding: var(--space-lg) var(--space-md);
  background: var(--bg-page); text-align: left;
  transition: background var(--dur-fast) var(--ease-out),
              transform 160ms var(--ease-out);
}
.case-nav-btn--next { text-align: right; }
.case-nav-dir {
  font-size: 12px; font-weight: 700; letter-spacing: .04em;
  color: var(--accent);
}
.case-nav-title {
  font-size: clamp(17px, 2vw, 24px); font-weight: 700;
  line-height: 1.15; letter-spacing: -.02em;
}
@media (hover: hover) and (pointer: fine) {
  .case-nav-btn:hover { background: var(--bg-surface); }
}
.case-nav-btn:active { transform: scale(.99); }
/* the writing keeps a reading measure in the full-bleed variant, and so should
   this — see the .ov--full rules above */
.ov--full .case-nav { max-width: 1100px; margin-inline: auto; }

/* ---- case hero ----
   Breaks the panel's own padding so the still runs edge to edge, the way a case
   opens on ddb.ae. Negative margins rather than a layout change, so every other
   overlay (scope, SLA, bios) is untouched. */
.ov-hero {
  position: relative; isolation: isolate;
  margin: calc(var(--space-2xl) * -1) calc(clamp(24px, 5vw, 64px) * -1) var(--space-xl);
  min-height: min(58vh, 460px);
  /* centred, the way ddb.ae sets a case title — it reads as a title card rather
     than a caption sitting in the corner of a photograph */
  display: grid; place-items: center;
  padding: var(--space-2xl) clamp(24px, 5vw, 64px);
  text-align: center;
  background-color: var(--ddb-black);
}
.ov-hero-shot {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
}
/* Scrim. Weighted to the CENTRE, because that is where the type sits — the
   original bottom-up gradient was built for a bottom-left title and left
   centred copy stranded on the lightest part of a pale still. */
.ov-hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(64% 56% at 50% 48%,
      rgba(18,16,16,.72) 0%, rgba(18,16,16,.34) 62%, transparent 100%),
    linear-gradient(to top,
      rgba(18,16,16,.52) 0%, rgba(18,16,16,.22) 55%, rgba(18,16,16,.28) 100%);
}
/* measured in em, so it scales WITH the headline. A ch-based cap is unreliable
   for display type — at 86px it was forcing one word per line. */
.ov-hero-in { max-width: 100%; }
.ov-hero-title { max-width: 13em; margin-inline: auto; }
/* uppercase yellow client name — DDB's own treatment over imagery. The site's
   usual eyebrow law (sentence case, .04em) is a light-ground rule; this is the
   agency speaking on its own work. */
.ov-hero-client {
  display: block; margin-bottom: 12px;
  font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--ddb-yellow);
}
.ov-hero-title {
  font-size: clamp(30px, 5.2vw, 62px); font-weight: 700;
  line-height: 1.02; letter-spacing: -.03em; color: #fff;
}
/* The campaign line runs at the SAME size as the title — it is the line the
   work actually ran on, and setting it small made the punchline the caption.
   Weight carries the hierarchy instead: 700 for the campaign name, 400 here. */
/* scoped to .ov-hero to outrank `.ov-body p` further down the file, which is
   (0,1,1) and was silently winning over a bare `.ov-hero-tag` */
.ov-hero .ov-hero-tag {
  margin-top: 18px;
  font-size: clamp(30px, 5.2vw, 62px); font-weight: 400;
  line-height: 1.08; letter-spacing: -.025em;
  color: #fff;
  max-width: 15em; margin-inline: auto;
}

.ov-close {
  position: sticky; top: 0; float: right;
  font-size: 30px; line-height: 1; color: var(--text-muted);
  padding: 4px 8px; z-index: 2;
}
.ov-close:hover { color: var(--text-primary); }
.ov-eyebrow {
  display: block; font-size: 13px; font-weight: 700;
  color: var(--accent); margin-bottom: 10px;
}
.ov-body h2 { max-width: 22ch; }
.ov-body p { font-size: 16px; line-height: 1.75; color: var(--text-muted); margin-top: 12px; }
.ov-sub { margin-top: var(--space-xl); }
.ov-film {
  margin-top: var(--space-lg); aspect-ratio: 16/9;
  background: #000; border-radius: var(--radius-sm); overflow: hidden;
}
.ov-film iframe { width: 100%; height: 100%; border: 0; display: block; }
.ov-cols {
  margin-top: var(--space-xl);
  display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
/* auto-fit collapses the empty track, so a lone column would otherwise run the
   full panel width — far too long a line to read comfortably */
.ov-cols:has(> :only-child) { grid-template-columns: minmax(0, 62ch); }
.ov-stills { margin-top: var(--space-xl); display: grid; gap: var(--space-md); }
.ov-stills img { width: 100%; border-radius: var(--radius-sm); }
/* the reset clears <ul> markers but not <ol> — without this the browser's
   own numbering sits next to the counter and you get '1. 01' */
.ov-list { margin-top: var(--space-md); display: grid; gap: 10px;
  counter-reset: n; list-style: none; padding: 0; }
.ov-list li {
  position: relative; padding-left: 26px;
  font-size: 15px; line-height: 1.6; color: var(--text-muted);
}
.ov-list li::before {
  counter-increment: n; content: counter(n, decimal-leading-zero);
  position: absolute; left: 0; top: .1em;
  font-size: 12px; font-weight: 700; color: var(--accent);
}
.ov-list--tight li { padding-left: 16px; }
.ov-list--tight li::before { content: ''; top: .62em; width: 4px; height: 4px; background: var(--accent); }
.ov-tier { margin-top: var(--space-lg); padding-top: var(--space-md); border-top: 1px solid var(--border-soft); }
.ov-tier-n { font-size: 12px; font-weight: 700; color: var(--accent); }
.ov-tier h4 { font-size: 20px; font-weight: 700; margin: 6px 0 8px; }
.ov-tier-label { display: block; margin-top: 14px; font-size: 13px; font-weight: 700; }
/* the ref / name / quantity row — quantity is the number the client will look
   for first, so it sits on the right where the RFP's QTY column was */
.ov-tier-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.ov-tier-head h4 { margin: 0; flex: 1 1 auto; }
.ov-qty { display: flex; align-items: baseline; gap: 6px; white-space: nowrap; }
.ov-qty b { font-size: 24px; font-weight: 700; color: var(--accent); line-height: 1; }
.ov-qty span { font-size: 12px; color: var(--text-muted); }
.ov-tier > .t-small:first-of-type { margin-top: 8px; }
/* the client's own footnote — set smaller than the scope it qualifies */
.ov-note {
  margin-top: 14px; padding-left: 12px;
  border-left: 2px solid var(--border-soft);
  font-size: 13px; line-height: 1.55; color: var(--text-muted);
}
.ov-uline { margin-top: 14px; text-decoration: underline; }
.ov-slacat { margin-top: var(--space-xl); }
@media (prefers-reduced-motion: reduce) {
  .ov-panel, .ov-scrim { transition: none; }
}

/* ============================================================================
   PEOPLE — departments
   Closed by default. Fifteen cards open on arrival is a wall of faces; the
   point of the section is choosing who to read.
   ============================================================================ */
/* ---- DDB colour, not DDB shape ----
   The palette is p.18; cycling rather than role-coding follows p.32. Each rule
   is set from a --ddb custom property written by js/sections.js, so the cycle
   lives in one place and the CSS never hardcodes a colour.
   These are pale by design — they mark a section as ours without competing
   with SAB red, which stays the only thing that means "act here". */
.pdept { border-top: 5px solid var(--ddb, var(--border-soft)); }
.pdept:last-of-type { border-bottom: 1px solid var(--border-soft); }
.pdept-head {
  display: flex; align-items: baseline; gap: var(--space-md);
  padding-block: var(--space-md);
}
/* the ref number becomes a colour block rather than red type — it is a label,
   not an action, so it should not borrow the accent */
.pdept-num {
  font-size: 12px; font-weight: 700; line-height: 1;
  color: var(--ddb-black); background: var(--ddb, var(--sab-grey-150));
  padding: 7px 9px; align-self: center;
}
.pdept-name { font-size: clamp(22px, 2.6vw, 34px); font-weight: 700; letter-spacing: -.02em; }
.pdept-count { font-size: 13px; color: var(--text-muted); }
/* solid, like the other CTAs — four of them, one per department, so the fill
   still reads as "act here" rather than decoration */
.pdept-toggle {
  margin-left: auto; display: inline-flex; align-items: center; gap: 8px;
}
.pdept-toggle .chev { transition: transform var(--dur-fast) var(--ease-out); }
.pdept.is-open .pdept-toggle .chev { transform: rotate(180deg); }
html[dir="rtl"] .pdept-toggle { margin-left: 0; margin-right: auto; }

/* 0fr→1fr animates height without measuring it. It must be minmax(0, 0fr):
   a bare 0fr can keep the row at its content's min-content height, which
   leaves a dead gap under every closed department. */
.pdept-body {
  display: grid; grid-template-rows: minmax(0, 0fr);
  transition: grid-template-rows 420ms var(--ease-out), opacity 300ms var(--ease-out);
  opacity: 0;
}
.pdept-body > * { overflow: hidden; min-height: 0; }
.pdept.is-open .pdept-body { grid-template-rows: minmax(0, 1fr); opacity: 1; }

.pcard-grid {
  display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  padding-bottom: var(--space-xl);
}
/* The headshots are transparent cutouts with the colour shape baked in, so
   they must sit INSIDE the well whole — object-fit: cover crops the cutout and
   takes the top of people's heads off. contain + padding shows the artwork as
   supplied, which is how it was shot. */
.pcard-photo {
  position: relative;
  aspect-ratio: 4 / 5; background: var(--bg-surface);
  border-radius: var(--radius-sm); overflow: hidden;
}
.pcard-photo img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain; object-position: center bottom;
  padding: 14px 10px 0;
}
.pcard-name { margin-top: 16px; font-size: 18px; font-weight: 700; }
.pcard-role { display: block; margin-top: 4px; font-size: 13px; color: var(--accent); font-weight: 600; }
.pcard-rule { display: block; width: 36px; height: 2px; background: var(--border-default); margin: 14px 0; }
.pcard-bio {
  font-size: 14px; line-height: 1.55; color: var(--text-muted);
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.pcard-more { margin-top: 12px; }

/* ---- 04 DDB Studio ---- */
.studio-card {
  display: grid; gap: var(--space-lg);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  align-items: center; padding-bottom: var(--space-xl);
}
.studio-reel { aspect-ratio: 16/9; background: #000; border-radius: var(--radius-sm); overflow: hidden; }
.studio-reel iframe { width: 100%; height: 100%; border: 0; display: block; }
.studio-logo { height: 30px; width: auto; margin-bottom: var(--space-sm); }
.studio-name { font-size: 22px; font-weight: 700; }
.studio-bio { margin-top: 12px; font-size: 15px; line-height: 1.7; color: var(--text-muted); white-space: pre-line; }

/* portrait inside the bio overlay */
.ov-portrait {
  width: 220px; aspect-ratio: 4/5;
  object-fit: contain; object-position: center bottom;   /* cutout, not a crop */
  padding: 12px 10px 0;
  border-radius: var(--radius-sm); background: var(--bg-surface);
  margin-top: var(--space-lg);
}
