﻿/* ============================================================================
   magic.css — מערכת העיצוב של "קסם של במה" (Fairyness)
   שפה: "הולוגרמה רגישה" (שקופיות המיתוג של נסיה).
   טיפוגרפיה: גברת לוין בלבד (D-21). לוגואים = נכסים רשמיים, טכני בלבד (D-25).
   ארט מלא-מסך לפי כיוון המסך (D-19). RTL. מובייל-פירסט.
   ============================================================================ */

/* ═══════════ 1. פונט ═══════════ */
@font-face {
  font-family: 'Gveret Levin';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/GveretLevinAlefAlefAlef-Regular.woff2) format('woff2');
}

/* ═══════════ 2. טוקנים ═══════════ */
:root {
  /* — פלטת "הולוגרמה רגישה" — */
  --pearl:      #FDFBF7;   /* לבן פנינה — טיפוגרפיה וכרטיסים */
  --pink-air:   #FBEFF2;   /* ורוד פסטל — רקעים */
  --gold-soft:  #C9A45C;   /* זהב רך — אקצנטים */
  --gold-hi:    #E8CE9C;
  --rose-gold:  #D9A982;
  --ink:        #4A3B40;   /* דיו רך — לעולם לא שחור */
  --ink-deep:   #6B3B52;   /* דיו על משטח בהיר (כפתור) */

  /* — עולם הקריסטל (ברירת מחדל: ורוד־פנינה, עד בחירה במסך 4) — */
  --c-primary: #E487AE;
  --c-deep:    #C25E8A;
  --c-air:     #FBEFF2;
  --c-glow:    rgba(228, 135, 174, .38);
  --c-ink:     #6B3B52;   /* דיו על משטח בהיר בצבע הקריסטל */

  /* ═══ יחידת המערכת ═══
     כל גודל, מרווח ומידה בעמוד נגזרים מ---u אחת. כך הקומפוזיציה גדלה
     ומתכווצת כגוף אחד ולא כאוסף אלמנטים שנסחפים זה מזה — זו התשובה
     ל"רספונסיביות מגושמת": לא מתאימים כל רכיב בנפרד, מקנה־מידה סצנה שלמה.
     הנוסחה נשענת על הממד הקטן מבין השניים, ולכן שום דבר לא גולש לעולם. */
  --u-base: clamp(3.15px, min(1.02vw, .445vh), 5.4px);
  /* שני מקדמים שנקבעים ב-JS, בסדר עדיפות מכוון:
     --fit-air  = אוויר (מרווחים, לוגו) — נכנע ראשון, יורד עד 0.4
     --fit      = טקסט — נכנע רק אחריו, ולעולם לא מתחת לרצפת קריאות
     כך כשצפוף מוותרים על מרווח ועל גודל לוגו לפני שפוגעים בקריאוּת. */
  --fit-air: 1;
  --fit: 1;
  --u: calc(var(--u-base) * var(--fit));
  --air: calc(var(--u-base) * var(--fit-air));

  /* — סקאלת טיפוגרפיה (גברת לוין: כתב־יד דק ⇒ גדול יותר, אוורירי יותר) — */
  --fs-greet: calc(var(--u) * 6.3);
  --fs-body:  calc(var(--u) * 4.95);
  --fs-cta:   calc(var(--u) * 5.9);
  --fs-micro: calc(var(--u) * 4);
  --lh-greet: 1.5;
  --lh-body:  1.72;

  /* — "משקל מדומה" (הפונט חד־משקלי) — לעולם ≤ .6px, אחרת נסתמות העיניות — */
  --stroke-soft:  .3px;
  --stroke-heavy: .5px;

  /* — מתכוני זוהר — */
  /* הצללה כפולה: גרעין כהה וצמוד = הפרדה חדה מהרקע; הילה ורודה-זהובה = הקסם */
  --halo-strong: 0 1px 2px rgba(15,10,26,.95), 0 0 8px rgba(15,10,26,.9),
                 0 0 22px rgba(242,175,196,.55), 0 0 54px rgba(217,169,130,.3);
  --halo-soft:   0 1px 2px rgba(15,10,26,.95), 0 0 7px rgba(15,10,26,.88),
                 0 0 18px rgba(242,175,196,.38);
  --glow-pill:   0 0 26px rgba(242,175,196,.42), 0 0 64px rgba(217,169,130,.2);

  /* ═══ קצב ותנועה — מערכת אחת לכל המסע ═══
     ⚠️ נבנה לפי תקני Material 3 / Apple HIG (HE):
     מיקרו-אינטראקציה 150-300ms · כניסת תוכן ≤400ms · מדרגה בין פריטים 40-80ms.
     קודם היה כאן 1000ms לכל אלמנט עם מדרגות של 300ms — פי 3-5 מהתקן, וזה
     בדיוק מה שהרגיש כבד ומכני. מדרגה צפופה נקראת כתנועה *אחת* זורמת, ולא
     כארבעה אירועים נפרדים.
     Motion system (EN): one shared rhythm across the journey. Durations and
     stagger follow MD3/HIG; the previous 1000ms/300ms values read as four
     separate sluggish events instead of a single flowing sweep. */
  --t-micro: 220ms;
  --t-scene: 820ms;
  --t-enter: 460ms;          /* כניסת אלמנט תוכן */
  --stagger: 80ms;           /* מדרגה בין אלמנטים עוקבים */
  --ease-out: cubic-bezier(.22, .9, .32, 1);
  /* האטה מודגשת — התקן ל"הגעה" שמרגישה טבעית ויקרה */
  --ease-enter: cubic-bezier(.05, .7, .1, 1);
  --ease-exit:  cubic-bezier(.3, 0, .8, .15);
}

/* במצב רוחבי הגובה הוא החוסם — היחידה נגזרת ממנו, והעולם גדל כגוש אחד */
@media (min-aspect-ratio: 4/5) {
  :root { --u-base: clamp(3.7px, .53vh, 6.5px); }
}

/* ═══════════ 3. בסיס ═══════════ */
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  font-family: 'Gveret Levin', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
  color: var(--pearl);
  background: #14101F;
  direction: rtl;
  overflow: hidden;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { display: block; max-width: 100%; }
button { font: inherit; color: inherit; }

/* חגורת בטיחות לגלישת טקסט — בשום סביבה שורה לא תישאר בלתי־שבורה */
.content, .content * { min-width: 0; max-width: 100%; overflow-wrap: break-word; }

/* ═══════════ 4. במה מלאת־מסך (D-19 — אין יותר "במה ממורכזת") ═══════════ */
#stage {
  position: fixed; inset: 0;
  width: 100%; height: 100dvh;
  overflow: hidden;
  perspective: 1100px;
}
#dust { position: fixed; inset: 0; z-index: 40; pointer-events: none; }

/* ═══════════ 5. מסכים ומעברי סצנה ═══════════ */
.step {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateZ(-300px) scale(.92);
  transition: opacity var(--t-scene) ease,
              transform var(--t-scene) var(--ease-out),
              visibility 0s linear var(--t-scene);
}
.step.is-active {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: none; transition-delay: 0s;
}
.step.is-exit { opacity: 0; visibility: visible; transform: translateZ(240px) scale(1.16); }
.step-inner { position: relative; width: 100%; height: 100%; }

body.warping #stage::after {
  content: ''; position: absolute; inset: 0; z-index: 30; pointer-events: none;
  background: radial-gradient(58% 58% at 50% 46%, rgba(253,241,246,.8), rgba(244,198,220,.22) 55%, transparent 78%);
  animation: warpflash 720ms ease-out forwards;
}
@keyframes warpflash { from { opacity: 0 } 28% { opacity: 1 } to { opacity: 0 } }

/* ═══════════ 6. שכבת הארט (לפי כיוון המסך) ═══════════ */
.art-layer { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.art-layer .art {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 68%;              /* עוגן אנכי: שומר על קשת השער */
  transform-origin: 50% 46%;
  will-change: transform;
}
@media (min-aspect-ratio: 4/5) {
  .art-layer .art { object-position: 50% 55%; transform-origin: 50% 52%; }
}
/* מסכי מחשב אולטרה-רחבים בלבד — הארט שלם על עותק מטושטש של עצמו.
   ⚠️ חייב min-width: טלפון מסובב מגיע ליחס 2.7 ואסור שיקטין לו את הארט. */
@media (min-aspect-ratio: 21/9) and (min-width: 1200px) {
  .art-layer .art { object-fit: contain; object-position: 50% 50%; z-index: 1; }
  .art-layer::before {
    content: ''; position: absolute; inset: -6%;
    background: var(--art-url) center / cover no-repeat;
    filter: blur(46px) saturate(1.12) brightness(.86);
    transform: scale(1.14);
  }
}
/* ═══ נשימת עולם ═══
   ⚠️ כאן ישב הבאג ש"הרגיש כמו עמעום": הנשימה התחילה מ-scale(1.012) ורצה
   ברקע, כך שברגע שהוידאו נמסר לארט הארט היה ב-scale(1.042) בזמן שהפריים
   האחרון של הסרטון הוא scale(1.0). התמונה קפצה ב-4.2% — כ-16px בקצוות.
   התיקון חסר־מצב: הנשימה מתחילה מ-scale 1 *ובהשהיה* ארוכה מ-LEAD_BUILD,
   ולכן בכל מסירה הארט נמצא בדיוק בקנה המידה של הסרטון. אין מה שיכול
   "לא להתעדכן" — זו תכונה של העיתוי עצמו, לא של דגל שמישהו צריך להדליק. */
.art-layer .art { animation: worldBreathe 11s 2.6s ease-in-out infinite alternate; }
@keyframes worldBreathe { from { transform: none } to { transform: scale(1.04) } }

/* ═══════════ 7. שכבות אווירה של מסך 1 ═══════════ */
.gate-glow {
  position: absolute; z-index: 1; pointer-events: none;
  left: 50%; top: 44%; width: 62%; aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(253,236,244,.3), rgba(244,198,220,.1) 55%, transparent 76%);
  animation: gatePulse 5.6s ease-in-out infinite;
}
@media (min-aspect-ratio: 4/5) { .gate-glow { top: 52%; width: 34%; } }
@keyframes gatePulse {
  0%, 100% { opacity: .5;  transform: translate(-50%,-50%) scale(.95) }
  50%      { opacity: 1;   transform: translate(-50%,-50%) scale(1.06) }
}

/* וילון האור על פתח השער — נפרם בלחיצה */
.veil { position: absolute; z-index: 1; inset: 40% 30% 12%; pointer-events: none; }
@media (min-aspect-ratio: 4/5) { .veil { inset: 34% 42% 14%; } }
.veil i {
  position: absolute; top: 0; bottom: 0; width: 52%;
  transition: transform 900ms ease-in, opacity 900ms ease-in;
}
.veil i:first-child { right: 0; background: linear-gradient(270deg, rgba(253,241,246,.3), transparent); }
.veil i:last-child  { left: 0;  background: linear-gradient(90deg,  rgba(253,241,246,.3), transparent); }
.veil { animation: veilBreathe 7s ease-in-out infinite alternate; }
@keyframes veilBreathe { from { opacity: .75 } to { opacity: 1 } }

/* וינייטה — עומק קולנועי */
.vignette {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(132% 96% at 50% 44%, transparent 56%,
              rgba(18,12,32,.34) 86%, rgba(14,10,26,.6) 100%);
}

/* ═══════════ 8. תוכן — פריסת מסך 1 ═══════════
   ⚠️ עיקרון מבני: לוגו, טקסט וכפתור הם פריטים באותו זרם אנכי אחד.
   הכפתור אינו מרחף בנפרד — ולכן התנגשות ביניהם אינה אפשרית פיזית.
   הגובה נשלט ע"י --fit (מנוע ההתאמה ב-app.js). */
.content {
  position: absolute; inset: 0; z-index: 3;
  display: flex;
  text-align: center;
  /* ⚠️ מרווח עליון מערכתי — כאן, פעם אחת, לכל המסכים. הבעיה חזרה שוב ושוב
     כי הבסיס היה 10px והתיקון היה נקודתי בכל מסך. עכשיו לאף מסך אין טקסט
     צמוד לקצה כברירת מחדל; scales עם גובה המסך ומכבד את המגרעת (notch).
     מסך רשאי להוסיף padding-bottom להרמת הכפתור — אבל לא צריך לגעת בעליון. */
  padding: max(clamp(30px, 8.5vh, 84px), env(safe-area-inset-top))
           max(18px, env(safe-area-inset-right))
           max(14px, env(safe-area-inset-bottom))
           max(18px, env(safe-area-inset-left));
  pointer-events: none;
}
.stack {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column; align-items: center;
  justify-content: space-between;      /* לוגו למעלה · טקסט באמצע · כפתור למטה */
  gap: calc(var(--air) * 2);
  /* ריווח תחתון כ-padding ולא כ-margin על הכפתור: margin של הפריט האחרון
     יוצר גלישת-רפאים שהמדידה לא יכולה לפתור לעולם. */
  padding-bottom: calc(var(--air) * 1.4);
}
.stack > * { pointer-events: auto; flex: 0 0 auto; }

/* לוגו האירוע — הכותרת המרכזית (D-26). מתכווץ מהר יותר מהטקסט כשצפוף */
.hero-logo {
  width: calc(var(--air) * 50);
  max-width: 46%;
  margin-top: calc(var(--air) * .4);
  opacity: 0;
  filter: drop-shadow(0 0 26px rgba(242,175,196,.55)) drop-shadow(0 6px 22px rgba(20,14,34,.6));
  animation: bloomIn 1250ms 380ms var(--ease-out) forwards;
}
@media (min-aspect-ratio: 4/5) { .hero-logo { width: calc(var(--air) * 40); max-width: 22%; margin-top: 0; } }

/* גוש הטקסט — פריט בזרם, לא שכבה מרחפת. נגמר תמיד לפני הכפתור */
.text-block {
  width: 100%;
  max-width: calc(var(--u) * 84);
  min-height: 0;
  display: grid; gap: calc(var(--air) * 2.9);
  /* ממורכז אנכית בדיוק בין הלוגו לכפתור. margin אוטומטי בתוך flex column
     בולע את כל השארית ומחלק אותה שווה בשווה מעל ומתחת — והתיבה עצמה
     עדיין מודדת את גובה תוכנה (בניגוד ל-flex:1 שהיה מותח את הזכוכית).
     כשאין שארית המרווחים מתאפסים מעצמם, והמנוע רואה את הגלישה כרגיל. */
  margin-block: auto;
}
@media (min-aspect-ratio: 4/5) { .text-block { max-width: calc(var(--u) * 96); } }

/* ── שורת הברכה: טקסט בשורה אחת, הלוגו מתחתיו, מרווחים שווים ── */
.greet {
  display: grid;
  justify-items: center;
  /* אותו מרווח בדיוק כמו בין הלוגו לשורה שאחריו ⇒ ריתמוס אנכי אחיד */
  gap: calc(var(--air) * 2.9);
  opacity: 0;
  animation: riseIn 1000ms 780ms var(--ease-out) forwards;
}
.greet .lead {
  display: block;
  white-space: nowrap;                 /* "ברוכה הבאה לעולם של" — שורה אחת תמיד */
  font-size: var(--fs-greet);
  line-height: var(--lh-greet);
  letter-spacing: .02em;
  color: var(--pearl);
  -webkit-text-stroke: var(--stroke-soft) currentColor;
  text-shadow: var(--halo-strong);
}
/* המילה Fairyness = הלוגו הרשמי (בפונט גברת לוין אין אותיות לטיניות) */
.greet .brand {
  display: block;
  width: calc(var(--air) * 40);
  max-width: 62%;
  filter: drop-shadow(0 1px 2px rgba(15,10,26,.95)) drop-shadow(0 0 7px rgba(15,10,26,.85))
          drop-shadow(0 0 22px rgba(242,175,196,.6));
}

/* ── גוף הקופי: היררכיה בגודל, בשקיפות, בריווח ובגוון — בפונט אחד ── */
.lines {
  display: grid; gap: calc(var(--air) * 2.6);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--pearl);
  -webkit-text-stroke: .22px currentColor;   /* משקל מדומה — כתב־יד דק צריך גוף */
  text-shadow: var(--halo-soft);
}
.lines .st { opacity: 0; animation: riseIn 900ms var(--ease-out) forwards; }
.lines .st:nth-child(1) { animation-delay: 1250ms; }
.lines .st:nth-child(2) { animation-delay: 1700ms; }
.lines .st:nth-child(3) { animation-delay: 2150ms; }
.lines .st:nth-child(4) { animation-delay: 2750ms; }
.lines i { display: block; font-style: normal; }

/* לחישת פתיחה — קטן, מרוחק, מהוסס */
/* ⚠️ מכפיל קטן מ-1 יכול לרדת מתחת לרצפת הקריאוּת *מבלי* שהמנוע כיווץ
   כלום — הרצפה שלו מגינה מפני כיווץ, לא מפני גודל טבעי קטן מדי.
   ב-320px הלחישה יצאה 14.3px. max() אוכף את הרצפה במקור. */
.st.whisper {
  font-size: max(15.2px, calc(var(--fs-body) * .92));
  letter-spacing: .045em;
  opacity: 0; color: #F3E4EA;
}
.st.whisper.shown, html.qa .st.whisper { opacity: .82; }

/* הגוף — הרגיל, הזורם */
.st.flow { max-width: 32ch; margin-inline: auto; }

/* הנשימה — שלוש מילים, שלוש שורות, אוויר גדול. הלב הפואטי */
.st.breath {
  margin-block: calc(var(--air) * 1.1);
  font-size: calc(var(--fs-body) * 1.06);
  line-height: 1.95;
  letter-spacing: .03em;
  color: #FDF4E8;
  text-shadow: 0 1px 2px rgba(15,10,26,.95), 0 0 8px rgba(15,10,26,.9),
               0 0 20px rgba(232,206,156,.45);
}
.st.breath i + i { opacity: .94; }

/* ההבטחה — גדולה במעט, והסיומת בזהב רך */
.st.promise {
  font-size: calc(var(--fs-body) * 1.05);
  max-width: 30ch; margin-inline: auto;
}
.st.promise em {
  font-style: normal;
  color: var(--gold-hi);
  -webkit-text-stroke: .3px currentColor;
  text-shadow: 0 1px 2px rgba(15,10,26,.95), 0 0 10px rgba(201,164,92,.6),
               0 0 26px rgba(232,206,156,.4);
}

@keyframes riseIn   { from { opacity: 0; transform: translateY(14px) } to { opacity: 1; transform: none } }
@keyframes fadeDown { from { opacity: 0; transform: translateY(-10px) } to { opacity: 1; transform: none } }
@keyframes bloomIn  { from { opacity: 0; transform: scale(.9) } 60% { opacity: 1 } to { opacity: 1; transform: none } }

/* ═══════════ 9. שני מצבי טקסט (?text=a|b) ═══════════ */
/* A — "הילה": טקסט חופשי + סקרים מקומיים עדינים (ברירת מחדל) */
html[data-text="a"] .content::before,
html[data-text="a"] .content::after {
  content: ''; position: absolute; left: 0; right: 0; z-index: -1; pointer-events: none;
}
/* שמי לילה מתעמקים סביב הלוגו — הוא זוהר במקום להיראות מודבק */
html[data-text="a"] .content::before {
  top: 0; height: 34%;
  background: radial-gradient(78% 100% at 50% 8%, rgba(18,12,32,.62), rgba(18,12,32,.3) 55%, transparent 78%);
}
/* גוש הטקסט התחתון — סקרים לקריאות על אור השער */
html[data-text="a"] .content::after {
  bottom: 0; height: 56%;
  background: linear-gradient(0deg, rgba(17,11,30,.8) 0%, rgba(17,11,30,.62) 28%,
              rgba(17,11,30,.36) 54%, rgba(17,11,30,.12) 76%, transparent 100%);
}
/* "מצע אור" — עמעום אליפטי רך בדיוק מאחורי הטקסט, במקום פס רוחבי כבד */
html[data-text="a"] .text-block { position: relative; }
html[data-text="a"] .text-block::after {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -14% -12% -6%;
  background: radial-gradient(58% 52% at 50% 46%, rgba(14,9,26,.62), rgba(14,9,26,.34) 52%, transparent 78%);
}

/* B — "זכוכית פנינה": פאנל עם מסגרת הולוגרפית */
html[data-text="b"] .content::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 34%; z-index: -1; pointer-events: none;
  background: radial-gradient(78% 100% at 50% 8%, rgba(18,12,32,.6), rgba(18,12,32,.28) 55%, transparent 78%);
}
html[data-text="b"] .text-block {
  position: relative;
  padding: clamp(18px, 2.8vh, 24px) clamp(16px, 4.6vw, 24px);
  /* אין margin-bottom: הוא היה "שמירת מקום" לכפתור מהתקופה שבה הכפתור ריחף.
     היום הכפתור פריט בזרם, והמרווח נקבע ע"י ה-gap של הסטאק ⇒ הזכוכית
     מתמרכזת באמת בין הלוגו לכפתור. */
  border-radius: 30px;
  background: rgba(26, 18, 42, .42);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  box-shadow: 0 0 40px rgba(242,175,196,.28), 0 14px 40px rgba(14,9,26,.45),
              inset 0 1px 0 rgba(253,251,247,.16);
}
html[data-text="b"] .lines { text-shadow: 0 1px 9px rgba(20,14,34,.6); }
html[data-text="b"] .text-block::before {
  content: ''; position: absolute; inset: -1px; border-radius: 31px; padding: 1.2px;
  background: conic-gradient(from 210deg, rgba(232,206,156,.85), rgba(242,175,196,.7),
              rgba(200,225,250,.5), rgba(242,175,196,.6), rgba(232,206,156,.85));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  html[data-text="b"] .text-block { background: rgba(28, 20, 45, .74); }
}

/* ═══════════ 10. כפתור אבקת־פיות (הנכס של נסיה + טקסט חי) ═══════════ */
.dust-btn {
  position: relative; z-index: 4;   /* בזרם — לא מרחף. אינו יכול להתנגש בטקסט */
  width: calc(var(--u) * 80);
  max-width: 78%;
  aspect-ratio: 917 / 262;
  min-height: 52px;
  display: grid; place-items: center;
  border: 0; background: transparent; cursor: pointer;
  opacity: 0;
  animation: riseIn 950ms 3050ms var(--ease-out) forwards;
  filter: drop-shadow(0 0 22px rgba(242,175,196,.4)) drop-shadow(0 6px 18px rgba(20,14,34,.45));
  transition: transform var(--t-micro) var(--ease-out), filter var(--t-micro) ease;
  -webkit-tap-highlight-color: transparent;
}
.dust-btn .pill {
  position: absolute; inset: 0; z-index: 0;
  background: url(../assets/ui/cta-pill.webp) center / 100% 100% no-repeat;
  border-radius: 999px; overflow: hidden;
}
/* הבזק שימר שחוצה את הכפתור */
.dust-btn .pill::after {
  content: ''; position: absolute; top: -20%; bottom: -20%; width: 28%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.72), transparent);
  transform: translateX(-260%) skewX(-14deg);
  animation: shimmer 5.4s 4s ease-in-out infinite;
}
@keyframes shimmer {
  0%   { transform: translateX(-260%) skewX(-14deg) }
  22%  { transform: translateX(360%)  skewX(-14deg) }
  100% { transform: translateX(360%)  skewX(-14deg) }
}
.dust-btn .label {
  position: relative; z-index: 1;
  font-size: var(--fs-cta); line-height: 1.15;
  color: var(--ink-deep);
  -webkit-text-stroke: var(--stroke-heavy) currentColor;
  text-shadow: 0 1px 0 rgba(253,251,247,.55);
  padding-bottom: .12em;
}
.dust-btn:hover { transform: scale(1.022);
  filter: drop-shadow(0 0 32px rgba(242,175,196,.6)) drop-shadow(0 6px 20px rgba(20,14,34,.5)); }
.dust-btn:active { transform: scale(.962); }
.dust-btn:focus-visible { outline: 3px solid var(--gold-hi); outline-offset: 6px; border-radius: 999px; }

/* ═══════════ 12. פתיחת השער (יציאה) — גיבוי CSS כשאין וידאו ═══════════
   עקומה איטית-בהתחלה ומאיצה: מרגיש כמו "נשאבים פנימה", לא כמו זום מכני. */
.s01.opening .art { animation: none; transform: scale(1.42);
  filter: blur(3px) brightness(1.12);
  transition: transform 1600ms cubic-bezier(.72,0,.58,1), filter 1600ms ease-in; }
.s01.opening .veil i:first-child { transform: translateX(72%); opacity: 0; }
.s01.opening .veil i:last-child  { transform: translateX(-72%); opacity: 0; }
.s01.opening .gate-glow { animation: none; opacity: 1;
  transform: translate(-50%,-50%) scale(2.8);
  transition: transform 1400ms ease-in, opacity 1400ms; }
/* ⚠️ כאן ישבה רשימת סלקטורים תלושה שנדבקה ל-.flare, ולכן .content ו-.dust-btn
   קיבלו position:absolute + gradient של הפלייר במסלול הגיבוי (כלומר בדסקטופ,
   בכל לחיצה). יציאת האלמנטים מטופלת ע"י .fading — שנשאר דלוק גם כאן. */
.flare {
  position: absolute; inset: 0; z-index: 6; pointer-events: none; opacity: 0;
  background: radial-gradient(54% 54% at 50% 46%, rgba(255,250,246,.96), rgba(248,217,230,.5) 52%, transparent 76%);
}
.s01.opening .flare { animation: flareIn 1600ms cubic-bezier(.7,0,.6,1) forwards; }
@keyframes flareIn { 0% { opacity: 0 } 40% { opacity: .16 } 78% { opacity: .62 } 100% { opacity: 1 } }

/* ═══════════ 12b. מעבר וידאו קולנועי בין מסכים ═══════════
   הפריים הראשון = הארט של המסך הנוכחי, האחרון = של הבא ⇒ מסירה בלי תפר. */
#xfade {
  position: fixed; inset: 0; z-index: 50;
  opacity: 0; pointer-events: none;
  /* ⚠️ אין רקע כהה! (HE) קודם היה כאן #14101F, וברגע שהווידאו הוסתר לפני
     שהפוסטר צויר — הכהה הזה הוא בדיוק "השנייה של חושך" שנראתה בטלפון.
     שכבה שקופה חושפת את המסך שמתחת (שכבר נבנה), לא צבע זר.
     No dark backdrop (EN): the previous #14101F was literally the "one second
     of black" seen on device whenever the video was hidden before the poster
     painted. Transparent reveals the already-built next screen instead. */
  background: transparent;
  background-size: cover;
  transition: opacity 560ms cubic-bezier(.4,0,.6,1);
}
#xfade.on { opacity: 1; }
/* ⚠️ ההופעה חייבת להיות מיידית ובלי דעיכה: הפריים הראשון של הסרטון זהה
   לארט שמתחתיו, ולכן הופעה פתאומית היא *בלתי־נראית* — בעוד fade-in הוא
   בדיוק ה"אפקט מעבר" שמסגיר את התפר. הדעיכה נשארת רק ליציאה. */
#xfade.instant { transition: none; }
/* ⚠️ חגורת בטיחות: כל מה שנמצא בשכבת הוידאו אינו לחיץ, נקודה. ל-#xfade יש
   pointer-events:none, אבל `.stack > *` מחזיר auto לילדים — ולכן תוכן שנשאר
   שם אחרי מעבר בלע את הלחיצות של המסך הבא. הניקוי ב-JS הוא התיקון;
   הכלל הזה מבטיח שגם אם ניקוי ייכשל, שום דבר לא ייחסם. */
#xfade, #xfade * { pointer-events: none !important; }

/* ── יציאת מסך 1 — תנועה, לא היעלמות ──
   מורם מעל שכבת הוידאו כדי שהתוכן ייראה נשאב פנימה בזמן שהשער כבר נפתח
   מתחתיו. כך התנועה מתחילה בפריים של הלחיצה, לא אחרי החלטה כלשהי. */
/* ⚠️ z-index לא יכול להרים את התוכן מעל הוידאו: #stage הוא position:fixed,
   ולכן הוא־עצמו הקשר־ערימה אטום — שום z-index מבפנים לא בורח החוצה.
   לכן ה-JS *מעביר* את .content לתוך #xfade לפני היציאה. הכללים כאן מסומנים
   על האלמנט עצמו (.is-exiting) ולא על אבותיו, כדי שיעבדו בשני המקומות:
   בתוך המסך (מסלול גיבוי) ובתוך שכבת הוידאו (מסלול וידאו). */
.content.is-exiting { z-index: 55; pointer-events: none; }
/* ⚠️ העיקוּל כאן הוא ההבדל בין "מיידי" ל"תקוע". עקומת ease-in חדה
   (cubic-bezier(.6,0,.85,.35)) משאירה את האטימות על 0.92 באמצע האנימציה —
   כלומר 60% מהזמן שבו *כלום לא נראה קורה*. זה נקרא "השהיה אחרי הלחיצה".
   לכן: linear בקיצור-דרך, והעיקולים מוגדרים בין הפריימים — האטימות יורדת
   מיד, בעוד התנועה עצמה ממשיכה להאיץ. */
/* ⚠️ אך ורק opacity ו-transform. שתי אלה רצות על ה-GPU בלי לגעת בפריסה;
   filter: blur() המונפש שהיה כאן קודם אילץ ריפיינט מלא בכל פריים, ועל
   פאנל שיש עליו גם backdrop-filter זה היה הגורם המרכזי לתקיעות. */
.content.is-exiting .hero-logo,
.content.is-exiting .text-block,
.content.is-exiting .dust-btn { will-change: transform, opacity; }

/* ⚠️ יציאה מהירה מכניסה (HE): כלל תנועה מקובל — יציאה ב-~65% ממשך הכניסה,
   כי המשתמשת כבר החליטה והמסך צריך לפנות מקום מיד. איטית מדי = "האתר תקוע".
   Exits run at ~65% of entrance duration (EN): the decision is already made,
   so lingering exits read as lag. */
.content.is-exiting .hero-logo  { animation: exitLift 300ms linear forwards !important; }
.content.is-exiting .text-block { animation: exitPull 340ms 20ms linear forwards !important; }
.content.is-exiting .dust-btn   { animation: exitSink 280ms linear forwards !important; }

/* הזכוכית מוותרת על ה-blur החי ברגע היציאה ולובשת את אותו גוון כצבע אטום.
   היא ממילא נמוגה תוך חצי שנייה — ההבדל בלתי־נראה, החיסכון עצום. */
.content.is-exiting .text-block {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  background: rgba(28, 20, 45, .52) !important;
}

@keyframes exitLift {
  0%   { opacity: 1;   transform: translateY(0)    scale(1);
         animation-timing-function: cubic-bezier(.2,.7,.4,1) }
  35%  { opacity: .48; transform: translateY(-4%)  scale(.985);
         animation-timing-function: cubic-bezier(.5,0,.75,.6) }
  100% { opacity: 0;   transform: translateY(-15%) scale(.94) }
}
@keyframes exitPull {
  0%   { opacity: 1;   transform: scale(1);
         animation-timing-function: cubic-bezier(.2,.7,.4,1) }
  35%  { opacity: .5;  transform: scale(1.045);
         animation-timing-function: cubic-bezier(.5,0,.75,.6) }
  100% { opacity: 0;   transform: scale(1.19) }
}
@keyframes exitSink {
  0%   { opacity: 1;   transform: translateY(0)   scale(1);
         animation-timing-function: cubic-bezier(.2,.7,.4,1) }
  35%  { opacity: .46; transform: translateY(6%)  scale(.982);
         animation-timing-function: cubic-bezier(.5,0,.75,.6) }
  100% { opacity: 0;   transform: translateY(24%) scale(.92) }
}
.s01.fading .art { animation: none; }
#xfade video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: translateZ(0);          /* שכבת קומפוזיטור משלו — בלי ריפיינטים */
  backface-visibility: hidden;
  object-position: 50% 68%;   /* אותו עוגן כמו הארט — הרצף נשמר */
}
@media (min-aspect-ratio: 4/5) { #xfade video { object-position: 50% 55%; } }

/* ═══════════ 12c. מסך 2 — המעטפה הסגורה ═══════════
   הארט הוא הגיבור: המעטפה במרכז עם החותם והסטיקר של נסיה (D-32).
   הטקסט חי מעליה, שדה השם והכפתור מתחתיה — הסטאק דוחף אותם לקצוות
   ו*האמצע נשאר ריק בכוונה*, שם רואים את המעטפה. */
.s02 .art-layer .art { object-position: 50% 50%; transform-origin: 50% 50%; }
@media (min-aspect-ratio: 4/5) { .s02 .art-layer .art { object-position: 50% 46%; } }

/* ═══ מסירה ישירה מהוידאו — בלי שום עמעום ═══
   נמדד: הפריים האחרון של הסרטון זהה לתמונה של נסיה עד כדי 1.84 (רעש דחיסה).
   כלומר הארט מעולם לא היה הבעיה — *השכבות מעליו* היו: וינייטה + שטיפה כהה
   עליונה + שטיפה כהה תחתונה, יחד עד 15 יחידות בהירות. הן לא קיימות בסרטון,
   ולכן ברגע המסירה כל המסך התכהה בבת אחת.
   הפתרון אינו לעמעם סביבן אלא למחוק אותן: מסך 2 מרונדר כארט נקי, ולכן הוא
   *אותם פיקסלים* כמו הפריים האחרון. הניגודיות נפתרת בצבע הטקסט עצמו. */
.s02 .vignette { display: none; }
.s02 .content::before,
.s02 .content::after { display: none; }

/* ═══ כוריאוגרפיית הכניסה של מסך 2 ═══
   ⚠️ סדר הקריאה הוא סדר התנועה (HE): כותרת → שאלה → שדה → כפתור. מדרגה
   צפופה (80ms) גורמת לארבעתם להיקרא כ*גל אחד* שנוחת, לא כארבע הופעות
   נפרדות. הכפתור מקבל טיפה יותר אוויר כי הוא הפעולה, ולכן צריך רגע משלו.
   Reading order = motion order (EN); an 80ms stagger reads as one landing
   wave. The CTA gets slightly more air so the action registers on its own. */
.s02 .env-title { animation: riseIn var(--t-enter) 0ms                        var(--ease-enter) both; }
.s02 .env-ask   { animation: riseIn var(--t-enter) var(--stagger)             var(--ease-enter) both; }
.s02 .field-wrap{ animation: riseIn var(--t-enter) calc(var(--stagger) * 2)   var(--ease-enter) both; }
.s02 .dust-btn  { animation: riseIn var(--t-enter) calc(var(--stagger) * 3.6) var(--ease-enter) both; }
/* ⚠️ מרווחים כיחידות מסך ולא דרך --air: --air נושא את מקדם הכיווץ, ולכן
   "לרדת מהשוליים" היה נעלם בדיוק במסכים הצפופים שבהם הוא הכי נחוץ.
   למעלה — אוויר לכותרת. למטה — מרימים את הכפתור מהקצה (padding על הסטאק
   ולא margin על הכפתור, אחרת נוצרת גלישת־רפאים). */
/* המרווח העליון מגיע מ-.content המערכתי; כאן רק הרמת הכפתור מהתחתית */
.s02 .stack { padding-bottom: clamp(60px, 15vh, 140px); }

.env-title {
  font-size: calc(var(--u) * 6.0);
  line-height: 1.3; color: var(--pearl);
  -webkit-text-stroke: .25px currentColor;
  text-shadow: var(--halo-strong);
  opacity: 0; animation: riseIn 1000ms 320ms var(--ease-out) forwards;
}
/* גוש עליון: כותרת → שאלה → שדה השם, הכול מעל המעטפה */
.env-top {
  display: grid; justify-items: center;
  gap: calc(var(--air) * 2.3);
  width: 100%;
}
/* ⚠️ צבע הטקסט נקבע לפי מה שמאחוריו, וזה זז כשהפריסה זזה: כשהשאלה ישבה
   על בסיס האבן הבהיר היא הייתה חייבת דיו כהה (הניגודיות שם 1.79 בטקסט
   בהיר). עכשיו היא מעל המעטפה, על אזור כהה — ולכן חוזרת להיות בהירה. */
.env-ask {
  font-size: calc(var(--fs-body) * 1.04);
  color: #FDF4E8; letter-spacing: .02em;
  text-shadow: var(--halo-soft);
  opacity: 0; animation: riseIn 900ms 760ms var(--ease-out) forwards;
}

/* ── שדה השם — האלמנט האינטראקטיבי הראשון במסע ──
   "זכוכית פיות": פנינה שקופה, מסגרת זהב דקה, זוהר במיקוד. */
.field-wrap {
  position: relative; width: calc(var(--u) * 74); max-width: 82%;
  opacity: 0; animation: riseIn 900ms 1000ms var(--ease-out) forwards;
}
.fairy-field {
  width: 100%;
  /* ⚠️ 16px הוא הרצפה המוחלטת: מתחת לזה iOS מזנק זום בפוקוס ושובר את
     כל הקומפוזיציה. הגודל גדל עם המערכת אבל לעולם לא יורד מתחת לזה. */
  font-size: max(16px, calc(var(--u) * 5.2));
  font-family: inherit;
  text-align: center;
  padding: calc(var(--air) * 2.1) calc(var(--air) * 2.4);
  /* ⚠️ מנוע ההתאמה מכווץ את ה-padding, ובמסך 320 השדה ירד ל-39px — מתחת
     ליעד המגע. לשטח מגע צריכה להיות רצפה בדיוק כמו לקריאוּת. */
  min-height: 48px;
  box-sizing: border-box;
  color: var(--ink-deep);
  background: rgba(253, 248, 250, .82);
  border: 1.4px solid rgba(232, 206, 156, .72);
  border-radius: 999px;
  box-shadow: 0 0 22px rgba(242,175,196,.3), inset 0 1px 0 rgba(255,255,255,.7);
  outline: none;
  transition: box-shadow 240ms ease, border-color 240ms ease, background 240ms ease;
  -webkit-appearance: none; appearance: none;
}
.fairy-field::placeholder { color: rgba(74, 54, 40, .42); }
.fairy-field:focus {
  background: rgba(255, 252, 253, .94);
  border-color: var(--gold-hi);
  box-shadow: 0 0 30px rgba(242,175,196,.55), 0 0 0 4px rgba(232,206,156,.22),
              inset 0 1px 0 rgba(255,255,255,.8);
}
/* עצירה רכה (D-28) — רעד עדין ולחישה, בלי אדום ובלי המילה "שגיאה" */
@keyframes fieldNudge {
  0%,100% { transform: translateX(0) }
  22% { transform: translateX(-5px) } 44% { transform: translateX(5px) }
  68% { transform: translateX(-3px) } 86% { transform: translateX(3px) }
}
.field-wrap.nudge .fairy-field { animation: fieldNudge 460ms ease; }
.field-note {
  display: block; margin-top: calc(var(--air) * 1.1);
  font-size: calc(var(--fs-body) * .86);
  color: var(--gold-hi); text-shadow: var(--halo-soft);
  opacity: 0; transition: opacity 320ms ease;
}
.field-wrap.nudge .field-note { opacity: .95; }

/* ═══════════ 12d. שבירת החותם — המעבר 2→3 בלי וידאו ═══════════
   החותם אפוי בתוך הארט ולכן אי אפשר "לשבור" אותו פיזית. מה שכן אפשר:
   פרץ אור *ממקומו המדויק* שמציף את המסך — נקרא כשחרור, לא כטריק. */
.seal-burst {
  position: absolute; z-index: 6; pointer-events: none;
  left: 50%; top: 62%; width: 34%; aspect-ratio: 1;
  transform: translate(-50%, -50%) scale(.2);
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255,251,247,.98),
              rgba(248,217,230,.62) 46%, rgba(242,175,196,.24) 68%, transparent 78%);
  opacity: 0;
}
@media (min-aspect-ratio: 4/5) { .seal-burst { top: 58%; width: 20%; } }
.s02.opening .seal-burst { animation: sealBurst 1100ms cubic-bezier(.5,0,.7,1) forwards; }
@keyframes sealBurst {
  0%   { opacity: 0;   transform: translate(-50%,-50%) scale(.2) }
  18%  { opacity: 1;   transform: translate(-50%,-50%) scale(.75) }
  100% { opacity: .96; transform: translate(-50%,-50%) scale(7) }
}
.s02.opening .art {
  animation: none; transform: scale(1.16);
  transition: transform 1150ms cubic-bezier(.6,0,.5,1);
}

/* ═══════════ 12d-2. מסך 4 — בחירת הקריסטל ═══════════
   ⚠️ הבחירה היא בין *המשפטים* (החלטת יוסף). הקריסטל בולט אבל קומפקטי,
   כדי שהמשפט יהיה הגיבור. הבועה נותנת לצבע מקום בלי להתחרות בקריאוּת. */
.s04 .stack { padding-bottom: clamp(40px, 9vh, 90px); }   /* מרווח עליון מ-.content */
.choose-head { display: grid; justify-items: center; gap: calc(var(--air) * 1.6); width: 100%;
  animation: riseIn var(--t-enter) 0ms var(--ease-enter) both; }
.choose-intro {
  font-size: max(15.2px, calc(var(--fs-body) * .96)); color: #F3E4EA;
  text-shadow: var(--halo-soft); max-width: 30ch; margin-inline: auto;
}

.choices {
  display: grid; gap: calc(var(--air) * 2.4);
  width: 100%; max-width: calc(var(--u) * 92);
}
/* כרטיס בחירה = בועת זכוכית מזויפת (בלי backdrop-filter חי — יקר) + קריסטל + משפט */
.choice {
  position: relative; display: flex; align-items: center;
  gap: calc(var(--air) * 2.2);
  width: 100%; padding: calc(var(--air) * 1.8) calc(var(--air) * 2.4);
  min-height: 56px;
  border: 1.2px solid rgba(253,251,247,.24);
  border-radius: calc(var(--u) * 7);
  background: rgba(30, 22, 46, .34);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14);
  cursor: pointer; text-align: right;
  transition: transform 240ms var(--ease-out), box-shadow 320ms ease,
              border-color 320ms ease, background 320ms ease, opacity 320ms ease;
  /* המדרגה בין שלוש הבחירות — צפופה, כך שהן נוחתות כגל אחד */
  animation: riseIn var(--t-enter) var(--ease-enter) both;
  animation-delay: calc(var(--stagger) * 1.5 + var(--i) * var(--stagger));
  -webkit-tap-highlight-color: transparent;
}
/* נגיעת הצבע של הקריסטל — רק רמז בשוליים, המשפט נשאר קריא */
.choice .bubble {
  position: relative; flex: 0 0 auto;
  width: calc(var(--u) * 15); height: calc(var(--u) * 15);
  min-width: 46px; min-height: 46px;
  display: grid; place-items: center; border-radius: 50%;
  transition: transform 320ms var(--ease-out), filter 320ms ease;
}
.choice .bubble::before {
  content: ''; position: absolute; inset: -14%;
  border-radius: 50%; opacity: .5;
  transition: opacity 320ms ease, transform 320ms ease;
}
.bubble-gold::before { background: radial-gradient(closest-side, rgba(232,206,156,.6), transparent 72%); }
.bubble-pink::before { background: radial-gradient(closest-side, rgba(228,135,174,.55), transparent 72%); }
.bubble-blue::before { background: radial-gradient(closest-side, rgba(143,184,230,.55), transparent 72%); }
.choice .crystal {
  position: relative; width: 100%; height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 2px 6px rgba(20,14,34,.5));
}
.choice-line {
  flex: 1 1 auto; min-width: 0;
  font-size: calc(var(--fs-body) * 1.02); line-height: 1.5;
  color: var(--pearl); text-shadow: var(--halo-soft);
}

/* מצב נבחר — הבועה מתמלאת ומזהרת בצבע שלה, המשפט מודגש */
.choice.picked {
  transform: scale(1.015);
  border-color: rgba(253,251,247,.5);
  background: rgba(42, 30, 60, .5);
}
.choice.picked .bubble::before { opacity: 1; transform: scale(1.12); }
.choice.picked .bubble { transform: scale(1.06); }
.bubble-gold ~ .choice-line {}
.choice.picked.choice[data-key] .choice-line { color: #fff; }
.choice.picked::after {
  content: ''; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none;
  padding: 1.4px;
  background: linear-gradient(120deg, var(--c-primary), transparent 60%, var(--c-primary));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
/* שאר הבחירות דוהות — כדי שהבחירה תורגש */
.choice.dimmed { opacity: .44; transform: scale(.985); }
.choice.dimmed .bubble { filter: saturate(.6); }

/* הכפתור כבוי עד שבוחרים.
   ⚠️ אנימציה עם forwards מנצחת חוק opacity רגיל, ולכן הכפתור הכבוי נראה
   מלא. הפתרון: האנימציה רק *מרימה* אותו (translateY), והעמעום נשלט בנפרד
   ב-opacity שלא מונפש — כך [disabled] באמת מכהה. */
.s04 .dust-btn {
  opacity: .32; pointer-events: none; filter: grayscale(.35);
  transition: opacity 420ms ease, filter 420ms ease;
  animation: riseNoFade var(--t-enter) calc(var(--stagger) * 5) var(--ease-enter) both;
}
.s04 .dust-btn.ready { opacity: 1; pointer-events: auto; filter: none; }
@keyframes riseNoFade { from { transform: translateY(14px) } to { transform: none } }

/* מסך 5 — המשפט של הקריסטל, מודגש בצבע שנבחר */
.crystal-says { margin-top: calc(var(--air) * 1.4); }
.crystal-says i {
  display: block; font-size: calc(var(--fs-body) * 1.04);
  color: var(--c-air); text-shadow: 0 0 18px var(--c-glow), var(--halo-soft);
}

/* ═══════════ 12e. מסך 3 — המכתב הפתוח ═══════════
   הארט מספק גיליון קרם ריק. הטקסט *לא* מוצמד לפיקסלים שלו (זה נשבר בכל
   יחס מסך) אלא יושב בפאנל בזרם עם שטיפת־קרם מרוככת־קצוות, שמתמזגת עם
   הגיליון המצויר במקום להיראות ככרטיס נפרד מעליו. */
.s03 .art-layer .art { object-position: 50% 42%; transform-origin: 50% 40%; }
@media (min-aspect-ratio: 4/5) { .s03 .art-layer .art { object-position: 50% 40%; } }

.s03 .text-block.letter {
  /* מבטל את "זכוכית הפנינה" הכהה של מסך 1 — כאן זה נייר, לא זכוכית.
     בלי backdrop-filter בכלל (לקח הביצועים ממסך 1). */
  -webkit-backdrop-filter: none; backdrop-filter: none;
  background: none;
  box-shadow: none;
  /* ריפוד מנותק ממנוע הכיווץ (כמו הרוחב) — אחרת השטיפה נצמדת לטקסט */
  padding: clamp(14px, 2.2vh, 26px) clamp(18px, 3.2vw, 36px);
  /* ⚠️ הרוחב *לא* נגזר מ---u. --u נושא את מקדם הכיווץ, ולכן רוחב מבוסס-u
     יוצר לולאת־משוב הפוכה: הטקסט מתכווץ ⇒ הפאנל מצטמצם ⇒ יותר שורות
     גולשות ⇒ המנוע מכווץ עוד. נמדד: הפאנל נתקע על 422px ב-1440 והטקסט
     על רצפת 15.2px. יחידות מסך מנתקות את הלולאה. */
  max-width: min(86vw, 34rem);
  position: relative;
  gap: calc(var(--air) * 2.2);
}
/* לרוחב הגיליון המצויר הוא עמודה צרה במרכז (~20% מהרוחב) — צר מכדי להכיל
   13 שורות בגודל קריא. לכן במסך רחב הנייר הוא גיליון משל עצמו, רחב
   מהמצויר, והשטיפה הרכה גורמת לזה להיקרא ככוונה ולא כתקלה. */
@media (min-aspect-ratio: 4/5) {
  .s03 .text-block.letter { max-width: min(62vw, 46rem); }
}
.s03 .text-block.letter::before {
  /* שטיפת הנייר — קצוות מרוככים במסכה, בלי מסגרת קשיחה. כשהיא חופפת
     לגיליון המצויר זה נקרא גיליון אחד; כשהיא גולשת ממנו זה עדיין מכוון. */
  /* ⚠️ כאן היה inset: -6% -7%. גלישה דקורטיבית מחוץ לתיבה *נספרת* כגלישת
     תוכן אמיתית ב-scrollHeight — 25px רפאים שגרמו למנוע ההתאמה להאמין
     שהטקסט לא נכנס, ולכווץ אותו לרצפת 15.2px בכל גודל מסך. קישוט לעולם
     לא יכתיב טיפוגרפיה: הריכוך נעשה במסכה, בתוך גבולות התיבה. */
  content: ''; position: absolute; inset: 0; z-index: -1;
  border-radius: 18px;
  /* נמדד: הפאנל מתלבש על הגיליון המצויר כמעט בדיוק לרוחב (19%-81% מול
     20%-81%), וגולש כ-8% מתחתיו. לכן שטיפה שקופה יותר ונמוגה חזק בתחתית —
     המרקם המצויר של נסיה נשאר נראה, והגלישה מתמוססת במקום להיחתך. */
  /* המסכה מחזיקה מלא על כל שטח הטקסט ונמוגה רק בקצה — אחרת השורה
     הראשונה והאחרונה נשארות בלי גיבוי מול הרקע הפרחוני הכהה. */
  background: radial-gradient(86% 74% at 50% 46%,
              rgba(255,248,236,.82), rgba(253,242,228,.73) 62%, rgba(252,238,224,.44) 86%, rgba(252,238,224,.16) 97%);
  -webkit-mask-image: radial-gradient(96% 88% at 50% 50%, #000 76%, transparent 99%);
  mask-image: radial-gradient(96% 88% at 50% 50%, #000 76%, transparent 99%);
}
/* דיו כהה על נייר בהיר — היפוך מכל שאר המסע */
.s03 .letter .lines { color: var(--ink-deep); text-shadow: none; -webkit-text-stroke: 0; }
.s03 .letter .greet-line {
  font-size: calc(var(--fs-body) * 1.12);
  color: #3E2C1E; letter-spacing: .01em;
  opacity: 0;
}
.s03 .letter .st { color: #4A3628; }
.s03 .letter .st em {
  font-style: normal; color: #8A5A2B;
  -webkit-text-stroke: .32px currentColor;
}
.s03 .letter .sign {
  margin-top: calc(var(--air) * 1.4);
  font-size: max(15.2px, calc(var(--fs-body) * .96));   /* אותה רצפה */
  color: #6B4A2E; opacity: 0;
}

/* "הפיה מקלידה" — שלוש נקודות אור לפני שהמכתב עולה */
.typing { display: flex; gap: 7px; justify-content: center; padding: calc(var(--air) * 1.6) 0; }
.typing i {
  width: 8px; height: 8px; border-radius: 50%;
  background: #B98A5E; opacity: .35;
  animation: typingPulse 1150ms ease-in-out infinite;
}
.typing i:nth-child(2) { animation-delay: 190ms }
.typing i:nth-child(3) { animation-delay: 380ms }
@keyframes typingPulse {
  0%,100% { opacity: .3;  transform: translateY(0) }
  40%     { opacity: .95; transform: translateY(-4px) }
}
.typing.done { display: none; }

/* גלילה עדינה בתוך הגיליון בלבד (D-31) — הכפתור תמיד נשאר גלוי */
.s03 .stack.overflowing .text-block.letter,
.s03 .text-block.letter.scrolls {
  overflow-y: auto;
  -webkit-mask-image: linear-gradient(#000 90%, transparent);
  mask-image: linear-gradient(#000 90%, transparent);
  scrollbar-width: none;
}
.s03 .text-block.letter::-webkit-scrollbar { display: none; }

/* ⚠️ הכללים הגלובליים של מסך 1 (.lines .st ו-.dust-btn) נושאים השהיות
   קבועות שנועדו לכוריאוגרפיה שלו. במסך 3 העיתוי מונע מה-JS (פסקה-פסקה
   אחרי "הפיה מקלידה"), ולכן חייבים לנטרל אותן — אחרת הטקסט היה מופיע
   לבד בזמנים של מסך 1 ומתנגש עם ההדרגתיות. */
.s03 .letter .lines .st {
  animation: none !important;
  opacity: 0; transform: translateY(10px);
  transition: opacity 720ms ease, transform 720ms var(--ease-out);
}
.s03 .letter .lines .st.shown { opacity: 1; transform: none; }
.s03 .dust-btn {
  animation: none !important;
  opacity: 0; transition: opacity 700ms ease;
}
.s03 .dust-btn.shown { opacity: 1; }
/* (עיתוי הכפתור של מסך 2 נקבע בסעיף 12c, יחד עם שאר הכניסה שאחרי המסירה) */

/* ⚠️ רשת ביטחון אחרי מסירת וידאו — ראה ההערה ב-app.js.
   מוחל 1.2 שניות אחרי ההחלפה, כלומר הרבה אחרי שהכניסה אמורה להסתיים:
   אם היא הסתיימה זו פעולת סרק, ואם לא — התוכן נחשף במקום להישאר ריק. */
/* ⚠️ הקפאת כוריאוגרפיה עד שהמסך נראה (HE):
   מסך שנבנה מתחת לשכבת וידאו מוקפא ב-.awaiting — כל האנימציות שלו עומדות
   בפריים 0 (כולל ההשהיות). ברגע החשיפה המחלקה מוסרת והכוריאוגרפיה רצה
   מההתחלה, מול העיניים. בלי זה היא רצה מתחת לווידאו והתוכן "קפץ" מוכן.
   Freeze choreography until visible (EN): a screen built under the overlay
   holds every animation at frame 0 (delays included) and starts only when
   revealed — otherwise the entrance plays unseen and content pops in. */
.step.awaiting .content *,
.step.awaiting .teaser * { animation-play-state: paused !important; }

.step.settled .env-title,
.step.settled .env-ask,
.step.settled .field-wrap,
.step.settled .dust-btn,
.step.settled .letter .st { opacity: 1 !important; }

/* ═══════════ 12f. מקלדת פתוחה (D-33) ═══════════
   ⚠️ ברירת המחדל הרעה: ה-viewport מתכווץ, מנוע ההתאמה "רואה" פחות מקום
   ומכווץ את כל העיצוב מול העיניים. הדרישה ההפוכה: הפריסה *קופאת* בדיוק
   כפי שהייתה, נדחפת מעלה, וניתן לגלול עליה במלואה.
   --kb-vis = הגובה הנראה מעל המקלדת · --kb-layout = גובה הפריסה המקורי. */
html.kb-open #stage {
  height: var(--kb-vis);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
html.kb-open .step.is-active {
  position: relative;
  height: var(--kb-layout);
  min-height: var(--kb-layout);
}
html.kb-open .step:not(.is-active) { display: none; }
/* שכבות מסך־מלא בתוך המסך הפעיל נשארות בגובה הפריסה המקורי,
   כך שהארט לא נמתח ולא נחתך כשגוללים. */
html.kb-open .step.is-active .art-layer,
html.kb-open .step.is-active .content { height: var(--kb-layout); }
html.kb-open #dust { display: none; }   /* חלקיקים מיותרים בזמן הקלדה */

/* ═══════════ 13. כפתור סאונד ═══════════ */
/* ═══════════ 13. כפתור מוזיקה — שרביט קסם ═══════════
   דלוק: כוכב זהב זוהר + נצנצים מנצנצים סביבו. כבוי: כוכב חלול, בלי נצנצים,
   קו עדין חוצה. SVG בלבד — חד בכל גודל, קליל, בלי עלות ובלי תמונות. */
#snd {
  position: absolute; z-index: 20;
  top: max(12px, env(safe-area-inset-top)); left: max(14px, env(safe-area-inset-left));
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid rgba(253,251,247,.30);
  background: rgba(30,22,48,.42);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  cursor: pointer; padding: 0;
  display: grid; place-items: center;
  transition: transform var(--t-micro) var(--ease-out), border-color 260ms ease, background 260ms ease;
}
#snd .wand { width: 26px; height: 26px; overflow: visible; display: block; }

/* המקל — תמיד נראה, זהב רך */
.wand-stick {
  stroke: var(--gold-hi); stroke-width: 2; stroke-linecap: round;
  transition: stroke 300ms ease;
}
/* כוכב הקצה */
.wand-star {
  fill: var(--gold-hi);
  filter: drop-shadow(0 0 3px rgba(232,206,156,.9)) drop-shadow(0 0 7px rgba(242,175,196,.7));
  transform-origin: 19px 9.8px;
  transition: fill 300ms ease, filter 300ms ease;
}
/* נצנצים — פנינה, מנצנצים */
.wand-sparks > * { fill: var(--pearl); transform-box: fill-box; transform-origin: center; }
.wand-sparks { transition: opacity 300ms ease; }

/* קו הביטול — מוסתר כשדלוק, מופיע כשכבוי */
.wand-slash {
  stroke: var(--pearl); stroke-width: 2; stroke-linecap: round;
  stroke-dasharray: 26; stroke-dashoffset: 26;   /* מוסתר */
  opacity: 0; transition: stroke-dashoffset 320ms var(--ease-out), opacity 200ms ease;
}

/* ── מצב דלוק (ברירת מחדל) — הקסם חי ── */
#snd:not(.off) .wand-star { animation: wandPulse 2.6s ease-in-out infinite; }
#snd:not(.off) .wand-sparks > * { animation: sparkTwinkle 1.8s ease-in-out infinite; }
#snd:not(.off) .wand-sparks > *:nth-child(2) { animation-delay: .5s; }
#snd:not(.off) .wand-sparks > *:nth-child(3) { animation-delay: 1s; }
@keyframes wandPulse {
  0%,100% { filter: drop-shadow(0 0 3px rgba(232,206,156,.9)) drop-shadow(0 0 6px rgba(242,175,196,.6)); }
  50%     { filter: drop-shadow(0 0 5px rgba(232,206,156,1)) drop-shadow(0 0 12px rgba(242,175,196,.85)); }
}
@keyframes sparkTwinkle {
  0%,100% { opacity: .35; transform: scale(.7); }
  50%     { opacity: 1;   transform: scale(1.15); }
}

/* ── מצב כבוי — הקסם נרדם ── */
#snd.off { background: rgba(30,22,48,.30); border-color: rgba(253,251,247,.18); }
#snd.off .wand-stick { stroke: rgba(253,251,247,.4); }
#snd.off .wand-star  { fill: none; stroke: rgba(253,251,247,.5); stroke-width: 1.4; filter: none; }
#snd.off .wand-sparks { opacity: 0; }
#snd.off .wand-slash  { stroke-dashoffset: 0; opacity: .85; }   /* הקו נמתח */

#snd:hover { transform: scale(1.08); border-color: rgba(253,251,247,.5); }
#snd:active { transform: scale(.94); }
#snd:focus-visible { outline: 3px solid var(--gold-hi); outline-offset: 3px; }

/* ═══════════ 13b. טלפון מסובב — הזמנה עדינה לחזור לאורך ═══════════
   הגובה בסיבוב (~340px) קטן מדי לחוויה; טאבלט ומחשב לא מושפעים. */
#rotate {
  position: fixed; inset: 0; z-index: 60;
  display: none; place-content: center; justify-items: center;
  gap: 18px; text-align: center; padding: 24px;
  background:
    radial-gradient(70% 90% at 50% 40%, rgba(40,28,62,.72), rgba(17,11,30,.94) 78%),
    url(../assets/bg/v2/s01-p-720.webp) center / cover no-repeat;
}
#rotate .ico {
  width: 62px; height: 62px;
  animation: turnPhone 3s ease-in-out infinite;
  filter: drop-shadow(0 0 16px rgba(242,175,196,.6));
}
#rotate p {
  font-size: clamp(19px, 4.6vh, 26px); line-height: 1.5; color: var(--pearl);
  text-shadow: var(--halo-strong);
}
#rotate small { font-size: clamp(14px, 3.4vh, 17px); color: var(--pink-air); opacity: .82; }
@keyframes turnPhone {
  0%, 42%   { transform: rotate(-90deg) }
  62%, 100% { transform: rotate(0deg) }
}
@media (orientation: landscape) and (max-height: 520px) {
  #rotate { display: grid; }
  #stage, #dust { visibility: hidden; }      /* עוצר את המסע עד שחוזרים לאורך */
}
@media (prefers-reduced-motion: reduce) { #rotate .ico { animation: none; transform: rotate(-90deg) } }

/* ═══════════ 14. מסך טיזר זמני ═══════════ */
.teaser {
  position: absolute; inset: 0; display: grid; place-content: center;
  gap: 12px; text-align: center; padding: 30px;
}
.teaser h2 {
  font-weight: 400; font-size: clamp(23px, 6vw, 30px); color: var(--pearl);
  text-shadow: var(--halo-strong);
}
.teaser p { font-size: var(--fs-body); color: var(--pink-air); text-shadow: var(--halo-soft); }
/* המסך הבא נבנה 2.1 שניות לפני סוף הסרטון, והטקסט עולה *מתחת* לוידאו —
   כך שכשהזנב נמס (0.9 שניות לפני הסוף) הוא כבר באמצע תנועה איטית, במקום
   להופיע אחרי השהייה. עלייה ארוכה ורכה, עם זוהר שנדלק לאט. */
.teaser h2, .teaser p { opacity: 0; }
.teaser h2 { animation: teaserRise var(--t-enter) 0ms var(--ease-enter) both; }
.teaser p  { animation: teaserRise var(--t-enter) var(--stagger) var(--ease-enter) both; }
/* opacity+transform בלבד — letter-spacing מונפש נראה קסום אבל מפעיל
   חישוב־פריסה מחדש בכל פריים, וזה בדיוק מה שניקינו מהיציאה. */
@keyframes teaserRise {
  0%   { opacity: 0; transform: translateY(22px) scale(.978) }
  55%  { opacity: .72 }
  100% { opacity: 1; transform: none }
}

/* ═══════════ 15. שער טעינת פונט — אפס FOUT/CLS ═══════════ */
html:not(.fonts-ready) .content,
html:not(.fonts-ready) .dust-btn { visibility: hidden; }

/* ═══════════ 16. דילוג על הכניסה ═══════════ */
html.skip-intro .hero-logo, html.skip-intro .greet,
html.skip-intro .lines .st, html.skip-intro .dust-btn {
  animation-duration: .01ms !important; animation-delay: 0ms !important;
}

/* ═══════════ 17. תנועה מופחתת ═══════════ */
@media (prefers-reduced-motion: reduce) {
  .art-layer .art, .gate-glow, .veil, .spark, .dust-btn .pill::after { animation: none !important; }
  .hero-logo, .greet, .lines .st, .dust-btn, .teaser h2, .teaser p {
    animation-duration: 300ms !important; animation-name: fadeOnly !important;
  }
  .content.is-exiting .hero-logo, .content.is-exiting .text-block, .content.is-exiting .dust-btn {
    animation: none !important; opacity: 0; transition: opacity 300ms ease;
  }
  @keyframes fadeOnly { from { opacity: 0 } to { opacity: 1 } }
  .step, .step.is-exit { transition: opacity 340ms ease; transform: none; }
  .s01.opening .art { transform: none; }
  body.warping #stage::after { display: none; }
  .s01.opening .flare { animation: none; opacity: .3; transition: opacity 400ms; }
}

/* מוצא אחרון: אם גם ברצפת הקריאות התוכן לא נכנס (מסך קיצוני) —
   גלילה קצרה בגוש הטקסט בלבד, עם רמז דעיכה. הכפתור נשאר תמיד נראה. */
.stack.overflowing .text-block {
  overflow-y: auto;
  -webkit-mask-image: linear-gradient(#000 88%, transparent);
  mask-image: linear-gradient(#000 88%, transparent);
}

/* ═══════════ 18. מצב QA — מצב סופי, בלי תנועה (לצילומי בקרה) ═══════════ */
html.qa *, html.qa *::before, html.qa *::after {
  animation: none !important; transition: none !important;
}
html.qa .hero-logo, html.qa .greet,
html.qa .lines .st, html.qa .dust-btn { opacity: 1 !important; }
html.qa .st.whisper { opacity: .82 !important; }
/* ⚠️ שער בטיחות: אם אלמנט כלשהו נשאר שקוף במצב בקרה — הצילום משקר.
   הכלל הזה מוודא שכל פריט בסטאק נראה, כדי שלא נבדוק שוב מסך "ריק" בטעות. */
html.qa .stack > * { opacity: 1 !important; }
/* ⚠️ השער לעיל מכסה *ילדים ישירים* בלבד. במסך 2 השאלה ושדה השם יושבים
   בתוך .ask-group, כלומר נכדים — והם נשארו שקופים בצילומי הבקרה. אותו
   כשל בדיוק שהתגלה במסך 1: מצב הבקרה מראה מסך חסר ומדווח "תקין". */
html.qa .env-title, html.qa .env-ask, html.qa .field-wrap,
html.qa .letter .st, html.qa .letter .sign,
html.qa .env-top > * { opacity: 1 !important; }
html.qa .choose-head, html.qa .choose-head > *,
html.qa .choice, html.qa .crystal-says { opacity: 1 !important; animation: none !important; }
html.qa .s04 .dust-btn[disabled] { opacity: .34 !important; }   /* כבוי במצב הבקרה — עד בחירה */
html.qa .field-note { opacity: 0 !important; }   /* מוסתר בכוונה עד עצירה רכה */
html.qa .typing { display: none !important; }    /* מצב סופי = המכתב כתוב */

/* ═══════════════════════════════════════════════════════════════════════════
   מסך 5 — הלב המעוטר (שלב 0ג, מפרט יוסף):
   בכניסה למסך הלב בצבע הקריסטל מופיע גדול במרכז, זוהר ומרחף ~5 שניות
   (טאפ מדלג), ואז מתכווץ ועף למקומו — מרכז-מעלה, ממש מעל בועת הזכוכית —
   ונשאר שם קטן וסטטי. הטקסט נכנס רק אחרי שהלב התיישב (הלב הוא הגיבור).

   Screen 5 — decorated heart choreography (FLIP technique, EN):
   The heart lives at its FINAL slot in the flex column (above .text-block).
   JS measures that slot, applies an inline transform that places it big at
   viewport center (phase 1), then .heart-settle transitions transform back
   to none — it lands EXACTLY where layout says, no coordinate guessing, and
   the fit engine keeps owning the final geometry. transform/opacity only.
   ═══════════════════════════════════════════════════════════════════════════ */
.s05 .heart-wrap {
  /* ⚠️ span הוא inline — בלי display:block ה-width נבלע והלב יושב בגודל
     התמונה הטבעי (נמדד: 354px במקום 171). הבאג נתפס ב-trace לפי scale<1. */
  display: block;
  position: relative;
  width: calc(var(--air) * 46);          /* המיקום הסופי: קטן, מעל הזכוכית */
  max-width: 44%;
  margin: 0 auto calc(var(--air) * -2);
  z-index: 3;
  will-change: transform;
}
.s05 .heart-hero { display: block; width: 100%; height: auto; }
.s05 .heart-glow {
  position: absolute; inset: -34%;
  background: radial-gradient(closest-side, var(--c-glow), transparent 72%);
  opacity: 0; z-index: -1; pointer-events: none;
}
/* פאזה 1 — הגיבור: זוהר פועם וריחוף עדין. ה-transform הגדול מוזרק ב-JS. */
.s05.heart-intro .heart-wrap { animation: heartAppear var(--t-enter) var(--ease-enter) both; }
.s05.heart-intro .heart-glow { opacity: 1; animation: heartPulse 2.2s .3s ease-in-out infinite alternate; }
.s05.heart-intro .heart-hero { animation: heartFloat 3.4s ease-in-out infinite alternate; }
/* בזמן שהלב מככב — הטקסט והכפתור מחכים מאחורי הקלעים.
   הסרת המחלקה מפעילה את אנימציות הכניסה הרגילות שלהם מאפס.
   Trap (EN): removing animation:none restarts their entrance keyframes —
   that restart IS the delayed entrance; do not "optimize" it away. */
.s05.heart-wait .text-block,
.s05.heart-wait .text-block *,
.s05.heart-wait .dust-btn { opacity: 0 !important; animation: none !important; }
/* פאזה 2 — התיישבות: חזרה רכה אל טרנספורם-אפס = המקום הטבעי בפריסה */
.s05.heart-settle .heart-wrap { transition: transform 950ms var(--ease-enter); transform: none !important; }
.s05.heart-settle .heart-glow { transition: opacity 950ms linear; opacity: 0; animation: none; }
@keyframes heartAppear { from { opacity: 0 } to { opacity: 1 } }
@keyframes heartPulse  { from { opacity: .5 } to { opacity: 1 } }
@keyframes heartFloat  { from { transform: translateY(-1.4%) } to { transform: translateY(1.8%) } }
/* מצב בקרה ותנועה מופחתת: בלי הצגה — הלב סטטי במקומו, הטקסט רגיל */
html.qa .s05 .heart-glow { opacity: 0 !important; animation: none !important; }
@media (prefers-reduced-motion: reduce) {
  .s05 .heart-glow, .s05 .heart-hero { animation: none !important; }
}

