/* ============================================================================
   Hoist the Tiranga
   ----------------------------------------------------------------------------
   Layout is two stacked bands: a fixed-height .stage holding the animated
   scene, and a .console holding the controls. Everything in the scene is sized
   off --pole-h so the whole rig scales as one unit.
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */

:root {
  /* Flag colours, per the Bureau of Indian Standards. */
  --saffron: #ff9933;
  --india-white: #ffffff;
  --india-green: #138808;
  --chakra: #000080;

  /* Sky. These four stops animate from pre-dawn to sunrise on hoist. */
  --sky-1: #05081c;
  --sky-2: #141a3f;
  --sky-3: #2d2450;
  --sky-4: #4a3352;

  --ink: #f3efe6;
  --ink-dim: #b3aec1;
  --ink-faint: #7d788c;
  --line: rgba(255 255 255 / 0.13);
  --panel: rgba(12 14 34 / 0.62);

  --pole-h: 46vh;
  --flag-w: calc(var(--pole-h) * 0.66);
  --uk-h: calc(var(--flag-w) / 2);      /* the Union Flag is 1:2 */
  --in-h: calc(var(--flag-w) / 1.5);    /* the Tiranga is 3:2    */

  --serif: 'Marcellus', 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --deva: 'Tiro Devanagari Hindi', 'Nirmala UI', 'Noto Sans Devanagari', serif;

  /* Ceremony timing. The Flag Code has a flag lowered slowly and hoisted
     briskly — the numbers below are deliberately asymmetric because of it. */
  --t-lower: 3200ms;
  --t-detach: 620ms;
  --t-raise: 1800ms;
  --t-unfurl: 760ms;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

/* The step sections carry `display: grid`, and an author declaration beats the
   user-agent `[hidden] { display: none }` rule regardless of order. Without
   this, every step renders at once. */
[hidden] { display: none !important; }

body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--sky-1);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(15px, 0.55vw + 13.4px, 17px);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skip-link {
  position: fixed; top: 0; left: 50%; z-index: 90;
  transform: translate(-50%, -110%);
  padding: 0.6rem 1rem; border-radius: 0 0 10px 10px;
  background: var(--saffron); color: #16130c; font-weight: 600;
  text-decoration: none;
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

:where(a) { color: var(--ink-dim); text-decoration-color: var(--line); text-underline-offset: 3px; }
:where(a:hover) { color: var(--ink); }

:where(button, a, input):focus-visible {
  outline: 2px solid var(--saffron);
  outline-offset: 3px;
  border-radius: 10px;
}

.nowrap { white-space: nowrap; }

/* =========================================================== the sky/stage */

.stage {
  position: relative;
  flex: 0 0 auto;
  height: min(62svh, 560px);
  min-height: 320px;
  overflow: hidden;
  isolation: isolate;
  contain: paint;
}

.sky {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
    var(--sky-1) 0%, var(--sky-2) 38%, var(--sky-3) 68%, var(--sky-4) 100%);
}

/* Sunrise is a second gradient cross-faded over the night one. Fading an
   overlay is portable in a way that transitioning background-image is not. */
.sky__dawn {
  position: absolute;
  inset: 0;
  opacity: 0;
  background: linear-gradient(to bottom,
    #0d1330 0%, #322656 30%, #7d453f 66%, #e2974b 100%);
  transition: opacity 2800ms ease-out;
}
.stage.is-dawn .sky__dawn { opacity: 1; }

.sky__stars {
  position: absolute;
  inset: 0 0 30% 0;
  transition: opacity 2200ms ease-out;
}
.stage.is-dawn .sky__stars { opacity: 0; }

/* A waning crescent, opposite the side the sun comes up. The crescent is cut by
   a second, offset shadow circle rather than drawn as an arc, which keeps both
   terminators as true circular edges. It sets before the sun rises. */
.sky__moon {
  position: absolute;
  /* Low and well to the left: the pole sits around a quarter of the way across
     on a phone, and at 12%/16% the crescent tangled with the gold finial. */
  top: 25%; left: 9%;
  width: clamp(32px, 4.6vw, 56px); aspect-ratio: 1;
  /* drop-shadow, not box-shadow: the SVG's own box is transparent, so a box
     shadow would trace a square halo around empty space. */
  filter: drop-shadow(0 0 9px rgb(253 246 227 / 0.5))
          drop-shadow(0 0 26px rgb(198 190 232 / 0.28));
  opacity: 0.92;
  transition: opacity 2000ms ease-out, transform 3400ms ease-in;
  pointer-events: none;
}
/* It sets as the sun comes up. */
.stage.is-dawn .sky__moon { opacity: 0; transform: translateY(-16px); }

/* Crepuscular rays fanning out of the sun. A repeating-conic-gradient gives the
   fan in one element; the radial mask fades it out before the edges so it reads
   as light in the air rather than as a drawn pinwheel. */
.rays {
  position: absolute;
  left: 62%; bottom: 17%;
  width: 190vmax; aspect-ratio: 1;
  translate: -50% 50%;
  background: repeating-conic-gradient(from 0deg,
    rgb(255 216 154 / 0.07) 0deg 3.2deg,
    transparent 3.2deg 12deg);
  -webkit-mask: radial-gradient(circle, #000 5%, rgb(0 0 0 / 0.35) 26%, transparent 58%);
  mask: radial-gradient(circle, #000 5%, rgb(0 0 0 / 0.35) 26%, transparent 58%);
  opacity: 0;
  transition: opacity 3200ms ease-out;
  animation: rays-turn 190s linear infinite;
  pointer-events: none;
}
.stage.is-dawn .rays { opacity: 1; }
@keyframes rays-turn { to { rotate: 360deg; } }

/* --------------------------------------------------------------- the birds */

/* They only appear once the sun is up. Each is a stroked gull silhouette whose
   vertical scale oscillates, which reads as a wingbeat. */
.birds {
  position: absolute;
  inset: 0 0 26% 0;
  z-index: 1;
  opacity: 0;
  transition: opacity 2400ms ease-out 900ms;
  pointer-events: none;
}
.stage.is-dawn .birds { opacity: 0.62; }

.bird {
  position: absolute;
  top: var(--y);
  left: 0;
  width: var(--size);
  color: #1a1024;
  animation:
    bird-cross var(--cross) linear var(--delay) infinite,
    bird-flap var(--flap) ease-in-out var(--delay) infinite;
}
@keyframes bird-cross {
  from { transform: translateX(-12vw); }
  to   { transform: translateX(112vw); }
}
@keyframes bird-flap {
  0%, 100% { scale: 1 1; }
  50%      { scale: 1 0.42; }
}
.sky__stars span {
  position: absolute;
  width: var(--s); height: var(--s);
  border-radius: 50%;
  background: #fff;
  opacity: var(--o);
  animation: twinkle var(--d) ease-in-out infinite alternate;
  animation-delay: var(--dl);
}
@keyframes twinkle { from { opacity: calc(var(--o) * 0.25); } to { opacity: var(--o); } }

.sky__sun {
  position: absolute;
  left: 62%; bottom: 4%;
  width: min(58vw, 420px); aspect-ratio: 1;
  translate: -50% 50%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgb(255 226 168 / 0.95) 0%,
    rgb(255 175 90 / 0.55) 34%,
    rgb(255 138 66 / 0.18) 62%,
    transparent 74%);
  opacity: 0;
  transition: opacity 2600ms ease-out, bottom 3600ms cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}
.stage.is-dawn .sky__sun { opacity: 1; bottom: 17%; }

.sky__haze {
  position: absolute;
  inset: auto 0 0 0; height: 46%;
  opacity: 0;
  background: linear-gradient(to top, rgb(255 153 51 / 0.3) 0%, transparent 100%);
  transition: opacity 2600ms ease-out;
  pointer-events: none;
}
.stage.is-dawn .sky__haze { opacity: 1; }

/* ------------------------------------------------------------- the Red Fort */

.ground { position: absolute; inset: auto 0 0 0; height: 22%; }

/* The curtain wall is one seamlessly tiling SVG repeated across the horizon, so
   it costs a single cached request at any screen width. */
.wall {
  position: absolute;
  inset: auto 0 0 0;
  height: 100%;
  background: url('fort-wall.svg') repeat-x bottom center;
  background-size: auto 100%;
}

/* The Lahori Gate, which is where the flag is really hoisted from, so the pole
   stands on its central block.

   Sized by width, not height: the pole sits about a quarter of the way across a
   phone screen, and a gate scaled purely off --pole-h and centred on the pole
   ran off the left edge there. The vw cap holds it on screen, and the offset is
   a smaller share of the flag width than .rig uses so the pole lands inside the
   central block at every size rather than out on a bastion. */
.gate {
  position: absolute;
  bottom: 0;
  left: 50%;
  translate: calc(-50% + var(--flag-w) * -0.3) 0;
  width: min(calc(var(--pole-h) * 0.95), 66vw);
  aspect-ratio: 560 / 390;
  background: url('fort-gate.svg') no-repeat bottom center;
  background-size: 100% 100%;
}

/* Drawn here rather than baked into either SVG: the wall and the gate are shown
   at different heights, so a band inside each would step at the join. */
.ground__plinth {
  position: absolute;
  inset: auto 0 0 0;
  height: 15%;
  background: #120b1b;
}

/* Sunrise reaching the stonework, so the fort warms with the sky instead of
   staying stuck at night behind it. */
.ground__glow {
  position: absolute;
  inset: -40% 0 0 0;
  opacity: 0;
  background: linear-gradient(to top,
    rgb(255 146 54 / 0.34) 0%, rgb(255 120 40 / 0.12) 42%, transparent 100%);
  transition: opacity 2800ms ease-out;
  mix-blend-mode: soft-light;
  pointer-events: none;
}
.stage.is-dawn .ground__glow { opacity: 1; }

/* ============================================================== flagpole */

/* The rig's own children are all absolutely positioned, so it has no intrinsic
   width — a percentage translate here resolves against zero and does nothing.
   Offsetting by a share of the flag width is what actually centres the pole and
   flag together, and it keeps the free edge on screen at every size. */
.rig {
  position: absolute;
  left: 50%;
  bottom: 17%;
  translate: calc(var(--flag-w) * -0.42) 0;
  height: var(--pole-h);
  z-index: 2;
}

/* The mast tapers toward the top, the way a real spar does; a uniform-width bar
   reads as drawn rather than built.

   The taper lives on a pseudo-element, not on .pole itself, because clip-path
   clips descendants too — applied to the parent it sliced the finial, the truck
   and the collar down to the width of the mast at their height. */
.pole { position: absolute; left: 0; top: 0; bottom: 0; width: 9px; }
.pole::before {
  content: '';
  position: absolute;
  inset: 0;
  clip-path: polygon(18% 0, 82% 0, 100% 100%, 0 100%);
  background: linear-gradient(to right,
    #6d7385 0%, #cfd4e0 30%, #f4f6fb 42%, #9aa0b2 64%, #474d60 100%);
  filter: drop-shadow(2px 0 5px rgb(0 0 0 / 0.45));
}

.pole__finial {
  position: absolute;
  left: 50%; top: 0;
  width: 20px; height: 20px;
  translate: -50% -80%;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #fff3c4, #e8b338 46%, #8c6212 100%);
  box-shadow: 0 0 18px rgb(255 197 84 / 0.5);
}

/* The pulley the halyard runs over. */
.pole__truck {
  position: absolute;
  left: 50%; top: 15px;
  width: 14px; height: 3px;
  translate: -50% 0;
  border-radius: 2px;
  background: #2b2f3d;
}

/* A brass collar where the mast enters the stonework. */
.pole__collar {
  position: absolute;
  left: 50%; bottom: 4px;
  width: 15px; height: 7px;
  translate: -50% 0;
  border-radius: 2px;
  background: linear-gradient(to bottom, #e8cd8a, #a8842f 55%, #6d5418);
}

/* ------------------------------------------------------- the pole platform */

/* Three courses of stone, widest at the bottom, in the fort's own tones so the
   pole reads as set into the rampart rather than resting on a dark slab. */
.pole__plinth {
  position: absolute;
  left: 4.5px; bottom: -6px;
  translate: -50% 0;
  display: grid;
  justify-items: center;
}
.pole__step {
  border-radius: 2px 2px 0 0;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.09);
}
.pole__step--top {
  width: clamp(26px, 3.6vw, 38px); height: 7px;
  background: linear-gradient(to bottom, #3a2a4c, #241834);
}
.pole__step--mid {
  width: clamp(38px, 5.4vw, 56px); height: 6px;
  background: linear-gradient(to bottom, #33243f, #1e1429);
}
.pole__step--base {
  width: clamp(52px, 7.4vw, 76px); height: 7px;
  border-radius: 2px;
  background: linear-gradient(to bottom, #2b1e38, #170f20);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.08), 0 6px 18px rgb(0 0 0 / 0.5);
}

/* ------------------------------------------------------------ the carriage */

.carriage {
  position: absolute;
  left: 5px;
  top: 18px;
  width: var(--flag-w);
  transform: translateY(var(--carriage-y, 0px));
  will-change: transform;
}

/* ================================================================== flags */

/* Each flag is a canvas that cloth.js redraws every frame. The canvas is wider
   and taller than the flag itself — folds push the cloth outside its nominal box
   and the free edge breathes in and out — so cloth.js also sets a negative
   margin to pull the flag's own top-left corner back onto the carriage origin. */
.flag {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  pointer-events: none;
  filter: drop-shadow(-3px 12px 20px rgb(0 0 0 / 0.45));
}

/* Which flag is on the pole is driven entirely by the stage phase. */
.flag--in { display: none; }
.stage[data-phase='raise'] .flag--in,
.stage[data-phase='unfurl'] .flag--in,
.stage[data-phase='flying'] .flag--in { display: block; }

/* Unclipped from the halyard and carried off, rather than blinking out. */
.stage[data-phase='detach'] .flag--uk {
  opacity: 0;
  transform: translate(-6px, 26px) rotate(-3deg);
  transition: opacity 420ms ease-in, transform 480ms ease-in;
}
.stage[data-phase='raise'] .flag--uk,
.stage[data-phase='unfurl'] .flag--uk,
.stage[data-phase='flying'] .flag--uk { display: none; }

/* ------------------------------------------------- the furled flag bundle */

.bundle {
  position: absolute;
  left: -2px; top: 0;
  width: 15px;
  height: var(--in-h);
  border-radius: 8px;
  background:
    linear-gradient(to bottom,
      var(--saffron) 0% 33.3%,
      var(--india-white) 33.3% 66.6%,
      var(--india-green) 66.6% 100%),
    #fff;
  box-shadow: inset -4px 0 8px rgb(0 0 0 / 0.32), 0 6px 16px rgb(0 0 0 / 0.45);
  transform-origin: 50% 0%;
  opacity: 0;
  scale: 1 0.4;
  transition: opacity 200ms, scale 320ms cubic-bezier(0.34, 1.4, 0.5, 1);
  pointer-events: none;
}
.bundle__tie {
  position: absolute;
  left: -2px; right: -2px;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(to bottom, #d8c48a, #8d7434);
}
.bundle__tie:nth-child(1) { top: 26%; }
.bundle__tie:nth-child(2) { top: 68%; }

.stage[data-phase='detach'] .bundle,
.stage[data-phase='raise'] .bundle { opacity: 1; scale: 1 1; }
.stage[data-phase='unfurl'] .bundle,
.stage[data-phase='flying'] .bundle {
  opacity: 0;
  scale: 1 1;
  transition: opacity 180ms ease-in;
}

/* The bright crack of cloth catching the wind, over the top of the unfurl. */
.snap {
  position: absolute;
  left: 0; top: 0;
  width: var(--flag-w); height: var(--in-h);
  background: linear-gradient(100deg, transparent 0%, rgb(255 255 255 / 0.85) 48%, transparent 68%);
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
}
.stage[data-phase='unfurl'] .snap { animation: snap 520ms ease-out; }
@keyframes snap {
  0%   { opacity: 0;   transform: translateX(-14%) scaleX(0.4); }
  22%  { opacity: 0.9; }
  100% { opacity: 0;   transform: translateX(6%) scaleX(1); }
}

/* ====================================================== confetti and petals */

/* One canvas over the whole scene; celebrate.js owns everything inside it. */
.confetti {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 4;
  pointer-events: none;
}

/* =============================================== scene chrome (sound/skip) */

.sound, .skip-ceremony {
  position: absolute;
  z-index: 6;
  border: 1px solid var(--line);
  background: rgb(10 12 30 / 0.5);
  backdrop-filter: blur(8px);
  color: var(--ink-dim);
  cursor: pointer;
  transition: color 160ms, border-color 160ms, background 160ms;
}
.sound:hover, .skip-ceremony:hover { color: var(--ink); border-color: rgb(255 255 255 / 0.3); }

/* ------------------------------------------------------- the running tally */

.tally {
  position: absolute;
  z-index: 6;
  top: calc(14px + env(safe-area-inset-top));
  left: calc(14px + env(safe-area-inset-left));
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.34rem 0.8rem 0.34rem 0.62rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgb(10 12 30 / 0.5);
  backdrop-filter: blur(8px);
  font-size: 0.8rem;
  color: var(--ink-dim);
  animation: rise 600ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
.tally b { color: var(--saffron); font-weight: 600; font-variant-numeric: tabular-nums; }
.tally__word { color: var(--ink-faint); }

.tally__dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: #3ddc84;
  box-shadow: 0 0 0 0 rgb(61 220 132 / 0.6);
  animation: tally-pulse 2.4s ease-out infinite;
}
@keyframes tally-pulse {
  0%   { box-shadow: 0 0 0 0 rgb(61 220 132 / 0.55); }
  70%  { box-shadow: 0 0 0 7px rgb(61 220 132 / 0); }
  100% { box-shadow: 0 0 0 0 rgb(61 220 132 / 0); }
}

@media (max-width: 380px) {
  .tally__word { display: none; }
}

.sound {
  top: calc(14px + env(safe-area-inset-top));
  right: calc(14px + env(safe-area-inset-right));
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 50%;
}
.sound .sound__on { display: none; }
.sound[aria-pressed='true'] { color: var(--saffron); border-color: rgb(255 153 51 / 0.4); }
.sound[aria-pressed='true'] .sound__on { display: block; }
.sound[aria-pressed='true'] .sound__off { display: none; }

.skip-ceremony {
  bottom: 14px;
  right: calc(14px + env(safe-area-inset-right));
  padding: 0.42rem 0.85rem;
  border-radius: 999px;
  font: inherit; font-size: 0.8rem; letter-spacing: 0.02em;
}

/* ============================================================== console */

.console {
  flex: 1 1 auto;
  width: 100%;
  max-width: 660px;
  margin-inline: auto;
  padding-block: clamp(1.4rem, 4vw, 2.4rem) 1rem;
  padding-inline:
    calc(1.25rem + env(safe-area-inset-left))
    calc(1.25rem + env(safe-area-inset-right));
  display: grid;
  align-content: start;
  gap: 1rem;
}

.card { display: grid; gap: 0.85rem; animation: rise 520ms cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.eyebrow {
  margin: 0;
  font-size: 0.74rem;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  color: var(--saffron);
  font-weight: 600;
}

.display {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.15rem, 8.4vw, 3.4rem);
  line-height: 1.02;
  letter-spacing: -0.012em;
  background: linear-gradient(102deg, #fff8ec 8%, #ffd9a8 52%, #ffe9cf 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.lede { margin: 0; color: var(--ink-dim); max-width: 46ch; }

/* ------------------------------------------------------- the three-step rail */

/* Visible from the first paint, before anything has been pressed, so the whole
   flow — hoist, sign, share — is known in advance rather than discovered one
   surprise at a time. */
.rail {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.7rem;
  font-size: 0.77rem;
  letter-spacing: 0.05em;
}
.rail__step {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--ink-faint);
  transition: color 240ms;
}
.rail__step b {
  display: grid;
  place-items: center;
  width: 20px; height: 20px;
  border: 1px solid var(--line);
  border-radius: 50%;
  font-size: 0.68rem;
  font-weight: 600;
  transition: background 240ms, color 240ms, border-color 240ms;
}
/* The connector belongs to the step before the gap, so it never trails off the
   end of the row. */
.rail__step:not(:last-child)::after {
  content: '';
  width: clamp(0.7rem, 4vw, 1.6rem);
  height: 1px;
  margin-left: 0.25rem;
  background: var(--line);
}
.rail__step[data-state='now'] { color: var(--ink); }
.rail__step[data-state='now'] b {
  background: var(--saffron);
  border-color: transparent;
  color: #1c1305;
  box-shadow: 0 0 0 4px rgb(255 153 51 / 0.15);
}
.rail__step[data-state='done'] { color: var(--ink-dim); }
.rail__step[data-state='done'] b {
  background: rgb(19 136 8 / 0.85);
  border-color: transparent;
  color: #fff;
}

/* ============================================================ the walkthrough */

/* A coach mark: a ring on the thing to press and a bubble hanging off it. Both
   are position: fixed and driven from coach.js, which measures the target.

   pointer-events stays none on everything except the dismiss button, so the
   walkthrough can never intercept the press it is asking for. */
.coach {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
}
/* Set while the target is scrolled out of view: keep the layout, drop the paint,
   rather than pointing a tail at something off screen. */
.coach[data-off] { opacity: 0; }

.coach__ring {
  position: fixed;
  border: 2px solid var(--saffron);
  box-shadow: 0 0 0 0 rgb(255 153 51 / 0.55);
  animation: coach-pulse 1.9s cubic-bezier(0.24, 0.6, 0.3, 1) infinite;
}
@keyframes coach-pulse {
  0%        { box-shadow: 0 0 0 0 rgb(255 153 51 / 0.5); }
  70%, 100% { box-shadow: 0 0 0 11px rgb(255 153 51 / 0); }
}

/* Cream on a near-black page: the bubble has to read as a layer above the app,
   and a dark bubble on a dark scene does not. */
.coach__bubble {
  position: fixed;
  max-width: min(19rem, calc(100vw - 2.2rem));
  padding: 0.7rem 2rem 0.75rem 0.85rem;
  border-radius: 15px;
  background: linear-gradient(180deg, #fff8ec, #ffe4bd);
  color: #2b1d08;
  box-shadow: 0 16px 38px rgb(0 0 0 / 0.5), 0 2px 0 rgb(255 255 255 / 0.5) inset;
}

/* Positioning is left/top from JS so transform stays free for the animations —
   an animation on transform would otherwise overwrite the placement. */
.coach__bubble.is-in {
  animation:
    coach-in 340ms cubic-bezier(0.34, 1.56, 0.5, 1) both,
    coach-bob 2.6s ease-in-out 420ms infinite;
}
@keyframes coach-in {
  from { opacity: 0; transform: scale(0.9) translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes coach-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* A rotated square, so the two visible edges pick up the bubble's own corner
   radius. Its colour is the gradient stop nearest that edge — `inherit` cannot
   carry a gradient across to a smaller box. */
.coach__tail {
  position: absolute;
  width: 14px;
  height: 14px;
  transform: translateX(-50%) rotate(45deg);
  border-radius: 3px;
}
.coach__bubble[data-place='below'] .coach__tail { top: -5px; background: #fff8ec; }
.coach__bubble[data-place='above'] .coach__tail { bottom: -5px; background: #ffe4bd; }
/* Beside the target: the tail leaves the left edge halfway down, so it takes the
   gradient's middle rather than either end. */
.coach__bubble[data-place='right'] .coach__tail {
  transform: translateY(-50%) rotate(45deg);
  background: #fff0d7;
}

.coach__chip {
  display: inline-block;
  margin-bottom: 0.3rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  background: rgb(43 29 8 / 0.1);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #7a5410;
}

.coach__text { margin: 0; font-size: 0.95rem; font-weight: 600; line-height: 1.35; }
.coach__sub { margin: 0.2rem 0 0; font-size: 0.82rem; line-height: 1.4; color: rgb(43 29 8 / 0.66); }

.coach__close {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: rgb(43 29 8 / 0.42);
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
}
.coach__close:hover { background: rgb(43 29 8 / 0.08); color: #2b1d08; }
.coach__close:focus-visible { outline: 2px solid #2b1d08; outline-offset: 1px; }

.invite {
  margin: 0;
  padding: 0.7rem 0.95rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--saffron);
  border-radius: 4px 12px 12px 4px;
  background: var(--panel);
  font-size: 0.92rem;
  color: var(--ink-dim);
}
.invite b { color: var(--ink); font-weight: 600; }

.quote {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.08rem, 3.6vw, 1.3rem);
  line-height: 1.5;
  color: #f6ecdc;
  border-left: 2px solid rgb(255 153 51 / 0.55);
  padding-left: 1rem;
}
.quote cite {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--sans);
  font-style: normal;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ---------------------------------------------------------------- buttons */

.btn {
  --btn-bg: linear-gradient(180deg, #ffb057, #f4832a);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.78rem 1.35rem;
  border: 0;
  border-radius: 12px;
  background: var(--btn-bg);
  color: #1c1305;
  font: inherit;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  transition: transform 140ms cubic-bezier(0.34, 1.5, 0.5, 1), filter 160ms, box-shadow 160ms;
  box-shadow: 0 6px 20px rgb(244 131 42 / 0.26);
}
.btn:hover { transform: translateY(-2px); filter: brightness(1.06); }
.btn:active { transform: translateY(0) scale(0.985); }

.btn--hero {
  position: relative;
  overflow: hidden;
  justify-self: start;
  padding: 0.95rem 1.9rem;
  font-size: 1.06rem;
}
.btn__shine {
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 34%, rgb(255 255 255 / 0.55) 50%, transparent 66%);
  translate: -120% 0;
  animation: sweep 3.6s ease-in-out 1.2s infinite;
}
@keyframes sweep { 0% { translate: -120% 0; } 42%, 100% { translate: 120% 0; } }

.btn--ghost {
  --btn-bg: rgb(255 255 255 / 0.06);
  color: var(--ink);
  border: 1px solid var(--line);
  box-shadow: none;
}
.btn--ghost:hover { --btn-bg: rgb(255 255 255 / 0.11); }

.btn--tweet { --btn-bg: linear-gradient(180deg, #23262b, #0d0f12); color: #fff; box-shadow: none; border: 1px solid rgb(255 255 255 / 0.16); }

/* First in the row and in its own colour, because on a phone in India this is
   the button that actually gets used. */
.btn--whatsapp { --btn-bg: linear-gradient(180deg, #3ad673, #1aa54f); color: #04220f; box-shadow: 0 6px 20px rgb(26 165 79 / 0.24); }

.counter { margin: 0; font-size: 0.86rem; color: var(--ink-faint); }
.counter b { color: var(--saffron); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------- name input */

.namer { display: grid; gap: 0.5rem; }
.namer__label { font-size: 0.78rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); }
.namer__row { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.namer__hint { margin: 0; font-size: 0.8rem; color: var(--ink-faint); }
.namer__hint[data-error] { color: #ff9d8a; }

.input {
  flex: 1 1 12rem;
  min-width: 0;
  padding: 0.78rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgb(255 255 255 / 0.05);
  color: var(--ink);
  font: inherit;
  transition: border-color 160ms, background 160ms;
}
.input::placeholder { color: var(--ink-faint); }
.input:focus { border-color: rgb(255 153 51 / 0.55); background: rgb(255 255 255 / 0.08); }

/* ------------------------------------------------------------ certificate */

.certificate {
  position: relative;
  overflow: hidden;
  padding: 1.5rem 1.4rem 1.35rem;
  border: 1px solid var(--line);
  border-radius: 16px;
  background:
    radial-gradient(120% 90% at 50% -20%, rgb(255 153 51 / 0.14), transparent 60%),
    var(--panel);
  text-align: center;
}
.certificate__band { position: absolute; inset: 0 0 auto 0; height: 4px;
  background: linear-gradient(to right, var(--saffron) 0 33.3%, #fff 33.3% 66.6%, var(--india-green) 66.6% 100%); }
.certificate__kicker { margin: 0; font-size: 0.72rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-faint); }
.certificate__name {
  margin: 0.35rem 0 0;
  font-family: var(--serif);
  font-size: clamp(1.7rem, 7vw, 2.5rem);
  line-height: 1.12;
  overflow-wrap: anywhere;
}
.certificate__meta { margin: 0.55rem 0 0; font-size: 0.88rem; color: var(--ink-dim); }
.certificate__seal { margin: 0.9rem 0 0; font-size: 0.74rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--saffron); }

.actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.actions .btn { padding: 0.7rem 1.1rem; font-size: 0.94rem; }


.restart {
  justify-self: start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 0.85rem;
  text-decoration: underline;
  text-underline-offset: 4px;
  cursor: pointer;
}
.restart:hover { color: var(--ink-dim); }

/* ---------------------------------------------------------- the full anthem */

.anthem { display: grid; gap: 0.5rem; justify-items: start; }

.anthem__play {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 1.05rem;
  border: 1px solid rgb(255 153 51 / 0.4);
  border-radius: 999px;
  background: rgb(255 153 51 / 0.08);
  color: var(--ink);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
  transition: background 160ms, border-color 160ms;
}
.anthem__play:hover { background: rgb(255 153 51 / 0.15); border-color: rgb(255 153 51 / 0.6); }
.anthem__icon { color: var(--saffron); flex: 0 0 auto; }
.anthem__icon--pause { display: none; }
.anthem__play[aria-pressed='true'] .anthem__icon--play { display: none; }
.anthem__play[aria-pressed='true'] .anthem__icon--pause { display: block; }

.anthem__track {
  width: min(100%, 17rem);
  height: 3px;
  border-radius: 2px;
  background: rgb(255 255 255 / 0.1);
  overflow: hidden;
  opacity: 0;
  transition: opacity 240ms;
}
.anthem__play[aria-pressed='true'] ~ .anthem__track { opacity: 1; }
.anthem__fill {
  height: 100%;
  width: 0%;
  border-radius: 2px;
  background: linear-gradient(to right, var(--saffron), #fff 60%, var(--india-green));
}

/* Standing for the anthem is the expected courtesy in India, so the app asks
   rather than just playing it at someone. */
.anthem__note {
  margin: 0;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--saffron);
}

/* Only ever shown when the browser actually fires beforeinstallprompt, so it
   never appears as a dead button on a platform that cannot install. */
.install {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.4rem;
  padding: 0.55rem 0.95rem;
  border: 1px dashed var(--line);
  border-radius: 999px;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: 0.83rem;
  cursor: pointer;
  transition: color 160ms, border-color 160ms;
}
.install:hover { color: var(--ink-dim); border-color: rgb(255 255 255 / 0.28); }

/* ================================================================= footer */

.foot {
  padding: 1.4rem
    calc(1.25rem + env(safe-area-inset-right))
    calc(1.9rem + env(safe-area-inset-bottom))
    calc(1.25rem + env(safe-area-inset-left));
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0.55rem;
  font-size: 0.79rem;
  color: var(--ink-faint);
  text-align: center;
}
.jaihind { font-family: var(--deva); font-size: 1.02rem; color: var(--saffron); }

/* ============================================================ responsive */

@media (min-width: 760px) {
  :root { --pole-h: 44vh; }
}

@media (max-width: 420px) {
  :root { --pole-h: 42vh; }
  .actions .btn { flex: 1 1 auto; }
}

/* The hoist button, and the arrow pointing at it, have to be on screen when the
   page opens — a call to action below the fold is a call to action nobody makes.
   On a phone the scene gives up the height for it. */
@media (max-width: 560px) {
  :root { --pole-h: 39svh; }
  .stage { height: min(55svh, 470px); }
  .console { padding-block: 1.1rem 0.9rem; gap: 0.85rem; }
  .card { gap: 0.7rem; }
}

/* Shorter phones — an SE, or any handset with a browser bar eating the bottom.
   Portrait only: landscape has its own rule below and a different problem. */
@media (max-height: 700px) and (orientation: portrait) {
  :root { --pole-h: 34svh; }
  .stage { height: min(47svh, 400px); }
  .lede { font-size: 0.94rem; }
}

/* Smaller again — a 360×640 Android. The headline gives up a little size too. */
@media (max-height: 660px) and (orientation: portrait) {
  :root { --pole-h: 31svh; }
  .stage { height: min(43svh, 360px); min-height: 260px; }
  .display { font-size: clamp(1.85rem, 7.4vw, 2.5rem); }
}

/* Laptops in a short window — a 1280×720 screen with browser chrome on top. Wide
   enough to be a real desktop, tall enough not to be a phone on its side, and
   the button was landing 60px under the fold. */
@media (min-width: 900px) and (max-height: 800px) and (min-height: 560px) {
  :root { --pole-h: 38svh; }
  .stage { height: min(50svh, 420px); }
  .console { padding-block: 1.2rem 1rem; }
}

/* Short landscape phones: shrink the stage so the controls stay reachable. */
@media (max-height: 620px) and (orientation: landscape) {
  .stage { height: 74svh; }
  :root { --pole-h: 54svh; }
}

/* ====================================================== reduced motion ── */

@media (prefers-reduced-motion: reduce) {
  /* cloth.js switches to its 'still' preset and stops its own clock; the
     confetti burst is skipped entirely in app.js. */
  .btn__shine, .sky__stars span { animation: none; }
  .rays { animation: none; }
  .bird { animation: none; opacity: 0; }
  /* The carriage keeps its glide: timings() already collapses the ceremony to
     about a second, and a short travel reads better than a jump cut. */
  .stage[data-phase='unfurl'] .snap { animation: none; }
  .card { animation: none; }
  .btn:hover { transform: none; }

  /* The walkthrough keeps its ring and its bubble — they are what makes it a
     walkthrough — and loses the pulse and the bob. */
  .coach__ring { animation: none; box-shadow: 0 0 0 4px rgb(255 153 51 / 0.18); }
  .coach__bubble.is-in { animation: none; }
}
