/* css/fx.css: the connective tissue. Header, mobile menu, ember cursor, magnetic buttons,
   Devanagari label decode and page atmosphere. Loaded right after styles.css.
   JS lives in js/fx.mjs. Everything decorative here is aria-hidden and pointer-events:none. */

/* ==========================================================================
   Header: transparent over the hero, a solid soot bar once scrolled,
   hides on scroll down (js adds .fx-hide) and returns on scroll up.
   ========================================================================== */
.site-header{
  position:fixed;top:0;left:0;right:0;z-index:50;
  min-height:var(--header-h);padding:0 clamp(16px,4.5vw,64px);
  display:flex;align-items:center;justify-content:flex-start;gap:clamp(12px,2vw,28px);
  color:var(--text);
  background:linear-gradient(180deg,rgb(14 10 8 / .72),rgb(14 10 8 / .3) 62%,rgb(14 10 8 / 0));
  border:0;box-shadow:none;
  transition:translate .65s var(--ease-out),box-shadow .45s ease;
}
/* The soot bar is a layer, so it can fade without repainting the header's contents. */
.site-header::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:var(--background);border-bottom:1px solid var(--line);
  opacity:0;transition:opacity .45s ease;
}
.site-header.is-scrolled{box-shadow:0 18px 40px -28px #000}
.site-header.is-scrolled::before{opacity:1}
.site-header.fx-hide{translate:0 -100%;box-shadow:none}
/* A transform on the header would trap the fixed menu overlay inside it, so none while the menu is open. */
body.menu-open .site-header{translate:none;transition:none}

/* Reading-progress line: a red fuse with an ember tip. It sits just under the bar,
   so it stays visible at the top of the viewport while the header is tucked away. */
.site-header::after{
  content:"";position:absolute;left:0;right:0;bottom:-2px;height:2px;z-index:2;pointer-events:none;
  background:linear-gradient(90deg,var(--oxblood),var(--red) 62%,var(--ember));
  box-shadow:0 0 12px rgb(255 106 31 / .4);
  transform-origin:left center;transform:scaleX(var(--scroll-progress,0));
  transition:opacity .3s ease;
}
body.menu-open .site-header::after{opacity:0}

/* Wordmark */
.wordmark{
  position:relative;z-index:1;order:0;margin-right:auto;
  display:inline-flex;align-items:center;gap:.45em;padding-block:10px;
  font-family:var(--serif);font-size:clamp(1.3rem,1.75vw,1.7rem);line-height:1;letter-spacing:.01em;white-space:nowrap;
}
.wordmark-dot{padding-left:0;font-size:.72em;line-height:1;color:var(--red);transform-origin:50% 50%;transition:color .3s ease,text-shadow .3s ease}
.wordmark:hover .wordmark-dot,.wordmark:focus-visible .wordmark-dot{color:var(--ember);text-shadow:0 0 14px rgb(255 106 31 / .7)}
.wordmark:focus-visible{animation:misprint .55s steps(1) 1}

/* Slot order: wordmark, nav (desktop); wordmark, menu toggle (mobile). */
.site-header nav{order:1}
.site-header>.menu-toggle{order:3}

/* Desktop nav */
.site-header nav{
  display:flex;align-items:center;gap:clamp(14px,2.1vw,34px);
  font-size:.72rem;line-height:1.2;letter-spacing:.14em;text-transform:uppercase;font-weight:400;
}
.site-header nav>a:not(.button){
  position:relative;display:inline-flex;align-items:flex-start;padding-block:12px;
  color:var(--muted);transition:color .3s ease;
}
.site-header nav>a:not(.button):hover,.site-header nav>a[aria-current]{color:var(--text)}
/* Devanagari number words (एक, दो, तीन, चार). On desktop they float in above the link on hover
   and stay above the current section's link; in the mobile menu they sit beside each link. */
.nav-num{
  position:absolute;left:50%;bottom:calc(100% - 9px);
  font-family:'Rozha One',serif;font-size:1.25em;line-height:1;letter-spacing:0;text-transform:none;white-space:nowrap;
  color:var(--ochre);opacity:0;translate:-50% 6px;pointer-events:none;
  transition:color .3s ease,opacity .3s ease,translate .5s var(--ease-spring);
}
@media (min-width:901px){
  .site-header nav>a:hover .nav-num,.site-header nav>a:focus-visible .nav-num,.site-header nav>a[aria-current] .nav-num{opacity:1;translate:-50% 0}
}
.site-header nav>a[aria-current] .nav-num{color:var(--ember)}
.nav-text{position:relative}
/* A dry-brush stroke that draws in from the left and wipes out to the right. */
.nav-text::after{
  content:"";position:absolute;left:-3px;right:-3px;bottom:-7px;height:6px;pointer-events:none;
  background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 10' preserveAspectRatio='none'%3E%3Cpath d='M2 6.4C22 4.2 44 5.6 66 4.6S108 3 130 3.8s46 1.6 68-.6l-.6 3.4c-20 1.6-42 .8-64 .9S94 8.6 72 8.4 26 8.9 2.6 9.2z'/%3E%3C/svg%3E") center/100% 100% no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 10' preserveAspectRatio='none'%3E%3Cpath d='M2 6.4C22 4.2 44 5.6 66 4.6S108 3 130 3.8s46 1.6 68-.6l-.6 3.4c-20 1.6-42 .8-64 .9S94 8.6 72 8.4 26 8.9 2.6 9.2z'/%3E%3C/svg%3E") center/100% 100% no-repeat;
  transform:scaleX(0);transform-origin:right center;transition:transform .55s var(--ease-out);
}
.site-header nav>a:hover .nav-text::after,.site-header nav>a:focus-visible .nav-text::after{transform:scaleX(1);transform-origin:left center}
.site-header nav>a[aria-current] .nav-text::after{transform:scaleX(1);transform-origin:left center;background:var(--ember)}
.nav-meta{display:none}

/* "Book tickets": a yellow paper fill with a torn top edge rises through the red. */
.site-header .nav-ticket{
  position:relative;overflow:hidden;isolation:isolate;gap:.6em;
  min-height:42px;padding:10px 18px;margin-left:clamp(0px,.6vw,10px);
  font-size:.72rem;letter-spacing:.14em;background:var(--red);border:1px solid var(--red);color:var(--text);
  transition:color .35s ease,border-color .35s ease,box-shadow .4s ease,scale .2s ease;
}
.site-header .nav-ticket::before{
  content:"";position:absolute;inset:-9px -1px -1px;z-index:-1;pointer-events:none;background:var(--yellow);
  clip-path:polygon(0 7px,7% 3px,15% 8px,24% 2px,33% 7px,43% 1px,52% 6px,61% 2px,70% 8px,79% 3px,88% 7px,95% 2px,100% 6px,100% 100%,0 100%);
  transform:translateY(101%);transition:transform .55s var(--ease-out);
}
.site-header .nav-ticket:hover,.site-header .nav-ticket:focus-visible{background:var(--red);color:var(--black);border-color:var(--yellow);box-shadow:0 10px 30px -12px rgb(255 106 31 / .7)}
.site-header .nav-ticket:hover::before,.site-header .nav-ticket:focus-visible::before{transform:none}
.nav-ticket-arrow{display:inline-block;font-family:var(--sans);line-height:1;transition:translate .45s var(--ease-spring)}
.site-header .nav-ticket:hover .nav-ticket-arrow{translate:2px -2px}

/* Menu toggle: "Menu +" morphs to "Close ×". Only the visible word is in the accessible name. */
.menu-toggle{
  display:none;position:relative;z-index:1;align-items:center;gap:10px;
  min-height:44px;padding:6px 2px 6px 10px;border:0;background:transparent;color:var(--text);cursor:pointer;
  font-family:var(--sans);font-size:.72rem;line-height:1;letter-spacing:.16em;text-transform:uppercase;
}
.menu-toggle-label{display:grid;overflow:hidden;padding-block:.2em}
.menu-toggle-label>span{grid-area:1/1;text-align:right;transition:translate .5s var(--ease-out),opacity .3s ease,visibility 0s linear 0s}
.menu-toggle-close,
.menu-toggle[aria-expanded="true"] .menu-toggle-open{translate:0 115%;opacity:0;visibility:hidden;transition:translate .5s var(--ease-out),opacity .3s ease,visibility 0s linear .5s}
.menu-toggle[aria-expanded="true"] .menu-toggle-open{translate:0 -115%}
.menu-toggle[aria-expanded="true"] .menu-toggle-close{translate:none;opacity:1;visibility:visible;transition:translate .5s var(--ease-out) .05s,opacity .3s ease .05s,visibility 0s linear 0s}
.menu-toggle-icon{
  position:relative;flex:none;width:32px;height:32px;border-radius:50%;
  border:1px solid rgb(243 230 207 / .35);
  transition:rotate .6s var(--ease-spring),border-color .3s ease,background-color .3s ease;
}
.menu-toggle-icon::before,.menu-toggle-icon::after{
  content:"";position:absolute;left:50%;top:50%;width:12px;height:1.5px;margin:-.75px 0 0 -6px;border-radius:1px;background:currentColor;
}
.menu-toggle-icon::after{rotate:90deg}
.menu-toggle:hover .menu-toggle-icon{border-color:var(--ochre)}
.menu-toggle[aria-expanded="true"] .menu-toggle-icon{rotate:135deg;border-color:var(--ember);background:rgb(255 106 31 / .12)}

/* ==========================================================================
   Mobile menu (<=900px): a full-screen soot overlay that drops like a torn curtain.
   Scoped to html.js (set in <head> before first paint), so the closed state holds from the first
   frame; without JS the nav stays an ordinary wrapped row. Closing transitions only run once js
   has armed the header (.fx-menu-armed), so nothing replays on load or when resizing past 900px.
   ========================================================================== */
@media (max-width:900px){
  .site-header{padding-inline:clamp(16px,5vw,40px);gap:12px}
  .menu-toggle:not([hidden]){display:inline-flex}
  body.menu-open{overflow:hidden}

  html.js .site-header nav{
    position:fixed;inset:0;z-index:0;width:auto;max-height:none;
    display:flex;flex-direction:column;flex-wrap:nowrap;align-items:stretch;justify-content:flex-start;gap:0;
    padding:calc(var(--header-h) + clamp(14px,4.5svh,44px)) clamp(20px,7vw,56px) max(24px,env(safe-area-inset-bottom));
    overflow:hidden auto;overscroll-behavior:contain;
    font-size:1rem;letter-spacing:0;text-transform:none;
    visibility:hidden;
  }
  /* Soot sheet with grain and a torn bottom edge; the edge sits off-screen once it has dropped. */
  html.js .site-header nav::before{
    content:"";position:fixed;inset:0 0 -12svh;z-index:-2;pointer-events:none;
    background:
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='.1'/%3E%3C/svg%3E") 0 0/200px 200px,
      radial-gradient(70% 45% at 92% 4%,rgb(101 28 24 / .55),transparent 70%),
      var(--soot);
    clip-path:polygon(0 0,100% 0,100% 97%,96% 98.5%,91% 97%,85% 99%,78% 97.5%,70% 99.5%,62% 98%,55% 99.3%,47% 97.4%,40% 99.6%,33% 98%,25% 99.4%,18% 97.6%,11% 99.2%,5% 97.8%,0 99%);
    transform:translateY(-101%);
  }
  /* Ember glow banked at the foot of the sheet. */
  html.js .site-header nav::after{
    content:"";position:fixed;left:-25%;right:-25%;bottom:-30svh;height:75svh;z-index:-1;pointer-events:none;
    background:radial-gradient(closest-side,rgb(255 106 31 / .34),rgb(155 42 28 / .2) 52%,transparent);
    opacity:0;
  }
  html.js .site-header nav>*{opacity:0;translate:0 42px}

  /* Closing: items fade first, then the sheet lifts away. */
  .site-header.fx-menu-armed:has(.menu-toggle[aria-expanded="false"]) nav{transition:visibility 0s linear .75s}
  .site-header.fx-menu-armed:has(.menu-toggle[aria-expanded="false"]) nav::before{transition:transform .6s cubic-bezier(.76,0,.24,1) .14s}
  .site-header.fx-menu-armed:has(.menu-toggle[aria-expanded="false"]) nav::after{transition:opacity .3s ease}
  .site-header.fx-menu-armed:has(.menu-toggle[aria-expanded="false"]) nav>*{transition:opacity .2s ease,translate 0s linear .3s}

  /* Opening: the sheet drops, then items stagger in. */
  .site-header:has(.menu-toggle[aria-expanded="true"]) nav{visibility:visible}
  .site-header:has(.menu-toggle[aria-expanded="true"]) nav::before{transform:none;transition:transform .6s cubic-bezier(.76,0,.24,1)}
  .site-header:has(.menu-toggle[aria-expanded="true"]) nav::after{opacity:1;transition:opacity .9s ease .35s;animation:fx-embers 4.5s ease-in-out 1.2s infinite alternate}
  .site-header:has(.menu-toggle[aria-expanded="true"]) nav>*{
    opacity:1;translate:none;
    transition:opacity .5s ease calc(.26s + var(--i,0)*70ms),translate .9s var(--ease-out) calc(.26s + var(--i,0)*70ms);
  }
  .site-header nav>:nth-child(2){--i:1}
  .site-header nav>:nth-child(3){--i:2}
  .site-header nav>:nth-child(4){--i:3}
  .site-header nav>:nth-child(5){--i:4}
  .site-header nav>:nth-child(6){--i:5}

  html.js .site-header nav>a:not(.button){
    display:flex;align-items:flex-start;gap:clamp(12px,3.5vw,22px);padding:.2em 0 .12em;
    border-bottom:1px solid var(--line);
    font-family:var(--serif);font-size:clamp(2.2rem,min(12.5vw,8.6svh),5.2rem);line-height:1.02;letter-spacing:.005em;text-transform:uppercase;
    color:var(--text);
  }
  html.js .site-header nav>a:first-child{border-top:1px solid var(--line)}
  html.js .site-header .nav-num{position:static;flex:none;width:2.6em;padding-top:.45em;font-size:clamp(1rem,3.8vw,1.35rem);line-height:1.3;translate:none;opacity:1}
  html.js .site-header .nav-text::after{bottom:-.02em;height:.14em}
  html.js .site-header nav>a[aria-current] .nav-text{text-shadow:0 0 28px rgb(255 106 31 / .45)}
  html.js .site-header nav>.nav-ticket{margin:clamp(20px,4svh,36px) 0 0;width:100%;min-height:58px;font-size:.8rem}
  html.js .site-header .nav-meta{
    display:flex;flex-direction:column;gap:4px;margin-top:auto;padding-top:clamp(18px,4svh,40px);
    font-size:.66rem;line-height:1.5;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  }
  .nav-meta-hi{font-family:'Rozha One',serif;font-size:clamp(2.8rem,16vw,6.5rem);line-height:1.15;letter-spacing:0;text-transform:none;color:var(--red-muted)}
}
@media (max-width:380px){
  .site-header{gap:8px}
  .wordmark{font-size:1.18rem;gap:.35em}
  .menu-toggle{gap:8px;padding-left:4px}
  .menu-toggle-icon{width:28px;height:28px}
}
@keyframes fx-embers{from{opacity:1;transform:scale(1)}to{opacity:.62;transform:scale(1.08) translateY(2%)}}

/* ==========================================================================
   Buttons: magnetic pull is written by js as the `translate` property,
   so it composes with any transform a section applies.
   ========================================================================== */
.button.fx-magnetic{transition:background-color .3s ease,border-color .3s ease,color .3s ease,box-shadow .4s ease,scale .25s var(--ease-spring)}

/* ==========================================================================
   Ember cursor (fine pointer + motion only; js adds html.fx-cursor-on)
   ========================================================================== */
html.fx-cursor-on,html.fx-cursor-on *{cursor:none!important}
.fx-cursor{
  position:fixed;left:0;top:0;width:0;height:0;z-index:2147483000;pointer-events:none;
  opacity:0;transition:opacity .35s ease;
  --c-dot:var(--ember);--c-ring:rgb(243 230 207 / .5);--c-hot:var(--ember);--c-glow:rgb(255 106 31 / .24);
  --c-chip:var(--paper);--c-ink:var(--black);
  --s:1;--p:1;
}
html.fx-cursor-on .fx-cursor{opacity:1}
.fx-cursor[data-tone="light"]{--c-dot:var(--red);--c-ring:rgb(26 18 13 / .55);--c-hot:var(--red);--c-glow:rgb(155 42 28 / .14);--c-chip:var(--black);--c-ink:var(--paper)}
.fx-cursor[data-tone="red"]{--c-dot:var(--yellow);--c-ring:rgb(243 230 207 / .62);--c-hot:var(--yellow);--c-glow:rgb(242 178 0 / .18);--c-chip:var(--black);--c-ink:var(--paper)}
.fx-cursor[data-state="link"]{--s:1.55}
.fx-cursor[data-state="label"]{--s:1.9}
.fx-cursor[data-state="hidden"]{--s:0}
.fx-cursor.is-down{--p:.78}
.fx-cursor__ring,.fx-cursor__label,.fx-cursor__dot{position:absolute;left:0;top:0;will-change:transform}
.fx-cursor__ring-shape{
  position:absolute;left:-21px;top:-21px;width:42px;height:42px;border-radius:50%;
  border:1px solid var(--c-ring);
  background:radial-gradient(circle,var(--c-glow),transparent 70%);
  scale:calc(var(--s) * var(--p));
  transition:scale .55s var(--ease-spring),border-color .3s ease,background .3s ease;
}
.fx-cursor[data-state="link"] .fx-cursor__ring-shape,.fx-cursor[data-state="label"] .fx-cursor__ring-shape{border-color:var(--c-hot);box-shadow:0 0 18px -4px var(--c-glow),inset 0 0 12px -6px var(--c-hot)}
.fx-cursor.is-down .fx-cursor__ring-shape{transition-duration:.12s,.3s,.3s}
.fx-cursor__dot::before{
  content:"";position:absolute;left:-3.5px;top:-3.5px;width:7px;height:7px;border-radius:50%;
  background:var(--c-dot);box-shadow:0 0 10px 1px var(--c-glow),0 0 3px var(--c-dot);
  transition:scale .35s var(--ease-spring),background-color .3s ease;
}
.fx-cursor[data-state="link"] .fx-cursor__dot::before,.fx-cursor[data-state="label"] .fx-cursor__dot::before{scale:.55}
.fx-cursor[data-state="hidden"] .fx-cursor__dot::before{scale:0}
.fx-cursor.is-down .fx-cursor__dot::before{scale:1.5}
/* Context label: a little ticket stub hanging off the ring, never covering the target's own text. */
.fx-cursor__chip{
  position:absolute;left:0;top:0;translate:34px 30px;rotate:-4deg;transform-origin:0 0;
  padding:6px 11px 5px;white-space:nowrap;
  font:400 .64rem/1.2 var(--sans);letter-spacing:.14em;text-transform:uppercase;
  background:var(--c-chip);color:var(--c-ink);box-shadow:0 10px 22px -10px #000c;
  -webkit-mask:radial-gradient(circle at 0 50%,#0000 3.5px,#000 4px) left/51% 100% no-repeat,radial-gradient(circle at 100% 50%,#0000 3.5px,#000 4px) right/51% 100% no-repeat;
  mask:radial-gradient(circle at 0 50%,#0000 3.5px,#000 4px) left/51% 100% no-repeat,radial-gradient(circle at 100% 50%,#0000 3.5px,#000 4px) right/51% 100% no-repeat;
  opacity:0;scale:.5;transition:opacity .18s ease,scale .45s var(--ease-spring),background-color .3s ease,color .3s ease;
}
.fx-cursor[data-state="label"] .fx-cursor__chip{opacity:1;scale:1}
.fx-cursor__sparks{position:absolute;left:0;top:0}
.fx-spark{
  position:absolute;left:0;top:-1px;width:13px;height:2px;border-radius:2px;transform-origin:0 50%;
  background:linear-gradient(90deg,transparent,var(--c-hot) 45%,#ffe2b8);
  box-shadow:0 0 6px var(--c-hot);
}
.fx-shock{position:absolute;left:-24px;top:-24px;width:48px;height:48px;border-radius:50%;border:1.5px solid var(--c-hot)}

/* ==========================================================================
   Label decode: Devanagari glyphs resolve into the Latin label.
   The final character always holds the width; the glyph floats over it.
   ========================================================================== */
.fx-dw{white-space:nowrap}
.fx-dc{position:relative}
.fx-dc__g{
  position:absolute;left:50%;top:50%;translate:-50% -52%;pointer-events:none;
  font-family:'Rozha One',serif;font-size:1.08em;line-height:1;letter-spacing:0;text-transform:none;font-style:normal;
  color:currentColor;opacity:.72;
}
.fx-dc:not(.is-set):not(.is-static) .fx-dc__f{opacity:0}
.fx-dc.is-set .fx-dc__g{opacity:0}
.fx-dc.is-set .fx-dc__f{animation:fx-dc-flash .7s ease-out both}
@keyframes fx-dc-flash{from{color:var(--ember);text-shadow:0 0 10px rgb(255 106 31 / .8)}to{}}

/* ==========================================================================
   Atmosphere: edge vignette (static) and drifting ash (js canvas).
   ========================================================================== */
.fx-vignette{
  position:fixed;inset:0;z-index:45;pointer-events:none;
  background:radial-gradient(135% 105% at 50% 42%,transparent 58%,rgb(7 4 3 / .26) 84%,rgb(5 3 2 / .5) 100%);
}
.fx-ash{position:fixed;inset:0;width:100%;height:100%;z-index:40;pointer-events:none}

/* ==========================================================================
   Reduced motion: no cursor, no ash, the header never hides.
   (styles.css already stops every animation and transition.)
   ========================================================================== */
:root[data-motion="reduce"] .fx-cursor,:root[data-motion="reduce"] .fx-ash{display:none}
:root[data-motion="reduce"] .site-header.fx-hide{translate:none}
@media (prefers-reduced-motion:reduce){
  .fx-cursor,.fx-ash{display:none}
  .site-header.fx-hide{translate:none}
}
