/* ============================================================
   PATCH REVEAL  v4
   Container: fixed, centred, not edge-to-edge.
   Stage layer: on TOP of tiles (z-index 2), revealed through
                a large rectangle clip-path that follows cursor.
   Tile grid:  z-index 1, 22×5 cells, wave-assembled.
   ============================================================ */

/* ---- sem1 image: compact, centred, sits behind shrinking patch (z-index 485) ---- */
#sem1Bg {
  position: fixed;
  left: 50%;
  top: calc(50% + var(--header-h) / 2);
  transform: translateX(-50%) translateY(-50%);
  width: clamp(450px, 72vw, 1120px);  /* near full width with breathing room */
  z-index: 485;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  background-color: #1e1e1e;
  border-radius: 8px;
  /* overflow intentionally omitted — ::after laser and spotlight box-shadow must bleed outside the box */
  max-height: calc(100vh - var(--header-h) - 60px);
  max-height: calc(100dvh - var(--header-h) - 60px);  /* mobile-stable; ignored where unsupported */
  /* NO css transition — clip-path and opacity driven frame-by-frame by scroll JS */
  will-change: transform, opacity;
}

#sem1Bg img {
  display: block;
  width: 100%;
  height: auto;    /* let the image determine its own height from its natural aspect ratio */
  object-fit: cover;
  object-position: center;
  border-radius: 8px;   /* round corners directly since parent doesn't clip */
}

/* ---- Glow + laser line — activated when sem1 is fully formed ---- */
@property --sem1Sabre {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

@keyframes sem1SabreSpin {
  to { --sem1Sabre: 360deg; }
}

#sem1Bg::after {
  content: "";
  position: absolute;
  inset: -2px;
  padding: 2px;
  border-radius: 10px;
  background: conic-gradient(
    from var(--sem1Sabre),
    transparent                    0%,
    transparent                   60%,
    rgba(100, 200, 255, 0.55)     76%,
    rgba(180, 235, 255, 0.90)     90%,
    transparent                  100%
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask-composite: exclude;
  filter: blur(3px);
  animation: sem1SabreSpin 9s linear infinite;
  opacity: 0;
  transition: opacity 0.9s ease;
  pointer-events: none;
}

#sem1Bg.glow-active {
  box-shadow:
    0 0 32px 6px  rgba(68, 175, 229, 0.28),
    0 0 72px 20px rgba(47, 142, 223, 0.10);
  transition: box-shadow 0.9s ease;
}

#sem1Bg.glow-active::after {
  opacity: 1;
}

/* ---- Reveal container ---- */
#patchReveal {
  position: fixed;
  left:  clamp(28px, 6vw, 100px);
  right: clamp(28px, 6vw, 100px);
  top: calc(50% + var(--header-h) / 2);
  /* Height auto — sized by tile grid aspect-ratio content */
  transform: translateY(-50%);
  z-index: 490;
  pointer-events: none;
  visibility: hidden;
}

#patchReveal.active {
  visibility: visible;
  pointer-events: auto;
}


/* ---- Tile grid: 22 × 5, aspect matches patch_stage.png (3168 × 1187 ≈ 2.67:1) ---- */
.pr-tile-grid {
  display: grid;
  grid-template-columns: repeat(22, 1fr);
  grid-template-rows: repeat(5, 1fr);
  width: 100%;
  aspect-ratio: 3168 / 1187;
  position: relative;
  z-index: 1;
}

/* ---- Seamless overlay: fades in after tile wave completes ---- */
.pr-seamless {
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0;
  transition: opacity 0.5s ease;
  pointer-events: none;
  overflow: hidden;
  border-radius: 3px;
}

.pr-seamless img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill;
}

/* ============================================================
   PATCH FINAL  — patch.png at its native aspect ratio (Phase 4)
   Separate container from patchReveal; sized by JS from image dims.
   ============================================================ */

#patchFinal {
  position: fixed;
  left:  clamp(28px, 6vw, 100px);
  right: clamp(28px, 6vw, 100px);
  top: calc(50% + var(--header-h) / 2);
  transform: translateY(calc(-50% + 10px)) scale(0.50);
  z-index: 490;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* aspect-ratio injected by patch-scene.js from patch.png natural dims */
  will-change: transform, opacity;
}

#patchFinal.active {
  visibility: visible;
  pointer-events: auto;
}

/* Tile grid: fills patchFinal width; aspect-ratio also set by JS */
.pf-tile-grid {
  display: grid;
  grid-template-columns: repeat(22, 1fr);
  grid-template-rows: repeat(5, 1fr);
  width: 100%;
  position: relative;
  z-index: 1;
}

/* Individual patch.png tile */
.pf-tile {
  background-image: url('../assets/images/patch.png');
  background-size: 2200% 500%;
  background-repeat: no-repeat;
  opacity: 0;
  transform: scale(0.28);
  transition:
    opacity   0.44s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.44s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}

/* ============================================================
   POST-USP ICON SCENE
   icon1 flies from start position → screen centre after USP 12.
   icon1Text fades in below it once it settles.
   JS (flip-scene.js) drives opacity, transform, visibility.
   ============================================================ */

#icon1 {
  position: fixed;
  left: 50%;
  top: 50%;
  /* JS applies translate(calc(-50% + Xpx), calc(-50% + Ypx)) scale() */
  width: clamp(90px, 14vw, 160px);
  opacity: 0;
  visibility: hidden;
  z-index: 495;
  pointer-events: none;
  will-change: transform, opacity;
}

#icon1 img {
  display: block;
  width: 100%;
  height: auto;
}

#icon1Text {
  position: fixed;
  left: 50%;
  /* sits below icon1's bottom edge at centre-screen */
  top: calc(50% + clamp(55px, 9vw, 100px) + 26px);
  /* JS applies translateX(-50%) */

  /* Wide enough so the sentence wraps into exactly 2 balanced lines */
  max-width: min(820px, 90vw);
  width: min(820px, 90vw);     /* force consistent width before JS kicks in */

  opacity: 0;
  visibility: hidden;
  z-index: 495;
  color: #fff;
  font-family: 'Open Sans', sans-serif;
  font-weight: 400;            /* Regular */
  font-style: normal;
  font-size: clamp(15px, 1.75vw, 21px);
  line-height: 1.90;           /* clear gap between the 2 lines */
  text-align: center;
  letter-spacing: 0.012em;
  word-break: normal;
  overflow-wrap: normal;
  white-space: normal;
  /* balance line lengths in supporting browsers */
  text-wrap: balance;
  pointer-events: none;
  will-change: transform, opacity;
}

#icon1Text em {
  font-style: normal;
  font-weight: 400;
}

.pf-tile.visible {
  opacity: 1;
  transform: scale(1);
}

/* Clean full-image overlay — fades in after wave to hide tile seams */
.pf-seamless {
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0;
  transition: opacity 0.5s ease;
  pointer-events: none;
  overflow: hidden;
  border-radius: 3px;
}

.pf-seamless img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill; /* container already has correct aspect ratio */
}

/* ---- Individual patch tile ---- */
.pr-tile {
  background-image: url('../assets/images/patch_stage.png');
  /*
    background-size: COLS×100%  ROWS×100%  = 2200% 500%
    Each tile shows exactly its 1/22 × 1/5 slice.
    background-position (set inline per tile) maps the correct strip.
    No borders, no gaps — seamless when all tiles are .visible.
  */
  background-size: 2200% 500%;
  background-repeat: no-repeat;
  opacity: 0;
  transform: scale(0.28);
  transition:
    opacity   0.44s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.44s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}

.pr-tile.visible {
  opacity: 1;
  transform: scale(1);
}

/* ============================================================
   OP1 SCENE  — post-USP image transition
   Tile grid assembles center-out, seamless image crossfades in.
   op1Text reveals word-by-word on continued scroll.
   ============================================================ */

#op1Scene {
  position: fixed;
  left: 50%;
  top: calc(50% + var(--header-h) / 2);
  transform: translateX(-50%) translateY(-50%);

  /* Width constrained so the 1920×1080 image ALWAYS fits vertically —
     min() picks whichever is narrower: 78vw cap OR the width that lets
     the 16:9-ish image sit within the available viewport height.        */
  width: min(
    clamp(480px, 78vw, 1160px),
    calc((100vh - var(--header-h) - 120px) * 1.77778)
  );
  /* No max-height — height flows from the aspect-ratio tile grid inside */

  z-index: 488;
  opacity: 0;
  visibility: hidden;
  /* overflow:hidden on flip faces, not here — prevents 3D flattening  */
  border-radius: 8px;
  pointer-events: none;
  will-change: opacity;
  perspective: 1400px;
}

/* ── Flip wrapper inside op1Scene ───────────────────────────── */
#op1FlipWrap {
  position: relative;
  width: 100%;
  transform-style: preserve-3d;
}

/* Front face (op1) and back face (op2) */
.op1-face {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
  border-radius: 8px;
}

.op1-front {
  position: relative;
  width: 100%;
}

.op1-back {
  position: absolute;
  inset: 0;
  transform: rotateX(180deg);
  background: #08090f;  /* fills letterbox gaps when op2 ≠ 1920:1040 */
}

.op1-back img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;  /* never crop — show full op2 image */
}

/* ── Dark cinematic overlay (post-flip) ─────────────────────── */
#op1Overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.84);
  z-index: 496;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* Sentence that appears over the dark overlay */
#op1SentB {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translateX(-50%) translateY(-50%);
  text-align: center;
  max-width: min(800px, 88vw);
  font-family: 'Open Sans', sans-serif;
  font-weight: 400; /* regular weight — matches #op1Text */
  font-size: clamp(1.0rem, 1.65vw, 1.45rem); /* matches #op1Text */
  line-height: 1.5;
  color: rgba(225, 240, 255, 0.96);
  text-shadow: 0 2px 22px rgba(0, 0, 0, 0.95);
  z-index: 497;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  will-change: opacity;
}

/* ── Op1 glow — identical to sem1Bg sabre spin ─────────────── */
@property --op1Sabre {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

@keyframes op1SabreSpin {
  to { --op1Sabre: 360deg; }
}

#op1Scene::after {
  content: "";
  position: absolute;
  inset: -2px;
  padding: 2px;
  border-radius: 10px;
  background: conic-gradient(
    from var(--op1Sabre),
    transparent                    0%,
    transparent                   60%,
    rgba(100, 200, 255, 0.55)     76%,
    rgba(180, 235, 255, 0.90)     90%,
    transparent                  100%
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask-composite: exclude;
  filter: blur(3px);
  animation: op1SabreSpin 9s linear infinite;
  opacity: 0;
  transition: opacity 0.9s ease;
  pointer-events: none;
}

#op1Scene.glow-active {
  box-shadow:
    0 0 32px 6px  rgba(68, 175, 229, 0.28),
    0 0 72px 20px rgba(47, 142, 223, 0.10);
  transition: box-shadow 0.9s ease;
}

#op1Scene.glow-active::after {
  opacity: 1;
}

/* 16 × 9 tile grid — op1.PNG is 1920 × 1080 (16:9) */
#op1TileGrid {
  display: grid;
  grid-template-columns: repeat(16, 1fr);
  grid-template-rows: repeat(9, 1fr);
  width: 100%;
  aspect-ratio: 16 / 9;
  position: relative;
  z-index: 1;
}

/* Each tile shows its 1/16 × 1/9 slice of op1.PNG.
   background-size: COLS×100%  ROWS×100%  =  1600%  900%
   background-position is set per-tile in JS.                  */
.op1-tile {
  background-image: url('../assets/images/op1.png');
  background-size: 1600% 900%;
  background-repeat: no-repeat;
  opacity: 0;
  will-change: transform, opacity;
}

/* Full-image overlay — crossfades in after tile wave completes */
#op1Seamless {
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0;
  pointer-events: none;
}

#op1Seamless img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;  /* never crop — show full op1 image */
}

/* Sentence reveal — centred on viewport, single line */
#op1Text {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translateX(-50%) translateY(-50%);
  white-space: nowrap;          /* force single line */
  width: auto;
  max-width: 92vw;              /* safety cap on very small screens */
  text-align: center;
  z-index: 494;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  font-family: 'Open Sans', sans-serif;
  font-weight: 400;
  font-size: clamp(1.0rem, 1.65vw, 1.45rem);
  line-height: 1;
  color: rgba(215, 235, 255, 0.96);
  text-shadow: 0 2px 18px rgba(0, 8, 30, 0.96);
  will-change: opacity;
}

/* ============================================================
   OP1 FLOATING GLASS PANELS  — 3 left + 3 right over op1 image
   ============================================================ */

@keyframes op1FloatA {
  0%, 100% { transform: translateY(0px) rotate(0.0deg); }
  30%       { transform: translateY(-10px) rotate(0.35deg); }
  60%       { transform: translateY(-3px) rotate(-0.20deg); }
}
@keyframes op1FloatB {
  0%, 100% { transform: translateY(-5px) rotate(-0.15deg); }
  40%       { transform: translateY(8px) rotate(0.25deg); }
  70%       { transform: translateY(1px) rotate(0.10deg); }
}
@keyframes op1FloatC {
  0%, 100% { transform: translateY(4px) rotate(0.10deg); }
  35%       { transform: translateY(-7px) rotate(-0.30deg); }
  65%       { transform: translateY(-12px) rotate(0.20deg); }
}

/* 3 panels left, 3 right (positioned by layoutGroup in JS). No float —
   each panel simply slides up + fades in when it is revealed, one-by-one
   as you scroll. Once revealed they stay put (no idle motion). */
.op1-panel {
  position: absolute;
  width: clamp(190px, 17vw, 260px);
  pointer-events: none;
  opacity: 0;
  /* Flat — no tilt. Only the slide-up + fade plays on reveal. */
  transform: translateY(24px);
  transition:
    opacity 0.55s ease,
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: opacity, transform;
}

.op1-panel.visible {
  opacity: 1;
  transform: translateY(0);
}

.op1-panel-inner {
  width: 100%;
  padding: 14px 16px 15px;
  text-align: center;          /* content centred within the card */

  /* True glassmorphism */
  background: linear-gradient(
    145deg,
    rgba(255, 255, 255, 0.09) 0%,
    rgba(18, 42, 90, 0.42)   50%,
    rgba(8,  20, 55, 0.55)  100%
  );
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);

  /* Flat, sharp edges — uniform thin border, square corners, no bevel. */
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 0;

  /* Drop shadow only (no inset highlight bevel) */
  box-shadow:
    0 2px  4px  rgba(0, 0, 0, 0.20),
    0 8px  24px rgba(0, 0, 0, 0.45),
    0 20px 48px rgba(0, 0, 0, 0.30);

  will-change: transform;
}

/* Unique float rhythm per panel */
.op1-float-0 { animation: op1FloatA 4.2s ease-in-out infinite; }
.op1-float-1 { animation: op1FloatC 3.8s ease-in-out infinite; animation-delay: -1.6s; }
.op1-float-2 { animation: op1FloatB 4.6s ease-in-out infinite; animation-delay: -0.9s; }
.op1-float-3 { animation: op1FloatB 3.7s ease-in-out infinite; animation-delay: -2.2s; }
.op1-float-4 { animation: op1FloatA 4.5s ease-in-out infinite; animation-delay: -0.5s; }
.op1-float-5 { animation: op1FloatC 3.9s ease-in-out infinite; animation-delay: -1.9s; }

.op1-panel-title {
  font-family: 'Open Sans', sans-serif;
  font-weight: 600;
  font-size: clamp(0.62rem, 0.88vw, 0.76rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.96);
  margin: 0 0 8px;
  line-height: 1.3;
  text-shadow: 0 1px 6px rgba(0, 20, 80, 0.70);
}

.op1-panel-desc {
  font-family: 'Open Sans', sans-serif;
  font-weight: 300;
  font-size: clamp(0.60rem, 0.78vw, 0.70rem);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.88);
  margin: 0;
  text-shadow: 0 1px 4px rgba(0, 10, 40, 0.60);

  /* Justified body, centred last line, and capped at exactly 3 lines so
     every card has a clean, equal block of text. */
  text-align: justify;
  text-align-last: center;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

/* ============================================================
   FINAL CTA — natural page section on grid background
   ============================================================ */

#finalCta {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 32px;
  /* Tall enough that the finale + footer fill the viewport, so it reveals
     from the top with no empty gap and the handoff never has to clamp the
     scroll (which caused the jump). */
  min-height: 82vh;
  padding: 64px clamp(24px, 6vw, 80px) 120px;
  position: relative;
  z-index: 10;
  text-align: center;
  opacity: 0;                       /* fades in when revealed (JS) */
  transition: opacity 0.7s ease;
}

#finalCta.revealed { opacity: 1; }

#finalCta p {
  max-width: min(1150px, 95vw); /* widened so the 2-line CTA sentence fits without an extra wrap, while still filling out for justification */
  width: 100%;
  font-family: 'Open Sans', sans-serif;
  font-weight: 300;
  font-size: clamp(1.2rem, 2.0vw, 1.7rem);
  line-height: 1.9;
  letter-spacing: 0.02em;
  text-align: center;
  color: rgba(225, 240, 255, 0.96);
  margin: 0;
}

/* Disable forced line break on small screens so it wraps naturally */
@media (max-width: 820px) {
  .cta-br { display: none; }
}

#finalCtaBtn {
  display: inline-block;
  padding: 16px 48px;
  font-family: 'Open Sans', sans-serif;
  font-weight: 600;
  font-size: clamp(0.85rem, 1.1vw, 1.0rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  
  /* Hero blue gradient with opacity for glassmorphism */
  background: linear-gradient(
    225deg,
    rgba(68, 175, 229, 0.28) 0%,
    rgba(47, 142, 223, 0.40) 50%,
    rgba(31,  99, 214, 0.45) 100%
  );
  
  /* Backdrop blur for glass look */
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  
  /* Sharp glass border */
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-top: 1px solid rgba(255, 255, 255, 0.35);
  border-left: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 8px;
  text-decoration: none;
  
  /* Glowing drop shadow + inset reflection */
  box-shadow:
    0 4px 24px rgba(47, 142, 223, 0.24),
    0 12px 40px rgba(31, 99, 214, 0.14),
    inset 0 1px 0 rgba(255, 255, 255, 0.25);
    
  transition: 
    box-shadow 0.26s cubic-bezier(0.16, 1, 0.3, 1), 
    transform 0.26s cubic-bezier(0.16, 1, 0.3, 1),
    background-color 0.26s ease,
    border-color 0.26s ease;
  will-change: transform, box-shadow;
}

#finalCtaBtn:hover {
  background: linear-gradient(
    225deg,
    rgba(68, 175, 229, 0.48) 0%,
    rgba(47, 142, 223, 0.60) 50%,
    rgba(31,  99, 214, 0.65) 100%
  );
  border-color: rgba(255, 255, 255, 0.35);
  box-shadow:
    0 8px 32px rgba(47, 142, 223, 0.42),
    0 20px 50px rgba(31, 99, 214, 0.24),
    inset 0 1px 0 rgba(255, 255, 255, 0.40);
  transform: translateY(-2px);
}

/* =========================================================
   LARGE DESKTOPS
   ========================================================= */
@media (min-width: 1921px) {

  #sem1Bg {
    width: clamp(700px, 68vw, 1450px);
  }

  #op1Scene {
    width: min(
      clamp(700px, 70vw, 1500px),
      calc((100vh - var(--header-h) - 120px) * 1.77778)
    );
  }

  .op1-panel {
    width: clamp(220px, 16vw, 300px);
  }

  #icon1 {
    width: clamp(120px, 12vw, 220px);
  }

}