/* ==========================================================================
   VOYZ — "Votre départ, confirmé"
   A boarding pass assembles itself across three beats: the offer prints, the
   departure fills in, the pass is stamped and lifts away. Scroll-scrubbed, so
   the user drives it; nothing loops on a timer.

   Progress contract — JS sets these on .departure:
     --b0 --b1 --b2   eased 0..1 per beat
     --lift           0..1 for the final take-off
   All default to 1 (the arrived state), so with no JS, on a headless render, or
   under reduced motion the section shows a finished pass rather than a blank.
   ========================================================================== */

.departure{
  --pass-w: min(clamp(340px, 37vw, 520px), 92vw);
  position:relative;
  color:var(--on-dark);
  background:
    radial-gradient(80% 60% at 88% 96%, rgba(18,184,204,.22), transparent 60%),
    radial-gradient(70% 55% at 4% 4%, rgba(47,134,218,.22), transparent 62%),
    linear-gradient(178deg, var(--ink-950), #0c2138 62%, var(--ink-900));
}

/* Scroll track: its height is the scrub distance. */
.departure-rail{height:300vh}
.departure-stage{
  position:sticky;top:0;
  min-height:100vh;min-height:100dvh;
  display:flex;align-items:center;
  /* Header clearance on top, matching optical weight below, so the scene sits
     centred in the pinned frame rather than riding high. */
  padding:clamp(84px,10vh,112px) 0 clamp(64px,9vh,104px);
  overflow:clip;
}
/* ---------- Flying plane ----------
   Rides a real flight path via CSS motion path, so travel and banking angle
   come from one property instead of hand-keyed transforms. --flight is the
   damped scroll progress; it defaults to a settled 1 with no JS. */
.flight{
  position:absolute;inset:0;width:100%;height:100%;
  pointer-events:none;z-index:0;
}
.flight-track{
  fill:none;stroke:rgba(255,255,255,.10);stroke-width:1.5;
  stroke-dasharray:1 10;stroke-linecap:round;
}
.flight-trail{
  fill:none;stroke:url(#trailFade);stroke-width:2.5;stroke-linecap:round;
  stroke-dasharray:var(--track-len,2100);
  stroke-dashoffset:calc(var(--track-len,2100) * (1 - var(--flight,1)));
  filter:drop-shadow(0 0 10px rgba(18,184,204,.5));
}
.flight-plane{
  fill:#dff8fc;
  offset-path:path("M-80 742 C 320 690 560 556 812 432 S 1230 186 1530 54");
  offset-distance:calc(var(--flight,1) * 100%);
  offset-rotate:auto;
  filter:drop-shadow(0 0 14px rgba(18,184,204,.85));
}
/* Content sits above the flight layer. */
.departure-grid{position:relative;z-index:1}

.departure-grid{
  width:min(calc(100% - 40px),var(--container));margin-inline:auto;
  display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(2rem,5vw,5rem);align-items:center;
}

/* ---------- Copy column ---------- */
.departure-copy h2{
  margin:0;font-size:var(--step-h2);letter-spacing:var(--track-h2);
  color:#fff;max-width:15ch;
}
.departure-copy>p{
  margin:1.15rem 0 0;max-width:46ch;
  color:var(--on-dark-mut);font-size:clamp(1rem,.95rem+.25vw,1.1rem);
  line-height:1.65;               /* light type on dark needs the extra leading */
}

.departure-beats{
  list-style:none;margin:clamp(2rem,4vh,3rem) 0 0;padding:0;
  display:flex;flex-direction:column;gap:.25rem;
}
.departure-beats li{
  position:relative;padding:1rem 0 1.15rem;
  border-top:1px solid rgba(255,255,255,.12);
  opacity:.42;transition:opacity .5s var(--ease-out);
}
.departure-beats li:first-child{border-top:0}
.departure-beats li.is-on{opacity:1}
/* Progress rule under the active beat — reads as the pass filling in. */
.departure-beats li::after{
  content:"";position:absolute;left:0;bottom:0;height:2px;width:100%;
  background:var(--accent);border-radius:2px;
  transform:scaleX(0);transform-origin:left;
  transition:transform .6s var(--ease-out-expo);
}
.departure-beats li.is-on::after{transform:scaleX(1)}
.lang-ar .departure-beats li::after{transform-origin:right}

.departure-beats h3{
  margin:0;display:flex;align-items:baseline;gap:.6rem;
  font-size:1.15rem;font-weight:var(--fw-medium);color:#fff;
}
.departure-beats h3 .beat-verb{
  font-size:.7rem;font-weight:var(--fw-label);letter-spacing:.16em;
  text-transform:uppercase;color:var(--accent);
}
.lang-ar .departure-beats h3 .beat-verb{letter-spacing:0}
.departure-beats p{margin:.3rem 0 0;color:var(--on-dark-mut);font-size:.92rem;line-height:1.55}

/* ---------- The pass ---------- */
.departure-scene{
  perspective:1500px;perspective-origin:50% 45%;
  display:grid;place-items:center;
}

.pass{
  position:relative;display:flex;
  width:var(--pass-w);
  transform-style:preserve-3d;
  /* Settles from a steep raked angle to almost flat, then lifts away. */
  transform:
    translate3d(0, calc(var(--lift,1) * -18%), 0)
    rotateX(calc(14deg - var(--b1,1) * 10deg))
    rotateY(calc(-22deg + var(--b1,1) * 15deg))
    rotateZ(calc(var(--lift,1) * -7deg))
    scale(calc(.92 + var(--b0,1) * .08));
  opacity:calc(.25 + var(--b0,1) * .75);
  will-change:transform;
}

.pass-main,.pass-stub{
  background:linear-gradient(158deg,#ffffff,#eef2f7);
  color:var(--ink);
  box-shadow:
    0 40px 80px -30px rgba(2,10,22,.75),
    0 8px 24px -8px rgba(2,10,22,.45);
}
/* Bottom padding reserves a band for the stamp so it never lands on a value. */
.pass-main{position:relative;flex:1 1 auto;min-width:0;padding:1.35rem 1.4rem 3.4rem;border-radius:var(--r) 0 0 var(--r)}
.pass-stub{
  flex:0 0 clamp(74px,7vw,92px);
  padding:1.35rem .7rem 1.5rem;border-radius:0 var(--r) var(--r) 0;
  display:flex;flex-direction:column;align-items:center;justify-content:space-between;gap:.9rem;
  /* Tears away at the perforation on the final beat. */
  transform:translate3d(calc(var(--lift,1) * 14px),0,calc(var(--lift,1) * 26px)) rotateY(calc(var(--lift,1) * 13deg));
  transition:none;
}
/* Perforation */
.pass-perf{
  flex:0 0 2px;align-self:stretch;margin-inline:-1px;
  background:repeating-linear-gradient(180deg,rgba(16,31,48,.32) 0 5px,transparent 5px 11px);
  position:relative;z-index:2;
}
.pass-perf::before,.pass-perf::after{
  content:"";position:absolute;left:50%;translate:-50% 0;
  width:15px;height:15px;border-radius:50%;background:var(--ink-950);
}
.pass-perf::before{top:-8px}
.pass-perf::after{bottom:-8px}

.pass-head{
  display:flex;align-items:center;justify-content:space-between;gap:.75rem;
  padding-bottom:.85rem;border-bottom:1px solid var(--line);
}
.pass-brand{font-family:var(--font-display);font-weight:var(--fw-strong);font-size:1rem;letter-spacing:.01em}
.pass-kind{font-size:.58rem;font-weight:var(--fw-label);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}

/* Route: two codes with an arc drawn between them. */
.pass-route{display:flex;align-items:center;gap:.7rem;margin:1.15rem 0 .35rem}
.pass-code{
  font-family:var(--font-display);font-weight:var(--fw-display);
  font-size:clamp(1.9rem,3.4vw,2.5rem);line-height:1;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;color:var(--ink);
}
.pass-arc{position:relative;flex:1 1 auto;height:26px;color:var(--accent-600)}
/* The line stretches to fill the gap; the plane must not, or it smears. */
.arc-svg{width:100%;height:100%;display:block;overflow:visible}
.arc-line{
  fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-dasharray:var(--arc-len,120);
  stroke-dashoffset:calc(var(--arc-len,120) * (1 - var(--b1,1)));
}
/* Rides the drawn line, stopping short of the destination code. */
.arc-plane{
  position:absolute;top:0;left:0;width:15px;height:15px;fill:currentColor;
  transform:
    translateX(calc(var(--b1,1) * (100cqw - 15px)))
    translateY(calc(16px - var(--b1,1) * 15px));
  opacity:calc(var(--b1,1) * .9 + .1);
}
.pass-arc{container-type:inline-size}
.pass-city{display:flex;justify-content:space-between;gap:1rem;font-size:.72rem;color:var(--muted);font-weight:var(--fw-medium)}

.pass-fields{
  margin:1.25rem 0 0;padding-top:1rem;border-top:1px solid var(--line);
  display:grid;grid-template-columns:1fr 1fr;gap:.9rem 1rem;
}
.pass-fields>div{min-width:0}
.pass-fields dt{font-size:.58rem;font-weight:var(--fw-label);letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.pass-fields dd{
  margin:.2rem 0 0;font-size:.92rem;font-weight:var(--fw-medium);color:var(--ink);
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
/* Prices, dates, airport codes and seat counts are inherently left-to-right.
   Without isolation the bidi algorithm reorders them in Arabic — "88 000 DZD"
   renders as "DZD 000 88". Isolate them and keep the RTL block alignment. */
.pass-code,.pass-fields dd,.pass-seat dd,.pass-city{direction:ltr;unicode-bidi:isolate}
[dir=rtl] .pass-fields dd,[dir=rtl] .pass-seat dd{text-align:right}
[dir=rtl] .pass-fields dt,[dir=rtl] .pass-seat dt{text-align:right}
/* Each field prints in: clipped from the left like a thermal printer pass. */
.pass-fields>div,.pass-code,.pass-city span{
  clip-path:inset(0 calc(100% - var(--fill,1) * 100%) 0 0);
  opacity:calc(.15 + var(--fill,1) * .85);
}
.pass-code.from,.pass-city span:first-child{--fill:var(--b0,1)}
.pass-code.to,.pass-city span:last-child{--fill:var(--b0,1)}
.pass-fields>.f-price{--fill:var(--b0,1)}
.pass-fields>.f-agency{--fill:var(--b0,1)}
.pass-fields>.f-city{--fill:var(--b1,1)}
.pass-fields>.f-date{--fill:var(--b1,1)}

/* Stub */
.pass-seat{text-align:center}
.pass-seat dt{font-size:.55rem;font-weight:var(--fw-label);letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.pass-seat dd{margin:.15rem 0 0;font-family:var(--font-display);font-weight:var(--fw-medium);font-size:1.15rem;color:var(--ink);font-variant-numeric:tabular-nums}
.pass-barcode{
  width:100%;height:54px;
  background:repeating-linear-gradient(90deg,var(--ink) 0 2px,transparent 2px 4px,var(--ink) 4px 5px,transparent 5px 9px);
  opacity:calc(.18 + var(--b2,1) * .62);
}

/* The stamp lands on the final beat. */
.pass-stamp{
  position:absolute;left:1.4rem;bottom:1.15rem;
  padding:.4rem .7rem;
  display:flex;align-items:center;gap:.35rem;
  font-size:.68rem;font-weight:var(--fw-strong);letter-spacing:.12em;text-transform:uppercase;
  color:var(--accent-ink);border:2px solid var(--accent-600);border-radius:var(--r-xs);
  background:rgba(18,184,204,.14);
  transform:rotate(-9deg) scale(calc(1.6 - var(--b2,1) * .6));
  opacity:var(--b2,1);
  z-index:3;
}
.lang-ar .pass-stamp{letter-spacing:0}
.pass-stamp svg{width:13px;height:13px}

/* Contrail behind the pass as it lifts. */
.departure-scene::after{
  content:"";position:absolute;z-index:-1;
  width:min(60vw,520px);height:2px;
  background:linear-gradient(90deg,transparent,var(--accent),transparent);
  filter:blur(1px);
  opacity:calc(var(--lift,0) * .55);
  transform:translateY(70px) rotate(-7deg) scaleX(var(--lift,0));
}

/* ---------- Responsive ---------- */
@media (max-width:1000px){
  .departure-grid{grid-template-columns:1fr;gap:clamp(2rem,6vh,3rem)}
  .departure-scene{order:-1}
  .departure-copy h2{max-width:none}
  .departure-rail{height:280vh}
  .pass{--pass-w:min(430px,88vw)}
}
@media (max-width:560px){
  .departure-stage{padding-top:clamp(80px,11vh,110px)}
  .pass-fields{grid-template-columns:1fr 1fr;gap:.7rem .8rem}
  .departure-beats p{font-size:.88rem}
}

/* ---------- Reduced motion: arrived, static, no scroll trap ---------- */
@media (prefers-reduced-motion:reduce){
  .departure-rail{height:auto}
  .departure-stage{position:static;min-height:0;padding:clamp(4rem,8vh,6rem) 0}
  .pass{transform:rotateX(4deg) rotateY(-7deg);opacity:1}
  .pass-stub{transform:none}
  .departure-beats li{opacity:1}
  .departure-beats li::after{transform:scaleX(1)}
  .departure-scene::after{display:none}
}

/* ==========================================================================
   Responsive scene

   On a phone the pass was rendering near-fullwidth at a steep rake, so it
   read as a tilted grey slab with the copy stranded underneath. Narrow
   viewports get: a flatter angle (depth is illegible at that size), a pass
   sized to the column rather than the viewport, and a shorter scrub so the
   section is not a scroll trap on a device where scrolling is the whole
   interaction.
   ========================================================================== */
@media (max-width:900px){
  .departure-rail{height:220vh}
  .departure-stage{padding:clamp(72px,9vh,96px) 0 clamp(40px,6vh,64px)}
  .departure-grid{gap:clamp(24px,4vh,36px)}
  .departure-scene{perspective:1100px}
  /* Flatter: strong rotation needs size to read as depth. */
  .pass{
    --pass-w:min(420px,84vw);
    transform:
      translate3d(0, calc(var(--lift,1) * -12%), 0)
      rotateX(calc(7deg - var(--b1,1) * 5deg))
      rotateY(calc(-11deg + var(--b1,1) * 8deg))
      rotateZ(calc(var(--lift,1) * -4deg))
      scale(calc(.94 + var(--b0,1) * .06));
  }
  .pass-code{font-size:clamp(1.6rem,7vw,2.1rem)}
  .pass-main{padding:1.1rem 1.15rem 3rem}
  .pass-stub{flex-basis:clamp(62px,16vw,80px)}
  .departure-copy h2{max-width:18ch}
  .flight-track,.flight-trail{stroke-width:2}
}

@media (max-width:560px){
  .departure-rail{height:200vh}
  .pass{--pass-w:min(360px,90vw)}
  .pass-fields{gap:.6rem .7rem}
  .pass-fields dd{font-size:.86rem}
  .pass-stamp{left:1.15rem;bottom:1rem;font-size:.62rem;padding:.34rem .6rem}
  .departure-beats li{padding:.85rem 0 1rem}
  .departure-beats p{font-size:.9rem}
  /* The plane's path is tuned for a wide frame; hide the trail rather than
     letting it cut across the copy at phone width. */
  .flight-trail{opacity:.45}
}

/* Short landscape phones: a 200vh rail would be five screens of scrolling. */
@media (max-height:520px) and (orientation:landscape){
  .departure-rail{height:170vh}
  .departure-stage{padding:64px 0 40px}
  .pass{--pass-w:min(320px,42vw)}
}
