
  /* ══ The Week — a horizontal journey across the days ═════════════════
     A pinned filmstrip: the section is N panels tall, an inner viewport STICKS
     for one screen, and the track pans sideways as you scroll — you travel left
     to right through the week (cover → six days → close). One rAF derives the
     whole thing from how far scrollY has moved through the section (kin to the
     old route engine, now horizontal): the track's translateX, a gold timeline
     that inks across the foot with a riding nib + per-day ticks, and a two-plane
     depth parallax (each illustration drifts a touch more than its text as the
     panel slides through centre). The real coloured-pencil illustrations are the
     heroes — large on bare #F5F6ED paper, titles kept small. Each burns into
     being on entry (see the WebGL reveal below). Narrow / reduced-motion fall
     back to a clean vertical stack; the burn still plays on scroll-in. */
  .way{
    position: relative;
    z-index: 1;                          /* paint above the fixed #gl shader */
    background: #F5F6ED;                  /* the same paper as the Cuisine section */
    color: var(--ink);
    --gold: #C8A24C;                     /* antique gold — the timeline, dates, ticks */
    --way-px: clamp(28px, 6vw, 150px);   /* panel side gutter */
    --art-amp: 46px;                     /* deep-plane parallax travel (horizontal) */
    --panel-scroll: 82vh;                /* scroll spent crossing one panel */
    font-family: 'Inter', system-ui, sans-serif;
    letter-spacing: -0.02em;
    -webkit-font-smoothing: antialiased;
  }
  .way__sr{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }

  /* horizontal mode: N panels tall; the viewport sticks while the track pans */
  .way.is-horizontal{ height: calc(var(--n, 8) * var(--panel-scroll)); }
  .way__viewport{ position: relative; height: 100vh; overflow: hidden; }
  .way.is-horizontal .way__viewport{ position: sticky; top: 0; height: 100vh; height: 100svh; }
  .way:not(.is-horizontal) .way__viewport{ height: auto; overflow: visible; }

  .way__field{ position:absolute; inset:0; z-index:0; pointer-events:none; background:#F5F6ED; }

  /* the track — a flex row in horizontal mode, a stacked column otherwise */
  .way__track{ position:relative; z-index:2; display:flex; height:100%; }
  .way.is-horizontal .way__track{ width: calc(var(--n, 8) * 100vw); will-change: transform; }
  .way:not(.is-horizontal) .way__track{ flex-direction:column; width:100%; }

  .way__panel{ position:relative; flex:0 0 100vw; height:100vh; display:flex; align-items:center; justify-content:center; padding: 0 var(--way-px); }
  /* stacked (mobile / reduced-motion): each day is content-height with a generous
     rhythm — NOT a rigid 100vh. The old full-viewport floor stacked seven near-empty
     screens (the text block + a ≤50vh illustration never fill 100vh) and, keyed to
     vh, shifted as the mobile URL-bar showed/hid. Content height removes both the
     dead scroll and that jump while each scene still reads as its own panel. */
  .way:not(.is-horizontal) .way__panel{
    flex:0 0 auto; width:100%; min-height:auto; height:auto;
    padding: clamp(56px,10vh,116px) max(clamp(24px,6vw,80px), env(safe-area-inset-left), env(safe-area-inset-right));
  }

  /* ── cover ── */
  .way__cover{ justify-content:center; gap: clamp(30px,5vw,84px); text-align:left; }
  .way__cover .way__col--text{ flex: 0 0 auto; max-width: min(44vw, 540px); }
  .way__kicker{
    font-size: clamp(10px,1vw,12px); font-weight:500; letter-spacing:0; text-transform:uppercase;
    color: rgba(11,11,12,.5); margin-bottom: clamp(16px,2.4vh,26px);
  }
  .way__cover-title{
    font-family:'LF Serif','Fraunces',Georgia,'Times New Roman',serif; font-optical-sizing:auto; font-weight:438;
    font-size: clamp(36px,5vw,72px); line-height:.98; letter-spacing:-0.022em;
  }
  .way__cover-sub{
    margin-top: clamp(16px,2.4vh,26px); max-width: 30em;
    font-size: clamp(13px,1.05vw,15px); line-height:1.7; color: rgba(11,11,12,.6);
  }
  .way__cover-hint{
    margin-top: clamp(22px,4vh,46px);
    font-size: 11px; font-weight:500; letter-spacing:.2em; text-transform:uppercase; color: var(--gold);
    display:inline-flex; align-items:center; gap:10px;
  }
  .way__cover-hint span{ display:inline-block; width:clamp(30px,4vw,56px); height:1px; background: currentColor; }

  /* ── a day panel: big illustration + a compact text block, sides alternate ── */
  .way__day{ gap: clamp(30px,5vw,96px); }
  .way__day.is-left{ flex-direction: row-reverse; }
  .way__col--text{ flex: 0 0 clamp(238px, 26vw, 358px); max-width: 358px; }
  .way:not(.is-horizontal) .way__col--text{ flex-basis:auto; max-width: 30em; }
  .way__col--art{ flex: 0 1 auto; display:flex; align-items:center; justify-content:center; min-width:0; }

  .way__label{ font-size:12px; font-weight:500; letter-spacing:.18em; text-transform:uppercase; color: rgba(11,11,12,.5); }
  .way__title{
    font-family:'LF Serif','Fraunces',Georgia,'Times New Roman',serif; font-optical-sizing:auto; font-weight:430;
    font-size: clamp(26px,3vw,44px); line-height:1.0; letter-spacing:-0.02em;
    margin-top: clamp(12px,1.6vh,18px);
  }
  .way__day--climax .way__title{ font-weight:446; }
  .way__eyebrow{ margin-top:9px; font-size:11.5px; letter-spacing:.14em; text-transform:uppercase; color: var(--gold); }
  .way__body{
    margin-top: clamp(13px,1.8vh,20px); max-width:28em;
    font-size: clamp(13px,1.02vw,15px); line-height:1.72; color: rgba(11,11,12,.62);
  }
  .way__date{
    margin-top: clamp(18px,2.8vh,30px);
    font-family:'LF Serif','Fraunces',Georgia,serif; font-weight:420; font-size: clamp(15px,1.4vw,19px);
    color: var(--gold); letter-spacing:.01em;
  }
  .way__rule{ display:block; height:1px; margin-top:12px; background: rgba(11,11,12,.16); transform: scaleX(0); transform-origin:left center; }

  /* the illustrations — large, the heroes of the page */
  .way__art-wrap{ position:relative; margin:0; line-height:0; }
  .way__art{
    display:block; width:auto; height:auto; object-fit:contain;
    /* will-change is scoped to .is-horizontal below — these images only transform
       (the --f parallax) in the filmstrip; in the stacked/mobile/reduced-motion
       layout they're transform:none, so promoting them there is dead GPU memory. */
  }
  .way__art--portrait{ max-height: min(84vh, 720px); max-width: 44vw; }
  .way__art--land    { max-width: min(56vw, 880px);  max-height: 80vh; }
  .way__art--wide    { max-width: min(62vw, 1040px); max-height: 78vh; }
  .way__art--map     { max-width: min(48vw, 680px);  max-height: 66vh; }
  /* deep-plane parallax: art rides --f (panel's offset from centre) a touch more
     than its text; horizontal in the filmstrip, off in the stacked fallback */
  .way.is-horizontal .way__art      { transform: translate3d(calc(var(--f,0) * var(--art-amp)), 0, 0); will-change: transform; }
  .way.is-horizontal .way__col--text{ transform: translate3d(calc(var(--f,0) * (var(--art-amp) * 0.34)), 0, 0); will-change:transform; }
  .way:not(.is-horizontal) .way__art{ transform:none; }

  /* narrow/stacked: illustrations go full width below the text */
  .way:not(.is-horizontal) .way__day,
  .way:not(.is-horizontal) .way__cover{ flex-direction:column; align-items:flex-start; gap: clamp(22px,5vw,34px); }
  .way:not(.is-horizontal) .way__cover .way__col--text{ max-width:none; }
  .way:not(.is-horizontal) .way__day.is-left{ flex-direction:column; }
  .way:not(.is-horizontal) .way__art, 
  .way:not(.is-horizontal) .way__art--portrait,
  .way:not(.is-horizontal) .way__art--land,
  .way:not(.is-horizontal) .way__art--wide{ max-width:100%; max-height:50vh; }

  /* ── the gold timeline at the foot of the viewport (horizontal mode only) ──
     a ghost rule the whole way, a gold rule that inks left→right with scroll, a
     nib riding the tip, and one tick per day (the active one inks gold + lifts
     its date). Fixed in the sticky viewport, so it holds still while panels pan. */
  .way__rail{ position:absolute; left: var(--way-px); right: var(--way-px); bottom: clamp(40px,7vh,72px); height:1px; z-index:5; pointer-events:none; }
  .way:not(.is-horizontal) .way__rail{ display:none; }
  .way__rail-ghost{ position:absolute; left:0; right:0; top:0; height:1px; background: rgba(11,11,12,.13); }
  .way__rail-ink{ position:absolute; left:0; right:0; top:0; height:1.4px; margin-top:-0.2px; background: var(--gold); transform: scaleX(var(--p,0)); transform-origin:left center; }
  .way__rail-end{ position:absolute; right:-4px; top:0; width:8px; height:8px; margin-top:-4px; border-radius:50%; border:1px solid var(--gold); opacity:.5; box-sizing:border-box; }
  /* The nib rides --p along the rail. It spans the full rail width (left:0;right:0)
     so translateX(p · 100%) moves it by p × its own width = p × rail width —
     geometrically identical to the old `left: calc(p*100%)`, but a transform
     composites on the GPU instead of forcing layout + re-rasterising the glowing
     box-shadow on every scrub frame. The visible 8px dot is the ::before, pinned to
     the nib's leading edge (margin -4px centres it on the rail line, as the old
     translate(-50%,-50%) did). */
  .way__nib{ position:absolute; top:0; left:0; right:0; height:0; transform: translate3d(calc(var(--p,0) * 100%), 0, 0); pointer-events:none; }
  .way__nib::before{ content:""; position:absolute; left:0; top:0; width:8px; height:8px; margin:-4px 0 0 -4px; border-radius:50%; background: var(--gold); box-shadow:0 0 0 1px rgba(200,162,76,.5), 0 0 12px 2px rgba(200,162,76,.34); }
  .way__tick{ position:absolute; top:0; left:0; transform: translate(-50%, 0); color: rgba(11,11,12,.4); transition: color .5s ease; }
  .way__tick i{ position:absolute; left:50%; top:-5px; width:1px; height:11px; background:currentColor; transform:translateX(-50%); }
  .way__tick b{ position:absolute; left:50%; top:-30px; transform:translateX(-50%); font-weight:500; font-size:11px; letter-spacing:.12em; font-variant-numeric:tabular-nums; white-space:nowrap; }
  .way__tick s{ position:absolute; left:50%; top:12px; transform:translateX(-50%); text-decoration:none; font-size:10.5px; letter-spacing:.03em; color:var(--gold); white-space:nowrap; opacity:0; transition:opacity .45s ease; }
  .way__tick.is-active{ color: var(--gold); }
  .way__tick.is-active s{ opacity:.9; }

  /* ── entrance (kin to .tjk): each panel armed by JS (.way-ready), released on
        .is-in. The illustration's reveal is owned by the burn (below); here we
        bring in the type. ── */
  .way.way-ready .way__day .way__label,
  .way.way-ready .way__day .way__title,
  .way.way-ready .way__day .way__eyebrow,
  .way.way-ready .way__day .way__body,
  .way.way-ready .way__day .way__date,
  .way.way-ready .way__cover .way__kicker,
  .way.way-ready .way__cover .way__cover-title,
  .way.way-ready .way__cover .way__cover-sub,
  .way.way-ready .way__cover .way__cover-hint{
    opacity:0; transform: translateY(18px); filter: blur(6px);
    transition: opacity 1s ease, transform 1.1s cubic-bezier(.2,.7,.2,1), filter 1s ease;
  }
  /* the illustration only blur-fades in WHEN the burn isn't handling it. The cover
     map is included so it starts hidden too — otherwise the eager cover img paints
     crisp for a beat before its burn mounts (a crisp→blank→burn flash). */
  .way.way-ready .way__day .way__art-wrap,
  .way.way-ready .way__cover .way__art-wrap{
    opacity:0; transform: translateY(24px) scale(.99); filter: blur(7px);
    transition: opacity 1.1s ease, transform 1.2s cubic-bezier(.2,.7,.2,1), filter 1.1s ease;
  }
  .way.way-ready .way__day.is-in .way__label,
  .way.way-ready .way__day.is-in .way__title,
  .way.way-ready .way__day.is-in .way__eyebrow,
  .way.way-ready .way__day.is-in .way__body,
  .way.way-ready .way__day.is-in .way__date,
  .way.way-ready .way__day.is-in .way__art-wrap,
  .way.way-ready .way__cover.is-in .way__art-wrap,
  .way.way-ready .way__cover.is-in .way__kicker,
  .way.way-ready .way__cover.is-in .way__cover-title,
  .way.way-ready .way__cover.is-in .way__cover-sub,
  .way.way-ready .way__cover.is-in .way__cover-hint{ opacity:1; transform:none; filter: blur(0); }
  /* stagger the type */
  .way.way-ready .way__day .way__title, .way.way-ready .way__cover .way__cover-title{ transition-delay:.07s; }
  .way.way-ready .way__day .way__eyebrow{ transition-delay:.10s; }
  .way.way-ready .way__day .way__body, .way.way-ready .way__cover .way__cover-sub{ transition-delay:.14s; }
  .way.way-ready .way__day .way__date{ transition-delay:.2s; }
  .way.way-ready .way__cover .way__cover-hint{ transition-delay:.26s; }
  .way.way-ready .way__day.is-in .way__rule{ transform: scaleX(1); transition: transform .9s cubic-bezier(.2,.7,.2,1) .28s; }

  /* ── reduced motion: a static, fully-printed itinerary; the engine never pins ── */
  @media (prefers-reduced-motion: reduce){
    .way__art, .way__col--text{ transform:none !important; }
    .way__rail{ display:none; }
    .way.way-ready .way__day *, .way.way-ready .way__cover *{
      opacity:1 !important; transform:none !important; filter:none !important; transition:none !important;
    }
    .way__rule{ transform: scaleX(1) !important; }
  }

    /* ── burning-paper reveal ────────────────────────────────────────────
     Each illustration is revealed by an advancing char/ember front rendered
     into a WebGL <canvas> that JS lays over the <img> (progressive enhancement:
     the section gets .way--burning only when WebGL is available AND motion is
     allowed). The canvas samples the cut-out webp as a texture and burns it into
     being; at the end it hands off to the crisp native <img>, which keeps the
     the --f deep-plane parallax and the exit-fade.
     No-WebGL / reduced-motion never set .way--burning, so the stock entrance
     reveal above stays fully in charge. */
  .way__burn{
    position:absolute;                 /* left/top/width/height set inline by JS, exactly over the img box */
    pointer-events:none;
    z-index:1;                         /* above the <img> while it burns */
    /* ride the SAME parallax as .way__art so ember and art never slip apart;
       horizontal in the filmstrip (var(--f) is 0 in the stacked fallback) */
    transform: translate3d(calc(var(--f,0) * var(--art-amp)), 0, 0);
    will-change: transform;
  }
  /* the instant a wrap's canvas mounts JS adds .has-burn: neutralise the stock
     art-wrap entrance reveal (so it never double-reveals / blurs UNDER the canvas)
     and hold the native <img> hidden until handoff. Scoped to .has-burn so any
     wrap WITHOUT a canvas (lazy-not-yet-mounted, or a failed context) still gets
     the normal reveal — a partial failure degrades per-image, never blanks one. */
  .way.way--burning .way__day .way__art-wrap.has-burn,
  .way.way--burning .way__day.is-right .way__art-wrap.has-burn,
  .way.way--burning .way__day.is-left  .way__art-wrap.has-burn,
  .way.way--burning .way__cover .way__art-wrap.has-burn{        /* cover burns on the same terms as a day */
    opacity:1 !important; transform:none !important; filter:none !important; transition:none !important;
  }
  .way.way--burning .way__art-wrap.has-burn > .way__art{ opacity:0; }            /* hidden under the canvas */
  .way.way--burning .way__art-wrap.has-burn.is-handed > .way__art{ opacity:1; }  /* instant handoff — no fade-dip */
