/* The documentary proof (2026-10-11): v1's stage and v2's pieces, plus the narrated lines and the sound button. Hadi on
   the first cut: no chapter cards (one continuous shot) and no cinema bars (the whole screen is the picture). */
#stage { background: #000; }

/* a narrated line on screen: whole, centred; revealed by the ripple (JS clips it), carried off by the camera */
.narr { position: absolute; inset: 0; margin: 0; display: flex; align-items: center; justify-content: center; padding: 0 24px;
  font-family: var(--disp); font-weight: 700; font-size: clamp(26px, 7.4vw, 60px); line-height: 1.5; text-align: center;
  visibility: hidden; transform-origin: 50% 50%; text-shadow: 0 0 22px rgba(238, 232, 220, .22); }

/* 2 · L5 over the prompt (prompt.js draws the prompt in the canvas): on a phone low, under the stack (as the worlds set
   their lines on a phone); on a wide screen above the field, at the head of its column. Its side margin is the worlds'
   (main.js sets --v3p-safe); whole, no word-by-word */
#v3p-l5 { flex-direction: column; justify-content: flex-end; align-items: flex-start; text-align: start;
  padding: 0 var(--v3p-safe, 36px) calc(8vh + env(safe-area-inset-bottom)); font-size: clamp(22px, 6.2vw, 32px); }
#v3p-l5 span { display: block; }
@media (min-width: 761px) and (min-aspect-ratio: 23/20) {
  #v3p-l5 { flex-direction: row; flex-wrap: wrap; justify-content: flex-start; align-items: flex-start; align-content: flex-start; column-gap: .3em;
    padding: 22vh var(--v3p-safe, 64px) 0; font-size: clamp(24px, 2.4vw, 46px); }
}

/* the touch hint breathes; the sound button sits by autoplay / manual */
/* until the touch, the whole glass is the thing to press (iOS also needs this to send the tap) */
#stage:not(.touched) { cursor: pointer; }
/* the touch hint (Hadi on review r2: the touch is required, and it turns the sound on): two lines under the light, which
   the canvas draws in the middle of the screen: «المس الفكرة» and, smaller, «التجربة أجمل بالصوت» after its sound mark.
   main.js who() stands each up into place (as the board's rows) and breathes them with the light; the mark's two waves
   run outward on their own, so something moves for as long as the light waits */
#touch-hint { position: absolute; inset-inline: 0; top: calc(50% + 66px); display: flex; flex-direction: column; align-items: center;
  gap: 10px; perspective: 600px; visibility: hidden; pointer-events: none; }
.th-l { margin: 0; transform-origin: 50% 100%; font-family: var(--text); letter-spacing: 0; text-shadow: 0 0 2px rgba(7, 7, 8, .85); }
#touch-hint-a { font-size: 15px; font-weight: 500; color: var(--bone); }
.th-snd { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 500; color: var(--ash); }
.th-snd svg { width: 20px; height: 16px; flex: none; overflow: visible; }
[dir="rtl"] .th-snd svg { transform: scaleX(-1); } /* the waves run the way the line reads */
.th-sp { fill: currentColor; }
.th-w { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: square; opacity: .2; animation: th-wave 1.8s linear infinite; }
.th-w2 { animation-delay: .3s; }
@keyframes th-wave { 0%, 70%, 100% { opacity: .2; } 35% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .th-w { animation: none; opacity: .8; } }
/* the door (Hadi's pick A, 2026-10-13): at the foot of the black screen, for a visitor who has reached the end card
   before, until the touch; its two rows stand up after the hint's (main.js touchHintAt) and stay still (a button that
   breathes reads as the thing to touch: the light is) */
#v3-door { position: absolute; inset-inline: 0; bottom: calc(44px + env(safe-area-inset-bottom)); display: flex; flex-direction: column;
  align-items: center; gap: 10px; perspective: 600px; visibility: hidden; }
.v3-door-q { font-size: 13px; font-weight: 500; color: var(--ash); }
.v3-door-btn { cursor: pointer; touch-action: manipulation; font-size: 14px; font-weight: 500; color: rgba(238, 232, 220, .9); background: rgba(7, 7, 8, .22);
  border: 1px solid rgba(238, 232, 220, .22); padding: 10px 18px; transition: border-color .2s, color .2s, translate .2s; }
.v3-door-btn:hover { border-color: rgba(238, 232, 220, .5); color: var(--bone); translate: 0 -4px; }
.v3-door-btn:active { translate: 0 -2px; }
.v3-door-btn:focus-visible { outline: 2px solid var(--bone); outline-offset: 4px; }
#sound { position: absolute; top: max(14px, env(safe-area-inset-top)); inset-inline-end: 86px; padding: 0; background: none; border: 0;
  cursor: pointer; z-index: 8; visibility: hidden; }
#sound .flap { min-width: 0; font-size: 12px; padding: 5px 10px; }
#chip, #mode { z-index: 8; }
#gate { z-index: 8; }

/* a press inside a world: the picture draws the button; this lands the press (and the keyboard's) on it */
#act { position: absolute; top: 0; left: 0; padding: 0; margin: 0; background: transparent; border: 0; cursor: pointer; z-index: 7;
  touch-action: manipulation; color: transparent; font-size: 1px; }
#act:focus-visible { outline: 2px solid var(--bone); outline-offset: 4px; }

/* the film's bar: chapters as segments (RTL: the film runs from the right), violet for what you have seen, dashed for
   what waits behind a gate; it thickens under the pointer, and a flap names the chapter */
#bar { position: absolute; inset-inline: 0; bottom: 0; height: calc(34px + env(safe-area-inset-bottom)); z-index: 8; cursor: pointer;
  touch-action: none; visibility: hidden; outline: none; -webkit-tap-highlight-color: transparent; }
#bar.on { visibility: visible; }
.rail { position: absolute; inset-inline: 14px; bottom: calc(12px + env(safe-area-inset-bottom)); height: 3px; display: flex; gap: 3px;
  transform-origin: 50% 100%; transition: transform .15s; }
#bar:hover .rail, #bar.drag .rail, #bar:focus-visible .rail { transform: scaleY(2); }
.rail .seg { position: relative; height: 100%; background: rgba(238, 232, 220, .24); overflow: hidden; }
.rail .seg.locked { background: repeating-linear-gradient(90deg, rgba(238, 232, 220, .2) 0 4px, transparent 4px 8px); }
.rail .seg i { position: absolute; inset: 0; background: var(--violet); transform-origin: 0 50%; transform: scaleX(0); }
[dir="rtl"] .rail .seg i { transform-origin: 100% 50%; }
.knob { position: absolute; inset-inline-start: 14px; bottom: calc(13.5px + env(safe-area-inset-bottom)); width: 12px; height: 12px; margin: -6px;
  background: var(--bone); box-shadow: 0 0 12px rgba(131, 107, 255, .9); pointer-events: none; opacity: 0; transition: opacity .15s; }
#bar:hover .knob, #bar.drag .knob, #bar:focus-visible .knob { opacity: 1; }
#bar:focus-visible .rail { outline: 1px solid var(--bone); outline-offset: 6px; }
.tip { position: absolute; inset-inline-start: 0; bottom: calc(28px + env(safe-area-inset-bottom)); min-width: 0; font-size: 12px; padding: 4px 8px;
  white-space: nowrap; pointer-events: none; visibility: hidden; }
#bar:hover .tip, #bar.drag .tip { visibility: visible; }

/* Hadi on the fourth cut: «light, premium UI/UX»: the controls are hairlines on the picture, not solid tiles; the
   gate's panel lets the sky through */
#chip .flap, #sound .flap, #mode .flap { background: rgba(7, 7, 8, .22); border-color: rgba(238, 232, 220, .16); font-weight: 500;
  color: rgba(238, 232, 220, .88); letter-spacing: .02em; transition: background-color .2s, border-color .2s, color .2s; }
#chip:hover .flap, #sound:hover .flap, #mode:hover .flap { border-color: rgba(238, 232, 220, .4); color: var(--bone); }
/* on a phone the intro's pull-back puts the brightest city lights under the chips: the narrated lines' ink halo under
   their letters (on a dark sky it does not show) */
@media (max-aspect-ratio: 4/5) {
  #chip .flap, #sound .flap, #mode .flap { text-shadow: 0 0 2px rgba(7, 7, 8, .85), 0 0 10px rgba(7, 7, 8, .7); }
}
/* autoplay and the sound, when on (Hadi, r3): the visitor's own decision, so the whole chip is violet; off, a hairline */
#sound[aria-pressed="true"] .flap, #mode[aria-pressed="true"] .flap,
#sound[aria-pressed="true"]:hover .flap, #mode[aria-pressed="true"]:hover .flap {
  background: var(--violet); border-color: var(--violet); color: #fff; text-shadow: none; }
#gate .flap { background: rgba(7, 7, 8, .25); border-color: rgba(238, 232, 220, .16); font-weight: 500; }
#gate .board .dest { font-weight: 600; }
#sheet { background: rgba(18, 18, 20, .9); border-color: rgba(238, 232, 220, .12); }
/* the board's column heads and the sheet's head are Arabic: never the mono face (IBM Plex Mono has no Arabic, its
   fallback breaks the joins); the Latin and the digits elsewhere stay mono */
#gate .board .col, #sheet .sheet-h { font-family: var(--text); font-weight: 500; letter-spacing: 0; }
/* on a phone, the column heads at the 12-px floor (story.css sets 11) */
@media (max-aspect-ratio: 4/5) { #gate .board .col { font-size: 12px; } }
/* the departures board never pops (Hadi: «smooth transitions»; it came and went in one frame). Its rows stand up into
   place like a split-flap board's, one after another, and the scrim behind them fades in. On the press (.leaving,
   main.js pressGate) the status flap turns over at once (below), «غادر» holds, and only from --fold (main.js sets it:
   FLIP_S − 0.55 s) do they fold away again: the button and the hint first, the board with «غادر» 0.25 s later, all
   folded by FLIP_S, the scrim with the board. Folded, a row lies back at 90°: it comes and goes the same way, so it
   never swings through the picture; the panel is hidden only once folded.
   The turn's pace: a row's height on screen goes as the sine of its turn, so a plain ease showed most of it in two
   frames (measured: 14/255 of change in one step). --g-in turns it so its height grows by the same amount every frame
   (2/π·asin t), --g-out so it shrinks evenly (2/π·acos(1 − t)); a cubic-bezier near them where linear() is missing */
#gate, #last { --g-in: cubic-bezier(.45, .05, .9, .55); --g-out: cubic-bezier(.1, .45, .55, .95); }
#gate { background: none; perspective: 900px; transition: visibility 0s linear .6s; --fold: .85s; }
@supports (transition-timing-function: linear(0, 1)) {
  #gate, #last { --g-in: linear(0, .064 10%, .128 20%, .194 30%, .262 40%, .333 50%, .41 60%, .494 70%, .59 80%, .713 90%, .798 95%, 1);
    --g-out: linear(0, .287 10%, .41 20%, .506 30%, .59 40%, .667 50%, .738 60%, .806 70%, .872 80%, .936 90%, .968 95%, 1); }
}
#gate.on { transition: visibility 0s; }
#gate::before { content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0;
  background: linear-gradient(to top, rgba(7, 7, 8, .66) 35%, rgba(7, 7, 8, 0)); transition: opacity .45s linear; }
#gate.on::before { opacity: 1; }
#gate.on.leaving::before { opacity: 0; transition: opacity .3s linear calc(var(--fold) + .25s); }
/* edge-on, perspective still leaves a sliver: a row's first third coming in and last third going out also fade, so
   no hairline appears or vanishes in one frame (the pops check flagged both) */
#gate .board, #gate .press, #gate .hint { rotate: x 90deg; opacity: 0; transform-origin: 50% 100%; }
#gate .board { transition: rotate .36s var(--g-in), opacity .12s linear; }
#gate .press { transition: transform .2s, background-color .2s, rotate .36s var(--g-in) .06s, opacity .12s linear .06s; }
#gate .hint { transition: rotate .36s var(--g-in) .12s, opacity .12s linear .12s; }
#gate.on .board, #gate.on .press, #gate.on .hint { rotate: none; opacity: 1; }
#gate.on.leaving .board, #gate.on.leaving .press, #gate.on.leaving .hint { rotate: x 90deg; opacity: 0; }
#gate.on.leaving .hint { transition: rotate .3s var(--g-out) var(--fold), opacity .1s linear calc(var(--fold) + .2s); }
#gate.on.leaving .press { transition: transform .2s, background-color .2s, rotate .32s var(--g-out) calc(var(--fold) + .02s),
  opacity .11s linear calc(var(--fold) + .23s); }
#gate.on.leaving .board { transition: rotate .3s var(--g-out) calc(var(--fold) + .25s), opacity .1s linear calc(var(--fold) + .45s); }
/* the button you pressed stays down, its breath held, until it folds */
#gate.on.leaving .press { background-color: var(--violet-down); transform: translateY(-2px); animation-play-state: paused; }
@media (min-width: 900px) { #gate::before { content: none; } }
@media (prefers-reduced-motion: reduce) {
  #gate .board, #gate .press, #gate .hint, #gate.on.leaving .board, #gate.on.leaving .press, #gate.on.leaving .hint {
    rotate: none; opacity: 0; transition: opacity .25s; }
  #gate.on .board, #gate.on .press, #gate.on .hint { opacity: 1; }
  #gate.on.leaving .board, #gate.on.leaving .press, #gate.on.leaving .hint { opacity: 0; transition: opacity .25s linear var(--fold); }
}

/* the status flap (Hadi on review r2: «I see the status as "Waiting" but not visibly changing when I click "انطلق"»; it
   changed at 0.25 s, as its row was already folding away): a split flap, four faces in one cell (index.html). On the
   press (main.js: .go) its upper half falls toward you round the hinge, edge-on at 0.22 s, and the lower half of «غادر»,
   on its back, comes down and lands at 0.43 s with a small bounce (its clatter: audio.js PLANS); «غادر» is violet, a
   person's decision, and its light comes on as it lands. The faces are solid, so one never shows through another */
#gate #gate-status { display: inline-grid; padding: 0; background: none; border: 0; position: relative; perspective: 200px;
  transition: box-shadow .45s linear; }
#gate #gate-status .sf-l { grid-area: 1 / 1; padding: 6px 10px; background: #0d0d10; border: 1px solid rgba(238, 232, 220, .18);
  color: var(--bone); backface-visibility: hidden; }
#gate #gate-status .sf-next, #gate #gate-status .sf-fall, #gate #gate-status .sf-rise { visibility: hidden; }
#gate #gate-status .sf-next, #gate #gate-status .sf-rise { background: var(--violet); border-color: var(--violet); color: #fff; }
/* the hinge: a hairline where the two halves meet */
#gate #gate-status::after { content: ''; position: absolute; inset-inline: 0; top: calc(50% - .5px); height: 1px; background: rgba(7, 7, 8, .7);
  z-index: 1; pointer-events: none; }
#gate #gate-status.go { box-shadow: 0 0 18px rgba(131, 107, 255, .65), 0 0 2px rgba(221, 155, 255, .9); transition-delay: .4s; }
#gate #gate-status.go .sf-now { clip-path: inset(50% 0 0 0); }
#gate #gate-status.go .sf-next { visibility: visible; clip-path: inset(0 0 50% 0); }
/* (a face is shown only by its animation, and never exactly edge-on: at 90° the eye lies in its plane and Chrome drew
   the face flat, the violet half for a frame before the fall; a face turning down toward you darkens, the one coming
   up from edge-on catches the light) */
#gate #gate-status.go .sf-fall { visibility: visible; clip-path: inset(0 0 50% 0); animation: sf-fall .22s cubic-bezier(.55, 0, .9, .45) forwards; }
#gate #gate-status.go .sf-rise { visibility: visible; clip-path: inset(50% 0 0 0); opacity: 0; animation: sf-rise .32s linear .22s forwards; }
@keyframes sf-fall { from { transform: rotateX(0); filter: brightness(1); } 99% { opacity: 1; } to { transform: rotateX(-89deg); filter: brightness(.45); opacity: 0; } }
@keyframes sf-rise {
  0% { transform: rotateX(89deg); opacity: 1; filter: brightness(1.5); animation-timing-function: cubic-bezier(.3, .55, .55, 1); }
  66% { transform: rotateX(0); filter: brightness(1); animation-timing-function: cubic-bezier(.25, .6, .5, 1); }
  83% { transform: rotateX(14deg); animation-timing-function: cubic-bezier(.5, 0, .75, .4); }
  100% { transform: rotateX(0); opacity: 1; filter: brightness(1); }
}
@media (prefers-reduced-motion: reduce) {
  #gate #gate-status.go .sf-fall, #gate #gate-status.go .sf-rise { animation: none; }
  #gate #gate-status.go .sf-now, #gate #gate-status.go .sf-fall { visibility: hidden; }
  #gate #gate-status.go .sf-next { clip-path: none; }
  #gate #gate-status.go { transition-delay: 0s; }
}

/* the narration script's cut (2026-10-11): the idea's lines sit under the point of light (the canvas draws it in the
   middle); L13 is two lines, and so is L13b after it (Hadi's G3), in the same place; a part too wide for a phone wraps,
   balanced. Both cross the Earth's sunlit limb: the intro's ink halo under their letters */
.narr.low { align-items: flex-end; padding-bottom: 30vh; }
#l13, #l13b { flex-direction: column; text-shadow: 0 0 2px rgba(7, 7, 8, .85), 0 0 14px rgba(7, 7, 8, .85); }
#l13 span, #l13b span { display: block; text-wrap: balance; }
/* the intro's lines L1–L4 (Hadi's review, 2026-10-11 night): an ink halo under the letters, so they read over the
   brightest city lights (no box); each breaks at its pause «…»: always on a phone (a part still too wide wraps, balanced,
   as 05's line does), on a wide screen only when the whole line does not fit. L4 is one breath, no pause (Hadi, G1): its
   parts are its two phrases, so a phone breaks it there and not after «من», where one balanced line put it */
#l1, #l2, #l3, #l4 { flex-wrap: wrap; column-gap: .28em; text-shadow: 0 0 2px rgba(7, 7, 8, .85), 0 0 14px rgba(7, 7, 8, .85); }
#l1, #l2, #l3 { align-content: flex-end; }
#l4 { align-content: center; }
#l1 > span, #l2 > span, #l3 > span, #l4 > span { text-wrap: balance; }
@media (max-aspect-ratio: 4/5) { #l1 > span, #l2 > span, #l3 > span, #l4 > span { flex-basis: 100%; } }
/* on a phone L1–L3 lie over the city's densest lights: a wider, darker halo under their letters */
@media (max-aspect-ratio: 4/5) {
  #l1, #l2, #l3 { text-shadow: 0 0 2px rgba(7, 7, 8, .85), 0 0 14px rgba(7, 7, 8, .85), 0 0 28px rgba(7, 7, 8, .75); }
}

/* 4 · you (Hadi on review r2: «bring the idea dot between the text and the button»): it reads from the top: L20 and L21
   (each in the same place, one at a time), then the point of light (finale.js layout(): midway between this line's foot
   and the press's head, so it reads these numbers), then the last press (#last), the whole Earth below. In vh, so it
   keeps its proportions on short screens */
.narr.you { align-items: flex-start; padding-top: 11vh; }
@media (min-aspect-ratio: 4/5) { .narr.you { padding-top: 12vh; } }
/* L20, L21 and L23 break at their pause «…» as the intro's lines do (finale.js sets the two parts): always on a phone,
   on a wide screen only when the whole line does not fit */
#l20, #l21, #l23 { flex-wrap: wrap; column-gap: .28em; align-content: flex-start; }
#l20 > span, #l21 > span, #l23 > span { text-wrap: balance; }
@media (max-aspect-ratio: 4/5) { #l20 > span, #l21 > span, #l23 > span { flex-basis: 100%; } }

/* 5 · the finale (finale.js places these every frame): the worlds' numbers in the machine voice, the lockup (an SVG,
   crisp at any density), L23 under it */
.fin-n { position: absolute; top: 0; left: 0; font-size: 13px; color: var(--bone); letter-spacing: .08em; visibility: hidden; }
@media (min-width: 900px) { .fin-n { font-size: 18px; } }
.fin-logo { position: absolute; top: 0; left: 0; transform-origin: 0 0; visibility: hidden; }
.fin-logo svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* (L23 can sit over the morning Earth: the intro's ink halo under its letters, no box) */
#l23 { align-items: flex-start; padding-top: 0; transform-origin: 50% 0; font-weight: 600; font-size: clamp(18px, 4.6vw, 34px);
  color: rgba(238, 232, 220, .92); text-shadow: 0 0 2px rgba(7, 7, 8, .85), 0 0 14px rgba(7, 7, 8, .85); }

/* the last press: the visitor's own, under the light (its line above it); finale.js layout() reads these two heights */
#last { position: absolute; inset-inline: 0; top: 35.3vh; display: flex; justify-content: center; visibility: hidden; z-index: 8; }
@media (min-aspect-ratio: 4/5) { #last { top: 32.5vh; } }
#last.on { visibility: visible; }
#last.nudge { animation: nudge .35s steps(5); }
#last .press { min-width: 220px; text-align: center; }
#last .press.pressed { background: var(--violet-down); transform: translateY(-2px); }
/* and it never pops in (it came whole in one frame): it stands up into place as the board's rows do (--g-in, its height
   on screen growing evenly; its edge-on first third fading). Its exit stays at once: your press detonates the light */
#last { perspective: 900px; }
#last .press { rotate: x 90deg; opacity: 0; transform-origin: 50% 100%;
  transition: transform .2s, background-color .2s, rotate .36s var(--g-in), opacity .12s linear; }
#last.on .press { rotate: none; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  #last .press { rotate: none; transition: transform .2s, background-color .2s, opacity .25s; }
}

/* the end card: no panel, the sky keeps moving behind it; under the lockup and L23 (finale.js sets --fin-top), the three
   doors (one column on a phone, a row on a wide screen), the address, the replay; each arrives from below */
.fin-end { position: absolute; inset-inline: 0; top: var(--fin-top, 40vh); display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 0 max(36px, 4vw); }
.fin-end p { margin: 0; }
.fin-kicker { font-family: var(--text); font-weight: 500; font-size: 14px; color: var(--ash); visibility: hidden; } /* Arabic: never the mono face */
.fin-doors { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; width: min(560px, 100%); }
.fin-doors li { overflow: hidden; }
.fin-door { display: grid; grid-template-columns: auto 1fr; column-gap: 14px; row-gap: 2px; align-items: baseline; padding: 13px 16px;
  background: rgba(10, 10, 14, .58); border: 1px solid rgba(238, 232, 220, .14); clip-path: var(--chamfer); visibility: hidden; }
.fin-door-n { grid-row: span 2; font-size: 13px; color: var(--ash); }
.fin-door b { font-family: var(--disp); font-weight: 700; font-size: clamp(20px, 5vw, 26px); }
.fin-door-l { font-size: 14px; color: rgba(238, 232, 220, .7); }
.fin-sub { font-family: var(--text); font-weight: 500; font-size: 15px; color: rgba(238, 232, 220, .85); visibility: hidden; }
.fin-replay { margin-top: 6px; display: inline-flex; align-items: center; gap: 10px; color: var(--bone); visibility: hidden; }
.fin-replay svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: square; }
@media (min-aspect-ratio: 4/5) {
  .fin-end { gap: 16px; }
  .fin-doors { grid-template-columns: repeat(3, minmax(0, 1fr)); width: min(1100px, 100%); gap: 16px; }
  .fin-door { padding: 16px 18px; }
}
/* the badge is Arabic too: the text face, not the mono one */
