/* ============================================================================
   Hoist the Parcham
   ----------------------------------------------------------------------------
   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. Pakistan green is very dark — the flag is meant to be read in
     daylight — and against this night sky it disappears, so the interface takes
     its accent from --pak-lit, the same green lifted toward the light. The true
     colour is still what the flag itself is drawn in. */
  --pak-green: #01411c;
  --pak-white: #ffffff;
  --pak-lit: #3fae74;
  /* The accent as bare channels, for the rgb(… / α) uses further down. */
  --pak-lit-rgb: 63 174 116;

  /* 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 */
  --pk-h: calc(var(--flag-w) / 1.5);    /* the Parcham is 3:2    */

  --serif: 'Marcellus', 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --urdu: 'Noto Nastaliq Urdu', 'Jameel Noori Nastaleeq', 'Noto Naskh Arabic', serif;

  /* Ceremony timing. Flag protocol 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(--pak-lit); color: #06210f; 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(--pak-lit);
  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;
  /* Warm, not the flag's green: this is the sun in the dust on the horizon. */
  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 Lahore 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 Alamgiri 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--pk { display: none; }
.stage[data-phase='raise'] .flag--pk,
.stage[data-phase='unfurl'] .flag--pk,
.stage[data-phase='flying'] .flag--pk { 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(--pk-h);
  border-radius: 8px;
  /* Across the roll, not down it: the flag is furled toward the mast, so what
     shows on a bundle this narrow is the hoist band and then the field — the
     same left-to-right division the flag itself has. Banding it top-to-bottom
     would be a tricolour's bundle, which this flag is not. */
  background:
    linear-gradient(to right,
      var(--pak-white) 0% 28%,
      var(--pak-green) 28% 100%),
    var(--pak-green);
  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(--pk-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); }

.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(--pak-lit); border-color: rgb(var(--pak-lit-rgb) / 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(--pak-lit);
  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(--pak-lit);
  border-color: transparent;
  color: #06210f;
  box-shadow: 0 0 0 4px rgb(var(--pak-lit-rgb) / 0.15);
}
.rail__step[data-state='done'] { color: var(--ink-dim); }
/* Between the flag's green and the lifted accent: dark enough to read as done
   rather than current, light enough not to vanish into the panel behind it. */
.rail__step[data-state='done'] b {
  background: #1d6b45;
  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(--pak-lit);
  box-shadow: 0 0 0 0 rgb(var(--pak-lit-rgb) / 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(var(--pak-lit-rgb) / 0.5); }
  70%, 100% { box-shadow: 0 0 0 11px rgb(var(--pak-lit-rgb) / 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; }

.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(var(--pak-lit-rgb) / 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 {
  /* Down toward the flag's true green rather than away from it, so the primary
     button is recognisably the same green as the thing being hoisted. Dark
     enough at the bottom that the label has to be light. */
  --btn-bg: linear-gradient(180deg, #34a86c, #0c6337);
  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: #f2fbf5;
  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(12 99 55 / 0.34);
}
.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 Pakistan 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); }

/* ------------------------------------------------------------ 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(var(--pak-lit-rgb) / 0.14), transparent 60%),
    var(--panel);
  text-align: center;
}
/* The flag's own proportions — a white quarter, then the field. In --pak-lit
   rather than the true green, which at 4px on this panel would read as a gap. */
.certificate__band { position: absolute; inset: 0 0 auto 0; height: 4px;
  background: linear-gradient(to right, var(--pak-white) 0 25%, var(--pak-lit) 25% 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(--pak-lit); }

.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(var(--pak-lit-rgb) / 0.4);
  border-radius: 999px;
  background: rgb(var(--pak-lit-rgb) / 0.08);
  color: var(--ink);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
  transition: background 160ms, border-color 160ms;
}
.anthem__play:hover { background: rgb(var(--pak-lit-rgb) / 0.15); border-color: rgb(var(--pak-lit-rgb) / 0.6); }
.anthem__icon { color: var(--pak-lit); 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(--pak-white), var(--pak-lit) 55%, #7fd3a5);
}

/* Standing for the anthem is the expected courtesy in Pakistan, 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(--pak-lit);
}

/* 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;
}
.zindabad { font-family: var(--urdu); font-size: 1.02rem; color: var(--pak-lit); }

/* ============================================================ 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(var(--pak-lit-rgb) / 0.18); }
  .coach__bubble.is-in { animation: none; }
}
