/* birthday-3 styles - zodiac pocket-watch animation. index.html depends on the
   .watch / .swing / .cover structure here; the swing keyframe timeline is the
   single source of truth for the open-hold-close cycle. */

:root {
  --paper: #faf8f5;
  --gold: #c9a84c;
  --gold-deep: #a8862e;
  --navy: #1c2a4a;
  --text-soft: #5c6675;
  --border: rgba(201, 168, 76, 0.45);

  /* Circle diameter - every layout offset below derives from this. Sized so
     the full scene (top padding + watch + reserved open-swing space below)
     fits inside a phone viewport without scrolling. */
  --size: 330px;

  /* Swing cycle: hold closed 0.5s, swing open 3s, hold open 7.5s, swing closed
     3s (continuing forward past 360deg instead of reversing - see keyframes),
     hold closed 2s = 16s total. Keyframe percentages in @keyframes swing-cycle
     are computed from these durations; change them together. */
  --cycle: 16s;

  /* Hinge sits this far above the cover's bottom edge, not on it - pulls the
     whole swing arc upward so the open ring settles higher / overlaps more.
     Must be a LENGTH (derived from --size), not a bare percentage: it's reused
     as an offset on .swing-item, whose containing block (.swing) is 0x0, so a
     percentage there would resolve against zero and silently collapse to 0. */
  --hinge-lift: calc(var(--size) * 0.1);
}

@font-face {
  font-family: "123Wave";
  src: url("123Wave-Regular.ttf") format("truetype");
  font-display: block; /* safe only because the loader covers the block period */
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scrollbar-color: var(--gold) var(--paper);
  scrollbar-width: thin;
  /* overflow-x belongs on html alone. On body it also forces overflow-y to
     compute as auto, which turns body into a scroll container that can never
     scroll - the trackpad wheel gesture latches onto that dead scroller. */
  overflow-x: hidden;
  overscroll-behavior-y: none;
}

::-webkit-scrollbar {
  width: 10px;
}

::-webkit-scrollbar-track {
  background: var(--paper);
}

::-webkit-scrollbar-thumb {
  background-color: var(--gold);
  border-radius: 6px;
  border: 2px solid var(--paper);
}

body {
  /* Fallback only - .bg-base covers the viewport; paper shows just if it fails */
  background-color: var(--paper);
}

.scene {
  position: relative;
  z-index: 1; /* above the fixed .bg stage (z-index:0) */
  display: flex;
  justify-content: center;
  min-height: 100vh;
  min-height: 100svh;
  /* Top padding gives the wheel breathing room; bottom reserves a full disc
     diameter for the open position so the page doesn't jump when it swings down */
  padding: 24px 0 calc(var(--size) + 40px);
  /* Clip the spinning square PNGs and the wide swing arc. Without this, those
     transformed elements enlarge the page's scroll area as they rotate/sweep
     out past the viewport, producing an intermittent scrollbar. The open (down)
     ring sits inside the reserved bottom padding, so it is NOT clipped. */
  overflow: hidden;
}

/* Watch = positioning context sized to the cover only. The disc lives below it
   in open state, hence the reserved padding on .scene, not extra height here. */
.watch {
  position: relative;
  width: var(--size);
  height: var(--size);
}

/* ---------- Spinning cover ---------- */

.cover {
  position: absolute;
  inset: 0;
  z-index: 3;
}

.ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  user-select: none;
  -webkit-user-select: none;
  will-change: transform;
}

/* One shared spin keyframe, three periods. Linear is mandatory - any easing
   would make the loop visibly hitch at the wrap point. */
@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

.ring--inner  { animation: spin 28s linear infinite; }
.ring--middle { animation: spin 52s linear infinite; }
.ring--outer  { animation: spin 85s linear infinite; }

/* ---------- Swinging disc ---------- */

/* Zero-size pivot parked exactly at the clasp (bottom center of the cover).
   transform-origin defaults to its own 0x0 point, so rotating it swings
   everything inside around the hinge. */
.swing {
  position: absolute;
  left: 50%;
  top: calc(100% - var(--hinge-lift));
  width: 0;
  height: 0;
  z-index: 1;
  will-change: transform;
  animation: swing-cycle var(--cycle) infinite;
}

/* Outer ring hangs below the pivot. At rotate(180deg) (closed) it sits exactly
   over the cover, framing middle+inner; at rotate(360deg) (open) it rests below.
   The img inside keeps its own slow spin, so the swing lives on this wrapper.
   top is offset by -hinge-lift (not 0) to counteract the pivot itself being
   raised by --hinge-lift on .swing - otherwise the closed/180deg position
   would drift upward off the cover by that same amount. Raising the pivot
   while keeping this offset only changes where the OPEN position rests. */
.swing-item {
  position: absolute;
  left: calc(var(--size) / -2);
  top: calc(-1 * var(--hinge-lift));
  width: var(--size);
  height: var(--size);
}

/* Circular text along the ring's inner edge. Shares the outer ring's spin
   (identical 85s duration/timing keeps them locked in sync) and swings with it
   because it lives in .swing-item. viewBox units == % of --size, so font-size
   below is effectively proportional to the ring at every breakpoint. */
.ring-arc {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  animation: spin 85s linear infinite;
}

.ring-arc text {
  font-family: "123Wave", "Noto Serif Georgian", serif;
  font-size: 3.6px;
  letter-spacing: 0.15px;
  fill: var(--gold-deep);
}

/* Centered in the ring's hole. Font-size scales with --size (calc, not clamp)
   so the block keeps the same fit at every breakpoint. max-width keeps the
   longest line clear of the gold frame. */
.ring-text {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--size) * 0.012);
  max-width: 74%;
  margin: 0 auto;
  font-family: "123Wave", "Noto Serif Georgian", serif;
  font-size: calc(var(--size) * 0.1);
  line-height: 1.05;
  color: var(--navy);
  text-align: center;
  pointer-events: none;
}

/* Hand-drawn stop-motion wobble, ported from weddsite-template-pro-8's
   namesStopMotion: tiny steps(1) jitters of opacity/translateY/rotate so the
   name looks frame-by-frame animated rather than smoothly tweened. */
@keyframes nameStopMotion {
  0%   { opacity: 0.92; transform: translateY(0px)  rotate(-0.15deg); animation-timing-function: steps(1); }
  13%  { opacity: 1.00; transform: translateY(-1px) rotate(0.10deg);  animation-timing-function: steps(1); }
  26%  { opacity: 0.88; transform: translateY(0px)  rotate(-0.10deg); animation-timing-function: steps(1); }
  39%  { opacity: 0.95; transform: translateY(1px)  rotate(0.18deg);  animation-timing-function: steps(1); }
  52%  { opacity: 1.00; transform: translateY(0px)  rotate(-0.12deg); animation-timing-function: steps(1); }
  65%  { opacity: 0.90; transform: translateY(-1px) rotate(0.15deg);  animation-timing-function: steps(1); }
  78%  { opacity: 0.94; transform: translateY(0px)  rotate(-0.18deg); animation-timing-function: steps(1); }
  91%  { opacity: 1.00; transform: translateY(1px)  rotate(0.10deg);  animation-timing-function: steps(1); }
  100% { opacity: 0.92; transform: translateY(0px)  rotate(-0.15deg); }
}

/* Bigger than its sibling lines, navy fill with a gold outline. paint-order
   draws the stroke first so it reads as a clean outline around the letters
   instead of thinning the fill. */
.ring-text__name {
  font-size: calc(var(--size) * 0.155);
  line-height: 1;
  -webkit-text-stroke: 1.5px var(--gold);
  paint-order: stroke fill;
  animation: nameStopMotion 4.2s infinite;
}

/* "დაბადების დღე" on a single line, smaller than the name. Negative
   animation-delays offset each line's wobble so the three never jitter in
   unison (same trick pro-8 uses on its name lines). */
.ring-text__sub {
  font-size: calc(var(--size) * 0.072);
  white-space: nowrap;
  animation: nameStopMotion 4.2s -1.4s infinite;
}

.ring-text__date {
  font-size: calc(var(--size) * 0.078);
  white-space: nowrap;
  animation: nameStopMotion 4.2s -2.7s infinite;
}

/* Softer, slower stop-motion for the badge - smaller jitters than the text so
   the illustration doesn't dance as hard. */
@keyframes signStopMotion {
  0%   { opacity: 0.96; transform: translateY(0px)   rotate(-0.06deg); animation-timing-function: steps(1); }
  25%  { opacity: 1.00; transform: translateY(-0.5px) rotate(0.05deg);  animation-timing-function: steps(1); }
  50%  { opacity: 0.97; transform: translateY(0px)   rotate(-0.05deg); animation-timing-function: steps(1); }
  75%  { opacity: 1.00; transform: translateY(0.5px)  rotate(0.06deg);  animation-timing-function: steps(1); }
  100% { opacity: 0.96; transform: translateY(0px)   rotate(-0.06deg); }
}

/* Zodiac badge below the date. Sized to --size so it scales with the ring;
   small extra top margin sets it apart from the text. */
.ring-text__sign {
  width: calc(var(--size) * 0.20);
  height: auto;
  margin-top: calc(var(--size) * 0.02);
  animation: signStopMotion 6s -0.6s infinite;
}

/* Closed = 180deg (ring framing the cover), open = 360deg (ring below).
   The close leg keeps rotating FORWARD to 540deg instead of reversing back
   to 180deg - 540deg is the same visual position as 180deg (mod 360), so it
   snaps back seamlessly at the next iteration's 0%, but the ring travels
   there via the opposite arc (through the left side rather than back through
   the right), and the two legs together trace one full 360deg revolution -
   the "full rotation" pass.
   Timeline on a 16s cycle:
     0%     - 3.13%  hold closed (0.5s)
     3.13%  - 21.88% swing open  (3s)
     21.88% - 68.75% hold open   (7.5s)
     68.75% - 87.5%  swing close, continuing forward (3s)
     87.5%  - 100%   hold closed (2s)
   timing-function on a keyframe applies to the segment that FOLLOWS it. */
@keyframes swing-cycle {
  0% {
    transform: rotate(180deg);
    animation-timing-function: cubic-bezier(0.55, 0.06, 0.35, 1);
  }
  3.13% {
    transform: rotate(180deg);
    animation-timing-function: cubic-bezier(0.55, 0.06, 0.28, 1.08);
  }
  21.88% {
    transform: rotate(360deg);
    animation-timing-function: linear;
  }
  68.75% {
    transform: rotate(360deg);
    animation-timing-function: cubic-bezier(0.55, 0.06, 0.28, 1.08);
  }
  87.5% {
    transform: rotate(540deg);
    animation-timing-function: linear;
  }
  100% {
    transform: rotate(540deg);
  }
}

/* ---------- Clasp ---------- */

/* Small diamond marking the hinge; static on top of both circles */
.clasp {
  position: absolute;
  left: 50%;
  top: 100%;
  width: 26px;
  height: 26px;
  transform: translate(-50%, -50%) rotate(45deg);
  background-color: #ffffff;
  border: 1px solid var(--navy);
  box-shadow: 0 2px 8px rgba(28, 42, 74, 0.25);
  z-index: 4;
}

/* ---------- Parallax background ---------- */

/* Fixed full-viewport stage behind the scene. z-index:0 (not negative) so it
   paints ABOVE the body's opaque fallback background - a negative z-index here
   would hide the whole stage behind that paper colour (the bug that made the
   parallax look dead). .scene sits at z-index:1 above it. overflow:hidden clips
   every drifting layer so nothing can push the page wider or taller. */
.bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.bg-layer {
  position: absolute;
  will-change: transform;
}

/* Base image fits the viewport exactly (inset:0, cover) and does NOT parallax,
   so it can never drift past an edge - this is what keeps the background from
   overflowing. Only the accent layers above it move. */
.bg-base {
  inset: 0;
  background-image: url("https://weddsite.b-cdn.net/showcase/birthday-3/hero-bg.png");
  background-size: cover;
  background-position: center;
}

.bg-corner {
  width: 110px;
  height: auto;
  display: block;
}

.bg-corner--tl {
  top: 0;
  left: 0;
}

.bg-corner--tr {
  top: 0;
  right: 0;
}

/* Wrapper centers vertically (static, via transform); the img inside takes
   the parallax transform from script.js, so the two transforms never fight
   over the same element. */
.bg-side {
  top: 50%;
  transform: translateY(-50%);
  width: 90px;
}

.bg-side--left { left: 0; }
.bg-side--right { right: 0; }

.bg-side img {
  display: block;
  width: 100%;
  height: auto;
  will-change: transform;
}

/* ---------- Shared section chrome ---------- */

/* Sections sit in normal flow above the fixed .bg (z-index:0), so they need
   their own positioned z-index to paint over it. */
.section {
  position: relative;
  z-index: 1;
  padding: 60px 24px;
  text-align: center;
}

.section__deco {
  color: var(--gold);
  font-size: 18px;
  line-height: 1;
  margin-bottom: 12px;
}

.section__title {
  font-family: "123Wave", "Noto Serif Georgian", serif;
  font-size: 30px;
  font-weight: 400;
  line-height: 1.15;
  margin-bottom: 1rem;
  color: var(--navy);
}

/* Short gold rule with a centered star sitting on it */
.section__rule {
  position: relative;
  width: 66px;
  height: 1px;
  margin: 18px auto 30px;
  background-color: var(--gold);
}

.section__rule::after {
  content: "✦";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 0 8px;
  background-color: var(--paper);
  color: var(--gold-deep);
  font-size: 12px;
}

/* Scroll reveal - fade + rise, driven by IntersectionObserver in script.js */
.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- Timetable ---------- */

/* Party "ticket": a deep-navy night-out card with gold neon accents. Rocks
   gently forever; its inner lines pop in one after another once revealed. */
.party-card {
  position: relative;
  overflow: hidden;
  max-width: 330px;
  margin: 0 auto;
  padding: 38px 26px 32px;
  border: 1px solid rgba(201, 168, 76, 0.5);
  border-radius: 22px;
  background-color: #1c2a4a;
  background-image: radial-gradient(120% 90% at 50% 0%, #2a3d63 0%, #16233c 62%);
  box-shadow: 0 20px 46px rgba(20, 30, 52, 0.4),
    inset 0 0 34px rgba(201, 168, 76, 0.07);
  animation: cardRock 6s ease-in-out infinite;
}

/* Twinkling corner stars - always animating; scattered by position + delay */
.spark {
  position: absolute;
  color: var(--gold);
  pointer-events: none;
  animation: twinkle 2.6s ease-in-out infinite;
}
.spark--1 { top: 14px;    left: 20px;  font-size: 13px; animation-duration: 2.4s; }
.spark--2 { top: 24px;    right: 26px; font-size: 10px; animation-delay: 0.6s; animation-duration: 3s; }
.spark--3 { top: 46%;     left: 12px;  font-size: 9px;  animation-delay: 1.1s; animation-duration: 2.2s; }
.spark--4 { bottom: 30px; left: 26px;  font-size: 12px; animation-delay: 0.3s; animation-duration: 2.8s; }
.spark--5 { bottom: 22px; right: 22px; font-size: 15px; animation-delay: 0.9s; animation-duration: 3.2s; }
.spark--6 { top: 40%;     right: 14px; font-size: 11px; animation-delay: 1.4s; animation-duration: 2.5s; }

.party-emoji {
  font-size: 42px;
  line-height: 1;
  margin-bottom: 6px;
  animation: floatY 3.6s ease-in-out infinite;
}

/* Pop-in targets - hidden until the section reveals, then staggered in */
.party-when,
.party-time,
.party-tag,
.party-sep,
.party-venue,
.party-address,
.party-map {
  opacity: 0;
}

.party-when {
  color: var(--gold);
  font-family: "Noto Serif Georgian", serif;
  font-size: 15px;
  letter-spacing: 0.04em;
}

.party-time {
  margin-top: 2px;
  color: var(--gold);
  font-family: "Noto Serif Georgian", serif;
  font-size: 56px;
  font-weight: 700;
  line-height: 1;
}

.party-tag {
  margin-top: 8px;
  color: #eef2f8;
  font-family: "123Wave", "Noto Serif Georgian", serif;
  font-size: 21px;
}

.party-sep {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 20px 0;
  color: var(--gold);
  font-size: 12px;
}

.party-sep::before,
.party-sep::after {
  content: "";
  width: 42px;
  height: 1px;
  background-color: rgba(201, 168, 76, 0.4);
}

.party-venue {
  color: #f4f1e7;
  font-family: "123Wave", "Noto Serif Georgian", serif;
  font-size: 23px;
}

.party-address {
  margin-top: 6px;
  color: #b7c2d3;
  font-family: "Noto Serif Georgian", serif;
  font-size: 14px;
  line-height: 1.5;
}

.party-map {
  display: inline-block;
  margin-top: 20px;
  padding: 10px 24px;
  border: 1px solid var(--gold);
  border-radius: 999px;
  color: var(--gold);
  font-family: "Noto Serif Georgian", serif;
  font-size: 14px;
  text-decoration: none;
  transition: background-color 0.25s ease, color 0.25s ease;
}

.party-map:hover {
  background-color: var(--gold);
  color: var(--navy);
}

/* Staggered reveal: each line pops with a little overshoot, one after another.
   party-time also keeps a slow neon glow (text-shadow only, so it never fights
   the pop's transform); party-map keeps a pulsing halo (box-shadow only). */
.timetable.visible .party-when    { animation: popIn 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.10s both; }
.timetable.visible .party-time    { animation: popIn 0.60s cubic-bezier(0.34, 1.56, 0.64, 1) 0.22s both, timeGlow 2.8s ease-in-out 1.2s infinite; }
.timetable.visible .party-tag     { animation: popIn 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.34s both; }
.timetable.visible .party-sep     { animation: popIn 0.50s ease 0.46s both; }
.timetable.visible .party-venue   { animation: popIn 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.56s both; }
.timetable.visible .party-address { animation: popIn 0.50s ease 0.68s both; }
.timetable.visible .party-map     { animation: popIn 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.80s both, mapPulse 2.6s ease-in-out 1.6s infinite; }

@keyframes popIn {
  0%   { opacity: 0; transform: translateY(16px) scale(0.9); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes floatY {
  0%, 100% { transform: translateY(0) rotate(-5deg); }
  50%      { transform: translateY(-9px) rotate(5deg); }
}

@keyframes twinkle {
  0%, 100% { opacity: 0.2; transform: scale(0.7); }
  50%      { opacity: 1;   transform: scale(1.2); }
}

@keyframes timeGlow {
  0%, 100% { text-shadow: 0 0 8px rgba(201, 168, 76, 0.35), 0 2px 10px rgba(0, 0, 0, 0.25); }
  50%      { text-shadow: 0 0 20px rgba(201, 168, 76, 0.8), 0 2px 14px rgba(0, 0, 0, 0.3); }
}

@keyframes cardRock {
  0%, 100% { transform: rotate(-0.6deg); }
  50%      { transform: rotate(0.6deg); }
}

@keyframes mapPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(201, 168, 76, 0.5); }
  50%      { box-shadow: 0 0 0 9px rgba(201, 168, 76, 0); }
}

/* Respect reduced-motion: kill the continuous loops, keep content visible */
@media (prefers-reduced-motion: reduce) {
  .party-card,
  .party-emoji,
  .spark {
    animation: none;
  }
  .timetable.visible .party-when,
  .timetable.visible .party-time,
  .timetable.visible .party-tag,
  .timetable.visible .party-sep,
  .timetable.visible .party-venue,
  .timetable.visible .party-address,
  .timetable.visible .party-map {
    animation: none;
    opacity: 1;
  }
}

/* ---------- RSVP ---------- */

.rsvp__note {
  margin: -14px auto 26px;
  font-family: "Noto Serif Georgian", serif;
  font-size: 14px;
  color: var(--text-soft);
}

.rsvp__form {
  max-width: 360px;
  margin: 0 auto;
  text-align: left;
}

.field {
  margin-bottom: 18px;
}

.field__label {
  display: block;
  margin-bottom: 7px;
  color: var(--gold-deep);
  font-family: "Noto Serif Georgian", serif;
  font-size: 13px;
}

/* 16px font-size on inputs stops iOS Safari from zooming on focus */
.field__input {
  width: 100%;
  padding: 13px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background-color: rgba(255, 255, 255, 0.78);
  color: var(--navy);
  font-family: "Noto Serif Georgian", serif;
  font-size: 16px;
  outline: none;
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}

.field__input:focus {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(201, 168, 76, 0.18);
}

.rsvp__attend {
  display: flex;
  gap: 12px;
  margin-bottom: 18px;
  border: none;
}

.rsvp__attend .field__label {
  flex-basis: 100%;
}

.attend-card {
  flex: 1;
  cursor: pointer;
}

/* Visually hidden but still focusable/checkable */
.attend-card input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.attend-card__box {
  display: block;
  padding: 14px 10px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background-color: rgba(255, 255, 255, 0.78);
  color: var(--navy);
  font-family: "Noto Serif Georgian", serif;
  font-size: 15px;
  text-align: center;
  transition: border-color 0.25s ease, background-color 0.25s ease,
    box-shadow 0.25s ease;
}

.attend-card input:checked + .attend-card__box {
  border-color: var(--gold);
  background-color: rgba(201, 168, 76, 0.16);
  box-shadow: 0 4px 14px rgba(201, 168, 76, 0.2);
}

.attend-card input:focus-visible + .attend-card__box {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(201, 168, 76, 0.22);
}

.rsvp__submit {
  width: 100%;
  margin-top: 6px;
  padding: 15px;
  border: none;
  border-radius: 12px;
  background-color: var(--navy);
  color: var(--paper);
  font-family: "Noto Serif Georgian", serif;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.25s ease, transform 0.15s ease;
}

.rsvp__submit:hover {
  background-color: #2a3d63;
}

.rsvp__submit:active {
  transform: translateY(1px);
}

.rsvp__submit:disabled {
  opacity: 0.55;
  cursor: default;
}

.rsvp__status {
  min-height: 20px;
  margin-top: 14px;
  font-family: "Noto Serif Georgian", serif;
  font-size: 14px;
  line-height: 1.5;
  text-align: center;
  color: var(--gold-deep);
}

/* Hidden when the guest-count field doesn't apply (e.g. "not attending") */
.field--hidden {
  display: none;
}

/* ---------- Footer ---------- */

.footer {
  position: relative;
  z-index: 1;
  padding: 10px 24px 36px;
  text-align: center;
}

.credit {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--navy);
  font-family: "Noto Serif Georgian", serif;
  font-size: 12px;
  text-decoration: none;
  opacity: 0.3;
  transition: opacity 0.3s ease;
}

.credit:hover,
.credit:focus-visible {
  opacity: 0.75;
}

.credit__logo {
  width: 16px;
  height: auto;
}

/* ---------- Viewport pin + loading screen ---------- */

/* --vh is written by the inline script in <head> off visualViewport and re-pinned
   by script.js for the first 6s only, so an in-app browser's sliding nav bar
   cannot resize the scene (vh, svh, lvh and dvh all move with it). The
   100vh/100svh floors on .scene stay as the no-JS fallback and MUST come before
   the .vh-lock rule that overrides them. */
:root {
  --vh: 1vh;
}

.vh-lock .scene {
  min-height: calc(var(--vh) * 100);
}

/* The watch must not swing open unseen behind the spinner: is-loading is set
   before first paint and removed on reveal, so every loop starts from frame
   zero exactly when the guest can first see it. */
.is-loading body *:not(.loader):not(.loader__spinner) {
  animation-play-state: paused !important;
}

.loader {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--paper);
  opacity: 1;
  transition: opacity 0.55s ease;
}

.loader.is-hidden {
  opacity: 0;
}

.loader.is-gone {
  display: none;
}

.loader__spinner {
  display: block;
  width: 40px;
  height: 40px;
  border: 2px solid rgba(201, 168, 76, 0.25);
  border-top-color: var(--navy);
  border-radius: 50%;
  animation: loader-spin 0.9s linear infinite;
}

@keyframes loader-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ---------- Desktop notice ---------- */

/* Mobile-only experience. Hidden on phones/tablets; the 769px query below
   reveals it and hides the scene, so wide screens never see the layout. */
.mobile-prompt {
  display: none;
}

/* ---------- Breakpoints ---------- */

/* Tablet - largest supported width. Just scales the watch and accents up. */
@media (min-width: 481px) {
  :root { --size: 350px; }
  .scene { padding: 40px 0 calc(var(--size) + 56px); }
  .bg-corner { width: 150px; }
  .bg-side { width: 120px; }
}

/* Past the tablet breakpoint = desktop: swap the whole site for the notice.
   Hiding every direct child except the notice keeps future sections covered
   without having to list each one here. */
@media (min-width: 769px) {
  body > *:not(.mobile-prompt) {
    display: none;
  }

  .mobile-prompt {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 10;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    padding: 40px;
    text-align: center;
    background-color: var(--paper);
  }

  .mobile-prompt__icon {
    width: 52px;
    height: 52px;
    opacity: 0.8;
  }

  .mobile-prompt__text {
    color: var(--navy);
    font-family: "Noto Serif Georgian", serif;
    font-size: 18px;
    font-weight: 400;
    line-height: 1.6;
    max-width: 360px;
  }
}
