/* ==========================================================================
   Ceremonial Curtain — opening-ceremony reveal component
   Self-contained. No dependencies. Transform/opacity only (compositor-safe).
   ========================================================================== */

:root {
  --cc-velvet-900: #240206;
  --cc-velvet-800: #46070f;
  --cc-velvet-700: #6b0e18;
  --cc-velvet-600: #8b141f;
  --cc-velvet-500: #a8202b;

  --cc-gold-200: #fbf1c9;
  --cc-gold-300: #f0dda0;
  --cc-gold-400: #dcbe6a;
  --cc-gold-500: #c09a30;
  --cc-gold-700: #7c5f14;

  --cc-hall-1: #14080a;
  --cc-hall-2: #060304;

  /* Cinematic travel: heavy start (fabric inertia), long settle. */
  --cc-ease-travel: cubic-bezier(0.66, 0.01, 0.16, 1);
  --cc-ease-soft:   cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---------- host ---------------------------------------------------------- */

html, body {
  margin: 0;
  padding: 0;
  background: var(--cc-hall-2);
}

ceremonial-curtain {
  display: block;
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--cc-hall-2);
  /* Reserve the box before upgrade so nothing shifts. */
  contain: layout paint;
}

.cc-stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  isolation: isolate;
  /* Timeline knobs — overwritten inline by the component. */
  --cc-d: 3000ms;
  --cc-travel: 39%;
  --cc-gather: 1;
  --cc-skew: 0deg;
  -webkit-tap-highlight-color: transparent;
}

/* ---------- hall backdrop (what sits behind the poster) ------------------- */

.cc-backdrop {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 90% at 50% -10%, #21121a 0%, var(--cc-hall-1) 45%, var(--cc-hall-2) 100%);
  z-index: 0;
}

/* Warm ceremonial wash that lifts as the curtain parts. */
.cc-spotlight {
  position: absolute;
  inset: -10%;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  background:
    radial-gradient(78% 66% at 50% 4%, rgba(255, 226, 168, 0.28) 0%, rgba(255, 205, 128, 0.11) 40%, transparent 78%),
    radial-gradient(58% 34% at 50% 104%, rgba(120, 60, 40, 0.22) 0%, transparent 70%);
  transition: opacity calc(var(--cc-d) * 0.7) var(--cc-ease-soft) calc(var(--cc-d) * 0.2);
}

/* ---------- poster -------------------------------------------------------- */

.cc-poster-frame {
  position: absolute;
  inset: 0;
  z-index: 2;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--cc-gap);
  box-sizing: border-box;
  pointer-events: none;

  /* The poster is framed *inside* the proscenium opening, so the parked
     curtain never crops it. Constant padding — the box is identical in every
     state, so nothing reflows while the curtain moves. */
  --cc-frame-x: clamp(84px, 12vw, 210px);
  --cc-frame-top: calc(clamp(74px, 15vh, 190px) * 0.95);
  --cc-frame-bottom: clamp(16px, 3.5vh, 42px);
  --cc-caption-h: clamp(16px, 2.4vh, 24px);
  --cc-mount: clamp(5px, 0.85vmin, 11px);
  --cc-gap: clamp(10px, 1.6vh, 22px);
  padding: var(--cc-frame-top) var(--cc-frame-x) var(--cc-frame-bottom);
}

/* Velvet mount + double gold hairline: the artwork reads as a mounted plaque
   being unveiled rather than a bare image floating on the stage. */
.cc-poster-shell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Shrink-wraps the artwork, so the caption always sits directly beneath it. */
  flex: 0 1 auto;
  min-height: 0;
  max-width: 100%;
  padding: var(--cc-mount);
  border-radius: 5px;
  background: linear-gradient(160deg, #2c0b12 0%, #150609 55%, #2c0b12 100%);
  box-shadow:
    0 0 0 1px rgba(226, 194, 106, 0.5),
    0 0 0 4px rgba(18, 5, 8, 0.92),
    0 0 0 5px rgba(160, 128, 54, 0.38),
    0 26px 70px rgba(0, 0, 0, 0.72);
  opacity: 0;
  transform: scale(1.035);
  transition:
    opacity  calc(var(--cc-d) * 0.5) var(--cc-ease-soft) calc(var(--cc-d) * 0.22),
    transform calc(var(--cc-d) * 0.8) var(--cc-ease-soft) calc(var(--cc-d) * 0.22);
}

/* Bounded against the stage height rather than a percentage chain, so the
   artwork can never overflow the opening or push the caption off screen.
   Override --cc-stage-h if the component is embedded at a custom height. */
.cc-poster {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  object-fit: contain;
  border-radius: 2px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
  --cc-stage-h: 100vh;
  max-height: calc(var(--cc-stage-h) - var(--cc-frame-top) - var(--cc-frame-bottom)
                   - var(--cc-caption-h) - var(--cc-gap) - (var(--cc-mount) * 2));
}

@supports (height: 100svh) {
  .cc-poster { --cc-stage-h: 100svh; }
}

/* Soft halo that blooms once, exactly as the poster clears the curtain. */
.cc-poster-shell::before {
  content: "";
  position: absolute;
  inset: -6%;
  border-radius: 12px;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(closest-side, rgba(255, 232, 178, 0.42), rgba(255, 214, 140, 0.12) 62%, transparent 80%);
  filter: blur(22px);
}

.cc-caption {
  flex: 0 0 auto;
  font: 500 clamp(11px, 1.55vmin, 15px)/1.5 "Segoe UI", "Noto Sans", system-ui, sans-serif;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cc-gold-300);
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.8);
  text-align: center;
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity   calc(var(--cc-d) * 0.4) var(--cc-ease-soft) calc(var(--cc-d) * 0.78),
    transform calc(var(--cc-d) * 0.4) var(--cc-ease-soft) calc(var(--cc-d) * 0.78);
}

/* No caption → reclaim the space it would have reserved. */
.cc-caption:empty { display: none; }
.cc-poster-frame:has(.cc-caption:empty) { --cc-caption-h: 0px; --cc-gap: 0px; }

/* ---------- light sweep (single, restrained pass) ------------------------- */

.cc-lightsweep {
  position: absolute;
  top: -30%;
  left: -60%;
  width: 55%;
  height: 160%;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  transform: rotate(9deg);
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 240, 205, 0.03) 35%,
    rgba(255, 245, 220, 0.09) 50%,
    rgba(255, 240, 205, 0.03) 65%,
    transparent 100%);
  filter: blur(20px);
  will-change: transform, opacity;
}

/* ---------- curtain ------------------------------------------------------- */

.cc-curtain {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
}

.cc-panel {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 56%;              /* panels overlap by 12% when closed */
  --cc-dir: -1;
  transform: translate3d(calc(var(--cc-travel) * var(--cc-dir)), 0, 0);
  transition: transform var(--cc-d) var(--cc-ease-travel);
  will-change: transform;
}

.cc-panel--left  { left: 0; --cc-dir: -1; }
.cc-panel--right { right: 0; --cc-dir: 1; }

/* The cloth gathers (bunches) towards the outer edge while the panel travels.
   Travel + gather together read as fabric being drawn aside rather than a
   rectangle sliding off screen. The skew lets the hem trail behind the rail. */
.cc-panel__gather {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform: scaleX(var(--cc-gather)) skewX(calc(var(--cc-skew) * var(--cc-dir) * -1));
  transition: transform var(--cc-d) var(--cc-ease-travel);
  will-change: transform;
}

.cc-panel--right .cc-panel__gather { transform-origin: right center; }

.cc-panel__fabric {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Contain the folds' overlay blending to the cloth itself — correctness
     (they must never blend with the poster) and a cheaper composite. */
  isolation: isolate;
  background:
    /* weave */
    repeating-linear-gradient(96deg, rgba(255, 255, 255, 0.016) 0 2px, rgba(0, 0, 0, 0.02) 2px 4px),
    /* vertical light fall: dark under the valance, deep shadow at the hem */
    linear-gradient(180deg,
      var(--cc-velvet-900) 0%,
      var(--cc-velvet-800) 9%,
      var(--cc-velvet-700) 34%,
      var(--cc-velvet-600) 58%,
      var(--cc-velvet-800) 88%,
      var(--cc-velvet-900) 100%);
  box-shadow: inset 0 24px 46px rgba(0, 0, 0, 0.62);
}

/* --- pleats: one element per major fold, laid out by JS via --i / --n --- */

.cc-pleat {
  position: absolute;
  top: -2%;
  bottom: -2%;
  left: calc(var(--i) * (100% / var(--n)));
  width: calc(100% / var(--n));
  mix-blend-mode: overlay;
  opacity: 0.9;
  background: linear-gradient(
    90deg,
    rgba(0, 0, 0, 0.72) 0%,
    rgba(0, 0, 0, 0.30) 14%,
    rgba(255, 255, 255, 0.10) 34%,
    rgba(255, 255, 255, 0.30) 46%,
    rgba(255, 255, 255, 0.07) 60%,
    rgba(0, 0, 0, 0.34) 80%,
    rgba(0, 0, 0, 0.76) 100%);
  transition: opacity calc(var(--cc-d) * 0.55) var(--cc-ease-soft) calc(var(--i) * 26ms);
}

/* Folds narrow towards the hem, the way hung cloth actually falls. */
.cc-pleat::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, transparent 26%, transparent 74%, rgba(0, 0, 0, 0.34) 100%);
}

/* --- inner (leading) edge: gold braid and the shadow it casts ------------
   Both live inside the gather so they track the real cloth edge, and both
   counter-scale so the braid keeps its true thickness while cloth compresses. */

.cc-panel__edge {
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(10px, 1.5vw, 22px);
  z-index: 3;
  transform: scaleX(calc(1 / var(--cc-gather)));
  transition: transform var(--cc-d) var(--cc-ease-travel);
  background:
    linear-gradient(90deg,
      rgba(0, 0, 0, 0.5) 0%,
      var(--cc-gold-700) 22%,
      var(--cc-gold-400) 46%,
      var(--cc-gold-200) 56%,
      var(--cc-gold-500) 72%,
      var(--cc-gold-700) 100%);
  box-shadow:
    0 0 14px rgba(0, 0, 0, 0.6),
    inset 0 0 24px rgba(0, 0, 0, 0.45);
}

.cc-panel--left  .cc-panel__edge { right: 0; transform-origin: right center; }
.cc-panel--right .cc-panel__edge {
  left: 0;
  transform-origin: left center;
  transform: scaleX(calc(-1 / var(--cc-gather)));   /* mirror the specular side */
}

/* Contact shadow the cloth throws onto the stage / poster. */
.cc-panel__cast {
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(40px, 7vw, 130px);
  z-index: 2;
  pointer-events: none;
  opacity: 0.85;
  transform: scaleX(calc(1 / var(--cc-gather)));
  transition:
    transform var(--cc-d) var(--cc-ease-travel),
    opacity calc(var(--cc-d) * 0.7) var(--cc-ease-soft);
}

.cc-panel--left .cc-panel__cast {
  left: 100%;
  transform-origin: left center;
  background: linear-gradient(90deg, rgba(0, 0, 0, 0.62), transparent);
}

.cc-panel--right .cc-panel__cast {
  right: 100%;
  transform-origin: right center;
  background: linear-gradient(270deg, rgba(0, 0, 0, 0.62), transparent);
}

/* ---------- valance / pelmet --------------------------------------------- */

.cc-valance {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: clamp(74px, 15vh, 190px);
  z-index: 6;
  transform: translate3d(0, 0, 0);
  transition: transform calc(var(--cc-d) * 0.85) var(--cc-ease-travel);
  will-change: transform;
}

.cc-valance__fabric {
  position: absolute;
  inset: 0 0 22% 0;
  background:
    repeating-linear-gradient(90deg,
      rgba(0, 0, 0, 0.34) 0 1.6%,
      rgba(255, 255, 255, 0.09) 3.2%,
      rgba(0, 0, 0, 0.34) 5%),
    linear-gradient(180deg, var(--cc-velvet-900), var(--cc-velvet-700) 55%, var(--cc-velvet-800));
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.62);
}

/* Scalloped lower hem of the pelmet. */
.cc-valance__scallops {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 34%;
  background:
    radial-gradient(circle at 50% 0, var(--cc-velvet-700) 68%, transparent 69%) repeat-x,
    linear-gradient(180deg, var(--cc-velvet-700), var(--cc-velvet-800));
  background-size: 9.09% 100%, 100% 100%;
  -webkit-mask-image: radial-gradient(circle at 50% 0, #000 68%, transparent 69%);
  mask-image: radial-gradient(circle at 50% 0, #000 68%, transparent 69%);
  -webkit-mask-size: 9.09% 100%;
  mask-size: 9.09% 100%;
  -webkit-mask-repeat: repeat-x;
  mask-repeat: repeat-x;
  filter: drop-shadow(0 6px 8px rgba(0, 0, 0, 0.5));
}

.cc-valance__trim {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 30%;
  height: clamp(4px, 0.9vh, 9px);
  background: linear-gradient(180deg, var(--cc-gold-200), var(--cc-gold-400) 40%, var(--cc-gold-700));
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.55);
}

/* ---------- tie-back ropes + tassels (appear as the curtain settles) ----- */

.cc-rope {
  position: absolute;
  top: clamp(64px, 13vh, 168px);
  width: clamp(30px, 4.4vw, 62px);
  height: clamp(70px, 13vh, 150px);
  z-index: 7;
  opacity: 0;
  transform: translateY(-14px) scale(0.94);
  transition:
    opacity   calc(var(--cc-d) * 0.42) var(--cc-ease-soft) calc(var(--cc-d) * 0.62),
    transform calc(var(--cc-d) * 0.55) var(--cc-ease-soft) calc(var(--cc-d) * 0.62);
}

.cc-rope--left  { left: 1.5vw; }
.cc-rope--right { right: 1.5vw; }

.cc-rope::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: clamp(3px, 0.42vw, 6px);
  height: 46%;
  transform: translateX(-50%);
  border-radius: 3px;
  background: repeating-linear-gradient(38deg,
    var(--cc-gold-500) 0 3px,
    var(--cc-gold-200) 3px 5px,
    var(--cc-gold-700) 5px 8px);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
}

.cc-rope::after {
  content: "";
  position: absolute;
  top: 42%;
  left: 50%;
  width: clamp(18px, 2.5vw, 34px);
  height: clamp(30px, 5.4vh, 62px);
  transform: translateX(-50%);
  border-radius: 46% 46% 40% 40% / 30% 30% 70% 70%;
  background:
    repeating-linear-gradient(90deg,
      rgba(0, 0, 0, 0.35) 0 2px,
      rgba(255, 255, 255, 0.18) 2px 4px),
    linear-gradient(180deg, var(--cc-gold-200), var(--cc-gold-400) 35%, var(--cc-gold-700));
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.6), inset 0 -6px 12px rgba(0, 0, 0, 0.35);
}

/* ---------- vignette + floor --------------------------------------------- */

.cc-vignette {
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  background:
    radial-gradient(130% 100% at 50% 42%, transparent 52%, rgba(0, 0, 0, 0.42) 84%, rgba(0, 0, 0, 0.72) 100%);
}

/* ---------- skip control -------------------------------------------------- */

.cc-skip {
  position: absolute;
  right: clamp(12px, 2.4vw, 30px);
  bottom: clamp(12px, 2.4vh, 30px);
  z-index: 9;
  padding: 8px 16px;
  border: 1px solid rgba(240, 221, 160, 0.35);
  border-radius: 999px;
  background: rgba(20, 8, 10, 0.55);
  backdrop-filter: blur(4px);
  color: var(--cc-gold-300);
  font: 500 12px/1 "Segoe UI", "Noto Sans", system-ui, sans-serif;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms ease, background-color 200ms ease, border-color 200ms ease;
}

.cc-skip:hover  { background: rgba(40, 14, 18, 0.8); border-color: rgba(240, 221, 160, 0.7); }
.cc-skip:focus-visible { outline: 2px solid var(--cc-gold-300); outline-offset: 3px; }

.cc-stage[data-state="closed"]  .cc-skip,
.cc-stage[data-state="opening"] .cc-skip { opacity: 0.75; pointer-events: auto; }

/* ==========================================================================
   States
   ========================================================================== */

/* loading / closed — curtain fully drawn, poster hidden but already decoded */
.cc-stage[data-state="loading"],
.cc-stage[data-state="closed"] {
  --cc-travel: 0%;
  --cc-gather: 1;
  --cc-skew: 0deg;
}

/* opening + open — panels travel outward while the cloth bunches */
.cc-stage[data-state="opening"],
.cc-stage[data-state="open"] {
  --cc-travel: 39%;
  --cc-gather: 0.55;
  --cc-skew: 1.1deg;
}

.cc-stage[data-state="opening"] .cc-spotlight,
.cc-stage[data-state="open"]    .cc-spotlight { opacity: 1; }

.cc-stage[data-state="opening"] .cc-poster-shell,
.cc-stage[data-state="open"]    .cc-poster-shell {
  opacity: 1;
  transform: scale(1);
}

.cc-stage[data-state="opening"] .cc-poster-shell::before {
  animation: cc-bloom calc(var(--cc-d) * 0.75) var(--cc-ease-soft) calc(var(--cc-d) * 0.25) both;
}

.cc-stage[data-state="opening"] .cc-caption,
.cc-stage[data-state="open"]    .cc-caption {
  opacity: 1;
  transform: translateY(0);
}

.cc-stage[data-state="opening"] .cc-rope,
.cc-stage[data-state="open"]    .cc-rope {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* Pelmet lifts a touch — reads as the whole rig being raised. */
.cc-stage[data-state="opening"] .cc-valance,
.cc-stage[data-state="open"]    .cc-valance {
  transform: translate3d(0, -14%, 0);
}

/* Gathered cloth catches less light and deepens in the folds. */
.cc-stage[data-state="opening"] .cc-pleat,
.cc-stage[data-state="open"]    .cc-pleat { opacity: 1; }

.cc-stage[data-state="opening"] .cc-panel__cast,
.cc-stage[data-state="open"]    .cc-panel__cast { opacity: 0.35; }

.cc-stage[data-state="opening"] .cc-lightsweep {
  animation: cc-sweep calc(var(--cc-d) * 0.72) var(--cc-ease-soft) calc(var(--cc-d) * 0.24) both;
}

/* Settled: stop compositing work and let the page underneath breathe. */
.cc-stage[data-state="open"] .cc-panel,
.cc-stage[data-state="open"] .cc-panel__fabric,
.cc-stage[data-state="open"] .cc-valance,
.cc-stage[data-state="open"] .cc-lightsweep { will-change: auto; }

.cc-stage[data-state="open"] .cc-lightsweep { display: none; }

@keyframes cc-sweep {
  0%   { opacity: 0;   transform: translateX(0)    rotate(9deg); }
  25%  { opacity: 0.6; }
  75%  { opacity: 0.5; }
  100% { opacity: 0;   transform: translateX(320%) rotate(9deg); }
}

@keyframes cc-bloom {
  0%   { opacity: 0; }
  45%  { opacity: 0.85; }
  100% { opacity: 0; }
}

/* ==========================================================================
   No-JS fallback — the poster still has to be presentable without the ceremony
   ========================================================================== */

.cc-noscript {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(10px, 1.6vh, 22px);
  padding: clamp(16px, 4vmin, 48px);
  box-sizing: border-box;
  background: radial-gradient(120% 90% at 50% 0%, #21121a, var(--cc-hall-2));
}

.cc-noscript img {
  max-width: 100%;
  max-height: 82%;
  width: auto;
  height: auto;
  border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(226, 194, 106, 0.5), 0 26px 70px rgba(0, 0, 0, 0.7);
}

.cc-noscript p {
  margin: 0;
  font: 500 clamp(11px, 1.55vmin, 15px)/1.5 "Segoe UI", "Noto Sans", system-ui, sans-serif;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cc-gold-300);
}

/* ==========================================================================
   Accessibility — reduced motion: present the finished frame, no travel
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .cc-stage,
  .cc-stage * {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    animation: none !important;
  }
  .cc-lightsweep { display: none !important; }
}

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

/* travel = gather - (visible sliver / panel width). Panels are 56% wide, so a
   7% sliver at 0.50 gather → 0.50 - 7/56 = 37.5% travel. */
@media (max-width: 900px) {
  .cc-stage[data-state="opening"],
  .cc-stage[data-state="open"] { --cc-travel: 37.5%; --cc-gather: 0.5; }
  .cc-rope { display: none; }
  .cc-poster-frame { --cc-frame-x: clamp(58px, 10vw, 120px); }
}

@media (max-width: 560px) {
  .cc-stage[data-state="opening"],
  /* Thinner parked cloth so a landscape poster gets every pixel of width. */
  .cc-stage[data-state="opening"],
  .cc-stage[data-state="open"] { --cc-travel: 33.5%; --cc-gather: 0.4; }
  .cc-valance { height: clamp(56px, 11vh, 96px); }
  .cc-poster-frame {
    --cc-frame-x: clamp(22px, 6.5vw, 48px);
    --cc-frame-top: calc(clamp(56px, 11vh, 96px) * 0.95);
  }
}

/* Tall portrait: seat the unveiled plaque a little above centre, the way a
   stage piece is actually hung, rather than floating in the exact middle. */
@media (orientation: portrait) and (min-height: 700px) {
  .cc-poster-frame { --cc-frame-bottom: clamp(70px, 16vh, 220px); }
}

/* Short/landscape phones: keep the poster the hero, shrink the rig. */
@media (max-height: 480px) and (orientation: landscape) {
  .cc-valance { height: clamp(40px, 14vh, 70px); }
  .cc-rope { display: none; }
  .cc-poster-frame {
    --cc-frame-top: calc(clamp(40px, 14vh, 70px) * 0.95);
    padding-bottom: clamp(8px, 2vh, 18px);
  }
}
