/* ══ FRONTEND-OWNED (not from solana-preview — sync.sh never touches it) ═══
   Loaded by components/Shell.tsx after the base sheets, on every page.

   RESIDENCE WHILE IT WAITS (2026-10-21): the hero and the story are drawn by
   js/pages/residence.js, which waits for Solana.ready (the live catalog and
   availability, ~1.2s on production). Until then #rhero and #res are empty
   and the 360° section sat right under the nav, then jumped down. Now: a
   quiet placeholder in the hero's place, everything after #res hidden until
   the page is drawn, and the drawn content fades in where it will stay.
   Keyed on :empty, so no script change; a safety reveal after 6s in case the
   script never runs. */
#rhero:empty {
  padding: calc(93px + 24px) var(--frame-x) 0;
}
#rhero:empty::before,
#rhero:empty::after {
  content: ""; display: block; background: var(--ivory);
  animation: fe-pulse 1.6s ease-in-out infinite alternate;
}
/* the name line, then the photographs (.rgal__grid's height) */
#rhero:empty::before { width: min(320px, 60%); height: 44px; margin: 26px 0 calc(47px + clamp(24px, 2.4vw, 32px)); }
#rhero:empty::after { height: clamp(380px, 56vh, 600px); }
@media (max-width: 1080px) { #rhero:empty::after { height: clamp(360px, 60vw, 560px); } }
@media (max-width: 720px) {
  #rhero:empty { padding: 64px 0 0; }
  #rhero:empty::before { margin: 74px var(--frame-x) 36px; }
  #rhero:empty::after { height: 75vw; }   /* the carousel picture, 4:3 */
}

body:has(#res:empty) main > #res ~ *,
body:has(#res:empty) .footer {
  visibility: hidden;
  animation: fe-reveal 0s 6s forwards;
}

/* THE FUNNEL WHILE IT WAITS (2026-10-21): checkout, payment, confirmation,
   account and login are drawn whole by their scripts, so until Solana.ready
   the footer sat right under the nav, then dropped. The footer stays hidden
   while the page's section is empty; checkout and payment (the band layout:
   back link, steps, title, then the form card and the summary) get bars in
   the places those will take — measured from checkout at 1440 and 390. */
:root { --fe-skel: rgba(var(--shadow-rgb), .05); }
body:has(#co:empty, #pay:empty, #done:empty, #acct:empty, #sign:empty) .footer {
  visibility: hidden;
  animation: fe-reveal 0s 6s forwards;
}
#co:empty::before, #pay:empty::before,
#co:empty::after, #pay:empty::after {
  content: ""; display: block;
  animation: fe-pulse 1.6s ease-in-out infinite alternate;
}
/* back link, steps, title, line */
#co:empty::before, #pay:empty::before {
  height: 268px;
  background:
    linear-gradient(var(--fe-skel), var(--fe-skel)) 0 8px / 113px 14px no-repeat,
    linear-gradient(var(--fe-skel), var(--fe-skel)) 0 63px / min(472px, 100%) 14px no-repeat,
    linear-gradient(var(--fe-skel), var(--fe-skel)) 0 129px / min(504px, 100%) 44px no-repeat,
    linear-gradient(var(--fe-skel), var(--fe-skel)) 0 200px / min(300px, 80%) 16px no-repeat;
}
/* the form card, the summary card beside it */
#co:empty::after, #pay:empty::after {
  height: 620px;
  background:
    linear-gradient(var(--fe-skel), var(--fe-skel)) 0 0 / 64% 100% no-repeat,
    linear-gradient(var(--fe-skel), var(--fe-skel)) 100% 0 / 34.5% 100% no-repeat;
}
@media (max-width: 720px) {
  #co:empty::before, #pay:empty::before {
    height: 197px;
    background:
      linear-gradient(var(--fe-skel), var(--fe-skel)) 0 8px / 113px 14px no-repeat,
      linear-gradient(var(--fe-skel), var(--fe-skel)) 0 51px / min(211px, 100%) 14px no-repeat,
      linear-gradient(var(--fe-skel), var(--fe-skel)) 0 95px / min(308px, 100%) 32px no-repeat,
      linear-gradient(var(--fe-skel), var(--fe-skel)) 0 145px / min(240px, 80%) 14px no-repeat;
  }
  /* phones: the summary first, full width */
  #co:empty::after, #pay:empty::after { height: 613px; background: var(--fe-skel); }
}

#rhero > *, #res > *,
#co > *, #pay > *, #done > *, #acct > *, #sign > * { animation: fe-in 280ms var(--ease-out) both; }

/* THE WAY BACK TO A HELD BOOKING (2026-10-21, js/booking.js holdBar): one
   white card under the nav, top right — clear of the booking bars and the
   WhatsApp button at the foot. Phones: full width under the nav. */
.heldbar {
  position: fixed; z-index: 60; top: calc(93px + 16px); right: var(--frame-x, 24px);
  display: flex; align-items: center; gap: 16px; max-width: min(560px, calc(100vw - 32px));
  padding: 14px 14px 14px 20px; background: var(--white); color: var(--ink);
  box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--hairline-color);
  animation: fe-in 280ms var(--ease-out) both;
}
.heldbar p { margin: 0; }
.heldbar b { font-weight: var(--weight-regular); color: var(--green); }
.heldbar__go { flex: none; color: var(--green); text-decoration: underline; text-underline-offset: 5px; text-decoration-color: var(--gold); }
.heldbar__go:hover { color: var(--gold-700); }
.heldbar__x {
  flex: none; width: 32px; height: 32px; border: 0; background: none; color: var(--muted);
  font-size: 22px; line-height: 1; cursor: pointer;
}
.heldbar__x:hover { color: var(--green); }
.heldbar__go:focus-visible, .heldbar__x:focus-visible { outline: 2px solid var(--gold-700); outline-offset: 2px; }
@media (max-width: 720px) {
  .heldbar { top: 84px; left: 0; right: 0; max-width: none; flex-wrap: wrap; gap: 8px 16px; padding: 12px 12px 12px 16px; }
  .heldbar p { flex: 1 1 100%; padding-right: 36px; }
  .heldbar__x { position: absolute; top: 6px; right: 6px; }
}
@media (prefers-reduced-motion: reduce) { .heldbar { animation: none; } }

@keyframes fe-pulse { from { opacity: 1; } to { opacity: .55; } }
@keyframes fe-in { from { opacity: 0; } }
@keyframes fe-reveal { to { visibility: visible; } }

@media (prefers-reduced-motion: reduce) {
  #rhero:empty::before, #rhero:empty::after,
  #co:empty::before, #pay:empty::before, #co:empty::after, #pay:empty::after { animation: none; }
  #rhero > *, #res > *,
  #co > *, #pay > *, #done > *, #acct > *, #sign > * { animation: none; }
}

/* LONG STAY · RATE ON REQUEST (2026-10-28): the client asked to hide the
   prices on /long-stay's residence cards only; the Compare table, the Living
   tiers and the FAQ keep theirs. The long page's #residences is the one whose
   bar is the WhatsApp quote (#book[data-wa-quote]); daily-stay shares the card
   classes and keeps its nightly prices. The figures stay in the markup
   (booking.js still fills them, and a preview sync can't bring them back);
   "Rate on request" shows in their place, in the price's type. Sold-out cards
   keep their "Sold out until …" line. */
#residences:has(#book[data-wa-quote]) .scard__price:not(.scard__price--sold) > *,
#residences:has(#book[data-wa-quote]) .scard__alt {
  display: none;
}
#residences:has(#book[data-wa-quote]) .scard__price:not(.scard__price--sold)::before {
  content: "Rate on request";
  font-family: var(--font-sans);
  font-weight: var(--weight-regular);
  font-size: var(--size-20);
  line-height: var(--lh-price);
}
