/* ==========================================================================
   REMA Conference 2026 — "From the Ground Up"
   Built from "REMA Landing Page.svg" / .pdf (1512 × 18001), the speaker modal
   export (1240 × 690) and the motif kit in Venco/motifs/.
   Every colour and dimension below is sampled from those files.
   ========================================================================== */

/* ---------- 1. FONTS ------------------------------------------------------ */
@font-face { font-family:'Nohemi'; src:url('../fonts/Nohemi-Light.woff2')     format('woff2'); font-weight:300; font-style:normal; font-display:swap; }
@font-face { font-family:'Nohemi'; src:url('../fonts/Nohemi-Regular.woff2')   format('woff2'); font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:'Nohemi'; src:url('../fonts/Nohemi-Medium.woff2')    format('woff2'); font-weight:500; font-style:normal; font-display:swap; }
@font-face { font-family:'Nohemi'; src:url('../fonts/Nohemi-SemiBold.woff2')  format('woff2'); font-weight:600; font-style:normal; font-display:swap; }
@font-face { font-family:'Nohemi'; src:url('../fonts/Nohemi-Bold.woff2')      format('woff2'); font-weight:700; font-style:normal; font-display:swap; }
@font-face { font-family:'Nohemi'; src:url('../fonts/Nohemi-ExtraBold.woff2') format('woff2'); font-weight:800; font-style:normal; font-display:swap; }
@font-face { font-family:'DM Sans'; src:url('../fonts/DMSans-Variable.woff2') format('woff2-variations'); font-weight:100 1000; font-style:normal; font-display:swap; }

/* ---------- 2. TOKENS ----------------------------------------------------- */
:root{
  /* Grounds — sampled from the export's section rects */
  --ink:        #03211E;   /* audience, sponsors, venue, closing, footer  */
  --ink-2:      #07211E;   /* hero, seal slab, handover                   */
  --ink-3:      #11302D;   /* display type on light; card body 01         */
  --ink-4:      #0C3531;   /* ticket panel                                */
  --ink-5:      #0C2926;   /* stats bar                                   */
  --ink-6:      #051F1D;   /* modal close button                          */

  /* Greens */
  --forest:     #017242;   /* speaker cards, Keynotes card, active filter */
  --forest-2:   #067848;   /* handover band 01                            */
  --grass:      #00A85A;   /* CTAs, motif strokes, headings on dark       */

  /* Limes + yellows */
  --lime:       #C1F16D;   /* hero seal, display accents, Workshops card  */
  --lime-m:     #CBF07F;   /* motif lime, modal role, handover tile 01    */
  --lime-3:     #ECFFD3;   /* register ground                            */
  --yellow:     #FFF215;   /* Panels card, speaker + modal tags           */
  --gold:       #FFCC2A;   /* motif gold                                  */
  --olive:      #867F0E;   /* handover tile 02                            */
  --olive-2:    #5B5718;   /* handover body 02                            */

  /* Papers */
  --paper:      #F6F9F3;   /* experience, schedule                        */
  --paper-2:    #FAFEF5;   /* form panel                                  */
  --paper-lime: #F5FFE7;   /* about                                       */
  --white:      #FFFFFF;

  /* Lines + muted */
  --line:       #E7EBE2;
  --line-2:     #E0E5DB;
  --line-f:     #E7EAE2;   /* speaker filter borders                      */
  --muted:      #818787;
  --muted-3:    #5B9890;   /* venue map link, on-dark muted               */

  /* Type */
  --display: 'Nohemi', 'Arial Narrow', sans-serif;
  --body:    'DM Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Type scale, measured off the 1512-wide frame ------------------------- */
  --t-h1:  clamp(2.9rem, 6.9vw, 6.5rem);    /* 104 — hero, closing        */
  --t-h2:  clamp(2.2rem, 4.8vw, 4.5rem);    /*  72 — "where it begins"    */
  --t-h3:  clamp(2rem,   3.7vw, 3.5rem);    /*  56 — seal slab            */
  --t-h4:  clamp(1.9rem, 3.45vw, 3.25rem);  /*  52 — section headings     */
  --t-h5:  clamp(1.5rem, 2.6vw, 2.3rem);    /*  37 — ticket, sub-heads    */
  --t-body: 1.0625rem;                      /*  17 — copy                 */

  /* Layout — 1512 frame on a 100px gutter */
  --maxw: 1312px;
  --gutter: clamp(20px, 6.6vw, 100px);

  --ease: cubic-bezier(.22,.61,.36,1);
  --ease-soft: cubic-bezier(.4,.08,.2,1);   /* gentle in and out -- photo hovers, header tint */
  --ease-out: cubic-bezier(.16,1,.3,1);
  --header-h: 70px;
}

/* ---------- 3. RESET ------------------------------------------------------ */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }
body{
  margin:0; background:var(--ink-2); color:var(--ink-3);
  font-family:var(--body); font-size:var(--t-body); line-height:1.6;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  /* clip, not hidden: `overflow-x:hidden` makes body a scroll container and
     kills `position:sticky` for everything inside it (the schedule aside).  */
  overflow-x:clip;
}
img,svg,video{ display:block; max-width:100%; }
img{ height:auto; }
/* The line above beats the UA sheet's [hidden]{display:none}, which is why the
   lightbox's poster-bearing <video hidden> was painting a second picture under
   the photo. Anything carrying the attribute stays out of the layout. */
[hidden]{ display:none !important; }
button,input,select,textarea{ font:inherit; color:inherit; }
button{ background:none; border:0; cursor:pointer; }
a{ color:inherit; text-decoration:none; }
ul{ margin:0; padding:0; list-style:none; }
h1,h2,h3,h4,p,figure,dl,dd,blockquote{ margin:0; }
:focus-visible{ outline:3px solid var(--grass); outline-offset:3px; border-radius:2px; }
.on-dark :focus-visible{ outline-color:var(--lime); }
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* ---------- 4. PRIMITIVES ------------------------------------------------- */
.wrap{ width:100%; max-width:calc(var(--maxw) + var(--gutter)*2); margin-inline:auto; padding-inline:var(--gutter); }

.display{ font-family:var(--display); font-weight:700; letter-spacing:-.018em; line-height:1.06; }
.caps{ text-transform:uppercase; line-height:.95; letter-spacing:-.02em; }
.h1{ font-size:var(--t-h1); } .h2{ font-size:var(--t-h2); }
.h3{ font-size:var(--t-h3); } .h4{ font-size:var(--t-h4); }
.h5{ font-size:var(--t-h5); }

.eyebrow{
  font-size:.8125rem; font-weight:500; letter-spacing:.3em;
  text-transform:uppercase; color:var(--muted);
}
.eyebrow--dark{ color:rgba(255,255,255,.45); }
.eyebrow--lime{ color:var(--lime-m); }
.lede{ font-size:var(--t-body); line-height:1.75; }
/* Responsive break: hidden below 900px, where the space before it carries
   the word gap instead. */
.brk{ display:none; }
@media (min-width:900px){ .brk{ display:inline; } }

/* Dark grounds carry the hero's dot grid from the export (REMA Landing Page.pdf):
   a 2px dot every 33px, first centre at (13, 12.5). The export's #0E423C read
   too strong against the copy at full size, so the dot now sits halfway between
   the ground (#07211E) and that value -- same lattice, half the contrast.
   Held in custom properties because the handover stage and the speaker modal
   paint the same grid on their own boxes. */
:root{
  --dot: #0B322D;
  --dot-grid: radial-gradient(circle, var(--dot) .6px, transparent 1.15px);
  --dot-size: 33px 33px;
  --dot-pos: -3px -4px;
}
/* The selector is doubled so the sections' own `background:` shorthands, which
   come later in the sheet and reset background-image, can't switch it off. */
.on-dark.dotted{
  background-image:var(--dot-grid);
  background-size:var(--dot-size);
  background-position:var(--dot-pos);
}

/* Buttons ----------------------------------------------------------------- */
.btn{
  --btn-bg:var(--grass); --btn-fg:#fff; --btn-bd:transparent;
  display:inline-flex; align-items:center; justify-content:center; gap:.6rem;
  padding:.9rem 1.7rem; min-height:52px;
  background:var(--btn-bg); color:var(--btn-fg); border:1px solid var(--btn-bd);
  font-weight:600; font-size:.9375rem; line-height:1;
  transition:transform .18s var(--ease), background-color .2s, color .2s, border-color .2s;
}
.btn:hover{ transform:translateY(-2px); --btn-bg:#00934e; }
.btn:active{ transform:translateY(0); }
.btn--lime{ --btn-bg:var(--lime); --btn-fg:var(--ink-3); }
/* "Register Now" is lime #C1F16D in the export, in the bar and the hero. */
.header .btn{ --btn-bg:var(--lime); --btn-fg:var(--ink-3); padding-block:.55rem; min-height:40px; }   /* slimmer than the page buttons */
.header .btn:hover{ --btn-bg:#b4ea54; }
.btn--lime:hover{ --btn-bg:#b4ea54; }
.btn--ghost{ --btn-bg:transparent; --btn-fg:var(--ink-3); --btn-bd:rgba(17,48,45,.35); }
.btn--ghost:hover{ --btn-bg:var(--ink-3); --btn-fg:#fff; --btn-bd:var(--ink-3); }
/* #284D49 is the mock's own stroke. The class is used in exactly two places
   -- the hero and the closing section above the footer -- so this is scoped
   to them without a selector for each. Hover still fills white. */
.btn--onDark{ --btn-bg:transparent; --btn-fg:#fff; --btn-bd:#284D49; }
.btn--onDark:hover{ --btn-bg:#fff; --btn-fg:var(--ink); --btn-bd:#fff; }
.btn--block{ width:100%; }

/* ---------- 5. MOTIFS ----------------------------------------------------- */
/* Icon strip — the supplied "horizontal Motif.svg" used verbatim (1512 x 186).
   Its motif cycle is 755.8px and the 1512 tile holds exactly two of them, so
   repeating the tile and translating one cycle loops seamlessly.        */
/* The tile is exactly one motif cycle (755.8 x 186) on a uniform 7.08px gap,
   so repeat-x tiles it evenly and one cycle of travel loops seamlessly. */
.strip{
  --strip-h:clamp(112px,12.3vw,186px);
  --strip-cycle:calc(var(--strip-h) * 755.8 / 186);
  position:relative; overflow:hidden; background:var(--ink);
  height:var(--strip-h);
}
.strip::before{
  content:''; position:absolute; top:0; bottom:0; left:0;
  right:calc(-1 * var(--strip-cycle));
  background:url('../img/patterns/horizontal-motif.svg') repeat-x left center / auto 100%;
  animation:strip-slide 44s linear infinite;
}
@keyframes strip-slide{ to{ transform:translateX(calc(-1 * var(--strip-cycle))); } }
.strip:hover::before{ animation-play-state:paused; }
@media (prefers-reduced-motion:reduce){ .strip::before{ animation:none; } }

/* The circular seal, drawn so it inherits the page font */
/* The supplied logo is a complete lockup (ring + icon), so it stays upright. */
/* Badge: two stacked layers so the arc lettering turns while the rules and
   the REMA mark inside hold still. */
.seal{ position:relative; display:block; }
.seal img{ display:block; width:100%; height:auto; }
.seal__core{ position:absolute; inset:0; }
.seal__ring{ animation:seal-spin 30s linear infinite; }
@keyframes seal-spin{ to{ transform:rotate(1turn); } }
@media (prefers-reduced-motion:reduce){ .seal__ring{ animation:none; } }

/* ---------- 6. HEADER ----------------------------------------------------- */
.header{
  position:fixed; inset:0 0 auto 0; z-index:88; height:var(--header-h);
  display:flex; align-items:center;
  /* Over the hero the bar is invisible -- the dark ground and its dot grid run
     straight through it. The tinted, blurred bar fades in only once content
     starts passing underneath (.is-scrolled), which is also when the nav and
     the small logo arrive, so the whole header resolves as one move. */
  background:transparent; backdrop-filter:none; -webkit-backdrop-filter:none;
  border-bottom:1px solid transparent;
  transition:background-color .5s var(--ease-soft), backdrop-filter .5s var(--ease-soft),
             -webkit-backdrop-filter .5s var(--ease-soft), border-color .32s, transform .38s var(--ease);
}
.header.is-scrolled{
  background:rgba(7,33,30,.82);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
}
.header__inner{ display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:1.25rem; width:100%; }  /* nav dead-centre, as in the export, whatever the logo width */
.header__inner > .btn{ justify-self:end; }
/* Three marks share one slot, every one of them absolutely placed so nothing
   reflows mid-swap. At the top of the page the full "Real Estate Management in
   Africa" wordmark shows; past 60px of scroll (.is-scrolled) it hands over to
   the REMA Conference mark, which flips to its dark variant over pale ground
   (.is-light). Width, opacity and scale all run the same .45s on the same
   curve, anchored at the left edge, so the pair reads as one shape resizing
   rather than two logos crossfading past each other. */
.header__logo{
  position:relative; display:block; height:34px; width:277px;
  transition:width .45s var(--ease);
}
.header__logo img{
  position:absolute; left:0; top:0; height:34px; width:auto; display:block;
  transform-origin:left center;
  transition:opacity .45s var(--ease), transform .45s var(--ease);
}
.header__logo .logo--full{ opacity:1; transform:none; }
.header__logo .logo--light,
.header__logo .logo--dark{ opacity:0; transform:scale(1.07); }
.header.is-scrolled .header__logo{ width:106px; }
.header.is-scrolled .logo--full{ opacity:0; transform:scale(.86); pointer-events:none; }
.header.is-scrolled .logo--light{ opacity:1; transform:none; }
/* The links belong to the REMA Conference mark, not the full wordmark: at the
   top of the page the header is just the wordmark and Register Now, and the nav
   arrives with the small mark. visibility (not display) keeps the centre column
   the same width, so nothing shifts sideways during the swap. */
.header__nav{
  margin-inline:auto; display:flex; gap:clamp(1rem,2.4vw,2.4rem);
  visibility:hidden; transition:visibility .45s;
}
.header.is-scrolled .header__nav{ visibility:visible; }
.header__nav a{
  position:relative; font-size:.9375rem; padding:.4rem 0; color:rgba(255,255,255,.9);
  opacity:0; transform:translateY(-5px);
  transition:opacity .38s var(--ease), transform .42s var(--ease-out), color .2s;
}
.header.is-scrolled .header__nav a{ opacity:1; transform:none; }
/* Staggered in, uniform out -- the delays live only in the scrolled state. */
.header.is-scrolled .header__nav a:nth-child(1){ transition-delay:.05s; }
.header.is-scrolled .header__nav a:nth-child(2){ transition-delay:.10s; }
.header.is-scrolled .header__nav a:nth-child(3){ transition-delay:.15s; }
.header.is-scrolled .header__nav a:nth-child(4){ transition-delay:.20s; }
.header__nav a::after{
  content:''; position:absolute; left:0; right:100%; bottom:0; height:2px;
  background:var(--lime); transition:right .3s var(--ease-out);
}
.header__nav a:hover::after, .header__nav a[aria-current="true"]::after{ right:0; }
.header__burger{ display:none; }
/* Light skin while a pale section sits under the bar */
.header.is-light{ background:rgba(246,249,243,.8); border-bottom-color:var(--line); }
.header.is-scrolled.is-light .header__logo .logo--light{ opacity:0; }
.header.is-scrolled.is-light .header__logo .logo--dark{ opacity:1; transform:none; }
.header.is-light .header__logo .logo--full{ opacity:0; }
.header.is-light .header__nav a{ color:var(--ink-3); }
.header.is-light .header__nav a::after{ background:var(--grass); }
.header.is-hidden{ transform:translateY(-100%); }
body:has(.drawer.is-open) .header.is-hidden{ transform:none; }
body:has(.drawer.is-open) .header{ background:var(--ink); border-bottom-color:rgba(255,255,255,.12); }

.progress{
  position:fixed; top:0; left:0; height:2px; width:100%; z-index:90;
  transform:scaleX(0); transform-origin:0 50%; background:var(--lime);
  pointer-events:none;
}

.drawer{
  position:fixed; inset:0; z-index:84; display:none;
  background:var(--ink); color:#fff;
  padding:calc(var(--header-h) + 2rem) var(--gutter) 2rem;
  flex-direction:column; gap:.25rem; opacity:0; transition:opacity .28s var(--ease);
}
.drawer.is-open{ display:flex; opacity:1; }
/* Title case, as the markup is written -- the uppercase was CSS, and it caught
   the Register Now button too, since that is an <a> inside the drawer. */
.drawer a{
  font-family:var(--body); font-size:1.25rem;   /* DM Sans 20px, links and the CTA alike */
  padding:.7rem 0; border-bottom:1px solid rgba(255,255,255,.1);
}
.drawer .btn{ margin-top:1.5rem; --btn-bg:var(--lime); --btn-fg:var(--ink-3); }   /* lime, as the header's CTA is -- it was falling through to the default grass */
.drawer .btn:hover{ --btn-bg:#b4ea54; }

/* ---------- 7. HERO + OPENING BAND (one pinned sequence) -----------------
   At rest this is the export's hero: copy up top, the estate photo inset in
   the wrap below. With scripting and motion, the section grows tall and the
   pin holds a viewport-height stage while the photo's window expands to fill
   the screen and "Where it begins" fades in over it — then it releases into
   the motif strip. Without JS / with reduced motion / under 1024px the photo
   stays in its slot with the line set over it.                              */
.hero{
  background:var(--ink-2); color:#fff; position:relative;
}
.hero__pin{
  position:relative;
  padding-top:calc(var(--header-h) + clamp(2.5rem,6.3vw,6rem));
  padding-bottom:clamp(2.5rem,6.5vw,6.2rem);
}
.hero.is-driven .hero__pin{
  position:sticky; top:0; height:100vh; height:100svh;
  display:flex; flex-direction:column; justify-content:flex-start;
  padding-bottom:clamp(1.5rem,3.5vw,3.2rem); overflow:hidden;
}
.hero__copy{ will-change:opacity, transform; }
.hero__head{ display:grid; grid-template-columns:1.32fr .88fr; gap:2rem 3rem; align-items:end; }
.hero__title{ color:#fff; }
.hero__sub{ margin-top:1.5rem; font-size:clamp(1rem,1.45vw,1.32rem); color:rgba(255,255,255,.92); }
.hero__meta{ text-align:right; }
.hero__date{ font-family:var(--display); font-weight:500; font-size:clamp(1.4rem,2.15vw,1.95rem); }
.hero__where{ margin-top:.45rem; font-size:.9375rem; color:rgba(255,255,255,.72); }
.hero__actions{ margin-top:1.8rem; display:flex; gap:.8rem; justify-content:flex-end; flex-wrap:wrap; }

/* The slot keeps the photo's place in the flow. */
.hero__slot{ position:relative; margin-top:clamp(2.4rem,5.2vw,4.2rem); aspect-ratio:1312/593; }
/* Driven: the slot is only a spacer (same size as at rest, so the window's
   start rectangle is the export's inset) and must NOT contain the frame,
   which is positioned against the pinned stage instead. */
.hero.is-driven .hero__slot{ position:static; }
/* (.hero__frame.img-reveal: the later .img-reveal{position:relative} would
   otherwise win on source order and collapse the frame to zero height.)   */
.hero__frame.img-reveal, .hero__frame{ position:absolute; inset:0; overflow:hidden; background:var(--ink); }
.hero__frame .hero__img{
  position:absolute; inset:0; width:100%; height:100%;
  /* 58% framed the previous photograph. The replacement puts its boulevard,
     clubhouse and hazy skyline in the upper half and plain foreground paving
     below, so the letterbox window is pulled up to keep the depth. */
  object-fit:cover; object-position:center 34%;
}
/* Driven: the frame covers the whole stage and is windowed with clip-path,
   so the photo never distorts as the window opens up. */
.hero.is-driven .hero__frame{
  position:absolute; inset:0; z-index:2;
  clip-path:inset(var(--ct,0px) var(--cr,0px) var(--cb,0px) var(--cl,0px));
  will-change:clip-path;
}
.hero.is-driven .hero__pin > .wrap:last-child{ position:static; }
.hero__shade{
  position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg, rgba(7,33,30,.62), rgba(7,33,30,.42) 45%, rgba(7,33,30,.92));
  opacity:var(--shade,1);
}
.hero__band{
  position:absolute; inset:0; display:grid; align-content:center; justify-items:center; text-align:center;
  padding:0 var(--gutter); color:#fff; pointer-events:none;
  opacity:var(--band,1); transform:translateY(calc((1 - var(--band,1)) * 28px));
}
.band__t{ color:#fff; }
.band__d{ margin-top:1.1rem; font-size:clamp(1rem,1.4vw,1.28rem); color:rgba(255,255,255,.92); }
/* At rest in the driven state the window is small: keep the line out of it
   and the shade light, exactly like the export's hero photo. */
/* Declared on the FRAME (the scroll-drive writes the live values there as
   inline custom properties, which then inherit down); declaring them on the
   shade/band themselves would override the inherited value.              */
.hero.is-driven .hero__frame{ --band:0; --shade:0; }

/* ---------- 7b. WORD GATHER (hero headline) --------------------------------
   Words start scattered along the line, half-size and faint, and settle into
   place with a stagger — the reference's headline entrance.                */
.gather .w{
  display:inline-block; opacity:0;
  transform:translateX(var(--dx,0)) scale(.5);
  transition:opacity .9s var(--ease-out), transform 1.05s var(--ease-out);
}
.gather .w:nth-child(2){ transition-delay:.06s; }
.gather .w:nth-child(4){ transition-delay:.12s; }
.gather .w:nth-child(5){ transition-delay:.18s; }
.gather.is-in .w{ opacity:1; transform:none; }
html:not(.js) .gather .w{ opacity:1; transform:none; }

/* ---------- 7c. IMAGE REVEAL (blur-up) -------------------------------------
   Every full photo sits over a 32px placeholder blown up and blurred. When
   the real file has loaded and the frame is in view they crossfade — the
   reference's image entrance.                                              */
/* --zoom-t is the hover-zoom duration. It has to be declared here rather than on
   `.reel img` / `.gal img`, because `.img-reveal [data-reveal]` (0,2,0) outranks
   those (0,1,1) whatever the source order -- their transition:transform was being
   replaced by the opacity one below, so the hover scale was landing in a single
   frame with no easing at all. */
.img-reveal{ position:relative; overflow:hidden; --zoom-t:.9s; }
.img-reveal .lqip{
  position:absolute; inset:0; z-index:1; width:100%; height:100%; object-fit:cover;
  filter:blur(14px) saturate(1.08); transform:scale(1.08);
  transition:opacity .7s var(--ease) .15s; pointer-events:none;
}
.img-reveal [data-reveal]{
  opacity:0;
  transition:opacity .75s var(--ease), transform var(--zoom-t) var(--ease-soft);
}
.img-reveal.is-loaded [data-reveal]{ opacity:1; }
.img-reveal.is-loaded .lqip{ opacity:0; }
html:not(.js) .img-reveal [data-reveal]{ opacity:1; }
html:not(.js) .img-reveal .lqip{ display:none; }
.figstats .lqip{ object-position:center 42%; }
.hero__frame .lqip{ object-position:center 34%; }   /* match the photo, or the blur-up jumps */
.reel [data-reveal], .gal [data-reveal]{ position:relative; z-index:2; }
.reel__play{ z-index:4; }
.figstats [data-reveal]{ position:relative; z-index:2; }
.figstats .stats{ z-index:5; }
.venue__fig [data-reveal]{ z-index:2; }

/* ---------- 7d. LOGO WIPE (on load) ---------------------------------------- */
/* A keyframe rather than a class toggle, so the lockup can never be left
   clipped if a script is slow or blocked. */
@keyframes logo-wipe{ from{ clip-path:inset(0 100% 0 0); } to{ clip-path:inset(0 0 0 0); } }
html.js .header__logo{ animation:logo-wipe 1s var(--ease-out) .25s backwards; }  /* backwards: if animations never run, the base (unclipped) state shows */

/* ---------- 9. SEAL SLAB -------------------------------------------------- */
.slab{ background:var(--ink-2); color:#fff; padding-block:clamp(4rem,9.5vw,9rem); }
/* Badge + copy sit as one group, centred in the viewport rather than pinned
   to the left gutter with dead space on the right. */
.slab__grid{ display:grid; grid-template-columns:auto auto; justify-content:center;
             gap:clamp(2rem,6vw,6rem); align-items:center; }
.slab__seal{ width:clamp(180px,26vw,376px); height:auto; }
/* Capped to the measure the copy actually fills, so the centred group reads
   centred - the heading's 14ch cap left ~80px of empty column beside it. */
.slab__body{ min-width:0; max-width:490px; }
.slab__t{ color:var(--lime); max-width:19ch; }

/* ---------- 10. HANDOVER — scroll-revealed question cards ----------------
   The export cuts card 03 off the right edge. Vertical scroll through the
   section drives the track horizontally so the rest reveal as you read.
   Falls back to a swipeable rail under 1024px / reduced motion.          */
.handover{ background:var(--ink-2); color:#fff; position:relative; }
/* While the cards swap, the section is ~2.5 screens tall and the stage is
   pinned to the top of it. Dots painted on the section would slide up behind
   the frozen content; painted on the sticky stage they hold still, which is
   what the swap is supposed to look like. Off the pinned path (tablet, phone,
   reduced motion) the stage is static and the grid scrolls with the page. */
.handover.dotted{ background-image:none; }
.handover__stage{
  min-height:100svh; display:flex; align-items:center;
  padding-block:clamp(3rem,7vw,6rem); overflow:hidden;
  background-image:var(--dot-grid);
  background-size:var(--dot-size);
  background-position:var(--dot-pos);
}
.handover__grid{
  display:grid; grid-template-columns:minmax(280px,614fr) minmax(0,734fr);
  gap:clamp(1.5rem,4.2vw,64px); align-items:center; width:100%;
}
.handover__t{ color:var(--lime-m); max-width:15ch; }
.handover__d{ margin-top:1.5rem; max-width:44ch; color:rgba(255,255,255,.86); }
.handover__d strong{ color:var(--lime-m); font-weight:600; }

/* The export runs the card track off the right edge of the frame. */
.handover__viewport{ overflow:hidden; margin-right:calc(-1 * var(--gutter)); }
.handover__track{ display:flex; gap:clamp(16px,4.2vw,64px); width:max-content; will-change:transform; }
.hcard{
  flex:0 0 clamp(280px,29.3vw,443px); min-width:0;
  background:var(--hc-body, var(--ink-3));
  display:flex; flex-direction:column;
  min-height:clamp(420px,36.8vw,557px);
  transition:opacity .45s var(--ease);
}
/* Header row is 134 tall with a 129-wide icon tile. */
.hcard__head{ display:grid; grid-template-columns:clamp(84px,8.53vw,129px) 1fr; align-items:stretch; }
.hcard__icon{
  background:var(--hc-tile); display:grid; place-items:center;
  min-height:clamp(88px,8.86vw,134px);
}
.hcard__icon img{ height:clamp(44px,4.5vw,68px); width:auto; max-width:none; }
.hcard__label{
  background:var(--hc-band); color:var(--hc-band-fg,#fff);
  display:flex; align-items:center;
  padding-inline:clamp(1rem,3.74vw,56px);
  font-family:var(--display); font-weight:700; line-height:1.11;
  font-size:clamp(1.2rem,2.65vw,40px);
}
.hcard__body{
  flex:1; position:relative;
  padding:clamp(1.4rem,4.23vw,64px) clamp(1.2rem,3.95vw,60px);
}
.hcard__body p{ font-size:clamp(.95rem,1.59vw,24px); line-height:1.5; }
.hcard__n{
  position:absolute; left:64%; bottom:clamp(.8rem,3.05vw,46px);
  font-family:var(--display); font-weight:400; line-height:1;
  font-size:clamp(2.4rem,4.36vw,66px); color:var(--hc-num, rgba(255,255,255,.14));
}
/* Cards stay at full strength while the track is driven - no dimming of the
   inactive ones. */

.handover__rail{ display:flex; align-items:center; gap:1rem; margin-top:clamp(1.6rem,3vw,2.4rem); }
.handover__dots{ display:flex; gap:.5rem; }
.handover__dots button{ width:34px; height:4px; background:rgba(255,255,255,.22); transition:background-color .3s; }
.handover__dots button[aria-current="true"]{ background:var(--lime-m); }

/* ---------- 11. ABOUT + STATS -------------------------------------------- */
.about{ background:var(--paper-lime); padding:clamp(3.5rem,8.2vw,7.4rem) 0 clamp(3rem,5.22vw,79px); }
.about__grid{ display:grid; grid-template-columns:1.05fr .95fr; gap:clamp(2rem,5.5vw,5.5rem); }
.about__t{ color:var(--ink-3); max-width:26ch; }
.about .btn{ margin-top:2.2rem; }
.about__copy p + p{ margin-top:1.5rem; }
.about__copy strong{ font-weight:600; }

/* Stats photo: an inset panel on the wrap (1440/755 in the design), with a
   green-teal wash and the stats bar floating inside it near the bottom. It
   reveals the way the reference's big image does: the blurred placeholder
   crossfades to the sharp file while the photo settles from a slight zoom. */
.figstats{ position:relative; margin-top:clamp(3rem,7.74vw,117px); }   /* no ground: while the window is narrow the section shows through beside it */
.figstats__media{ position:relative; }
.figstats__media [data-reveal]{
  display:block; width:100%; aspect-ratio:1440/755; object-fit:cover; object-position:center 42%;
}
/* Scroll-linked reveal (design frames "Desktop - 122"): the photo is first
   seen as a centred window 39.5% of the panel's width - the same picture at
   the same scale, cropped to the stage - and the window opens sideways to
   the full panel as the block climbs the viewport; the stats bar fades in
   over the last stretch. --gx / --bo are written by the scroll handler.   */
html.js .figstats.is-reveal .figstats__media{ clip-path:inset(0 var(--gx,0%) 0 var(--gx,0%)); will-change:clip-path; }
html.js .figstats.is-reveal .stats{ opacity:var(--bo,1); transform:translateY(calc((1 - var(--bo,1)) * 18px)); }
/* Photo tone from "REMA Picture.svg": #0C2926 multiplied over the picture, 15%
   a third of the way down rising to 50% near the bottom. Shared by every
   photo section (reel, gallery, venue) so the pictures read as one family. */
.figstats__media::after,.reel::after,.gal button::after,.venue__fig::after{
  content:''; position:absolute; inset:0; z-index:3; pointer-events:none;
  background:linear-gradient(180deg, rgba(12,41,38,.15) 31.6%, rgba(12,41,38,.5) 90.2%);
  mix-blend-mode:multiply;
}
.figstats__media [data-reveal]{ transform:scale(1.046); transform-origin:50% 43%; }   /* the design's bleed */
.stats{
  position:absolute; z-index:2; left:clamp(1rem,5.29vw,80px); right:clamp(1rem,5.29vw,80px);
  bottom:clamp(1.4rem,5.29vw,80px);
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr));
  background:rgba(12,41,38,.2); border:1px solid rgba(255,255,255,.1);
  backdrop-filter:blur(50px); -webkit-backdrop-filter:blur(50px);
  min-height:clamp(120px,9.99vw,151px); align-content:center; padding-block:clamp(1.1rem,2.1vw,1.7rem);
}
.stat{ text-align:center; color:#fff; }
.stat__n{
  font-family:var(--display); font-weight:700; color:var(--lime);
  font-size:clamp(1.9rem,3.6vw,3.1rem); line-height:1; font-variant-numeric:tabular-nums;
}
.stat__l{ margin-top:.55rem; font-size:clamp(.8rem,1.02vw,1rem); }

/* ---------- 12. EXPERIENCE CARDS -----------------------------------------
   Measured off "Desktop - 133.svg": cards 429.3x393 (row 1) and 650x337
   (row 2) on a 12px gap; 56px padding; 70px icon at the top-left; title 38px;
   body 18px/28px pitch; and the ghost is the SAME artwork as the icon at
   140px, flush to the card's top-right corner, at opacity .05.          */
.experience{ background:#FFFFFF; padding:clamp(3.5rem,6.9vw,104px) 0 clamp(3.5rem,8.1vw,122px); }
.experience__t{
  color:var(--ink-3); max-width:44ch; line-height:1.35;
  margin-bottom:clamp(2rem,4.1vw,62px);
}
.xgrid{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; }
.xgrid--b{ grid-template-columns:repeat(2,minmax(0,1fr)); margin-top:12px; }
.xcard{
  position:relative; overflow:hidden;
  background:var(--xc-bg); color:var(--xc-fg,#fff);
  padding:clamp(1.4rem,3.7vw,56px);
  min-height:clamp(260px,26vw,393px);
  display:flex; flex-direction:column;
}
.xgrid--b .xcard{ min-height:clamp(230px,22.3vw,337px); }
/* Watermark. Figma places each mark individually rather than on a grid, so the
   size and offsets come straight off "Desktop - 133.svg" (1512 frame):
   --gw / --gr are percentages of the card's own width, --gt the top inset.  */
.xcard__ghost{
  position:absolute; z-index:0; pointer-events:none; max-width:none;
  top:var(--gt,0); right:var(--gr,0); width:var(--gw); height:auto; opacity:.05;
}
/* Icons are 70px tall in the design and vary in width (66 - 71.17); Keynotes
   is the one placed smaller, at 62.354 tall -- hence --ih.                  */
.xcard__icon{ position:relative; z-index:1; align-self:flex-start;
              height:calc(clamp(46px,4.63vw,70px) * var(--ih,1));
              width:auto; max-width:none; }
.xcard__t{
  position:relative; z-index:1; margin-top:clamp(1.8rem,3.505vw,53px);
  font-family:var(--display); font-weight:600; letter-spacing:-.012em; line-height:1.1;
  font-size:clamp(1.3rem,2.51vw,38px);
}
/* Figma measures the 56px bottom padding from the last BASELINE, so trim the
   descent + half-leading that CSS puts below it -- keeps the card at 393.   */
.xcard__d{
  position:relative; z-index:1;
  margin-top:clamp(.5rem,.96vw,14.5px); margin-bottom:-.405em;
  max-width:42ch; font-size:clamp(.9375rem,1.19vw,18px); line-height:1.55;
}

/* ---------- 13. AUDIENCE -------------------------------------------------- */
.audience{ background:var(--ink); color:#fff; padding-block:clamp(3.5rem,8.2vw,7.4rem); }
.audience__t{ color:var(--grass); max-width:32ch; margin:.8rem 0 clamp(2.4rem,4.8vw,3.8rem); }
.arow{
  display:grid; grid-template-columns:128px 1fr minmax(0,.42fr); gap:1.5rem; align-items:center;
  padding-block:clamp(1.4rem,2.55vw,2.15rem); border-top:1px solid rgba(255,255,255,.12);
  transition:padding-left .35s var(--ease);
}
.arow:last-child{ border-bottom:1px solid rgba(255,255,255,.12); }
.arow__n{ font-family:var(--display); font-size:clamp(1.3rem,1.95vw,1.7rem); color:rgba(255,255,255,.26); transition:color .3s; }
.arow__t{
  font-family:var(--display); font-weight:600; letter-spacing:-.014em;
  font-size:clamp(1.35rem,2.5vw,2.1rem); transition:color .3s;
}
.arow__d{ font-size:.9375rem; color:rgba(255,255,255,.74); }
.arow:hover{ padding-left:clamp(.5rem,1.4vw,1.4rem); }
.arow:hover .arow__t{ color:var(--grass); }
.arow:hover .arow__n{ color:var(--lime); }

/* ---------- 14. SPEAKERS -------------------------------------------------- */
.speakers{ background:var(--white); padding-block:clamp(3.5rem,8.2vw,7.4rem); }
.speakers__t{ color:var(--ink-3); max-width:34ch; margin:.8rem 0 clamp(1.8rem,3.6vw,2.8rem); }
.filters{ display:flex; flex-wrap:wrap; gap:11px; margin-bottom:clamp(2rem,4.2vw,3.2rem); }
.filter{
  min-height:39px; padding:.55rem 1.15rem; border:1px solid var(--line-f);
  font-size:.9375rem; background:var(--white); color:var(--ink-3);
  transition:background-color .2s, color .2s, border-color .2s;
}
.filter:hover{ border-color:var(--forest); }
.filter[aria-pressed="true"]{ background:var(--forest); border-color:var(--forest); color:#fff; }

.sgrid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:clamp(1.1rem,1.9vw,1.9rem) clamp(.8rem,1.3vw,1.25rem); }
.scard[hidden]{ display:none; }   /* the card's display:flex would otherwise beat the hidden attribute */
.scard{
  display:flex; flex-direction:column; text-align:left; width:100%; min-width:0;
  animation:cardIn .5s var(--ease-out) backwards;   /* no forwards hold, so :hover transforms apply after entry */
}
@keyframes cardIn{ from{ opacity:0; transform:translateY(14px); } }
.scard > *{ display:block; }
.scard__fig{
  display:block; position:relative; aspect-ratio:254.4/349; overflow:hidden;
  background:var(--forest);
  border-radius:0 0 64px 0;          /* the export's bottom-right cut */
}
.scard__fig::before{     /* the kit's outline tile, sized to the card width */
  content:''; position:absolute; inset:0; z-index:0;
  background:url('../img/patterns/card-motif.svg') no-repeat left 9% / 100% auto;
}
/* Each portrait is individually placed in the export; --pl/--pt/--pw carry
   that placement per card, as a share of the 254.4 x 349 card box. */
.scard__fig img{
  position:absolute; z-index:1;
  left:var(--pl,0); top:var(--pt,0); width:var(--pw,100%); height:auto;
  max-width:none;                     /* the reset's 100% cap would clamp it */
  transform-origin:50% 0;
  transition:transform .6s var(--ease-out);
}
.scard:hover .scard__fig img{ transform:scale(1.035); }
.scard__tag{                          /* flush top-LEFT, 95×28 */
  position:absolute; z-index:3; top:0; left:0;
  min-width:95px; height:28px; display:inline-flex; align-items:center; justify-content:center;
  background:var(--yellow); color:var(--ink-3);
  font-size:.6875rem; font-weight:500; letter-spacing:.05em; text-transform:uppercase;
  padding-inline:.6rem;
}
.scard__name{ margin-top:1.05rem; font-weight:600; font-size:1rem; color:var(--ink-3); }
.scard__role{
  margin-top:.3rem; font-size:.9375rem; color:var(--forest);
  /* wraps rather than truncating: a role now carries the organisation too */
  overflow-wrap:break-word;
}
.scard__hint{   /* hover-only, so it reserves as little row height as possible */
  margin-top:.15rem; font-size:.72rem; line-height:1.2; color:var(--grass); opacity:0;
  transform:translateY(-3px); transition:opacity .2s, transform .2s;
}
.scard:hover .scard__hint, .scard:focus-visible .scard__hint{ opacity:1; transform:none; }
.speakers__more{ display:flex; justify-content:center; margin-top:clamp(2rem,3.8vw,3rem); }
.speakers__more .btn{ --btn-bg:transparent; --btn-fg:var(--ink-3); --btn-bd:var(--line-f); padding-inline:2rem; }
.speakers__more .btn:hover{ --btn-bd:var(--forest); --btn-bg:transparent; --btn-fg:var(--ink-3); }
.speakers__more svg{ transition:transform .3s var(--ease); }
.speakers__more .btn[aria-expanded="true"] svg{ transform:rotate(180deg); }
.sempty{ padding:3rem 0; text-align:center; color:var(--muted); }

/* ---------- 15. SPEAKER MODAL (from "Speaker's Bio Modal.svg") -----------
   The export is 1240 x 690: a 502.97-wide portrait panel with a 150px cut at
   its bottom-right, and the copy alongside. Rendered a little smaller here,
   at a fixed height, so the portrait always fits its panel and only the copy
   scrolls.                                                                */
.modal{
  position:fixed; inset:0; z-index:100; display:grid; place-items:center;
  padding:clamp(1rem,3vw,2.5rem); background:rgba(3,33,30,.72);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  /* visibility flips with no delay on the way in, so the dialog is focusable
     the instant .is-open lands -- transitioning it meant the flip happened
     midway through the fade and the focus() was refused, leaving focus on the
     card behind. On the way out it is delayed instead, keeping the fade. */
  opacity:0; visibility:hidden;
  transition:opacity .28s var(--ease), visibility 0s linear .28s;
}
.modal.is-open{ opacity:1; visibility:visible; transition:opacity .28s var(--ease), visibility 0s linear 0s; }
.modal__panel{
  position:relative; width:min(1160px,100%); height:min(645px,88vh);
  background:var(--ink); color:#fff; overflow:hidden;
  /* Same dot grid as the dark sections. It sits on the panel rather than the
     body so it stays put while a long bio scrolls. */
  background-image:var(--dot-grid);
  background-size:var(--dot-size);
  background-position:var(--dot-pos);
  display:grid; grid-template-columns:40.562% minmax(0,1fr);
  transform:translateY(18px) scale(.985); transition:transform .32s var(--ease-out);
}
.modal.is-open .modal__panel{ transform:none; }

.modal__fig{
  position:relative; overflow:hidden; height:100%; background:var(--forest);
  border-radius:0 0 clamp(56px,21.7vh,140px) 0;   /* the export's corner cut */
}
.modal__fig::before{
  content:''; position:absolute; inset:0; z-index:0;
  background:url('../img/patterns/card-motif.svg') no-repeat left 6% / 100% auto;
}
/* Same per-speaker placement as the card in the speakers grid (the two panels
   share the 254.4/349 aspect), so the modal shows the identical portrait. */
.modal__fig img{
  position:absolute; z-index:1;
  left:var(--pl,0); top:var(--pt,0); width:var(--pw,100%); height:auto;
  /* The placement is copied off the card, whose frame is 254.4/349. This frame
     is a fixed height that narrows with the viewport, so below ~1200 it grows
     proportionally taller than the card's and a portrait sized off its *width*
     stopped reaching the bottom -- 116px of bare frame at 820, 9px at 1024.
     Both percentages resolve against the frame height, so this is exactly the
     distance from the portrait's top edge to the frame's bottom; where the
     natural height already covers it nothing changes, and where it does not the
     box stretches and cover crops from the bottom rather than distorting. */
  min-height:calc(100% - var(--pt,0%));
  object-fit:cover; object-position:50% 0;
  max-width:none;
}
.modal__fig::after{                   /* bottom fade, as in the export */
  content:''; position:absolute; z-index:2; inset:auto 0 0 0; height:20%;
  background:linear-gradient(180deg, transparent, rgba(1,114,66,.55));
}
.modal__tag{                          /* flush top-left, 186 x 56 at 1240 */
  position:absolute; z-index:3; top:0; left:0;
  min-width:15%; height:56px;
  display:inline-flex; align-items:center; justify-content:center;
  padding-inline:1.1rem; background:var(--yellow); color:var(--ink-3);
  font-size:17px; font-weight:500; letter-spacing:.02em; text-transform:uppercase;
}
.modal__body{
  padding:75px 73px 76.6px 50.5px;
  display:flex; flex-direction:column; min-height:0;
  overflow-y:auto; overscroll-behavior:contain;
}
.modal__name{
  font-family:var(--display); font-weight:700; text-transform:uppercase;
  font-size:32px; line-height:1.1; letter-spacing:.008em;
  color:#fff; padding-right:96px;
}
.modal__role{
  margin-top:9px; font-family:var(--body); font-weight:400;
  font-size:24px; line-height:1.25; letter-spacing:-.018em; color:var(--lime-m);
}
.modal__bio{
  margin-top:54px; font-family:var(--body); font-weight:400;
  font-size:16px; line-height:1.8125; letter-spacing:-.01em; color:#fff;
}
.modal__foot{ margin-top:auto; padding-top:44px; }
.modal__foot::before{
  content:''; display:block; height:1px; background:#839190;
  margin-bottom:34px;
}
.modal__foot .eyebrow{
  font-family:var(--body); font-weight:400; font-size:18px; line-height:1;
  letter-spacing:.01em; text-transform:uppercase; color:var(--lime-m);
}
.modal__session{
  margin-top:20px; font-family:var(--display); font-weight:600;
  text-transform:uppercase; font-size:24px; line-height:1.2;
  letter-spacing:-.005em; color:#fff;
}
.modal__x{
  position:absolute; z-index:4; top:34px; right:34px; width:56px; height:56px;
  display:grid; place-items:center; color:#fff;
  background:var(--ink-6); border:1px solid rgba(255,255,255,.18);
  transition:background-color .2s, color .2s, border-color .2s;
}
.modal__x:hover{ background:#fff; color:var(--ink); border-color:#fff; }
@media (max-width:820px){ .modal__x{ top:14px; right:14px; width:44px; height:44px; } }

/* ---------- 16. SCHEDULE -------------------------------------------------- */
/* Every number below is measured off "Event Schedule.svg" (a 1512 x 1396
   frame of this section). Cards sit at x 558.5 and are 853 wide, so the left
   column plus gutter is 458.5 of the 1311.5 wrap = 34.9581%.               */
.schedule{
  background:var(--paper); position:relative; overflow:clip;
  padding-top:clamp(3.5rem,9.292vw,140.5px);
  padding-bottom:clamp(4rem,10.48vw,158.5px);
}
/* Same outline tile as the closing band: 168 wide (11.1111% of the frame),
   one whole tile 332 tall, flush to the section's bottom edge.            */
.schedule__band{
  position:absolute; z-index:0; inset:auto 0 0 0; height:clamp(152px,21.96vw,332px);
  background:url('../img/patterns/line-pale.svg') left bottom/11.1111% auto repeat-x;
  pointer-events:none;
  /* fades in from the top so it never collides with the sticky REMA badge */
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 62%);
          mask-image:linear-gradient(180deg,transparent 0,#000 62%);
}
.schedule .wrap{ position:relative; z-index:1; }
.schedule__grid{ display:grid; grid-template-columns:34.9581% minmax(0,1fr); gap:0; align-items:start; }
/* minmax(0,…), not 1fr: a bare 1fr track floors at its content's min-content
   width, and the chapter rail is a nowrap flex row, so its labels would size
   the column and push the schedule out under #schedule's overflow:clip. */

/* The left panel rides along until the last track scrolls past. */
.schedule__aside{ position:sticky; top:calc(var(--header-h) + 2rem); }

.schedule__t{
  margin-top:-.127em;          /* cap-top flush with the first card's top edge */
  font-family:var(--display); font-weight:600; text-transform:none;
  font-size:clamp(2rem,3.373vw,51px); line-height:1.157; letter-spacing:0;
  color:#0E3F3A;
}
.schedule__d{
  margin-top:clamp(1.2rem,2.037vw,30.8px);
  font-family:var(--body); font-weight:400;
  font-size:clamp(1rem,1.323vw,20px); line-height:1.59; letter-spacing:-.02em;
  color:#818787; max-width:clamp(210px,17.26vw,261px);
}
.schedule__seal{
  display:block; width:clamp(176px,16.53vw,250px); height:auto;
  margin-left:clamp(13px,1.252vw,18.93px);
  margin-top:clamp(2.6rem,5.192vw,78.5px);
}

/* ---- tracks ---- */
#tracks{ overflow-anchor:none; }   /* we compensate the single-open collapse ourselves */
.track{ background:#fff; border:1px solid #E7EBE2; }
.track + .track{ margin-top:17px; }
.track__btn{
  display:grid; grid-template-columns:54px minmax(0,1fr) 39px; align-items:center;
  column-gap:40px; width:100%; text-align:left;
  padding:30.5px 31px 30.5px 30.5px;
}
.track__n{
  display:grid; place-items:center; width:54px; height:54px;
  background:#00A85A; color:#fff;
  font-family:var(--display); font-weight:600; font-size:20px; line-height:1; letter-spacing:.02em;
}
.track__h{
  display:block; font-family:var(--display); font-weight:500;
  font-size:20px; line-height:1.1; letter-spacing:.02em; color:#1A413C;
}
.track__strap::before{ content:' \00b7\0020'; }   /* the escape eats a following space, so spell it */
.track__m{
  display:block; margin-top:9px;
  font-family:var(--body); font-weight:400; font-size:16px; line-height:1.1;
  letter-spacing:-.01em; color:#818787;
}
.track__i{
  position:relative; width:39px; height:39px; border:1px solid #ECF0EF; justify-self:end;
  transition:border-color .2s;
}
.track__i::before,.track__i::after{
  content:''; position:absolute; left:50%; top:50%; width:18.76px; height:1.5px;
  background:#0E3F3A; transform:translate(-50%,-50%); transition:transform .3s var(--ease);
}
.track__i::after{ transform:translate(-50%,-50%) rotate(90deg); }
.track[open] .track__i::before{ transform:translate(-50%,-50%) rotate(45deg); }
.track[open] .track__i::after{ transform:translate(-50%,-50%) rotate(-45deg); }
.track[open] .track__i{ border-color:#E7EBE2; }
.track__panel{ display:grid; grid-template-rows:0fr; transition:grid-template-rows .42s var(--ease-out); }
.track[open] .track__panel{ grid-template-rows:1fr; }
.track__panelInner{ overflow:hidden; }

/* ---- session list: a 12px dot at x+55.5 with a hairline running down the
        side of each row, and the row card starting at x+131.75. ---- */
.track__list{ padding:8.75px 31.75px 31.75px 55.5px; }
.tl{ display:block; margin:0; padding:0; list-style:none; }
.tl__row{ display:grid; grid-template-columns:12px minmax(0,1fr); column-gap:64.25px; }
.tl__row + .tl__row{ margin-top:16.5px; }
.tl__mark{ position:relative; }
.tl__mark::before{
  content:''; position:absolute; top:0; left:0; width:12px; height:12px;
  border-radius:50%; background:#1A413C;
}
.tl__mark::after{
  content:''; position:absolute; top:16px; bottom:0; left:6px;
  width:.6px; margin-left:-.3px; background:#E7EBE2;
}
.tl__card{
  background:#fff; border:.5px solid #E7EBE2;
  padding:21px 24.25px 19.3px;
  display:grid; grid-template-columns:96px minmax(0,1fr); column-gap:24.45px;
}
.tl__time{ display:flex; flex-direction:column; }
.tl__time b{
  font-family:var(--body); font-weight:500; font-size:18px; line-height:1.1;
  letter-spacing:-.01em; color:#1A413C; font-variant-numeric:tabular-nums;
}
.tl__time small{
  margin-top:10.8px; font-family:var(--body); font-weight:400; font-size:15px;
  line-height:1.1; letter-spacing:0; text-transform:none; color:#818787;
}
.tl__body{ min-width:0; }
.tl__t{
  display:block; font-family:var(--body); font-weight:500; font-size:18px;
  line-height:1.25; letter-spacing:-.01em; color:#1A413C;
}
.tl__meta{
  display:block; margin-top:9.2px;
  font-family:var(--body); font-weight:400; font-size:15px; line-height:1.1;
  color:#818787;
}
/* tags sit on their own full-width row, aligned with the time column */
.tl__people{ grid-column:1/-1; display:flex; flex-wrap:wrap; gap:8px; margin-top:25px; margin-bottom:8px; }
.pchip{
  display:inline-flex; align-items:center; gap:10px; height:41px;
  padding:2px 14px 2px 2px;
  background:#F6F9F3; border:1px solid #E1EBD0;
  font-family:var(--body); font-weight:500; font-size:14px; letter-spacing:0;
  color:#11302D;
  transition:background-color .2s, border-color .2s;
}
button.pchip:hover{ background:#E4F5C6; border-color:var(--forest); }
.pchip img{
  width:37px; height:37px; object-fit:cover; object-position:center top;
  background:var(--forest); flex:0 0 auto;
}
.pchip--plain{ padding-left:14px; }

/* ---------- 17. HIGHLIGHTS ----------------------------------------------- */
.highlights{ background:var(--white); padding-block:clamp(3.5rem,8.2vw,7.4rem); }
.highlights__head{ margin-top:clamp(.9rem,1.6vw,1.5rem); display:grid; grid-template-columns:1.28fr .72fr; gap:clamp(1.5rem,4.2vw,4.2rem); align-items:end; }
.highlights__t{ color:var(--ink-3); max-width:26ch; }
.reel{ position:relative; margin-top:clamp(2rem,4.2vw,3.4rem); overflow:hidden; border-radius:4px; }
.reel{ --zoom-t:1.15s; }   /* the bigger picture wants a longer, slower move */
.reel img{ width:100%; aspect-ratio:1312/715; object-fit:cover; }
.reel:hover img{ transform:scale(1.03); }
.reel__play{ position:absolute; z-index:4; left:clamp(1.2rem,2.8vw,2.6rem); bottom:clamp(1.2rem,2.8vw,2.6rem); }
/* Gallery: a horizontal rail, as in the export (533x349 tiles on a 553 pitch,
   the first already bleeding off the left edge). It runs from the left gutter
   to the viewport edge and snaps tile by tile; arrows appear on hover. */
.galwrap{ position:relative; margin-top:20px; }
.gal{
  display:flex; gap:20px; overflow-x:auto; scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch; scrollbar-width:none;
  margin-inline:calc(-1 * var(--gutter)); padding-inline:var(--gutter);
  scroll-padding-inline:var(--gutter);
}
.gal::-webkit-scrollbar{ display:none; }
.gal button{
  flex:0 0 clamp(280px, 35.25vw, 533px); scroll-snap-align:start;
  display:block; overflow:hidden; border-radius:4px;
  padding:0; border:0; background:none;   /* the UA button padding (1px 6px) let the blurred placeholder show around the photo */
}
.gal img{ display:block; width:100%; aspect-ratio:533/349; object-fit:cover; }
.gal__nav{
  position:absolute; top:50%; translate:0 -50%; z-index:5; width:44px; height:44px; border-radius:50%;
  display:grid; place-items:center; padding:0; border:0; cursor:pointer;
  background:rgba(255,255,255,.94); color:var(--ink-3); box-shadow:0 6px 20px rgba(3,33,30,.18);
  opacity:0; transition:opacity .3s var(--ease), transform .3s var(--ease-out), background-color .2s;
}
.gal__nav--prev{ left:-22px; }
.gal__nav--next{ right:calc(20px - var(--gutter)); }   /* the rail bleeds a gutter past the wrap */
.galwrap:hover .gal__nav, .gal__nav:focus-visible{ opacity:1; }
.gal__nav:hover{ background:#fff; transform:scale(1.06); }
.gal__nav[disabled]{ opacity:0 !important; pointer-events:none; }
.gal button:hover img{ transform:scale(1.06); }

/* ---------- 18. SPONSORS (dark in this revision) ------------------------- */
.sponsors{ background:var(--ink); color:#fff; padding-block:clamp(3.5rem,8.2vw,7rem); overflow:hidden; }
.sponsors__head{ display:grid; grid-template-columns:1.28fr .72fr; gap:clamp(1.5rem,4.2vw,4.2rem); align-items:start; }
.sponsors__t{ color:#fff; max-width:22ch; }
.sponsors__d{ color:rgba(255,255,255,.86); }
.marquee{
  position:relative; margin-top:clamp(3rem,6vw,5.5rem);   /* no edge fade: tiles run cleanly off both sides */
}
.marquee__track{ display:flex; gap:22px; width:max-content; animation:slide 38s linear infinite; }
.marquee:hover .marquee__track{ animation-play-state:paused; }
@keyframes slide{ to{ transform:translateX(-50%); } }
@media (prefers-reduced-motion:reduce){ .marquee__track{ animation:none; } .marquee{ overflow-x:auto; } }
.slogo{
  flex:0 0 248px; height:118px; display:grid; place-items:center;
  background:var(--white); border-radius:3px; padding:1.5rem;
}
.slogo img{ max-height:56px; width:auto; max-width:170px; object-fit:contain; }

/* ---------- 19. REGISTER -------------------------------------------------- */
.register{ background:var(--lime-3); padding-block:clamp(3.5rem,8.2vw,7.4rem); }
.register__head{ display:grid; grid-template-columns:1.28fr .72fr; gap:clamp(1.5rem,4.2vw,4.2rem); align-items:start; }
.register__t{ color:var(--ink-3); max-width:24ch; }
.register__d em{ font-style:italic; font-weight:600; }
.rgrid{ display:grid; grid-template-columns:825fr 486fr; margin-top:clamp(2.4rem,4.8vw,3.8rem); }
.rform{ background:var(--paper-2); padding:clamp(1.6rem,3.2vw,3rem); }
.rform__t{ font-family:var(--display); font-weight:600; font-size:clamp(1.4rem,2.1vw,1.85rem); color:var(--ink-3); }
.rform__d{ margin-top:.6rem; color:var(--muted); font-size:.9375rem; max-width:52ch; }
.fields{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:1.2rem 1.6rem; margin-top:clamp(1.6rem,2.6vw,2.2rem); }
.field--full{ grid-column:1 / -1; }
.field .req{ color:var(--grass); margin-left:.1em; }
.field label{ display:block; font-size:.9375rem; margin-bottom:.5rem; }
.field input,.field select{
  width:100%; height:52px; padding:0 1rem; background:var(--white);
  border:1px solid var(--line-2); border-radius:0;
  transition:border-color .2s, box-shadow .2s;
}
.field select{ appearance:none; padding-right:2.4rem; cursor:pointer; }
.field ::placeholder{ color:#AFB4B1; }
.field input:focus,.field select:focus{
  outline:none; border-color:var(--lime); box-shadow:0 0 0 3px rgba(193,241,109,.45);
}
.field.has-error input,.field.has-error select{ border-color:#C0392B; box-shadow:0 0 0 3px rgba(192,57,43,.14); }
.field__err{ display:none; margin-top:.35rem; font-size:.8125rem; color:#C0392B; }
.field.has-error .field__err{ display:block; }
.selectwrap{ position:relative; }
.selectwrap svg{ position:absolute; right:1rem; top:50%; transform:translateY(-50%); pointer-events:none; }
.phone{ display:grid; grid-template-columns:auto minmax(0,1fr); }
.phone select{ border-right:0; text-align:left; padding-inline:.65rem 1.7rem; width:auto; min-width:0; }   /* hugs the code */
.phone .selectwrap svg{ right:.55rem; }
.rform .btn{ margin-top:1.8rem; min-height:52px; }
.rform__fine{ margin-top:1.2rem; text-align:center; font-size:.9375rem; color:var(--muted); }
.rform__ok{
  display:none; margin-top:1.2rem; padding:1rem 1.15rem;
  background:var(--paper-lime); border:1px solid var(--grass); font-size:.9375rem;
}
.rform.is-sent .rform__ok{ display:block; }
fieldset.fields{ border:0; padding:0; min-width:0; }
.rform [hidden]{ display:none !important; }
.rform__actions{ display:flex; flex-wrap:wrap; gap:1rem 1.5rem; margin-top:1rem; }
.rform__link{ background:none; border:0; padding:.4rem 0; color:var(--ink-3); text-decoration:underline; cursor:pointer; font:inherit; }
.rform__link:focus-visible{ outline:2px solid var(--forest); outline-offset:4px; }
.rform button:disabled{ opacity:.6; cursor:default; }
.rform fieldset:disabled{ opacity:.7; }
.rform__error{ margin-top:1.2rem; padding:1rem; color:#922A20; background:#FFF0EE; border:1px solid #C0392B; }
.rform__notice:not(:empty){ margin-top:1rem; color:var(--ink-3); }
.rform__ok{ overflow-wrap:anywhere; }
.rform__captcha{ margin-top:1.5rem; text-align:center; }
.rform__captcha [data-captcha-widget]{ display:flex; justify-content:center; }
.rform__captcha > p:first-child{ margin-bottom:.75rem; font-size:.875rem; color:var(--muted); }
.rform__captcha-status:not(:empty){ margin-top:.75rem; color:#922A20; font-size:.875rem; }

.ticket{ background:var(--ink-4); color:#fff; padding:clamp(1.6rem,3.2vw,3rem); display:flex; flex-direction:column; }
.ticket__brand{ font-family:var(--display); font-weight:700; font-size:1.35rem; }
.ticket__t{ margin-top:clamp(2rem,4.2vw,3.4rem); color:var(--lime); }
.ticket__s{ margin-top:1rem; font-size:.9375rem; color:rgba(255,255,255,.86); }
/* The rows used to carry margin-top:auto, which parked a 116px void between
   the sub copy and the details while ADMIT ONE sat 33px under them: empty in
   the middle, bunched at the foot. The details now follow the copy on a
   normal gap and the stub takes the auto instead, so the slack sits where a
   ticket's perforation would be. */
.ticket__rows{ margin-top:clamp(1.8rem,3.4vw,2.6rem); }
.trow{ display:flex; justify-content:space-between; gap:1rem; padding:.95rem 0; border-top:1px solid rgba(255,255,255,.14); font-size:.9375rem; }
.trow dt{ color:rgba(255,255,255,.55); }
.trow dd{ margin:0; font-weight:600; text-align:right; }
.ticket__stub{
  /* takes the auto the rows used to have, so it sits at the foot of the
     ticket however tall the form beside it grows */
  margin-top:auto; padding-top:clamp(1.6rem,3vw,2.4rem);
  display:flex; align-items:center; gap:1rem;
  font-family:var(--display); font-size:.8rem; letter-spacing:.22em;
  text-transform:uppercase; white-space:nowrap; color:var(--grass);
}
.ticket__stub::before,.ticket__stub::after{ content:''; flex:1; height:1px; background:rgba(255,255,255,.16); }

/* ---------- 20. VENUE ---------------------------------------------------- */
.venue{ background:var(--ink); color:#fff; }
.venue__grid{ display:grid; grid-template-columns:772fr 740fr; }
.venue__fig{ position:relative; min-height:420px; }
.venue__fig img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
/* No bottom padding while the photo sits alongside: the body's height is what
   sets the row, and the figure stretches to it, so any padding here pushes the
   photo that much lower than the map link. In the export both columns end on
   the same row (design y 16459), which is what this restores. Padding comes
   back below 1180 where the two stack and the link would otherwise butt into
   the next section. */
.venue__body{ padding:clamp(2.4rem,5.4vw,5.4rem) clamp(1.6rem,5vw,6.6rem) 0 clamp(2rem,6.6vw,100px); }
.venue__t{ color:var(--grass); margin:.8rem 0 clamp(1.6rem,3.2vw,2.6rem); }
.vrow{ display:grid; grid-template-columns:132px 1fr; gap:1.5rem; padding:clamp(1.1rem,2.1vw,1.7rem) 0; border-top:1px solid rgba(255,255,255,.14); }
.vrow dt{ font-size:.75rem; letter-spacing:.24em; text-transform:uppercase; color:rgba(255,255,255,.5); padding-top:.35rem; }
.vrow b{ display:block; font-family:var(--display); font-weight:600; font-size:clamp(1.05rem,1.55vw,1.45rem); }
.vrow small{ display:block; margin-top:.32rem; font-size:.9375rem; color:rgba(255,255,255,.62); }
.venue__map{ display:block; margin-top:clamp(1.8rem,3.2vw,2.8rem); overflow:hidden; }
.venue__map img{ width:100%; max-width:477px; transition:transform .6s var(--ease-out); }
.venue__map:hover img{ transform:scale(1.03); }
.venue__link{
  display:inline-flex; align-items:center; gap:.5rem; margin-top:1.5rem;
  font-family:var(--display); text-transform:uppercase;
  font-size:clamp(.95rem,1.35vw,1.2rem); color:var(--muted-3);
  transition:color .25s, gap .25s;
}
/* The export's arrow is nearly cap height (15.25 against a 17.1 cap) with a
   ~2.3px stroke. Ours drew 9px of ink inside a 15px box, under half the cap,
   because the old viewBox left a third of itself empty on every side — that
   padding also inflated the visual gap to 11px against the export's 7.5. The
   viewBox is now cropped to the ink, so the box IS the arrow and the flex gap
   alone spaces it; em keeps it tracking the text down the clamp. */
.venue__link svg{ width:.71em; height:.71em; flex:none; }
.venue__link:hover{ color:var(--lime); gap:.8rem; }

/* ---------- 21. CLOSING + FOOTER ----------------------------------------- */
.closing{
  background:var(--ink); color:#fff; text-align:center; position:relative; overflow:hidden;
  /* The export leaves 192px of clear ground between the buttons and the first
     row of the motif band. The band is anchored to this section's bottom edge,
     so that gap is set from here: 523 put the first motif 268px below the
     buttons, because hanging the band's faded tail below the section (see
     .closing__pat) moved every visible row down by 76px. 447 puts it back. */
  padding:clamp(4.5rem,10.5vw,9.5rem) 0 clamp(11rem,29.56vw,447px);   /* the 11rem floor is unchanged: phones were already tight and were not the complaint */
}
/* Same tile, rendered 168 wide (11.1111% of 1512) here -- one whole tile,
   332 tall, four complete rows, stroke #0D4F46 at full strength.          */
.closing__pat{
  --pat-h:clamp(152px,21.96vw,332px);
  position:absolute; left:0; right:0; top:auto; z-index:0; pointer-events:none;
  height:var(--pat-h);
  background:url('../img/patterns/line-ink.svg') left bottom/11.1111% auto repeat-x;
  /* The original fade, unchanged: opaque at the top, gone by 77%. Everything
     below that point was drawing nothing while still taking up 23% of the band,
     which is what put ~185px of dead ground between the last motif and the
     footer logo. So the band now hangs that tail below the section and
     overflow:hidden clips it -- the gradient looks exactly as it did, and the
     last visible row lands on the section's bottom edge, 101px from the logo
     as in the export. */
  bottom:calc(var(--pat-h) * -0.23);
  -webkit-mask-image:linear-gradient(180deg,#000 0,rgba(0,0,0,.38) 50%,transparent 77%);
          mask-image:linear-gradient(180deg,#000 0,rgba(0,0,0,.38) 50%,transparent 77%);
}
.closing .wrap{ position:relative; z-index:1; }
.closing__t{ color:#fff; max-width:16ch; margin-inline:auto; }
.closing__t em{ font-style:normal; color:var(--lime); }
.closing__d{ margin:1.6rem auto 0; max-width:56ch; color:rgba(255,255,255,.88); }
.closing__a{ margin-top:2.4rem; display:flex; gap:.8rem; justify-content:center; flex-wrap:wrap; }

/* The export leaves ~100px of clear ground under the copyright row before the
   page ends; the bar's own 1.9rem was carrying all of it. */
.footer{
  background:var(--ink); color:#fff; position:relative; z-index:1;
  padding-bottom:clamp(2.5rem,4.6vw,70px);
}
/* Column starts measured off REMA Landing Page.pdf at 1512: gutter 100, "Get
   Involved" at 768, and the last column right-aligned to the 1412 gutter edge.
   With the 64px gap that is 604/330/250 of the 1184px of free space, so the fr
   values land the columns exactly where the export puts them. The old
   1.5fr 1fr 1fr started the middle column at 671, 97px short. */
.footer__grid{ display:grid; grid-template-columns:604fr 330fr 250fr; gap:clamp(2rem,5vw,4rem); padding:clamp(3rem,6.6vw,100px) 0 clamp(2.5rem,5vw,4rem); }
.footer__logo{ height:72px; width:auto; }
/* The measure sets where the copy breaks. At 34ch it was 348.35px against a
   348.1px first line -- "Conference." was clearing by a quarter of a pixel and
   hanging on line one. 32.4ch sits mid-window ([30.81ch, 33.99ch]), so it reads
   "...in Africa / Conference. Rethinking how communities live, / operate and
   grow." and stays there across the font-size clamp, ch being proportional. */
.footer__d{ margin-top:clamp(1.6rem,2.75vw,2.6rem); max-width:32.4ch; font-size:.9375rem; color:rgba(255,255,255,.55); }
.footer h4{ font-size:.9375rem; font-weight:400; color:rgba(255,255,255,.5); margin-bottom:1.35rem; }
.footer__links a{ display:block; padding:.45rem 0; font-size:.9375rem; font-weight:600; transition:color .2s; }
.footer__links a:hover{ color:var(--lime); }
.footer__venco{ height:26px; width:auto; }
/* The organiser column sits on the wrap's right edge, so its right-aligned
   content lines up with the social icons in the bar below. */
.footer__grid > :last-child{ text-align:right; }
.footer__grid > :last-child .footer__venco{ display:inline-block; }
.footer__bar{
  display:flex; align-items:center; justify-content:space-between; gap:1.5rem; flex-wrap:wrap;
  /* The export leaves 56px between the rule and the copyright/social ink; the
     even 1.9rem was giving 35. Below the row stays as it was -- the footer's own
     bottom padding carries the tail space. */
  padding:clamp(2.2rem,3.4vw,3.2rem) 0 1.9rem; border-top:1px solid rgba(255,255,255,.14);
}
.footer__cp{ font-size:.9375rem; color:rgba(255,255,255,.8); }
.social{ display:flex; gap:1.5rem; align-items:center; margin:-7px; }
/* The glyphs are 17-20px. Padding cancelled by an equal negative margin on the
   row grows the tap target past the 24px minimum without moving anything. */
.social a{
  display:inline-flex; padding:7px; opacity:.9;
  transition:opacity .2s, transform .2s, color .2s;
}
.social a:hover{ opacity:1; color:var(--lime); transform:translateY(-2px); }

/* ---------- 22. LIGHTBOX ------------------------------------------------- */
.lightbox{
  position:fixed; inset:0; z-index:110; display:grid; place-items:center; padding:clamp(1rem,4vw,3rem);
  background:rgba(3,33,30,.92); opacity:0; visibility:hidden;
  transition:opacity .3s, visibility 0s linear .3s;   /* see .modal: focusable immediately */
}
.lightbox.is-open{ opacity:1; visibility:visible; transition:opacity .3s, visibility 0s linear 0s; }
.lightbox img{ max-width:100%; max-height:86vh; object-fit:contain; }
.lightbox__video{ width:min(1280px,100%); max-height:86vh; aspect-ratio:16/9; background:#000; outline:none; }
.lightbox.is-video .lightbox__nav{ display:none; }
.lightbox__x{ position:absolute; top:1.2rem; right:1.4rem; width:44px; height:44px; display:grid; place-items:center; color:#fff; border:1px solid rgba(255,255,255,.3); }
.lightbox__x:hover{ background:#fff; color:var(--ink); }
.lightbox__nav{ position:absolute; top:50%; transform:translateY(-50%); width:52px; height:52px; display:grid; place-items:center; color:#fff; border:1px solid rgba(255,255,255,.3); }
.lightbox__nav:hover{ background:#fff; color:var(--ink); }
.lightbox__nav--p{ left:clamp(.6rem,2vw,2rem); }
.lightbox__nav--n{ right:clamp(.6rem,2vw,2rem); }

/* ---------- 23. REVEALS -------------------------------------------------- */
.rv{ opacity:0; transform:translateY(22px); transition:opacity .7s var(--ease-out), transform .7s var(--ease-out); }
.rv.is-in{ opacity:1; transform:none; }
.rv-d1{ transition-delay:.08s; } .rv-d2{ transition-delay:.16s; }
.rv-d3{ transition-delay:.24s; } .rv-d4{ transition-delay:.32s; }

@media (prefers-reduced-motion:reduce){
  .rv{ opacity:1; transform:none; transition:none; }
  .gather .w{ opacity:1; transform:none; transition:none; }
  .img-reveal .lqip{ transition:none; }
  html.js .header__logo{ animation:none; }
  .handover__stage{ min-height:0; }
  *,*::before,*::after{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

/* ---------- 24. RESPONSIVE ----------------------------------------------- */
@media (max-width:1180px){
  /* stacked section: put the details and the map beside each other in the body */
  .venue__body{ display:grid; grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr); column-gap:clamp(1.6rem,4vw,3.2rem); align-items:start; }
  .venue__body .eyebrow,.venue__t{ grid-column:1 / -1; }
  .venue__body dl{ grid-column:1; grid-row:3; }
  .venue__map{ grid-column:2; grid-row:3; margin-top:0; }
  .venue__map img{ max-width:none; }
  .venue__link{ grid-column:2; grid-row:4; justify-self:start; margin-top:1rem; }
  .sgrid{ grid-template-columns:repeat(4,minmax(0,1fr)); }
  .venue__grid{ grid-template-columns:1fr; }
  .venue__fig{ min-height:320px; }
  .venue__body{ padding-bottom:clamp(2.4rem,5.4vw,5.4rem); }   /* stacked: nothing below to align to */
  .scard__fig{ border-radius:0 0 48px 0; }
}
@media (max-width:1024px){
  .header__nav{ display:none; }
  .header__inner{ display:flex; }
  /* The 44x44 hit area is flush with the gutter, but its 22px glyph is
     centred in it, so the bars sat 11px short of everything they line up
     with -- the drawer's links and its button. Pulling the button out by
     that (44-22)/2 puts the glyph on the same right edge and leaves the
     tap target its full size. */
  .header__burger{ display:grid; place-items:center; margin-left:auto; margin-right:-11px; width:44px; height:44px; }
  .header__burger span{ display:block; width:22px; height:2px; background:#fff; position:relative; transition:background-color .2s; }
  .header__burger span::before,.header__burger span::after{
    content:''; position:absolute; left:0; width:22px; height:2px; background:#fff; transition:transform .28s var(--ease);
  }
  .header__burger span::before{ top:-7px; } .header__burger span::after{ top:7px; }
  .header.is-light .header__burger span,
  .header.is-light .header__burger span::before,
  .header.is-light .header__burger span::after{ background:var(--ink-3); }
  .header__burger[aria-expanded="true"] span,
  .header.is-light .header__burger[aria-expanded="true"] span{ background:transparent; }
  .header__burger[aria-expanded="true"] span::before{ transform:translateY(7px) rotate(45deg); background:#fff; }
  .header__burger[aria-expanded="true"] span::after{ transform:translateY(-7px) rotate(-45deg); background:#fff; }
  .header .btn{ display:none; }

  .hero__head{ grid-template-columns:1fr; align-items:start; }
  .hero__meta{ text-align:left; }
  .hero__actions{ justify-content:flex-start; }

  .slab__grid{ grid-template-columns:1fr; justify-items:start; }
  .slab__body{ max-width:none; }
  .about__grid,.highlights__head,.sponsors__head,.register__head{ grid-template-columns:1fr; }
  .rgrid{ grid-template-columns:1fr; }
  /* -- tablet band: stack what was squeezed side-by-side -- */
  .handover__grid{ grid-template-columns:1fr; gap:clamp(1.6rem,3vw,2.4rem); }
  .handover__stage{ min-height:0; padding-block:clamp(3rem,6vw,5rem); }
  .handover__d{ max-width:60ch; }
  .xgrid,.xgrid--b{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .xgrid > .xcard:nth-child(3){ grid-column:1 / -1; }
  .xcard,.xgrid--b .xcard{ min-height:0; padding:clamp(1.4rem,3.4vw,40px); }
  .xcard__ghost{ width:clamp(96px,14vw,140px); }
  .arow{ grid-template-columns:64px minmax(0,1fr); gap:.5rem 1.2rem; }
  .arow__d{ grid-column:2; }
  .schedule__grid{ grid-template-columns:minmax(0,1fr); }
  .hero__slot{ aspect-ratio:auto; min-height:clamp(360px,88vw,560px); }
  .hero__band .band__t{ font-size:clamp(2rem,9vw,3.4rem); }
  .schedule__aside{ position:static; margin-bottom:clamp(1.8rem,4vw,2.6rem); }
  .schedule__seal{ display:none; }
  .schedule{ padding-top:clamp(3rem,6vw,5rem); padding-bottom:clamp(3.5rem,8vw,7rem); }
  .schedule__d{ max-width:44ch; }
  .track__btn{ padding:22px 22px 22px 22px; column-gap:24px; }
  /* Tracker under the number box, cards on the heading: box centres on 50
     and the heading starts at 101, so a 44 indent centres the 12px dot and
     a 45 gutter lands the card. Same reasoning as the phone rule. */
  .track__list{ padding:8px 22px 22px 44px; }
  .tl__row{ grid-template-columns:12px minmax(0,1fr); column-gap:45px; }
  .tl__card{ padding:18px 18px 16px; column-gap:18px; }
  .footer__grid{ grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
  .footer__grid > :last-child{ text-align:left; }


  /* Handover falls back to a swipeable rail */
  .handover__stage{ min-height:0; }
  .handover__grid{ grid-template-columns:1fr; }
  .handover__viewport{ overflow-x:auto; scroll-snap-type:x mandatory; -webkit-overflow-scrolling:touch; }
  .handover__viewport::-webkit-scrollbar{ height:0; }
  .handover__track{ transform:none !important; }
  .hcard{ scroll-snap-align:start; }
}
@media (max-width:820px){
  :root{ --header-h:64px; }
  .sgrid{ grid-template-columns:repeat(3,minmax(0,1fr)); }
  .xgrid,.xgrid--b{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  /* Highlights gallery: a horizontal snap rail that bleeds to the screen
     edges, instead of three stacked tiles. */
  .gal{
    display:flex; gap:12px; overflow-x:auto; scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch; scrollbar-width:none;
    margin-inline:calc(-1 * var(--gutter)); padding-inline:var(--gutter);
    scroll-padding-inline:var(--gutter);   /* snap to the gutter, not the screen edge */
  }
  .gal::-webkit-scrollbar{ display:none; }
  .gal button{ flex:0 0 min(78vw,420px); scroll-snap-align:start; }
  .galwrap{ margin-top:12px; }
  .gal__nav{ display:none; }
  .arow{ grid-template-columns:60px 1fr; gap:.6rem 1rem; }
  .arow__d{ grid-column:2; }
  .stats{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:1.6rem 0; position:static; margin-top:-1px; background:var(--ink); }
  .figstats img{ aspect-ratio:4/3; }
  .fields{ grid-template-columns:1fr; }
    .track__btn{ grid-template-columns:44px minmax(0,1fr) 32px; gap:1rem; padding:18px; align-items:start; }
  .track__i{ margin-top:2px; }
  .track__n{ width:44px; height:44px; font-size:1.05rem; }
  .track__i{ width:32px; height:32px; }
  .track__i::before,.track__i::after{ width:14px; }
  .track__h{ font-size:1.0625rem; line-height:1.2; }
  .track__m{ font-size:.875rem; line-height:1.4; margin-top:5px; }
  .track__time{ display:block; font-weight:500; color:#1A413C; }
  .track__strap{ display:block; margin-top:2px; }
  .track__strap::before{ content:none; }
  .track__list{ padding:4px 14px 16px 36px; }   /* box centres on 41, heading at 79 */
  .tl__row{ grid-template-columns:10px minmax(0,1fr); column-gap:33px; }
  .tl__mark::before{ width:10px; height:10px; }
  .tl__mark::after{ left:5px; top:14px; }
  .tl__card{ grid-template-columns:1fr; padding:14px 14px 12px; }
  .tl__time{ flex-direction:row; align-items:baseline; gap:10px; margin-bottom:10px; }
  .tl__time small{ margin-top:0; }
  .tl__t{ font-size:1rem; }
  .tl__meta{ margin-top:8px; font-size:.875rem; }
  .tl__people{ margin-top:16px; margin-bottom:0; }
  .footer__grid{ grid-template-columns:1fr; }
  .scard__fig{ border-radius:0 0 36px 0; }
}
@media (max-width:600px){
  .venue__body{ display:block; }
  .venue__map{ margin-top:clamp(1.8rem,3.2vw,2.8rem); }
  .venue__map img{ max-width:477px; }
  .vrow{ grid-template-columns:84px minmax(0,1fr); gap:.9rem; }
  .venue__body{ padding-inline:var(--gutter); }
  .sgrid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .xgrid,.xgrid--b{ grid-template-columns:1fr; }
  .hero__actions .btn,.closing__a .btn{ flex:1 1 100%; }
  .slogo{ flex-basis:156px; height:84px; padding:1rem; }
  .slogo img{ max-height:40px; max-width:118px; }
  .marquee__track{ gap:14px; }
  .hcard{ flex-basis:min(80vw,320px); }
  .scard__fig{ border-radius:0 0 28px 0; }
}

/* ---------- 25. PRINT ---------------------------------------------------- */
@media print{
  .header,.progress,.drawer,.marquee,.lightbox,.modal,.strip{ display:none !important; }
  body{ background:#fff; color:#000; }
  .handover__stage{ min-height:0; }
  .handover__track{ transform:none !important; flex-wrap:wrap; }
}

/* ==========================================================================
   26. FIGMA-EXACT TYPE + COLOUR
   Decoded from "REMA website.fig" (canvas 1512 x 17886) by parsing the Kiwi
   document, so every value below is the authored one rather than a guess.
   Sizes are px at the 1512 frame, expressed as clamp(min, size/15.12 vw, max).
   ========================================================================== */

/* ---- Header ---- */
.header__nav a{ font-family:var(--body); font-weight:500; font-size:clamp(.875rem,.99vw,15px); }
.header .btn{ font-family:var(--body); font-weight:600; font-size:clamp(.875rem,1.06vw,16px); letter-spacing:0; }

/* ---- Hero: Nohemi SemiBold 100/120, sub 24/28, date DM Sans SemiBold 28 ---- */
.hero__title{ font-weight:600; font-size:clamp(2.75rem,6.61vw,100px); line-height:1.2; letter-spacing:0; color:var(--paper); }
.hero__sub{ font-size:clamp(1rem,1.59vw,24px); line-height:1.17; color:#fff; }
.hero__date{ font-family:var(--body); font-weight:600; font-size:clamp(1.25rem,1.85vw,28px); line-height:1.2; }
.hero__where{ font-size:clamp(.875rem,1.06vw,16px); line-height:1.5; color:#fff; }
.hero__actions .btn{ font-weight:600; font-size:clamp(.9375rem,1.19vw,18px); letter-spacing:-.04em; }

/* ---- Opening band: Nohemi Bold 80/140.4 ls 2%; sub Nohemi Regular 24 ---- */
.band__t{ font-weight:700; font-size:clamp(2.25rem,5.29vw,80px); line-height:1.1; letter-spacing:.02em; }
.band__d{ font-family:var(--display); font-weight:400; font-size:clamp(1rem,1.59vw,24px); letter-spacing:.02em; }

/* ---- Seal slab: Nohemi Bold 56/70 ls 2%; body DM Sans 20/36 ---- */
.slab__t{ font-weight:700; font-size:clamp(1.75rem,3.70vw,56px); line-height:1.25; letter-spacing:.02em; max-width:14ch; }
.slab__d{ margin-top:clamp(1.5rem,2.9vw,44px); font-size:clamp(1rem,1.32vw,20px); line-height:1.8; max-width:34ch; color:#fff; }
.slab__d p + p{ margin-top:clamp(1.1rem,1.85vw,28px); }

/* ---- Handover ---- */
.handover__t{ font-weight:600; font-size:clamp(1.75rem,3.70vw,56px); line-height:1.25; letter-spacing:.02em; color:var(--lime); max-width:clamp(260px,33.1vw,500px); }
.handover__d{ font-family:var(--body); font-weight:500; font-size:clamp(1rem,1.32vw,20px); line-height:1.8; letter-spacing:-.01em; color:#fff; max-width:clamp(280px,32.4vw,490px); }
.handover__d strong{ color:var(--lime); font-weight:600; }
.hcard__label{ font-weight:700; font-size:clamp(1.2rem,2.65vw,40px); line-height:1.1; letter-spacing:.03em; }
.hcard__body p{ font-size:clamp(.95rem,1.59vw,24px); line-height:1.5; letter-spacing:-.02em; }
.hcard__n{ font-weight:300; font-size:clamp(2.4rem,4.23vw,64px); letter-spacing:.03em; }

/* ---- About + stats ---- */
.about__t{ font-weight:700; font-size:clamp(1.75rem,2.91vw,44px); line-height:1.36; letter-spacing:.02em; color:#0E3F3A; max-width:15ch; }
.about__copy{ font-size:clamp(1rem,1.32vw,20px); line-height:1.6; color:#092F2B; }
.about .btn{ font-weight:600; font-size:clamp(.9375rem,1.19vw,18px); letter-spacing:-.04em; }
.stat__n{ font-weight:500; font-size:clamp(2rem,4.23vw,64px); line-height:1; }
.stat__l{ font-family:var(--body); font-weight:500; font-size:clamp(.875rem,1.19vw,18px); line-height:1.33; }

/* ---- Experience ---- */
.experience__t{ font-weight:600; font-size:clamp(1.75rem,3.17vw,48px); line-height:1.458; letter-spacing:.02em; color:#0E3F3A; }
.xcard__t{ font-weight:500; font-size:clamp(1.25rem,2.38vw,36px); line-height:1.1; letter-spacing:0; }
.xcard__d{ font-size:clamp(.9375rem,1.19vw,18px); line-height:1.556; letter-spacing:-.02em; }

/* ---- Audience: heading lime; rows Nohemi 40/56 ---- */
.audience .eyebrow{ font-weight:600; font-size:clamp(.8125rem,1.32vw,20px); letter-spacing:.3em; color:#fff; }
.audience__t{ font-weight:600; font-size:clamp(1.75rem,3.70vw,56px); line-height:1.25; letter-spacing:.02em; color:var(--lime); max-width:20ch; }
.arow__n{ font-family:var(--display); font-weight:300; font-size:clamp(1.25rem,2.65vw,40px); line-height:1.4; color:#fff; }
.arow__t{ font-weight:500; font-size:clamp(1.25rem,2.65vw,40px); line-height:1.4; letter-spacing:0; }
.arow__d{ font-size:clamp(.9375rem,1.32vw,20px); line-height:1.4; letter-spacing:-.01em; color:rgba(255,255,255,.6); }
.arow:hover .arow__t,.arow:hover .arow__n{ color:var(--lime); }

/* ---- Speakers ---- */
.speakers .eyebrow{ font-weight:600; font-size:clamp(.75rem,1.06vw,16px); letter-spacing:.3em; color:#858F8D; }
.speakers__t{ font-weight:600; font-size:clamp(1.6rem,2.91vw,44px); line-height:1.27; letter-spacing:.02em; color:#0E3F3A; }
.scard__tag{ font-family:var(--body); font-weight:500; font-size:clamp(.625rem,.79vw,12px); letter-spacing:-.02em; color:#0D2F2B; }
.scard__name{ font-family:var(--display); font-weight:500; font-size:clamp(.9375rem,1.19vw,18px); line-height:1.3; color:#0C2926; }
.scard__role{ font-family:var(--body); font-weight:500; font-size:clamp(.8125rem,.99vw,15px); line-height:1.3; color:var(--grass); }
.speakers__more .btn{ font-weight:600; font-size:clamp(.9375rem,1.19vw,18px); letter-spacing:-.02em; }

/* ---- Schedule ---- */
/* schedule type now lives in section 16, measured off "Event Schedule.svg" */

/* ---- Highlights ---- */
.highlights .eyebrow{ font-weight:600; font-size:clamp(.75rem,1.06vw,16px); letter-spacing:.3em; color:#858F8D; }
.highlights__t{ font-weight:600; font-size:clamp(1.75rem,3.17vw,48px); line-height:1.25; letter-spacing:0; color:#0E3F3A; }
.highlights .lede{ font-size:clamp(.9375rem,1.19vw,18px); line-height:1.67; letter-spacing:-.01em; color:#092F2B; }
.reel__play{ font-weight:600; font-size:clamp(.875rem,1.06vw,16px); letter-spacing:-.04em; }

/* ---- Sponsors ---- */
.sponsors__t{ font-weight:600; font-size:clamp(1.75rem,3.17vw,48px); line-height:1.458; letter-spacing:0; color:#fff; }
.sponsors__d{ font-size:clamp(1rem,1.32vw,20px); line-height:1.6; letter-spacing:-.01em; }
.sponsors .btn{ font-weight:600; font-size:clamp(.9375rem,1.19vw,18px); letter-spacing:-.04em; }

/* ---- Register ---- */
.register__t{ font-weight:600; font-size:clamp(1.75rem,3.31vw,50px); line-height:1.4; letter-spacing:0; color:#0E3F3A; }
.register__d{ font-size:clamp(1rem,1.32vw,20px); line-height:1.6; letter-spacing:-.01em; color:#0E3F3A; }
.rform__t{ font-weight:600; font-size:clamp(1.35rem,2.12vw,32px); letter-spacing:.03em; color:#1A413C; }
.rform__d{ font-family:var(--body); font-weight:500; font-size:clamp(.875rem,1.06vw,16px); line-height:1.5; letter-spacing:-.02em; color:#414645; }
.field label{ font-weight:500; font-size:clamp(.8125rem,.99vw,15px); color:#1A413C; }
.field input,.field select{ font-weight:500; font-size:clamp(.875rem,1.06vw,16px); letter-spacing:-.02em; }
.rform .btn{ font-weight:600; font-size:clamp(.9375rem,1.19vw,18px); }
.rform__fine{ font-size:clamp(.875rem,1.06vw,16px); line-height:1.5; letter-spacing:-.02em; color:#414645; }
.ticket__brand{ font-weight:700; font-size:clamp(1.05rem,1.59vw,24px); letter-spacing:.03em; color:#FAFEF5; }
.ticket__t{ font-weight:800; font-size:clamp(1.6rem,3.70vw,56px); line-height:1.1; letter-spacing:.03em; color:var(--lime); }
.ticket__s{ font-family:var(--body); font-weight:500; font-size:clamp(.8125rem,1.06vw,16px); letter-spacing:-.03em; color:#FAFEF5; }
.trow{ font-size:clamp(.8125rem,1.06vw,16px); }
.trow dt{ font-weight:500; color:rgba(255,255,255,.4); }
.trow dd{ font-weight:600; }
.ticket__stub{ font-weight:700; font-size:clamp(.75rem,1.06vw,16px); letter-spacing:.03em; color:#1B6B62; }

/* ---- Venue ---- */
.venue .eyebrow{ font-weight:600; font-size:clamp(.8125rem,1.32vw,20px); letter-spacing:.3em; color:#fff; }
.venue__t{ font-weight:600; font-size:clamp(1.75rem,3.31vw,50px); line-height:1.4; letter-spacing:0; color:var(--grass); }
.vrow dt{ font-family:var(--body); font-weight:300; font-size:clamp(.8125rem,1.06vw,16px); letter-spacing:.1em; color:#fff; }
.vrow b{ font-weight:500; font-size:clamp(1.05rem,1.85vw,28px); line-height:1.3; letter-spacing:0; }
.vrow small{ font-size:clamp(.875rem,1.06vw,16px); line-height:1.75; letter-spacing:-.01em; color:#fff; }
.venue__link{ font-weight:500; font-size:clamp(1rem,1.59vw,24px); letter-spacing:0; color:#81908E; }

/* ---- Closing ---- */
.closing__t{ font-weight:600; font-size:clamp(2.25rem,5.29vw,80px); line-height:1.25; letter-spacing:0; max-width:13ch; }
.closing__d{ font-size:clamp(1rem,1.32vw,20px); line-height:1.6; letter-spacing:-.01em; }
.closing__a .btn{ font-weight:600; font-size:clamp(.9375rem,1.19vw,18px); letter-spacing:-.04em; }

/* ---- Footer ---- */
.footer__d{ font-size:clamp(.8125rem,.99vw,15px); line-height:1.47; letter-spacing:-.01em; color:#fff; }
.footer h4{ font-weight:400; font-size:clamp(.8125rem,.99vw,15px); line-height:1.6; color:#43736F; }
.footer__links a{ font-weight:500; font-size:clamp(.8125rem,.99vw,15px); line-height:1.6; }
.footer__cp{ font-weight:500; font-size:clamp(.8125rem,.99vw,15px); line-height:1.6; }

/* ---------- 27. MOTION POLISH --------------------------------------------
   One layer of consistent motion over every section: the same lift on hover
   for every card-like thing, the same easing, and reveals for the lists that
   had none (tracks, audience rows, venue rows, stats, footer columns) with a
   small stagger. Everything here is a transform/opacity/colour transition, so
   the global reduced-motion rule in section 23 switches it all off.         */
:root{ --lift:translateY(-4px); --lift-sm:translateY(-2px); --shadow-lift:0 14px 34px -18px rgba(3,33,30,.45); }

/* -- buttons: settle on press, gentle shadow on lift -- */
.btn{ transition:transform .25s var(--ease-out), background-color .25s, color .25s, border-color .25s, box-shadow .25s; }
.btn:hover{ box-shadow:var(--shadow-lift); }
.btn:active{ transform:translateY(0) scale(.98); box-shadow:none; transition-duration:.08s; }
.header__logo{ transition:opacity .2s, width .45s var(--ease); } .header__logo:hover{ opacity:.82; }

/* -- experience cards -- */
.xcard{ transition:transform .45s var(--ease-out), box-shadow .45s var(--ease-out), opacity .7s var(--ease-out); }
.xcard__ghost{ transition:opacity .5s var(--ease); }
.xcard__icon{ transition:transform .45s var(--ease-out); }
.xcard:hover{ transform:var(--lift); box-shadow:var(--shadow-lift); }
.xcard:hover .xcard__ghost{ opacity:.11; }
.xcard:hover .xcard__icon{ transform:translateY(-3px); }

/* -- handover cards + dots -- */
.hcard{ transition:transform .45s var(--ease-out), box-shadow .45s var(--ease-out); }
.hcard:hover{ transform:var(--lift); box-shadow:0 18px 40px -20px rgba(0,0,0,.6); }
.handover__dots button{ transition:background-color .3s, transform .3s var(--ease-out); }
.handover__dots button:hover{ background:rgba(255,255,255,.6); transform:scaleY(1.6); }
.handover__dots button[aria-current="true"]:hover{ background:var(--lime-m); }

/* -- audience rows: the base rules' shift + colour change on hover are enough (no rule line) -- */

/* -- speakers -- */
.scard{ transition:transform .45s var(--ease-out); }
.scard:hover{ transform:var(--lift); }
.scard__name{ transition:color .25s; } .scard:hover .scard__name{ color:var(--forest); }
.filter{ transition:background-color .25s, color .25s, border-color .25s, transform .25s var(--ease-out); }
.filter:hover{ background:#F0F7EA; transform:var(--lift-sm); }
.filter[aria-pressed="true"]:hover{ background:var(--forest); }

/* -- schedule -- */
.track{ transition:border-color .25s, box-shadow .35s var(--ease-out), transform .7s var(--ease-out), opacity .7s var(--ease-out); }
.track:hover{ border-color:#CFD9CE; box-shadow:var(--shadow-lift); }
.track__btn{ cursor:pointer; }
.track__i{ transition:background-color .25s, border-color .25s; }
.track:hover .track__i{ background:var(--lime); border-color:var(--lime); }
.tl__card{ transition:border-color .25s, box-shadow .3s var(--ease-out); }
.tl__card:hover{ border-color:#CFD9CE; box-shadow:0 8px 22px -14px rgba(3,33,30,.35); }
.pchip{ transition:background-color .2s, border-color .2s, transform .25s var(--ease-out); }
button.pchip:hover{ transform:var(--lift-sm); }
@keyframes list-in{ from{ opacity:0; transform:translateY(10px); } to{ opacity:1; transform:none; } }
.track[open] .tl__row{ animation:list-in .5s var(--ease-out) both; }
.track[open] .tl__row:nth-child(2){ animation-delay:.06s; } .track[open] .tl__row:nth-child(3){ animation-delay:.12s; }
.track[open] .tl__row:nth-child(4){ animation-delay:.18s; } .track[open] .tl__row:nth-child(5){ animation-delay:.24s; }

/* -- highlights + sponsors -- */
.gal button{ transition:transform .6s var(--ease-soft), box-shadow .6s var(--ease-soft); }
.gal button:hover{ transform:var(--lift); box-shadow:var(--shadow-lift); }
.reel__play{ transition:transform .5s var(--ease-soft), background-color .3s var(--ease-soft), box-shadow .3s var(--ease-soft); }
.reel:hover .reel__play{ transform:translateX(4px); }
.slogo{ transition:transform .4s var(--ease-out), box-shadow .4s var(--ease-out); }
.slogo:hover{ transform:translateY(-3px); box-shadow:0 14px 30px -16px rgba(0,0,0,.55); }

/* -- register form -- */
.field input,.field select{ transition:border-color .2s, box-shadow .2s, background-color .2s; }
.field input:hover,.field select:hover{ border-color:var(--forest); }

/* -- venue + stats + footer -- */
.vrow{ transition:background-color .25s; }
.vrow b{ transition:color .25s; } .vrow dt{ transition:color .25s; }
.vrow:hover b{ color:var(--lime); } .vrow:hover dt{ color:rgba(255,255,255,.85); }
.stat__n{ transition:transform .35s var(--ease-out); }
.stat:hover .stat__n{ transform:translateY(-3px); }
.footer__links a{ display:table; background:linear-gradient(currentColor,currentColor) no-repeat 0 100% / 0 1px; transition:color .2s, background-size .3s var(--ease-out); }   /* table: own line, shrink-to-fit so the underline is text-width */
.footer__links a:hover{ background-size:100% 1px; }

/* -- overlays: content eases in with the backdrop -- */
.lightbox img,.lightbox__video{ transform:scale(.97); transition:transform .35s var(--ease-out); }
.lightbox.is-open img,.lightbox.is-open .lightbox__video{ transform:none; }

/* -- reveals for the lists that had none: same fade/rise as .rv, staggered -- */
.track,.arow,.vrow,.stat,.footer__grid > *{ opacity:0; transform:translateY(18px); }
.track.is-in,.arow.is-in,.vrow.is-in,.stat.is-in,.footer__grid > .is-in{ opacity:1; transform:none; }
.arow,.vrow,.stat,.footer__grid > *{ transition:opacity .7s var(--ease-out), transform .7s var(--ease-out), background-color .25s, color .25s, padding-left .35s var(--ease); }
.track:nth-child(2),.arow:nth-child(2),.vrow:nth-child(2),.stat:nth-child(2),.footer__grid > :nth-child(2){ transition-delay:.06s; }
.track:nth-child(3),.arow:nth-child(3),.vrow:nth-child(3),.stat:nth-child(3),.footer__grid > :nth-child(3){ transition-delay:.12s; }
.track:nth-child(4),.arow:nth-child(4),.vrow:nth-child(4),.stat:nth-child(4){ transition-delay:.18s; }
.track:nth-child(5),.arow:nth-child(5){ transition-delay:.24s; } .track:nth-child(6),.arow:nth-child(6){ transition-delay:.3s; }
.arow:nth-child(7){ transition-delay:.36s; } .arow:nth-child(8){ transition-delay:.42s; }
html:not(.js) .track,html:not(.js) .arow,html:not(.js) .vrow,html:not(.js) .stat,html:not(.js) .footer__grid > *{ opacity:1; transform:none; }
/* hover lifts must not fight the reveal transform once revealed */
.track.is-in:hover{ transform:var(--lift-sm); }
@media (prefers-reduced-motion:reduce){
  .track,.arow,.vrow,.stat,.footer__grid > *{ opacity:1; transform:none; transition:none; }
  .track[open] .tl__row{ animation:none; }
  .xcard:hover,.hcard:hover,.scard:hover,.gal button:hover,.slogo:hover,.track.is-in:hover{ transform:none; }
}

/* Phones: the full wordmark drops to 30px so it clears the burger. */
@media (max-width:600px){
  .header__logo{ height:30px; width:min(245px, calc(100vw - var(--gutter)*2 - 64px)); }
  .header__logo img{ height:30px; }
  .header.is-scrolled .header__logo{ width:94px; }
}

/* ---------- 28. SMALL-SCREEN HERO + HANDOVER CARDS ------------------------
   These sit at the end on purpose: section 26's typography block re-declares
   font-size for .hero__title, .hero__date and .hcard__body p at the same
   specificity, so an override inside an earlier media block would lose to it
   on source order.                                                          */

/* Phone hero, per the supplied mock: lime headline and date, a rule between
   the tagline and the meta block, and a slightly larger headline than the
   shared clamp's floor was giving. */
@media (max-width:600px){
  .hero__title{ color:var(--lime); font-size:clamp(2.9rem,12.6vw,3.4rem); }
  .hero__date{ color:var(--lime); font-size:clamp(1.5rem,6.3vw,1.75rem); }
  .hero__meta{
    margin-top:clamp(1.5rem,5.6vw,2rem);
    padding-top:clamp(1.5rem,5.6vw,2rem);
    border-top:1px solid rgba(255,255,255,.16);
  }
}

/* Handover cards: min-height was clamp(420px,36.8vw,557px), and below 1141px
   the 420px floor took over — so a phone got a 420px card holding three lines
   of copy and ~200px of dead ground above the number. Sized to the content it
   actually carries instead, with the body text up a notch now that the card is
   no longer doing the work of filling the space. */
@media (max-width:1024px){
  .hcard{ min-height:clamp(300px,38vw,360px); }   /* enough that the 0N/ numeral clears the last line of copy */
  .hcard__body p{ font-size:clamp(1rem,1.9vw,1.0625rem); }
  .hcard__label{ font-size:clamp(1.25rem,4.6vw,1.6rem); }
}

/* ---------- 29. PHONE PASS ------------------------------------------------
   Tightening for the phone layout. Also at the end of the sheet: section 26
   re-declares font-size for most of these at equal specificity.            */
@media (max-width:600px){
  /* -- hero: close the vertical gaps, tagline on one line -- */
  .hero__head{ gap:1.1rem; }
  .hero__sub{ margin-top:.75rem; font-size:clamp(.7rem,3.6vw,1rem); }   /* 3.6vw is what keeps the tagline on one line: 13.5px at 375 measures 319 against 326 of column */
  .hero__meta{ margin-top:1.15rem; padding-top:1.15rem; }
  .hero__actions{ margin-top:1.15rem; gap:.6rem; }
  .hero__where{ margin-top:.3rem; }
  .hero__slot{ margin-top:1.6rem; }

  /* -- sub-copy runs the full column; the ch/px measures are desktop caps -- */
  .slab__t, .slab__d, .about__t, .about__d, .handover__t, .handover__d,
  .speakers__t, .highlights__t, .highlights .lede, .sponsors__t, .sponsors__d,
  .register__t, .register__d, .rform__d, .venue__t, .closing__t, .closing__d,
  .footer__d, .xcard__d, .aud__d{ max-width:none; }

  /* -- every standalone CTA fills the column, as the hero and closing already did.
        .reel__play is deliberately out: it sits on the photo, not in the flow. -- */
  .about .btn, .speakers__more .btn, .sponsors .btn, .rform .btn{ width:100%; }

  /* -- highlights: the preview was 326x177 with a 204px button across 63% of it.
        Taller frame, smaller button. -- */
  .reel img{ aspect-ratio:3/2; }
  .reel__play{ font-size:.8125rem; padding:.6rem 1rem; min-height:42px; gap:.45rem; }
  .reel__play svg{ width:16px; height:16px; }

  /* -- narrower rails so the next card/photo peeks in and reads as scrollable -- */
  .gal button{ flex:0 0 min(64vw,300px); }
  .hcard{ flex-basis:min(70vw,300px); }
}

/* ---------- 31. PHONE: STATS, SCHEDULE ALIGNMENT, FOOTER ------------------ */

/* The badge only ever shows on phones; display:none keeps exactly one of the
   two marks in the accessibility tree at any width. */
.footer__badge{ display:none; }

@media (max-width:600px){

  /* -- Stats: a flat 2x2 of numbers under the photo read as an afterthought.
        Hairline gutters turn the gap itself into a rule, each cell picks up the
        dark ground and the dot grid, and a lime edge ties the block to the
        photo above it. -- */
  .stats{
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:1px; background:rgba(255,255,255,.13);
    border-top:2px solid var(--lime);
  }
  .stat{
    background-color:var(--ink);
    background-image:var(--dot-grid);
    background-size:var(--dot-size);
    background-position:-3px -4px;
    padding:clamp(1.2rem,5.3vw,1.75rem) .6rem;
  }
  .stat__n{ font-size:clamp(2.1rem,9.3vw,2.75rem); }
  .stat__l{ margin-top:.4rem; font-size:clamp(.8125rem,3.4vw,.9375rem); color:rgba(255,255,255,.72); }

  /* -- Schedule: the tracker ran down x=20 while the number box centres on 41,
        and the session cards began at 37 against a heading at 79. The dot is
        10px at left:0 of its column, so a 36px indent centres it under the box,
        and a 33px gutter starts the cards on the heading. -- */

  /* -- Footer, to the supplied mock. It is a 2x render of a 393px screen --
        the Venco mark measures 330px there against its natural 165px -- so every
        figure below is that image halved, expressed in vw off 393 so it tracks:
        seal 182 (46.3vw), copy 15.5, links 16 on a 43 pitch, h4 14 with 35
        under it, 41 of padding inside each block, socials 20px on a 48 pitch,
        53 between the copyright and the icons, 70 above the seal. -- */
  .footer__grid{ gap:0; padding-top:clamp(2.8rem,17.8vw,5rem); padding-bottom:0; }   /* the last block's own padding already sits above the bar rule; the grid's 40px floor was pushing it 40 low */
  .footer__grid > *{ text-align:center; padding-block:clamp(1.6rem,8.6vw,2.4rem); }
  .footer__grid > :last-child{ text-align:center; }   /* the :last-child rules above are (0,2,0) and outrank the line above */
  .footer__grid > * + *{ border-top:1px solid rgba(255,255,255,.14); }
  .footer__grid > :first-child{ padding-top:0; }
  .footer__logo{ display:none; }
  .footer__badge{ display:block; margin-inline:auto; height:clamp(140px,46.3vw,190px); width:auto; }
  .footer__d{ margin-inline:auto; margin-top:clamp(1.5rem,8vw,2.4rem); font-size:clamp(.875rem,3.94vw,1.0625rem); line-height:1.55; }
  .footer h4{ font-size:clamp(.8125rem,3.6vw,1rem); margin-bottom:clamp(.6rem,3vw,1rem); }   /* the link's own padding carries the rest of the 43 to the first item */
  .footer__links a{ margin-inline:auto; font-size:clamp(.9375rem,4.07vw,1.0625rem); padding-block:clamp(.4rem,2.2vw,.7rem); }
  .footer__venco{ display:block; margin-inline:auto; }   /* explicit centring rather than relying on the inherited text-align */
  .footer__bar{ flex-direction:column; align-items:center; text-align:center; gap:clamp(1.6rem,13.5vw,3.4rem); }
  .footer__cp{ font-size:clamp(.875rem,3.8vw,1rem); }
  .social{ gap:clamp(1.4rem,7.1vw,2rem); }
  .social svg{ width:20px; height:20px; }
}

/* ---------- 32. MODAL STACKS ONLY ON PHONES -------------------------------
   These used to live in the 1024 block. At 820 the 4/3 figure took 578 of the
   panel's 645, leaving 67px for the bio -- the speaker's details were simply
   off the bottom. Tablets are wide enough for the two-column panel, so the
   stack now waits until 700.                                                */
@media (max-width:700px){
  .modal__panel{ grid-template-columns:1fr; grid-template-rows:auto minmax(0,1fr); height:min(645px,92vh); }
  /* Stacked: the card's per-speaker placement (--pl/--pt/--pw) is for the
     tall portrait box and pushes wide-placed portraits out of a landscape
     frame -- so here the photo just covers a 4/3 frame, anchored to the top. */
  .modal__fig{ aspect-ratio:4/3; height:auto; border-radius:0; }
  .modal__fig img{ left:0; top:0; width:100%; height:100%; object-fit:cover; object-position:center 12%; }
  .modal__body{ padding:1.6rem 1.4rem 1.8rem; }
  .modal__name{ font-size:clamp(1.4rem,5vw,2rem); padding-right:56px; }
  .modal__role{ font-size:clamp(1rem,3.4vw,1.35rem); margin-top:.5rem; }
  .modal__bio{ font-size:.95rem; margin-top:1.4rem; }
  .modal__foot{ padding-top:1.6rem; }
  .modal__foot::before{ margin-bottom:1.2rem; }
  .modal__session{ font-size:clamp(1.05rem,3.6vw,1.4rem); margin-top:.6rem; }
}

/* ---------- 33. TABLET PASS (701-1024) ------------------------------------
   The 1024 block collapses these to one column, which is right for a phone but
   wastes a tablet: at 820 a head block has ~740px to work with. Restored to the
   two-column split the desktop uses, with the copy caps lifted so headings run
   the width of their column instead of wrapping early. Sits at the end so it
   outranks section 26's typography block on source order.                    */
@media (min-width:701px) and (max-width:1024px){
  .hero__head{ grid-template-columns:1.32fr .88fr; align-items:end; }
  .hero__meta{ text-align:right; }
  .hero__actions{ justify-content:flex-end; }
  .about__grid,.highlights__head,.sponsors__head,.register__head{ grid-template-columns:1.28fr .72fr; }
  .footer__grid{ grid-template-columns:1.5fr 1fr 1fr; }
  .footer__grid > :last-child{ text-align:right; }

  /* Headings and copy fill their column; the ch/px measures are desktop caps. */
  .slab__t, .slab__d, .about__t, .about__d, .handover__t, .handover__d,
  .speakers__t, .highlights__t, .highlights .lede, .sponsors__t, .sponsors__d,
  .register__t, .register__d, .rform__d, .venue__t, .closing__d, .footer__d,
  .audience__t, .schedule__t, .schedule__d, .xcard__d, .aud__d{ max-width:none; }
  /* .closing__t keeps its 13ch: it is a centred statement, not a column of copy. */
}

/* ---------- 34. PHONE MOTION ----------------------------------------------
   A longer, softer entrance than the shared .rv, plus staggered cascades for
   the two card grids that had none, so a phone scroll has some rhythm.      */
@media (max-width:820px){
  .rv{ transform:translateY(30px) scale(.985); transition:opacity .8s var(--ease-out), transform .8s var(--ease-out); }
  .rv.is-in{ transform:none; }

  /* Experience cards are single-column here, so they cascade down the screen. */
  .xgrid > .xcard:nth-child(2), .xgrid--b > .xcard:nth-child(2){ transition-delay:.09s; }
  .xgrid > .xcard:nth-child(3), .xgrid--b > .xcard:nth-child(3){ transition-delay:.18s; }

  /* Speaker cards ride their grid's reveal rather than each being observed:
     one element on the observer, the cascade in CSS. cardIn is switched off
     here so the two mechanisms are not animating the same properties. */
  html.js .scard{ animation:none; opacity:0; transform:translateY(20px); transition:opacity .6s var(--ease-out), transform .6s var(--ease-out); }
  html.js .sgrid.is-in .scard{ opacity:1; transform:none; }
  html.js .sgrid.is-in .scard:nth-child(2){ transition-delay:.07s; }
  html.js .sgrid.is-in .scard:nth-child(3){ transition-delay:.14s; }
  html.js .sgrid.is-in .scard:nth-child(4){ transition-delay:.21s; }
  html.js .sgrid.is-in .scard:nth-child(5){ transition-delay:.28s; }
  html.js .sgrid.is-in .scard:nth-child(6){ transition-delay:.35s; }
}
@media (max-width:820px) and (prefers-reduced-motion:reduce){
  .rv{ transform:none; }
  html.js .scard{ opacity:1; transform:none; transition:none; }
}

/* ---------- 35. FOOTER: CLOSE UP THE PHONE GAPS --------------------------- */
@media (max-width:600px){
  .footer__grid{ padding-top:clamp(2.2rem,13.2vw,3.6rem); }
  .footer__grid > *{ padding-block:clamp(1.15rem,6.1vw,1.75rem); }
  .footer__d{ margin-top:clamp(1.1rem,5.6vw,1.7rem); }
  .footer__badge{ display:block; margin-inline:auto; width:clamp(126px,40vw,168px); height:auto; }
  .footer__bar{ gap:clamp(1.2rem,9vw,2.4rem); }
}

/* ---------- 36. DESKTOP-ONLY LINE BREAK ----------------------------------- */
/* .brk breaks from 900 up, which still splits headings across the tablet
   range. This one holds the line together until the desktop layout. */
.brk-lg{ display:none; }
@media (min-width:1025px){ .brk-lg{ display:inline; } }

/* ---------- 37. FLOATING REGISTER CTA (<=1024) ----------------------------
   Below 1024 the header's Register button is hidden and the nav lives behind
   the burger, so the primary action is two taps away. This keeps it one tap.
   It rises in once the hero is behind you and drops away over the register
   section and the footer, where it would only be repeating what is on screen. */
.fab{ display:none; }
@media (max-width:1024px){
  .fab{
    position:fixed; z-index:86;
    left:var(--gutter); right:var(--gutter); bottom:clamp(.9rem,3.2vw,1.4rem);
    display:flex; align-items:center; justify-content:center;
    min-height:54px; padding:.9rem 1.5rem;
    background:var(--lime); color:var(--ink-3);
    font-family:var(--body); font-weight:600; letter-spacing:0;
    font-size:clamp(.9375rem,4vw,1.0625rem);
    box-shadow:0 12px 30px -10px rgba(3,33,30,.55);
    opacity:0; transform:translateY(150%); pointer-events:none;
    transition:opacity .3s var(--ease), transform .45s var(--ease-out), background-color .2s;
  }
  .fab.is-in{ opacity:1; transform:none; pointer-events:auto; }
  .fab:active{ background:#b4ea54; }
  /* Anything that owns the screen takes it back. */
  body:has(.drawer.is-open) .fab,
  body:has(.modal.is-open) .fab,
  body:has(.lightbox.is-open) .fab{ opacity:0; transform:translateY(150%); pointer-events:none; }
}
@media (prefers-reduced-motion:reduce){ .fab{ transition:opacity .2s; transform:none; } .fab.is-in{ transform:none; } }

/* ---------- 38. PHONE: TIMELINE TIME MATCHES ITS LABEL -------------------- */
@media (max-width:600px){
  .tl__time b{ font-size:15px; }   /* was 18 against the 15px "Morning" beside it */
}

/* ---------- 40. PROGRAMME (schedule chapters + speaker directory) ---------
   The schedule keeps its existing look: a session is still a .track accordion
   with the numbered chip, the heading, the time/type meta line and the +/-
   icon, and it still expands into .track__panel. What is new is the chapter
   rail, the category chips, and the speaker rows inside the panel.
   Built from the site's own tokens -- no new colours, fonts or easing.      */

/* -- chapter rail: text navigation with the header nav's growing underline,
      not pill buttons. Scrolls sideways on a phone so it never wraps. -- */
.programme{ min-width:0; }
.prail{ min-width:0; margin-bottom:clamp(1.4rem,2.6vw,2.2rem); }
.pfilters{
  display:flex; gap:clamp(1rem,2.2vw,2rem); align-items:baseline;
  border-bottom:1px solid var(--line-f, #E7EBE2);
  overflow-x:auto; scrollbar-width:none; -webkit-overflow-scrolling:touch;
}
.pfilters::-webkit-scrollbar{ display:none; }
.pfilter{
  position:relative; flex:none; padding:0 0 .7rem; border:0; background:none; cursor:pointer;
  font-family:var(--body); font-weight:600; letter-spacing:.12em; text-transform:uppercase;
  font-size:clamp(.75rem,.93vw,.875rem); color:#818787;
  transition:color .25s var(--ease);
}
.pfilter::after{
  content:''; position:absolute; left:0; right:100%; bottom:-1px; height:2px;
  background:var(--forest); transition:right .3s var(--ease-out);
}
.pfilter:hover{ color:var(--ink-3); }
.pfilter[aria-selected="true"]{ color:var(--ink-3); }
.pfilter[aria-selected="true"]::after{ right:0; }
.pfilter:focus-visible{ outline:2px solid var(--forest); outline-offset:3px; }
.pempty{ padding:2.5rem 0; color:#5C6B69; font-size:clamp(.9375rem,1.19vw,1.0625rem); letter-spacing:-.02em; }

/* -- the meta line on the collapsed row. Understated: the title and the time
      stay the loudest things in the row. -- */
.pcount{
  font-family:var(--body); font-weight:500; font-size:clamp(.6875rem,.86vw,.8125rem);
  letter-spacing:-.02em; color:#818787;
}
.pcount + .pcount::before{ content:'·'; margin-right:.5rem; color:#C3CCC9; }

/* -- expanded panel: description, then the people -- */
.sdesc{
  margin:0 0 clamp(1.2rem,2.2vw,1.8rem);
  font-size:clamp(.9375rem,1.19vw,1.0625rem); line-height:1.65; letter-spacing:-.02em;
  color:#3F4E4C; max-width:66ch;
}
/* with the line-up held back the description is often the whole panel, and its
   bottom margin would stack with the panel's own padding */
.sdesc:last-child{ margin-bottom:0; }
.slabel{
  margin:0 0 .85rem; font-family:var(--body); font-weight:600;
  font-size:clamp(.6875rem,.8vw,.75rem); letter-spacing:.18em; text-transform:uppercase; color:#818787;
}
.slabel + .speople{ margin-bottom:clamp(1.2rem,2.2vw,1.8rem); }
.speople{ list-style:none; margin:0; padding:0; display:grid; gap:.5rem; grid-template-columns:repeat(2,minmax(0,1fr)); }
.sperson{
  width:100%; display:flex; align-items:center; gap:.85rem; text-align:left;
  padding:.55rem .7rem .55rem .55rem; border:.5px solid #E7EBE2; background:#fff; cursor:pointer;
  transition:border-color .25s, box-shadow .3s var(--ease-out), transform .3s var(--ease-out);
}
.sperson:hover{ border-color:#CFD9CE; box-shadow:0 8px 22px -14px rgba(3,33,30,.35); transform:var(--lift-sm); }
.sperson:focus-visible{ outline:2px solid var(--forest); outline-offset:2px; }
.sperson__fig{
  position:relative; flex:none; width:44px; aspect-ratio:1/1; overflow:hidden;
  background:var(--forest); border-radius:2px;
}
.sperson__fig img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center 18%; }
.sperson__txt{ min-width:0; display:flex; flex-direction:column; gap:.15rem; }
.sperson__n{ font-family:var(--body); font-weight:600; font-size:clamp(.875rem,1.06vw,1rem); color:var(--ink-3); line-height:1.25; }
.sperson__r{ font-size:clamp(.75rem,.93vw,.875rem); color:#818787; line-height:1.3; }

/* -- initials tile: the honest stand-in for a portrait we do not have. The
      motif already sitting behind .scard__fig does the decorative work. -- */
.mono__i{
  position:absolute; inset:0; z-index:2; display:grid; place-items:center;
  font-family:var(--display); font-weight:600; letter-spacing:.06em;
  color:rgba(255,255,255,.92); font-size:clamp(1.5rem,3.2vw,3rem);
}
.sperson__fig.is-mono .mono__i{ font-size:.9375rem; letter-spacing:.04em; }
.mono__i--lg{ font-size:clamp(3rem,7vw,6rem); }
.modal__fig:not(.is-mono) #spkMono{ display:none; }

/* -- speaker card gains one line: the session they appear in -- */
.scard__in{
  margin-top:.35rem; font-family:var(--body); font-weight:600;
  font-size:clamp(.625rem,.73vw,.6875rem); letter-spacing:.14em; text-transform:uppercase; color:#818787;
}
.speakers__d{ max-width:60ch; margin:.9rem 0 clamp(1.8rem,3.6vw,2.8rem); }

/* -- "At REMA" list in the profile: each session is a way back to the rail -- */
.modal__session{ display:grid; gap:.5rem; margin-top:.9rem; }
.atrema{
  display:grid; gap:.2rem; text-align:left; width:100%; cursor:pointer;
  padding:.8rem .9rem; background:rgba(255,255,255,.05);
  border:1px solid rgba(255,255,255,.14);
  transition:background-color .25s, border-color .25s, transform .3s var(--ease-out);
}
.atrema:hover{ background:rgba(255,255,255,.1); border-color:rgba(193,241,109,.5); transform:var(--lift-sm); }
.atrema:focus-visible{ outline:2px solid var(--lime); outline-offset:2px; }
.atrema__t{ font-family:var(--body); font-weight:600; font-size:.6875rem; letter-spacing:.16em; text-transform:uppercase; color:var(--lime); }
.atrema__h{ font-family:var(--body); font-weight:500; font-size:clamp(.9375rem,1.19vw,1.0625rem); line-height:1.35; color:#fff; }
.atrema__w{ font-size:.8125rem; color:rgba(255,255,255,.6); font-variant-numeric:tabular-nums; }

/* -- entrance: section 27 already fades/rises a .track on reveal; this just
      carries its stagger past the sixth row, which is where its nth-child
      delays stop. --i is set by the filter so the sequence restarts on each
      chapter rather than counting hidden rows. -- */
html.js #tracks .track{ transition-delay:calc(var(--i,1) * 40ms); }

@media (max-width:1024px){
  .speople{ grid-template-columns:minmax(0,1fr); }
}
@media (max-width:600px){
  .pfilters{ margin-inline:calc(-1 * var(--gutter)); padding-inline:var(--gutter); gap:1.35rem; }
  .sperson{ padding:.5rem .6rem; gap:.7rem; }
  .sperson__fig{ width:40px; }
}
@media (prefers-reduced-motion:reduce){
  html.js #tracks .track{ animation:none; }
  .sperson:hover,.atrema:hover{ transform:none; }
}

/* ---------- 41. SCHEDULE ROW ALIGNMENT ------------------------------------
   The collapsed row was a chip followed by three ragged metadata lines, and
   the expanded panel started under the chip rather than under the title, so
   nothing lined up down the list. The row is now one text column beside the
   number: the time and the duration hold the top line -- the duration flushed
   to the right edge of that column, so every row ends on the same vertical --
   then the title, then a single meta line of type, people and chapter. The
   panel is indented to the title, so an open session reads as one block.
   Same card, same type, same spacing language: just aligned.               */
.track__btn{ align-items:start; }
.track__main{ min-width:0; }
.track__when{
  display:block; margin-bottom:.5rem;
  font-family:var(--body); font-weight:600; font-size:clamp(.8125rem,.93vw,.875rem);
  line-height:1.2; letter-spacing:-.02em; color:#3F5B57;
  font-variant-numeric:tabular-nums; white-space:nowrap;
}
.track__sub{
  display:flex; flex-wrap:wrap; align-items:center; gap:.35rem .45rem; margin-top:.55rem;
}
.track__sub .pcount{ font-size:clamp(.75rem,.93vw,.875rem); }
.track__n{ margin-top:1px; }
.track__i{ margin-top:1px; }

/* the panel picks up the title's left edge: 54 box + 24 gutter, 44 + 16 below */
.track__list{ padding-left:calc(30.5px + 54px + 24px); }
@media (min-width:1025px){
  .track__btn{ grid-template-columns:54px minmax(0,1fr) 39px; column-gap:24px; padding:28px 30.5px; }
}
@media (max-width:1024px){
  .track__btn{ grid-template-columns:44px minmax(0,1fr) 32px; column-gap:16px; padding:20px 22px; }
  .track__list{ padding-left:calc(22px + 44px + 16px); }
  .track__when{ margin-bottom:.4rem; }
  .track__sub{ margin-top:.45rem; }
}
/* on a phone that indent would cost more measure than the alignment is worth,
   so the panel runs flush with the card instead */
@media (max-width:600px){
  .track__btn{ padding:18px; }
  .track__list{ padding:2px 18px 18px; }
}

/* ---------- 42. SPLASH ----------------------------------------------------
   A held first frame, not a fake progress bar. The cover is the exact ground
   the hero already sits on -- var(--ink-2) under the same dot grid -- so it
   dissolves into the page instead of cutting to it, and the only thing on it
   is the seal, breathing, with its ring turning at the same 30s the slab and
   the footer use.

   It exists only with JS (the head script sets .is-splash), only until the
   fonts and the hero photograph are in (main.js S0 holds a 900ms floor and a
   2.6s ceiling), and it never locks scrolling -- so browser scroll
   restoration and #deep-links still land where they should, under the cover.
   If the script never runs at all, `splash-failsafe` drops it at 6s.        */
.splash{ display:none; }
html.js.is-splash .splash{
  display:grid; place-items:center;
  position:fixed; inset:0; z-index:300;
  background:var(--ink-2) var(--dot-grid);
  background-size:var(--dot-size); background-position:var(--dot-pos);
  transition:opacity .5s var(--ease-out);
  animation:splash-failsafe 0s linear 6s forwards;
}
@keyframes splash-failsafe{ to{ opacity:0; visibility:hidden; pointer-events:none; } }

/* No fill-mode, and a resting opacity of 1: a browser that pauses animations
   (a background tab) then shows the mark plainly rather than holding it at the
   keyframe's opacity:0 and rendering an empty cover. */
.splash__seal{
  width:clamp(132px,14vw,180px); opacity:1;
  animation:splash-mark .55s var(--ease-out),
            splash-breathe 2.1s ease-in-out .55s infinite;
}
@keyframes splash-mark{ from{ opacity:0; transform:scale(.92); } }
@keyframes splash-breathe{ 0%,100%{ opacity:1; } 50%{ opacity:.38; } }

/* the lift: the mark goes first and a touch closer, then the ground fades */
html.is-lifting .splash{ opacity:0; pointer-events:none; }
html.is-lifting .splash__seal{
  animation:none; opacity:0; transform:scale(1.07);
  transition:opacity .28s var(--ease), transform .5s var(--ease-out);
}

@media (prefers-reduced-motion:reduce){
  html.js.is-splash .splash{ transition-duration:.22s; }
  .splash__seal{ animation:none; }
  html.is-lifting .splash__seal{ transition:opacity .18s linear; transform:none; }
}

/* ---------- 43. SPEAKERS: ANNOUNCING SOON ---------------------------------
   The roster's stand-in, sitting above the schedule's own heading: near enough
   to be read by anyone looking for the line-up, far enough out of the list to
   read as its own block rather than a session. A solid #06322D band, deeper
   than the palette's --forest, so it carries against the schedule's pale ground and
   the white rows below it, with the brand motifs blocked up flush against the
   right and bottom edges. programme.js drops the whole thing, and restores the
   Speakers section, the moment SHOW_SPEAKERS goes true.                     */
.spksoon{
  --sp-py:clamp(1.3rem,2.2vw,1.9rem);
  --sp-px:clamp(1.5rem,2.6vw,2.2rem);
  --mo:clamp(52px,5.25vw,68px);          /* one motif cell; three of them set the height */
  display:grid; grid-template-columns:minmax(0,1fr) auto auto; align-items:center;
  gap:clamp(1.4rem,2.6vw,2.4rem);
  margin-bottom:clamp(2.4rem,5vw,4.4rem);   /* clears the schedule's heading */
  padding:var(--sp-py) 0 var(--sp-py) var(--sp-px);
  background:#06322D; color:#fff;
}
.spksoon__body{ min-width:0; }
.spksoon__k{
  margin:0 0 clamp(1rem,1.6vw,1.45rem); font-family:var(--body); font-weight:700;
  font-size:clamp(.8125rem,1.06vw,.9375rem); line-height:1.2; letter-spacing:.04em;
  text-transform:uppercase; color:var(--lime);
}
.spksoon__d{
  margin:0; font-family:var(--body); font-weight:400;
  font-size:clamp(1.0625rem,1.39vw,1.3125rem); line-height:1.5; letter-spacing:-.02em;
  color:#fff; max-width:46ch;
}
.spksoon__cta{ flex:none; white-space:nowrap; }

/* the motif block ignores the panel's vertical padding so it sits edge to edge */
.spksoon__motif{
  align-self:center; display:grid;
  grid-template-columns:repeat(2,var(--mo)); grid-auto-rows:var(--mo);
  margin-block:calc(-1 * var(--sp-py));
  /* the block stays pinned right, so widening its own column is what pulls the
     button back towards the copy it belongs to */
  margin-left:clamp(1rem,4.7vw,71px);
}
.mo{ display:grid; place-items:center; }
.mo img{ display:block; width:74%; height:auto; }
/* the burst and the star already carry their own grounds, so they run the full
   cell where the ring, the flora and the dot grid sit inside theirs */
.mo--wide img{ width:100%; }
.mo--bleed img{ width:100%; height:100%; }

@media (max-width:820px){
  .spksoon{ grid-template-columns:minmax(0,1fr) auto; row-gap:1.3rem; }
  /* the CTA drops to its own row but keeps its own width -- full-bleed lime
     across the panel reads louder than the message it is attached to */
  .spksoon__cta{ grid-column:1; justify-self:start; }
  /* the copy is taller than the block here, so it keeps the bottom-right
     corner rather than floating in the middle of the panel's right edge */
  .spksoon__motif{
    grid-column:2; grid-row:1 / span 2; align-self:end;
    margin-left:clamp(1rem,2.6vw,1.8rem);
    margin-block:0 calc(-1 * var(--sp-py));
  }
}
/* on a phone the block would take a third of the panel's width, so the copy
   gets it back and the CTA runs the full width the way every button does there */
@media (max-width:600px){
  .spksoon{ grid-template-columns:minmax(0,1fr); padding:1.4rem; }
  .spksoon__motif{ display:none; }
  .spksoon__cta{ width:100%; }
}

/* ---------- 44. PHONE HERO, TO THE iPhone 16 MOCK -------------------------
   Every number below is measured off "iPhone 16 - 1.svg" (393x900). The text
   in that export is outlined, so the sizes are not read off it -- they are
   solved: each string was rendered in the site's own face and weight and the
   size iterated until its ink box matched the mock's path box to under .05px.
   (DM Sans is variable and Chrome runs its optical-size axis, so glyph widths
   are not linear in font-size and a single scale step lands ~10% out.)

   Mock, at 393:  gutter 24 | logo ink 69.3 | headline ink 175.5-268.8 |
   tagline 289.9-303.3 | rule 332.1 | date 363.8-384.0 | venue 405.2-419.6 |
   buttons 456.1 and 521.6, both 345x49 | photo 594.8.
   Sizes solved: headline 50.02, tagline 14.01, date 24.06, venue 15.50,
   button label 18.03. The vw figures hit those at 393 and scale from there. */
@media (max-width:600px){
  .hero{ --gutter:clamp(18px,6.107vw,24px); }        /* 24 at 393, hero only */
  /* The mock draws no header, so its 175.5 headline puts a canyon under the
     real 64px bar. Its own logo-to-headline gap is 75.3 (logo ink ends 100.2,
     headline starts 175.5); the site's header logo ink ends at 46.5, so the
     same gap lands the headline on 121.8. Same rhythm, measured from the logo
     that is actually there. */
  .hero__pin{ padding-top:clamp(88px,29.59vw,128px); }    /* headline ink on 121.8 */

  .hero__title{
    color:var(--lime);
    font-size:clamp(2.6rem,12.73vw,3.4rem);           /* 50.02 at 393 */
    line-height:1.12;                                 /* mock's two-line ink = 93.3 */
  }
  .hero__head{ gap:0; }                               /* the rule's own margins own this seam */
  .hero__sub{
    margin-top:4px;   /* small on purpose: the headline's line box already
                         hangs 13px below its cap ink */
    font-size:clamp(.8125rem,3.565vw,1rem);           /* 14.01 at 393 */
    line-height:1.3;
  }
  .hero__meta{
    margin-top:clamp(22px,7.1vw,32px); padding-top:clamp(20px,6.39vw,29px);
    border-top:1px solid #19443F;                     /* the mock's own stroke */
  }
  .hero__date{
    color:var(--lime);
    font-size:clamp(1.35rem,6.122vw,1.75rem);         /* 24.06 at 393 */
    line-height:1.2;
  }
  .hero__where{
    margin-top:clamp(11px,3.54vw,16px);
    font-size:clamp(.875rem,3.944vw,1.0625rem);       /* 15.50 at 393 */
    line-height:1.35;
  }
  .hero__actions{ margin-top:clamp(26px,8.7vw,40px); gap:clamp(13px,4.2vw,19px); }
  .hero__actions .btn{
    min-height:49px; padding-block:0;
    font-size:clamp(1rem,4.588vw,1.15rem);            /* 18.03 at 393 */
  }
  .hero__slot{ margin-top:clamp(19px,6.16vw,28px); }

  /* the band over the photograph: 26.44 / 12.97 at 393, both solved the same
     way off the mock's paths -- .band__t is Nohemi 700 and .band__d is Nohemi
     400, not DM Sans, which the first solve got wrong */
  .hero__band .band__t{ font-size:clamp(1.4rem,6.728vw,2rem); line-height:1.225; }
  .band__d{ font-size:clamp(.75rem,3.301vw,.9375rem); }
}

/* ---------- 45. EXPERIENCE CARDS: STAGGERED ICON ENTRANCE ------------------
   Hover is left exactly as it was -- the lift, the shadow, the watermark to 11%
   and the icon up 3px, all in section 21. The motif rotation that briefly sat
   here was reverted.

   This is the entrance only, and it is the part a phone gets at all, since
   hover does not exist on touch: each card's icon arrives just after the card
   lands, stepping across all five.

   It is an *animation* rather than a transition on purpose. The card reveal and
   the hover both want `transform`, so a transition-delay for the stagger would
   also delay every hover by up to 360ms. `animation-fill-mode: backwards` holds
   the from-state through the delay and then lets go entirely, leaving the
   transform free for the hover transition.                                   */
.xgrid    .xcard:nth-child(1){ --xd:.04s; }
.xgrid    .xcard:nth-child(2){ --xd:.12s; }
.xgrid    .xcard:nth-child(3){ --xd:.20s; }
.xgrid--b .xcard:nth-child(1){ --xd:.28s; }
.xgrid--b .xcard:nth-child(2){ --xd:.36s; }

.xcard.is-in .xcard__icon{ animation:xicon-in .55s var(--ease-out) var(--xd,0s) backwards; }
@keyframes xicon-in{ from{ opacity:0; transform:translateY(14px) scale(.9); } }

@media (prefers-reduced-motion:reduce){
  .xcard.is-in .xcard__icon{ animation:none; }
}

/* ---------- 46. REGISTRATION SUCCESS OVERLAY -------------------------------
   The form used to confirm with a line of text under the button. This is the
   same shell as .modal -- including the visibility flip that is instant on the
   way in and delayed on the way out, so focus can land the moment .is-open
   does -- with the panel composed as one centred column and the motif block
   bled into its bottom-right corner, as the speakers notice does.            */
.done{
  position:fixed; inset:0; z-index:120; display:grid; place-items:center;
  padding:clamp(1rem,3vw,2.5rem);
  background:rgba(3,33,30,.72);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  opacity:0; visibility:hidden;
  transition:opacity .3s var(--ease), visibility 0s linear .3s;
}
.done.is-open{ opacity:1; visibility:visible; transition:opacity .3s var(--ease), visibility 0s linear 0s; }

.done__panel{
  position:relative; text-align:center;
  width:min(560px,100%);
  /* At 560x694 this clears a 720-tall viewport by 13px and nothing shorter, and
     the panel used to be overflow:hidden -- so a laptop or a landscape phone
     lost the buttons with no way to reach them. Cap it and let it scroll. */
  max-height:calc(100dvh - clamp(2rem,6vw,5rem));
  overflow-y:auto; overflow-x:hidden; overscroll-behavior:contain;
  /* the extra bottom padding is the motif row's lane, so the buttons never
     sit on top of it -- a corner block did exactly that in the first cut */
  padding:clamp(2.4rem,5vw,3.4rem) clamp(1.5rem,4vw,3rem) clamp(4.4rem,9vw,5.4rem);
  background:#06322D var(--dot-grid);
  background-size:var(--dot-size); background-position:var(--dot-pos);
  color:#fff;
  transform:translateY(20px) scale(.98);
  transition:transform .38s var(--ease-out);
}
.done.is-open .done__panel{ transform:none; }
.done__x{ top:16px; right:16px; width:44px; height:44px; }

/* the seal lands first and the column steps in behind it */
.done__seal{
  width:clamp(76px,15vw,96px); margin:0 auto clamp(1.1rem,2.4vw,1.5rem);
}
.done.is-open .done__seal{ animation:done-pop .6s var(--ease-out) .08s backwards; }
@keyframes done-pop{ from{ opacity:0; transform:scale(.55); } }

.done__k{
  margin:0 0 .55rem; font-family:var(--body); font-weight:700;
  font-size:clamp(.75rem,1.7vw,.875rem); letter-spacing:.2em; text-transform:uppercase;
  color:var(--lime);
}
.done__t{ margin:0 0 clamp(.8rem,1.8vw,1.1rem); color:#fff; }
.done__d{
  margin:0 auto; max-width:42ch;
  font-family:var(--body); font-size:clamp(.9375rem,1.9vw,1.0625rem);
  line-height:1.6; letter-spacing:-.02em; color:rgba(255,255,255,.86);
}
.done__d b{ color:#fff; font-weight:600; }

.done__meta{
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:1rem clamp(1rem,3vw,2rem); margin:clamp(1.5rem,3.2vw,2.1rem) 0;
  padding:clamp(1.1rem,2.4vw,1.5rem) 0;
  border-top:1px solid #19443F; border-bottom:1px solid #19443F;
}
.done__meta dt{
  margin:0 0 .35rem; font-family:var(--body); font-weight:600;
  font-size:clamp(.625rem,1.4vw,.6875rem); letter-spacing:.18em;
  text-transform:uppercase; color:#7FA79F;
}
.done__meta dd{
  margin:0; font-family:var(--body); font-weight:500;
  font-size:clamp(.8125rem,1.8vw,.9375rem); line-height:1.35; letter-spacing:-.02em; color:#fff;
}

.done__a{ display:flex; gap:.7rem; justify-content:center; flex-wrap:wrap; }
.done__a .btn{ flex:1 1 auto; min-width:150px; }

/* One row along the bottom edge rather than the speakers notice's corner block.
   This panel is a centred column with a full-width button row, so anything in a
   corner collides with it; a band cannot. The empty first cell is kept -- it
   puts a deliberate gap in the run. */
.done__motif{
  position:absolute; left:0; right:0; bottom:0; pointer-events:none;
  display:grid; grid-auto-flow:column; grid-auto-columns:var(--mo);
  justify-content:center;
  --mo:clamp(30px,6vw,40px); opacity:.32;
}

@media (max-width:600px){
  .done__meta{ grid-template-columns:minmax(0,1fr); gap:.9rem; }
  .done__a .btn{ flex:1 1 100%; }
  .done__motif{ --mo:26px; opacity:.28; }
}
/* Short viewports -- a laptop at 720 fits with 13px to spare, and a landscape
   phone does not. Scale the vertical rhythm off the height so the buttons stay
   above the panel's fold instead of only being reachable by scrolling. */
@media (max-height:680px){
  .done__panel{ padding-block:clamp(1.3rem,3vh,2rem) clamp(2.8rem,7vh,4rem); }
  .done__seal{ width:clamp(52px,9vh,72px); margin-bottom:clamp(.6rem,1.6vh,1.1rem); }
  .done__t{ font-size:clamp(1.35rem,4.4vh,2.1rem); }
  .done__d{ font-size:clamp(.875rem,1.9vh,1rem); line-height:1.5; }
  .done__meta{ margin-block:clamp(.8rem,2.4vh,1.4rem); padding-block:clamp(.7rem,2vh,1.1rem); }
  .done__motif{ --mo:clamp(22px,4.4vh,32px); }
}

@media (prefers-reduced-motion:reduce){
  .done__panel{ transform:none; transition:none; }
  .done.is-open .done__seal{ animation:none; }
}

/* ---------- 47. REGISTRATION FORM STRUCTURE --------------------------------
   The fieldset is one two-column grid and the fields pair by meaning: the two
   names, then the two ways to reach you, then where you work, with the
   category spanning the row. It collapses to a single column at 820px. What is
   left is the detail: a required marker, a phone control whose two halves read
   as one field, and a select that does not sit at placeholder grey once a real
   choice is made.                                                            */

/* the country code and the number are one control, so they share one outline
   and only the pair gets the focus ring */
.phone{ position:relative; }
.phone select:focus, .phone input:focus{ position:relative; z-index:1; }

/* an unchosen select should look like a placeholder, not like an answer */
.field select:invalid{ color:#AFB4B1; }
.field select option{ color:var(--ink-3); }

/* ---------- 48. REGISTRATION: THE TWO STEPS -------------------------------
   registration.mjs was already a two-phase flow, but both phases were on
   screen at once: asking for a code while the details it came from sat above,
   greyed out. Step one is now removed outright when a code is issued, so the
   panel shows one thing at a time and the ticket beside it never reflows.

   main.js owns the .is-step2 class and reveals the boxes; it drives both off
   #regOtp's hidden attribute, which is the module's own signal.            */
.rstep__k{
  font-family:var(--body); font-weight:600; font-size:.75rem;
  letter-spacing:.12em; text-transform:uppercase; color:var(--grass);
  margin-bottom:.7rem;
}
.rform.is-step2 #regStep1,
.rform.is-step2 .rform__fine{ display:none; }
.rstep--code{ animation:rstep-in .4s var(--ease-out) backwards; }
@keyframes rstep-in{ from{ opacity:0; transform:translateY(8px); } }
.rstep--code .rform__d{ overflow-wrap:anywhere; }
.rcode{ margin-top:1.5rem; max-width:22rem; }

/* Six boxes rather than one long input: they show the expected length, and a
   pasted code spreads across them. #f-otp stays the value the module reads. */
.rcode__boxes{
  display:grid; grid-template-columns:repeat(6,minmax(0,1fr));
  gap:.5rem; margin-top:.5rem;
}
.rcode__boxes input{
  width:100%; height:56px; padding:0; text-align:center;
  font-family:var(--display); font-weight:600; font-size:1.35rem; color:var(--ink-3);
  background:var(--white); border:1px solid var(--line-2); border-radius:0;
  transition:border-color .2s, box-shadow .2s;
}
.rcode__boxes input:focus{
  outline:0; border-color:var(--forest); box-shadow:0 0 0 3px rgba(0,168,90,.18);
}
.rcode__boxes input:disabled{ background:#F4F6F5; color:var(--muted); }
.field.has-error .rcode__boxes input{ border-color:#C0392B; }

/* With the boxes live the real input is only a value carrier, but it stays in
   the DOM and reachable, so it is taken out of the layout rather than the
   accessibility tree's reach being cut. */
.rform.has-codeboxes #f-otp{
  position:absolute; width:1px; height:1px; margin:-1px;
  padding:0; border:0; overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%);
}
.rform.has-codeboxes .rcode label{
  display:block; font-size:.9375rem; margin-bottom:.5rem;
}
