/* ==========================================================================
   SENATOR GROUP · DESIGN SYSTEM "SHARP"
   A faithful translation of sharplink.com's system onto Senator's locked brand.

   What the reference actually does (measured on the live site, 1440x900):
     · one grotesque, Neue Helvena, for everything, condensed to 82% and
       +0.085em tracking, only for micro labels
     · display 88 / 68 / 44 px, weight 400, negative tracking -3% / -2% / -1%
     · two canvases only: near-white #f3f3f3 and black, joined by long
       gradient washes of a single brand colour
     · a dotted blueprint grid, four columns wide, drawn across every band,
       with 6px accent squares dropped on the intersections
     · hairlines at 15% opacity. No shadows. No fills except chips
     · exactly one saturated accent, used on squares, arrow buttons and
       nothing else. Never as text
     · scroll is the interface: propositions light one at a time against a
       pinned render, statements brighten line by line

   For Senator the electric blue becomes the brand gold and the blue wash
   becomes the brand navy, because the brief will not let us introduce a
   colour the client does not already own. Everything else is the reference.
   ========================================================================== */

/* --------------------------------------------------------------------------
   FONTS
   -------------------------------------------------------------------------- */
/* Neue Helvena, variable: one file carries the whole family. Two axes, weight
   200 to 900 and width 75 to 125, so the display face and the condensed micro
   labels that used to be two fonts are now two settings of one. Latin plus
   latin-ext in a single subset (553 glyphs): every accent Spanish and French
   need is in it, checked against the cmap rather than assumed. */
@font-face{font-family:"Neue Helvena";
  src:url(../fonts/NeueHelvena-var.woff2) format("woff2-variations"),
      url(../fonts/NeueHelvena-var.woff2) format("woff2");
  font-weight:200 900;font-stretch:75% 125%;font-style:normal;font-display:swap}

/* --------------------------------------------------------------------------
   TOKENS
   -------------------------------------------------------------------------- */
:root{
  /* canvases. Two, and only two, warmed a step towards ivory for Senator */
  --paper:#f7f6f2;
  --ivory:#f3f1ec;
  --ink:#000000;

  /* The wash. Nine stops, taken from the luminance curve measured on the
     reference and re-hued to Senator navy. Long and luminous is only possible
     because the text theme flips with it, see .band--wash below. */
  --w0:#eef1f5;
  --w1:#c9d8ea;
  --w2:#93b0d4;
  --w3:#6b8fc0;
  --w4:#1a4172;
  --w5:#17427a;
  --w6:#0a2b55;
  --w7:#061a33;
  --w8:#03080f;
  --navy-1:var(--w1);
  --navy-2:var(--w3);
  --navy-3:var(--w5);
  --navy-4:var(--w7);

  /* the one accent. Fill and marker only, never a text colour */
  --gold:#d4af63;
  --gold-hi:#d4af63;   /* was #f0d593, a pale yellow. One gold ink now. */
  /* 19/09: was #9a6b26, which measures 4.31:1 on --paper and fails AA as text.
     It is the ink of .tbo__where, .tbo__draw-name and the New badge on careers,
     so it has to clear 4.5. #8f6222 measures 4.93:1 and is the same gold to look
     at. Its decorative uses (the loader, the live dot, the spin button ground)
     only gain from the extra depth. */
  --gold-deep:#8f6222;

  /* structure */
  --line-l:rgba(0,0,0,.15);
  --line-d:rgba(243,241,236,.15);
  --line-l-soft:rgba(0,0,0,.08);
  --line-d-soft:rgba(243,241,236,.08);

  /* text on each canvas. -dim is a scroll state, never a resting value */
  --tx-l:#000000;
  --tx-l-2:rgba(0,0,0,.62);
  --tx-l-dim:rgba(0,0,0,.55);
  --tx-d:#ffffff;
  --tx-d-2:rgba(255,255,255,.93);
  --tx-d-dim:rgba(255,255,255,.52);

  /* chips */
  --chip-l:rgba(0,0,0,.05);
  --chip-d:rgba(3,8,15,.46);

  /* metrics measured off the reference */
  --edge:clamp(20px,2vw,28px);
  --max:1440px;
  --col:calc((100% - var(--edge) * 2) / 4);
  --band:clamp(88px,10vw,176px);
  --r-panel:20px;

  --t-d1:clamp(44px,6.1vw,88px);
  --t-d2:clamp(34px,4.7vw,68px);
  --t-d3:clamp(26px,3.05vw,44px);
  --t-h3:clamp(22px,2.2vw,32px);
  --t-h4:clamp(19px,1.7vw,24px);
  --t-h5:16px;
  --t-body:16px;
  --t-sm:14px;
  --t-micro:12px;

  /* Motion. Two curves and one scale, so every movement on the site reads
     as one hand. --ease for what ARRIVES or RESPONDS to the hand: reveals,
     lines, masks, roll, plates, hover in. --ease-io for what COVERS or
     LEAVES: loader, veil, drawer, arrow passing, dive.
       --dur-1  micro     colour, chip ground, FAQ sign, live dip
       --dur-2  state     label roll, hover, FAQ, data-on theme, deck body, veil
       --dur-3  move      drawer, stack plate, nav, .rv, deck FLIP, marker
       --dur-4  arrival   lines (.lnr), photo mask, footer rise
       --dur-5  display   band wipe, .apart
       --stag   the step between siblings (lines, photos, drawer links)
     Scroll driven values (--out, --p, --drift, --fp, --x, --tlp) carry no
     duration: they are geometry. Four one-off pieces keep their own curve
     and length by name: the loader turn (.load__s), markturn and pulse (the
     map's coasts and routes moved onto the tokens, MOTION POWER 06). */
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-io:cubic-bezier(.76,0,.24,1);
  --dur-1:160ms;
  --dur-2:320ms;
  --dur-3:560ms;
  --dur-4:900ms;
  --dur-5:1250ms;
  --stag:80ms;
}

/* --------------------------------------------------------------------------
   BASE
   -------------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--paper);color:var(--tx-l);
  font-family:"Neue Helvena",Helvetica,Arial,sans-serif;
  font-size:var(--t-body);font-weight:400;line-height:1.5;letter-spacing:0;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img,svg,video{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
input,select,textarea{font:inherit;color:inherit}
h1,h2,h3,h4,h5,p,figure,ul,ol{margin:0}
ul,ol{padding:0;list-style:none}
::selection{background:var(--gold);color:var(--ink)}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) :focus-visible{outline-color:var(--gold-hi)}

.skip{position:absolute;left:-9999px;top:0;z-index:300;background:var(--ink);color:var(--ivory);
  padding:12px 18px;font-size:var(--t-micro)}
.skip:focus{left:12px;top:12px}
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* --------------------------------------------------------------------------
   TYPE
   -------------------------------------------------------------------------- */
/* The cover line is bold at the client's request (07/09). The rest of the
   display scale stays at 400, which is the reference's own voice. */
.d1{font-size:var(--t-d1);font-weight:400;line-height:.98;letter-spacing:-.03em}
.d2{font-size:var(--t-d2);font-weight:400;line-height:1.02;letter-spacing:-.02em}
.d3{font-size:var(--t-d3);font-weight:400;line-height:1.16;letter-spacing:-.012em}
.h3{font-size:var(--t-h3);font-weight:500;line-height:1.16;letter-spacing:-.01em}
.h4{font-size:var(--t-h4);font-weight:500;line-height:1.2;letter-spacing:-.01em}
.h5{font-size:var(--t-h5);font-weight:500;line-height:1.35;letter-spacing:0}
.lede{font-size:clamp(17px,1.35vw,19px);line-height:1.45;letter-spacing:-.005em}
.sm{font-size:var(--t-sm);line-height:1.5}
.tx2{color:var(--tx-l-2)}

/* Full width canvas, capped measure. :where() carries no specificity, so any
   component or utility that states its own width still wins, and prose that
   states nothing stops before it becomes unreadable. */
:where(.wrap,.foot__panel) p,
:where(.wrap,.foot__panel) ul:not([class]) li,
:where(.wrap,.foot__panel) ol:not([class]) li{max-width:78ch}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .tx2{color:var(--tx-d-2)}

/* --------------------------------------------------------------------------
   LAYOUT + THE DOTTED BLUEPRINT GRID
   Four columns of dotted rule, drawn edge to edge behind every band.
   -------------------------------------------------------------------------- */
.wrap{max-width:var(--max);margin:0 auto;padding:0 var(--edge);position:relative}
/* clip, not hidden: overflow:hidden made every band a scroll container, and a
   scroll container is the containing block of any position:sticky inside it,
   so the stack plate and the .side rail were released the moment their band
   scrolled. overflow:clip clips the same and creates no scroll container. */
.band{position:relative;padding:var(--band) 0;overflow:clip}
@supports not (overflow:clip){.band{overflow:hidden}}
.band--tight{padding:calc(var(--band) * .55) 0}
.band--dark{background:var(--ink);color:var(--tx-d)}
.band--wash{color:var(--tx-d);
  background:linear-gradient(180deg,var(--paper) 0%,var(--w0) 6%,var(--w1) 17%,var(--w2) 30%,
    var(--w3) 44%,var(--w4) 51%,var(--w5) 66%,var(--w6) 83%,var(--w8) 92%,var(--ink) 100%)}
.band--wash-up{color:var(--tx-d);
  background:linear-gradient(180deg,var(--ink) 0%,var(--w8) 8%,var(--w6) 18%,var(--w5) 32%,var(--w4) 46%,
    var(--w3) 53%,var(--w2) 70%,var(--w1) 84%,var(--w0) 94%,var(--paper) 100%)}
main > .band--wash-up:last-child{
  background:linear-gradient(180deg,var(--ink) 0%,var(--w8) 10%,var(--w6) 22%,var(--w5) 40%,var(--w4) 50%,
    var(--w3) 68%,var(--w2) 86%,var(--w1) 100%)}
main:has(> .band--wash-up:last-child) + .foot{
  background:linear-gradient(180deg,var(--w1) 0%,var(--w4) 5%,var(--w6) 34%,var(--w7) 62%,var(--w8) 100%)}
.band--dawn{background:linear-gradient(180deg,var(--navy-1) 0%,#e2e6ea 46%,var(--paper) 100%)}
.band--dusk{background:linear-gradient(180deg,var(--paper) 0%,#dbe2ea 40%,var(--navy-2) 100%);color:var(--tx-l)}


/* the grid itself */
.gridlines{display:none}
.band > .wrap{position:relative;z-index:1}

/* horizontal dotted rule, with the accent square at its left end */
.rule,.rule--plain{display:none}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .rule{
  background-image:linear-gradient(var(--line-d),var(--line-d))}


/* the standard head of a band: rule, kicker, display, optional right action */
.head{display:grid;grid-template-columns:1fr auto;align-items:end;gap:24px;margin-bottom:clamp(44px,4.4vw,68px)}
.head__k{margin-bottom:22px}
.head__a{align-self:center}

/* --------------------------------------------------------------------------
   BUTTONS
   Chip + a square that carries the arrow. The square is the only place the
   accent appears at size.
   -------------------------------------------------------------------------- */
.btn{display:inline-flex;align-items:center;gap:0;font-size:var(--t-micro);font-weight:500;
  letter-spacing:.085em;text-transform:uppercase;line-height:1}
.btn > span{display:inline-flex;align-items:center;height:38px;padding:0 18px;
  background:var(--chip-l);color:var(--tx-l);position:relative;overflow:hidden;white-space:nowrap;
  transition:background var(--dur-1) var(--ease)}
.btn > b{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;
  background:var(--gold);color:var(--ink);font-weight:400;overflow:hidden;
  transition:background var(--dur-1) var(--ease)}
.btn > b svg{width:15px;height:15px;display:block}
.btn:hover > span{background:rgba(0,0,0,.10)}
/* The arrow square holds its colour on hover. The gold body and the gold
   square are one object; repainting half of it on hover broke it in two.
   The arrow moving is the whole answer, see casino-scene.css. */
.btn:hover > b{background:var(--gold)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .btn > span{
  background:var(--chip-d);color:var(--ivory)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .btn:hover > span{background:rgba(3,8,15,.68)}
.btn--solid > span{background:var(--ivory);color:var(--ink)}
.btn--ghost > b{display:none}
.btn--ghost > span{background:var(--chip-l)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .btn--ghost > span{background:var(--chip-d)}

/* bare square arrow, used in nav and next to headings */
.sqbtn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;
  background:var(--chip-l);transition:background var(--dur-1) var(--ease)}
.sqbtn:hover{background:var(--gold);color:var(--ink)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .sqbtn{background:var(--chip-d)}
.sqbtn svg{width:15px;height:15px}

/* --------------------------------------------------------------------------
   NAV
   No chips, no dividers, no boxes. A bare wordmark far left and plain text far
   right, the way worldquantfoundry.com sets it, with the roll on hover: the
   label slides up and its own copy arrives from below. The runtime writes the
   copy into data-t after every language change, so the effect survives ES and FR.
   -------------------------------------------------------------------------- */
.nav{position:fixed;top:0;left:0;right:0;z-index:120;
  padding:28px var(--edge);pointer-events:none}
/* A graduated blur behind the chrome, the way the reference stacks it: four
   layers, each blurrier than the last and masked to a shorter window, so the
   page dissolves upward instead of ending on a hard edge. The colour scrim
   under it is what actually guarantees the labels stay legible, including
   where backdrop-filter is unsupported. */
.scrim{position:absolute;left:0;right:0;top:0;height:132px;pointer-events:none;z-index:-1}
.scrim i{position:absolute;inset:0;display:block}
.scrim i:nth-child(1){backdrop-filter:blur(1px);-webkit-backdrop-filter:blur(1px);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 45%,transparent 100%);
  mask-image:linear-gradient(180deg,#000 0%,#000 45%,transparent 100%)}
.scrim i:nth-child(2){backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 26%,transparent 68%);
  mask-image:linear-gradient(180deg,#000 0%,#000 26%,transparent 68%)}
.scrim i:nth-child(3){backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 12%,transparent 44%);
  mask-image:linear-gradient(180deg,#000 0%,#000 12%,transparent 44%)}
.scrim i:nth-child(4){backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,transparent 24%);
  mask-image:linear-gradient(180deg,#000 0%,transparent 24%)}
.scrim::after{content:"";position:absolute;inset:0;transition:background var(--dur-2) var(--ease);
  background:linear-gradient(180deg,rgba(247,246,242,.92) 0%,rgba(247,246,242,.62) 46%,rgba(247,246,242,0) 100%)}
.nav--on-dark .scrim::after{
  background:linear-gradient(180deg,rgba(3,8,15,.86) 0%,rgba(3,8,15,.52) 46%,rgba(3,8,15,0) 100%)}
.nav__in{max-width:calc(var(--max) - var(--edge) * 2);margin:0 auto;
  display:flex;align-items:center;justify-content:space-between;gap:20px;pointer-events:auto}
.nav__logo{display:flex;align-items:center;gap:13px;color:var(--tx-l);
  transition:color var(--dur-2) var(--ease)}
.nav__logo img{width:auto;filter:brightness(0);transition:filter var(--dur-2) var(--ease)}
.nav__logo .lk-s{height:34px}

/* The monogram, extruded and turning on hover. Same construction as the loader:
   the client's own mark stacked on Z. It stays one colour, so the depth comes
   from opacity falling off towards the back rather than from a second tone,
   and the whole stack inherits the chrome's colour so it still inverts. */
.nav__mark{position:relative;width:26px;height:34px;perspective:520px;flex:none}
.nav__mark span{position:absolute;inset:0;transform-style:preserve-3d;
  transform:rotateY(0deg)}
.nav__mark i{position:absolute;inset:0;display:block;background:currentColor;
  -webkit-mask:url(../logo/senator-s-black.png) no-repeat center/contain;
  mask:url(../logo/senator-s-black.png) no-repeat center/contain}
.nav__mark i:nth-child(1){transform:translateZ(4.5px)}
.nav__mark i:nth-child(2){transform:translateZ(3.5px);opacity:.86}
.nav__mark i:nth-child(3){transform:translateZ(2.5px);opacity:.74}
.nav__mark i:nth-child(4){transform:translateZ(1.5px);opacity:.63}
.nav__mark i:nth-child(5){transform:translateZ(.5px);opacity:.54}
.nav__mark i:nth-child(6){transform:translateZ(-.5px);opacity:.46}
.nav__mark i:nth-child(7){transform:translateZ(-1.5px);opacity:.39}
.nav__mark i:nth-child(8){transform:translateZ(-2.5px);opacity:.33}
.nav__mark i:nth-child(9){transform:translateZ(-3.5px);opacity:.28}
.nav__mark i:nth-child(10){transform:translateZ(-4.5px);opacity:.24}
.nav__logo:hover .nav__mark span,.nav__logo:focus-visible .nav__mark span{
  animation:markturn 1.15s cubic-bezier(.55,0,.2,1)}
@keyframes markturn{from{transform:rotateY(0deg)}to{transform:rotateY(360deg)}}
@media (prefers-reduced-motion:reduce){
  .nav__logo:hover .nav__mark span,.nav__logo:focus-visible .nav__mark span{animation:none}
}
/* clip-path and opacity are declared at rest so the wordmark's return (item 9,
   nav-intent) transitions too */
.nav__logo .lk-w{height:17px;padding-left:13px;border-left:1px solid var(--line-l);
  clip-path:inset(0);
  transition:filter var(--dur-2) var(--ease),border-color var(--dur-2) var(--ease),
    clip-path var(--dur-3) var(--ease),opacity var(--dur-2) var(--ease)}

.nav__right{display:flex;align-items:center;gap:clamp(20px,2.4vw,42px)}
.nav__menu{display:flex;align-items:center;gap:clamp(18px,2.2vw,38px)}
.nav__menu a{position:relative;display:block;overflow:hidden;white-space:nowrap;
  font-size:var(--t-micro);font-weight:500;letter-spacing:.085em;text-transform:uppercase;
  line-height:1.5;color:var(--tx-l);transition:color var(--dur-2) var(--ease)}
.nav__menu a > span{display:block;transition:transform var(--dur-2) var(--ease)}
.nav__menu a::after{content:attr(data-t);position:absolute;left:0;top:0;
  transform:translateY(100%);transition:transform var(--dur-2) var(--ease)}
.nav__menu a:hover > span{transform:translateY(-100%)}
.nav__menu a:hover::after{transform:translateY(0)}
/* the current section is marked by a rule under it, not by a box */
.nav__menu a[aria-current="page"]::before{content:"";position:absolute;left:0;right:0;bottom:0;
  height:1px;background:var(--gold)}

.nav__lang{display:flex;align-items:center;gap:10px}
.nav__lang button{font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:11px;font-weight:500;letter-spacing:.085em;line-height:1.5;
  color:var(--tx-l-2);transition:color var(--dur-2) var(--ease)}
.nav__lang button[aria-pressed="true"]{color:var(--tx-l)}
.nav__lang button[aria-pressed="true"]::after{content:"";display:block;height:1px;
  background:var(--gold)}

.nav__go{display:flex;align-items:center;justify-content:center;
  color:var(--tx-l);transition:color var(--dur-2) var(--ease),transform var(--dur-2) var(--ease)}
.nav__go:hover{transform:translateX(4px)}
.nav__go svg{width:22px;height:22px}

.nav__burger{display:none;width:26px;height:26px;align-items:center;justify-content:center}
.nav__burger span,.nav__burger span::before,.nav__burger span::after{
  display:block;width:20px;height:1px;background:currentColor;content:"";
  transition:transform var(--dur-2) var(--ease),background var(--dur-1) var(--ease)}
.nav__burger span{position:relative}
.nav__burger span::before{position:absolute;top:-6px}
.nav__burger span::after{position:absolute;top:6px}
/* three strokes that fold into a cross while the drawer is up: the outer two
   travel to the middle and turn, the middle one goes. Transform and background
   only, so the mark turns in place and never reflows the chrome. */
.nav__burger{transition:color var(--dur-2) var(--ease)}
.nav__burger[aria-expanded="true"] span{background:transparent}
.nav__burger[aria-expanded="true"] span::before{transform:translateY(6px) rotate(45deg)}
.nav__burger[aria-expanded="true"] span::after{transform:translateY(-6px) rotate(-45deg)}

/* over a dark ground the whole chrome inverts, cross-faded */
.nav--on-dark .nav__menu a,.nav--on-dark .nav__go,.nav--on-dark .nav__burger{color:var(--ivory)}
.nav--on-dark .nav__lang button{color:var(--tx-d-2)}
.nav--on-dark .nav__lang button[aria-pressed="true"]{color:var(--ivory)}
.nav--on-dark .nav__logo{color:var(--tx-d)}
.nav--on-dark .nav__logo img{filter:brightness(0) invert(1)}
.nav--on-dark .nav__logo .lk-w{border-left-color:var(--line-d)}

.drawer{position:fixed;inset:0;z-index:119;background:var(--ink);color:var(--ivory);
  display:none;flex-direction:column;justify-content:center;gap:6px;padding:0 var(--edge)}
.drawer.is-open{display:flex}
.drawer a{font-size:clamp(28px,7vw,44px);font-weight:400;letter-spacing:-.02em;padding:8px 0;
  border-bottom:1px solid var(--line-d)}

/* --------------------------------------------------------------------------
   HERO
   -------------------------------------------------------------------------- */
.hero{position:relative;height:100svh;min-height:640px;display:flex;flex-direction:column;
  padding:0 var(--edge) 30px;color:var(--tx-d);overflow:hidden;isolation:isolate}
.hero__media{position:absolute;inset:0;z-index:-2}
.hero__media img,.hero__media video{width:100%;height:100%;object-fit:cover;
  filter:grayscale(.42) contrast(1.06) brightness(.62) saturate(.8)}
.hero__media::after{content:"";position:absolute;inset:0;
  background:
    linear-gradient(180deg,rgba(4,10,20,.72) 0%,rgba(4,10,20,.34) 40%,rgba(4,10,20,.86) 100%),
    linear-gradient(90deg,rgba(4,10,20,.55) 0%,rgba(4,10,20,0) 62%)}
.hero__grid{display:none}
.hero__in{max-width:calc(var(--max) - var(--edge) * 2);margin:0 auto;width:100%;flex:1;
  display:flex;flex-direction:column;justify-content:center;padding-top:60px}
.js .hero{--out:0}
/* The exit, in three layers scrubbed by --out (0 at rest, 1 once the hero has
   left), which initHeroCinema writes. The foot goes first (gone by .36), the
   headline and CTA shrink and lift (gone by .45), and the footage darkens to
   ink while its frame narrows to the page margins. No transition: it is scrub.
   .hero__news lives inside .hero__foot on every hero page and rides that
   layer; the direct-child selector covers a page that ever puts the card
   beside the foot, without doubling the fade. At first paint --out is 0, so
   nothing here delays the LCP. */
.js .hero__foot,
.js .hero > .hero__news{
  opacity:clamp(0,1 - var(--out,0) * 2.8,1);
  transform:translateY(calc(var(--out,0) * 28px));
  will-change:transform,opacity}
.js .hero__in{
  opacity:clamp(0,1 - var(--out,0) * 2.2,1);
  transform:scale(calc(1 - var(--out,0) * .08)) translateY(calc(var(--out,0) * -24px));
  transform-origin:50% 30%;
  will-change:transform,opacity}
.js .hero__media::before{content:"";position:absolute;inset:0;z-index:1;
  background:var(--ink);opacity:calc(var(--out,0) * .92);pointer-events:none}
/* --------------------------------------------------------------------------
   B · THE PINNED HERO
   sticky under the fixed chrome; main is its containing block (no overflow,
   no transform on it, checked). Ink ground so the shrinking footage sits in
   night, not in paper. Once fully covered (--out = 1, class hero--under) it is
   taken out of compositing: the band above it is opaque, nothing is lost.
   -------------------------------------------------------------------------- */
.js .hero{position:sticky;top:0;z-index:0;background:var(--ink)}
.js .hero.hero--under{visibility:hidden}
/* The bands after the hero rise over it. Each becomes its own stacking
   context (z-index:0 keeps tree order, so the hero, earlier in the tree, is
   under) and a band that paints no ground of its own gets one on ::before:
   a ground on the band itself would be read by initTheme and re-stamp every
   flat page. The gradient bands already paint an opaque ground. */
.js .hero ~ .band{z-index:0}
.js .hero ~ .band:not(.band--dark):not(.band--wash):not(.band--wash-up):not(.band--dawn):not(.band--dusk)::before{
  content:"";position:absolute;inset:0;z-index:-1;background:var(--paper)}
/* The footage: no clip to the margins any more (the curtain does the framing),
   it shrinks to .94 and blurs to 6px as it is covered. The filter sits on the
   media itself (img/video), never on the hero, which is the sticky element.
   The scrim goes 0 to .92 over the gradient the hero already carries. */
/* 21/09: was scale(1 - out*.06). The media is inset:0 on the hero, so
   shrinking it by 6% on the way out pulled it off all four edges and the
   hero's own black showed as a frame -- "no puede verse recortado la
   imagen, es horrible; prefiero mas zoom". It leans IN now: the picture
   is never smaller than the hero, and the move is a slow push instead of
   a retreat. */
.js .hero__media{clip-path:none;transform:scale(calc(1 + var(--out,0) * .06));transform-origin:50% 50%;
  will-change:transform}
.js .hero__media img,.js .hero__media video{
  filter:grayscale(.42) contrast(1.06) brightness(.62) saturate(.8) blur(calc(var(--out,0) * 6px));
  will-change:filter}

/* --------------------------------------------------------------------------
   A · THE OVERTURE
   Hidden only while hero--ov is on, which the runtime sets before the first
   frame after load and removes when the choreography has ended. Without JS
   there is no hero--ov; with reduced motion initHeroCinema never runs.
   -------------------------------------------------------------------------- */
/* the footage: 1.08 to 1 in --dur-5. During the overture the scrub still
   applies and the same transition smooths it, so a hand that scrolls early
   sees a lag, never a jump, and the classes leave on equal values. */
.js .hero--ov .hero__media{transform:scale(1.08)}
.js .hero--ov.hero--in .hero__media{transform:scale(calc(1 + var(--out,0) * .06));
  transition:transform var(--dur-5) var(--ease)}
/* the headline: split into lines by initHeroCinema (splitLines, .lnr, .ln__i
   from 112% with 2.6deg, --stag between lines: the LINE REVEAL rules above do
   the work). Its lines take --dur-3, not the --dur-4 of a line further down
   the page: the same travel, quicker, because the headline has to be readable
   within 600 ms of the first paint on a repeat visit (rule 6) and at --dur-4
   its first line clears its mask only at about 550 ms, which under load is
   the wrong side of that line. A headline that cannot be split (inline
   markup) rises whole. */
.js .hero--ov .hero__h1.lnr .ln__i{transition-duration:var(--dur-3)}
.js .hero--ov .hero__h1:not(.lnr){opacity:0;transform:translateY(32px)}
.js .hero--ov.hero--tell .hero__h1:not(.lnr){opacity:1;transform:none;
  transition:opacity var(--dur-4) var(--ease),transform var(--dur-4) var(--ease)}
/* the chip pair, the credential and the lede: up 32px and in, stepped after
   the headline; the news card from the right, 48px, last */
.js .hero--ov .hero__cta > *,
.js .hero--ov .hero__cred,
.js .hero--ov .hero__lede{opacity:0;transform:translateY(32px)}
.js .hero--ov .hero__news{opacity:0;transform:translateX(48px)}
.js .hero--ov.hero--tell .hero__cta > *,
.js .hero--ov.hero--tell .hero__cred,
.js .hero--ov.hero--tell .hero__lede,
.js .hero--ov.hero--tell .hero__news{opacity:1;transform:none;
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease)}
.js .hero--ov.hero--tell .hero__cta > :nth-child(1){transition-delay:calc(var(--stag) * 3)}
.js .hero--ov.hero--tell .hero__cta > :nth-child(2){transition-delay:calc(var(--stag) * 4)}
.js .hero--ov.hero--tell .hero__cta > :nth-child(n+3){transition-delay:calc(var(--stag) * 5)}
.js .hero--ov.hero--tell .hero__cred{transition-delay:calc(var(--stag) * 4)}
.js .hero--ov.hero--tell .hero__lede{transition-delay:calc(var(--stag) * 5)}
.js .hero--ov.hero--tell .hero__news{transition-delay:calc(var(--stag) * 6);
  transition-duration:var(--dur-4)}
/* the drift is scrub: no transition on the figure */
.js .stack__media figure{--drift:0px;transform:translateY(var(--drift));will-change:transform}
.hero__h1{max-width:15ch;margin-bottom:34px}
.hero__cta{display:flex;flex-wrap:wrap;gap:10px}
.hero__foot{max-width:calc(var(--max) - var(--edge) * 2);margin:0 auto;width:100%;
  display:grid;grid-template-columns:1fr 1.25fr 1.15fr;align-items:end;gap:28px;padding-bottom:4px}
.hero__lede{max-width:42ch;font-size:clamp(15px,1.2vw,17px);line-height:1.42}
.hero__cred{display:flex;align-items:center;gap:12px}
.hero__cred img{height:26px;width:auto;opacity:.92;filter:brightness(0) invert(1)}
.hero__news{align-self:end;border:1px solid var(--line-d);background:rgba(4,10,20,.55);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  display:grid;grid-template-columns:1fr auto;transition:background var(--dur-1) var(--ease)}
.hero__news:hover{background:rgba(4,10,20,.75)}
.hero__news > div{padding:16px 18px}
.hero__news__top{display:flex;justify-content:space-between;gap:16px;margin-bottom:12px}
.hero__news b{display:block;font-size:15px;font-weight:400;line-height:1.34;letter-spacing:-.005em}
.hero__news > a{display:flex;align-items:center;justify-content:center;width:52px;
  border-left:1px solid var(--line-d)}

/* --------------------------------------------------------------------------
   STACK. The pinned proposition scroller.
   Media pinned right, list left. One item lit at a time.
   -------------------------------------------------------------------------- */
.stack{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:clamp(24px,3vw,64px);align-items:start}
.stack__list > li{padding:0 0 clamp(56px,9vh,110px)}
.stack__list > li:last-child{padding-bottom:0}
.stack__row{display:grid;grid-template-columns:1fr 1fr;gap:26px;max-width:none}
/* The scroll state has to beat the reveal: .js .rv.is-in{opacity:1} (0,3,0)
   would outrank a 0,2,0 row and a revealed row would never dim again, and
   .js [data-on]{transition:color} would replace the row's opacity transition
   by order. 0,5,0, with colour and transform kept in the list so the theme
   flip and the reveal still animate. transition-delay:0s so a row with .rv-d3
   lights on the frame, not 240ms later. */
/* .34 was the same bet the markets index made at .42 on the home, and it
   was replaced there for the same reason: a row nobody is pointing at is
   still a row somebody is reading. Every row stays legible and what the
   pointer changes is the emphasis, not whether the text can be read. */
.js:not(.rm) .stack__list .stack__row{opacity:.68;transition-delay:0s;
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-3) var(--ease),color var(--dur-2) var(--ease)}
.js:not(.rm) .stack__list .stack__row.is-on{opacity:1}
.stack__row .kick{margin-bottom:16px}
.stack__row > *{max-width:56ch}
.stack__media{position:sticky;top:0;height:100svh;display:grid;place-items:center;
  padding-left:var(--edge)}
/* every figure sits in cell 1/1, so two plates can be on screen at once for
   the length of one cross-fade */
.stack__media figure{position:relative;width:100%;max-width:min(560px,100%);grid-area:1/1}
/* Which plate is showing is a scroll state, so the stylesheet only takes the
   others away when there is JavaScript to bring them back, and only when the
   reader has not asked for less motion. Otherwise the column goes static and
   shows every photograph. */
.js:not(.rm) .stack__media [data-stack-media]{opacity:0;visibility:hidden;clip-path:inset(10%);
  transition:opacity var(--dur-3) var(--ease),visibility 0s var(--dur-3),
    clip-path var(--dur-4) var(--ease)}
.js:not(.rm) .stack__media [data-stack-media].is-on{opacity:1;visibility:visible;clip-path:inset(0);
  transition-delay:0s}
.js:not(.rm) .stack__media [data-stack-media].is-out{clip-path:inset(0)}
/* the incoming photograph lands from 1.10 (the counter-scale of the mask) while
   the outgoing one recedes to .97 (is-out, initStackBrandsPower) and fades;
   filter stays in the list so .ph keeps its colour return */
.js:not(.rm) .stack__media [data-stack-media] img{transform:scale(1.10);
  transition:transform var(--dur-4) var(--ease),filter var(--dur-2) var(--ease)}
.js:not(.rm) .stack__media [data-stack-media].is-on img{transform:none}
.js:not(.rm) .stack__media [data-stack-media].is-out img{transform:scale(.97)}
/* without JS, or with reduced motion, grid-area must not stack the plates:
   the column goes back to flow and shows every photograph */
html:not(.js) .stack__media,html.rm .stack__media{position:static;height:auto;padding-bottom:34px;display:block}
html:not(.js) .stack__media [data-stack-media] + [data-stack-media],
html.rm .stack__media [data-stack-media] + [data-stack-media]{margin-top:30px}
.stack__media img{width:100%;height:auto;max-height:64svh;object-fit:cover}

/* --------------------------------------------------------------------------
   STMT. A large statement whose first clause is lit and the rest dims,
   brightening word by word as it crosses the viewport.
   -------------------------------------------------------------------------- */
.stmt{font-size:var(--t-d3);font-weight:400;line-height:1.24;letter-spacing:-.012em;max-width:22ch;
  max-width:min(72ch,100%)}
.stmt w{display:inline}
.js .stmt w{color:var(--tx-d-dim);transition:color var(--dur-2) var(--ease)}
.js .stmt w.is-on{color:var(--tx-d)}
/* Lighter than the shared --tx-l-dim (rgba(0,0,0,.55)) that the rest of the
   site's quiet text uses, and lighter on purpose: here the dim state is not
   quiet text, it is the half of the sentence that has not arrived yet, and at
   .55 against a #f7f6f2 band it sat too close to the finished word to see the
   colour travelling. .45 is the floor: the sentence sets at 59px, so it is
   large text and owes 3:1, and .45 leaves 3.31:1 for a reader who never
   scrolls far enough to light it. Scoped to .stmt, so the token keeps its
   value everywhere else. */
.band--dawn .stmt w,.band:not(.band--dark):not(.band--wash):not(.band--wash-up) .stmt w{color:rgba(0,0,0,.45)}
.band--dawn .stmt w.is-on,.band:not(.band--dark):not(.band--wash):not(.band--wash-up) .stmt w.is-on{color:var(--tx-l)}

/* --------------------------------------------------------------------------
   ROWS. Numbered feature rows, dotted separators, line-art icon at the left.
   -------------------------------------------------------------------------- */
.rows{border-top:1px solid transparent;
  background-image:linear-gradient(var(--line-l),var(--line-l));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 0}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .rows{
  background-image:linear-gradient(var(--line-d),var(--line-d))}
.rows li{position:relative;display:grid;grid-template-columns:96px minmax(0,1fr) auto;gap:clamp(20px,3vw,48px);
  padding:34px 0;
  background-image:linear-gradient(var(--line-l),var(--line-l));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .rows li{
  background-image:linear-gradient(var(--line-d),var(--line-d))}
.rows li > div:nth-child(2){max-width:64ch}
.rows li > div:last-child{align-self:center}
.rows__ico{width:74px;height:74px;object-fit:contain;opacity:.55}
.rows--dim{position:relative}
.js:not(.rm) .rows--dim li{opacity:.42;transition-delay:0s;
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-3) var(--ease),color var(--dur-2) var(--ease)}
.js:not(.rm) .rows--dim li.is-on{opacity:1}

/* --------------------------------------------------------------------------
   RAIL. Numbered side cards with a faint line-art mark bottom right.
   -------------------------------------------------------------------------- */
.rail{display:grid;gap:0}
.rail li{position:relative;min-height:206px;padding:22px 24px 24px;overflow:hidden;
  background-image:linear-gradient(var(--line-l),var(--line-l));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 0}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .rail li{
  background-image:linear-gradient(var(--line-d),var(--line-d))}
.rail li .chip-n{margin-bottom:16px}
.rail li .h5{max-width:22ch}
.rail__art{position:absolute;right:14px;bottom:10px;width:132px;opacity:.28;pointer-events:none}

/* --------------------------------------------------------------------------
   DATA CARD. Dark panel, kicker, big number, sparkline, action bar.
   -------------------------------------------------------------------------- */
.dcard{position:relative;display:flex;flex-direction:column;justify-content:space-between;
  gap:26px;min-height:0;padding:22px;margin:0;color:var(--tx-d);overflow:hidden;
  background:linear-gradient(200deg,var(--w8) 0%,var(--w7) 30%,var(--w6) 60%,var(--w5) 100%)}
.dcard__grid{display:none}
.dcard__set{position:relative;display:grid;gap:26px}
.dcard__n{font-size:clamp(30px,3.4vw,46px);font-weight:400;letter-spacing:-.02em;line-height:1}
.dcard:has(.dcard__spark){min-height:520px}
/* The rebuilt panel (07/09): no empty plot frame. The client's own mark sits
   behind it as a watermark, cropped by the panel, and a hairline separates the
   live count from the pool it feeds. The count carries the weight; the honest
   "Awaiting feed" reads as a state, not as a headline. */
.dcard__seal{position:absolute;right:-14%;bottom:-16%;width:min(74%,340px);
  aspect-ratio:459/600;opacity:.07;pointer-events:none;background:var(--tx-d);
  -webkit-mask:url(../logo/senator-s-black.png) no-repeat center/contain;
  mask:url(../logo/senator-s-black.png) no-repeat center/contain}
.dcard:has(.dcard__seal){min-height:420px}
.dcard__row + .dcard__row{padding-top:26px;border-top:1px solid var(--line-d)}
.dcard__n--lead{font-size:clamp(46px,5.6vw,78px);letter-spacing:-.03em}
.dcard__n--wait{font-size:clamp(24px,2.4vw,32px);color:var(--tx-d-2)}
.dcard__spark{position:relative;flex:1 1 auto;min-height:120px}
.dcard__spark svg{width:100%;height:100%}
.dcard__foot{position:relative;display:grid;gap:16px;justify-items:start}
.dcard__foot .btn{align-self:stretch;width:100%}
.dcard__foot .btn > span{flex:1;justify-content:center;background:rgba(3,8,15,.46)}
.sq-inline{display:inline;font-size:14px}

/* provenance: the client's core worry, answered in the interface */
.prov{display:inline-flex;align-items:center;gap:7px;font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:11px;font-weight:500;letter-spacing:.085em;text-transform:uppercase;color:var(--tx-l-2)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .prov{color:var(--tx-d-2)}
.prov::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--tx-l-dim)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .prov::before{background:var(--tx-d-dim)}
/* The live dot is the one approved thing that moves while you read. The
   ring that used to be an animated box-shadow (a repaint per frame) is a
   second disc behind the dot, scaled and faded on the compositor; the
   runtime pauses both while the dot is off screen (initLive, .is-seen). */
.prov--live{position:relative;isolation:isolate}
.prov--live::before{background:var(--gold);animation:pulse 2.4s ease-in-out infinite}
.prov--live::after{content:"";position:absolute;left:0;top:50%;width:6px;height:6px;margin-top:-3px;
  border-radius:50%;background:var(--gold);opacity:.55;z-index:-1;
  animation:pulse-ring 2.4s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.55}}
@keyframes pulse-ring{0%,100%{opacity:.55;transform:scale(1)}50%{opacity:0;transform:scale(2.7)}}
.js .prov--live:not(.is-seen)::before,.js .prov--live:not(.is-seen)::after{animation-play-state:paused}

/* --------------------------------------------------------------------------
   TIMELINE
   The growth line. Scrolling down drives it sideways: the section is several
   viewports tall, the frame inside it is pinned, and the track slides. Without
   JavaScript the section collapses to its natural height and the track becomes
   an ordinary horizontal scroller, which is the same content and the same order.
   -------------------------------------------------------------------------- */
.tl{padding:0;overflow:visible}
.tl__pin{position:relative;display:flex;flex-direction:column;justify-content:center;
  min-height:100svh;padding:clamp(80px,9vw,140px) 0 clamp(40px,5vw,70px);overflow:hidden}
/* 500svh, not 420: the journey now ends with the last stop on the reading rail
   instead of when the list runs out of overflow, which is 72% further to walk
   (1400px to 2404px at 1440). At 420 the line would sprint. Kept under ~574svh
   so the section stays shorter than the jump reveal.mjs takes at 65%. */
.js .tl{height:560svh}
.js .tl__pin{position:sticky;top:0;height:100svh;
  /* the stops dissolve across the gutter on their way in and out, never
     inside the content column: opaque exactly from the wrap's edge. A mask
     makes no containing block, so the pin stays a pin (probed in fix-small) */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,
    #000 calc((100% - min(100%,var(--max))) / 2 + var(--edge)),
    #000 calc(100% - (100% - min(100%,var(--max))) / 2 - var(--edge)),transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,
    #000 calc((100% - min(100%,var(--max))) / 2 + var(--edge)),
    #000 calc(100% - (100% - min(100%,var(--max))) / 2 - var(--edge)),transparent 100%)}
.tl__track{overflow-x:auto;scrollbar-width:none;margin:0 calc(var(--edge) * -1);
  padding-inline:var(--edge)}
.tl__track::-webkit-scrollbar{display:none}
.js .tl__track{overflow:visible;margin:0;padding:0;
  transform:translate3d(var(--x,0px),0,0);will-change:transform}
.tl__list{display:flex;align-items:flex-start;gap:clamp(48px,7vw,140px);width:max-content}
.tl__stop{flex:0 0 auto;width:min(76vw,380px);position:relative;padding-top:40px;
  display:grid;align-content:start}
/* the band writes transition:color on every descendant (.js [data-on] *), and a
   scrubbed value under a transition lags the hand by a third of a second */
.js .tl .tl__stop,.js .tl .tl__stop *{transition:none}

/* --------------------------------------------------------------------------
   THE LINE ITSELF. Six stops, and the runtime writes two numbers: --tlp, how
   far along the journey we are (0 to 1, linear: the notches below are only
   honest while it is), and --tlk, which stop is on the rail.

   From those two, each stop derives its own state with no class and no JS per
   element: --i is its index, --on is 1 once the line has reached it, and --seg
   is how much of the rule to the NEXT stop has been drawn. The rail is always
   whole; the gold is what has been built. That is the difference between six
   identical gold squares lit at once and a line that gets made as you read it.
   -------------------------------------------------------------------------- */
.tl__stop:nth-child(1){--i:0}
.tl__stop:nth-child(2){--i:1}
.tl__stop:nth-child(3){--i:2}
.tl__stop:nth-child(4){--i:3}
.tl__stop:nth-child(5){--i:4}
.tl__stop:nth-child(6){--i:5}
.tl__stop:nth-child(n+7){--i:6}
.tl--live .tl__stop{
  /* --seg: how much of the rule to the NEXT stop is drawn.
     --lit: how lit this stop is, and it fills across the run of the rule that
     reaches it, so nothing switches on a step. Both are continuous in --tlp. */
  --seg:clamp(0,calc(var(--tlp,0) * 5 - var(--i)),1);
  --lit:clamp(0,calc(var(--tlp,0) * 5 - var(--i) + 1),1)}
.tl__stop::before{content:"";position:absolute;left:0;top:0;width:9px;height:9px;
  background:var(--gold)}
/* not yet reached: the square is drawn in the rail's own grey, and the gold
   floods it from the left as the line arrives. A dimmed gold square just reads
   as a broken one. */
.tl--live .tl__stop::before{background:
  linear-gradient(var(--gold),var(--gold)) no-repeat left center / calc(var(--lit,1) * 100%) 100%,
  linear-gradient(var(--line-d),var(--line-d))}
.tl__stop::after{content:"";position:absolute;left:9px;top:4px;
  width:calc(100% + clamp(48px,7vw,140px) - 9px);height:1px;background:currentColor;opacity:.26}
/* live, the rule is two layers: the whole rail, and the gold drawn across it at
   the pace the track walks */
.tl--live .tl__stop::after{opacity:1;background:
  linear-gradient(var(--gold),var(--gold)) no-repeat left center / calc(var(--seg,0) * 100%) 1px,
  linear-gradient(var(--line-d),var(--line-d)) no-repeat left center / 100% 1px}
.tl__stop:last-child::after{width:120px}
/* the line does not stop: it is drawn to the end and leaves the frame */
.tl--live .tl__stop:last-child{--seg:var(--lit)}
.tl--live .tl__stop:last-child::after{width:calc(120px + var(--lit,0) * 1180px)}
.tl__y{font-size:clamp(54px,7.2vw,104px);font-weight:400;letter-spacing:-.035em;line-height:.9}
.terr.tl__terr{width:64px;height:auto;margin:18px 0 0;opacity:.85}
/* the only layer in a stop that may dim: an <svg> of <path> has no text node,
   so nothing that guards text is measuring it. It comes up as its stop lands. */
.tl--live .terr.tl__terr{opacity:calc(.34 + .51 * var(--lit,1))}
.tl__stop h3{margin-top:18px}
.tl__stop .kick{margin-top:8px}
.tl__stop p{margin-top:12px}
.tl__bar{display:flex;align-items:center;gap:clamp(20px,3vw,44px);
  margin-top:clamp(30px,3.4vw,54px)}
/* --------------------------------------------------------------------------
   THE READ-OUT. It used to be a textContent swap: the glyphs changed in place
   and, because TODAY is 105px wide against 2021's 67 in this face (measured,
   and tabular-nums does not help: these are not all digits), the gold bar's
   origin jumped with it. Now the width is reserved and the year rolls the way
   the line runs, by transform inside a clipped box. Never opacity: opacity on
   text is exactly what reveal.mjs and degraded.mjs are watching for.
   -------------------------------------------------------------------------- */
.tl__bar .carou__idx{overflow:hidden;display:inline-block;vertical-align:bottom}
.tl__bar .carou__idx b{display:block;min-width:2.5em;
  transition:transform var(--dur-1) var(--ease)}
.tl__bar .carou__idx b.is-out{transform:translateY(calc(var(--rl,1) * -115%))}
.tl__bar .carou__idx b.is-now{transition:none;transform:translateY(calc(var(--rl,1) * 115%))}
/* --------------------------------------------------------------------------
   THE BAR IS A MAP. Six notches, one per stop, at the fraction where each one
   lands on the rail. They are only honest because the journey is linear in
   --tlp and the six stops are the same width (the runtime checks the pitch and
   gives up if the CMS breaks it). Gold covers what has been walked.
   -------------------------------------------------------------------------- */
.tl__prog{position:relative;flex:1;height:1px;background:var(--line-d)}
.tl__prog::before{content:"";position:absolute;left:0;top:-3px;width:100%;height:7px;
  background:
    linear-gradient(var(--line-d),var(--line-d)) no-repeat right center / 1px 100%,
    repeating-linear-gradient(90deg,var(--line-d) 0 1px,transparent 1px 20%)}
.tl__prog::after{content:"";position:absolute;left:0;top:0;height:1px;width:100%;
  transform:scaleX(var(--tlp,0));transform-origin:0 50%;background:var(--gold)}
/* the hint withdraws once the line has arrived: there is nothing left to scroll
   sideways for. Transform inside a clipped box, so no text ever loses opacity. */
.tl__hint{display:flex;align-items:center;gap:12px;white-space:nowrap;overflow:hidden}
.tl--live .tl__hint > *{display:block;
  transform:translateY(calc(clamp(0,calc((var(--tlp,0) - .82) * 10),1) * 320%))}
.tl__hint svg{width:17px;height:17px}
@media (max-width:760px){
  .js .tl{height:auto}
  .js .tl__pin{position:relative;height:auto;min-height:0;-webkit-mask-image:none;mask-image:none}
  .js .tl__track{overflow-x:auto;margin:0 calc(var(--edge) * -1);padding-inline:var(--edge);
    transform:none}
  .tl__stop{width:76vw}
}
@media (prefers-reduced-motion:reduce){
  .js .tl{height:auto}
  .js .tl__pin{position:relative;height:auto;min-height:0;-webkit-mask-image:none;mask-image:none}
  .js .tl__track{overflow-x:auto;transform:none}
}

/* --------------------------------------------------------------------------
   WIPE
   Measured on worldquantfoundry.com: a whole section is revealed by a
   clip-path running left to right, inset(0 100% 0 0) to inset(0). It is the
   move behind their statement bands and it costs one property.
   The clip sits on the band's .wrap, never on the band: Chromium applies a
   clip-path to the intersection maths, so a clipped band reports ratio 0 to
   every observer and never opens. With the clip on the child the band's own
   background paints first (no blank gap under a dark band) and the band is
   observable; the content then sweeps in left to right.
   -------------------------------------------------------------------------- */
.js .wipe > .wrap{clip-path:inset(0 100% 0 0);
  transition:clip-path var(--dur-5) var(--ease)}
.js .wipe.is-in > .wrap{clip-path:inset(0)}
/* landed: the clip goes, so the observers inside (the roulette's loop, the
   reveals) can see what is under it; inset(0) and none paint the same */
.js .wipe.is-open > .wrap{clip-path:none}

/* Their hero sets the two halves of a line apart and closes them as you
   arrive. Applied here to a statement's first and last line. */
.js .apart .ap-l,.js .apart .ap-r{display:inline-block;
  transition:transform var(--dur-5) var(--ease)}
.js .apart .ap-l{transform:translateX(-14%)}
.js .apart .ap-r{transform:translateX(14%)}
.js .apart.is-in .ap-l,.js .apart.is-in .ap-r{transform:none}

@media (prefers-reduced-motion:reduce){
  .js .wipe > .wrap{clip-path:none}
  .js .apart .ap-l,.js .apart .ap-r{transform:none}
}

/* --------------------------------------------------------------------------
   DECK
   The centre stage carousel from worldquantfoundry.com: the item you are on
   opens into a full panel in the middle, its neighbours fall back to their name
   and their mark, and two arrows move between them. Nothing scrolls and nothing
   advances on its own. Click, arrows and keyboard only: no drag, no wheel.
   The move is a FLIP on transform (never on flex-basis): the cell changes
   width by class, the card is always the open width and centred on its cell,
   trimmed by a clip-path that opens on the FLIP's own timing; the plate
   (.deck__plate) fades in and carries the brackets; the body sweeps open by
   clip-path. Radius 0. No text colour written: the runtime themes the cards.
   -------------------------------------------------------------------------- */
.deck{position:relative;
  --deck-closed:clamp(120px,14vw,210px);
  --deck-open:min(46vw,520px);
  --deck-inset:calc((var(--deck-open) - var(--deck-closed)) / 2)}
.deck__track{display:flex;align-items:stretch;justify-content:center;
  gap:clamp(18px,2.4vw,46px);list-style:none;padding:0;margin:0}

/* The cell. Its width is a class, never animated; the runtime FLIPs it on
   transform. It carries no other transition, so the invert step can switch
   its transition off without cancelling anything else (a running transition
   does not survive transition:none on the same element). */
.deck__item{flex:0 0 var(--deck-closed);min-width:0;display:grid;
  grid-template-columns:minmax(0,1fr);transition:none}
.deck__item.is-on{flex:0 0 var(--deck-open)}
.js:not(.rm) .deck__item{transition:transform var(--dur-3) var(--ease) var(--deck-dd,0s)}
/* the step between cells (MOTION POWER 07): data-dd is written by show() before
   the classes change, 0 on the card that closes, one --stag per step of
   distance, so the opening card, the furthest of the movers, goes last */
.deck__item[data-dd="1"]{--deck-dd:var(--stag)}
.deck__item[data-dd="2"]{--deck-dd:calc(var(--stag) * 2)}
.deck__item[data-dd="3"]{--deck-dd:calc(var(--stag) * 3)}
.deck__item.is-on{z-index:1}

/* The card: always the open width, centred on its cell by a negative margin
   (an auto grid track would grow to the card instead), so its content never
   reflows and its centre rides the cell's FLIP. A clip-path trims it to the
   cell when closed; that clip opening is the card opening, on the FLIP's own
   duration and curve. Its text colour cross-fades on the plate's own time.
   Radius 0: the only radius in the build is the footer. */
.deck__card{position:relative;isolation:isolate;display:flex;flex-direction:column;
  align-items:center;gap:16px;text-align:center;padding:clamp(20px,2.4vw,34px);
  border-radius:0;min-height:clamp(300px,42vw,560px);background:transparent}
.js .deck__item .deck__card{width:var(--deck-open);justify-self:start;
  margin-left:calc((100% - var(--deck-open)) / 2);
  clip-path:inset(0 var(--deck-inset));
  transition:clip-path var(--dur-3) var(--ease) var(--deck-dd,0s),color var(--dur-3) var(--ease),
    opacity var(--dur-3) var(--ease) var(--deck-d,0s),transform var(--dur-3) var(--ease) var(--deck-d,0s)}
.js .deck__item.is-on .deck__card{clip-path:inset(0)}
/* The resting ground. Stamped by the runtime once the plate has landed, so the
   open card's own computed background is the navy the contrast gate reads;
   the plate does the arriving, this does the staying. */
.deck__item.is-set .deck__card{
  background:linear-gradient(168deg,var(--w4) 0%,var(--w6) 58%,var(--w7) 100%)}
/* .ext would drop its mark as a stray glyph after the body: the mark is drawn
   on the chip instead, where every other .ext on the site carries it */
.deck__card.ext::after{content:none}

/* The plate: the panel that fades in and carries the corner brackets. A child
   of the card, so the card's clip trims it and its corners are the panel's
   real corners at every moment of the move. Behind the content. */
.deck__plate{position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(168deg,var(--w4) 0%,var(--w6) 58%,var(--w7) 100%)}
.js .deck__item .deck__plate{opacity:0;transform:scale(1.08);transform-origin:50% 50%;
  transition:opacity var(--dur-3) var(--ease) var(--deck-dd,0s),transform var(--dur-3) var(--ease) var(--deck-dd,0s)}
.js .deck__item.is-on .deck__plate{opacity:1;transform:none}
/* the corner brackets, only on the open one, growing from their own corner */
.deck__plate::before,.deck__plate::after{content:"";position:absolute;width:16px;height:16px;
  border:1px solid var(--gold)}
.deck__plate::before{left:14px;top:14px;border-right:0;border-bottom:0;transform-origin:0 0}
.deck__plate::after{right:14px;bottom:14px;border-left:0;border-top:0;transform-origin:100% 100%}
.js .deck__item .deck__plate::before,.js .deck__item .deck__plate::after{
  transform:scale(0);transition:transform var(--dur-1) var(--ease)}
.js .deck__item.is-on .deck__plate::before,.js .deck__item.is-on .deck__plate::after{
  transform:scale(1);transition-duration:var(--dur-2)}
.js .deck__item.is-on .deck__plate::after{transition-delay:calc(var(--stag) * 1.5)}

/* The name. No colour: the runtime themes the card. Closed, it is muted and
   seven tenths, a state armed under .js and lifted by the hand; open, full. */
.deck__name{font-size:clamp(18px,1.9vw,26px);font-weight:400;letter-spacing:-.015em;
  line-height:1.15}
.js:not(.rm) .deck__item .deck__name{opacity:.62;transform:scale(.7);
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-3) var(--ease),
    color var(--dur-3) var(--ease)}
.js:not(.rm) .deck__item.is-on .deck__name{opacity:1;transform:none}
.js:not(.rm) .deck__item:not(.is-on) .deck__card:hover .deck__name{opacity:1}
/* reduced motion has no scale, so the long domains get a smaller size closed;
   no dim either: with reduced motion every word reads at full contrast */
html.rm .deck__item:not(.is-on) .deck__name{font-size:clamp(15px,1.3vw,18px)}

/* The operating brand's mark, one tone, halfway between the name and the
   body. A closed card spans the ramp's crossover (name on daylight, mark on
   night), so the mark carries its own data-on, read at its own position. */
.deck__mark{width:clamp(52px,5vw,78px);height:auto;margin-top:auto;opacity:.4;
  filter:brightness(0)}
.deck__mark--word{width:clamp(120px,12vw,180px)}
.deck__mark[data-on="dark"]{filter:brightness(0) invert(1)}
.deck__item.is-on .deck__mark{opacity:.9;filter:brightness(0) invert(1)}
.js .deck__item .deck__mark{transition:opacity var(--dur-2) var(--ease),filter var(--dur-2) var(--ease)}
.js:not(.rm) .deck__item:not(.is-on) .deck__card:hover .deck__mark{opacity:.7}
/* reduced motion lifts nothing by hand, so the closed mark is whole from the
   start; its one-tone filter stays, read off the ramp, or the cream wordmark
   would vanish on the light half */
html.rm .deck__item:not(.is-on) .deck__mark{opacity:1}

/* The body: description and the chip, at the foot of the card. Hidden only
   under .js: it sweeps open top to bottom, one and a half --stag after the
   plate starts (the plan's 120, derived so the timing gate reads a token), and
   sweeps shut, bottom to top, on the card that closes, its copy gone in the
   first --dur-1 so the panel that closes over it never carries a ghost. */
.deck__body{display:grid;gap:16px;justify-items:center;margin-top:auto;width:100%}
.js .deck__item .deck__body{clip-path:inset(0 0 100% 0);opacity:0;visibility:hidden;
  transition:clip-path var(--dur-2) var(--ease),opacity var(--dur-1) var(--ease),
    visibility 0s var(--dur-2)}
.js .deck__item.is-on .deck__body{clip-path:inset(0);opacity:1;visibility:visible;
  transition-duration:var(--dur-3),var(--dur-2),0s;
  transition-delay:calc(var(--stag) * 1.5 + var(--deck-dd,0s)),calc(var(--stag) * 1.5 + var(--deck-dd,0s)),0s}
.deck__desc{max-width:34ch}
.deck__go::after{content:"";display:inline-block;width:7px;height:7px;margin-left:8px;
  border-top:1px solid currentColor;border-right:1px solid currentColor;
  transform:translateY(-1px) rotate(-45deg);opacity:.55}
.deck__card:hover .deck__go::after{opacity:1}

/* Focus: the card is wider than its cell, so the ring is drawn on the cell */
.js .deck__item .deck__card:focus-visible{outline:none}
.js .deck__item:has(> .deck__card:focus-visible){outline:2px solid var(--gold);outline-offset:3px}
.js .deck__item:has(> .deck__card[data-on="dark"]:focus-visible){outline-color:var(--gold-hi)}

/* Arrival. The deck carries .rv only as the trigger: its own fade is cancelled
   and the four cards arrive instead, one --stag apart. Armed under .js only. */
.js .deck.rv{opacity:1;transform:none;transition:none}
.js:not(.rm) .deck.rv .deck__card{opacity:0;transform:translateY(18px)}
.js:not(.rm) .deck.rv.is-in .deck__card{opacity:1;transform:none}
.deck__item:nth-child(2){--deck-d:var(--stag)}
.deck__item:nth-child(3){--deck-d:calc(var(--stag) * 2)}
.deck__item:nth-child(4){--deck-d:calc(var(--stag) * 3)}

/* The arrows: bare squares, radius 0, themed by the runtime from where they
   land on the ramp. Gold on hover is the accent's permitted use. */
.deck__nav{display:flex;justify-content:center;gap:12px;margin-top:clamp(26px,3vw,44px)}
.deck__nav button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;
  border-radius:0;background:var(--chip-l);
  transition:background var(--dur-1) var(--ease),opacity var(--dur-1) var(--ease)}
:is(.band--dark,.band--wash,.band--wash-up) .deck__nav button{background:var(--chip-d)}
.deck__nav[data-on="light"] button{background:var(--chip-l);color:var(--tx-l)}
.deck__nav[data-on="dark"] button{background:var(--chip-d);color:var(--tx-d)}
.deck__nav button:hover{background:var(--gold);color:var(--ink)}
.deck__nav button[disabled]{opacity:.3;pointer-events:none}
.deck__nav svg{width:18px;height:18px}

/* Without JavaScript: four equal cards, open, in a row, on their plates; no
   arrows. Every hidden state above lives under .js, so nothing else is needed. */
html:not(.js) .deck__item{flex:1 1 0}
html:not(.js) .deck__mark{opacity:.9;filter:brightness(0) invert(1)}
html:not(.js) .deck__nav{display:none}

/* Below 900px the deck is a column and every card is open and on its plate. */
@media (max-width:900px){
  .deck__track{flex-direction:column;gap:16px}
  .deck__item,.deck__item.is-on{flex:0 0 auto;width:100%}
  .deck__card{min-height:0;
    background:linear-gradient(168deg,var(--w4) 0%,var(--w6) 58%,var(--w7) 100%)}
  .js .deck__item .deck__card{width:auto;margin-left:0;justify-self:stretch;clip-path:none}
  .js .deck__item .deck__plate{opacity:1;transform:none}
  .js .deck__item .deck__plate::before,.js .deck__item .deck__plate::after{transform:none}
  .js:not(.rm) .deck__item .deck__name{opacity:1;transform:none}
  html.rm .deck__item:not(.is-on) .deck__name{font-size:clamp(18px,1.9vw,26px);opacity:1}
  .deck__mark{opacity:.9;filter:brightness(0) invert(1)}
  .js .deck__item .deck__body{clip-path:none;opacity:1;visibility:visible}
  .deck__nav{display:none}
}
/* Written at the specificity of the rules they cancel: a bare .deck__body
   (0,1,0) never beat .js .deck__item.is-on .deck__body (0,4,0), so the body
   still waited its stagger and swept open under reduced motion */
@media (prefers-reduced-motion:reduce){
  .js .deck__item,.js .deck__item .deck__card,.js .deck__item .deck__name,
  .js .deck__item .deck__mark,.js .deck__item .deck__plate,
  .js .deck__item .deck__plate::before,.js .deck__item .deck__plate::after,
  .js .deck__item.is-on .deck__plate::before,.js .deck__item.is-on .deck__plate::after,
  .js .deck__item .deck__body,.js .deck__item.is-on .deck__body{transition:none}
}
/* the client reads PDFs: every card open, two to a row */
@media print{
  .deck__track{flex-wrap:wrap}
  .deck__item,.deck__item.is-on{flex:1 1 40%}
  .js .deck__item .deck__card{width:auto;margin-left:0;clip-path:none;opacity:1;transform:none}
  .js .deck__item .deck__body{clip-path:none;opacity:1;visibility:visible}
  .js:not(.rm) .deck__item .deck__name{opacity:1;transform:none}
  .deck__nav{display:none}
}

/* --------------------------------------------------------------------------
   CAROUSEL
   Big plates, snapped, driven by the reader and never by a timer. The track is
   a native scroller, so touch and trackpad work with no script at all and the
   arrows are an enhancement on top. No frame, no box: the photograph is the
   object and the only chrome is a counter and two arrows.
   -------------------------------------------------------------------------- */
.carou{position:relative}
.carou__track{display:flex;gap:clamp(14px,1.6vw,26px);overflow-x:auto;
  scroll-snap-type:x mandatory;scroll-behavior:smooth;scroll-padding-inline:var(--edge);
  scrollbar-width:none;-ms-overflow-style:none;
  padding-bottom:4px;margin:0 calc(var(--edge) * -1);padding-inline:var(--edge)}
.carou__track::-webkit-scrollbar{display:none}
.carou__slide{flex:0 0 min(78%,860px);scroll-snap-align:center;margin:0}
.carou__slide:first-child{scroll-snap-align:start}
.carou__slide:last-child{scroll-snap-align:end}
.carou__shot{position:relative;aspect-ratio:16/10;overflow:hidden}
.carou__shot img{width:100%;height:100%;object-fit:cover}
.carou__slide figcaption{display:flex;justify-content:space-between;gap:20px;
  padding-top:14px}
/* the plate you are on is the only one at full strength */
.js .carou__slide{opacity:.34;transition:opacity var(--dur-2) var(--ease)}
.js .carou__slide.is-on{opacity:1}
/* keyboard: the plate that holds focus is lit at once, before the track has
   moved (the runtime centres it on focusin, and the scroll then syncs .is-on) */
.js .carou__slide:focus-within{opacity:1}

.carou__bar{display:flex;align-items:center;justify-content:space-between;gap:24px;
  margin-top:clamp(20px,2.2vw,32px)}
.carou__idx{font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:var(--t-micro);font-weight:500;letter-spacing:.085em;text-transform:uppercase}
.carou__idx b{font-family:"Neue Helvena",Helvetica,Arial,sans-serif;
  font-size:clamp(30px,3vw,44px);font-weight:400;letter-spacing:-.02em;line-height:1;
  margin-right:10px;vertical-align:-4px}
.carou__line{position:relative;flex:1;height:1px;background:var(--line-l);margin:0 clamp(20px,3vw,52px)}
[data-on="dark"] .carou__line,
:is(.band--dark,.band--wash,.band--wash-up) .carou__line{background:var(--line-d)}
.carou__line::after{content:"";position:absolute;left:0;top:0;height:1px;width:100%;
  transform:scaleX(var(--carou-p,.2));transform-origin:0 50%;background:var(--gold);
  transition:transform var(--dur-2) var(--ease)}
.carou__nav{display:flex;gap:10px}
.carou__nav button{display:flex;align-items:center;justify-content:center;width:46px;height:46px;
  background:var(--chip-l);transition:background var(--dur-1) var(--ease),opacity var(--dur-1) var(--ease)}
[data-on="dark"] .carou__nav button,
:is(.band--dark,.band--wash,.band--wash-up) .carou__nav button{background:var(--chip-d)}
.carou__nav button:hover{background:var(--gold);color:var(--ink)}
.carou__nav button[disabled]{opacity:.28;pointer-events:none}
.carou__nav svg{width:17px;height:17px}
@media (max-width:760px){.carou__slide{flex:0 0 88%}.carou__shot{aspect-ratio:4/3}}
@media (prefers-reduced-motion:reduce){
  .carou__track{scroll-behavior:auto}
  .js .carou__slide{opacity:1}
}

/* --------------------------------------------------------------------------
   MARKS
   A row of supplier or system lockups, knocked back to one tone the way the
   footer treats the group's own brands. The marks are the client's, lifted
   from senator_elements_2024.pdf, so they are theirs to show.
   -------------------------------------------------------------------------- */
.marks{display:flex;flex-wrap:wrap;align-items:center;gap:0}
.marks{gap:clamp(24px,3vw,52px)}
.marks li{display:flex;align-items:center}
.marks img{width:auto;height:26px;opacity:.62;filter:brightness(0);
  transition:opacity var(--dur-1) var(--ease)}
.marks img:hover{opacity:1}
.marks .m-tall{height:38px}
[data-on="dark"] .marks img,.marks[data-on="dark"] img,
:is(.band--dark,.band--wash,.band--wash-up) .marks img{filter:brightness(0) invert(1)}


/* a market's operating facts, in one band: what runs, what pays, what we back */
.ops{display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(34px,5vw,88px) clamp(34px,5vw,96px)}
.ops > li{display:grid;align-content:start;gap:16px;max-width:38ch}
.ops__v{font-size:clamp(24px,2.4vw,34px);font-weight:400;letter-spacing:-.018em;line-height:1.12}
@media (max-width:900px){.ops{grid-template-columns:1fr}}

/* --------------------------------------------------------------------------
   WORLD MAP
   Real geometry, not an illustration: Natural Earth 110m, public domain,
   projected Robinson and cropped to the latitudes the group actually trades in.
   The land is a hairline ground; the seven markets are the only things that
   carry weight, and each one is a link to its own page.
   -------------------------------------------------------------------------- */
.wmap{position:relative;margin:0}
.wmap figcaption{margin-top:clamp(20px,2.4vw,34px)}
.wmap__stage{position:relative}

/* A country's own outline, normalised to its own box. The same component
   carries the hover card here and the header of each market page, so a market
   is always introduced by its own shape rather than by a pin on a globe. */
.terr{width:100%;height:auto;display:block}
/* The stroke does not scale (it is drawn in screen pixels), so a width picked
   for the full page silhouette turned into a fat black edge on the 56px shape
   in the map's hover card, a tenth of its width. One fine hairline for both
   sizes: the outline reads as a drawn line, never as a border. */
.terr path{fill:currentColor;fill-opacity:.20;stroke:currentColor;stroke-width:1.2;
  stroke-linejoin:round;vector-effect:non-scaling-stroke}
.terr--solo{max-width:none}
.terr--solo path{fill-opacity:.10}

/* The card. Pure CSS: :has() on the stage swaps it, so it works with no
   JavaScript at all and there is nothing to keep in sync. */
.wmap__cards{position:absolute;left:0;top:0;width:min(320px,31%);pointer-events:none}
.wmap__card{position:absolute;left:0;top:0;width:100%;padding:20px 0 0;
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-2) var(--ease),visibility var(--dur-2)}
/* a hairline, not a panel. The system's rule is that structure is drawn with
   lines and never with boxes, and a floating card was the one place it was not. */
.wmap__card::before{content:"";position:absolute;left:0;top:0;width:100%;height:1px;
  background:currentColor;opacity:.34}
.wmap__card::after{content:"";position:absolute;left:0;top:-3px;width:7px;height:7px;
  background:var(--gold)}
.wmap__card.is-default{opacity:1;visibility:visible;transform:none}
.wmap__card__top{display:grid;grid-template-columns:56px 1fr;gap:16px;align-items:center}
.wmap__card .terr{color:var(--gold)}
.wmap__card .btn{pointer-events:auto}
.wmap:has(:is(.wmap__m,.wmap__flag):is(:hover,:focus-visible)) .wmap__card.is-default{opacity:0;visibility:hidden}
.wmap:has([data-m="hr"]:hover) .wmap__card[data-m="hr"],
.wmap:has([data-m="mk"]:hover) .wmap__card[data-m="mk"],
.wmap:has([data-m="gua"]:hover) .wmap__card[data-m="gua"],
.wmap:has([data-m="els"]:hover) .wmap__card[data-m="els"],
.wmap:has([data-m="sur"]:hover) .wmap__card[data-m="sur"],
.wmap:has([data-m="ke"]:hover) .wmap__card[data-m="ke"],
.wmap:has([data-m="mu"]:hover) .wmap__card[data-m="mu"],
.wmap:has([data-m="hr"]:focus-visible) .wmap__card[data-m="hr"],
.wmap:has([data-m="mk"]:focus-visible) .wmap__card[data-m="mk"],
.wmap:has([data-m="gua"]:focus-visible) .wmap__card[data-m="gua"],
.wmap:has([data-m="els"]:focus-visible) .wmap__card[data-m="els"],
.wmap:has([data-m="sur"]:focus-visible) .wmap__card[data-m="sur"],
.wmap:has([data-m="ke"]:focus-visible) .wmap__card[data-m="ke"],
.wmap:has([data-m="mu"]:focus-visible) .wmap__card[data-m="mu"]{
  opacity:1;visibility:visible;transform:none;pointer-events:auto}

/* the flags, which are also the map's controls */
.wmap__flags{display:grid;grid-template-columns:repeat(7,1fr);gap:0;
  margin-top:clamp(24px,3vw,44px);
  background-image:linear-gradient(var(--line-d),var(--line-d));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 0}
.wmap__flag{display:grid;justify-items:center;gap:12px;padding:22px 8px 0;
  border-right:1px solid var(--line-d);text-align:center}
.wmap__flags li:last-child .wmap__flag{border-right:0}
/* the flags carry their own colour at rest: hovering only lifts them
   (Javi, 07/09: apagadas y encendiendose al pasar el raton quedaba raro) */
.wmap__flag img{width:44px;height:auto;
  transition:filter var(--dur-2) var(--ease),transform var(--dur-2) var(--ease)}
.wmap__flag:is(:hover,:focus-visible) img{filter:brightness(1.1);transform:translateY(-3px)}
.wmap__flag .kick{transition:color var(--dur-2) var(--ease)}
@media (max-width:900px){
  .wmap__cards{position:relative;width:100%;margin-top:24px}
  .wmap__card{position:relative;transform:none}
  .wmap__card:not(.is-default){display:none}
  .wmap:has(:is(.wmap__m,.wmap__flag):is(:hover,:focus-visible)) .wmap__card.is-default{opacity:1;visibility:visible}
  .wmap__flags{grid-template-columns:repeat(4,1fr);row-gap:22px}
  .wmap__flag{border-right:0}
}
.wmap__svg{width:100%;height:auto;display:block}
.wmap__land path{fill:none;stroke:currentColor;stroke-width:1;stroke-linejoin:round;opacity:.34}
.wmap__mkts{isolation:isolate}
/* The dive moves ONE group with a transform. Animating the viewBox instead
   repaints every path in the map on every frame, which is what made it stutter. */
.wmap__all{transform-box:view-box;transform-origin:0 0;
  transition:transform var(--dur-4) var(--ease-io)}
.wmap--dive .wmap__all{will-change:transform}
.wmap--dive .wmap__land,.wmap--dive .wmap__arcs{will-change:opacity}
/* the dive. On click the frame drops into the country and the page hands over */
.wmap__land,.wmap__arcs,.wmap__lbl,.wmap__lead,.wmap__hq{
  transition:opacity var(--dur-1) var(--ease-io),visibility var(--dur-1)}
.wmap--dive .wmap__land{opacity:0;visibility:hidden}
.wmap--dive .wmap__arcs,.wmap--dive .wmap__lbl,
.wmap--dive .wmap__lead,.wmap--dive .wmap__hq{opacity:0}
.wmap--dive .wmap__cards,.wmap--dive .wmap__flags{opacity:0;
  transition:opacity var(--dur-2) var(--ease-io)}
.wmap--dive .wmap__zone{fill-opacity:.5;stroke-opacity:.9}
/* the halos hold still while the frame is moving: a halo mid-bloom (the
   arrival, if the click comes early) is work on every frame of the one
   animation that has to stay smooth */
.wmap--dive .wmap__halo{animation:none}
.wmap--dive .wmap__m:not(:hover) .wmap__halo{opacity:0}
.dive-veil{position:fixed;inset:0;z-index:300;background:var(--ink);
  opacity:0;pointer-events:none;transition:opacity var(--dur-2) var(--ease-io)}
.dive-veil.is-on{opacity:1}
@media (prefers-reduced-motion:reduce){
  .wmap--dive .wmap__land path,.dive-veil{transition:none}
}
/* the target is the whole band from pin to label, not the 7px pin */
.wmap__hit{fill:transparent;pointer-events:all}

/* The coastlines draw themselves in when the band arrives. */
.js .wmap__land path{stroke-dasharray:2400;stroke-dashoffset:2400;
  transition:stroke-dashoffset var(--dur-5) var(--ease)}
.js .wmap.is-live .wmap__land path{stroke-dashoffset:0}

/* Seven routes out of the head office. This is the group's own argument drawn:
   one operator in Budapest, seven countries, and every line starts in the same
   place. They draw in sequence once the map is on screen. */
.wmap__arc{fill:none}
.wmap__arcs path{fill:none;stroke:var(--gold);stroke-width:1.2;stroke-opacity:.34;
  vector-effect:non-scaling-stroke}
.js .wmap__arcs path{stroke-dasharray:1600;stroke-dashoffset:1600;
  transition:stroke-dashoffset var(--dur-3) var(--ease),stroke-opacity var(--dur-2) var(--ease)}
.js .wmap.is-live .wmap__arcs path{stroke-dashoffset:0}
/* the seven routes leave Budapest one at a time: each draws for --dur-3 and
   the next leaves one --dur-2 later, nearest market first (MOTION POWER 06) */
.js .wmap.is-live [data-a="hr"]{transition-delay:var(--dur-4)}
.js .wmap.is-live [data-a="mk"]{transition-delay:calc(var(--dur-4) + var(--dur-2))}
.js .wmap.is-live [data-a="gua"]{transition-delay:calc(var(--dur-4) + var(--dur-2) * 2)}
.js .wmap.is-live [data-a="els"]{transition-delay:calc(var(--dur-4) + var(--dur-2) * 3)}
.js .wmap.is-live [data-a="sur"]{transition-delay:calc(var(--dur-4) + var(--dur-2) * 4)}
.js .wmap.is-live [data-a="ke"]{transition-delay:calc(var(--dur-4) + var(--dur-2) * 5)}
.js .wmap.is-live [data-a="mu"]{transition-delay:calc(var(--dur-4) + var(--dur-2) * 6)}
/* at rest the routes answer hover at once again */
.js .wmap.is-rest .wmap__arcs path{transition-delay:0s}
/* while one market is being read, its own route is the only lit one */
.wmap:has(:is(.wmap__m,.wmap__flag):is(:hover,:focus-visible)) .wmap__arcs path{stroke-opacity:.09}
.wmap:has([data-m="hr"]:is(:hover,:focus-visible)) [data-a="hr"],
.wmap:has([data-m="mk"]:is(:hover,:focus-visible)) [data-a="mk"],
.wmap:has([data-m="gua"]:is(:hover,:focus-visible)) [data-a="gua"],
.wmap:has([data-m="els"]:is(:hover,:focus-visible)) [data-a="els"],
.wmap:has([data-m="sur"]:is(:hover,:focus-visible)) [data-a="sur"],
.wmap:has([data-m="ke"]:is(:hover,:focus-visible)) [data-a="ke"],
.wmap:has([data-m="mu"]:is(:hover,:focus-visible)) [data-a="mu"]{stroke-opacity:.95}

/* the head office, which is not a market and never pretends to be one */
.wmap__hq rect{fill:none;stroke:currentColor;stroke-width:1.4;vector-effect:non-scaling-stroke}
.wmap__hq__ring{fill:none;stroke:currentColor;stroke-width:1;stroke-opacity:.4;
  vector-effect:non-scaling-stroke}
/* the ring is 56 units round: the dash is the whole ring, drawn in --dur-4 */
.js .wmap__hq__ring{stroke-dasharray:60;stroke-dashoffset:60;transition:stroke-dashoffset var(--dur-4) var(--ease)}
.js .wmap.is-live .wmap__hq__ring{stroke-dashoffset:0}
.wmap__hq__t{font-size:13px;fill-opacity:.55}


.wmap__m{cursor:pointer}
.wmap__zone{fill:currentColor;fill-opacity:.28;stroke:currentColor;stroke-width:1;stroke-opacity:.55;
  transition:fill-opacity var(--dur-2) var(--ease)}
.wmap__lead{fill:none;stroke:currentColor;stroke-width:.8;stroke-opacity:.34;
  transition:stroke-opacity var(--dur-2) var(--ease)}
.wmap__pin{fill:var(--gold);transform-box:fill-box;transform-origin:center}
.wmap__halo{fill:var(--gold);opacity:.14;transform-box:fill-box;transform-origin:center;
  transform:scale(.55);transition:transform var(--dur-2) var(--ease),opacity var(--dur-2) var(--ease)}
.wmap__lbl{font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:15px;font-weight:500;letter-spacing:.085em;text-transform:uppercase;
  fill:currentColor;fill-opacity:.72;dominant-baseline:middle;
  transition:fill-opacity var(--dur-2) var(--ease)}
.wmap__m:is(:hover,:focus-visible) .wmap__zone{fill-opacity:.62}
.wmap__m:is(:hover,:focus-visible) .wmap__lead{stroke-opacity:.8}
.wmap__m:is(:hover,:focus-visible) .wmap__lbl{fill-opacity:1}
.wmap__m:hover .wmap__halo{transform:scale(1);opacity:.3}
.wmap__m:focus-visible{outline:none}
.wmap__m:focus-visible .wmap__halo{transform:scale(1.25);opacity:.5}

/* Arrival, once. The routes leave Budapest in order and at the end of each
   one the pin lands, the country fills, the label lights and the halo
   settles. Then the map rests: nothing moves while you read, and hover or
   focus answer the hand through the transitions above. Every hidden state is
   under .js and .wmap:not(.is-live); the runtime (initMap, through watch())
   turns the map live on screen, after a deep jump, or at 6 s at the latest,
   and .is-rest after the sequence releases the elements to their own rules.
   A market's clock, --at, is the moment its route reaches it: the arcs
   draw for --dur-5 plus their own step, so the pin lands as the line arrives. */
/* MOTION POWER 06: the pin lands (1.6 to 1) instead of sprouting, the halo
   blooms open to 3x and fades ONCE before settling on its resting .14, the
   label slides in from its pin, and the clock --at is the moment the route
   reaches the market (route start + route length, one --dur-1 early). */
.js .wmap:not(.is-live) .wmap__pin{opacity:0;transform:scale(1.6)}
.js .wmap:not(.is-live) .wmap__halo{opacity:0}
.js .wmap:not(.is-live) .wmap__zone,.js .wmap:not(.is-live) .wmap__lbl{opacity:0}
.js .wmap.is-live .wmap__pin{animation:map-land var(--dur-2) var(--ease) backwards}
.js .wmap.is-live .wmap__halo{animation:map-bloom var(--dur-4) var(--ease) backwards}
.js .wmap.is-live .wmap__zone{animation:map-in var(--dur-3) var(--ease) backwards}
.js .wmap.is-live .wmap__lbl{animation:map-lbl-l var(--dur-3) var(--ease) backwards}
/* :where() keeps this at the weight of the rule above, so the .is-rest and
   reduced-motion resets below (same weight, later) reach these labels too */
.js .wmap.is-live .wmap__lbl:where([text-anchor="end"]){animation-name:map-lbl-r}
.js .wmap.is-live .wmap__hq__t{animation-delay:var(--dur-2)}
.js .wmap.is-live [data-m="hr"]{--at:calc(var(--dur-4) + var(--dur-3) - var(--dur-1))}
.js .wmap.is-live [data-m="mk"]{--at:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2))}
.js .wmap.is-live [data-m="gua"]{--at:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 2)}
.js .wmap.is-live [data-m="els"]{--at:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 3)}
.js .wmap.is-live [data-m="sur"]{--at:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 4)}
.js .wmap.is-live [data-m="ke"]{--at:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 5)}
.js .wmap.is-live [data-m="mu"]{--at:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 6)}
.js .wmap.is-live .wmap__m .wmap__pin{animation-delay:var(--at)}
.js .wmap.is-live .wmap__m .wmap__zone{animation-delay:calc(var(--at) + var(--stag))}
.js .wmap.is-live .wmap__m .wmap__lbl{animation-delay:calc(var(--at) + var(--stag) * 2)}
.js .wmap.is-live .wmap__m .wmap__halo{animation-delay:calc(var(--at) + var(--stag) * 3)}
@keyframes map-land{from{opacity:0;transform:scale(1.6)}to{opacity:1;transform:scale(1)}}
@keyframes map-bloom{
  0%{opacity:0;transform:scale(.4)}
  14%{opacity:.6;transform:scale(.7)}
  72%{opacity:0;transform:scale(3)}
  73%{opacity:0;transform:scale(.55)}
  100%{opacity:.14;transform:scale(.55)}}
@keyframes map-in{from{opacity:0}to{opacity:1}}
@keyframes map-lbl-l{from{opacity:0;transform:translateX(-14px)}to{opacity:1;transform:none}}
@keyframes map-lbl-r{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}
/* the flags open on their market's clock, one --dur-2 apart */
.js .wmap:not(.is-live) .wmap__flag{clip-path:inset(0 0 100% 0)}
.js .wmap__flag{transition:clip-path var(--dur-4) var(--ease),color var(--dur-2) var(--ease)}
.js .wmap.is-live .wmap__flags li:nth-child(1) .wmap__flag{transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1))}
.js .wmap.is-live .wmap__flags li:nth-child(2) .wmap__flag{transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2))}
.js .wmap.is-live .wmap__flags li:nth-child(3) .wmap__flag{transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 2)}
.js .wmap.is-live .wmap__flags li:nth-child(4) .wmap__flag{transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 3)}
.js .wmap.is-live .wmap__flags li:nth-child(5) .wmap__flag{transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 4)}
.js .wmap.is-live .wmap__flags li:nth-child(6) .wmap__flag{transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 5)}
.js .wmap.is-live .wmap__flags li:nth-child(7) .wmap__flag{transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 6)}
.js .wmap.is-rest .wmap__flag{transition-delay:0s}
/* the default card enters last; a hand on a market during the arrival still
   swaps it at once (the delay only holds while nothing is hovered or focused) */
.js .wmap:not(.is-live) .wmap__card.is-default{opacity:0;transform:translateY(8px)}
.js .wmap.is-live:not(.is-rest):not(:has(:is(.wmap__m,.wmap__flag):is(:hover,:focus-visible))) .wmap__card.is-default{
  transition-delay:calc(var(--dur-4) + var(--dur-3) - var(--dur-1) + var(--dur-2) * 6 + var(--dur-4))}
/* at rest (and when the map lands already on screen) nothing is animating:
   hover and focus own the halo again and getAnimations() on the map is empty */
.js .wmap.is-rest .wmap__pin,.js .wmap.is-rest .wmap__halo,.js .wmap.is-rest .wmap__zone,
.js .wmap.is-rest .wmap__lbl{animation:none}
@media (max-width:760px){.wmap__lbl{font-size:26px}.wmap__land path{stroke-width:1.4}}

/* --------------------------------------------------------------------------
   CARDS + MEDIA
   -------------------------------------------------------------------------- */
.cards{--cards-line:var(--line-l);
  display:grid;grid-template-columns:repeat(4,1fr);gap:1px;
  background:var(--cards-line)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .cards{--cards-line:var(--line-d)}
.cards--3{grid-template-columns:repeat(3,1fr)}
.cards--2{grid-template-columns:repeat(2,1fr)}
.card{position:relative;background:var(--paper);padding:22px;display:flex;flex-direction:column;gap:14px;
  transition:background var(--dur-1) var(--ease)}
:is(.band--dark,.band--wash,.band--wash-up) .card{background:var(--ink)}
.card:hover{background:var(--ivory)}
:is(.band--dark,.band--wash,.band--wash-up) .card:hover{background:#0a0a0a}
.card__media{position:relative;aspect-ratio:4/3;overflow:hidden;margin:-22px -22px 4px}
.card__media img{width:100%;height:100%;object-fit:cover}
.card__mark{display:none}

/* the one photo treatment. It is what makes ~100 venues shot by seven
   countries read as one brand. Colour returns on hover.
   19/09: it used to be grayscale(.76) brightness(.86), and it was doing that
   unifying job twice. The twelve room shots are now graded on the way in --
   shadows lifted, the green/magenta spread across the set pulled from 13.1 to
   4.5 -- so the set already reads as one hand. Three quarters of the colour
   removed on top of that is what made the rooms look dead on the page, and it
   was throwing the grade away: Javi, looking at the regraded files in situ,
   "las imagenes no las cambiaste". A touch of grey still ties the set; the
   photograph now survives it. */
.ph{filter:grayscale(.18) brightness(.97) contrast(1.02);
  transition:filter var(--dur-2) var(--ease)}
a:hover .ph,.card:hover .ph,figure:hover .ph{filter:grayscale(0) brightness(1) contrast(1)}
.ph--light{filter:grayscale(.3) brightness(.99)}

/* portrait / venue grid, on the brand wash with the grid overlaid */
.people{display:grid;grid-template-columns:repeat(4,1fr);gap:26px}
.people figure{margin:0;display:flex;flex-direction:column;height:100%}
.people__img{position:relative;aspect-ratio:1/1;overflow:hidden;
  background:linear-gradient(180deg,var(--navy-3) 0%,var(--navy-2) 100%)}
.people__img img{width:100%;height:100%;object-fit:cover;filter:grayscale(1) contrast(1.06)}

.people__mark{display:none}
.people figcaption{padding-top:14px;display:flex;flex-direction:column;gap:6px;flex:1}
.people figcaption > .btn:last-child,.people figcaption > a:last-child{margin-top:auto;padding-top:12px}

/* --------------------------------------------------------------------------
   LIST ROWS. Date chip, title, action. Licensing, news, filings.
   -------------------------------------------------------------------------- */
.rowlist{display:grid;grid-template-columns:auto minmax(0,1fr) auto}
.rowlist li{position:relative;display:grid;grid-template-columns:subgrid;grid-column:1/-1;
  gap:24px;align-items:center;padding:20px 0;
  background-image:linear-gradient(var(--line-l),var(--line-l));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .rowlist li{
  background-image:linear-gradient(var(--line-d),var(--line-d))}
@supports not (grid-template-columns:subgrid){
  .rowlist{display:block}
  .rowlist li{grid-template-columns:auto minmax(0,1fr) auto}
}
/* .rows caps its measure and .rowlist did not, so body copy in a register ran
   to 175 characters unless the page author remembered to cap it by hand. */
.rowlist li > *:nth-child(2){max-width:78ch}

.dchip{display:inline-flex;align-items:center;height:30px;padding:0 12px;background:var(--chip-l);
  font-size:11px;font-weight:500;letter-spacing:.085em;text-transform:uppercase;white-space:nowrap}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .dchip{background:var(--chip-d)}

/* sticky section rail, used on licensing / investors-style pages */
.side{position:sticky;top:104px;display:grid;gap:1px;align-content:start}
.side a{display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;background:var(--chip-l);
  font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:var(--t-micro);font-weight:500;letter-spacing:.085em;text-transform:uppercase}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .side a{background:var(--chip-d)}
.side a.is-on::before{content:"";width:6px;height:6px;background:var(--gold)}

/* --------------------------------------------------------------------------
   FAQ / ACCORDION
   -------------------------------------------------------------------------- */
.faq li{background-image:linear-gradient(var(--line-l),var(--line-l));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .faq li{
  background-image:linear-gradient(var(--line-d),var(--line-d))}
.faq__q{display:grid;grid-template-columns:auto 1fr auto;gap:24px;align-items:center;width:100%;
  padding:20px 0;text-align:left}
.faq__q h3{font-size:var(--t-h4);font-weight:400;letter-spacing:-.01em}
.faq__t{position:relative;display:flex;align-items:center;justify-content:center;
  width:34px;height:34px;background:var(--ink);color:var(--ivory);flex:none}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .faq__t{background:var(--chip-d)}
/* 0,3,0 on purpose: .js [data-on] * sets transition:color on everything inside a
   themed li, and this has to win in both directions of the toggle */
.faq .faq__q .faq__t{transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease)}
/* the sign is drawn, not typed: two strokes in currentColor, a plus that turns
   into a cross. The open square is gold, the one fill the accent is allowed */
.faq__t::before,.faq__t::after{content:"";position:absolute;left:50%;top:50%;width:13px;height:1px;
  background:currentColor;
  transform:translate(-50%,-50%) rotate(var(--r,0deg));
  transition:transform var(--dur-2) var(--ease)}
.faq__t::after{--r:90deg}
.faq__q[aria-expanded="true"] .faq__t::before{--r:45deg}
.faq__q[aria-expanded="true"] .faq__t::after{--r:135deg}
.faq__q[aria-expanded="true"] .faq__t{background:var(--gold);color:var(--ink)}
/* display:none to block cannot transition: .is-open puts the panel in the flow
   clipped to nothing, .is-live one frame later opens the clip top-down. Height
   is never animated. Under .js only: without the runtime the markup's .is-open
   simply shows */
.faq__a{display:none;padding:0 58px 26px calc(var(--col) * 0 + 58px);max-width:78ch}
.faq__a.is-open{display:block}
/* without the runtime the buttons do nothing: every answer stays in the flow */
html:not(.js) .faq__a{display:block}
.js .faq .faq__a.is-open{clip-path:inset(0 0 0 0);opacity:1;
  transition:clip-path var(--dur-2) var(--ease),opacity var(--dur-2) var(--ease),color var(--dur-2) var(--ease)}
.js .faq .faq__a.is-open:not(.is-live){clip-path:inset(0 0 100% 0);opacity:0}
.faq__a p + p{margin-top:12px}

/* --------------------------------------------------------------------------
   FORMS
   -------------------------------------------------------------------------- */
.field{display:grid;gap:8px}
.field input,.field select,.field textarea{height:44px;padding:0 14px;background:transparent;
  border:1px solid var(--line-l);color:inherit;font-size:15px;width:100%;border-radius:0}
/* focus lifts the hairline to the text colour itself; :user-invalid thickens
   the bottom edge with no script and no markup; the demo note arrives from
   below. :enabled is there for specificity only (0,3,1 beats [data-on] .field
   input at 0,2,1): a disabled field cannot take focus anyway. */
.field :is(input,select,textarea):enabled{transition:border-color var(--dur-1) var(--ease)}
.field :is(input,select,textarea):focus:enabled{border-color:currentColor}
.field :is(input,select,textarea):enabled:user-invalid{border-color:currentColor;border-bottom-width:2px}
[data-demo-note]:not([hidden]){animation:note-in var(--dur-3) var(--ease)}
@keyframes note-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.field select{appearance:none;-webkit-appearance:none;padding-right:38px;
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.6'%3E%3Cpath d='M6 10l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:15px}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .field select{
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f3f1ec' stroke-width='1.6'%3E%3Cpath d='M6 10l6 6 6-6'/%3E%3C/svg%3E")}
.field select option{color:#000;background:#fff}

/* --------------------------------------------------------------------------
   DROPDOWN. The browser paints a native option list with the operating
   system's own type, colours and radius: the one control on the page that
   refuses the design. So the runtime keeps the <select> as the source of truth
   (it still submits, and without JavaScript it is all there is) and draws a
   list of our own over it: same hairlines, same type, same two text colours,
   no box and no shadow.
   -------------------------------------------------------------------------- */
.sel{position:relative}
/* A band clips its own overflow so nothing escapes it while it animates. That
   also amputates an open dropdown: measured on casino-finder, the country list
   is 280px tall and its band ends 90px above the bottom of it, so five of the
   options were cut off with no way to reach them. The clip is lifted only
   while a select is actually open, which is the one moment it must not apply. */
.band:has(.sel[data-open]),
.wrap:has(.sel[data-open]),
.finder:has(.sel[data-open]){overflow:visible}
/* The list never runs past the fold either: it scrolls inside itself. */
.sel__list{max-height:min(46vh,340px);overflow-y:auto;overscroll-behavior:contain}
.sel__btn{display:flex;align-items:center;justify-content:space-between;gap:12px;
  width:100%;height:44px;padding:0 14px;background:transparent;color:inherit;
  border:1px solid var(--line-l);border-radius:0;font:inherit;font-size:15px;
  text-align:left;cursor:pointer;transition:border-color var(--dur-1) var(--ease)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .sel__btn{border-color:var(--line-d)}
.sel__btn:focus-visible{border-color:currentColor}
.sel__btn b{flex:none;width:15px;height:15px;display:block;
  transition:transform var(--dur-2) var(--ease)}
.sel__btn svg{width:100%;height:100%;display:block}
.sel[data-open] .sel__btn b{transform:rotate(180deg)}
.sel[data-open] .sel__btn{border-color:currentColor}
.sel__list{position:absolute;left:0;right:0;top:calc(100% - 1px);z-index:60;
  margin:0;padding:4px 0;list-style:none;max-height:280px;overflow:auto;
  background:var(--paper);border:1px solid currentColor;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity var(--dur-1) var(--ease),transform var(--dur-2) var(--ease),visibility var(--dur-2)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .sel__list{background:var(--w8)}
.sel[data-open] .sel__list{opacity:1;visibility:visible;transform:none}
.sel__opt{padding:9px 14px;font-size:15px;cursor:pointer;
  transition:background var(--dur-1) var(--ease)}
.sel__opt[aria-selected="true"]{background:var(--chip-l)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .sel__opt[aria-selected="true"]{background:var(--chip-d)}
.sel__opt.is-cursor{background:var(--gold);color:var(--ink)}
/* the native control stays for forms and for no-JS, out of sight once ours is up */
.js .sel > select{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
@media (prefers-reduced-motion:reduce){
  .sel__list,.sel__btn b{transition:none}
}
.field textarea{height:auto;padding:12px 14px;min-height:132px;resize:vertical}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .field input,:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .field select,:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .field textarea{border-color:var(--line-d)}
.field input::placeholder,.field textarea::placeholder{color:var(--tx-l-2)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .field input::placeholder{color:var(--tx-d-2)}

.signup{display:grid;grid-template-columns:1fr auto;align-items:center;gap:0;
  border-bottom:1px solid var(--line-d);max-width:400px}
.signup input{height:46px;background:transparent;border:0;color:var(--ivory);font-size:17px}
.signup input::placeholder{color:var(--tx-d-2)}

/* --------------------------------------------------------------------------
   FOOTER
   An inset panel, the way worldquantfoundry.com closes: the page ends on black
   and the footer is a single object sitting inside it, carrying the invitation,
   the sections at display size, and the family of marks. Radius is the one
   thing this build borrows from that reference; everywhere else it stays 0.
   -------------------------------------------------------------------------- */
/* main paints its own ground and sits above the footer, which is stuck to the
   viewport bottom underneath it: the last band lifts off it like a curtain.
   The ground goes on main and not on .band, so initTheme's reading of the
   light bands does not change. */
main{position:relative;z-index:1;background:var(--paper)}
.foot{position:sticky;bottom:0;z-index:0;overflow:hidden;color:var(--tx-d);
  padding:clamp(38px,5vw,86px) var(--edge) clamp(24px,2.4vw,36px);
  background:linear-gradient(157deg,var(--w4) 0%,var(--w6) 36%,var(--w7) 68%,var(--w8) 100%)}
/* the two pages that end on a ramp keep the w1 to w1 seam; a stuck footer
   taller than the viewport would leave its own top out of reach (phones, and
   the runtime's foot--flat when it measures that it does not fit); reduced
   motion gets a plain block */
main:has(> .band--wash-up:last-child) + .foot{position:relative}
@media (max-width:900px){.foot{position:relative}}
.foot.foot--flat{position:relative}
html.rm .foot{position:relative}
html.rm .hero{position:relative}
html.rm .hero.hero--under{visibility:visible}
@media (prefers-reduced-motion:reduce){.foot{position:relative}}
.foot__panel{position:relative;max-width:calc(var(--max) - var(--edge) * 2);margin:0 auto;
  padding:0;
  background:none}

.foot__top{position:relative;display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr) minmax(0,1fr);
  gap:clamp(30px,4vw,72px);padding-bottom:clamp(48px,6vw,104px)}

.foot__say .d2{max-width:12ch}
.foot__sub{margin-top:20px;max-width:46ch;color:var(--tx-d-2);
  font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:13px;letter-spacing:.06em;line-height:1.65;text-transform:uppercase}

/* the bracketed link, corners only, from the reference */
.brk{position:relative;display:inline-flex;align-items:center;justify-content:center;
  margin-top:clamp(30px,4vw,64px);padding:15px 34px;
  font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:var(--t-micro);font-weight:500;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ivory)}
.brk{--brk:14px;background-repeat:no-repeat;
  background-image:linear-gradient(var(--gold),var(--gold)),linear-gradient(var(--gold),var(--gold)),
    linear-gradient(var(--gold),var(--gold)),linear-gradient(var(--gold),var(--gold)),
    linear-gradient(var(--gold),var(--gold)),linear-gradient(var(--gold),var(--gold)),
    linear-gradient(var(--gold),var(--gold)),linear-gradient(var(--gold),var(--gold));
  background-position:left top,left top,right top,right top,
    left bottom,left bottom,right bottom,right bottom;
  background-size:var(--brk) 1px,1px var(--brk),var(--brk) 1px,1px var(--brk),
    var(--brk) 1px,1px var(--brk),var(--brk) 1px,1px var(--brk);
  transition:--brk var(--dur-2) var(--ease),background-size var(--dur-2) var(--ease),color var(--dur-1) var(--ease)}
.brk:hover{--brk:26px;color:var(--gold-hi)}

.foot__big{display:grid;gap:2px;align-content:start}
.foot__big a{position:relative;width:max-content;font-size:clamp(24px,2.5vw,38px);
  font-weight:400;line-height:1.24;letter-spacing:-.02em;color:var(--tx-d-2);
  transition:color var(--dur-1) var(--ease)}
/* the underline is drawn, not slid: scaleX from the left on the way in and,
   with the origin flipped, it leaves by the right on the way out */
.foot__big a::after{content:"";position:absolute;left:0;right:0;bottom:2px;height:1px;
  background:var(--gold);transform:scaleX(0);transform-origin:100% 50%;
  transition:transform var(--dur-2) var(--ease)}
.foot__big a:hover{color:var(--ivory)}
.foot__big a:hover::after,.foot__big a:focus-visible::after{transform:none;transform-origin:0 50%}

.foot__from{display:grid;align-content:start;gap:24px}
.foot__brands{display:flex;flex-wrap:wrap;align-items:center;gap:0}
.foot__brands li{display:flex;align-items:center;padding:0 clamp(16px,1.6vw,26px);
  border-right:1px solid var(--line-d)}
.foot__brands li:first-child{padding-left:0}
.foot__brands li:last-child{border-right:0}
.foot__brands img{width:auto;opacity:.66;filter:brightness(0) invert(1);
  transition:opacity var(--dur-1) var(--ease)}
.foot__brands img:hover{opacity:1}
.foot__brands .m-word{height:15px}
.foot__brands .m-crest{height:34px}

/* the ornamental S, oversized and almost out of the panel */
.foot__seal{position:absolute;right:-3%;bottom:-14%;width:min(38%,460px);aspect-ratio:459/600;
  pointer-events:none;opacity:.05;background:var(--ivory);
  -webkit-mask:url(../logo/senator-s-black.png) no-repeat center/contain;
  mask:url(../logo/senator-s-black.png) no-repeat center/contain}
/* the layers settle from different depths as the footer is exposed (--fp 0 to
   1, written by initFooterCurtain). Scrubbed, no transition. Text opacity is
   never touched: the footer is uncovered, not faded. */
.js .foot__say{transform:translateY(calc((1 - var(--fp,1)) * 32px))}
.js .foot__big{transform:translateY(calc((1 - var(--fp,1)) * 48px))}
.js .foot__from{transform:translateY(calc((1 - var(--fp,1)) * 64px))}
/* the ornamental S: still the 12vh drop, now also turning in from -12deg and
   settling from 1.15 (REPLACE of the original .js .foot__seal rule) */
.js .foot__seal{transform-origin:50% 50%;
  transform:translateY(calc((1 - var(--fp,1)) * 12vh))
    rotate(calc((1 - var(--fp,1)) * -12deg))
    scale(calc(1 + (1 - var(--fp,1)) * .15))}
/* and it is not painted while the footer is still behind main: painted at
   first paint, the 256 KB S was the largest contentful paint of every repeat
   visit (perf.json, lcpRepeatVisit). Under the runtime it starts at 0 and
   comes back scrubbed from --fp while the curtain is live (foot--live,
   initFooterCurtain: at rest by 5% of exposure, well before the drop reads),
   or with foot--open where the footer is not stuck and arrives through
   watch(). Reduced motion: the rm block at the end restores .05. */
.js .foot__seal{opacity:0}
.js .foot--live .foot__seal{opacity:calc(min(1,var(--fp,0) * 20) * .05)}
.js .foot--open .foot__seal{opacity:.05}


.foot__legal{position:relative;display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr) minmax(0,1fr) auto;
  gap:clamp(20px,2.4vw,44px);align-items:end;padding-top:clamp(24px,2.4vw,34px);
  border-top:1px solid var(--line-d)}
.foot__legal p + p{margin-top:6px}
.foot__fine{display:flex;flex-wrap:wrap;gap:8px 18px;font-size:var(--t-sm)}
.foot__fine a{position:relative;color:var(--tx-d-2);transition:color var(--dur-1) var(--ease)}
.foot__fine a:hover{color:var(--gold-hi)}

/* External links carry a mark. Used on every page, and until now on no rule. */
.ext::after{content:"";display:inline-block;width:7px;height:7px;margin-left:8px;
  border-top:1px solid currentColor;border-right:1px solid currentColor;
  transform:translateY(-1px) rotate(-45deg);opacity:.55}
.ext:hover::after{opacity:1}
/* A .btn is not a line of text, it is a chip of two cells: the label and the
   arrow. The mark lands as a THIRD flex item after the arrow, so it floated
   as a stray corner in a strip of empty button, and the arrow beside it was
   already saying the same thing. Dropped where the arrow exists, kept on the
   plain and ghost links that have no arrow. Same reason .deck__card.ext
   drops it above. */
.btn.ext:has(> b)::after{content:none}
.foot__end{display:grid;justify-items:end;align-content:start;gap:18px;justify-self:end}
.foot__up{display:flex;align-items:center;gap:12px}

/* the signature. Small, last, and it does not compete with the client's mark */
.foot__by{display:flex;align-items:center;gap:11px;
  font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:11px;font-weight:500;letter-spacing:.085em;text-transform:uppercase;
  color:var(--tx-d-2);transition:color var(--dur-1) var(--ease)}
.foot__by img{height:13px;width:auto;filter:brightness(0) invert(1);opacity:.62;
  transition:opacity var(--dur-1) var(--ease)}
.foot__by:hover{color:var(--ivory)}
.foot__by:hover img{opacity:1}

@media (max-width:1180px){
  .foot__top{grid-template-columns:1fr 1fr;row-gap:52px}
  .foot__from{grid-column:1/-1}
  .foot__legal{grid-template-columns:1fr 1fr;row-gap:22px;align-items:start}
  .foot__up{justify-self:start}
}
@media (max-width:760px){
  .foot__top,.foot__legal{grid-template-columns:1fr}
  .foot__end{justify-items:start;justify-self:start}
  .foot__seal{width:60%;right:-14%;bottom:-6%}
}

/* --------------------------------------------------------------------------
   LOADER
   The reference fills its mark from the bottom and lifts the panel away. Ours
   fills the client's own wordmark, which already carries the gold sweep in its
   vector, then the panel leaves upward. It is injected by the runtime, so it
   never exists without JavaScript, it runs once per session, and reduced motion
   skips it entirely.
   -------------------------------------------------------------------------- */
.load{position:fixed;inset:0;z-index:400;background:var(--ink);
  transition:transform var(--dur-4) var(--ease-io)}
.load--out{transform:translateY(-101%)}
/* The stage is only as tall as the mark, so -101% of ITSELF lifts it barely
   300 px and leaves it hanging mid screen until the runtime removes it: that
   is the S that "stays up there and disappears". It has to travel a whole
   viewport plus its own height to actually leave. */
.load__stage.load--out{transform:translateY(calc(-100svh - 100%))}
/* The client's own ornamental S, given depth by stacking eighteen masked
   copies a fraction apart on Z, then turned. It is the mark itself in three
   dimensions, not a logo sitting on a 3D card. */
/* The stage is a sibling of the panel, fixed and centred on its own (inset:0
   plus margin:auto with an explicit height): a fixed element inside the
   transformed panel would be positioned against it and lift away with it.
   pointer-events:none so the header under it is clickable the moment the
   panel is gone. The transition lets .load--out lift the stage with the
   panel when there is no .nav__mark to fly to. */
.load__stage{position:fixed;inset:0;margin:auto;z-index:401;
  width:min(26vw,300px);height:calc(min(26vw,300px) * 600 / 459);
  perspective:1400px;pointer-events:none;
  transition:transform var(--dur-4) var(--ease-io)}
/* The S does not fly to the header monogram: the panel lifts and takes the mark
   with it. Removed at the client's request (07/09). */
.load__s{position:relative;width:100%;height:100%;transform-style:preserve-3d;
  transform:rotateY(-96deg) scale(.86);
  transition:transform 1.5s cubic-bezier(.16,.84,.28,1)}
.load--fill .load__s{transform:rotateY(0deg) scale(1)}
.load__s i{position:absolute;inset:0;display:block;
  -webkit-mask:url(../logo/senator-s-black.png) no-repeat center/contain;
  mask:url(../logo/senator-s-black.png) no-repeat center/contain}
.load__s i:nth-child(n){background:var(--gold-deep)}
.load__s i:nth-child(1){background:linear-gradient(150deg,var(--paper),var(--gold) 60%,var(--gold-deep));
  transform:translateZ(17px)}
.load__s i:nth-child(2){transform:translateZ(15px)}
.load__s i:nth-child(3){transform:translateZ(13px)}
.load__s i:nth-child(4){transform:translateZ(11px)}
.load__s i:nth-child(5){transform:translateZ(9px)}
.load__s i:nth-child(6){transform:translateZ(7px)}
.load__s i:nth-child(7){transform:translateZ(5px)}
.load__s i:nth-child(8){transform:translateZ(3px)}
.load__s i:nth-child(9){transform:translateZ(1px)}
.load__s i:nth-child(10){transform:translateZ(-1px)}
.load__s i:nth-child(11){transform:translateZ(-3px)}
.load__s i:nth-child(12){transform:translateZ(-5px)}
.load__s i:nth-child(13){transform:translateZ(-7px)}
.load__s i:nth-child(14){transform:translateZ(-9px)}
.load__s i:nth-child(15){transform:translateZ(-11px)}
.load__s i:nth-child(16){transform:translateZ(-13px)}
.load__s i:nth-child(17){transform:translateZ(-15px)}
.load__s i:nth-child(18){transform:translateZ(-17px);background:#4a3413}
html.loading,html.loading body{overflow:hidden}

/* --------------------------------------------------------------------------
   UTILITIES. The only ones. A page that needs more needs a component.
   -------------------------------------------------------------------------- */
.mt8{margin-top:8px}.mt12{margin-top:12px}.mt16{margin-top:16px}.mt24{margin-top:24px}
.mt32{margin-top:32px}.mt48{margin-top:48px}
.mt-band{margin-top:clamp(52px,7vw,104px)}
.mb16{margin-bottom:16px}.mb24{margin-bottom:24px}.mb32{margin-bottom:32px}
.mw20{max-width:20ch}.mw28{max-width:28ch}.mw38{max-width:38ch}
.mw52{max-width:52ch}.mw64{max-width:64ch}
.stretch{align-items:stretch}
.g3{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(20px,2.4vw,34px)}
.g2{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(20px,2.4vw,34px)}
.gsplit{display:grid;grid-template-columns:1.35fr 1fr;gap:clamp(24px,4vw,64px);align-items:start}
.gsplit > *:has(.side),.railed > *:has(.side){align-self:stretch}
.grow{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
.between{display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between}

/* A sticky rail plus its content. The rail is a rail at any viewport width, so
   its track is capped rather than taken from the four column measure. */
.railed{display:grid;grid-template-columns:minmax(168px,clamp(190px,17vw,290px)) minmax(0,1fr);
  gap:clamp(24px,4vw,72px);align-items:stretch}
.railed--right{grid-template-columns:minmax(0,1fr) minmax(168px,clamp(190px,17vw,290px))}

/* the scale band: display / data panel / numbered rail */
.trio{display:grid;grid-template-columns:1.4fr 1.15fr .85fr;gap:clamp(24px,3vw,52px);align-items:start}
@media (max-width:1180px){.trio{grid-template-columns:1fr 1fr}.trio > *:last-child{grid-column:1/-1}}
@media (max-width:900px){.trio,.gsplit,.g3,.g2,.railed{grid-template-columns:1fr}
  .railed .side{position:static;grid-auto-flow:column;grid-auto-columns:max-content;overflow-x:auto}}

/* --------------------------------------------------------------------------
   LINE REVEAL
   Measured off tiwis.fr: display type is split into rendered lines, each line
   masked by its own overflow box, and each arrives from below with about two
   and a half degrees of rotation, staggered. It is the single most expensive
   looking thing on that site and it costs one transform per line.
   -------------------------------------------------------------------------- */
.js .lnr .ln{display:block;position:relative;top:-.22em;overflow:hidden;padding-block:.22em;margin:0 0 -.44em}
.js .lnr .ln__i{display:block;transform:translateY(112%) rotate(2.6deg);
  transform-origin:0% 100%;
  transition:transform var(--dur-4) var(--ease)}
.js .lnr.is-in .ln__i{transform:none}
.js .lnr .ln:nth-child(2) .ln__i{transition-delay:var(--stag)}
.js .lnr .ln:nth-child(3) .ln__i{transition-delay:calc(var(--stag) * 2)}
.js .lnr .ln:nth-child(4) .ln__i{transition-delay:calc(var(--stag) * 3)}
.js .lnr .ln:nth-child(5) .ln__i{transition-delay:calc(var(--stag) * 4)}
.js .lnr .ln:nth-child(n+6) .ln__i{transition-delay:calc(var(--stag) * 5)}

/* Plates grow into place and settle back as they leave, the way that site
   handles its media. Driven by the element's own progress through the frame.
   The unveil mask lives apart, on [data-unmask] (MOTION block below): same
   element, so this scale is its counter-scale for free. No extra transform
   on the image. */
/* THE PLATE'S GROW ----------------------------------------------------------
   Javi, 21/09: "quita la animacion, que se vea la imagen en los marcos negros
   ... no puede verse recortado la imagen, es horrible; prefiero mas zoom de la
   imagen y se ve completa."
   This used to scale the PLATE from .93 to 1 as it came up the screen. A plate
   at .93 is 7% smaller than the frame it sits in, so for the whole length of
   the move the frame's own black showed as a border on all four sides -- the
   black frames in his screenshot.
   The move is kept, but it belongs to the photograph, not to the plate: the
   plate holds its size and the picture inside it settles from a little over
   full to full, clipped by the plate's own overflow. The frame is filled at
   every moment of it, and the picture is never smaller than the hole it is in.
   -------------------------------------------------------------------------- */
.js [data-grow]{--p:0;transform:none}
.js [data-grow] > img,.js [data-grow] > picture > img{
  transform:scale(calc(1.06 - var(--p) * .06));transform-origin:50% 50%}
/* the layer only while the plate is within 200px of the viewport (is-near,
   written by initGrow, the same band it scrubs): a permanent will-change on
   every plate of the page was a layer per photograph, on or off screen */
.js [data-grow].is-near{will-change:transform}

/* the chrome gets out of the way going down and comes back going up. The
   exit takes --dur-3; the return answers the hand, so it is quicker. 100% is
   the nav's own height; the blur scrim behind it runs 132px, so the extra
   44px is exactly what used to show as a grey strip under the hidden chrome */
.nav{transition:transform var(--dur-3) var(--ease)}
.nav:not(.nav--away){transition-duration:var(--dur-2)}
.nav--away{transform:translateY(calc(-100% - 44px))}

@media (prefers-reduced-motion:reduce){
  .js .lnr .ln__i{transform:none}
  .js [data-grow]{transform:none}
  .js [data-grow] > img,.js [data-grow] > picture > img{transform:none}
  .nav--away{transform:none}
}

/* --------------------------------------------------------------------------
   REVEAL. Everything below is motion, and motion only.
   Without JS or with reduced motion the page renders at full contrast.
   -------------------------------------------------------------------------- */
.js .rv{opacity:0;transform:translateY(22px);
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease)}
.js .rv.is-in{opacity:1;transform:none}
/* Landing as painted: the runtime (land) adds .is-now for one style pass
   when something is revealed while the page is still arriving (restored
   scroll, fragment jump) or on focus, so the final state is computed first
   and no transition runs. The class is gone on the next frame. */
.js .is-now,.js .is-now *{transition:none!important}
.js .rv-d1{transition-delay:var(--stag)}.js .rv-d2{transition-delay:calc(var(--stag) * 2)}
.js .rv-d3{transition-delay:calc(var(--stag) * 3)}.js .rv-d4{transition-delay:calc(var(--stag) * 4)}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important}
  .js .rv{opacity:1;transform:none}
  .js .hero__in,.js .hero__foot,.js .hero > .hero__news{transform:none;opacity:1}
  .js .hero__media{clip-path:none}
  .js .hero__media::before{opacity:0}
  .js .hero{position:relative}
  .js .hero.hero--under{visibility:visible}
  .js .hero__media,.js .hero--ov .hero__media{transform:none}
  .js .hero__media img,.js .hero__media video{filter:grayscale(.42) contrast(1.06) brightness(.62) saturate(.8)}
  .js .hero--ov .hero__h1:not(.lnr),
  .js .hero--ov .hero__cta > *,.js .hero--ov .hero__cred,.js .hero--ov .hero__lede,
  .js .hero--ov .hero__news{opacity:1;transform:none}
  .js .stack__media figure{transform:none}
  .js .stack__row{opacity:1}
  .js .stmt w{color:inherit}
  .js .rows--dim li{opacity:1}
  .stack__media{position:static;height:auto}
}



/* Micro label. Neue Helvena condensed, uppercase, wide. The reference's tell. */
.kick,.chip,.btn,.nav__menu a,.nav__menu button,.tag,.foot__col h4,.dchip,.pgn button{
  font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
}
.kick{display:block;font-size:var(--t-micro);font-weight:500;letter-spacing:.085em;
  text-transform:uppercase;line-height:1;color:var(--tx-l)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .kick{color:var(--tx-d)}
.kick--2{color:var(--tx-l-2)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .kick--2{color:var(--tx-d-2)}

/* 6px accent square. Dropped on grid intersections and before labels. */
.sq,.sq--row{display:none}

/* Numbered chip:  ■ 01 */
.chip-n{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:var(--ink);
  color:var(--ivory);font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:11px;font-weight:500;letter-spacing:.085em;line-height:1}
.chip-n::before{content:"";width:4px;height:4px;background:var(--gold)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .chip-n{background:var(--chip-d);color:var(--ivory)}

/* --------------------------------------------------------------------------
   RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width:1180px){
  .cards{grid-template-columns:repeat(2,1fr)}
  .people{grid-template-columns:repeat(3,1fr)}
  .foot__top{grid-template-columns:1fr 1fr;row-gap:44px}
  .foot__legal{grid-template-columns:1fr;row-gap:18px;align-items:start}
  .foot__top-link{justify-self:start}
}
@media (max-width:900px){
  :root{--col:calc((100% - var(--edge) * 2) / 2)}
  .gridlines i:nth-child(3),.hero__grid i:nth-child(3){display:none}
  .gridlines i:nth-child(1),.hero__grid i:nth-child(1){left:calc(var(--edge) + var(--col))}
  .gridlines i:nth-child(2),.hero__grid i:nth-child(2){display:none}
  .nav__menu,.nav__go{display:none}
  .nav__burger{display:flex}
  .stack{grid-template-columns:1fr}
  .stack__media{position:relative;height:auto;padding:0 0 44px;order:-1}
  .stack__row{grid-template-columns:1fr;gap:12px}
  .rows li{grid-template-columns:1fr;gap:12px}
  .rows__ico{width:54px;height:54px}
  .hero__foot{grid-template-columns:1fr;gap:20px}
  .hero__lede{justify-self:start}
  .hero__news{position:relative;right:auto;bottom:auto;width:100%;margin-bottom:26px}
  .head{grid-template-columns:1fr;align-items:start}
  .head__a{justify-self:start}
  .dcard{min-height:440px}
}
@media (max-width:680px){
  .rail li{min-height:0}
  .cards,.cards--3,.cards--2{grid-template-columns:1fr}
  .people{grid-template-columns:repeat(2,1fr)}
  .foot__top{grid-template-columns:1fr}
  .foot__nav{grid-template-columns:1fr 1fr}
  .rowlist,.rowlist li{grid-template-columns:1fr}
  .rowlist li{row-gap:10px;justify-items:start}
  .rowlist li > *{max-width:100%}
  .faq__q{gap:14px}
  .faq__a{padding-left:0;padding-right:0}
}

/* print: the client reads PDFs */
@media print{
  .nav,.drawer,.hero__media,.gridlines,.hero__grid,.foot__top-link{display:none!important}
  body{background:#fff;color:#000}
  .band,.foot,.hero{background:#fff!important;color:#000!important;padding:24px 0!important;
    min-height:0!important}
  .band--dark *,.band--wash *,.foot *,.hero *{color:#000!important}
  .stack__media{position:static;height:auto}
  .stack__row,.rows--dim li,.rv{opacity:1!important;transform:none!important}
  .stmt w{color:#000!important}
  .card,.rail li{break-inside:avoid}
  .foot{position:static}
  .foot__say,.foot__big,.foot__from,.foot__seal{transform:none!important}
  .js i.stack__mk{display:none}
  .stack__media{display:block}
  .stack__media [data-stack-media]{opacity:1!important;visibility:visible!important}
  .rows li.rv::after,.rowlist li.rv::after{transform:none!important}
  @page{size:A4;margin:14mm}
}

/* --------------------------------------------------------------------------
   TEXT THEME
   The reference uses exactly two text colours, black and its near white, and
   picks per element according to where that element lands in the wash. That is
   what lets a gradient run from daylight to black without one unreadable line,
   and it is the turn you watch while scrolling. The runtime measures every
   element that paints text against its band's own declared gradient and stamps
   data-on. Each rule is emitted twice: for the element itself, carrying an
   extra [data-on] so its own reading outranks any ancestor themed the other
   way, and for descendants that paint no text of their own.
   -------------------------------------------------------------------------- */
[data-on="light"],
.kick[data-on="light"][data-on],
[data-on="light"] .kick,
.d1[data-on="light"][data-on],
[data-on="light"] .d1,
.d2[data-on="light"][data-on],
[data-on="light"] .d2,
.d3[data-on="light"][data-on],
[data-on="light"] .d3,
.h3[data-on="light"][data-on],
[data-on="light"] .h3,
.h4[data-on="light"][data-on],
[data-on="light"] .h4,
.h5[data-on="light"][data-on],
[data-on="light"] .h5,
h1[data-on="light"][data-on],
[data-on="light"] h1,
h2[data-on="light"][data-on],
[data-on="light"] h2,
h3[data-on="light"][data-on],
[data-on="light"] h3,
h4[data-on="light"][data-on],
[data-on="light"] h4,
p[data-on="light"][data-on],
[data-on="light"] p,
a[data-on="light"][data-on],
[data-on="light"] a,
li[data-on="light"][data-on],
[data-on="light"] li,
span[data-on="light"][data-on],
[data-on="light"] span,
b[data-on="light"][data-on],
[data-on="light"] b,
w[data-on="light"][data-on],
[data-on="light"] w{color:var(--tx-l)}
.tx2[data-on="light"][data-on],
[data-on="light"] .tx2,
.kick--2[data-on="light"][data-on],
[data-on="light"] .kick--2,
.prov[data-on="light"][data-on],
[data-on="light"] .prov{color:rgba(0,0,0,.88)}
.rule[data-on="light"][data-on],
[data-on="light"] .rule,
.rows[data-on="light"][data-on],
[data-on="light"] .rows,
.rows li[data-on="light"][data-on],
[data-on="light"] .rows li,
.rowlist li[data-on="light"][data-on],
[data-on="light"] .rowlist li,
.rail li[data-on="light"][data-on],
[data-on="light"] .rail li,
.faq li[data-on="light"][data-on],
[data-on="light"] .faq li{background-image:linear-gradient(var(--line-l),var(--line-l))}
.btn > span[data-on="light"][data-on],
[data-on="light"] .btn > span,
.sqbtn[data-on="light"][data-on],
[data-on="light"] .sqbtn,
.dchip[data-on="light"][data-on],
[data-on="light"] .dchip,
.side a[data-on="light"][data-on],
[data-on="light"] .side a,
.btn--ghost > span[data-on="light"][data-on],
[data-on="light"] .btn--ghost > span{background:var(--chip-l);color:var(--tx-l)}
.chip-n[data-on="light"][data-on],
[data-on="light"] .chip-n,
.faq__t[data-on="light"][data-on],
[data-on="light"] .faq__t{background:var(--ink);color:var(--ivory)}
.prov[data-on="light"][data-on]::before,
[data-on="light"] .prov::before{background:var(--tx-l-dim)}
.prov--live[data-on="light"][data-on]::before,
[data-on="light"] .prov--live::before{background:var(--gold-deep)}
.field input[data-on="light"][data-on],
[data-on="light"] .field input,
.field select[data-on="light"][data-on],
[data-on="light"] .field select,
.field textarea[data-on="light"][data-on],
[data-on="light"] .field textarea{border-color:var(--line-l)}
/* The un-coloured half has to read as clearly unfinished, or the sweep does
   not register at all. Lightened from .55, which put it 4.67:1 against the
   band while the finished word is 19.4:1 -- too close to see travelling.
   .45 is as far as it goes: the sentence sets at 59px, so it is large text
   and owes 3:1, and .45 leaves 3.31:1. Below .43 a reader who never scrolls
   past cannot read the half that has not lit yet. */
.stmt w[data-on="light"][data-on],
[data-on="light"] .stmt w{color:rgba(0,0,0,.45)}

[data-on="dark"],
.kick[data-on="dark"][data-on],
[data-on="dark"] .kick,
.d1[data-on="dark"][data-on],
[data-on="dark"] .d1,
.d2[data-on="dark"][data-on],
[data-on="dark"] .d2,
.d3[data-on="dark"][data-on],
[data-on="dark"] .d3,
.h3[data-on="dark"][data-on],
[data-on="dark"] .h3,
.h4[data-on="dark"][data-on],
[data-on="dark"] .h4,
.h5[data-on="dark"][data-on],
[data-on="dark"] .h5,
h1[data-on="dark"][data-on],
[data-on="dark"] h1,
h2[data-on="dark"][data-on],
[data-on="dark"] h2,
h3[data-on="dark"][data-on],
[data-on="dark"] h3,
h4[data-on="dark"][data-on],
[data-on="dark"] h4,
p[data-on="dark"][data-on],
[data-on="dark"] p,
a[data-on="dark"][data-on],
[data-on="dark"] a,
li[data-on="dark"][data-on],
[data-on="dark"] li,
span[data-on="dark"][data-on],
[data-on="dark"] span,
b[data-on="dark"][data-on],
[data-on="dark"] b,
w[data-on="dark"][data-on],
[data-on="dark"] w{color:var(--tx-d)}
.tx2[data-on="dark"][data-on],
[data-on="dark"] .tx2,
.kick--2[data-on="dark"][data-on],
[data-on="dark"] .kick--2,
.prov[data-on="dark"][data-on],
[data-on="dark"] .prov{color:var(--tx-d-2)}
.rule[data-on="dark"][data-on],
[data-on="dark"] .rule,
.rows[data-on="dark"][data-on],
[data-on="dark"] .rows,
.rows li[data-on="dark"][data-on],
[data-on="dark"] .rows li,
.rowlist li[data-on="dark"][data-on],
[data-on="dark"] .rowlist li,
.rail li[data-on="dark"][data-on],
[data-on="dark"] .rail li,
.faq li[data-on="dark"][data-on],
[data-on="dark"] .faq li{background-image:linear-gradient(var(--line-d),var(--line-d))}
.btn > span[data-on="dark"][data-on],
[data-on="dark"] .btn > span,
.sqbtn[data-on="dark"][data-on],
[data-on="dark"] .sqbtn,
.dchip[data-on="dark"][data-on],
[data-on="dark"] .dchip,
.side a[data-on="dark"][data-on],
[data-on="dark"] .side a,
.btn--ghost > span[data-on="dark"][data-on],
[data-on="dark"] .btn--ghost > span{background:var(--chip-d);color:var(--ivory)}
.chip-n[data-on="dark"][data-on],
[data-on="dark"] .chip-n,
.faq__t[data-on="dark"][data-on],
[data-on="dark"] .faq__t{background:var(--chip-d);color:var(--ivory)}
.prov[data-on="dark"][data-on]::before,
[data-on="dark"] .prov::before{background:var(--tx-d-dim)}
.prov--live[data-on="dark"][data-on]::before,
[data-on="dark"] .prov--live::before{background:var(--gold)}
.field input[data-on="dark"][data-on],
[data-on="dark"] .field input,
.field select[data-on="dark"][data-on],
[data-on="dark"] .field select,
.field textarea[data-on="dark"][data-on],
[data-on="dark"] .field textarea{border-color:var(--line-d)}
.stmt w[data-on="dark"][data-on],
[data-on="dark"] .stmt w{color:var(--tx-d-dim)}

/* the word reveal keeps its lit state on top of whichever theme it landed in */
.js .stmt w[data-on="light"][data-on].is-on{color:var(--tx-l)}
.js .stmt w[data-on="dark"][data-on].is-on{color:var(--tx-d)}

.js [data-on],.js [data-on] *{transition:color var(--dur-2) var(--ease)}
/* A themed .rv lost its arrival: the rule above and .js .rv are both 0,2,0,
   so by order the card, the dcard, the .rule carrier and any paragraph read
   on the ramp arrived with colour only, no fade, no rise, no step. One list
   with both, at 0,3,0. The step is restated because a transition shorthand
   resets transition-delay. Kept before the .stack__media exception so that
   one still wins by order. */
.js .rv[data-on],.js [data-on] .rv{
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease),color var(--dur-2) var(--ease)}
/* Same replacement, three more victims found by the pattern probe
   (.qa/motion/fix/rv-theme-transition/clobber.mjs): the card's hover ground,
   the photograph's colour return, and the map label's fill on hover and its
   dip on the dive. Each restated with colour in the list. */
.js .card[data-on]{
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease),color var(--dur-2) var(--ease),background var(--dur-1) var(--ease)}
.js [data-on] .ph{transition:filter var(--dur-2) var(--ease),color var(--dur-2) var(--ease)}
.js .wmap__lbl[data-on]{
  transition:fill-opacity var(--dur-2) var(--ease),opacity var(--dur-1) var(--ease-io),visibility var(--dur-1),color var(--dur-2) var(--ease)}
.js .rv-d1[data-on],.js [data-on] .rv-d1{transition-delay:var(--stag)}
.js .rv-d2[data-on],.js [data-on] .rv-d2{transition-delay:calc(var(--stag) * 2)}
.js .rv-d3[data-on],.js [data-on] .rv-d3{transition-delay:calc(var(--stag) * 3)}
.js .rv-d4[data-on],.js [data-on] .rv-d4{transition-delay:calc(var(--stag) * 4)}
/* except where the element itself is moving through the ramp: a sticky caption
   would otherwise spend the whole scroll mid cross-fade */
.js .stack__media [data-on],.js .stack__media [data-on] *{transition:none}

/* On the crossover, muted stops being muted. Two rules, and they have to beat
   the themed muted rules above, hence the doubled attribute. */
[data-strong][data-on="dark"][data-on]{color:var(--tx-d)}
[data-strong][data-on="light"][data-on]{color:var(--tx-l)}
/* the statement's dim state is three classes deep, so on the crossover it has
   to be outranked explicitly or a word sits at half strength on a mid ground */
.js .stmt w[data-strong][data-on="dark"]{color:rgba(255,255,255,.72)}
.js .stmt w[data-strong][data-on="dark"].is-on{color:var(--tx-d)}
.js .stmt w[data-strong][data-on="light"]{color:rgba(0,0,0,.72)}
.js .stmt w[data-strong][data-on="light"].is-on{color:var(--tx-l)}

/* On a mid tone ground a chip that darkens makes black text worse, and one
   that lightens makes white text worse. In the crossover window each side
   pushes the ground the way its own text needs. */
:is(.btn > span,.sqbtn,.dchip,.side a,.chip-n)[data-strong][data-on="light"]{
  background:rgba(255,255,255,.66);color:var(--tx-l)}
:is(.btn > span,.sqbtn,.dchip,.side a)[data-strong][data-on="dark"]{
  background:rgba(3,8,15,.62);color:var(--tx-d)}

/* A numbered chip is a black chip on any ground. On a mid tone the translucent
   variant was leaving its own label at 4.4:1. */
.chip-n,.chip-n[data-on="dark"][data-on],.chip-n[data-on="light"][data-on],
[data-on="dark"] .chip-n,[data-on="light"] .chip-n{background:var(--ink);color:var(--ivory)}


/* ==========================================================================
   MOTION · 2026-09-02
   The movement pass (MOTION-PLAN.md). Rules that replace an existing one were
   applied in place above; everything genuinely new lives here, one block per
   item, in the plan's order. Tokens are in :root. Reduced motion and print
   overrides for these rules close the block, so they win by order.
   ========================================================================== */

/* --------------------------------------------------------------------------
   MOTION 04 · stack-pin · list travel and the marker
   The list gains travel (measured: with 1.7 the plate stays put for 630px at
   900 high). The list is the marker's positioning box. Below 900px the plate
   is relative and the list keeps its natural height.
   -------------------------------------------------------------------------- */
.js .stack__list{position:relative;display:flex;flex-direction:column;
  justify-content:space-between;min-height:calc(100svh * 2.1);padding:36svh 0 52svh}
@media (max-width:900px){.js .stack__list{min-height:0;padding:0}}
/* The marker. A 6px gold square, the one canonical use of the accent,
   injected by the runtime as the first child of .stack__list and of
   .rows--dim. It travels on transform to --mky, which the runtime writes as
   the lit row's offsetTop plus the centre of its first label line.
   i.stack__mk rather than .stack__mk: the .rows carrier is themed, and
   .js [data-on] *{transition:color} would otherwise replace this transition
   by specificity. Not injected under reduced motion; hidden below 900px. */
/* MOTION POWER 07: a 3 x 36px bar, not a square, centred on the same line
   (--mky is the centre of the first label line minus 3, hence the 15px lift);
   --ease-io so it reads as a mechanism, no overshoot */
.js i.stack__mk{position:absolute;left:-22px;top:0;width:3px;height:36px;
  background:var(--gold);opacity:0;pointer-events:none;
  transform:translateY(calc(var(--mky,0px) - 15px));
  transition:transform var(--dur-3) var(--ease-io),opacity var(--dur-2) var(--ease)}
.js i.stack__mk.is-live{opacity:1}
@media (max-width:900px){.js i.stack__mk{display:none}}

/* --------------------------------------------------------------------------
   MOTION 05 · photo-unveil · the mask and the grid focus
   The plate that already carries data-grow is masked top to bottom on
   arrival; the scale it already runs underneath is the counter-scale. --i is
   written by the runtime: the plate's index among the plates of its own grid,
   modulo 4, so a row opens left to right with one step between sisters.
   -------------------------------------------------------------------------- */
/* 1. The mask. A letterbox: the top and bottom 24% are covered and the
   strip opens both ways in --dur-5, two --stag between sisters of the same
   row. --i is written by the runtime (initPhotoUnveil, then restated by
   initPhotoDrama as the plate's place in its visual row, modulo 4), so a
   row of four opens left to right over 480 ms plus the display duration. */
.js [data-unmask]{clip-path:inset(24% 0 24% 0);
  transition:clip-path var(--dur-5) var(--ease);
  transition-delay:calc(var(--i,0) * var(--stag) * 2)}
.js [data-unmask].is-in{clip-path:inset(0)}
/* 2. The photograph under the mask. Over-tall by 12% so it has room to
   travel inside its plate, scaled 1.16 while the strip is closed and
   settling to 1 as it opens (the counter-scale, from the centre), and
   carried by --py, the depth the runtime writes from the plate's position in
   the viewport (-5 at the bottom edge .. 5 at the top edge, per cent of the
   photograph's own height). scale and translate are the individual
   transform properties: the settle transitions, the depth is scrubbed with
   no transition at all, and neither fights the other.
   (0,3,1) on purpose: .js [data-on] .ph is (0,3,0) and would replace this
   transition list with colour and filter only, and the settle would snap.
   No will-change here: ~100 photographs with a filter each is exactly the
   layer bill the plan refused; the plate above already carries the layer. */
.js [data-unmask][data-grow] > img{position:absolute;left:0;right:0;top:-6%;width:100%;height:112%;
  scale:1.16;translate:0 calc(var(--py,0) * 1%);transform-origin:50% 50%;
  transition:scale var(--dur-5) var(--ease) calc(var(--i,0) * var(--stag) * 2),
    filter var(--dur-2) var(--ease),color var(--dur-2) var(--ease)}
.js [data-unmask][data-grow].is-in > img{scale:1}
/* 3. Grid focus, pointer only. The photograph under the hand keeps its
   colour (the hover that already exists); its sisters step back to .55.
   Only the image, never the caption. The step back is a navy veil over each
   plate (an ::after of the media box, which is already positioned and
   clipped) fading in with opacity: the old way changed the filter of every
   sister, which re-rasterised the whole grid on each hover (53 to 76 ms
   frames); an opacity change on a layer of its own composites. z-index 1 on
   the veil sits above the photograph (absolute under the mask) and under
   nothing: the caption is outside the media box. */
@media (hover:hover){
  .card__media::after,.people__img::after,.carou__shot::after{
    content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
    background:var(--w8);opacity:0;transition:opacity var(--dur-2) var(--ease)}
  .cards:hover .card:not(:hover) .card__media::after,
  .carou__track:hover .carou__slide:not(:hover) .carou__shot::after,
  .people:hover figure:not(:hover) .people__img::after{opacity:.45}
  .people figure:hover .people__img img{filter:grayscale(0) contrast(1) brightness(1)}
}

/* --------------------------------------------------------------------------
   MOTION 06 · micro-craft · the roll, the arrow that passes, the drawn
   underline and the traced hairline
   The roll: the label slides up and its own copy arrives from below, the
   construction the nav already has. The runtime (initMicroCraft) wraps the
   label in <i> and writes the translated text into data-t after every
   language change. Without JavaScript there is no <i> and no data-t: the chip
   is today's chip. The arrow: on hover it leaves the gold square by the right
   edge and comes back in from the left. The square is the one place the
   accent may move.
   -------------------------------------------------------------------------- */
/* the theme rule .js [data-on] sets a colour-only transition on every themed
   element, which would take the background fade away from the chip. Both,
   from here on: the ground at --dur-1, the colour at --dur-2. */
.js .btn > span,.js .btn > b{transition:background var(--dur-1) var(--ease),color var(--dur-2) var(--ease)}

/* the label. Stretched to the chip's height so a full turn takes it clear of
   the clip box, and centred inside; the chip's own line-height is 1 */
.js .btn > span > i{display:flex;align-items:center;align-self:stretch;font-style:normal;
  transition:transform var(--dur-2) var(--ease),color var(--dur-2) var(--ease)}
/* its copy, waiting below. Same padding as the chip, same colour by
   inheritance, so it can never arrive in a different tone from the label it
   replaces. Hidden from assistive tech where the alt-text syntax is known. */
.js .btn > span::after{content:attr(data-t);content:attr(data-t) / "";
  position:absolute;inset:0;display:flex;align-items:center;padding:inherit;
  transform:translateY(100%);transition:transform var(--dur-2) var(--ease)}
/* padding:inherit, not a hardcoded 18px. The chip is 24px on the hero pair,
   on "see every market" and on the licensing link, so the copy rolling up was
   landing 6px to the left of the label it replaces and the text visibly jumped
   sideways on hover. It now always matches the chip it rolls inside. */
.js .dcard__foot .btn > span::after{justify-content:center}
.js .btn:hover > span > i,.js .btn:focus-visible > span > i{transform:translateY(-100%)}
.js .btn:hover > span::after,.js .btn:focus-visible > span::after{transform:none}

/* the arrow passes through the square: out by the far edge, back in from the
   near one. 220% of its own width clears every square it sits in (38, 46 and
   50px boxes with 15 to 18px glyphs). One shot per hover, --ease-io because it
   leaves before it arrives. Pure CSS, so it needs no script to run. */
@keyframes arrow-pass{0%{transform:none}49%{transform:translateX(220%)}50%{transform:translateX(-220%)}100%{transform:none}}
@keyframes arrow-pass-l{0%{transform:none}49%{transform:translateX(-220%)}50%{transform:translateX(220%)}100%{transform:none}}
@keyframes arrow-pass-up{0%{transform:none}49%{transform:translateY(-220%)}50%{transform:translateY(220%)}100%{transform:none}}
.sqbtn,.carou__nav button,.deck__nav button,.hero__news > a{overflow:hidden}
.btn:hover > b svg,.btn:focus-visible > b svg,
.sqbtn:hover svg,.sqbtn:focus-visible svg,
a:hover > .sqbtn svg,a:focus-visible > .sqbtn svg,
.carou__nav button:hover svg,.carou__nav button:focus-visible svg,
.deck__nav button:hover svg,.deck__nav button:focus-visible svg,
.hero__news:hover > a svg,.hero__news > a:focus-visible svg{
  animation:arrow-pass var(--dur-2) var(--ease-io) 1}
/* a left-pointing arrow leaves by the left */
.carou__nav [data-carou="prev"]:hover svg,.carou__nav [data-carou="prev"]:focus-visible svg,
.deck__nav [data-deck="prev"]:hover svg,.deck__nav [data-deck="prev"]:focus-visible svg{
  animation-name:arrow-pass-l}
/* and the footer's up arrow leaves by the top */
.foot__up:hover .sqbtn svg,.foot__up:focus-visible .sqbtn svg{animation-name:arrow-pass-up}
/* the arrow squares lose their background fade to the theme rule the same way
   the chip does; restored here with the scale */
.js .sqbtn{transition:background var(--dur-1) var(--ease),color var(--dur-2) var(--ease)}
.js .carou__nav button,.js .deck__nav button{
  transition:background var(--dur-1) var(--ease),opacity var(--dur-1) var(--ease),color var(--dur-2) var(--ease)}
/* the fine print gets the same drawn underline as the big links; .ext keeps
   its own mark, so it is left out */
.foot__fine a:not(.ext)::after{content:"";position:absolute;left:0;right:0;bottom:-3px;height:1px;
  background:var(--gold);transform:scaleX(0);transform-origin:100% 50%;
  transition:transform var(--dur-2) var(--ease)}
.foot__fine a:not(.ext):hover::after,.foot__fine a:not(.ext):focus-visible::after{
  transform:none;transform-origin:0 50%}
/* The line under each .rows and .rowlist row is traced from the left as the
   row arrives, in --dur-4 and with the row's own stagger. Only rows the
   runtime tagged .rv trace; a row without the tag keeps the painted line.
   The painted line is taken away only where the traced one exists, so it is
   never doubled and never missing. */
.js:not(.rm) .rows li.rv,.js:not(.rm) .rowlist li.rv{background-image:none}
.js:not(.rm) .rows li.rv::after,.js:not(.rm) .rowlist li.rv::after{content:"";
  position:absolute;left:0;bottom:0;width:100%;height:1px;
  background:currentColor;opacity:.15;
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform var(--dur-4) var(--ease)}
.js:not(.rm) .rows li.rv.is-in::after,.js:not(.rm) .rowlist li.rv.is-in::after{transform:none}
.js:not(.rm) :is(.rows,.rowlist) li.rv-d1::after{transition-delay:var(--stag)}
.js:not(.rm) :is(.rows,.rowlist) li.rv-d2::after{transition-delay:calc(var(--stag) * 2)}
.js:not(.rm) :is(.rows,.rowlist) li.rv-d3::after{transition-delay:calc(var(--stag) * 3)}
.js:not(.rm) :is(.rows,.rowlist) li.rv-d4::after{transition-delay:calc(var(--stag) * 4)}

/* --------------------------------------------------------------------------
   MOTION 08 · page-transit · the veil between pages
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   VEIL. Rises from the bottom over everything, including the chrome, the
   drawer and the map's own dive veil, in the state duration and on the
   "covers or leaves" curve. The S is ivory, not gold: the gold is the loader's
   and appears once per session. Injected by the runtime on click, so it never
   exists without JavaScript or under reduced motion.
   -------------------------------------------------------------------------- */
/* Cross-document motion is defined in page-transitions.css. */

/* --------------------------------------------------------------------------
   MOTION 09 · nav-intent · reading progress and the folding wordmark
   The hairline element is injected by the runtime (initNavIntent), so the
   header partial stays byte-identical. Block D is the optional piece to show
   Javi: remove that rule alone to drop the effect.
   -------------------------------------------------------------------------- */
/* --- block C: reading progress. A 1px hairline under the chrome, injected by
   the runtime, in the chrome's own colour (never gold). scaleX is scroll
   geometry and carries no duration; only its presence fades, with the stuck
   state. Aligned with .nav__in at any width: past --max the edge moves in
   with the centred row, so at 1920 and 2560 it still sits under the labels. */
.nav__prog{position:absolute;bottom:0;height:1px;
  left:calc(var(--edge) + max(0px,(100% - var(--max)) / 2));
  right:calc(var(--edge) + max(0px,(100% - var(--max)) / 2));
  background:var(--tx-l);opacity:0;
  transform:scaleX(var(--sp,0));transform-origin:0 50%;
  transition:opacity var(--dur-2) var(--ease)}
.nav--on-dark .nav__prog{background:var(--ivory)}
.nav[data-stuck] .nav__prog{opacity:.35}

/* --- block D removed at the client's request (07/09): the wordmark used to
   fold away past the scroll threshold and leave only the S. The full lockup,
   mark and SENATOR, now stays in the header at every scroll position and in
   every state. --------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   MOTION 10 · drawer-stagger · the chrome over the panel, and the panel
   While the drawer is up the header sits on ink, so it inverts the way it
   does over a dark band. The runtime adds .nav--menu with the panel and
   removes it once the panel has gone. Mirrors .nav--on-dark with one more
   class of specificity so it wins over it in both directions.
   -------------------------------------------------------------------------- */
.nav.nav--menu .nav__menu a,.nav.nav--menu .nav__go,.nav.nav--menu .nav__burger{color:var(--ivory)}
.nav.nav--menu .nav__lang button{color:var(--tx-d-2)}
.nav.nav--menu .nav__lang button[aria-pressed="true"]{color:var(--ivory)}
.nav.nav--menu .nav__logo{color:var(--tx-d)}
.nav.nav--menu .nav__logo img{filter:brightness(0) invert(1)}
.nav.nav--menu .nav__logo .lk-w{border-left-color:var(--line-d)}
.nav.nav--menu .scrim::after{
  background:linear-gradient(180deg,rgba(3,8,15,.86) 0%,rgba(3,8,15,.52) 46%,rgba(3,8,15,0) 100%)}
/* The panel. Without JavaScript .drawer{display:none} still holds. With it the
   panel is always in the tree, hidden by visibility and clipped to nothing,
   and it comes down from the header as the bottom edge of the clip descends:
   the same reveal as a height animation, without touching layout. On the way
   out the links go first and the panel lifts after them; visibility flips to
   hidden only once the clip has closed. */
.js .drawer{display:flex;visibility:hidden;clip-path:inset(0 0 100% 0);
  transition:clip-path var(--dur-3) var(--ease-io),visibility 0s var(--dur-3)}
.js .drawer.is-open{visibility:visible;clip-path:inset(0);
  transition:clip-path var(--dur-3) var(--ease-io)}
/* Each link rises 20px into place. Its place in the queue is --i, written by
   the runtime; the delay is a 120ms head start plus one --stag per link,
   expressed in steps of --stag so no duration off the scale appears here. */
.js .drawer a{opacity:0;transform:translateY(20px);
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-2) var(--ease)}
.js .drawer.is-open a{opacity:1;transform:none;
  transition-delay:calc((var(--i,0) + 1.5) * var(--stag))}

/* --------------------------------------------------------------------------
   MOTION 11 · component-states · the lightbox
   Built by the runtime on first use over .carou__shot and [data-lb], so
   nothing sits over the first paint. The veil covers, so it takes --ease-io;
   the photo arrives, so it settles on --ease from .96 to 1. Opening is a
   state step, closing a micro step. The close button is the FAQ sign, open.
   -------------------------------------------------------------------------- */
.lb{position:fixed;inset:0;z-index:350;display:flex;align-items:center;justify-content:center;
  padding:var(--edge);background:rgba(0,0,0,.92);color:var(--ivory);cursor:zoom-out;
  opacity:0;visibility:hidden;
  transition:opacity var(--dur-1) var(--ease-io),visibility var(--dur-1)}
/* visibility flips at once on open (a transitioned visibility starts hidden
   on its first frame, and the close button could not take focus); the resting
   rule above still delays the hide until the fade out has run */
.lb[data-open]{opacity:1;visibility:visible;
  transition:opacity var(--dur-2) var(--ease-io),visibility 0s}
.lb img{max-width:min(92vw,1400px);max-height:88vh;width:auto;height:auto;cursor:default;
  transform:scale(.96);transition:transform var(--dur-3) var(--ease)}
.lb[data-open] img{transform:none}
.lb__x{position:absolute;top:var(--edge);right:var(--edge);width:44px;height:44px;
  background:var(--line-d-soft);color:var(--ivory);cursor:pointer;
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease)}
.lb__x::before,.lb__x::after{content:"";position:absolute;left:50%;top:50%;width:15px;height:1px;
  background:currentColor;transform:translate(-50%,-50%) rotate(45deg)}
.lb__x::after{transform:translate(-50%,-50%) rotate(135deg)}
.lb__x:hover,.lb__x:focus-visible{background:var(--gold);color:var(--ink)}
/* the plate is a trigger now: say so with the cursor, and give the keyboard
   a ring it can see against a photograph */
.carou__shot[role="button"]{cursor:zoom-in}
.carou__shot[role="button"]:focus-visible{outline-offset:-2px}

/* ==========================================================================
   POTENCIA · 2026-09-03
   The second movement pass: what Javi asked for after the first ("more
   modern, more top, ultra powerful animations"). Eight pieces, built and
   proven in _motion/ (previews and Playwright runs in .qa/motion/pow/), then
   folded in here. Rules that REPLACE an existing one were applied in place
   above (the REPLACE notes of each piece are kept in
   .qa/motion/pow/integrate/replace-notes/); everything
   genuinely new lives here, one block per piece. Only transform, opacity,
   clip-path, filter (on leaves) and colour; every duration and curve is a
   token. Reduced motion and print for these rules close the sheet's MOTION
   block below, so they win by order.
   ========================================================================== */

/* --------------------------------------------------------------------------
   POTENCIA 02 · entrances-bold · entrances you can see at a human scroll
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   1. The block. 56px of travel (36 on a phone), a full fade, --dur-4.
   Longhands, never the shorthand: the shorthand resets transition-delay and
   the .rv-d1..d5 step rules rely on it. --rv-op is the opacity duration so
   a scroll-state row (.rows--dim li, .stack__row) can keep its own quick
   dip without restating the list.
   -------------------------------------------------------------------------- */
.js .rv{--rv-y:56px;--rv-op:var(--dur-4);--rv-blur:10px;
  opacity:0;transform:translateY(var(--rv-y));
  transition-property:opacity,transform,filter,color,background;
  transition-duration:var(--rv-op),var(--dur-4),var(--dur-4),var(--dur-2),var(--dur-1);
  transition-timing-function:var(--ease)}
.js .rv.is-in{opacity:1;transform:none}
/* the themed copy of the rule (sharp.css line 1787) is a shorthand at 0,3,0
   and would put --dur-3 back: restated as longhands at the same weight */
.js .rv[data-on],.js [data-on] .rv{
  transition-property:opacity,transform,filter,color,background;
  transition-duration:var(--rv-op),var(--dur-4),var(--dur-4),var(--dur-2),var(--dur-1);
  transition-timing-function:var(--ease)}
/* the step runs to six siblings, then holds */
.js .rv-d5,.js .rv-d5[data-on],.js [data-on] .rv-d5{transition-delay:calc(var(--stag) * 5)}
@media (max-width:760px){.js .rv{--rv-y:36px}}

/* --------------------------------------------------------------------------
   2. Leaves resolve out of a blur (worldquantfoundry). A leaf is a .rv with
   no .rv inside it and nothing pinned or drawn by the GPU inside it: a
   paragraph, a card, a row, a data card, a FAQ item, a portrait. filter is
   never written on an ancestor of a sticky element (.stack__media, .side,
   .tl__pin, .foot) nor on the deck, the map, the carousel, a canvas or a
   video, and never inside the hero, which has its own choreography.
   is-in resolves to filter:none, not blur(0): none drops the effect node.
   -------------------------------------------------------------------------- */
/* (.dcard left out: data-theatre, below, brings the figure into focus itself
   and its own transition list on the card would drop the filter) */
.js .rv:not(.head,.deck,.dcard,.hero *,:has(> .lnr),:has(.rv,.stack__media,.side,.tl__pin,.foot,.wmap,.deck,.carou,canvas,video,iframe,[data-sen3d])){
  filter:blur(var(--rv-blur))}
.js .rv.is-in:not(.head,.deck,.dcard,.hero *,:has(> .lnr),:has(.rv,.stack__media,.side,.tl__pin,.foot,.wmap,.deck,.carou,canvas,video,iframe,[data-sen3d])){
  filter:none}
/* (.head and a block with a display heading are excluded here and handled
   in 4: they do not blur as a block, their parts arrive) */
/* a container that holds leaves does not move as a block: its leaves arrive
   one step apart and the container is only the trigger (watch fires the
   ancestors first, so a leaf is never behind a hidden parent) */
.js .rv:has(.rv){opacity:1;transform:none}

/* --------------------------------------------------------------------------
   The card strip does not arrive as one block that rises and resolves out of a
   blur, the way everything else does. Its hairlines draw themselves from the
   top (the strip's own background, grown from 0 height, so it works the same
   at four columns, at two and at one), and the label and the line inside each
   column rise behind them, one column a step after the last. Cards that carry
   a photograph keep the house entrance: this is for the plain data columns.
   (Javi, 07/09: "la animacion de cajas quiero que sea otra")
   -------------------------------------------------------------------------- */
.js .cards.rv{background-color:transparent;
  background-image:linear-gradient(var(--cards-line),var(--cards-line));
  background-repeat:no-repeat;background-position:0 0;background-size:100% 0%;
  transition:background-size var(--dur-4) var(--ease-io)}
.js .cards.rv.is-in{background-size:100% 100%}
.js .cards > .card.rv:not(:has(.card__media)){opacity:1;transform:none;filter:none}
.js .cards > .card.rv:not(:has(.card__media)) > *{opacity:0;transform:translateY(14px);
  transition-property:opacity,transform;
  transition-duration:var(--dur-3),var(--dur-3);
  transition-timing-function:var(--ease)}
.js .cards > .card.rv.is-in:not(:has(.card__media)) > *{opacity:1;transform:none}
/* the chain: one --stag between columns, holding from the fourth on, the way
   the display lines do */
.js .cards > .card.rv:nth-child(1):not(:has(.card__media)) > *{transition-delay:var(--stag)}
.js .cards > .card.rv:nth-child(2):not(:has(.card__media)) > *{transition-delay:calc(var(--stag) * 2)}
.js .cards > .card.rv:nth-child(3):not(:has(.card__media)) > *{transition-delay:calc(var(--stag) * 3)}
.js .cards > .card.rv:nth-child(n+4):not(:has(.card__media)) > *{transition-delay:calc(var(--stag) * 4)}
/* reduced motion: the strip is simply there */
.js.rm .cards.rv{background-size:100% 100%}
.js.rm .cards > .card.rv,
.js.rm .cards > .card.rv > *{opacity:1;transform:none}

/* the two scroll-state rows keep their own quick opacity dip (--dur-2) and
   take the blur resolve with the rise. Their shorthands sit at 0,4,0 and
   0,3,1 in sharp.css (lines 456 and 516): restated one weight above. */
.js:not(.rm) .stack__list .stack__row.rv,.js:not(.rm) .rows--dim li.rv{--rv-op:var(--dur-2);
  transition-property:opacity,transform,filter,color;
  transition-duration:var(--dur-2),var(--dur-4),var(--dur-4),var(--dur-2);
  transition-timing-function:var(--ease)}

/* --------------------------------------------------------------------------
   3. Display lines: from 115% below, three degrees, a hair smaller, then
   home. Same mask, same --dur-4 and the same step per line (sharp.css line
   1457). The split is rebuilt by applyLang and keeps is-in: the new lines
   are styled at rest, nothing here changes that.
   -------------------------------------------------------------------------- */
.js .lnr .ln__i{transform:translateY(115%) rotate(3deg) scale(.985);transform-origin:0% 100%}
.js .lnr.is-in .ln__i{transform:none}

/* --------------------------------------------------------------------------
   4. The head of a band, and any block whose first-level child is a display
   heading (.trio > div, .gsplit > div, .railed > div): the block itself
   stays put and its parts arrive in order. The kicker wipes in from the
   left (--dur-3, first), the heading's lines rise two steps later, and the
   rest (the lede, the action) resolves three steps in. All keyed on the
   block's own is-in, which watch() guarantees (6 s net, sweep), and cut by
   .is-now when the block lands painted.
   -------------------------------------------------------------------------- */
.js .head.rv,.js .rv:has(> .lnr){opacity:1;transform:none;filter:none}
/* the kicker: a horizontal wipe */
.js :is(.head.rv,.rv:has(> .lnr)) .kick{clip-path:inset(0 100% 0 0);
  transition:clip-path var(--dur-3) var(--ease),color var(--dur-2) var(--ease)}
.js :is(.head.rv.is-in,.rv.is-in:has(> .lnr)) .kick{clip-path:inset(0)}
/* the lines: two steps after the kicker */
.js :is(.head,.rv:has(> .lnr)) .lnr .ln__i{transition-delay:calc(var(--stag) * 2)}
.js :is(.head,.rv:has(> .lnr)) .lnr .ln:nth-child(2) .ln__i{transition-delay:calc(var(--stag) * 3)}
.js :is(.head,.rv:has(> .lnr)) .lnr .ln:nth-child(3) .ln__i{transition-delay:calc(var(--stag) * 4)}
.js :is(.head,.rv:has(> .lnr)) .lnr .ln:nth-child(4) .ln__i{transition-delay:calc(var(--stag) * 5)}
.js :is(.head,.rv:has(> .lnr)) .lnr .ln:nth-child(n+5) .ln__i{transition-delay:calc(var(--stag) * 6)}
/* the rest: a lede, an action, a list, or the wrapper of a heading that
   could not be split (inline markup: it stays whole and rises as one).
   Never a nested .rv, which keeps its own arrival and step. */
.js :is(.head.rv,.rv:has(> .lnr)) > :not(.lnr,.kick,.rv,:has(.lnr)),
.js :is(.head.rv,.rv:has(> .lnr)) > :has(.lnr) > :not(.lnr,.kick,.rv){
  opacity:0;transform:translateY(var(--rv-y,56px));filter:blur(var(--rv-blur,10px));
  transition-property:opacity,transform,filter,color,background;
  transition-duration:var(--dur-4),var(--dur-4),var(--dur-4),var(--dur-2),var(--dur-1);
  transition-timing-function:var(--ease);
  transition-delay:calc(var(--stag) * 3)}
.js :is(.head.rv.is-in,.rv.is-in:has(> .lnr)) > :not(.lnr,.kick,.rv,:has(.lnr)),
.js :is(.head.rv.is-in,.rv.is-in:has(> .lnr)) > :has(.lnr) > :not(.lnr,.kick,.rv){
  opacity:1;transform:none;filter:none}
/* a heading that stayed whole (no .lnr) inside a head: its wrapper rose as
   one above, so the lines rule never applies to it. Nothing else needed. */

/* --------------------------------------------------------------------------
   5. The traced hairline (MOTION 06) starts one state after the row does,
   so the line is drawn under a row that has already resolved, not under a
   blur. --dur-4, the row's own step, to six siblings. The FAQ item gets the
   same trace: same construction (a painted 1px line at the bottom).
   -------------------------------------------------------------------------- */
.js:not(.rm) .faq li.rv{background-image:none}
.js:not(.rm) .faq li.rv::after{content:"";
  position:absolute;left:0;bottom:0;width:100%;height:1px;
  background:currentColor;opacity:.15;
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform var(--dur-4) var(--ease)}
.js:not(.rm) .faq li{position:relative}
.js:not(.rm) .faq li.rv.is-in::after{transform:none}
.js:not(.rm) :is(.rows,.rowlist,.faq) li.rv::after{transition-delay:var(--dur-2)}
.js:not(.rm) :is(.rows,.rowlist,.faq) li.rv-d1::after{transition-delay:calc(var(--dur-2) + var(--stag))}
.js:not(.rm) :is(.rows,.rowlist,.faq) li.rv-d2::after{transition-delay:calc(var(--dur-2) + var(--stag) * 2)}
.js:not(.rm) :is(.rows,.rowlist,.faq) li.rv-d3::after{transition-delay:calc(var(--dur-2) + var(--stag) * 3)}
.js:not(.rm) :is(.rows,.rowlist,.faq) li.rv-d4::after{transition-delay:calc(var(--dur-2) + var(--stag) * 4)}
.js:not(.rm) :is(.rows,.rowlist,.faq) li.rv-d5::after{transition-delay:calc(var(--dur-2) + var(--stag) * 5)}

/* --------------------------------------------------------------------------
   POTENCIA 03 · photo-drama · the hand on the plate (the mask, the counter-scale
   and the .55 grid focus replaced their MOTION 05 originals in place)
   -------------------------------------------------------------------------- */

/* 4. The hand on a plate: what sits under the photograph rises 8px towards
   it (the card's kicker, title and copy together; the figure's caption) and
   the plate's bottom hairline is traced in gold, left to right. Gold as a
   line only. Pointer only: a touch has no hover to leave.
   (0,5,0) with :has and :not, above .js [data-on] * (0,2,0) which sets a
   colour-only transition on everything themed; colour and ground restated. */
@media (hover:hover){
  .js .card:has(> .card__media) > :not(.card__media){
    transition:translate var(--dur-2) var(--ease),color var(--dur-2) var(--ease),background var(--dur-1) var(--ease)}
  .js .card:has(> .card__media):hover > :not(.card__media){translate:0 -8px}
  .js .people figure > figcaption,.js .carou__slide > figcaption{
    transition:translate var(--dur-2) var(--ease),color var(--dur-2) var(--ease)}
  .js .people figure:hover > figcaption,.js .carou__slide:hover > figcaption{translate:0 -8px}
  .js .people figure,.js .carou__slide{position:relative}
  /* 20/09: .carou__slide dropped from this list. The slide already carries a
   gold progress line under the whole carousel, so a second gold line wiping in
   under the caption on hover read as a double rule. Javi: "quita la doble linea
   que sale... quita la de debajo de la imagen". The card and the portrait keep
   it: neither of them sits above a rule of its own. */
.js .card:has(> .card__media):not(.card--cas)::after,.js .people figure::after{
    content:"";position:absolute;left:0;right:0;bottom:0;height:1px;z-index:1;pointer-events:none;
    background:var(--gold);transform:scaleX(0);transform-origin:0 50%;
    transition:transform var(--dur-3) var(--ease)}
  .js .card:has(> .card__media):not(.card--cas):hover::after,.js .people figure:hover::after{
    transform:scaleX(1)}
}

/* 5. The carousel's plate is a lightbox trigger (role=button): keep the
   focus ring above the moving photograph. */
.js .carou__shot[role="button"]:focus-visible{z-index:2}

/* --------------------------------------------------------------------------
   POTENCIA 04 · data-theatre · figures that resolve with theatre
   -------------------------------------------------------------------------- */

/* --- the plate, dealt ------------------------------------------------------
   Hidden by clip, not opacity: the card's own .rv fade (sharp.css) keeps
   running underneath. The clip is released to inset(0) on dt-on (a
   transition needs a value to reach, not none) and dropped at dt-done. */
.js:not(.rm) .dcard{transition:clip-path var(--dur-4) var(--ease-io),transform var(--dur-5) var(--ease),
  opacity var(--dur-3) var(--ease)}
.js:not(.rm) .dcard:not(.dt-on){clip-path:inset(0 0 100% 0);transform:translateY(64px)}
.js:not(.rm) .dcard.dt-on{clip-path:inset(0)}
.js:not(.rm) .dcard.dt-done{clip-path:none}

/* --- the figure ---------------------------------------------------------
   Born below its line, small and out of focus. Its line (.dcard__n) is the
   slot: clipped at its bottom edge, open at the top so the count can breathe.
   The figure rises and grows over --dur-5, the same span the count runs
   (initDataTheatre sets data-dur to that token), so the last digit lands
   the moment the glyphs are sharp. Inline-block so it can scale; origin at
   its left baseline so it grows in place, not off the line. */
.js:not(.rm) .dcard__n:has(> span[data-count]){clip-path:inset(-.14em 0 0 0)}
.js:not(.rm) .dcard.dt-done .dcard__n:has(> span[data-count]){clip-path:none}
.js:not(.rm) span[data-count]{display:inline-block;transform-origin:0 100%;transform:translateY(110%) scale(.82);
  filter:blur(6px);
  transition:transform var(--dur-5) var(--ease),filter var(--dur-5) var(--ease-io),color var(--dur-2) var(--ease)}
.js:not(.rm) span[data-count].dt-run,.js:not(.rm) span[data-count].dt-done{transform:none;filter:none}

/* --- what follows the figure --------------------------------------------
   Kickers and unit arrive two steps after the figure starts, sliding in
   from the left (a real distance, not a nudge). The unit is inline in the
   markup, so inline-block for the transform. The second kicker two steps
   later still. */
.js:not(.rm) .dcard .kick--2,
.js:not(.rm) .dcard .dcard__n > .sq-inline{opacity:0;transform:translateX(-56px);
  transition:opacity var(--dur-4) var(--ease),transform var(--dur-4) var(--ease),color var(--dur-2) var(--ease);
  transition-delay:calc(var(--stag) * 2)}
.js:not(.rm) .dcard .dcard__n > .sq-inline{display:inline-block}
.js:not(.rm) .dcard .dcard__set > * + * .kick--2{transition-delay:calc(var(--stag) * 4)}
.js:not(.rm) .dcard.dt-on .kick--2,
.js:not(.rm) .dcard.dt-on .dcard__n > .sq-inline{opacity:1;transform:none}

/* --- "Awaiting feed" -----------------------------------------------------
   Stays text (never a plausible number). Enters through a horizontal clip,
   left to right, after the figure and its labels. Only the figure line that
   carries no counter. */
.js:not(.rm) .dcard .dcard__n:not(:has(span[data-count])){clip-path:inset(0 100% 0 0);
  transition:clip-path var(--dur-4) var(--ease);transition-delay:calc(var(--stag) * 6)}
.js:not(.rm) .dcard.dt-on .dcard__n:not(:has(span[data-count])){clip-path:inset(0)}

/* --- the sparkline grid, swept --------------------------------------------
   The chart ground draws itself left to right once the figure is in flight:
   the data area opening for the feed. */
.js:not(.rm) .dcard .dcard__spark{clip-path:inset(0 100% 0 0);
  transition:clip-path var(--dur-5) var(--ease);transition-delay:calc(var(--stag) * 4)}
.js:not(.rm) .dcard.dt-on .dcard__spark{clip-path:inset(0)}

/* --- the foot ---------------------------------------------------------------
   Live label and button rise last, 32px, so the beat lands on a label that
   has just arrived. */
.js:not(.rm) .dcard .dcard__foot{opacity:0;transform:translateY(32px);
  transition:opacity var(--dur-4) var(--ease),transform var(--dur-4) var(--ease);
  transition-delay:calc(var(--stag) * 8)}
.js:not(.rm) .dcard.dt-on .dcard__foot{opacity:1;transform:none}

/* --- the card's hairline, traced -----------------------------------------
   Two pseudo-elements carry the four sides: ::before top + right, ::after
   bottom + left. The hairline exists in every mode (no JS, reduced motion);
   with motion it is drawn top, right, bottom, left over --dur-5 in gold (the
   colour of the live dot, never of a word) and settles to the sheet's line
   once the figure has landed (dt-done). z-index 1 keeps it over the
   gradient; the card's 22px padding keeps it off the content. */
.dcard::before,.dcard::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:1;
  border:0 solid var(--line-d);transition:border-color var(--dur-4) var(--ease)}
.dcard::before{border-top-width:1px;border-right-width:1px}
.dcard::after{border-bottom-width:1px;border-left-width:1px}
.js:not(.rm) .dcard:not(.dt-on)::before{clip-path:inset(0 100% calc(100% - 1px) 0)}
.js:not(.rm) .dcard:not(.dt-on)::after{clip-path:inset(calc(100% - 1px) 0 0 100%)}
.js:not(.rm) .dcard.dt-on::before,.js:not(.rm) .dcard.dt-on::after{clip-path:inset(0);border-color:var(--gold)}
.js:not(.rm) .dcard.dt-on::before{animation:dt-trace-a var(--dur-5) var(--ease)}
.js:not(.rm) .dcard.dt-on::after{animation:dt-trace-b var(--dur-5) var(--ease)}
.js:not(.rm) .dcard.dt-on.dt-done::before,.js:not(.rm) .dcard.dt-on.dt-done::after{border-color:var(--line-d)}
@keyframes dt-trace-a{
  0%{clip-path:inset(0 100% calc(100% - 1px) 0)}
  25%{clip-path:inset(0 0 calc(100% - 1px) 0)}
  50%,100%{clip-path:inset(0)}}
@keyframes dt-trace-b{
  0%,50%{clip-path:inset(calc(100% - 1px) 0 0 100%)}
  75%{clip-path:inset(calc(100% - 1px) 0 0 0)}
  100%{clip-path:inset(0)}}

/* --- the live dot's beat -------------------------------------------------
   A layer over the dot (built by initDataTheatre, one <i> per .prov--live),
   invisible until a figure lands or the feed writes a value: then one beat,
   1 to 1.8 to 1 over --dur-3, with a halo that leaves. The dot's own pulse
   (sharp.css, .prov--live::before) keeps going underneath. */
.prov--live .dt-dot{position:absolute;left:0;top:50%;width:6px;height:6px;margin-top:-3px;border-radius:50%;
  background:var(--gold);opacity:0;pointer-events:none;z-index:1}
.prov--live .dt-dot::before{content:"";position:absolute;inset:-3px;border-radius:50%;border:1px solid var(--gold);opacity:0}
.prov--live[data-on="light"] .dt-dot,[data-on="light"] .prov--live .dt-dot{background:var(--gold-deep)}
.prov--live[data-on="light"] .dt-dot::before,[data-on="light"] .prov--live .dt-dot::before{border-color:var(--gold-deep)}
.js:not(.rm) .prov--live .dt-dot.dt-beat{animation:dt-beat var(--dur-3) var(--ease)}
.js:not(.rm) .prov--live .dt-dot.dt-beat::before{animation:dt-beat-halo var(--dur-4) var(--ease)}
@keyframes dt-beat{0%{transform:scale(1);opacity:1}50%{transform:scale(1.8);opacity:1}100%{transform:scale(1);opacity:0}}
@keyframes dt-beat-halo{0%{transform:scale(1);opacity:.9}100%{transform:scale(5);opacity:0}}

/* --- landed as painted ----------------------------------------------------
   Same contract as .is-now (land): one style pass with no transition and no
   animation, so a figure written in one go (restored scroll, fragment jump,
   focus) shows at its value and its card dealt with its line drawn. */
.js .dt-now,.js .dt-now *,.js .dt-now::before,.js .dt-now::after,.js .dt-now *::before,.js .dt-now *::after{
  transition:none!important;animation:none!important}

/* --------------------------------------------------------------------------
   POTENCIA 05 · footer-veil-cinema · the foot as a moment (the seal and the
   veil replaced their originals in place: FOOTER and MOTION 08 blocks)
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   A · FOOT · choreography scrubbed by --fp (0 covered, 1 exposed), written by
   initFooterCurtain. Each layer has an index --fv-i and resolves over a slice
   of the travel: k = clamp(0, (fp - i * step) / span, 1). At --fp = 1 every k
   is 1 and everything is at rest; --fp absent (phones, ramp pages, reduced
   motion, no JS) reads as 1 through var(--fp,1). Nothing here transitions:
   if the hand stops, the page stops.
   --fv-step mirrors --stag / --dur-4 (80 / 900 = .089): the step between
   siblings as a fraction of the curtain's arrival, because a scrubbed value
   has no clock to hang a millisecond on. --fv-span is the slice each layer
   takes; the last index (6) starts at .48 and lands at .98.
   -------------------------------------------------------------------------- */
.foot{--fv-step:.08;--fv-span:.5}
/* the six big links, one behind the other: 40px each on top of the column's
   own 48px, so the last one travels 88px while the first travels 48 */
.js .foot__big a{--fv-i:1;
  --fv-k:clamp(0,calc((var(--fp,1) - var(--fv-i) * var(--fv-step)) / var(--fv-span)),1);
  transform:translateY(calc((1 - var(--fv-k)) * 40px))}
.js .foot__big a:nth-child(2){--fv-i:2}
.js .foot__big a:nth-child(3){--fv-i:3}
.js .foot__big a:nth-child(4){--fv-i:4}
.js .foot__big a:nth-child(5){--fv-i:5}
.js .foot__big a:nth-child(n+6){--fv-i:6}

/* the claim, line by line. initFooterVeilCinema splits the heading into its
   rendered lines (.fv-ln > .fv-ln__i, words first wrapped in .fv-w to read
   where the browser broke them). Each line box clips, each line rises from
   under its own box with the two and a half degrees of the .lnr lines. The
   heading itself never moves or clips, so a language change that rewrites
   it leaves plain, visible text until the split runs again. */
.fv-w{display:inline}
.js .fv-ln{display:block;overflow:hidden;padding-bottom:.06em;margin-bottom:-.06em}
.js .fv-ln__i{display:block;--fv-i:0;
  --fv-k:clamp(0,calc((var(--fp,1) - var(--fv-i) * var(--fv-step)) / var(--fv-span)),1);
  transform:translateY(calc((1 - var(--fv-k)) * 112%)) rotate(calc((1 - var(--fv-k)) * 2.6deg));
  transform-origin:0 100%}
.js .fv-ln:nth-child(2) .fv-ln__i{--fv-i:1}
.js .fv-ln:nth-child(3) .fv-ln__i{--fv-i:2}
.js .fv-ln:nth-child(n+4) .fv-ln__i{--fv-i:3}

/* the legal row follows from a little deeper, like the columns above it */
.js .foot__legal{transform:translateY(calc((1 - var(--fp,1)) * 24px))}

/* Two things resolve with a clock rather than the hand, once the footer is
   half exposed (foot--open, set by initFooterVeilCinema at --fp >= .5, on
   focus inside the footer, at the end of the page, or through watch() where
   the footer is not stuck): the bracketed link draws its corners in --dur-3
   and the brand lockup fades in last. Closed only under .js without reduced
   motion; the is-now pass lands them without a transition. */
.js:not(.rm) .foot .brk{transition:background-size var(--dur-3) var(--ease),color var(--dur-1) var(--ease)}
.js:not(.rm) .foot:not(.foot--open) .brk{--brk:0px}
.js:not(.rm) .foot .foot__brands{transition:opacity var(--dur-4) var(--ease) calc(var(--stag) * 4),
  transform var(--dur-4) var(--ease) calc(var(--stag) * 4)}
.js:not(.rm) .foot:not(.foot--open) .foot__brands{opacity:0;transform:translateY(24px)}

/* --------------------------------------------------------------------------
   POTENCIA 06 · markets-cascade · the cascade, the card that answers the hand
   and the territory (the map sequence replaced its WORLD MAP originals in place)
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   A · THE CASCADE. .card--cas is set by the runtime on the cards of a .cards
   grid that carry a photograph; --k is the card's diagonal (row + column),
   written inline because it depends on the live column count. The card rises
   64 px over --dur-4 while its photograph (photo-unveil, [data-unmask] with
   --i = --k + 1) opens top to bottom one step behind. The list restates
   colour and background so the themed card (.js .card[data-on], 0,3,0) keeps
   its theme fade and its hover ground: a transition shorthand replaces the
   whole list.
   -------------------------------------------------------------------------- */
.js .cards > .card--cas.rv{opacity:0;transform:translateY(64px);
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-4) var(--ease),
    filter var(--dur-4) var(--ease),
    color var(--dur-2) var(--ease),background var(--dur-1) var(--ease);
  transition-delay:calc(var(--k,0) * var(--stag)),calc(var(--k,0) * var(--stag)),calc(var(--k,0) * var(--stag)),0s,0s}
/* its photograph (photo-drama's letterbox, --i = --k + 1 written by
   initMarketsCascade) opens one --stag behind the card, on the cascade's clock */
.js .card--cas .card__media[data-unmask]{transition-delay:calc(var(--i,0) * var(--stag))}
.js .card--cas .card__media[data-unmask][data-grow] > img{transition-delay:calc(var(--i,0) * var(--stag)),0s,0s}
.js .cards > .card--cas.rv.is-in{opacity:1;transform:none}

/* The card answers the hand. 20/09, Javi: "quita la linea que hay encima y
   quiero algo mas moderno mas top".
   It used to draw a 2px gold bar across the whole top edge, which is a lot of
   accent for a hover and sat above the photograph rather than on anything the
   reader was looking at. The accent is still a line -- never a fill behind
   text -- but it is now the title's own rule, drawn under the words it
   belongs to, while the photograph pushes in behind its frame and the arrow
   travels. Three small moves that all point at the same place, instead of one
   big one at the edge. Keyboard focus gets the same answer. */
/* width:fit-content, not display:inline-block: .card is a flex container and
   a flex item's inline-block is blockified by the spec, so the rule below
   would have spanned the whole column instead of the title. */
.js .card--cas .h4{position:relative;width:fit-content;max-width:100%;
  transition:transform var(--dur-2) var(--ease),color var(--dur-2) var(--ease)}
.js .card--cas .h4::after{content:"";position:absolute;left:0;right:0;bottom:-6px;height:1px;
  background:var(--gold);transform:scaleX(0);transform-origin:0 50%;
  transition:transform var(--dur-3) var(--ease);pointer-events:none}
.card--cas:hover .h4::after,.card--cas:focus-visible .h4::after{transform:scaleX(1)}
.card--cas:hover .h4,.card--cas:focus-visible .h4{transform:translateY(-4px)}

/* the photograph leans in behind its own frame */
.js .card--cas .card__media{overflow:hidden}
.js .card--cas .card__media > img{transition:transform var(--dur-4) var(--ease),
  filter var(--dur-2) var(--ease)}
.card--cas:hover .card__media > img,
.card--cas:focus-visible .card__media > img{transform:scale(1.045)}
/* the arrow, injected by the runtime on link cards only (decoration: no text,
   aria-hidden). It waits half hidden at the card's foot and comes forward. */
.card__go{display:flex;justify-content:flex-end;margin-top:auto;padding-top:4px;
  line-height:0;overflow:hidden;pointer-events:none}
.card__go svg{width:22px;height:22px;transform:translateX(-16px);opacity:.42;
  transition:transform var(--dur-2) var(--ease),opacity var(--dur-2) var(--ease)}
.card--cas:hover .card__go svg,.card--cas:focus-visible .card__go svg{transform:none;opacity:1}
/* --------------------------------------------------------------------------
   C · THE TERRITORY. On a market page the country's outline traces itself
   in over --dur-5 as it arrives (pathLength 1000 set by the runtime, so the
   dash is the whole outline whatever its length) and the fill settles in
   behind it. .is-trace is the runtime's mark; .is-in comes through watch().
   -------------------------------------------------------------------------- */
.js .terr--solo.is-trace path{stroke-dasharray:1000;stroke-dashoffset:1000;fill-opacity:0;
  transition:stroke-dashoffset var(--dur-5) var(--ease),fill-opacity var(--dur-4) var(--ease) var(--dur-4)}
.js .terr--solo.is-trace.is-in path{stroke-dashoffset:0;fill-opacity:.10}

/* --------------------------------------------------------------------------
   POTENCIA 07 · stack-brands-power · the row that lights, the plate's caption,
   the deck's photograph (list travel, marker, plates, deck plate/step/body
   replaced their originals in place: MOTION 04, STACK and DECK blocks)
   -------------------------------------------------------------------------- */

/* the caption arrives with the mask, a step behind the photograph */
.js:not(.rm) .stack__media [data-stack-media] figcaption{transform:translateY(14px);
  transition:transform var(--dur-3) var(--ease)}
.js:not(.rm) .stack__media [data-stack-media].is-on figcaption{transform:none;
  transition-delay:var(--stag)}

/* --------------------------------------------------------------------------
   STACK · the row
   -------------------------------------------------------------------------- */
/* the kick is traced left to right when the row lights: a one-shot
   animation, so at rest, lit or dim, it is whole. Hover and focus light a
   row too, so the hand replays it. */
@keyframes kick-trace{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0)}}
.js:not(.rm) .stack__row.is-on .kick{animation:kick-trace var(--dur-3) var(--ease) both}
/* the title waits 16px low and rises when the row lights; the paragraph
   follows one --stag later. Transform only: the row's own dim state is its
   opacity, untouched here. */
.js:not(.rm) .stack__row .h3{transform:translateY(16px);
  transition:transform var(--dur-3) var(--ease),color var(--dur-2) var(--ease)}
.js:not(.rm) .stack__row > p{transform:translateY(10px);
  transition:transform var(--dur-3) var(--ease),color var(--dur-2) var(--ease)}
.js:not(.rm) .stack__row.is-on .h3,.js:not(.rm) .stack__row.is-on > p{transform:none}
.js:not(.rm) .stack__row.is-on > p{transition-delay:var(--stag)}

/* --------------------------------------------------------------------------
   DECK · the plate and its photograph
   -------------------------------------------------------------------------- */
/* the plate lands from 1.08 while it fades in; the card's clip trims the
   overshoot, so the panel is seen settling into its own frame */
.js:not(.rm) .deck__item .deck__plate{transform:scale(1.08);transform-origin:50% 50%;
  transition:opacity var(--dur-3) var(--ease) var(--deck-dd,0s),
    transform var(--dur-3) var(--ease) var(--deck-dd,0s)}
.js:not(.rm) .deck__item.is-on .deck__plate{transform:none}
/* the market photograph, behind the copy. Masked so the name at the top and
   the body at the foot sit on plain navy, and darkened so what shows in the
   middle is a place, not a competitor to the text. It settles from 1.12 on
   the plate's own arrival. Filter on a leaf, never on an ancestor. */
.deck__ph{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:.55;filter:grayscale(.35) brightness(.55) contrast(1.06);
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 24%,#000 60%,transparent 90%);
  mask-image:linear-gradient(180deg,transparent 0,#000 24%,#000 60%,transparent 90%)}
.js:not(.rm) .deck__item .deck__ph{transform:scale(1.12);
  transition:transform var(--dur-4) var(--ease) var(--deck-dd,0s)}
.js:not(.rm) .deck__item.is-on .deck__ph{transform:none}
/* the brackets and the plate follow the item's step */
.js:not(.rm) .deck__item.is-on .deck__plate::before{transition-delay:var(--deck-dd,0s)}
.js:not(.rm) .deck__item.is-on .deck__plate::after{transition-delay:calc(var(--stag) * 1.5 + var(--deck-dd,0s))}

/* the description and the chip rise into the sweep, one --stag apart. The
   chip is a .btn inside a themed card, so colour stays in its list. */
.js:not(.rm) .deck__item .deck__desc,.js:not(.rm) .deck__item .deck__go{transform:translateY(18px);
  transition:transform var(--dur-3) var(--ease),color var(--dur-2) var(--ease)}
.js:not(.rm) .deck__item.is-on .deck__desc{transform:none;
  transition-delay:calc(var(--stag) * 2 + var(--deck-dd,0s)),0s}
.js:not(.rm) .deck__item.is-on .deck__go{transform:none;
  transition-delay:calc(var(--stag) * 3 + var(--deck-dd,0s)),0s}
@media (max-width:900px){
  /* same specificity as the rules above, so the column wins by order */
  .js:not(.rm) .deck__item .deck__plate,.js:not(.rm) .deck__item .deck__ph{transform:none}
  .js:not(.rm) .deck__item .deck__desc,.js:not(.rm) .deck__item .deck__go{transform:none}
  /* the column is short, so the copy sits over the middle of the photograph:
     it steps further back there */
  .deck__ph{opacity:.4}
}

/* --------------------------------------------------------------------------
   POTENCIA 08 · flight-layer · the fixed WebGL layer, its landing pads and the
   footer marker (sen3d.js mountFlight, mounted by initFlightLayer)
   -------------------------------------------------------------------------- */

/* ==========================================================================
   MOTION · piece 08 · flight-layer
   The fixed WebGL layer where five chips and three cards travel with the
   scroll (sen3d.js mountFlight, built by the other session), the two landing
   pads where they rest on the home, and the marker that stands in for the
   footer anchor.
   Integrates into assets/css/sharp.css at the end of the SEN3D block, right
   after .p3--tall. No colour, no duration: the engine paints, the scroll
   drives, nothing here moves on its own.
   Stacking, measured in sharp.css: main 1 and .foot 0 (the bands), .drawer
   119, .nav 120, .dive-veil 300, .lb 350, .veil and .load 400. 100 sits above
   every band and under every piece of chrome.
   ========================================================================== */
.sen3d-flight{position:fixed;inset:0;z-index:100;pointer-events:none;contain:strict}
.sen3d-flight canvas{width:100%;height:100%;display:block}
/* Landing pads: every anchor on the home is one. An anchor without
   data-sen3d-side is an empty box the cast settles inside, whole, so "never
   over text" holds by construction; the side mode had nothing to park in on
   this full bleed layout (the .wrap is the viewport less 28 px) and left only
   slivers past the edge. Six pads, measured at 1440x900:
   hero   the right half of the hero, from 30 to 80 svh, right of the headline
          (ends at x 783) and above the foot (from 768). The first child of
          main, out of flow: not inside .hero, which is sticky (a pad in it
          would keep the same screen position for the whole page and the
          journey would never start), and not after it, because
          initHeroCinema takes hero.nextElementSibling for the band that
          covers the hero and would scrub --out from the pad's top edge.
   trio   the free space under the Presence paragraph; the row is 618 tall at
          1440 and the column with this pad 604, so nothing grows.
   plate  the photograph of the first pinned plate, short of its caption. The
          figure is the containing block and ends at the caption (12 px, 16 px
          under the photo): bottom 64 px stops the pad 36 px above the photo's
          lower edge, because the engine spreads the cast by piece size and a
          tilted card lands up to 14 px past the box (measured with the cover
          gate: 15 % of "Casino Flamingo · Nairobi" under a queen at rest).
   stmt   a row of air under the story, the width of the text column, so the
          cast lands beside the roulette and never on it.
   mkt    a strip the width of the grid under the seven market cards. The
          engine spreads the cast by piece size, not by box: settled, the
          eight pieces span 119 px above and 115 px below the pad's centre
          (alpha of the canvas, pad-clearance probe, 1440). A 220 px pad put
          the top of that spread 8 px past its own edge and 22 px under the
          last legend of the grid, and a tilted card on arrival touched
          "Croatia" (pow-after h07). 300 px keeps the spread whole inside
          the box and 62 px clear of the legends; the FAQ kick stays 219 px
          under it.
   foot   out of flow, hanging off the bottom edge of main (top:100% is the
          seam), over the ornamental S in the footer's right column. Its top
          is the footer's own padding plus 150 px (the form ends 136 px under
          that padding at every width, measured 1181 to 1920), so settled the
          cast sits 10 px under the sign-up button. The footer is sticky and
          the pad is not: from the settle edge (frac .84) to the end of the
          page there are 81 px of scroll during which the cast is parked in
          the pad and the pad is still rising, so the cast rides 81 px lower
          than its final place, into the legal row. No page height fixes
          that (every px added below the pad adds a px of ride), so the pad
          is narrow and sits in the one column of the legal row that has no
          text: between the copyright line (ends x 1058 at 1440) and "Back to
          top" (starts 1285). 160 px wide the engine's lane spread collapses
          to piece size (max(half * .6, w/2 - half)) and the cast settles in
          x 1050 to 1190; the pieces that ride lowest (the queen and the chip
          at rise .72) pass between the two lines and touch neither. That
          narrow column is a pile, not the spread the wide pad gave: the
          price of a clean rest at every scroll position until the engine's
          settle rule knows about the sticky footer. 300 px tall (top 136 px
          under the padding, centre unchanged) loosens the pile vertically:
          settled, the cast runs from 10 px under the sign-up button to 26
          px above the copyright line (544 to 818 at 1440x900). The
          legal grid's columns scale with the wrap, so the pad is anchored
          to the panel's right edge (the wrap's gutter, max(0, (100% -
          --max) / 2) + --edge, not --edge alone: past 1440 the panel stops
          growing and the viewport does not) with fixed offsets, and the gap
          holds at 1600 and 1920 (measured). Below 1400 the air between the form and the legal row is not
          the cast's height and the pad goes: the flight ends on the markets
          strip.
   Widths: below 1180 the hero headline runs to the right edge and the trio
   folds, so the hero and trio pads go; below 900 the trio is one column. */
.sen3d-pad{pointer-events:none}
.sen3d-pad--hero{position:absolute;right:var(--edge);top:30svh;width:40%;height:50svh}
.sen3d-pad--trio{height:240px}
.sen3d-pad--plate{position:absolute;left:0;right:0;top:0;bottom:64px}
.sen3d-pad--stmt{height:220px;width:42%}
.sen3d-pad--mkt{height:300px}
.sen3d-pad--foot{position:absolute;right:calc(max(0px,(100% - var(--max)) / 2) + var(--edge));top:calc(100% + clamp(38px,5vw,86px) + 160px);width:400px;height:180px}
html:not(.js) .sen3d-flight,html.rm .sen3d-flight,
html:not(.js) .sen3d-pad,html.rm .sen3d-pad{display:none}
/* without JavaScript the poster is the whole piece: no dead control, no HUD */
html:not(.js) .p3__act,html:not(.js) .p3__hud{display:none}
@media (max-width:1399px){.sen3d-pad--foot{display:none}}
@media (max-width:1180px){.sen3d-pad--hero{display:none}}
@media (max-width:900px){.sen3d-pad--trio{display:none}}
@media (max-width:759px){.sen3d-flight,.sen3d-pad{display:none}}

/* --------------------------------------------------------------------------
   MOTION · reduced motion and print for the rules above. Last, so they win.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .js [data-unmask]{clip-path:none}
  /* POTENCIA 02 */
  /* .rv.rv.rv: 0,4,0, one above the leaf rule, so the blur goes too */
  .js .rv.rv.rv{opacity:1;transform:none;filter:none}
  .js :is(.head.rv,.rv:has(> .lnr)) .kick{clip-path:none}
  .js :is(.head.rv,.rv:has(> .lnr)) > :not(.lnr,.kick,.rv,:has(.lnr)),
  .js :is(.head.rv,.rv:has(> .lnr)) > :has(.lnr) > :not(.lnr,.kick,.rv){opacity:1;transform:none;filter:none}
  .js .faq li.rv::after{transform:none}
  /* POTENCIA 03 */
  .js [data-unmask][data-grow] > img{scale:none;translate:none}
  .js .card:has(> .card__media):hover > :not(.card__media),
  .js .people figure:hover > figcaption,.js .carou__slide:hover > figcaption{translate:none}
  /* POTENCIA 04 */
  .js .dcard{clip-path:none;transform:none}
  .js span[data-count]{transform:none;filter:none}
  .js .dcard .kick--2,.js .dcard .dcard__n > .sq-inline,.js .dcard .dcard__foot{opacity:1;transform:none}
  .js .dcard .dcard__n,.js .dcard .dcard__spark{clip-path:none}
  .js .dcard::before,.js .dcard::after{clip-path:none;animation:none}
  .js .prov--live .dt-dot,.js .prov--live .dt-dot::before{animation:none}
  /* POTENCIA 05 */
  .js .foot .brk{--brk:14px}
  .js .foot .foot__brands{opacity:1;transform:none}
  .js .foot__seal,.js .foot__legal,.js .foot__big a,.js .fv-ln__i{transform:none}
  .js .foot__seal{opacity:.05}
  /* POTENCIA 06 */
  .js .cards > .card--cas.rv{opacity:1;transform:none;transition-delay:0s}
  .card--cas .h4,.card--cas:hover .h4,.card__go svg{transform:none}
  .card__go svg{opacity:1}
  .js .wmap__flag,.js .wmap:not(.is-live) .wmap__flag{clip-path:none;transition-delay:0s}
  .js .wmap:not(.is-live) .wmap__pin{opacity:1;transform:none}
  .js .wmap.is-live .wmap__pin,.js .wmap.is-live .wmap__halo,
  .js .wmap.is-live .wmap__zone,.js .wmap.is-live .wmap__lbl{animation:none}
  .js .wmap.is-live .wmap__arcs path,.js .wmap.is-live .wmap__card.is-default{transition-delay:0s}
  .js .terr--solo.is-trace path{stroke-dashoffset:0;fill-opacity:.10;transition-delay:0s}
  /* POTENCIA 07 */
  .js .stack__media [data-stack-media]{clip-path:none}
  .js .stack__media [data-stack-media] img{transform:none}
  .js .stack__media [data-stack-media] figcaption{transform:none}
  .js .stack__row .h3,.js .stack__row > p{transform:none}
  .js .stack__row .kick{animation:none}
  .js .deck__item .deck__plate,.js .deck__item .deck__ph,
  .js .deck__item .deck__desc,.js .deck__item .deck__go{transition:none;transform:none}
  .btn:hover > b svg,.btn:focus-visible > b svg,
  .sqbtn:hover svg,.sqbtn:focus-visible svg,a:hover > .sqbtn svg,a:focus-visible > .sqbtn svg,
  .carou__nav button:hover svg,.carou__nav button:focus-visible svg,
  .deck__nav button:hover svg,.deck__nav button:focus-visible svg,
  .hero__news:hover > a svg,.hero__news > a:focus-visible svg{animation:none}
  .js .rows li.rv::after,.js .rowlist li.rv::after{transform:none}
  .js .drawer,.js .drawer.is-open,.js .drawer a,.js .drawer.is-open a{transition-delay:0s}
}
/* html.rm, the runtime's own flag, mirrors the query for the POTENCIA rules */
.js.rm .rv.rv.rv,.js.rm :is(.head.rv,.rv:has(> .lnr)) > :not(.lnr,.kick,.rv,:has(.lnr)),
.js.rm :is(.head.rv,.rv:has(> .lnr)) > :has(.lnr) > :not(.lnr,.kick,.rv){opacity:1;transform:none;filter:none}
.js.rm :is(.head.rv,.rv:has(> .lnr)) .kick{clip-path:none}
html.rm [data-unmask]{clip-path:none}
html.rm [data-unmask][data-grow] > img{scale:none;translate:none}
@media print{
  .rv,.rv *{opacity:1!important;transform:none!important;filter:none!important;clip-path:none!important}
  .faq li.rv::after{transform:none!important}
  .fv-ln__i,.foot__big a,.foot__legal,.foot__brands{transform:none!important;opacity:1!important}
  .stack__media [data-stack-media]{clip-path:none!important}
  .stack__media [data-stack-media] img,.stack__row .h3,.stack__row > p{transform:none!important}
  .deck__ph{display:none}
}

/* ==========================================================================
   SEN3D · the three WebGL pieces (roulette in the home statement band).
   Markup and module from sen3d-lab/INTEGRACION.md; the container keeps the
   poster until the module sets is-live. Timing on the system tokens.
   ========================================================================== */
.stwheel{display:grid;grid-template-columns:minmax(0,0.88fr) minmax(0,1.12fr);
  gap:clamp(28px,4vw,64px);align-items:center}
.p3{position:relative;overflow:hidden}
.p3 canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.p3 picture{position:absolute;inset:0;display:block}
.p3__poster{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  opacity:.95;transition:opacity var(--dur-3) var(--ease)}
.p3.is-live .p3__poster{opacity:0}
.p3--wide{aspect-ratio:16/11}
.p3--tall{aspect-ratio:4/5}
/* .ctapile and .p3--pile held the chip pile beside the black band's claim.
   The client did not want the chips (07/09); the rules go with them. */
.p3__hud{position:absolute;left:0;bottom:0;z-index:2;pointer-events:none}
.p3__hud b{display:block;font:400 clamp(30px,3.4vw,46px)/1 "Neue Helvena",Helvetica,Arial,sans-serif;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.p3__act{position:absolute;right:0;bottom:0;z-index:2}
/* the throw is in play: the button keeps its focus and its text, only the
   arrow square goes quiet and the pointer says wait */
.p3__act .btn[aria-disabled="true"]{cursor:progress}
.p3__act .btn[aria-disabled="true"] > b{background:var(--chip-d);color:var(--ivory)}
@media (max-width:860px){
  .stwheel{grid-template-columns:1fr;gap:26px}
  .p3--wide{aspect-ratio:4/5}
}
@media (prefers-reduced-motion:reduce){.p3__poster{transition:none}}


/* ==========================================================================
   THE TABLE. Pressing "spin the wheel" opens a demonstration table: the piece
   that lives in the statement band moves into it, a layout of bets goes beside
   it, and the throw is settled against the pockets at the real European odds.
   It is a demonstration and it says so: there is no money in it, no account,
   and nothing leaves the browser. The group's own rule, stated on this site,
   is that where it holds no online licence it offers no online play; a table
   that pretended otherwise would contradict the page it sits on.

   No red. A roulette cloth is red and black, and red is not a colour this
   brand owns, so the bets that would be colour are the ones that are not:
   even and odd, low and high, dozens and columns. The only saturated thing on
   the table is the group's gold, on the chip you are holding and on the number
   that came up.
   ========================================================================== */
.tbl{position:fixed;inset:0;z-index:420;display:grid;grid-template-rows:auto 1fr;
  background:var(--w8);color:var(--tx-d);overflow:auto;overscroll-behavior:contain}
.tbl[hidden]{display:none}
.js .tbl{opacity:0;transform:translateY(2%);
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-3) var(--ease-io)}
.js .tbl.is-on{opacity:1;transform:none}
.tbl__top{display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:18px var(--edge);border-bottom:1px solid var(--line-d)}
.tbl__demo{display:inline-flex;align-items:center;gap:9px}
.tbl__demo::before{content:"";width:6px;height:6px;background:var(--gold)}
.tbl__body{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);
  gap:clamp(20px,3vw,52px);align-items:start;padding:clamp(20px,3vw,44px) var(--edge)}
.tbl__stage{position:relative;min-height:320px}
.tbl__stage .p3{width:100%}
/* the read-out under the wheel: what came up, and what it paid */
.tbl__out{display:grid;gap:10px;margin-top:18px;min-height:132px;align-content:start}
.tbl__num{display:flex;align-items:center;gap:16px}
.tbl__num b{font-size:clamp(54px,7vw,96px);font-weight:700;line-height:.9;
  letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.js .tbl__num b{opacity:0;transform:scale(.86);filter:blur(8px)}
.js .tbl__num.is-in b{opacity:1;transform:none;filter:none;
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-4) var(--ease),filter var(--dur-4) var(--ease)}
.tbl__zero b{color:var(--gold)}
.tbl__verdict{font-size:clamp(17px,1.8vw,22px)}
.tbl__verdict.is-win{color:var(--gold-hi)}
.js .tbl__verdict{opacity:0;transform:translateY(10px)}
.js .tbl__verdict.is-in{opacity:1;transform:none;
  transition:opacity var(--dur-2) var(--ease) var(--dur-1),transform var(--dur-3) var(--ease) var(--dur-1)}
/* the layout */
.tbl__grid{display:grid;grid-template-columns:auto repeat(12,1fr);gap:3px}
.tbl__cell{position:relative;display:flex;align-items:center;justify-content:center;
  min-height:44px;padding:6px 2px;background:var(--chip-d);color:var(--tx-d);
  border:0;font:inherit;font-size:14px;font-variant-numeric:tabular-nums;cursor:pointer;
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease)}
.tbl__cell:hover{background:var(--w5)}
.tbl__cell[data-on-bet]{background:var(--gold);color:var(--ink);font-weight:700}
.tbl__cell--zero{grid-row:span 3;background:var(--w6)}
.tbl__cell--hit{outline:2px solid var(--gold-hi);outline-offset:-2px}
.tbl__outside{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;margin-top:3px}
.tbl__outside .tbl__cell{min-height:40px;font-size:13px;letter-spacing:.06em;
  text-transform:uppercase;font-stretch:82%}
.tbl__chips{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:20px}
.tbl__chip{width:46px;height:46px;border-radius:50%;border:1px solid var(--line-d);
  background:transparent;color:inherit;font:inherit;font-size:14px;cursor:pointer;
  font-variant-numeric:tabular-nums;transition:background var(--dur-1) var(--ease),border-color var(--dur-1) var(--ease)}
.tbl__chip[aria-pressed="true"]{background:var(--gold);color:var(--ink);border-color:var(--gold)}
.tbl__act{display:flex;flex-wrap:wrap;gap:12px;margin-top:20px;align-items:center}
/* --------------------------------------------------------------------------
   THE THROW. This is the one control on the table you should find without
   looking for it: the tallest thing in the bar, and the only one that fills
   with gold as the hand comes near. Once there is a chip down it wears a thin
   gold ring, so the table says when it is ready.
   (Javi, 08/09: "el boton de spin mas grande mas top")
   -------------------------------------------------------------------------- */
.tbl__act .btn--spin{transition:box-shadow var(--dur-2) var(--ease)}
.tbl__act .btn--spin > span{height:60px;padding:0 30px;font-size:16px;letter-spacing:.12em;
  background-color:var(--gold);color:var(--ink);font-weight:700;
  background-image:linear-gradient(var(--gold-hi),var(--gold-hi));
  background-repeat:no-repeat;background-position:0 50%;background-size:0% 100%;
  transition:background-size var(--dur-3) var(--ease-io),background-color var(--dur-1) var(--ease)}
.tbl__act .btn--spin > b{width:60px;height:60px;background:var(--gold-deep);color:var(--ivory)}
.tbl__act .btn--spin:is(:hover,:focus-visible) > b{background:var(--ink);color:var(--paper)}
.tbl__act .btn--spin > b svg{width:20px;height:20px;
  transition:transform var(--dur-2) var(--ease-io)}
.tbl__act .btn--spin:is(:hover,:focus-visible) > span{
  background-color:var(--gold);color:var(--ink);
  background-image:linear-gradient(var(--gold-hi),var(--gold-hi));
  background-repeat:no-repeat;background-position:0 50%;background-size:100% 100%}
.tbl__act .btn--spin:is(:hover,:focus-visible) > b svg{transform:translateX(4px)}
/* a chip is down: the throw is armed */
.tbl__act .btn--spin[aria-disabled="false"]{
  box-shadow:0 0 0 3px var(--ink),0 0 0 4px var(--gold)}
/* a button that cannot do anything right now says so */
.tbl__act .btn[aria-disabled="true"]{opacity:.55;cursor:not-allowed}
.tbl__act .btn--spin[aria-disabled="true"] > span{background-size:0% 100%}
.tbl__bank{display:flex;gap:26px;align-items:baseline;margin-top:18px;
  padding-top:16px;border-top:1px solid var(--line-d)}
.tbl__bank b{font-size:26px;font-weight:700;font-variant-numeric:tabular-nums}
@media (max-width:980px){
  .tbl__body{grid-template-columns:1fr;gap:16px;padding-block:16px}
  .tbl__cell{min-height:38px;font-size:13px}
  /* On a phone the wheel is the whole width, and the engine keeps the ball's
     whole travel in frame: a square canvas whose wheel fills barely two fifths
     of it, so a third of the screen was empty sky between the wheel and the
     cloth. The piece keeps its size (a smaller canvas draws a smaller wheel)
     and the stage crops the sky instead. */
  .tbl__stage{overflow:clip;min-height:0}
  .tbl .p3--wide{margin-block:-20% -34%;max-height:none}
  /* the read-out no longer holds a lane open before there is anything to read */
  .tbl__out{min-height:0;margin-top:10px;
    display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 14px}
  .tbl__num b{font-size:44px}
  .tbl__chips{margin-top:14px}
  .tbl__act{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:14px}
  .tbl__act .btn--spin{grid-column:1/-1}
  .tbl__act .btn--spin > span{flex:1;justify-content:center;padding:0 16px}
  .tbl__act .btn:not(.btn--spin){width:100%}
  .tbl__act .btn:not(.btn--spin) > span{width:100%;justify-content:center;
    padding:0 6px;height:44px;font-size:11px;text-align:center}
  .tbl__bank{margin-top:14px;padding-top:12px}
}
@media (prefers-reduced-motion:reduce){
  .js .tbl,.js .tbl__num b,.js .tbl__verdict{transition:none;opacity:1;transform:none;filter:none}
}
/* the table is a dark ground of its own: the piece's own read-out and throw
   button belong to the band, not here, and the wheel gets the room it needs */
.tbl .p3__hud,.tbl .p3__act{display:none}
.tbl .p3--wide{aspect-ratio:1/1;max-height:56svh;margin-inline:auto}
.tbl__stage{display:grid;align-content:start}

/* Red and black. On a roulette layout these are not brand colours, they are
   the game telling you what it is: every table in the world shows this exact
   distribution, and a player reads the cloth before the wheel. So the red is
   here, on the cloth only, deep enough to sit beside the navy without shouting,
   and it never appears anywhere else on the site. */
.tbl{--felt-red:#8d1b22;--felt-red-hi:#a52028}

/* ---------------------------------------------------------------------------
   The announcement. When the ball stops, the number it fell on takes the whole
   table for a moment: the figure in the colour of its own pocket, what it
   paid, and the bets that paid it, one line at a time. It goes on the button,
   on the veil, on Escape, on the next spin, or on its own after seven seconds.
   (Javi, 07/09: "que salga el numero en plan popup chulo, has ganado xxx")
   --------------------------------------------------------------------------- */
/* display:grid would beat the [hidden] display:none, and an invisible veil
   over the felt swallows every click on the table */
.tblpop[hidden]{display:none}
.tblpop{position:absolute;inset:0;z-index:2;display:grid;place-items:center;
  padding:24px;background:rgba(0,0,0,.74);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  opacity:0;transition:opacity var(--dur-2) var(--ease)}
.tblpop.is-in{opacity:1}
.tblpop__in{position:relative;width:min(430px,100%);background:var(--ink);
  border:1px solid var(--line-d);padding:34px 30px 30px;
  display:grid;gap:16px;justify-items:center;text-align:center;
  opacity:0;transform:translateY(18px);
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease-io)}
.tblpop.is-in .tblpop__in{opacity:1;transform:none}
/* a gold rule draws itself across the head as the panel lands */
.tblpop__in::before{content:"";position:absolute;left:0;top:0;width:100%;height:2px;
  background:var(--gold);transform:scaleX(0);transform-origin:0 50%;
  transition:transform var(--dur-3) var(--ease-io) var(--stag)}
.tblpop.is-in .tblpop__in::before{transform:none}
.tblpop__k{color:var(--gold-hi)}
/* the figure, in the colour of the pocket it fell into */
.tblpop__n{margin:0}
.tblpop__n b{display:grid;place-items:center;width:118px;height:118px;
  font-size:58px;font-weight:700;line-height:1;color:var(--tx-d);
  border:1px solid var(--line-d);
  opacity:0;transform:scale(1.12);
  transition:opacity var(--dur-2) var(--ease) var(--stag),
    transform var(--dur-3) var(--ease-io) var(--stag)}
.tblpop.is-in .tblpop__n b{opacity:1;transform:none}
.tblpop--red .tblpop__n b{background:var(--felt-red);border-color:var(--felt-red-hi)}
.tblpop--black .tblpop__n b{background:#141c27;border-color:rgba(255,255,255,.20)}
.tblpop--zero .tblpop__n b{background:#12452f;border-color:#1c6746}
/* colour, even or odd, half: the way a board reads a number */
.tblpop__t{margin:-6px 0 0;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--tx-d);opacity:0;transform:translateY(8px);
  transition:opacity var(--dur-2) var(--ease) calc(var(--stag) * 2),
    transform var(--dur-2) var(--ease) calc(var(--stag) * 2)}
.tblpop__t:empty{display:none}
.tblpop.is-in .tblpop__t{opacity:.62;transform:none}
.tblpop__v{margin:0;font-size:clamp(20px,2.4vw,28px);line-height:1.12;
  opacity:0;transform:translateY(10px);
  transition:opacity var(--dur-3) var(--ease) calc(var(--stag) * 3),
    transform var(--dur-3) var(--ease) calc(var(--stag) * 3)}
.tblpop.is-in .tblpop__v{opacity:1;transform:none}
.tblpop.is-win .tblpop__v{color:var(--gold-hi)}
/* the breakdown: one row per bet that paid, each a step behind the last */
.tblpop__list{list-style:none;margin:0;padding:0;width:100%;display:grid}
.tblpop__list:empty{display:none}
.tblpop__list li{display:flex;justify-content:space-between;gap:16px;
  padding:9px 0;border-top:1px solid var(--line-d);font-size:14px;
  opacity:0;transform:translateY(8px);
  transition-property:opacity,transform;
  transition-duration:var(--dur-2),var(--dur-2);
  transition-timing-function:var(--ease);
  transition-delay:calc(var(--stag) * 4)}
.tblpop__list li:nth-child(1){transition-delay:calc(var(--stag) * 4)}
.tblpop__list li:nth-child(2){transition-delay:calc(var(--stag) * 5)}
.tblpop__list li:nth-child(n+3){transition-delay:calc(var(--stag) * 6)}
.tblpop.is-in .tblpop__list li{opacity:1;transform:none}
.tblpop__list b{color:var(--gold-hi)}
.tblpop__go{opacity:0;transform:translateY(8px);
  transition:opacity var(--dur-2) var(--ease) calc(var(--stag) * 4),
    transform var(--dur-2) var(--ease) calc(var(--stag) * 4)}
.tblpop.is-in .tblpop__go{opacity:1;transform:none}
@media (max-width:760px){
  .tblpop__in{padding:26px 20px 22px}
  .tblpop__n b{width:96px;height:96px;font-size:46px}
}
/* ---------------------------------------------------------------------------
   The money travels. A win flies from the figure that paid it to the balance
   and fades as it lands, and the meter counts up under it; a loss falls off
   the table instead. The balance stays gold until the next chip goes down.
   (Javi, 07/09: "si ganas se te va el dinero a balance, en plan animacion")
   --------------------------------------------------------------------------- */
.fly{position:fixed;z-index:600;pointer-events:none;
  transform:translate(-50%,-50%);opacity:1;
  font-size:clamp(22px,2.6vw,34px);font-weight:700;line-height:1;
  letter-spacing:-.02em;white-space:nowrap;
  transition-property:transform,opacity;
  transition-duration:var(--dur-4),var(--dur-2);
  transition-timing-function:var(--ease-io),var(--ease);
  transition-delay:0s,var(--dur-3)}
.fly--win{color:var(--gold-hi)}
.fly--lose{color:var(--felt-red-hi)}
.fly.is-go{opacity:0}
.tbl__bank b{transition:color var(--dur-2) var(--ease)}
.tbl__bank .is-up b{color:var(--gold-hi)}
.rm .fly{display:none}

/* reduced motion: the announcement is simply there */
.rm .tblpop,.rm .tblpop__in,.rm .tblpop__n b,.rm .tblpop__t,.rm .tblpop__v,
.rm .tblpop__list li,.rm .tblpop__go{opacity:1;transform:none}
.rm .tblpop__in::before{transform:none}
.tbl__cell--red{background:var(--felt-red)}
.tbl__cell--red:hover{background:var(--felt-red-hi)}
.tbl__cell--black{background:#0b1017}
.tbl__cell--black:hover{background:var(--w6)}
.tbl__cell--red[data-on-bet],.tbl__cell--black[data-on-bet]{background:var(--gold);color:var(--ink)}
/* the number that came up, in the colour it came up */
.tbl__red b{color:#e2565e}
.tbl__black b{color:var(--tx-d)}

/* THE NAV SHORTCUT -----------------------------------------------------------
   This was a bare 22px arrow after the language buttons, labelled only for
   screen readers. It links to the casino finder, which in a group of nearly a
   hundred rooms is one of the most useful things on the site, and nobody could
   tell by looking at it. It now says where it goes, in the same anatomy as
   every other button: label, hairline, arrow. Site wide, not just the home:
   the shortcut is in the header of all 23 pages. */
/* Half strength, like the ghost button in the hero: a solid currentColor
   hairline reads heavier than the 50% one it sits next to. */
.nav__go{gap:0;padding:0;min-height:34px;
  border:1px solid color-mix(in srgb, currentColor 50%, transparent)}
.nav__go__t{display:inline-flex;align-items:center;min-height:34px;
  padding:0 13px;font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:500;white-space:nowrap}
.nav__go svg{width:15px;height:15px;flex:none;
  box-sizing:content-box;padding:0 10px;
  border-left:1px solid color-mix(in srgb, currentColor 50%, transparent);align-self:stretch;
  height:auto;transition:transform var(--dur-2) var(--ease)}
.nav__go:hover{transform:none}
.nav__go:hover svg{transform:translateX(3px)}
@media (max-width:1180px){.nav__go__t{display:none}
  .nav__go{border:0}
  .nav__go svg{border-left:0;padding:0}}
@media (prefers-reduced-motion:reduce){
  .nav__go svg{transition:none}
  .nav__go:hover svg{transform:none}}

/* ===========================================================================
   THE HOME'S SHELL, EVERYWHERE
   The home was the only page loading editorial.css, so everything shaped there
   stopped at its own door: measured, its header stood 100px tall against 92 on
   the other 21 pages, and its buttons 42 against 38. What follows is the part
   of that work that belongs to the whole site rather than to the home's own
   sections, lifted out of the .editorial scope so every page gets it.
   =========================================================================== */

/* Header. 18 + 64 + 18 = 100, with the scroll progress as a hairline on the
   bottom edge instead of a border. */
.nav{padding:18px var(--edge)}
.nav .nav__in{min-height:64px;padding-bottom:18px;border-bottom:0;position:relative}
.nav .nav__prog{position:absolute;left:0;right:0;bottom:0;height:1px;opacity:1;transform:none;
  background:linear-gradient(to right,var(--gold-deep) calc(var(--sp,0) * 100%),var(--line-l) 0);
  transition:none}
.nav--on-dark .nav__in,.casino-active .nav .nav__in{border-bottom:0}
.nav--on-dark .nav__prog{background:linear-gradient(to right,var(--gold) calc(var(--sp,0) * 100%),var(--line-d) 0)}
@media(max-width:900px){.nav .nav__in{min-height:56px;padding-bottom:14px}.nav{padding:14px var(--edge)}}

/* Buttons. One anatomy on every page: a gold body, the arrow inside it,
   divided by a hairline. The quieter twin keeps its outline. */
/* Every button that carries an arrow, not just the ones in section headers:
   measured, about, markets and online-gaming led with a different .btn and
   were still sitting at 38px with a grey body. */
.btn:not(.btn--ghost):has(> b){min-height:42px;justify-content:space-between}
.btn:not(.btn--ghost):has(> b) > span{
  background:var(--gold);color:#16130e;border-bottom:0;
  padding:0 18px;margin-right:0;min-height:42px;display:inline-flex;align-items:center}
.btn:not(.btn--ghost):has(> b) > b{
  background:var(--gold);color:#16130e;
  border-left:1px solid rgba(0,0,0,.18);min-height:42px;width:42px}
/* The dark bands set their own chip on .btn > span at the same weight. */
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .btn:not(.btn--ghost):has(> b) > span{
  background:var(--gold);color:#16130e}
#wheel-spin.btn,.foot .btn:not(.btn--ghost){padding:0;border:0;background:transparent}
/* Nothing changes colour on hover: the arrow travels instead. */
.btn>b svg{transition:transform var(--dur-2) var(--ease)}
.btn:is(:hover,:focus-visible)>b svg{transform:translateX(4px)}
@media (prefers-reduced-motion:reduce){
  .btn>b svg{transition:none}
  .btn:is(:hover,:focus-visible)>b svg{transform:none}
}

/* THE PACE ------------------------------------------------------------------
   The site's timing was built for a mechanism: --ease is a quartic out and the
   arrivals ran in 560 to 900ms with 80ms between siblings, which lands each
   block with a small stop at the end. The brief is the opposite of a mechanism.

   Same system, slower and softer: an exponential out, which covers most of the
   distance early and then settles for a long time instead of arriving and
   stopping. The travel shortens as the duration grows, so nothing looks like
   it is being thrown into place. Site wide: the rhythm is not a property of one page. */
/* :root, not html: the original token block up top is :root, which outranks a
   type selector, so an html{} override silently did nothing. */
:root{
  --ease:cubic-bezier(.16,1,.3,1);
  --dur-2:420ms;
  --dur-3:820ms;
  --dur-4:1150ms;
  --dur-5:1400ms;
  --stag:105ms;
  --rv-y:40px;
  --rv-blur:9px;
}
[data-arrive]{--arrive-y:30px;
  transition-duration:var(--dur-4);transition-timing-function:var(--ease)}
.directory__row.rv{--rv-y:26px}
.collection__item.rv{--rv-y:22px}
.chipband__brands li{transition-duration:var(--dur-3)}

@media (prefers-reduced-motion:reduce){
  :root{--dur-2:0ms;--dur-3:0ms;--dur-4:0ms;--dur-5:0ms;--stag:0ms}
}

/* CARDS ----------------------------------------------------------------------
   Measured on brands.html: four cards 345x627 with 170 to 191px of dead black
   under the copy, separated by a 1px line, and the country links rendered as
   solid grey chips stacked in the middle of that emptiness.

   Three changes, no new vocabulary: the links drop to the foot of the card so
   the hole closes up, they become hairline tags instead of filled chips, and
   the grid gets air between cards instead of a hairline. */
.card .grow{margin-top:auto;display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end}
.card .grow .btn--ghost{min-height:0}
.card .grow .btn--ghost > span{
  background:transparent;
  border:1px solid color-mix(in srgb, currentColor 28%, transparent);
  min-height:30px;padding:0 13px;font-size:10px;letter-spacing:.1em;
  transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease)}
.card .grow .btn--ghost:is(:hover,:focus-visible) > span{
  border-color:color-mix(in srgb, currentColor 65%, transparent);
  background:color-mix(in srgb, currentColor 8%, transparent)}
:is(.band--dark,.band--wash,.band--wash-up,.hero,.foot,.dcard,.tbl) .card .grow .btn--ghost > span{
  background:transparent}

/* Air between the cards. The grid paints its own background and the 1px gap is
   what used to show of it, which is how the hairline between cards was drawn.
   Widening the gap without clearing that background turned the hairline into a
   grey band the width of the gap. The gap is the separation now, so the grid
   has nothing left to paint. */
.cards{gap:clamp(10px,1.1vw,18px);background:transparent}

/* The card on a dark band was pure black, which on a near black band reads as
   a hole rather than a surface. It lifts just off the ground it sits on, stays
   opaque, and its hover lifts once more in the same direction. */
:is(.band--dark) .card{background:#0a0f16}
:is(.band--dark) .card:hover{background:#111823}



/* OPEN ROLES -----------------------------------------------------------------
   One row per published vacancy, rendered from the feed the backoffice writes.
   The row is the site's own rowlist with a tag rail: nothing new to learn, and
   it sits beside the hiring teams list above it without arguing with it. */
.openings .opening{display:grid;grid-template-columns:minmax(0,1fr) auto auto;
  align-items:center;gap:clamp(16px,2.4vw,40px)}
.opening__meta{display:block;color:var(--tx-l-2);margin-bottom:6px}
:is(.band--dark,.band--wash,.band--wash-up,.foot) .opening__meta{color:var(--tx-d-2)}
.opening__title{margin:0}
.opening__tags{display:flex;flex-wrap:wrap;gap:6px;list-style:none;margin:0;padding:0}
.opening__tag{font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  padding:5px 10px;border:1px solid color-mix(in srgb, currentColor 22%, transparent);
  color:var(--tx-l-2);white-space:nowrap;line-height:1.4}
.opening__tags{justify-content:flex-end;max-width:none}
:is(.band--dark,.band--wash,.band--wash-up,.foot) .opening__tag{color:var(--tx-d-2)}
/* The one tag that is not a category but a signal, so it carries the accent. */
.opening__tag--new{border-color:var(--gold);color:var(--gold-deep)}
:is(.band--dark,.band--wash,.band--wash-up,.foot) .opening__tag--new{color:var(--gold)}
.opening__cta{justify-self:end}
@media (max-width:760px){
  .openings .opening{grid-template-columns:1fr;gap:14px}
  .opening__cta{justify-self:start}
}

/* THE TOMBOLA BOARD ----------------------------------------------------------
   One panel per market: the month's pot, what it has already paid, and the
   calendar of draws with what each one pays.

   Two things this gets right that the first attempt did not. It takes the whole
   row instead of the middle column of a trio, where two markets side by side
   broke every label onto three lines. And it is a light surface with a rule
   around it, not a black box dropped on a light page: the page is paper, so the
   board is paper. */
.tbo{grid-column:1 / -1;display:grid;gap:clamp(16px,1.6vw,24px);
  grid-template-columns:repeat(auto-fit,minmax(320px,1fr));margin-top:clamp(28px,3vw,48px)}
.tbo__market{background:var(--paper);color:var(--tx-l);
  border:1px solid var(--line-l);
  padding:clamp(24px,2.6vw,38px);display:grid;gap:clamp(18px,1.8vw,26px);align-content:start}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__market{
  background:#0a0f16;color:var(--tx-d);border-color:var(--line-d)}

/* Market and month, on one line, over a rule. */
.tbo__head{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  border-bottom:1px solid var(--line-l);padding-bottom:14px}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__head{border-color:var(--line-d)}
.tbo__where{color:var(--gold-deep)}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__where{color:var(--gold)}
.tbo__month{margin:0;font-size:12px;letter-spacing:.06em;color:var(--tx-l-2);white-space:nowrap}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__month{color:var(--tx-d-2)}

.tbo__totals{display:grid;grid-template-columns:1fr 1fr;gap:clamp(16px,1.8vw,28px)}
.tbo__total{display:grid;gap:8px;align-content:start}
.tbo__figure{font-size:clamp(30px,3.2vw,44px);line-height:1;letter-spacing:-.04em;
  font-variant-numeric:tabular-nums}
/* Waiting is a state, not a headline: label size, with the accent as a marker. */
.tbo__wait{font-size:13px;letter-spacing:.01em;color:var(--tx-l-2);
  display:inline-flex;align-items:center;gap:8px}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__wait{color:var(--tx-d-2)}
.tbo__wait::before{content:'';width:6px;height:6px;border-radius:50%;
  background:var(--gold);flex:none}

.tbo__cal{display:grid;gap:12px}
.tbo__draws{list-style:none;margin:0;padding:0;display:grid}
.tbo__draw{display:flex;justify-content:space-between;align-items:baseline;gap:20px;
  padding:15px 0;border-top:1px solid var(--line-l);flex-wrap:wrap;row-gap:4px}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__draw{border-color:var(--line-d)}
.tbo__draw-name{margin:0;font-size:16px;font-weight:500}
.tbo__draw-when{margin:4px 0 0;font-size:12px;color:var(--tx-l-2)}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__draw-when{color:var(--tx-d-2)}
.tbo__draw-prize{text-align:right;margin-left:auto}
.tbo__draw-prize .tbo__figure{font-size:clamp(17px,1.6vw,21px)}
/* The month's headline draw carries the accent. The others do not, or it stops
   meaning anything. */
.tbo__draw--feature .tbo__draw-name{color:var(--gold-deep)}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__draw--feature .tbo__draw-name{color:var(--gold)}

.tbo__pending,.tbo__boot{margin:0;font-size:13px;color:var(--tx-l-2)}
:is(.band--dark,.band--wash,.band--wash-up) :is(.tbo__pending,.tbo__boot){color:var(--tx-d-2)}
.tbo__venue{margin:0;font-size:12px;color:var(--tx-l-2);
  border-top:1px solid var(--line-l);padding-top:14px}
:is(.band--dark,.band--wash,.band--wash-up) .tbo__venue{color:var(--tx-d-2);border-color:var(--line-d)}
.tbo__venue .kick{display:block;margin-bottom:4px}
@media (max-width:560px){.tbo__totals{grid-template-columns:1fr}}


/* ===========================================================================
   THE GREY SEAM, AND THE BOXES THAT FLOATED
   Javi, 19/09: "las cajas estas siguen con zonas grises", "sigue saliendo
   cajas negras feas", "esta parte volando raro".
   Three separate causes, measured on the rendered page rather than guessed.
   =========================================================================== */

/* 1. THE GREY SEAM.
   .js .cards.rv paints --cards-line as a wipe: the grid's own background
   grows 0% -> 100% height so the hairline between cards draws itself in.
   That was right while the gap WAS the hairline, at 1px. The gap is 16px
   now, so the same wipe paints a 16px grey band down every seam, on every
   page that uses a card grid. The cards already stagger in one by one, so
   the grid has nothing left of its own to animate. */
.js .cards.rv,
.js .cards.rv.is-in,
.js.rm .cards.rv{background-image:none}

/* 2. THE BLACK BOXES.
   .band--wash runs paper -> ink and .band--wash-up runs ink -> paper, so how
   dark the ground is under a card depends on how far down the band the card
   sits. One fixed dark fill cannot answer both ends: at the pale end #0a0f16
   sat on #f7f6f2 and read as a hole punched in the page.
   Dropping the fill altogether was the wrong answer and measured 1.28:1 on
   real pixels: sharp.js reads a card's OWN background to choose its ink ("a
   card paints its own opaque ground and does not follow the ramp"), so a
   transparent card reads as luminance 0, takes white text, and then lands on
   #c9d8ea.
   So the card keeps an opaque ground, and the ground follows the ramp.
   sharp.js measures the gradient under each card and writes --card-bg: the
   card sits one step clear of its own ground, lighter on light and deeper on
   dark, which is the separation the rest of the site already uses. */
:is(.band--wash,.band--wash-up) .card{
  background:var(--card-bg,var(--paper));
  box-shadow:inset 0 0 0 1px color-mix(in srgb,currentColor 12%,transparent)}
:is(.band--wash,.band--wash-up) .card:hover{
  background:var(--card-bg-hi,var(--card-bg,var(--ivory)))}
:is(.band--wash,.band--wash-up) .card:has(.card__media){box-shadow:none}

/* 3. THE BOXES THAT FLOATED.
   .rail li was held open to 206px whatever it held, and holds 22ch of text
   in a 533px column: 39% of the width inked and most of the height empty.
   The height was there to line three rails up, and a grid row already does
   that. The measure widens so a line of it fills the column it was given. */
.rail li{min-height:0;padding:24px 26px 28px}
.rail li .h5{max-width:34ch}

/* .rows li reserved a third column for the provenance badge. With the badge
   gone the row would keep an empty column and the sentence would stay
   pinned to the left half of the page. Two columns, and the sentence takes
   the width. */
/* Scoped to the desktop grid on purpose. Unscoped, this rule sat after the
   @media (max-width:900px) block that stacks a row on a phone, so it won the
   cascade at every width and pinned the sentence into whatever was left beside
   a 96px number column: measured on a 390px phone, markets.html was giving its
   text 37px, about four characters a line. The row still stacks below 900. */
@media (min-width:901px){
  .rows li{grid-template-columns:96px minmax(0,1fr)}
  .rows li > div:nth-child(2){max-width:72ch}
  .rows li:has(> div:nth-child(3)){grid-template-columns:96px minmax(0,1fr) auto}
}

/* THE GROWTH LINE, AS A ROW LIST -------------------------------------------
   Javi, 20/09: "por que quitaste lo del raton bajando y ver como pasan los
   años" — and then "esto lo quiero mas estilo como la home La misma acogida
   en cada sala".
   It had been a pinned horizontal scrub: six full viewport heights, the page
   locked, the line dragged sideways under it. Un-pinning it to a native
   sideways scroller was worse, not better: the years clipped at both edges
   and a mouse had to drag. So it becomes the band it should always have been
   -- the same .rows--dim register as "The same welcome in every room", where
   scrolling DOWN lights one row at a time. The years still pass under the
   reader; they pass the way the rest of this site passes.
   The only thing this needs that .rows does not already give it is room for
   the year, which is display type and will not sit in a 96px number column.
   Scoped to the desktop grid: below 900 the row stacks and the year leads it. */
@media (min-width:901px){
  .rows--years li{grid-template-columns:clamp(112px,11vw,168px) minmax(0,1fr)}
  .rows--years li:has(> div:nth-child(3)){
    grid-template-columns:clamp(112px,11vw,168px) minmax(0,1fr) auto}
}
.rows--years .tl__y{font-size:clamp(34px,3.4vw,52px);line-height:.92;margin:0}
.rows--years li > div:first-child{align-self:start}

/* THE FOUR PLATFORMS ---------------------------------------------------------
   Javi, 21/09: "no quiero ninguna linea ni entre la foto arriba ni la
   animacion con una linea, eso es feo. El see the site se ve pegado. Hay un
   trazo negro, eso quitar. Algo mas limpio mas top."
   Four goes. What each one added and this one takes back out:
     · the grey slab of words under the picture          -> gone
     · the boxed ghost button                            -> gone
     · four gold corner brackets                         -> gone
     · a gold seam between picture and type              -> gone
     · the gold rule that drew itself under the name     -> gone
     · a separate ink panel, whose top edge was the black stroke he saw
                                                         -> gone
   What is left is one photograph, one gradient with no edge anywhere in it,
   and the words standing on the dark end of it with room on every side. The
   only thing that moves on hover is the picture and the arrow.
   -------------------------------------------------------------------------- */
body.editorial .cards .card.card--plat,
.card--plat{position:relative;isolation:isolate;overflow:hidden;
  aspect-ratio:3/4;padding:0;gap:0;border:0;
  display:flex;flex-direction:column;justify-content:flex-end;
  background:#06090f}

body.editorial .cards .card.card--plat .card__media,
.card--plat .card__media{position:absolute;inset:0;margin:0;aspect-ratio:auto;z-index:0}
.card--plat .card__media .ph{width:100%;height:100%;object-fit:cover;
  filter:grayscale(.06) brightness(.94) contrast(1.03);
  transition:transform var(--dur-5) var(--ease),filter var(--dur-3) var(--ease)}
.card--plat:hover .card__media .ph,
.card--plat:focus-visible .card__media .ph{transform:scale(1.04);
  filter:grayscale(0) brightness(1.02) contrast(1.02)}

/* ONE gradient, over the whole card, with no stop that can read as an edge:
   it starts at nothing, and every step after it is small. A panel with a top
   edge is what drew the black stroke. */
.card--plat::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,
    rgba(6,9,15,0) 0%, rgba(6,9,15,.04) 26%, rgba(6,9,15,.16) 40%,
    rgba(6,9,15,.38) 52%, rgba(6,9,15,.62) 64%, rgba(6,9,15,.82) 76%,
    rgba(6,9,15,.93) 88%, rgba(6,9,15,.97) 100%)}

/* the mark, in the light half */
.card--plat .card__media img.card__mark{display:block;position:absolute;left:50%;top:26%;
  transform:translate(-50%,-50%);z-index:2;width:clamp(116px,11.5vw,168px);height:auto;
  filter:brightness(0) invert(1);opacity:.95;pointer-events:none;
  transition:transform var(--dur-3) var(--ease),opacity var(--dur-2) var(--ease)}
/* a mark supplied in its own colours keeps them: the Gana777 wordmark is gold
   and white already, and flattening it to white throws the brand away */
.card--plat .card__media img.card__mark--asis{filter:none;opacity:1;
  width:clamp(152px,15vw,218px)}
.card--plat .card__media img.card__mark--word{width:clamp(150px,15vw,224px)}
.card--plat:hover .card__media img.card__mark,
.card--plat:focus-visible .card__media img.card__mark{
  transform:translate(-50%,-50%) scale(1.03);opacity:1}

/* the words */
.card--plat > :not(.card__media){position:relative;z-index:2;color:var(--tx-d);
  padding-inline:clamp(22px,2vw,30px)}
.card--plat > .kick{padding-top:0;margin:0;opacity:.66;letter-spacing:.16em;font-size:10px}
.card--plat > h3{margin:10px 0 0;font-size:clamp(23px,2.05vw,31px);
  letter-spacing:-.022em;line-height:1.06}
.card--plat > p{margin:11px 0 0;max-width:32ch;font-size:13.5px;line-height:1.52;
  color:rgba(255,255,255,.74)}

/* the call to action, with room under it */
/* padding-block only: a flat `padding:0` here would wipe the padding-inline
   the rule above gives every child, and the label would start on the card's
   own left edge while the copy above it kept its margin. That is the
   "see the site pegado a la caja". */
.card--plat > .btn,.card--plat > .btn--ghost{min-height:0;background:none;border:0;
  padding-block:0;margin:22px 0 clamp(28px,2.6vw,38px);align-self:flex-start;
  font-family:"Neue Helvena",Helvetica,Arial,sans-serif;font-stretch:82%;
  font-size:var(--t-micro);font-weight:500;letter-spacing:.1em;text-transform:uppercase;
  color:var(--tx-d);display:inline-flex;align-items:center;gap:12px}
.card--plat > .btn > span{background:none;padding:0;min-height:0}
.card--plat > .btn::after{content:"";width:17px;height:10px;flex:none;
  background:currentColor;transition:transform var(--dur-2) var(--ease);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 14'%3E%3Cpath d='M0 7h20M14 1l6 6-6 6' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3C/svg%3E") no-repeat center/contain;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 14'%3E%3Cpath d='M0 7h20M14 1l6 6-6 6' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3C/svg%3E") no-repeat center/contain}
.card--plat:hover > .btn::after{transform:translateX(6px)}
/* the runtime injects its own arrow on a link card; this one has its own */
.card--plat .card__go{display:none}
/* and the site-wide card hover draws a gold rule under the name: not here */
.js .card--plat h3::after{display:none}

@media (max-width:1100px){.cards:has(.card--plat){grid-template-columns:repeat(2,1fr)}}
@media (max-width:640px){.cards:has(.card--plat){grid-template-columns:1fr}
  .card--plat{aspect-ratio:4/5}}

.card--plat .card__media img.card__mark--asis{filter:none;opacity:1}
.card--plat .card__media img.card__mark--asis{width:clamp(148px,14vw,208px)}

/* the platform cards answer the hand the same way as the casino cards */
.js .card--plat h3{position:relative;width:fit-content;max-width:100%;
  transition:transform var(--dur-2) var(--ease)}
.js .card--plat h3::after{content:"";position:absolute;left:0;right:0;bottom:-6px;height:1px;
  background:var(--gold);transform:scaleX(0);transform-origin:0 50%;
  transition:transform var(--dur-3) var(--ease)}
.card--plat:hover h3::after{transform:scaleX(1)}
.card--plat:hover h3{transform:translateY(-4px)}

/* THE RAMP CARD, UNDER THE EDITORIAL SKIN -----------------------------------
   20/09: the skin went site-wide, and editorial.css carries
   `body.editorial .card{background:transparent}` at (0,2,1), which out-ranks
   the (0,2,0) rule above and loads after it. The card went transparent again,
   its ink stayed white, and "Register at the desk" landed on the pale end of
   the wash at 4.43:1 -- the exact defect that rule exists to prevent.
   Same fix, stated loud enough to survive the skin. */
body.editorial :is(.band--wash,.band--wash-up) .card{
  background:var(--card-bg,var(--paper))}
body.editorial :is(.band--wash,.band--wash-up) .card:hover{
  background:var(--card-bg-hi,var(--card-bg,var(--ivory)))}
body.editorial :is(.band--dark) .card{background:#0a0f16}
body.editorial :is(.band--dark) .card:hover{background:#111823}

/* THE PLATFORM CARD'S OWN ARRIVAL -------------------------------------------
   Javi, 21/09: "pon otra animacion mas bonita mas top", pointing at a frame
   of the reveal in flight.
   The site's photo-unveil opens a picture like a slit: [data-unmask] goes from
   clip-path:inset(24% 0 24% 0) to inset(0). On a card where the photograph is
   only part of the composition that reads as a reveal. On these cards the
   photograph IS the card, so the slit shows the card's own black through the
   top and bottom quarters for the length of the animation -- the black stroke
   and the "linea" he kept seeing.
   These cards settle instead of opening: the picture arrives a little large
   and a little soft and comes to rest, the words rise a short way behind it,
   and nothing is ever clipped. Same clock as the rest of the grid, so the four
   still land one after another.
   -------------------------------------------------------------------------- */
.js .card--plat .card__media[data-unmask]{clip-path:none}
/* .ph, never `> img`: the mark is a direct child of .card__media too, and an
   unscoped `> img` gave it inset:0 and width:100% -- the wordmark filled the
   whole card. */
.js .card--plat .card__media[data-unmask][data-grow] > img.ph{
  position:absolute;inset:0;width:100%;height:100%;top:0;
  scale:1.12;filter:blur(9px) grayscale(.06) brightness(.94) contrast(1.03);
  transition:scale var(--dur-5) var(--ease) calc(var(--i,0) * var(--stag)),
             filter var(--dur-4) var(--ease) calc(var(--i,0) * var(--stag))}
.js .card--plat .card__media[data-unmask][data-grow].is-in > img.ph{
  scale:1;filter:blur(0) grayscale(.06) brightness(.94) contrast(1.03)}
/* the hover still belongs to the hover, and must out-rank the arrival's rest
   state or the picture would never lean in again */
.js .card--plat:hover .card__media[data-unmask][data-grow].is-in > img.ph,
.js .card--plat:focus-visible .card__media[data-unmask][data-grow].is-in > img.ph{
  scale:1.05;filter:blur(0) grayscale(0) brightness(1.02) contrast(1.02)}

/* the words come up behind the picture, a beat later */
.js .card--plat > :not(.card__media){opacity:0;transform:translateY(16px);
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-4) var(--ease)}
.js .card--plat.is-in > :not(.card__media){opacity:1;transform:none}
.js .card--plat.is-in > .kick{transition-delay:calc(var(--i,0) * var(--stag) + 80ms)}
.js .card--plat.is-in > h3{transition-delay:calc(var(--i,0) * var(--stag) + 140ms)}
.js .card--plat.is-in > p{transition-delay:calc(var(--i,0) * var(--stag) + 200ms)}
.js .card--plat.is-in > .btn{transition-delay:calc(var(--i,0) * var(--stag) + 260ms)}

@media (prefers-reduced-motion:reduce){
  .js .card--plat .card__media[data-unmask][data-grow] > img.ph{scale:1;filter:none}
  .js .card--plat > :not(.card__media){opacity:1;transform:none}
}

/* THE LICENCE PANEL, INVERTED ------------------------------------------------
   Javi, 21/09: "logo no se ve loteria", then "ponerlo todo a la inversa".
   The regulator's wordmark is #313A83 and it is drawn for paper: on the data
   panel's #0a0f16 it measures 2.29:1 and is simply not there. A white plate
   behind it worked but read as a sticker on a dark card.
   So the card turns over. Paper ground, ink type, the site's own light hairline
   between rows, and the seal sits on it in its own colours at 8.41:1 -- no
   plate, no invert, nothing done to the mark at all. Its `data-on` is stamped
   light by sharp.js from the ground it now paints, so every child follows. */
.dcard--lit{background:var(--paper);color:var(--tx-l)}
.dcard--lit .dcard__row + .dcard__row{border-top-color:var(--line-l)}
.dcard--lit .lic-seal{display:block;width:clamp(124px,12vw,164px);height:auto;opacity:1}
