@font-face{font-family:'DM Sans';font-style:normal;font-weight:400;font-display:swap;src:url('../assets/fonts/dm-sans-400.woff2') format('woff2');}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:500;font-display:swap;src:url('../assets/fonts/dm-sans-500.woff2') format('woff2');}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:600;font-display:swap;src:url('../assets/fonts/dm-sans-600.woff2') format('woff2');}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:700;font-display:swap;src:url('../assets/fonts/dm-sans-700.woff2') format('woff2');}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:800;font-display:swap;src:url('../assets/fonts/dm-sans-800.woff2') format('woff2');}
:root{
  --purple:#4225A6; --purple-dark:#2E1A7A; --purple-deep:#1a1d23; --purple-night:#111318;
  --magenta:#D51254; --magenta-soft:#F0407E;
  --hl-dark:#C4B5FD;--hl-soft:#DDD6FE; --hl-light:#4225A6;
  --lilac:#F0EEF8; --lilac-2:#EDE9FC; --paper:#FCFBFF;
  --ink:#17123B; --ink-soft:#4A4270;
  --amber:#F4B740; --teal:#12B3A6;
  --hair:rgba(66,37,166,.14);
  --hair-light:rgba(255,255,255,.14);
  --grad-head:linear-gradient(135deg,#4225a6 34%,#6d1f8e 73%,#8b1b7d 93%);
  --shadow:0 24px 60px -28px rgba(21,12,54,.45);
  --shadow-sm:0 10px 30px -18px rgba(21,12,54,.5);
  --ease:cubic-bezier(.22,.61,.36,1);
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
  font-family:'DM Sans',Arial,sans-serif;
  color:var(--ink);
  background:var(--lilac);
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
  line-height:1.5;
}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
.wrap{max-width:1160px;margin:0 auto;padding:0 32px;position:relative}
/* The runway appears at 961px and up, but .wrap only starts clearing it once the
   viewport exceeds roughly 1224px, where the max-width centring pushes content
   past x=46. Between those two points the strip sits ON the copy. June had the
   same fault and got away with it: a 2px hairline overlapped by 4px reads as a
   stray line, while an 18px runway swallows the first character of every line.
   This band gives the content the clearance the runway needs. */
@media(min-width:961px) and (max-width:1223px){.wrap{padding-left:76px}}
.eyebrow{
  font-size:12px;font-weight:600;letter-spacing:.22em;text-transform:uppercase;
  display:inline-flex;align-items:center;gap:10px;
}
.eyebrow .sig{width:8px;height:8px;border-radius:50%;background:var(--magenta);flex:none}
h1,h2,h3{letter-spacing:-.03em;line-height:1.04;font-weight:800}
.reveal{opacity:0;transform:translateY(26px);transition:opacity .8s var(--ease),transform .8s var(--ease)}
.reveal.in{opacity:1;transform:none}
.d1{transition-delay:.08s}.d2{transition-delay:.16s}.d3{transition-delay:.24s}.d4{transition-delay:.32s}

/* ---------- Progress runway ----------
   Was a 2px dotted hairline with a magenta dot. Now a runway: asphalt strip,
   dashed centreline, piano-key threshold bars at each end, and an aircraft that
   rides it nose-down in the direction of travel with a magenta trail behind it.

   The old spine used mix-blend-mode:difference so a hairline stayed visible
   over both the dark sections and the lilac ones. That is dropped here. A blend
   group inverts everything inside it, so the aircraft's magenta would shift
   colour section by section, and moving the aircraft out of the group to avoid
   that would need a second fixed element tracking the same geometry. The runway
   carries its own contrast instead: translucent asphalt over a backdrop blur,
   which reads as a dark strip on the lilac grounds and as a slightly deeper,
   glassier strip on the purple ones. It also matches the hero stat panel, which
   is the only other element on the page using that treatment.

   The width went 2px -> 18px, so the left offset comes in from 34px to 28px to
   keep the strip's optical centre roughly where the hairline sat. ---------- */
/* --pass is the aircraft's y offset inside the runway, written every frame by
   frame(). It drives the centreline mask below. Declared here so the value
   inherits down to .rwy and so the mask has something valid to read on the
   first paint, before any scroll has happened. */
#spine{position:fixed;left:28px;top:12vh;bottom:12vh;width:18px;z-index:40;pointer-events:none;--pass:0px}
#spine .rwy{position:absolute;inset:0;border-radius:10px;overflow:hidden;
  background:rgba(10,6,28,.40);
  -webkit-backdrop-filter:blur(7px) saturate(1.25);backdrop-filter:blur(7px) saturate(1.25);
  border:1px solid rgba(255,255,255,.22);
  box-shadow:0 10px 30px -16px rgba(10,6,28,.65),inset 0 1px 0 rgba(255,255,255,.10)}
/* Centreline. Inset top and bottom so it never runs into the threshold bars.

   The dashes clear as the aircraft passes over them. A mask hides everything
   above the aircraft and leaves the runway ahead of it intact, so the strip
   reads as consumed rather than merely progressed against. The 22px subtracted
   from --pass converts the aircraft's runway-relative offset into this
   pseudo-element's own coordinate space, which starts at the same 22px inset --
   change one and change the other. The 16px band gives the dash directly under
   the nose a soft wipe instead of a hard cut; the magenta trail rises into the
   space the dashes vacate.

   Masking rather than repainting the gradient: the background stays a single
   static paint and only the mask position moves, so nothing re-rasterises on
   scroll. -webkit- first for Safari, which still needs the prefix here. */
#spine .rwy::after{content:"";position:absolute;left:50%;top:22px;bottom:22px;width:2px;
  transform:translateX(-50%);
  background:repeating-linear-gradient(180deg,rgba(255,255,255,.66) 0 11px,transparent 11px 24px);
  -webkit-mask-image:linear-gradient(180deg,transparent 0,transparent calc(var(--pass) - 22px),
    #000 calc(var(--pass) - 6px),#000 100%);
  mask-image:linear-gradient(180deg,transparent 0,transparent calc(var(--pass) - 22px),
    #000 calc(var(--pass) - 6px),#000 100%)}
/* Piano-key threshold markings. Four bars, same at both ends. */
#spine .thr{position:absolute;left:4px;right:4px;height:8px;display:flex;gap:2px}
#spine .thr.top{top:6px}
#spine .thr.bot{bottom:6px}
#spine .thr i{flex:1;border-radius:1px;background:rgba(255,255,255,.62)}
/* Distance covered. Sits under the aircraft and grows with it; height is set
   from the same scroll fraction in frame(). */
#spine .trail{position:absolute;left:50%;top:18px;width:3px;height:0;transform:translateX(-50%);
  border-radius:3px;
  background:linear-gradient(180deg,rgba(213,18,84,0) 0%,rgba(213,18,84,.55) 40%,rgba(213,18,84,.95) 100%)}
/* The aircraft. rotate(90deg) points the nose down the runway, which is the
   direction it travels as the page scrolls. */
#spine .plane{position:absolute;left:50%;top:0;width:22px;height:22px;color:var(--magenta);
  transform:translate(-50%,-50%) rotate(90deg);
  filter:drop-shadow(0 0 9px rgba(213,18,84,.75)) drop-shadow(0 1px 2px rgba(10,6,28,.5))}
#spine .plane svg{width:100%;height:100%;display:block}
@media(prefers-reduced-motion:reduce){#spine .plane{transition:none}}
@media(max-width:960px){#spine{display:none}}

/* ---------- Top bar ---------- */
header.bar{position:fixed;top:0;left:0;right:0;z-index:60;
  transition:background .4s var(--ease),box-shadow .4s var(--ease),padding .4s var(--ease);
  padding:20px 0}
header.bar.solid{background:rgba(14,8,36,.82);backdrop-filter:blur(14px);
  box-shadow:0 1px 0 rgba(255,255,255,.08);padding:12px 0}
.bar .wrap{display:flex;align-items:center;justify-content:space-between;gap:20px}
.brandlock{display:flex;align-items:center;gap:14px}
.brandlock img{height:27px}
.brandlock .x{color:rgba(255,255,255,.5);font-weight:600;font-size:13px;letter-spacing:.1em}
.brandlock .eg-logo{height:22px;width:auto}
nav.jump{display:flex;align-items:center;gap:26px}
@media(max-width:1040px){nav.jump{gap:18px}.brandlock{gap:10px}}
nav.jump a{font-size:13px;font-weight:600;color:rgba(255,255,255,.72);letter-spacing:.02em;position:relative;padding:4px 0}
nav.jump a::after{content:"";position:absolute;left:0;bottom:-2px;height:2px;width:0;background:var(--magenta);transition:width .3s var(--ease)}
nav.jump a:hover{color:#fff}nav.jump a:hover::after{width:100%}
.edition{font-size:11px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.6);
  border:1px solid rgba(255,255,255,.22);border-radius:100px;padding:6px 12px;white-space:nowrap}
/* Raised from 820px: the enlarged lockup needs more room before the nav and
   edition pill can share the row without being squeezed. */
@media(max-width:900px){nav.jump,.edition{display:none}}

/* ---------- Hero ---------- */
/* padding-top is load-bearing: the hero bottom-aligns inside min-height, so
   whenever the content is taller than 82vh (any landscape phone) it overflows
   upward. With no top padding that put the kicker and H1 underneath the fixed
   bar, which sits at z-index 60 against the hero content's z-index 3.
   Reserving the bar's height makes the section grow instead of collide. */
.hero{position:relative;min-height:82vh;display:flex;align-items:flex-end;
  padding:92px 0 6vh;overflow:hidden;background:var(--purple-night)}
.hero .bg{position:absolute;inset:-12% 0;z-index:0;will-change:transform}
/* The hero crops HORIZONTALLY, not vertically, which is worth knowing before
   anyone tries to reframe it. The layer is 124% of the section and the image is
   120% of that, so at 1440x820 the box is 1440x1220 against a 3:2 source: cover
   scales to height and trims ~390px off the width. Changing the Y value does
   nothing; X is the only axis with travel.

   Hence 70% rather than June's centre. July's photo puts the traveller and the
   case in the right third, and centring cut the case in half against the edge
   of the frame. */
.hero .bg img{width:100%;height:120%;object-fit:cover;object-position:70% 50%;filter:saturate(1.02)}
.hero .scrim{position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,rgba(14,8,36,.72) 0%,rgba(14,8,36,.38) 30%,rgba(21,12,54,.86) 78%,var(--purple-night) 100%)}
.hero .scrim2{position:absolute;inset:0;z-index:1;mix-blend-mode:multiply;
  background:linear-gradient(120deg,rgba(66,37,166,.75),transparent 60%)}
/* Deliberately NOT position:relative. The stat panel is nested in here now, and
   on desktop it is absolutely positioned against .hero -- giving .wrap a
   position would make it the containing block and shift the panel. z-index
   still applies because .wrap is a flex item of .hero. */
.hero .wrap{position:static;z-index:3;width:100%}
/* On desktop both of these are plain blocks: the panel inside is absolute and
   out of flow, so the headline and paragraph lay out exactly as they always did.
   Neither may ever carry .reveal or any other transform -- a transformed
   ancestor becomes the containing block for the absolutely positioned panel and
   would drag it out of position, then jump it back when the transform clears.
   The reveals belong on the h1 and p themselves. */
.hero-mid{}
.hero-copy{}
.hero .kicker{color:rgba(255,255,255,.86);margin-bottom:20px}
.hero h1{color:#fff;font-size:clamp(40px,6.8vw,88px);max-width:14ch}
.hero h1 .hl{color:#fff;position:relative;display:inline-block;z-index:1}
.hero h1 .hl::after{content:"";position:absolute;left:-.03em;right:-.03em;bottom:.03em;height:.16em;
  background:#D51254;z-index:-1;border-radius:2px}
.hero p.sub{color:rgba(255,255,255,.8);font-size:clamp(15px,1.8vw,19px);max-width:52ch;margin-top:18px;font-weight:400}
.flightstrip{display:inline-flex;align-items:center;gap:0;margin-top:28px;
  background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);border-radius:14px;
  backdrop-filter:blur(8px);overflow:hidden}
.flightstrip .leg{padding:14px 22px;display:flex;flex-direction:column;gap:2px}
.flightstrip .leg .code{font-size:20px;font-weight:800;color:#fff;letter-spacing:.04em}
.flightstrip .leg .lbl{font-size:10px;font-weight:600;letter-spacing:.16em;color:rgba(255,255,255,.6);text-transform:uppercase}
.flightstrip .path{position:relative;width:96px;height:2px;background:rgba(255,255,255,.28);margin:0 4px}
.flightstrip .path .plane-icon{position:absolute;top:50%;left:0;transform:translateY(-50%) rotate(0deg);
  width:16px;height:16px;animation:flyPlane 3.4s var(--ease) infinite}
@keyframes flyPlane{0%{left:-8px;opacity:0}12%{opacity:1}88%{opacity:1}100%{left:calc(100% - 8px);opacity:0}}

/* --fs-px drives both the panel's padding and the rule's negative margin, so
   the rule stays full-bleed at every breakpoint from one value. */
.hero .floatstat{--fs-px:30px;
  position:absolute;right:6%;top:44%;z-index:3;will-change:transform;min-width:296px;
  padding:26px var(--fs-px) 22px;border-radius:22px;
  background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.18);
  backdrop-filter:blur(18px) saturate(1.4);
  -webkit-backdrop-filter:blur(18px) saturate(1.4);
  box-shadow:0 8px 32px rgba(14,8,36,.28),inset 0 1px 0 rgba(255,255,255,.22)}
.hero .floatstat .n{font-weight:800;letter-spacing:-.04em;line-height:1;font-variant-numeric:tabular-nums}
/* The headline metric is pure white, digits and % alike, so nothing competes
   with it. The two supporting stats sit a step back in a soft lavender --
   number and unit in the same colour, so each reads as one value rather than
   a figure with a differently-coloured sign stuck on. */
.hero .floatstat .fs-lead .n,
.hero .floatstat .fs-lead .n b,
.hero .floatstat .fs-lead .n .u{color:#fff}
.hero .floatstat .fs-cell .n,
.hero .floatstat .fs-cell .n b,
.hero .floatstat .fs-cell .n .u{color:var(--hl-soft)}
.hero .floatstat .l{font-weight:600;text-transform:uppercase;color:rgba(255,255,255,.78)}
.hero .floatstat .fs-lead{text-align:center}
.hero .floatstat .fs-lead .n{font-size:clamp(44px,5.4vw,68px)}
.hero .floatstat .fs-lead .l{font-size:11px;letter-spacing:.18em;margin-top:9px}
.hero .floatstat .fs-rule{height:1px;background:rgba(255,255,255,.16);
  margin:18px calc(var(--fs-px) * -1) 16px}
.hero .floatstat .fs-sub{display:grid;grid-template-columns:1fr 1fr}
/* Desktop keeps the two stats side by side, split by a vertical border, so the
   horizontal divider between them is mobile-only. */
.hero .floatstat .fs-sub .fs-rule{display:none}
.hero .floatstat .fs-cell{text-align:center;padding:0 10px}
/* ~ not +: the divider element now sits between the two cells, so the adjacent
   sibling selector would no longer match. */
.hero .floatstat .fs-cell ~ .fs-cell{border-left:1px solid rgba(255,255,255,.16)}
.hero .floatstat .fs-cell .n{font-size:clamp(19px,1.9vw,25px)}
.hero .floatstat .fs-cell .l{font-size:9px;letter-spacing:.13em;margin-top:7px;color:rgba(255,255,255,.62)}
@media(max-width:1080px){.hero .floatstat{--fs-px:24px;right:4%;top:auto;bottom:20%;
  padding:20px var(--fs-px) 18px;min-width:262px}}

/* Below 820px the panel drops out of its absolute slot and becomes the right
   column of a two-column row. The left column is the headline AND the paragraph
   together, so the panel spans both: its top lines up with the headline, its
   bottom with the last line of the paragraph.

   align-items:stretch does the real work. This row used to be
   align-items:center with the paragraph alone, so a panel taller than the
   paragraph pushed dead space above and below it. Stretching the panel to the
   copy's height removes that gap by construction rather than by tuning margins,
   and "no overlap" stays structural: the copy cannot grow under the panel,
   because the panel owns its own column. */
@media(max-width:820px){
  .hero{flex-direction:column;justify-content:flex-end;align-items:stretch}
  .hero-mid{display:flex;align-items:stretch;gap:14px}
  .hero-copy{flex:1 1 auto;min-width:0}
  .hero p.sub{font-size:13px;line-height:1.5;max-width:none;margin-top:20px}

  /* display:contents dissolves .fs-sub, so all five pieces -- lead, divider,
     stat, divider, stat -- become direct children of one flex column. That is
     what makes space-between able to give every gap the same height. Nesting
     the two stats inside a wrapper meant their spacing was set by the wrapper's
     own rules and could never match the gaps around the first divider.
     Equal-height bands with justify-content:center could not do this either:
     the lead's number is larger, so centring left less room under it than under
     the smaller stats. Spacing the gaps directly, rather than the bands, is
     what makes them even. */
  .hero .floatstat{--fs-px:11px;
    position:static;flex:0 0 auto;width:fit-content;min-width:0;margin:0;
    padding:15px var(--fs-px);border-radius:14px;text-align:center;
    display:flex;flex-direction:column;justify-content:space-between;
    transform:none !important}          /* !important beats the parallax inline transform */
  .hero .floatstat .fs-sub{display:contents}
  .hero .floatstat .fs-sub .fs-rule{display:block}
  .hero .floatstat .fs-rule{margin:0;flex:0 0 auto}
  .hero .floatstat .fs-lead{flex:0 0 auto;text-align:center}
  .hero .floatstat .fs-lead .n{font-size:24px}
  .hero .floatstat .fs-lead .l{font-size:7.5px;letter-spacing:.1em;margin-top:4px}
  .hero .floatstat .fs-cell{flex:0 0 auto;text-align:center;padding:0}
  .hero .floatstat .fs-cell ~ .fs-cell{border-left:none}
  .hero .floatstat .fs-cell .n{font-size:15px}
  .hero .floatstat .fs-cell .l{font-size:7.5px;letter-spacing:.06em;margin-top:3px}
}
/* Landscape phones: 82vh is only ~320px, far less than the hero content needs.
   Drop the min-height entirely and scale the type down so it fits without the
   section ballooning. Keyed on height, so it catches landscape at any width. */
@media(max-height:560px){
  .hero{min-height:auto;padding:88px 0 44px}
  .hero h1{font-size:clamp(28px,4.4vw,42px)}
  .hero p.sub{font-size:14.5px;margin-top:12px;max-width:60ch}
  .hero .kicker{margin-bottom:14px}
  .flightstrip{margin-top:18px}
  .flightstrip .leg{padding:10px 16px}
  .flightstrip .leg .code{font-size:16px}
}

/* Remove default focus/active outline ring on interactive elements */
.note, .cta, .chat-prompt, .gate, .pass, button, a, input {
  outline: none;
  -webkit-tap-highlight-color: transparent;
}
.note:focus, .cta:focus, .chat-prompt:focus, button:focus, a:focus {
  outline: none;
}

/* ---------- Section shells ---------- */
section{position:relative}
/* Section rhythm. All .pad sections share one value so the space above every
   eyebrow stays identical; change it here and the whole page stays even. */
.pad{padding:88px 0}
.sec-head{max-width:640px;margin-bottom:56px}
.sec-head h2{font-size:clamp(30px,4.4vw,52px);margin-top:16px}
.sec-head p{margin-top:18px;font-size:17px;color:var(--ink-soft);font-weight:400}
.dark{background:var(--purple-deep);color:#fff}
.dark .sec-head p{color:rgba(255,255,255,.5)}
.dark .eyebrow{color:rgba(255,255,255,.8)}

/* ---------- Departure board (KPIs) ---------- */
.board{border:1px solid rgba(255,255,255,.12);border-radius:20px;overflow:hidden;background:linear-gradient(180deg,rgba(255,255,255,.05),rgba(255,255,255,.01))}
.board-top{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:16px 24px;background:rgba(0,0,0,.28);border-bottom:1px solid rgba(255,255,255,.1)}
.board-top .t{font-size:12px;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.8);display:flex;align-items:center;gap:10px}
.board-top .t .dot{width:8px;height:8px;border-radius:50%;background:var(--amber);box-shadow:0 0 12px var(--amber);animation:blink 2.4s steps(2) infinite}
@keyframes blink{50%{opacity:.3}}
.board-top .now{display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:flex-end;
  font-size:12px;font-weight:600;letter-spacing:.14em;color:rgba(255,255,255,.55);text-transform:uppercase}
/* The reporting period is the one thing a reader checks first, so it gets a
   pill rather than being buried in the same grey run as the scope text. */
.board-top .now .range{color:#fff;font-weight:700;letter-spacing:.1em;white-space:nowrap;
  border:1px solid rgba(255,255,255,.24);background:rgba(255,255,255,.06);border-radius:100px;padding:5px 12px}
.kpis{display:grid;grid-template-columns:repeat(4,1fr)}
.kpi{padding:34px 26px;border-right:1px solid rgba(255,255,255,.1);border-bottom:1px solid rgba(255,255,255,.1);position:relative;overflow:hidden}
.kpi:nth-child(4n){border-right:none}
.kpi::before{content:"";position:absolute;left:0;top:0;bottom:0;width:0;background:rgba(213,18,84,.14);transition:width .5s var(--ease)}
.kpi:hover::before{width:100%}
.kpi .val{font-size:clamp(30px,3.6vw,46px);font-weight:800;letter-spacing:-.03em;font-variant-numeric:tabular-nums;position:relative}
.kpi .val .pre,.kpi .val .suf{color:var(--hl-dark)}
.kpi .lbl{position:relative;margin-top:12px;font-size:12px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:rgba(255,255,255,.6)}
.kpi .sub{position:relative;margin-top:6px;font-size:13px;color:rgba(255,255,255,.44);font-weight:400}
.kpi.flip .val{animation:flipIn .6s var(--ease) both}
@keyframes flipIn{0%{transform:rotateX(-90deg);opacity:0}100%{transform:none;opacity:1}}

/* ---------- Month-on-month chart ---------- */
.mom{margin-top:22px;border:1px solid rgba(255,255,255,.12);border-radius:20px;overflow:hidden;
  background:linear-gradient(180deg,rgba(255,255,255,.05),rgba(255,255,255,.01))}
.mom-top{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:16px 24px;background:rgba(0,0,0,.28);border-bottom:1px solid rgba(255,255,255,.1)}
.mom-top .t{font-size:12px;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.8);display:flex;align-items:center;gap:10px}
.mom-top .t .dot{width:8px;height:8px;border-radius:50%;background:var(--hl-dark);box-shadow:0 0 12px var(--hl-dark);flex:none}
.mom-top .now{font-size:12px;font-weight:600;letter-spacing:.14em;color:rgba(255,255,255,.55);text-transform:uppercase;white-space:nowrap}
.mom-body{padding:26px 24px 22px}
.mom-legend{display:flex;align-items:center;gap:22px;margin-bottom:6px}
.mom-legend .lg{display:inline-flex;align-items:center;gap:8px;font-size:12px;font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.66)}
.mom-legend .lg i{width:16px;height:3px;border-radius:2px;flex:none}
.mom-legend .roas i{background:var(--hl-dark)}
.mom-legend .cpa i{background:var(--magenta-soft)}
.mom-chart svg{width:100%;height:auto;display:block;overflow:visible}
.mom-chart .grid{stroke:rgba(255,255,255,.10);stroke-width:1}
.mom-chart .axis{fill:rgba(255,255,255,.5);font-size:12px;font-weight:500;font-variant-numeric:tabular-nums}
.mom-chart .axis-title{fill:rgba(255,255,255,.42);font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase}
.mom-chart .ln{fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.mom-chart .ln.roas{stroke:var(--hl-dark)}
.mom-chart .ln.cpa{stroke:var(--magenta-soft)}
.mom-chart .pt{stroke:var(--purple-deep);stroke-width:2}
.mom-chart .pt.roas{fill:var(--hl-dark)}
.mom-chart .pt.cpa{fill:var(--magenta-soft)}
.mom-chart .dl{font-size:11.5px;font-weight:700;font-variant-numeric:tabular-nums}
.mom-chart .dl.roas{fill:var(--hl-dark)}
.mom-chart .dl.cpa{fill:var(--magenta-soft)}
.mom-chart .jun-band{fill:rgba(255,255,255,.06)}
.mom-chart .jun-rule{stroke:rgba(255,255,255,.28);stroke-width:1;stroke-dasharray:3 4}
.mom-chart .jun-tick{fill:#fff;font-weight:700}
.mom-chart .pill-bg.roas{fill:var(--hl-dark)}
.mom-chart .pill-bg.cpa{fill:var(--magenta-soft)}
.mom-chart .pill-tx{font-size:12px;font-weight:800;fill:var(--purple-deep);font-variant-numeric:tabular-nums}
.mom-chart .halo{fill:none;stroke-width:2}
.mom-chart .halo.roas{stroke:var(--hl-dark);opacity:.45}
.mom-chart .halo.cpa{stroke:var(--magenta-soft);opacity:.45}
.mom-chart .mini-title{fill:rgba(255,255,255,.7);font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase}
.mom-foot{font-size:13px;color:rgba(255,255,255,.55);font-weight:400;margin-top:18px;max-width:70ch}
.mom-foot b{color:rgba(255,255,255,.92);font-weight:700}
.mom-chart .draw{stroke-dasharray:var(--len);stroke-dashoffset:var(--len);transition:stroke-dashoffset 1.5s var(--ease)}
.mom.in .mom-chart .draw{stroke-dashoffset:0}
.mom-chart .fadein{opacity:0;transition:opacity .6s var(--ease) .9s}
.mom.in .mom-chart .fadein{opacity:1}
@media(prefers-reduced-motion:reduce){
  .mom-chart .draw{stroke-dasharray:none;stroke-dashoffset:0;transition:none}
  .mom-chart .fadein{opacity:1;transition:none}
}

/* ---------- Boarding passes (brands) ---------- */
/* All four passes share one size. The priority pass is marked by colour
   (magenta border, magenta stub) rather than by being larger. */
.passes{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.pass{position:relative;background:var(--paper);border-radius:18px;box-shadow:var(--shadow-sm);
  display:grid;grid-template-columns:1fr 104px;overflow:hidden;transition:transform .45s var(--ease),box-shadow .45s var(--ease);
  border:1px solid var(--hair)}
.pass:hover{transform:translateY(-6px);box-shadow:var(--shadow)}
.pass .main{padding:20px 22px}
.pass .flag{display:inline-flex;align-items:center;gap:7px;font-size:9.5px;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;color:var(--magenta);margin-bottom:12px}
.pass .flag .sig{width:6px;height:6px;border-radius:50%;background:var(--magenta);animation:pulse 2s infinite}
.pass .flag.alt{color:var(--purple)}
.pass .flag.alt .sig{background:var(--purple);animation:none}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(213,18,84,.5)}50%{box-shadow:0 0 0 6px rgba(213,18,84,0)}}
.pass .toprow{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}
.pass .logo{height:21px;display:flex;align-items:center}
.pass .logo img{height:100%;width:auto;object-fit:contain}
.pass .logo img.tall{height:17px}
.pass .fmt{font-size:9px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--purple);
  background:var(--lilac-2);padding:5px 10px;border-radius:100px;white-space:nowrap}
.pass .fields{display:grid;grid-template-columns:repeat(3,auto);gap:16px}
.pass .field .fl{font-size:9px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-soft)}
.pass .field .fv{font-size:19px;font-weight:800;letter-spacing:-.02em;margin-top:4px;font-variant-numeric:tabular-nums;white-space:nowrap}
.pass .field.roas .fv{color:var(--purple)}
/* flex-wrap is the safety net: "Activated via [DSP]" plus the benchmark chip
   does not fit on one line in every pass at every width, and without wrapping
   the overflow shoves the ticket stub outside the card. */
.pass .dsp{margin-top:16px;display:flex;align-items:center;gap:9px;flex-wrap:wrap;row-gap:10px;
  font-size:11.5px;color:var(--ink-soft);font-weight:500}
.pass .dsp .bm{margin-left:auto}
.pass .dsp .chip{display:inline-flex;align-items:center;height:30px;padding:0 11px;background:#fff;border:1px solid var(--hair);border-radius:7px;flex:none}
.pass .dsp .chip img{height:17px;width:auto}
/* DV360 ships as a two-line stacked lockup, so at a shared cap height it reads
   noticeably smaller than the single-line Trade Desk wordmark next to it. Sizing
   it up on its own keeps the two optically matched rather than mathematically
   equal. Matched by alt text, since that is what the markup carries. */
.pass .dsp .chip img[alt="DV360"]{height:21px}
.pass .stub{position:relative;background:var(--grad-head);color:#fff;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:10px;padding:16px 10px}
.pass .stub::before{content:"";position:absolute;left:-8px;top:0;bottom:0;width:16px;
  background:radial-gradient(circle at 0 50%,transparent 0 7px,var(--paper) 7px) 0 0/16px 22px repeat-y}
.pass .stub .brl{writing-mode:vertical-rl;transform:rotate(180deg);font-size:8px;font-weight:600;letter-spacing:.24em;text-transform:uppercase;color:rgba(255,255,255,.72)}
.pass .stub .barcode{height:52px;width:28px;background:
  repeating-linear-gradient(90deg,#fff 0 2px,transparent 2px 4px,#fff 4px 5px,transparent 5px 9px,#fff 9px 10px,transparent 10px 13px)}
.pass .stub .seat{font-size:16px;font-weight:800;letter-spacing:.02em}
/* The CTV pass spans row 2 rather than leaving a hole beside it. Its three
   fields spread across the extra width instead of clustering at the left edge,
   and the stub widens a step so the ticket stays in proportion. */
.pass.wide{grid-column:1 / -1;grid-template-columns:1fr 132px}
.pass.wide .fields{grid-template-columns:repeat(3,minmax(0,1fr));max-width:640px}
/* Same cap on the DSP row. Without it margin-left:auto throws the benchmark
   chip to the far edge of the card while the figures stop at 640px. */
/* .bm uses margin-left:auto to sit at the far end of the row. On the wide pass
   that flung it to the 640px cap, leaving a gap the eye reads as a mistake.
   Dropping the auto margin lets it sit right after the DSP chip on the row's
   own 9px gap, which is how it already behaves on the two narrow passes where
   the row runs out of width naturally. */
.pass.wide .dsp{max-width:640px}
.pass.wide .dsp .bm{margin-left:0}
.pass.wide .stub .barcode{width:34px}
@media(max-width:900px){.pass.wide{grid-template-columns:1fr 104px}}
@media(max-width:760px){.pass.wide{grid-template-columns:1fr 84px}}

/* priority pass: colour only, same footprint as the rest */
.pass.priority{border:1px solid rgba(213,18,84,.4);box-shadow:0 26px 60px -34px rgba(213,18,84,.5)}
.pass.priority .stub{background:linear-gradient(160deg,var(--magenta),#8b1b7d)}
/* Raised from 760px: two passes side by side leave the DSP row too narrow for
   the benchmark chip once the stub takes its 104px. */
@media(max-width:900px){.passes{grid-template-columns:1fr}}
@media(max-width:760px){
  .pass{grid-template-columns:1fr 84px}
  /* Type comes down a step across the whole pass so the three fields fit on one
     line. "Post-ad Rev" was wrapping to "Post-ad / Rev" on narrower handsets,
     which broke the row into two heights and threw the ticket out of line. */
  .pass .main{padding:16px 16px}
  .pass .fields{gap:10px}
  .pass .field .fl{font-size:8px;letter-spacing:.08em;white-space:nowrap}
  .pass .field .fv{font-size:15px}
  .pass .flag{font-size:8.5px;letter-spacing:.1em;margin-bottom:10px}
  .pass .fmt{font-size:8px;padding:4px 8px}
  .pass .logo{height:18px}
  .pass .logo img.tall{height:15px}
  .pass .dsp{font-size:10.5px;margin-top:13px;gap:7px}
  .pass .dsp .chip{height:26px;padding:0 9px}
  .pass .dsp .chip img{height:14px}
  .pass .dsp .chip img[alt="DV360"]{height:18px}
  /* The benchmark chips leave with the space: on a phone the pass has to carry
     spend, revenue and pROAS legibly first, and the same callouts are still in
     the format table right below. */
  .pass .dsp .bm{display:none}
}

/* ---------- Benchmark callouts ----------
   One chip, used on the boarding passes and in the format table so the two
   never disagree. Purple for above, magenta for below: magenta is the palette's
   attention colour, and a line under its benchmark is exactly the thing a
   reader should not skim past. Greying the misses would have been quieter but
   would also have hidden them. */
.bm{display:inline-flex;align-items:center;gap:5px;padding:4px 9px;border-radius:6px;
  font-size:10px;font-weight:700;letter-spacing:.03em;white-space:nowrap;
  font-variant-numeric:tabular-nums;line-height:1}
.bm .arw{font-size:7px;line-height:1;transform:translateY(.5px)}
.bm.up{background:var(--lilac-2);color:var(--purple)}
.bm.down{background:rgba(213,18,84,.09);color:var(--magenta)}

/* Format Overview table */
.fmt-table-wrap{border-radius:20px;overflow:hidden;background:var(--paper);border:1px solid var(--hair);box-shadow:var(--shadow-sm)}
.fmt-table-head{padding:22px 28px;display:flex;align-items:center;gap:18px;border-bottom:1px solid var(--hair)}
.fmt-table-head .eyebrow{color:var(--purple)}
.fmt-sub{font-size:14px;color:var(--ink-soft);font-weight:400}
.fmt-table-outer{overflow-x:auto}
.fmt-table{width:100%;border-collapse:collapse;font-size:14px}
.fmt-table thead tr{background:linear-gradient(135deg,#4225a6 0%,#2e1a7a 60%,#1f1252 100%)}
.fmt-table th{text-align:left;padding:16px 20px;font-size:11px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:#fff;border-bottom:none;white-space:nowrap}
.fmt-table th.r,.fmt-table td.r{text-align:right}
.fmt-table th.hl-col{color:#fff}
.fmt-table td{padding:16px 20px;border-bottom:1px solid var(--hair);font-weight:500;vertical-align:middle}
.fmt-table tr:last-child td{border-bottom:none}
.fmt-table tr.hi{background:rgba(66,37,166,.04)}
.fmt-table td.r{font-variant-numeric:tabular-nums;font-weight:700}
.fmt-table td.hl-col{color:var(--purple);font-weight:800;font-size:16px}
.fmt-pill{display:inline-block;padding:5px 12px;border-radius:8px;font-size:12px;font-weight:600;letter-spacing:.04em}
.fmt-pill.disp{background:var(--lilac-2);color:var(--purple)}
.fmt-pill.ctv-pill{background:rgba(244,183,64,.12);color:#b5870a}
/* Video is a new format on this page; its own tint keeps it distinct from the
   purple Display pill without reaching for magenta, which stays rationed. */
.fmt-pill.vid{background:rgba(46,26,122,.10);color:var(--purple-dark)}

/* Format table, now standalone and full width. Taller rows and a larger pROAS
   figure give it presence so it does not read as a stranded strip where the
   two-up pair used to be. */
.fmt-table.fmt-wide th{padding:16px 24px;font-size:11px}
.fmt-table.fmt-wide td{padding:22px 24px;font-size:15px}
.fmt-table.fmt-wide td.hl-col{font-size:22px}
.fmt-table.fmt-wide .fmt-pill{padding:6px 14px;font-size:13px}
/* Center-aligned columns: pROAS + Post-ad Rev (Format table), DSP + Format (Geo).
   .c wins over the .r right-align because it is listed after it here. */
.fmt-table.mini th.c,.fmt-table.mini td.c{text-align:center}
/* Nudge the type down so "Display & Video" and "United Kingdom" stay on one
   line in the narrower side-by-side columns. */
.fmt-table.mini{font-size:12.5px}
.fmt-table.mini th{font-size:9.5px;letter-spacing:.1em;padding:12px 14px;white-space:nowrap}
.fmt-table.mini td{padding:13px 14px;white-space:nowrap}
.fmt-table.mini .fmt-pill{padding:4px 9px;font-size:11px;white-space:nowrap}
.fmt-table.mini .dsp-text{white-space:nowrap}
.fmt-table.mini td.hl-col{font-size:15px}

/* ===== New Activations ===== */
.activations{background:var(--lilac)}
.sec-sub{margin-top:18px;font-size:17px;color:var(--ink-soft);font-weight:400;max-width:640px}
.act-block{margin-top:40px}
.act-block+.act-block{margin-top:56px}
.act-head{display:flex;align-items:center;justify-content:space-between;gap:20px;margin-bottom:20px;flex-wrap:wrap}
.act-title{font-size:22px;font-weight:700;color:var(--ink)}
/* Brand toggle: two logo buttons, the active one lifted onto white. */
.brand-toggle{display:inline-flex;gap:6px;background:var(--lilac-2);border-radius:12px;padding:5px}
.bt-btn{display:inline-flex;align-items:center;justify-content:center;height:40px;min-width:104px;padding:0 20px;
        background:transparent;border:0;border-radius:8px;cursor:pointer;transition:background .18s var(--ease),box-shadow .18s var(--ease)}
.bt-btn img{height:19px;width:auto;opacity:.5;transition:opacity .18s var(--ease)}
.bt-btn:hover img{opacity:.78}
.bt-btn.is-active{background:#fff;box-shadow:var(--shadow-sm)}
.bt-btn.is-active img{opacity:1}
/* Static brandmark for the Other Brand-Specific block (no toggle). */
.act-brandmark{display:inline-flex;align-items:center;height:40px;padding:0 18px;background:#fff;border-radius:10px;box-shadow:var(--shadow-sm)}
.act-brandmark img{height:19px;width:auto}
/* The activations tables carry more columns; let them scroll on narrow screens
   rather than crush the numbers. */
.act-table{font-size:13.5px;min-width:680px}
.act-table th{padding:14px 16px;font-size:10.5px;white-space:nowrap}
.act-table td{padding:15px 16px;white-space:nowrap}
.act-table .fmt-pill{white-space:nowrap}
/* "Reporting awaited" - a quiet neutral pill so an empty metric does not shout. */
.await{display:inline-block;padding:4px 11px;border-radius:8px;font-size:11.5px;font-weight:600;
       letter-spacing:.02em;background:rgba(23,18,59,.06);color:var(--ink-soft);white-space:nowrap}
.brand-cell{min-width:120px}
.tb-logo{height:20px;width:auto;object-fit:contain}
.tb-logo.vrbo-tb{height:16px}
.tb-logo.hotels-tb{height:18px}
.dsp-text{display:inline-block;padding:5px 12px;border-radius:8px;font-size:12px;font-weight:700;letter-spacing:.06em;
  background:var(--lilac-2);color:var(--purple)}

/* ---------- Insights (dot grid) ---------- */
.insights{background:var(--purple-night);color:#fff;position:relative;overflow:hidden}
#dotgrid{position:absolute;inset:0;z-index:0}
.insights .wrap{position:relative;z-index:2}
.insights .sec-head p{color:rgba(255,255,255,.72)}
.notes{display:grid;grid-template-columns:repeat(2,1fr);gap:22px}
.note{position:relative;border:1px solid rgba(255,255,255,.12);border-radius:18px;padding:32px;overflow:hidden;
  background:linear-gradient(180deg,rgba(255,255,255,.045),transparent);transition:transform .4s var(--ease),border-color .4s var(--ease)}
.note::before{content:"";position:absolute;left:0;top:0;bottom:0;width:0;background:var(--purple);transition:width .5s var(--ease);z-index:-1}
.note:hover{transform:translateY(-6px);border-color:rgba(213,18,84,.4)}
.note:hover::before{width:100%}
.note .ic{width:46px;height:46px;border-radius:12px;display:flex;align-items:center;justify-content:center;
  background:rgba(213,18,84,.14);border:1px solid rgba(213,18,84,.3);margin-bottom:20px}
.note .ic svg{width:22px;height:22px;stroke:var(--magenta-soft);fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;transition:stroke .4s}
.note:hover .ic{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.4)}
.note:hover .ic svg{stroke:#fff}
.note .tag{font-size:11px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.55)}
.note h3{font-size:21px;font-weight:800;margin:8px 0 12px;letter-spacing:-.01em}
.note p{font-size:15px;color:rgba(255,255,255,.72);font-weight:400}
.pubchips{display:flex;flex-wrap:wrap;gap:10px;margin-top:18px}
.pubchips .pc{height:34px;padding:0 14px;background:#fff;border-radius:8px;display:flex;align-items:center;transition:transform .3s var(--ease)}
.pubchips .pc:hover{transform:translateY(-3px) scale(1.03)}
.pubchips .pc img{height:15px;width:auto;object-fit:contain}
.pubchips .pc img.sm{height:13px}
/* The Weather Channel ships as a square tile rather than a wordmark, so it
   needs height to stay legible where a wordmark only needs cap height. */
.pubchips .pc img.sq{height:22px;border-radius:3px}
@media(max-width:700px){.notes{grid-template-columns:1fr}}

/* ---------- Upsell ---------- */
.upsell{position:relative;overflow:hidden;background:var(--purple-deep);color:#fff}
/* Full bleed again, with 12% of vertical overscan for the parallax to travel
   into. The source is an AI-extended frame sized to this box (see
   README-JULY-CHANGES.md), so cover has almost nothing to trim. */
/* auto height, top-anchored: the layer is the picture, not the whole section.
   The 12% of overscan above is kept for the parallax to travel into.

   The layer hangs 9% off the RIGHT edge rather than sitting flush. The
   subject's head is at 70-87% of the frame and the genres panel covers 63-88%
   of the viewport, so flush she disappears behind it entirely and the only
   part of her in the clear is a bare shoulder. Pushing the picture right slides
   her head to 79-96%: the panel still crosses her, which is the intent, but the
   back of her head and the headphone cup now sit in the open beside it. Note
   the direction -- widening the layer would move her LEFT, since it is pinned
   right; only a negative right offset moves her out. The 9% lost off the right
   edge is blurred foliage. */
.upsell .bg{position:absolute;top:-12%;right:-9%;left:auto;bottom:auto;width:100%;
  z-index:0;will-change:transform}
/* No cover. The section runs 1253px tall at every desktop width, so against a
   1.40:1 source the box is 0.93:1 at 1440 and cover would keep only the right
   66% of the frame -- which is the subject, filling half the band. Rendering at
   the picture's own aspect shows the whole scene at every width instead, and
   the subject sits at her natural 35% of the frame.

   This works because the asset fades to --purple-deep at its own bottom edge
   (see build_audio_bg.py). The band ends, the section's ground continues, and
   there is no seam between them. Swap in an asset without that baked fade and
   a hard horizontal edge appears partway down the section. */
.upsell .bg img{width:100%;height:auto;display:block}
/* Only a whisper at the very bottom. The asset fades to --purple-deep on its
   own lower edge, so the CSS gradient that used to do that job now double-
   darkens: between the two, everything below 60% of the picture went to
   ground, which took the subject's shoulders and the table with it. This is
   here purely to catch the case where the section is shorter than the picture
   and the baked fade gets clipped. */
.upsell .bg::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(26,29,35,0) 0%,rgba(26,29,35,0) 88%,
    rgba(26,29,35,.45) 100%)}
/* Lighter than it was, because the image is no longer cropped. When cover was
   throwing away 55% of the width, the surviving strip was the subject's face
   and the scrim's job was to bury it. Now the whole beach is on screen, and a
   .94 stop at 42% was hiding the very thing that makes the picture readable as
   a wide shore rather than a close-up.

   The left stops stay heavy because the copy sits there over bright sand and
   needs the contrast; the right two thirds open up so the beach, the dune line
   and the subject all read. */
/* Heavy on the left where the copy sits, opening up across the right so the
   extended frame reads. The subject sits behind the glass panel, which adds its
   own 18px blur on top of this, so she stays a soft presence rather than a
   competing focal point. */
.upsell .scrim{position:absolute;inset:0;z-index:1;
  background:linear-gradient(90deg,var(--purple-deep) 0%,rgba(21,12,54,.86) 30%,
    rgba(21,12,54,.34) 58%,rgba(21,12,54,.14) 100%)}
/* start, not center. The left column is now much taller than the boarding card,
   and centring the card left a wedge of dead space under the copy before the
   detail bands began. */
/* The copy is capped so it clears the right-anchored photograph, which now
   fills the space a glass genres panel briefly occupied. That panel is gone: it
   had begun sitting squarely on the subject's face. */
.upsell .wrap{position:relative;z-index:2;display:block}
.au-top{display:grid;grid-template-columns:1.3fr .7fr;gap:56px;align-items:stretch}
.au-intro{max-width:none}
.upsell .flag{color:#D51254;margin-bottom:22px}
.upsell h2{font-size:clamp(34px,5vw,60px);color:#fff}
/* Lavender fill only, no underline. The hero already carries the one underlined
   .hl on the page, and repeating the device here competed with it rather than
   echoing it. This is the same rule June used behind the OmniReach wordmark. */
.upsell h2 .hl{color:var(--hl-dark)}
/* ---------- Audio detail (July sell sheet) ----------
   Full-width bands under the two-column intro, hairline-separated rather than
   boxed: the boarding pass above is the only card in this section, and giving
   these their own panels made the two compete.

   Every logo from the sell sheet is a dark mark, so they all sit on white
   .lchip tiles. The genre icons are the exception, being white line art that
   sits straight on the section ground. */
.upsell .tagline{font-size:21px;font-weight:700;color:#fff;margin:0 0 16px;letter-spacing:-.01em}
.upsell .tagline .hl{color:var(--hl-dark)}

.claim{margin-top:30px}
.claim-h{font-size:16px;font-weight:700;color:#fff;margin-bottom:12px;padding-left:13px;
  border-left:3px solid var(--magenta)}
.claim-list{list-style:none;margin:0;padding:0}
.claim-list li{position:relative;padding-left:20px;margin-bottom:9px;font-size:14.5px;
  color:rgba(255,255,255,.80);line-height:1.5;display:flex;align-items:center;flex-wrap:wrap;gap:2px}
/* The bullet is a pseudo-element rather than a list marker so it keeps its
   position on the wrapped SearchSignals row, where the line box starts with an
   image instead of text. */
.claim-list li::before{content:"";position:absolute;left:0;top:.55em;width:6px;height:6px;
  border-radius:50%;background:var(--magenta)}
/* The SearchSignals lockup is dark artwork, so it carries its own white tile
   inline rather than being dropped onto the section ground. */
.ss-mark{height:18px;width:auto;background:#fff;padding:3px 7px;border-radius:5px;
  vertical-align:-.28em;margin-right:3px}

/* The intro and the bands are one column now, so this margin is the only thing
   separating the CTA from the first band. It was 8px, which was correct when a
   56px grid row-gap sat above it and wrong the moment that grid went away. */
.audio-detail{margin-top:52px}
.ad-band{padding-top:26px;margin-top:26px;border-top:1px solid rgba(255,255,255,.12)}
.ad-band:first-child{padding-top:0;margin-top:0;border-top:0}
.ad-lbl{font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.52);margin-bottom:16px}

/* auto-fit so five genres spread on desktop and reflow to two up on mobile
   without a second breakpoint */
/* The hero stat panel's glass: this page's established treatment for content
   floating over photography, and the reason the subject can sit behind it. The
   18px backdrop blur is what keeps her a soft presence rather than a face
   competing with the genre labels. */
.genre-panel{display:flex;flex-direction:column;padding:28px 28px 26px;border-radius:22px;
  background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.18);
  backdrop-filter:blur(18px) saturate(1.4);
  -webkit-backdrop-filter:blur(18px) saturate(1.4);
  box-shadow:0 8px 32px rgba(14,8,36,.28),inset 0 1px 0 rgba(255,255,255,.22)}
.gp-lbl{font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.62);margin-bottom:6px}
.gp-foot{margin:16px 0 0;padding-top:16px;border-top:1px solid rgba(255,255,255,.14);
  font-size:13px;line-height:1.5;color:rgba(255,255,255,.62)}
/* Rows share the leftover height equally, so each divider sits exactly halfway
   between the two labels it separates. */
.genres-grid{flex:1;display:flex;flex-direction:column}
.genre{flex:1;display:flex;align-items:center;gap:14px;padding:10px 0;
  border-top:1px solid rgba(255,255,255,.10)}
.genre:first-child{border-top:0}
/* Fixed 38x32 icon column: the icons are pre-rendered at constant optical area,
   and the fixed box starts every label at the same x. */
.genre img{width:38px;height:32px;flex:none;object-fit:contain;opacity:.92}
.genre span{font-size:14.5px;font-weight:500;color:rgba(255,255,255,.90);line-height:1.35}

.lchips{display:grid;gap:12px}
.lchips.dsps{grid-template-columns:repeat(6,1fr)}
.lchips.pubs{grid-template-columns:repeat(4,1fr)}
@media(max-width:1100px){
  .lchips.dsps{grid-template-columns:repeat(3,1fr)}
  .lchips.pubs{grid-template-columns:repeat(4,1fr)}
}
.lchip{display:flex;align-items:center;justify-content:center;height:64px;padding:0 10px;
  background:#fff;border-radius:10px;transition:transform .3s var(--ease),box-shadow .3s var(--ease)}
.lchip:hover{transform:translateY(-3px);box-shadow:0 12px 28px -12px rgba(10,6,28,.7)}
.lchip img{width:100%;height:44px;object-fit:contain;display:block}

.omni-band .omni-row{display:grid;grid-template-columns:auto 1fr;gap:16px 38px;align-items:center}
/* content-box, deliberately, against the global border-box at the top of this
   file. With border-box, `height` is the TILE and the white padding eats into
   the artwork: the old 22px height with 6px padding left just 10px of actual
   wordmark, which is why it read as a footnote rather than as the partner mark
   the line names. content-box makes `height` mean the mark itself.

   30px of artwork in a 48px tile. The source is re-exported at 848x136, more
   than 2x this height, so it stays crisp on retina. */
.omni-mark{box-sizing:content-box;height:30px;width:auto;background:#fff;
  padding:9px 15px;border-radius:9px;display:block}
.omni-band p{margin:0;font-size:14.5px;line-height:1.6;color:rgba(255,255,255,.80);max-width:52ch}

@media(max-width:860px){
  .audio-detail{margin-top:34px}
  .ad-band{padding-top:22px;margin-top:22px}
  .upsell .tagline{font-size:17px}
  .genre img{height:22px}
  .genre span{font-size:13.5px}
  .lchips.dsps,.lchips.pubs{grid-template-columns:repeat(2,1fr)}
  .lchips{gap:10px}
  .lchip{height:56px;padding:0 8px}
  .lchip img{height:38px}
  .omni-band .omni-row{grid-template-columns:1fr;gap:14px}
  .cta{width:100%}
  /* Columns collapse, so the panel becomes a full-width block under the copy. */
  .au-top{grid-template-columns:1fr;gap:32px;align-items:start}
  /* No cover here. Stacked, the section runs ~1900px tall against a 390px
     viewport, so the box aspect is about 0.17 against a 1.6 source and cover
     would keep a 10%-wide vertical sliver of the frame. The picture instead
     renders at its own aspect as a band across the top: full width, auto
     height, nothing cropped, with the fade carrying it into the ground. */
  /* A fixed 420px band, not the whole section and not the picture's own
     height. Full-section cover would leave a 10%-wide sliver of the frame at
     this aspect; the picture's own height puts the subject at 18% of a 390px
     band, which is too small to read. 420px against 390px wide is a 0.93 box
     against the 1.6 source, so cover keeps the right 58% -- the part she is
     in -- and she renders about 160px across. */
  /* Same treatment stacked: the picture is a band across the top at its own
     aspect. No cover, so nothing is cropped at 390px either. */
  .upsell .bg{inset:0 0 auto;height:auto}
  .upsell .bg img{width:100%;height:auto}
  .upsell .bg::after{background:linear-gradient(180deg,var(--purple-deep) 0%,
    rgba(26,29,35,0) 14%,rgba(26,29,35,0) 46%,rgba(26,29,35,.80) 76%,
    var(--purple-deep) 97%)}
  .upsell .scrim{background:linear-gradient(180deg,rgba(21,12,54,.58) 0%,
    rgba(21,12,54,.68) 42%,rgba(21,12,54,.24) 100%)}
  .genres-grid{display:block}
  .genre-panel{padding:22px 20px 20px}
  .genre{padding:12px 0}
}
@media(min-width:861px) and (max-width:1100px){.au-top{gap:36px}}

.omnireach-wordmark{display:inline-flex;align-items:center;vertical-align:-.12em}
.omnireach-inline{height:clamp(30px,4.4vw,52px);width:auto;display:block}
.upsell p.lead{font-size:18px;color:rgba(255,255,255,.82);margin-top:22px;max-width:46ch;font-weight:400}
.omni-feats{display:flex;flex-wrap:wrap;gap:10px;margin-top:26px}
.omni-feats span{font-size:13px;font-weight:500;letter-spacing:.02em;padding:10px 16px;border-radius:10px;
  border:1px solid rgba(255,255,255,.24);background:rgba(255,255,255,.06)}

.nextpass{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.18);border-radius:20px;
  backdrop-filter:blur(10px);overflow:hidden}
.nextpass .np-top{padding:18px 24px;border-bottom:1px dashed rgba(255,255,255,.24);display:flex;justify-content:space-between;align-items:center}
.nextpass .np-top .lbl{font-size:10px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.6)}
.nextpass .np-top .to{font-size:22px;font-weight:800;color:#fff}
.nextpass .np-body{padding:24px}
.nextpass .np-row{display:flex;justify-content:space-between;padding:10px 0;border-bottom:1px solid rgba(255,255,255,.1);font-size:14px}
.nextpass .np-row:last-of-type{border-bottom:none}
.nextpass .np-row .k{color:rgba(255,255,255,.6)}
.nextpass .np-row .v{font-weight:700}
/* width:auto, not 100%. Inside the old card the button filled a fixed panel;
   freestanding in a grid column, 100% stretched it the full column width and it
   read as a banner rather than a button. */
.cta{margin-top:26px;width:auto;display:inline-flex;align-items:center;justify-content:center;gap:10px;
  padding:16px 22px;border-radius:12px;background:var(--magenta);color:#fff;font-weight:700;font-size:15px;font-family:'DM Sans',Arial,sans-serif;
  letter-spacing:.01em;cursor:pointer;border:none;position:relative;overflow:hidden;transition:transform .3s var(--ease)}
.cta span{position:relative;z-index:2}
.cta::before{content:"";position:absolute;inset:0;background:var(--purple);transform-origin:left center;transform:scaleX(0);
  transition:transform .6s cubic-bezier(.34,1.56,.64,1);z-index:1}
.cta:hover::before{transform:scaleX(1)}
.cta:hover{transform:translateY(-2px);transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.cta svg{width:18px;height:18px;position:relative;z-index:2;transition:transform .3s var(--ease)}
.cta:hover svg{transform:translateX(4px)}
#dealLibraryCta:hover svg{transform:none}
@media(max-width:860px){.upsell .wrap{grid-template-columns:1fr;gap:34px}
  /* Nothing to re-frame now that the image is uncropped; at 390px it simply
     renders as a 390x188 band at the top of the section. */
  }

/* placeholder note */
.phnote{margin-top:26px;font-size:12px;color:rgba(255,255,255,.5);font-weight:400;
  border-left:2px solid rgba(255,255,255,.3);padding-left:12px;max-width:44ch}

/* ---------- Footer ---------- */
footer{background:var(--purple-night);color:rgba(255,255,255,.7);padding:70px 0 46px;position:relative}
footer .ftop{display:flex;justify-content:space-between;align-items:flex-start;gap:40px;flex-wrap:wrap;
  padding-bottom:38px;border-bottom:1px solid rgba(255,255,255,.1)}
footer .fl img{height:24px;margin-bottom:16px}
footer .fl p{font-size:14px;max-width:40ch;font-weight:400}
footer .fr{display:flex;gap:56px;flex-wrap:wrap}
footer .fcol h4{font-size:11px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.5);margin-bottom:14px}
footer .fcol a{display:block;font-size:14px;color:rgba(255,255,255,.8);padding:5px 0;transition:color .3s}
footer .fcol a:hover{color:var(--magenta-soft)}
footer .fbot{display:flex;justify-content:space-between;align-items:center;gap:20px;flex-wrap:wrap;padding-top:26px}
footer .fbot p{font-size:12px;color:rgba(255,255,255,.5)}
footer .fbot .conf{display:inline-flex;align-items:center;gap:8px}
footer .fbot .conf .sig{width:7px;height:7px;border-radius:50%;background:var(--magenta)}

@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  .reveal{opacity:1;transform:none}
  .hero .bg,.band .bg,.upsell .bg,.hero .floatstat{transform:none!important}
}


/* Gated PDF section */
.gated-pdf{background:var(--purple-deep);color:#fff}
.gated-pdf .eyebrow{color:#fff}
.gated-card{display:grid;grid-template-columns:1fr 1fr;gap:52px;align-items:center;
  background:linear-gradient(180deg,rgba(255,255,255,.05),transparent);border:1px solid rgba(255,255,255,.14);
  border-radius:24px;padding:52px}
.gated-left h2{font-size:clamp(28px,4vw,42px);color:#fff;margin-top:16px;letter-spacing:-.02em;line-height:1.1}
.gated-left p{margin-top:18px;color:rgba(255,255,255,.72);font-size:15px;max-width:42ch}
.gated-right{background:var(--paper);border-radius:18px;padding:32px;box-shadow:var(--shadow-sm)}
.gated-form{display:flex;flex-direction:column;gap:16px}
.gf-field{display:flex;flex-direction:column;gap:6px;font-size:12px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink-soft)}
.gf-field input{border:1px solid var(--hair);border-radius:10px;padding:12px 14px;font-size:15px;
  font-family:'DM Sans',Arial,sans-serif;color:var(--ink);outline:none;transition:border-color .2s;font-weight:400}
.gf-field input:focus{border-color:var(--purple)}
.gf-submit{width:100%;justify-content:center;margin-top:4px}
.gf-note{font-size:12px;color:var(--ink-soft);margin-top:2px;font-weight:400}
/* handleGatedSubmit() adds .hidden to the form, but nothing ever acted on it,
   so .gated-form{display:flex} kept the Unlock button on screen and the success
   block rendered directly beneath it -- tick flush against the button. The form
   was always meant to disappear on submit; it just never did. */
.gated-form.hidden{display:none}
.gated-success{text-align:center}
.gated-success.hidden{display:none}
.gs-icon{width:52px;height:52px;border-radius:50%;background:var(--lilac-2);color:var(--purple);
  display:flex;align-items:center;justify-content:center;margin:0 auto 16px}
.gated-success h3{font-size:20px;color:var(--ink);font-weight:800}
.gated-success p{color:var(--ink-soft);font-size:14px;margin-top:8px;font-weight:400;line-height:1.5}
@media(max-width:820px){.gated-card{grid-template-columns:1fr;padding:32px}}


/* ============================================================
   MOBILE OVERRIDES (<=680px)
   Scoped fixes for: logo image distortion, format table,
   boarding passes, the month-on-month chart, and the gated PDF
   form. Upsell Spotlight and Flight Notes are intentionally left
   untouched.
   ============================================================ */
@media(max-width:680px){

  /* The New Activations tables have 8 columns and their min-width:680px pushes
     the data columns off-screen on a phone, leaving only the header visible.
     Below the breakpoint, drop the min-width and switch each row to the same
     stacked-card layout the main table uses, so every value shows with its label. */
  .act-table{ min-width:0; }
  #activations .fmt-table-outer{ overflow-x:visible; }
  .act-table, .act-table thead, .act-table tbody,
  .act-table th, .act-table td, .act-table tr{ display:block; width:100%; }
  .act-table thead{ display:none; }
  .act-table tr{ border-bottom:1px solid var(--hair); padding:14px 18px 16px; }
  .act-table tr:last-child{ border-bottom:none; }
  .act-table tr.hi{ background:rgba(66,37,166,.05); }
  .act-table td{
    display:flex; align-items:center; justify-content:space-between; gap:14px;
    padding:7px 0; border-bottom:none; white-space:normal; text-align:right;
  }
  .act-table td::before{
    content:attr(data-label); font-size:11px; font-weight:600; letter-spacing:.08em;
    text-transform:uppercase; color:var(--ink-soft); flex:none; text-align:left;
  }
  /* Toggle can shrink to fit a narrow header row. */
  .act-head{ gap:14px; }

  /* ---- 0a. Live PMP Performance board. Four KPI columns collapse to a 2x2
     grid; at 4-up each cell is only ~35px of content on a phone, which wraps
     "$18.10M" onto three lines. Border sides are re-dealt for two columns. ---- */
  .board-top{ flex-direction:column; align-items:flex-start; gap:8px; padding:14px 18px; }
  .board-top .t{ font-size:11px; letter-spacing:.16em; }
  /* Stacked, the row is left-aligned, so the pill must be too -- it inherits
     justify-content:flex-end from the desktop layout otherwise and reads as a
     stray indent. */
  .board-top .now{ font-size:11px; letter-spacing:.1em; justify-content:flex-start; gap:10px; }
  .kpis{ grid-template-columns:1fr 1fr; }
  .kpi{ padding:22px 16px; border-right:1px solid rgba(255,255,255,.1); }
  .kpi:nth-child(4n){ border-right:1px solid rgba(255,255,255,.1); }
  .kpi:nth-child(2n){ border-right:none; }
  .kpi:nth-last-child(-n+2){ border-bottom:none; }
  .kpi .val{ font-size:26px; }
  .kpi .lbl{ font-size:10px; letter-spacing:.12em; margin-top:10px; }
  .kpi .sub{ font-size:11.5px; margin-top:5px; }

  /* ---- 0b. Month-on-month chart. The chart itself swaps to a separate
     two-chart render in JS (see the chart block in the script); these are
     only the surrounding shell fixes. The header strip stacks instead of
     letting the date range wrap mid-phrase. ---- */
  .mom-top{ flex-direction:column; align-items:flex-start; gap:6px; padding:14px 18px; }
  .mom-top .t{ font-size:11px; letter-spacing:.16em; }
  .mom-top .now{ font-size:11px; letter-spacing:.1em; }
  .mom-body{ padding:18px 14px 16px; }
  .mom-legend{ gap:16px; margin-bottom:2px; }
  .mom-legend .lg{ font-size:11px; letter-spacing:.1em; }
  .mom-chart svg + svg{ margin-top:14px; }
  .mom-foot{ font-size:12.5px; margin-top:14px; }

  /* Hero kicker is the only June marker on mobile, since the top-bar
     edition pill is hidden below 820px. Keep it from wrapping oddly. */
  .hero .kicker{ font-size:10px; letter-spacing:.16em; margin-bottom:16px; }

  /* Hero type down a step on phones so the block clears the bar comfortably
     and the lines stop crowding each other. The paragraph's size is set once in
     the 820px block, beside the layout that depends on it -- do not re-set it
     here or the two breakpoints disagree. */
  .hero h1{ font-size:34px; }
  .flightstrip{ margin-top:22px; }
  .flightstrip .leg{ padding:11px 16px; }
  .flightstrip .leg .code{ font-size:17px; }
  .flightstrip .leg .lbl{ font-size:9px; }
  .flightstrip .path{ width:64px; }

  /* Header logos are larger now; keep the bar compact on small screens. */
  .brandlock img{ height:23px; }
  .brandlock .eg-logo{ height:19px; }

  /* Section rhythm again, tighter: 88px of dead space at each end of every
     section is a lot of thumb-scrolling on a phone. */
  .pad{ padding:64px 0; }
}

/* Very small phones (320px). Two KPI columns leave ~94px of content each, and
   "$18.10M" at 26px needs 96. Two pixels, but it clips the M. */
@media(max-width:360px){
  .kpi{ padding:20px 12px; }
  .kpi .val{ font-size:22px; }
  .kpi .lbl{ font-size:9px; letter-spacing:.1em; }
  .kpi .sub{ font-size:10.5px; }

  /* ---- 1. Logo/vector safety: never let fixed height + shrinking
     containers squash aspect ratio. max-height (not height) lets the
     browser scale both dimensions together. ---- */
  .tb-logo, .pass .logo img, .pass .logo img.tall,
  footer .fl img, .dsp-badge img {
    height: auto !important;
    width: auto !important;
    max-width: 100% !important;
    object-fit: contain;
  }
  .tb-logo{ max-height:18px; }
  .tb-logo.vrbo-tb{ max-height:14px; }
  .tb-logo.hotels-tb{ max-height:16px; }
  .pass .logo{ height:22px; }
  .pass .logo img{ max-height:22px; }
  .pass .logo img.tall{ max-height:18px; }

  /* ---- 2. Format Overview table -> stacked cards ---- */
  .fmt-table-outer{ overflow-x:visible; }
  .fmt-table, .fmt-table thead, .fmt-table tbody,
  .fmt-table th, .fmt-table td, .fmt-table tr{
    display:block;
    width:100%;
  }
  .fmt-table thead{ display:none; }
  .fmt-table tr{
    border-bottom:1px solid var(--hair);
    padding:14px 18px 16px;
  }
  .fmt-table tr:last-child{ border-bottom:none; }
  .fmt-table tr.hi{ background:rgba(66,37,166,.05); }
  .fmt-table td{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:14px;
    padding:7px 0;
    border-bottom:none;
    white-space:normal;
    text-align:right;
  }
  .fmt-table td.r{ text-align:right; }
  .fmt-table td::before{
    content:attr(data-label);
    font-size:11px;
    font-weight:600;
    letter-spacing:.08em;
    text-transform:uppercase;
    color:var(--ink-soft);
    flex:none;
    text-align:left;
  }
  .fmt-table td.hl-col{ font-size:17px; }
  .fmt-table .brand-cell{ min-width:0; }
  .fmt-table .tb-logo{ margin-left:auto; }
  .fmt-table .dsp-badge, .fmt-table .dsp-text{ margin-left:auto; }
  .fmt-table .fmt-pill{ margin-left:auto; white-space:nowrap; }

  /* ---- 3. Boarding passes: stack main content above a horizontal stub ---- */
  .pass, .pass.priority{
    grid-template-columns:1fr !important;
  }
  .pass .main, .pass.priority .main{
    padding:22px 20px;
  }
  .pass .stub, .pass.priority .stub{
    flex-direction:row;
    justify-content:space-between;
    align-items:center;
    padding:12px 20px;
    gap:12px;
  }
  /* swap the vertical perforation for a horizontal one along the top */
  .pass .stub::before{
    left:0; right:0; top:-8px; bottom:auto; width:auto; height:16px;
    background:radial-gradient(circle at 50% 0,transparent 0 7px,var(--paper) 7px) 0 0/26px 16px repeat-x;
  }
  .pass .stub .brl{
    writing-mode:horizontal-tb;
    transform:none;
    font-size:10px;
  }
  .pass .stub .barcode{
    height:34px; width:70px;
    background:repeating-linear-gradient(90deg,#fff 0 2px,transparent 2px 4px,#fff 4px 5px,transparent 5px 9px,#fff 9px 10px,transparent 10px 13px);
  }
  .pass .stub .seat{ font-size:16px; }

  .pass .fields, .pass.priority .fields{
    grid-template-columns:repeat(3,1fr) !important;
    gap:14px !important;
  }
  .pass .field .fv{ font-size:17px; }
  .pass.priority .field.roas .fv{ font-size:26px; }
  .pass .toprow{ flex-wrap:wrap; row-gap:10px; }
  .pass .logo{ max-width:60%; }
  .pass .fmt{ font-size:9px; padding:5px 9px; }
  .pass .dsp{ flex-wrap:wrap; }

  /* ---- 4. Gated PDF form: fix CSS Grid min-width overflow bug + center ---- */
  .gated-card{
    grid-template-columns:1fr !important;
    padding:24px !important;
    gap:26px !important;
  }
  .gated-left, .gated-right{
    min-width:0;
    width:100%;
  }
  .gated-left{ text-align:center; }
  .gated-left h2{ font-size:clamp(24px,7vw,32px); }
  .gated-left p{ margin-left:auto; margin-right:auto; }
  .gated-right{
    margin:0 auto;
    max-width:100%;
    padding:24px 20px;
  }
  .gf-field input{ width:100%; box-sizing:border-box; }
}

/* Chatbot */
#chatbot-fab{position:fixed;bottom:28px;right:28px;z-index:80;width:56px;height:56px;border-radius:50%;
  background:var(--purple);box-shadow:0 6px 24px rgba(66,37,166,.45);display:flex;align-items:center;justify-content:center;
  cursor:pointer;transition:transform .3s var(--ease),box-shadow .3s var(--ease)}
#chatbot-fab:hover{transform:scale(1.08);box-shadow:0 8px 30px rgba(66,37,166,.6)}
#chatbot-fab svg{width:26px;height:26px}
.chatwin{position:fixed;bottom:96px;right:28px;z-index:90;width:380px;max-height:520px;border-radius:18px;
  background:#fff;box-shadow:0 20px 60px rgba(0,0,0,.22);display:flex;flex-direction:column;overflow:hidden;
  font-family:'DM Sans',Arial,sans-serif;transition:opacity .25s var(--ease),transform .25s var(--ease)}
.chatwin.hidden{opacity:0;pointer-events:none;transform:translateY(16px) scale(.96)}
.chat-head{display:flex;align-items:center;justify-content:space-between;padding:16px 18px;
  background:var(--grad-head);color:#fff;gap:10px}
.chat-head-l{display:flex;align-items:center;gap:12px}
.chat-avatar{width:34px;height:34px;border-radius:50%;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center}
.chat-title{font-size:14px;font-weight:700;letter-spacing:-.01em}
.chat-sub{font-size:11px;color:rgba(255,255,255,.7);font-weight:400}
.chat-close{background:none;border:none;color:rgba(255,255,255,.8);font-size:24px;cursor:pointer;padding:0 4px;line-height:1}
.chat-close:hover{color:#fff}
.chat-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;max-height:340px;min-height:200px}
.chat-msg{padding:12px 16px;border-radius:14px;font-size:14px;line-height:1.5;max-width:90%;font-weight:400;animation:msgIn .3s var(--ease)}
@keyframes msgIn{0%{opacity:0;transform:translateY(8px)}100%{opacity:1;transform:none}}
.chat-msg.bot{background:var(--lilac-2);color:var(--ink);align-self:flex-start;border-bottom-left-radius:4px}
.chat-msg.user{background:var(--purple);color:#fff;align-self:flex-end;border-bottom-right-radius:4px}
.chat-msg.typing{color:var(--ink-soft)}
.chat-msg.typing::after{content:"...";animation:dots 1.2s steps(4) infinite}
@keyframes dots{0%{content:"."}33%{content:".."}66%{content:"..."}100%{content:"."}}
.chat-followup{display:flex;flex-direction:column;gap:10px}
.chat-followup-label{font-size:12px;color:var(--ink-soft);font-weight:600;padding:2px 2px 0}
.chat-prompts{display:flex;flex-direction:column;gap:8px}
.chat-prompt{background:none;border:1px solid var(--hair);border-radius:12px;padding:10px 14px;font-size:13px;
  color:var(--purple);font-weight:500;text-align:left;cursor:pointer;font-family:'DM Sans',Arial,sans-serif;
  transition:background .2s,border-color .2s}
.chat-prompt:hover{background:var(--lilac-2);border-color:var(--purple)}
.chat-input-wrap{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--hair)}
.chat-input{flex:1;border:1px solid var(--hair);border-radius:12px;padding:10px 14px;font-size:14px;
  font-family:'DM Sans',Arial,sans-serif;outline:none;transition:border-color .2s}
.chat-input:focus{border-color:var(--purple)}
.chat-send{width:38px;height:38px;border-radius:50%;background:var(--purple);border:none;color:#fff;
  display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .2s}
.chat-send:hover{background:var(--magenta)}
@media(max-width:440px){.chatwin{right:8px;left:8px;width:auto;bottom:88px}}
