/* ============================================================
   HERO SECTION — the invitation

   ONE COORDINATE SYSTEM, ONE CONTROLLED SCALE.

   The reference invitation is 358 design units across. --u is one of
   those units. Every size, gap, offset and ornament below is written
   as a multiple of --u, so the elements can never drift apart from one
   another — the whole composition moves as a single designed sheet.

     --u grows with the section width  ...up to a ceiling.

   Below the ceiling the composition is the reference at 1:1, so a
   phone shows exactly the supplied design. Above it the scale holds
   steady and the parchment simply gets wider around the invitation:
   full-width background, controlled composition. Nothing becomes
   gigantic on a 1920 monitor.

   The two things anchored to the paper's edges rather than to the
   composition are the side flowers (which must stay half off the edge,
   as in the reference) and the two arms (which must always reach in
   from off-paper to meet in the middle).
   ============================================================ */

.invitation {
  container-type: inline-size;
  position: relative;
  width: 100%;
  overflow: hidden;           /* the arms and flowers run off both edges */

  --paper-cream: #f8f0dd;
  --ink-maroon: #6e3323;      /* couple names, countdown */
  --ink-navy: #17406e;        /* Shiv-Parvati */
  --ink-body: #6b3a2a;        /* invitation message */
  --ink-muted: #8a6a5b;       /* "Son of" / "Daughter of" */
  --ink-parents: #4b3a32;

  --ease-out-soft: cubic-bezier(0.33, 0, 0.1, 1);
  --ease-hand: cubic-bezier(0.4, 0.05, 0.12, 1);

  background-color: var(--paper-cream);
}

.invitation__canvas {
  /* One design unit. 100/358 = 0.27933. The ceiling stops the
     composition growing past a comfortable size on large displays. */
  --u: min(0.27933cqw, 3px);

  /* The arms take the design size, or however much is needed to reach
     in from the paper's edge — whichever is larger. They always keep
     their 330 : 250 relationship to each other. */
  --parvati-w: max(calc(330 * var(--u)), 67.3cqw);
  --shiva-w: calc(var(--parvati-w) * 0.7576);

  /* Where the two fingertips meet, a little right of centre as in the
     reference. The gap between them is measured in --u so it stays in
     scale with the hands themselves. */
  --tip-parvati: calc(50cqw - 0.2 * var(--u));
  --tip-shiva: calc(50cqw + 11.6 * var(--u));

  position: relative;
  background-color: var(--paper-cream);
  background-image: url("../images/bg.png");
  background-size: 100% auto;
  background-repeat: repeat-y;
  background-position: center top;
  background-blend-mode: multiply;
}

/* ---- Layer 1 — the temple friezes -------------------------------------- */

/* Tiled rather than stretched, so the pattern keeps its own proportions
   at any width. At the reference scale exactly one tile spans the paper. */
.invitation__border {
  position: relative;
  z-index: 6;
  width: 100%;
  height: calc(27.4 * var(--u));
  background-image: url("../images/below-temple-minar.png");
  background-repeat: repeat-x;
  background-position: center top;
  background-size: auto 100%;
}

.invitation__border--bottom {
  transform: scaleY(-1);      /* pendants point back up along the lower edge */
}

/* ---- Layer 2 — the four temple bells ----------------------------------- */

/* Two pairs, one per side. Each group is a zero-size anchor pinned a share
   of the paper's width in from its edge, so the pairs stay near the sides
   at any viewport; the spacing *within* a pair is in --u, so the two bells
   never drift apart from one another. */
.invitation__bells {
  position: absolute;
  z-index: 5;
  top: calc(13 * var(--u));
  /* A real box, so the pair has something to be measured against: big
     bell (30) + gap (3) + small bell (22). */
  width: calc(55 * var(--u));
  height: 0;
}

.invitation__bells--left {
  left: 5%;
}

.invitation__bells--right {
  right: 5%;
}

.invitation__bell {
  position: absolute;
  top: 0;
  height: auto;
  max-width: none;
  transform-origin: 50% 2%;   /* where the chain meets the frieze */
}

/* Sizes come straight from the artwork — 114 x 321 against 84 x 234 — so
   the big bell reads as the big one, and because the small bell's chain is
   shorter it naturally hangs higher than its partner. */
.invitation__bell--big {
  width: calc(30 * var(--u));
}

.invitation__bell--small {
  width: calc(22 * var(--u));
}

.invitation__bells--left .invitation__bell--big {
  left: 0;
}

.invitation__bells--left .invitation__bell--small {
  left: calc(33 * var(--u));
}

.invitation__bells--right .invitation__bell--big {
  right: 0;
}

.invitation__bells--right .invitation__bell--small {
  right: calc(33 * var(--u));
}

/* ---- Layer 3 — the side flowers ---------------------------------------- */

/* Anchored to the paper's edges and deliberately running off them, so
   only the inner part of each spray is on the page. */
.invitation__flower {
  position: absolute;
  z-index: 2;
  top: calc(148 * var(--u));
  width: calc(62 * var(--u));
  height: auto;
  opacity: 0.95;
}

.invitation__flower--left {
  left: calc(-22 * var(--u));
  rotate: -4deg;
}

.invitation__flower--right {
  right: calc(-22 * var(--u));
  scale: -1 1;
  rotate: -4deg;
}

/* ---- The centred column ------------------------------------------------ */

.invitation__content {
  position: relative;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: calc(306 * var(--u));
  margin-inline: auto;
  padding: calc(46 * var(--u)) 0 calc(24 * var(--u));
  text-align: center;
}

/* ---- Layer 4 — typography and devotional marks ------------------------- */

.invitation__trishul {
  width: calc(46 * var(--u));
  height: auto;
}

.invitation__blessed {
  /* Rises just enough on wide screens to stay legible under a 55px
     heading, while holding the hierarchy at roughly 4:1. */
  margin: calc(7 * var(--u)) 0 0;
  font-family: 'Montserrat', 'Segoe UI', system-ui, sans-serif;
  font-weight: 600;
  font-size: clamp(11px, 0.9vw, 14px);
  line-height: 1.4;
  letter-spacing: 0.05em;
  color: var(--ink-body);
}

.invitation__deities {
  /* Reaches its full 55px at laptop width (~1280px) and holds there on
     larger desktops, then eases down through tablet to 30px on a phone.
     Line height is unitless so it tracks the size at every step.

     The padding is paid back by the negative margins, so the layout is
     unchanged. It exists for the brush-stroke reveal: a mask clips at the
     border box, and this script face swings its loops well outside its
     line box. Without the room, the tails would be cut off. */
  margin: calc(1 * var(--u) - 0.2em) -0.35em -0.2em;
  padding: 0.2em 0.35em;
  font-family: 'Roaster Brush', 'Brush Script MT', cursive;
  font-weight: 400;
  font-size: clamp(30px, 4.3vw, 55px);
  line-height: 1.15;
  letter-spacing: 0.005em;
  color: var(--ink-navy);
}

.invitation__divider {
  width: calc(90 * var(--u));
  height: auto;
  margin-top: calc(3 * var(--u));
}

.invitation__name {
  margin: calc(17 * var(--u)) 0 0;
  font-family: 'Times New Roman', Times, serif;
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: calc(30 * var(--u));
  letter-spacing: 0.005em;
  color: var(--ink-maroon);
}

.invitation__name--bride {
  margin-top: calc(15 * var(--u));
}

.invitation__rel {
  margin: calc(5 * var(--u)) 0 0;
  font-family: 'Montserrat', 'Segoe UI', system-ui, sans-serif;
  font-weight: 600;
  font-size: calc(6.2 * var(--u));
  line-height: calc(8 * var(--u));
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}

.invitation__parents {
  margin: calc(2.5 * var(--u)) 0 0;
  font-family: 'Montserrat', 'Segoe UI', system-ui, sans-serif;
  font-weight: 600;
  font-size: calc(7 * var(--u));
  line-height: calc(10 * var(--u));
  letter-spacing: 0.02em;
  color: var(--ink-parents);
}

.invitation__swastik {
  width: calc(36 * var(--u));
  height: auto;
  margin-top: calc(15 * var(--u));
}

/* ---- Layer 5 — Shiva and Parvati --------------------------------------- */

/* The band's height follows the arms, so it always holds them however
   far they have had to reach. */
.invitation__hands {
  position: relative;
  z-index: 4;
  width: 100vw;
  max-width: 100cqw;
  height: calc(0.325 * var(--parvati-w));   /* both arms, whole, with the new artwork */
  margin-top: calc(6 * var(--u));
}

/* Each arm is placed by its fingertip, never by its edge: Parvati's
   fingertip sits 98.94% along her artwork (2172 x 724) and 16.05% of its
   width down from the top, Shiva's 1.39% along his and 24.60% down. That
   is what makes them meet on the same point at every screen size.
   (Parvati's figures were re-measured off the pixels when her artwork was
   replaced; the old 91.2% / 23.92% belonged to the previous drawing, and
   left her hand high and over Shiva's.) */
.invitation__hand {
  position: absolute;
  height: auto;
}

.invitation__hand--parvati {
  width: var(--parvati-w);
  left: calc(var(--tip-parvati) - 0.9894 * var(--parvati-w));
  top: calc(0.1515 * var(--parvati-w) - 0.1605 * var(--parvati-w));
  z-index: 1;
}

.invitation__hand--shiva {
  width: var(--shiva-w);
  left: calc(var(--tip-shiva) - 0.0139 * var(--shiva-w));
  top: calc(0.1515 * var(--parvati-w) - 0.246 * var(--shiva-w));
  z-index: 2;
}

/* ---- Layer 6 — the lower content --------------------------------------- */

.invitation__message {
  max-width: calc(290 * var(--u));
  margin: calc(14 * var(--u)) 0 0;
  font-family: 'Montserrat', 'Segoe UI', system-ui, sans-serif;
  font-weight: 600;
  font-size: calc(7 * var(--u));
  line-height: calc(13 * var(--u));
  letter-spacing: 0.01em;
  color: var(--ink-body);
}

.invitation__countdown {
  margin: calc(17 * var(--u)) 0 0;
  font-family: 'Akshar', 'Segoe UI', system-ui, sans-serif;
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: calc(15 * var(--u));
  letter-spacing: 0.01em;
  color: var(--ink-maroon);
}

.invitation__damru {
  width: calc(104 * var(--u));
  height: auto;
  margin-top: calc(10 * var(--u));
  transform-origin: 50% 22%;
}

/* ============================================================
   THE SEQUENCE

   Two clocks.

   THE CROWN runs off the section arriving (invitation--live):

     0.20s  the top frieze unfurls outward from its centre
     0.30s  the big bell drops onto its chain and rings itself quiet
     0.45s  the small bell follows, on its own beat
     0.50s  the side flowers breathe in from the edges

   THE COLUMN runs as it is read. invitation.js adds .is-in to each
   element as it comes into view and hands it a --rv-delay, so anything
   arriving together still lands in document order, a beat apart:

            trishul, the blessing, Shiv-Parvati written in one stroke
            Aarav Sharma, then his parents
            swastik, arriving in a small bloom of gold
            Ananya Joshi, then her parents
            THE HANDS — see below
            the message, then the countdown
            the damru arrives, keeps one slow beat, and rests
            the lower frieze unfurls to close the sheet

   THE HANDS. With the motion layer running, scroll drives the crossing
   (invitation-animations.js) and the rule below is switched off. Without
   it, the hands still cross on their own clock the moment they are seen.

   Every distance travelled is a share of the canvas or of --u, so the
   choreography scales exactly like the layout. Every animation ends on
   the element's natural state, so the settled hero is precisely the
   static composition defined above.
   ============================================================ */

.invitation--idle .invitation__border,
.invitation--idle .invitation__bell,
.invitation--idle .invitation__flower,
.invitation--idle .invitation__hand,
.invitation--idle .invitation__damru,
.invitation--idle .rv {
  opacity: 0;
}

/* The column stays hidden past the crown until each piece is actually read. */
.invitation--live .rv:not(.is-in),
.invitation--live .invitation__hand:not(.is-in),
.invitation--live .invitation__damru:not(.is-in),
.invitation--live .invitation__border--bottom:not(.is-in) {
  opacity: 0;
}

.invitation--live .invitation__border--top {
  animation: friezeUnfurl 1.4s var(--ease-out-soft) 0.2s both;
}

.invitation--live .invitation__border--bottom.is-in {
  animation: friezeUnfurl 1.4s var(--ease-out-soft) var(--rv-delay, 0s) both;
}

/* Each of the four hangs on its own clock: it drops onto its chain, rings
   itself quiet, then keeps a slow endless sway. The periods are all
   different and none divides into another, so the pairs never fall into
   step and the motion stays in the background. */
.invitation--live .invitation__bells--left .invitation__bell--big {
  animation:
    bellSettle 1.7s var(--ease-out-soft) 0.3s both,
    bellSway 7.3s ease-in-out 1.9s infinite;
}

.invitation--live .invitation__bells--left .invitation__bell--small {
  animation:
    bellSettleSmall 1.55s var(--ease-out-soft) 0.42s both,
    bellSwaySmall 6.1s ease-in-out 1.85s infinite;
}

.invitation--live .invitation__bells--right .invitation__bell--big {
  animation:
    bellSettle 1.7s var(--ease-out-soft) 0.38s both,
    bellSway 8.1s ease-in-out 2.15s infinite;
}

.invitation--live .invitation__bells--right .invitation__bell--small {
  animation:
    bellSettleSmall 1.55s var(--ease-out-soft) 0.5s both,
    bellSwaySmall 6.7s ease-in-out 2.35s infinite;
}

.invitation--live .invitation__flower--left {
  animation: flowerLeft 1.6s var(--ease-out-soft) 0.5s both;
}

.invitation--live .invitation__flower--right {
  animation: flowerRight 1.6s var(--ease-out-soft) 0.6s both;
}

.invitation--live .invitation__trishul.is-in,
.invitation--live .invitation__blessed.is-in,
.invitation--live .invitation__divider.is-in {
  animation: inkRise 0.9s var(--ease-out-soft) var(--rv-delay, 0s) both;
}

/* Shiv-Parvati is painted, not placed: one brush stroke travels left to
   right with a soft wet edge. The mask is only attached while this rule
   applies, so the static invitation never carries it. */
.invitation--live .invitation__deities.is-in {
  -webkit-mask-image: linear-gradient(90deg, #000 46%, transparent 54%);
  mask-image: linear-gradient(90deg, #000 46%, transparent 54%);
  -webkit-mask-size: 220% 100%;
  mask-size: 220% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  animation: brushWrite 1.6s cubic-bezier(0.45, 0.05, 0.25, 1) var(--rv-delay, 0s) both;
}

.invitation--live .invitation__name.is-in {
  animation: inkRise 0.95s var(--ease-out-soft) var(--rv-delay, 0s) both;
}

.invitation--live .invitation__rel.is-in,
.invitation--live .invitation__parents.is-in {
  animation: inkRise 0.85s var(--ease-out-soft) var(--rv-delay, 0s) both;
}

.invitation--live .invitation__swastik.is-in {
  animation: swastikBless 1.25s var(--ease-out-soft) var(--rv-delay, 0s) both;
}

/* The heart of the sequence: a slow, deliberate crossing. */
.invitation--live .invitation__hand--parvati.is-in {
  animation: parvatiCrosses 2.15s var(--ease-hand) var(--rv-delay, 0s) both;
}

.invitation--live .invitation__hand--shiva.is-in {
  animation: shivaCrosses 2s var(--ease-hand) calc(var(--rv-delay, 0s) + 0.15s) both;
}

.invitation--live .invitation__message.is-in {
  animation: inkRise 1s var(--ease-out-soft) var(--rv-delay, 0s) both;
}

.invitation--live .invitation__countdown.is-in {
  animation: inkRise 0.95s var(--ease-out-soft) var(--rv-delay, 0s) both;
}

.invitation--live .invitation__damru.is-in {
  animation:
    damruArrives 1s var(--ease-out-soft) var(--rv-delay, 0s) both,
    damruRhythm 2.2s ease-in-out calc(var(--rv-delay, 0s) + 0.75s) forwards;
}

/* ---- Keyframes --------------------------------------------------------- */

/* The frieze draws itself outward from the centre of the sheet. Clip only,
   no transform, so the lower frieze keeps its scaleY(-1) flip untouched. */
@keyframes friezeUnfurl {
  from {
    opacity: 0.25;
    clip-path: inset(0 50% 0 50%);
  }
  to {
    opacity: 1;
    clip-path: inset(0 0 0 0);
  }
}

/* One brush stroke. The mask is 220% wide with a soft 8% edge; sliding it
   from 100% to 0% sweeps that wet edge across the word exactly once. */
@keyframes brushWrite {
  from {
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
    transform: translateY(calc(2 * var(--u)));
  }
  to {
    -webkit-mask-position: 0% 0;
    mask-position: 0% 0;
    transform: none;
  }
}

@keyframes inkRise {
  from {
    opacity: 0;
    transform: translateY(calc(9 * var(--u)));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* The swastik arrives upright and stays upright — it scales and blooms,
   it never turns. A swastik caught mid-rotation reads as a tilted cross,
   which is exactly the association this symbol must never be given. */
@keyframes swastikBless {
  0% {
    opacity: 0;
    transform: scale(0.8);
    filter: drop-shadow(0 0 0 rgba(214, 164, 58, 0));
  }
  45% {
    opacity: 1;
    transform: scale(1.06);
    filter: drop-shadow(0 0 calc(7 * var(--u)) rgba(214, 164, 58, 0.8));
  }
  100% {
    opacity: 1;
    transform: none;
    filter: drop-shadow(0 0 0 rgba(214, 164, 58, 0));
  }
}

/* A bell dropping onto its chain and swinging itself quiet. */
@keyframes bellSettle {
  0% {
    opacity: 0;
    transform: translateY(-9%) rotate(-2.8deg);
  }
  22% {
    opacity: 1;
  }
  38% {
    transform: translateY(0) rotate(2deg);
  }
  60% {
    transform: rotate(-1.2deg);
  }
  80% {
    transform: rotate(0.6deg);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* The lighter bell settles a touch quicker, and the other way about, so a
   pair never looks mechanically synchronised. */
@keyframes bellSettleSmall {
  0% {
    opacity: 0;
    transform: translateY(-9%) rotate(2.4deg);
  }
  22% {
    opacity: 1;
  }
  40% {
    transform: translateY(0) rotate(-1.8deg);
  }
  62% {
    transform: rotate(1deg);
  }
  82% {
    transform: rotate(-0.45deg);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* The resting sway. A degree or so either side over seven-odd seconds:
   enough that the bells are alive, little enough that nothing pulls the
   eye away from the invitation. Both start and end at rest, so they pick
   up from the settle without a step. */
@keyframes bellSway {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(1.15deg);
  }
  50% {
    transform: rotate(0deg);
  }
  75% {
    transform: rotate(-1.15deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

/* The smaller, lighter bell carries a fraction more travel. */
@keyframes bellSwaySmall {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(-1.5deg);
  }
  50% {
    transform: rotate(0deg);
  }
  75% {
    transform: rotate(1.5deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

/* The sprays ease in from the paper's edge and settle. */
@keyframes flowerLeft {
  0% {
    opacity: 0;
    transform: translateX(calc(-7 * var(--u))) scale(0.98);
  }
  60% {
    opacity: 0.95;
  }
  100% {
    opacity: 0.95;
    transform: none;
  }
}

@keyframes flowerRight {
  0% {
    opacity: 0;
    transform: translateX(calc(7 * var(--u))) scale(0.98);
  }
  60% {
    opacity: 0.95;
  }
  100% {
    opacity: 0.95;
    transform: none;
  }
}

/* Parvati crosses in from well beyond the left edge of the paper.
   The distance is in cqw, so the journey is the same proportion of the
   canvas on a phone as it is on a monitor. */
@keyframes parvatiCrosses {
  0% {
    opacity: 0;
    transform: translateX(-58cqw);
  }
  10% {
    opacity: 1;
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* Shiva crosses in from beyond the right, arriving on the same beat. */
@keyframes shivaCrosses {
  0% {
    opacity: 0;
    transform: translateX(55cqw);
  }
  10% {
    opacity: 1;
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes damruArrives {
  from {
    opacity: 0;
    transform: translateY(calc(8 * var(--u))) scale(0.965) rotate(-2.4deg);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* One slow devotional beat, fading out to stillness. */
@keyframes damruRhythm {
  0% {
    transform: rotate(0deg);
  }
  16% {
    transform: rotate(2.6deg);
  }
  38% {
    transform: rotate(-2.1deg);
  }
  58% {
    transform: rotate(1.4deg);
  }
  76% {
    transform: rotate(-0.8deg);
  }
  90% {
    transform: rotate(0.3deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

/* ---- Reduced motion — the finished invitation, straight away ----------- */

@media (prefers-reduced-motion: reduce) {
  .invitation--idle .invitation__border,
  .invitation--idle .invitation__bell,
  .invitation--idle .invitation__hand,
  .invitation--idle .invitation__damru,
  .invitation--idle .rv {
    opacity: 1;
  }

  .invitation--idle .invitation__flower {
    opacity: 0.95;
  }

  .invitation--live .invitation__border,
  .invitation--live .invitation__bell,
  .invitation--live .invitation__flower,
  .invitation--live .invitation__hand,
  .invitation--live .invitation__damru,
  .invitation--live .rv,
  .invitation--live .invitation__border.is-in,
  .invitation--live .invitation__hand.is-in,
  .invitation--live .invitation__damru.is-in,
  .invitation--live .rv.is-in {
    animation: none;
  }

  /* If the setting flips mid-visit, nothing still waiting to be read may
     stay hidden. */
  .invitation--live .rv:not(.is-in),
  .invitation--live .invitation__hand:not(.is-in),
  .invitation--live .invitation__damru:not(.is-in),
  .invitation--live .invitation__border--bottom:not(.is-in) {
    opacity: 1;
  }
}
