/* ============================================================================
   WARNER BROS. — EDGE OF TOMORROW INDIA CAMPAIGN CASE STUDY
   Four sections, campaign-system led.

   Written mobile-first for real: every rule outside a media query targets a
   ~390px canvas, and larger screens only ever ADD to it through min-width
   blocks. Nothing here is a desktop layout being folded back down.

   Layered on top of style.css, which already supplies the design tokens, the
   topbar/footer chrome, the optional-image loader, the reveal system, the
   .count count-up hook and the .btn set.

   SECTIONS 3-4 (primitives + editorial furniture) intentionally repeat the
   equivalents in casestudy-delhivery.css and casestudy-siemens.css at
   IDENTICAL values, so the three case studies read as one system. They are
   duplicated rather than shared because those files also carry their own
   hero/challenge layouts, which have no business loading here. Siemens' file
   carries a note suggesting a shared casestudy.css once a third study lands —
   this is that third study, and lifting the common 200-odd lines out of all
   three is now worth doing as a separate, testable change. It is deliberately
   NOT done here so that adding this page cannot regress the two live ones.

   COLOUR — one accent, no client note. #b162fe (--primary-red, aliased here
   as --cs-red) carries every eyebrow, index, hairline, button and arrow on
   this page, exactly as it does on the Delhivery, Siemens and AIFF studies.
   This page previously carried a steel blue drawn from the film's key art as
   a secondary note; it was removed because four case studies each borrowing
   their client's colour left the set reading as four different sites rather
   than one portfolio. The client is named in type, not in hue. Do not
   reintroduce a per-client accent here.

     1  Page tokens & gutter
     2  Chrome adjustments
     3  Primitives — ghost, plate, credit
     4  Editorial furniture — eyebrow, headings, lede, meta, copy
     5  Hero
     6  Hero data strip + loop hairline
     7  The assignment — quote, arc, identity
     8  The creative system — source row, chapters, adaptations
     9  Scale — statements
    10  CTA & next
    11  TABLET         min-width: 768px
    12  DESKTOP        min-width: 1024px
    13  LARGE DESKTOP  min-width: 1440px
    14  Reduced motion
   ========================================================================= */

/* --------------------------------------------------------- 1 tokens & gutter */
:root {
  /* Carried straight from the Delhivery and Siemens studies so all three
     pages share one type colour and one hairline weight. --cs-red IS
     --primary-red. */
  --cs-red:    #b162fe;
  --cs-white:  #f7f5f2;   /* warm white */
  --cs-grey:   #a8a5a0;   /* warm light grey */
  --cs-dim:    #6e6b66;
  --cs-line:   rgba(247, 245, 242, .1);
  --cs-line-2: rgba(247, 245, 242, .18);
  --cs-panel:  #101011;

  /* The same red at 42% for hairlines, dividers and rules — anywhere the
     accent has to sit UNDER type rather than beside it. Same name and same
     job as --cs-red-lo on the Delhivery study. */
  --cs-red-lo: rgba(177, 98, 254, .42);

  --cs-space: 5.5rem;     /* 88px — mobile section rhythm */
  --cs-gap:   3.5rem;
  --cs-h1:    2.5rem;     /* 40px — this page's H1 is two lines, so it sits a
                             notch below Siemens' 2.6rem to keep the mobile
                             hero from running past the fold */
  --cs-h2:    1.95rem;
  --cs-h3:    1.45rem;

  /* Hero data-strip figure size. The ONE value each breakpoint sets for that
     strip: the numerals take it directly, the "Pan-India" cell takes half of
     it, and the shared baseline box is .9 of it. Resize this and the whole
     strip stays in proportion and in line — which is the point, because the
     previous arrangement had three separate per-breakpoint declarations and
     one of them going missing is exactly how Pan-India ended up rendering at
     the numerals' size. */
  --fig: 2.9rem;

  /* Adaptation grid base row height. Slots are uniform per shape class; the
     ARTWORK inside them is drawn at each unit's true ratio, which is what
     stops 24 executions reading as an equal grid.

     36vw. Tuned, not guessed: it is the largest value at which the 336x280
     large rectangle still fits the width of a half-row column on a 375px
     screen. Go higher and both rectangles hit max-width and clamp to the
     SAME size, which is the flaw the per-class scaling below exists to fix;
     go much lower and the executions become thumbnails.
     --ad-gap and --ad-pad are not cosmetic: the fit calculation in section 8
     subtracts them to get the usable slot height, so they must be kept in
     step with the gap and padding rules there (and re-declared alongside
     --ad-row in every breakpoint that changes it). */
  --ad-row: 36vw;
  --ad-gap: .7rem;
  --ad-pad: .5rem;

  /* master creative slot ratio. Set here, once, because it is the single
     value most likely to need changing when the real artwork arrives — if the
     masters turn out to be landscape, put 3 / 2 here and nothing else moves. */
  --master-ar: 4 / 5;

  /* 22px of horizontal breathing room on mobile — style.css drops the global
     gutter to 18.4px under 640px, which is tighter than this page wants. */
  --gutter: 1.375rem;
}

/* ------------------------------------------------------- 2 chrome adjustments */
/* style.css makes the topbar transparent under 640px because the homepage hero
   sits behind it. Here it is a plain bar over a plain canvas, so it needs its
   background back. */
@media (max-width: 640px) {
  .topbar { background: var(--background); }
}

.cs-brand { display: flex; align-items: center; gap: .6rem; min-height: 44px; }
.cs-brand__arrow {
  width: 1.3rem; height: .6rem; color: var(--cs-grey);
  transition: transform .3s var(--ease), color .3s var(--ease);
}
.cs-brand:hover .cs-brand__arrow,
.cs-brand:focus-visible .cs-brand__arrow { transform: translateX(-5px); color: var(--cs-red); }

.cs-body { background: var(--background); }
/* NOTE: style.css sets `body { overflow-x: hidden }` sitewide, which is the
   classic way to break a position:sticky descendant. It does not break the
   section 3 master here — verified by probing both `hidden` and `clip` at
   1280px and measuring an identical pinned offset — because the body's
   overflow is propagated to the viewport rather than making the body its own
   scroll container. No override is needed; if a future engine regresses this,
   `.cs-body { overflow-x: clip }` is the one-line fix. */

/* ============================================================= 3 primitives */

/* Placeholder that shows through wherever a frame has not been supplied yet —
   script.js removes the <img> and this is what is left. Identical to the
   Delhivery and Siemens ghosts so a half-populated site stays coherent.
   On this page 27 of the 34 slots are campaign work that has not been supplied
   yet, so the ghost is doing more work here than anywhere else on the site:
   its label is what tells you which execution is missing. */
.cs-ghost {
  position: absolute; inset: 0; z-index: 0;
  display: grid; place-items: center;
  font-family: var(--font-cond); font-weight: 300;
  font-size: clamp(.72rem, 3.1vw, .95rem);
  letter-spacing: .18em; text-transform: uppercase; line-height: 1.7;
  color: rgba(247, 245, 242, .3);
  text-align: center;
  background:
    radial-gradient(130% 110% at 74% 8%, rgba(177, 98, 254, .16), transparent 64%),
    linear-gradient(158deg, #17171a, #0b0b0c 60%, #121214);
  pointer-events: none;
}

/* plate — a bare bordered frame. Every image on this page is either film
   photography or campaign artwork, so there is no browser chrome anywhere. */
.cs-plate {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--cs-line);
  background: var(--cs-panel);
  box-shadow: 0 30px 58px -32px rgba(0, 0, 0, .85);
}
.cs-plate picture { position: absolute; inset: 0; z-index: 1; }
.cs-plate img { width: 100%; height: 100%; object-fit: cover; object-position: var(--pos, center); }

/* Provenance line. Every piece of official Warner Bros. artwork on this page
   carries one; campaign work never does. Small, italic, dim — it should read
   as a museum wall label, not a disclaimer banner, but it must always be
   legible. Do not lower this contrast. */
.cs-credit {
  display: block;
  margin-top: .55rem;
  font-family: var(--font-cond); font-weight: 300; font-style: italic;
  font-size: .64rem; letter-spacing: .1em;
  color: var(--cs-dim);
}
.cs-credit--block {
  margin-top: 1.5rem;
  padding-left: .85rem;
  border-left: 1px solid var(--cs-line-2);
  font-size: .72rem; line-height: 1.65; letter-spacing: .04em;
  color: var(--cs-grey);
  max-width: 56ch;
}

/* ================================================== 4 editorial furniture */
.cs-sec {
  padding-block: var(--cs-space);
  border-top: 1px solid var(--cs-line);
}
.cs-sec__head { margin-bottom: 2.75rem; }

.cs-eyebrow {
  display: flex; align-items: center; gap: .8rem;
  margin-bottom: 1.35rem;
  font-family: var(--font-cond); font-weight: 500;
  font-size: .68rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--cs-red);
}
.cs-eyebrow__rule { width: 1.6rem; height: 1px; background: var(--cs-red); flex: none; }

.cs-h1, .cs-h2, .cs-h3 {
  color: var(--cs-white);
  font-family: var(--font-cond); font-weight: 400;
  letter-spacing: -.012em;
  text-wrap: balance;
}
/* No max-width in ch here, unlike Siemens: both headlines on this page carry
   an author-placed <br>, and a ch cap on top of that produced a ragged three-
   line first half on a phone. The line breaks are the constraint. */
.cs-h1 { font-size: var(--cs-h1); line-height: 1.06; }
.cs-h2 { font-size: var(--cs-h2); line-height: 1.14; }
.cs-h3 { font-size: var(--cs-h3); line-height: 1.2; max-width: 24ch; }

.cs-lede {
  margin-top: 1.35rem;
  font-size: 1rem; line-height: 1.7;
  color: var(--cs-grey);
  max-width: 48ch;
}

.cs-copy > p + p { margin-top: 1.1rem; }
.cs-copy p {
  font-size: 1rem; line-height: 1.7;
  color: var(--cs-grey);
  max-width: 50ch;
}

.cs-meta {
  display: grid; gap: 1.35rem;
  margin-top: 2.5rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--cs-line);
}
.cs-meta dt {
  font-family: var(--font-cond); font-weight: 500;
  font-size: .62rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cs-dim);
  margin-bottom: .45rem;
}
.cs-meta dd {
  font-family: var(--font-cond); font-weight: 300;
  font-size: .95rem; letter-spacing: .02em; line-height: 1.5;
  color: var(--cs-white);
}

/* ================================================================== 5 hero */
/* Full-bleed official key art with the copy sitting on it. The section is the
   stacking context; the media is pinned behind and the shell rides on top. */
.cs-hero {
  position: relative;
  isolation: isolate;
  display: flex; align-items: flex-end;
  min-height: 88vh;
  padding-block: 6rem 3rem;
  overflow: hidden;
}
/* svh where supported: on mobile browsers vh includes the retracting URL bar,
   which makes the hero taller than the screen on first paint. */
@supports (height: 1svh) { .cs-hero { min-height: 88svh; } }

.cs-hero__media { position: absolute; inset: 0; z-index: -2; }
.cs-hero__media picture { position: absolute; inset: 0; }
.cs-hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: 72% center; }

/* Two scrims, not one. The vertical pass buys legibility for the copy block;
   the horizontal pass keeps the frame's right side readable as an image
   instead of flattening the whole thing to grey. The chosen frame puts both
   leads on the right, which is why the horizontal scrim runs left-to-right. */
.cs-hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(to top,
      #070707 0%, rgba(7, 7, 7, .95) 20%, rgba(7, 7, 7, .66) 50%,
      rgba(7, 7, 7, .4) 78%, rgba(7, 7, 7, .52) 100%),
    linear-gradient(to right, rgba(7, 7, 7, .84) 0%, rgba(7, 7, 7, .3) 56%, transparent 100%);
}

/* Slow scale on load — the film-frame settle. 2.6s, once, then it rests. The
   same gesture the Siemens hero uses, at the same values. Started by CSS
   rather than JS because there is nothing to wait for. */
.cs-hero__media img { animation: cs-settle 2.6s var(--ease-out) both; }
@keyframes cs-settle { from { transform: scale(1.07); } to { transform: scale(1); } }

.cs-hero__inner { position: relative; z-index: 1; width: 100%; }

/* A hairline under the eyebrow rather than a coloured word, so the accent
   registers as a mark and the label stays plain type. */
.cs-hero__eyebrow .cs-eyebrow__rule { background: var(--cs-red); }

.cs-hero .cs-lede { max-width: 46ch; }
/* the film title is italicised inline; Oswald has no true italic, so the
   synthesised slant is left to the body face where it actually exists */
.cs-lede i, .cs-copy i { font-style: italic; }

/* ================================================ 6 hero data strip + loop */
/* Editorial figures on a hairline, deliberately NOT dashboard cards: no
   panels, no borders around each number, no icons. Every figure here is one
   of the four verified facts about the project. */
.wb-data {
  margin-top: 3rem;
}
.wb-data__row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.75rem 1.25rem;
  padding-bottom: 1.75rem;
}
.wb-data__cell { display: grid; gap: .4rem; align-content: start; }

/* The figure. Both its size and the word cell's derive from --fig, and every
   breakpoint sets ONLY --fig — see the note on that token in section 1.

   min-height + flex-end is what puts all four figures on one baseline. Each
   cell is its OWN grid, so `align-self: end` on the word could never reach
   across to the numerals' row; it aligned within a row that was exactly its
   own height, which is to say it did nothing. Giving every figure the same
   minimum box and bottom-aligning inside it lines up the four baselines, and
   therefore the four labels underneath them, whatever sizes are in play. */
.wb-data__fig {
  display: flex; align-items: flex-end;
  min-height: calc(var(--fig) * .9);    /* .9 = the line-height below */
  font-family: var(--font-cond); font-weight: 400;
  font-size: var(--fig); line-height: .9; letter-spacing: -.02em;
  color: var(--cs-white);
  font-variant-numeric: tabular-nums;   /* the count-up must not reflow */
}
/* The word cell — set smaller than the raw counts, because "Pan-India" is a
   place, not a quantity, and matching the numerals' size would dress it as
   one.

   Selector is DOUBLED on purpose. `.wb-data__fig--word` alone has the same
   specificity as `.wb-data__fig`, so a later breakpoint resizing the base
   figure silently beat it: at 1440 the 6rem base won, Pan-India rendered at
   96px, wrapped to two lines and dragged its label 87px below the other
   three. Deriving from --fig removes the per-breakpoint overrides that caused
   it, but keep the doubled form anyway — it is the guard. */
.wb-data__fig.wb-data__fig--word {
  font-size: calc(var(--fig) * .5);
  letter-spacing: .01em; text-transform: uppercase;
}
.wb-data__lbl {
  font-family: var(--font-cond); font-weight: 300;
  font-size: .66rem; letter-spacing: .18em; text-transform: uppercase;
  line-height: 1.5;
  color: var(--cs-dim);
}

/* LOOP MOTIF, 1 of 2.
   A hairline that fills, resets and fills again — three iterations, one per
   master direction, then it rests. This is the film's time loop stated once,
   quietly, and then dropped: no glitching, no flashing, no repetition for the
   rest of the visit. The base rule stays; only the red fill animates. */
.wb-loop {
  position: relative;
  height: 1px;
  background: var(--cs-line);
  overflow: hidden;
}
.wb-loop i {
  position: absolute; inset: 0 auto 0 0;
  display: block; width: 0;
  background: linear-gradient(90deg, transparent, var(--cs-red));
  animation: wb-loop 2.9s var(--ease-out) 3 both;
}
@keyframes wb-loop {
  0%   { width: 0;    opacity: 0; }
  12%  { opacity: 1; }
  76%  { width: 100%; opacity: 1; }
  100% { width: 100%; opacity: 0; }
}

/* ==================================================== 7 the assignment */
/* The pull quote. This is the page's one raised voice, so it is the one
   place the accent carries a whole element. */
.wb-quote {
  margin: 3rem 0 0;
  padding-left: 1.15rem;
  border-left: 2px solid var(--cs-red);
  font-family: var(--font-cond); font-weight: 300;
  font-size: 1.35rem; line-height: 1.4; letter-spacing: -.005em;
  color: var(--cs-white);
  max-width: 30ch;
  text-wrap: balance;
}

/* The three beats. Type and hairlines only — the brief explicitly rules out
   boxed process cards, and a numbered editorial line says the same thing in
   a third of the space. */
.wb-arc {
  display: grid; gap: .1rem;
  margin-top: 3.25rem;
  border-top: 1px solid var(--cs-line);
}
.wb-arc__beat {
  display: flex; align-items: baseline; gap: .9rem;
  padding-block: .9rem;
  border-bottom: 1px solid var(--cs-line);
  font-family: var(--font-cond); font-weight: 300;
  font-size: 1.05rem; letter-spacing: .02em;
  color: var(--cs-white);
}
.wb-arc__beat span {
  flex: none;
  font-size: .66rem; font-weight: 500; letter-spacing: .2em;
  color: var(--cs-red);
}

.wb-identity { margin-top: 3rem; }
.wb-identity__plate { aspect-ratio: 16 / 10; }
.wb-identity__cap { margin-top: 1rem; }
.wb-identity__cap b {
  display: block;
  margin-bottom: .35rem;
  font-family: var(--font-cond); font-weight: 500;
  font-size: .62rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cs-white);
}
.wb-identity__cap > span {
  display: block;
  font-size: .88rem; line-height: 1.6;
  color: var(--cs-grey);
  max-width: 44ch;
}

/* ============================================ 8 the creative system */

/* The supplied material — three official film frames, fenced by a label above
   and a credit below so the boundary between studio artwork and campaign work
   is visible rather than asserted. */
.wb-source { margin-top: 3.5rem; }
.wb-source__lbl {
  margin-bottom: 1rem;
  font-family: var(--font-cond); font-weight: 500;
  font-size: .62rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cs-dim);
}
.wb-source__row { display: grid; gap: .75rem; }
.wb-source__plate { aspect-ratio: 16 / 9; }

/* ---- chapters -------------------------------------------------------- */
/* One structure, run three times. The repetition IS the point: the film's
   loop is expressed by the page returning to the same shape rather than by
   any effect playing on screen. */
.ch { margin-top: 4.5rem; }

.ch__head {
  display: flex; align-items: center; gap: 1.1rem;
  margin-bottom: 1.75rem;
}
.ch__index {
  display: flex; align-items: baseline; gap: .6rem;
  flex: none;
  margin: 0;
}
.ch__word {
  font-family: var(--font-cond); font-weight: 500;
  font-size: .66rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--cs-dim);
}
/* The chapter numbers. Small, repeated, quiet. */
.ch__num {
  font-family: var(--font-cond); font-weight: 400;
  font-size: 1.9rem; line-height: 1; letter-spacing: -.01em;
  color: var(--cs-red);
  font-variant-numeric: tabular-nums;
}

/* LOOP MOTIF, 2 of 2.
   The rule redraws itself at the head of every chapter — the same gesture,
   three times, on scroll. It rides the sitewide reveal class rather than
   shipping its own observer, so it costs nothing extra in JS and inherits the
   reduced-motion behaviour for free. */
.ch__rule {
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, var(--cs-red-lo), var(--cs-line));
  transform: scaleX(0);
  transform-origin: left center;
}
.js .ch__head[data-reveal] .ch__rule {
  transition: transform 1.5s var(--ease-out) 220ms;
}
.js .ch__head[data-reveal].is-in .ch__rule { transform: scaleX(1); }
/* without JS the reveal class never lands, so the rule must start drawn */
html:not(.js) .ch__rule { transform: scaleX(1); }

.ch__grid { display: grid; gap: 2rem; }

.ch__plate { aspect-ratio: var(--master-ar); }
.ch__cap {
  margin-top: .85rem;
  font-family: var(--font-cond); font-weight: 300;
  font-size: .66rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--cs-dim);
}

/* Expertise callouts as side notes beside the master artwork — editorial
   annotations, not a row of service cards. A single hairline on the inline
   start edge is the whole treatment. */
.ch__note {
  margin-top: 1.75rem;
  padding-left: 1rem;
  border-left: 1px solid var(--cs-red-lo);
}
.ch__note b {
  display: block;
  margin-bottom: .45rem;
  font-family: var(--font-cond); font-weight: 500;
  font-size: .66rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cs-white);
}
.ch__note span {
  display: block;
  font-size: .88rem; line-height: 1.6;
  color: var(--cs-grey);
  max-width: 38ch;
}
.ch__note--close {
  margin-top: 4rem;
  padding-top: 0;
}

/* the 01-08 marker above each set — the count that resets every chapter */
.ch__count {
  display: flex; align-items: center; gap: .8rem;
  margin-bottom: 1rem;
  font-family: var(--font-cond); font-weight: 300;
  font-size: .62rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cs-dim);
}
.ch__count i { flex: 1 1 auto; height: 1px; background: var(--cs-line); }

/* ---- the adaptations ------------------------------------------------- */
/* Uniform SLOTS, non-uniform ARTWORK. Each slot is a plain dark cell on the
   grid; the execution inside it is drawn at that format's true aspect ratio
   and scaled to fit. A 3:1 wide banner therefore reads short and wide and a
   1:3 vertical banner tall and narrow, inside identical cells.

   This is the only honest way to show eight wildly different ad formats
   together — you cannot put a 3:1 and a 1:3 at the same scale in one row
   without one of them becoming unusable — and it is what stops twenty-four
   executions reading as an equal-size grid. The two-column and two-row spans
   below give the wide and tall formats the room their shapes need. */
/* Two columns at every width. The eight units pair off by shape on their own
   — the two rectangles sit together, the two skyscrapers sit together, and
   each of the four banners takes a full-width band — so the grid needs no
   column-count changes and no dense packing to read as a considered layout.
   Rows are auto-sized; each slot states its own height instead. */
.ch__adapts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ad-gap);
  align-items: start;
}
.ad {
  display: flex; flex-direction: column; min-width: 0;
  --slot-box: var(--ad-row);
}
/* the four banner units — far too wide to sit in half a row */
.ad--band { grid-column: 1 / -1; --slot-box: calc(var(--ad-row) * .52); }
/* the two skyscrapers — 600px tall in spec, so they get a double-height slot */
.ad--tall { --slot-box: calc(var(--ad-row) * 2 + var(--ad-gap)); }

.ad__slot {
  height: var(--slot-box);
  display: grid; place-items: center;
  overflow: hidden;         /* safety net against sub-pixel rounding only */
  padding: var(--ad-pad);
  border: 1px solid var(--cs-line);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .022), transparent 60%),
    var(--cs-panel);

  /* usable height inside the slot, computed rather than measured */
  --slot-h: calc(var(--slot-box) - 2 * var(--ad-pad) - 2px);
}

/* The artwork itself, drawn from its real spec (--w x --h, unitless spec
   pixels supplied by the markup).

   Each SHAPE CLASS is internally true-to-scale: within a class every unit is
   sized against the largest member of that class, so the 728x90 leaderboard
   really is three quarters the width of the 970x90, and the 300x250 medium
   rectangle really is smaller than the 336x280 large rectangle. Without this
   the two rectangles rendered pixel-identical and the 320x50 mobile banner
   came out WIDER than the 970x90 leaderboard — both measured, both absurd.

   The classes are scaled independently of one another rather than all sharing
   one multiplier, because a single multiplier across all eight is set by the
   970px leaderboard and would shrink a 300x250 rectangle to about 96x80 on a
   phone. Section 2 is where all eight are compared at one true scale; this
   grid is the showcase, so each execution is shown as large as its row allows.

   Height always comes from aspect-ratio, never from a second definite value —
   see the note in section 3 of this file about why max-height cannot do it. */
.ad__fit {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: var(--w) / var(--h);
  max-width: 100%;
  background: #0a0a0b;
  box-shadow: 0 10px 22px -14px rgba(0, 0, 0, .9);
}
/* rectangles — height-bound, scaled against the 280px-tall large rectangle */
.ad__fit { width: calc(var(--slot-h) * var(--w) / 280); }
/* skyscrapers — height-bound, scaled against their shared 600px height */
.ad--tall .ad__fit { width: calc(var(--slot-h) * var(--w) / 600); }

/* BANNERS, PHONE: fill the band instead of holding scale against the 970px
   leaderboard. On a 375px screen the band is about 313px wide, and a true
   970-relative 320x50 mobile banner works out 103x16 — too small to read as
   anything. Legibility wins at this width; the true cross-unit comparison is
   section 2's job and it survives there at every size. The min() keeps the
   tallest banner inside its slot. */
.ad--band .ad__fit { width: min(100%, calc(var(--slot-h) * var(--w) / var(--h))); }
.ad__fit picture { position: absolute; inset: 0; z-index: 1; }
.ad__fit img { width: 100%; height: 100%; object-fit: cover; }
/* the ghost label inside an adaptation slot is small, so it loses the
   generous tracking the full-size ghost carries */
.ad__fit .cs-ghost { font-size: clamp(.5rem, 1.9vw, .62rem); letter-spacing: .12em; }

.ad__cap {
  flex: none;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: .15rem .5rem;
  margin-top: .55rem;
  font-family: var(--font-cond); font-weight: 300;
  font-size: .62rem; letter-spacing: .13em; text-transform: uppercase;
  color: var(--cs-grey);
}
.ad__cap b {
  font-weight: 500;
  color: var(--cs-dim);
  font-variant-numeric: tabular-nums;
}
/* the real pixel spec, set quieter than the unit name so the caption reads
   "name, then size" rather than as two competing labels */
.ad__cap span {
  color: var(--cs-dim);
  letter-spacing: .1em;
  font-variant-numeric: tabular-nums;
}

/* ============================================================== 9 scale */
/* The four statements — identical treatment to the Siemens outcome list, so
   the two studies close the same way. */
.out__list {
  display: grid;
  margin-top: 3.5rem;
  border-top: 1px solid var(--cs-line);
}
.out__item {
  display: flex; align-items: baseline; gap: 1.1rem;
  padding-block: 1.35rem;
  border-bottom: 1px solid var(--cs-line);
}
.out__num {
  flex: none;
  font-family: var(--font-cond); font-weight: 400;
  font-size: .68rem; letter-spacing: .2em;
  color: var(--cs-red);
}
.out__stmt {
  font-family: var(--font-cond); font-weight: 300;
  font-size: 1.3rem; line-height: 1.3; letter-spacing: -.005em;
  color: var(--cs-white);
  text-wrap: balance;
}

/* ==================================================== 10 CTA & next */
/* Closing action — two links, no headline. The block carries no rule of its
   own: the outcome list above already ends on a hairline and .cs-next below
   opens with one, so a third here just crowds them. Values match the AIFF
   study so all the case studies end identically.
   There were .cs-cta__title and .cs-cta__line rules here for a "Have a
   campaign that needs to work everywhere? / Start a Project" pitch. Both the
   markup and the rules were deleted: the site documents work done in
   full-time roles and does not solicit projects. */
.cs-cta { margin-top: 3rem; }
.cs-cta__actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: .7rem 1.1rem;
}
/* page-scoped touch-target floor: the shared .btn lands at 40px on a phone,
   and raising it in style.css would move every button on every page */
.cs-cta__actions .btn { min-height: 44px; }

.cs-next {
  margin-top: 4.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--cs-line);
}
.cs-next__label {
  font-family: var(--font-cond); font-weight: 500;
  font-size: .62rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cs-dim);
  margin-bottom: .5rem;
}
.cs-next__link {
  display: flex; align-items: center; justify-content: space-between; gap: 1.25rem;
  min-height: 44px;   /* touch target */
  font-family: var(--font-cond); font-weight: 400;
  font-size: 1.5rem; letter-spacing: -.005em;
  color: var(--cs-white);
  transition: color .3s var(--ease);
}
.cs-next__link .arrow { width: 2.1rem; color: var(--cs-red); }
.cs-next__link:hover, .cs-next__link:focus-visible { color: var(--cs-red); }
.cs-next__link:hover .arrow { transform: translateX(6px); }

/* Reveals are entirely style.css's: `.js [data-reveal]` / `.is-in` there
   already carry the fade-and-rise, the --d delay hook and the no-JS safety of
   being scoped to .js. This page only uses the attributes. */


/* ============================================================================
   11  TABLET — min-width: 768px
   ========================================================================= */
@media (min-width: 768px) {
  :root {
    --gutter: 2.25rem;
    --cs-space: 7rem;
    --cs-gap: 5rem;
    --cs-h1: 3.4rem;
    --cs-h2: 2.6rem;
    --cs-h3: 1.85rem;
    --ad-row: 170px;      /* same reasoning as the mobile value */
    --ad-gap: 1rem;
  }

  .cs-hero { min-height: 82vh; padding-block: 7rem 4rem; }
  @supports (height: 1svh) { .cs-hero { min-height: 82svh; } }

  /* Client / Campaign / Project Type are short; My Role is a four-part
     string, so it takes the remaining track instead of a quarter of it. */
  /* Five fields, four tracks. Client / Campaign / Project Type / My Role fill
     row one and Completed Through drops to row two on its own. Deliberately
     NOT five across: My Role is a four-part string and a fifth track squeezes
     it into an unreadable column at this width. */
  .cs-meta {
    grid-template-columns: auto auto auto minmax(0, 1fr);
    gap: 2rem;
  }
  .cs-lede { font-size: 1.05rem; }

  .wb-data__row { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.5rem; }
  :root { --fig: 3.6rem; }

  .wb-quote { font-size: 1.5rem; padding-left: 1.4rem; }
  .wb-arc { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 2rem; }
  .wb-arc__beat { border-bottom: 0; }

  .wb-identity__plate { aspect-ratio: 21 / 9; }

  .wb-source__row { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; }

  /* From here the band is wide enough for the small units to survive being
     held at true scale against the 970px large leaderboard, so they are —
     see the phone-width note on this rule in section 8. */
  .ad--band .ad__fit { width: calc(var(--w) / 970 * 100%); }

  .ch__num { font-size: 2.4rem; }

  .out__stmt { font-size: 1.75rem; }
  .out__item { gap: 1.6rem; padding-block: 1.75rem; }


  .cs-next__link { font-size: 2rem; justify-content: flex-start; }
}


/* ============================================================================
   12  DESKTOP — min-width: 1024px
   ========================================================================= */
@media (min-width: 1024px) {
  :root {
    /* style.css narrows the shell to 900px under `max-width: 1024px`, which
       overlaps this block at exactly 1024 and would otherwise leave the
       desktop layout ~100px narrower than it is designed for. Reclaim the
       site's wide shell from here up — a campaign page needs the width. */
    --shell: 1480px;

    --gutter: 3rem;
    --cs-space: 9.5rem;
    --cs-gap: 8rem;
    --cs-h1: 4.2rem;
    --cs-h2: 3.2rem;
    --cs-h3: 2.2rem;
    /* Taller rows than tablet, not shorter, because from here up the grid
       shares the row with the master and drops to two columns — see the
       .ch__adapts rule below for why. */
    --ad-row: 200px;
    --ad-gap: 1.25rem;
  }

  /* ---- hero ------------------------------------------------------------ */
  .cs-hero { min-height: min(92vh, 860px); padding-block: 9rem 4.5rem; }
  @supports (height: 1svh) { .cs-hero { min-height: min(92svh, 860px); } }
  /* the copy occupies the left half of the frame; the right half stays image */
  .cs-hero__copy { max-width: 62%; }
  .cs-hero .cs-lede { font-size: 1.15rem; max-width: 44ch; }

  /* Meta stays four tracks here, with Completed Through wrapping to its own
     row — the shell is width-capped by the viewport until 1440, and a fifth
     track at 1025 leaves My Role a 168px column that breaks its four-part
     string over four lines. It goes five-across in the 1440 block instead. */

  .wb-data { margin-top: 4.5rem; }
  .wb-data__row { gap: 2rem; padding-bottom: 2.25rem; }
  :root { --fig: 5rem; }
  .wb-data__lbl { font-size: .7rem; }

  /* ---- section heads: heading left, paragraph right -------------------- */
  /* the eyebrow spans both columns so the heading and its copy start on the
     same line beneath it */
  .cs-sec__head--split {
    display: grid;
    grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
    column-gap: clamp(3rem, 6vw, 7rem);
    align-items: start;
  }
  .cs-sec__head--split .cs-eyebrow { grid-column: 1 / -1; }
  .cs-sec__head--split .cs-h2 { grid-column: 1; }
  .cs-sec__head--split .cs-copy,
  .cs-sec__head--split .cs-lede {
    grid-column: 2;
    margin-top: .55rem;   /* optically level with the heading's first line */
    max-width: 42ch;
  }

  /* ---- the assignment -------------------------------------------------- */
  .wb-quote { font-size: 2.1rem; padding-left: 1.75rem; max-width: 34ch; margin-top: 4rem; }
  .wb-arc { margin-top: 4.5rem; }
  .wb-arc__beat { font-size: 1.2rem; padding-block: 1.1rem; }
  .wb-identity { margin-top: 4rem; }
  .wb-identity__cap {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    column-gap: 3rem;
    margin-top: 1.35rem;
  }
  .wb-identity__cap b { grid-column: 1; }
  .wb-identity__cap > span { grid-column: 2; grid-row: 1 / span 2; font-size: .95rem; }
  .wb-identity__cap .cs-credit { grid-column: 1; margin-top: 0; }
  .wb-fmt { gap: 1.5rem; }

  /* ---- the creative system --------------------------------------------- */
  .wb-source { margin-top: 4.5rem; }
  .ch { margin-top: 7rem; }
  .ch__head { margin-bottom: 2.5rem; gap: 1.6rem; }
  .ch__num { font-size: 3.2rem; }

  /* The master creative pins while its eight executions scroll past it. That
     difference in behaviour — one thing held, many things moving — is what
     communicates the hierarchy between a master and its adaptations without
     labelling it.

     `top` clears nothing in particular: this page's topbar is static, not
     fixed, so the offset is purely breathing room. If sticky is ever
     unavailable the master simply sits at the top of its column, which is
     still the intended composition, so nothing here is load-bearing. */
  .ch__grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: clamp(2.5rem, 4vw, 4.5rem);
    align-items: start;
  }
  .ch__master { position: sticky; top: 5rem; }

  /* TWO columns here, not the four the tablet grid uses — this is a reduction
     on purpose. From this breakpoint the grid no longer spans the page; it
     shares the row with the master and gets 7 of 12 columns. Four executions
     across that leaves each one about 150px wide, which is the "tiny poster
     thumbnail" the brief rules out, and it also stacks into only three rows —
     measured shorter than the master column, so the sticky master had zero
     travel and simply never pinned.

     Two columns fixes both: each execution lands near 320px, and six rows
     make the grid roughly 600px taller than the master, which is the scroll
     distance the pinned artwork needs to read as pinned. Hierarchy is kept by
     area rather than by column count — the master plate is over four times
     the size of any single execution beside it. */
  .ch__adapts { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .ch__note { margin-top: 2.25rem; padding-left: 1.25rem; }
  .ch__note span { font-size: .95rem; }
  .ch__note--close { margin-top: 6rem; max-width: 52ch; }

  /* ---- scale ------------------------------------------------------------ */
  .cs-sec__head--split .cs-copy { margin-top: .55rem; }

  .out__stmt { font-size: 2.3rem; }
  .out__item { padding-block: 2rem; gap: 2.25rem; }


  .cs-cta { margin-top: 4.5rem; }
  .cs-next { margin-top: 7rem; }
  .cs-next__link { font-size: 2.75rem; }
}


/* ============================================================================
   13  LARGE DESKTOP — min-width: 1440px
   ========================================================================= */
@media (min-width: 1440px) {
  :root {
    --gutter: 4rem;
    --cs-space: 11.5rem;
    --cs-gap: 10rem;
    --cs-h1: 5rem;
    --cs-h2: 3.9rem;
    --cs-h3: 2.6rem;
    /* must stay ABOVE the 1024 value — an earlier 180px here was below it and
       made the executions shrink as the screen grew */
    --ad-row: 240px;
    --ad-gap: 1.25rem;
  }

  .cs-hero__copy { max-width: 56%; }

  /* Only here does the shell reach its full 1480 and the fifth meta field fit
     on the row: the four fixed tracks plus gaps take ~750px, leaving My Role
     ~566px for a string that needs 479. Below this it wraps — see the note in
     the 1024 block. */
  .cs-meta { grid-template-columns: auto auto auto minmax(0, 1fr) auto; }

  :root { --fig: 6rem; }
  .wb-quote { font-size: 2.5rem; }
  .out__stmt { font-size: 2.8rem; }
  .cs-next__link { font-size: 3.2rem; }
}


/* ============================================================================
   14  REDUCED MOTION
   The hero settles instantly, the loop hairline never runs, the chapter rules
   render already drawn and the strip stops smooth-scrolling. The format strip
   itself keeps working — it is an interaction, not an animation, and removing
   it would remove content. (script.js already renders the .count figures at
   their final value under this query.)
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .cs-hero__media img { animation: none; }
  .wb-loop i { animation: none; width: 100%; opacity: .5; }
  .js .ch__head[data-reveal] .ch__rule { transition: none; }
  .ch__rule { transform: scaleX(1); }
  .cs-next__link:hover .arrow { transform: none; }
  .cs-brand:hover .cs-brand__arrow { transform: none; }
}
