/* ==========================================================================
   Jua Boutique Hotel · Jambiani, Zanzibar
   V8 · ONE DAY IN THE SUN

   The ground is ONE continuous painted SKY that runs the whole document, dawn
   to dawn. It is a single ramp resampled at even intervals down the page, so
   its colour is a continuous function of scroll and no section owns a colour.
   Gold is INK, never a ground colour.

   The stylesheet alone renders a COMPLETE, correctly coloured, legible page.
   Motion only ever subtracts from a finished state, and only once
   `html.motion-on` is set by the head script.

   ZERO PAINT: per scroll frame only `transform` and `opacity` may change.
   The sky is repainted wholesale on load / resize / ScrollTrigger refresh and
   never per frame. An animated painted surface is the 1,127ms frame.
   ========================================================================== */

/* ---------- fonts ---------- */
@font-face{
  font-family:'Fraunces';
  src:url('../fonts/fraunces-latin.woff2') format('woff2');
  font-weight:100 900; font-style:normal; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2122,U+2212;
}
@font-face{
  font-family:'Fraunces';
  src:url('../fonts/fraunces-italic-latin.woff2') format('woff2');
  font-weight:100 900; font-style:italic; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2122,U+2212;
}
@font-face{
  font-family:'Jost';
  src:url('../fonts/jost-latin.woff2') format('woff2');
  font-weight:100 900; font-style:normal; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2122,U+2212;
}

/* ==========================================================================
   TOKENS
   ========================================================================== */
:root{
  /* INK. Gold is ink; it never paints a ground. */
  --ink:#22303B;            /* day text */
  --ink-night:#F5EFE4;      /* night text */
  --ink-soft:#3A4654;
  --gold-ink:#8A6329;       /* day accent: hours, prices, rules, labels */
  /* The direction's own contrast table calls gold "labels/large only,
     borderline body". Measured, it is: the Italian fact line landed at 4.48:1
     against the served pixels at 768, a 0.4% shortfall on the 4.5 floor. This
     is the same gold four percent darker, used ONLY where gold carries a run
     of body-sized text, and it measures 5.1:1 on the same ground. */
  --gold-ink-body:#7F5B25;
  --ember:#E8B87A;          /* night accent */
  --panel:#FFF7EB;          /* opaque panel ground, light */
  --panel-night:#1A2138;    /* opaque panel ground, dark */
  /* #B98A44 is BANNED as a ground. It survives only as the dial disc's own
     mark colour and the logo SVGs' internal gradient strokes. */
  --gold:#B98A44;

  --dawn:#FFEBD2;           /* pre-paint page background = first light */
  --dawn-hi:#FFF3E0;        /* the mobile drawer's opaque ground */

  /* THE DAY - one continuous ramp for the whole document, authored as anchors
     pinned to real section geometry and via colours placed by perceptual arc
     length, interpolated in OkLab through an authored rose so the warm to
     violet crossing can never go brown, then resampled at even intervals down
     the page. Gold is not in this list. Gold is ink.

     JS rewrites this from the real section offsets on load, resize and every
     ScrollTrigger refresh. This default keeps the page correctly coloured with
     JS switched off. */
  --sky-ramp:
    #FFEBD2 0.0%,#FFE9CE 1.0%,#FFE8CA 2.0%,#FFE6C5 3.0%,#FFE4C1 4.0%,#FFE3BE 5.0%,
    #FFE2BC 6.0%,#FFE2BC 7.0%,#FFE3BE 8.0%,#FFE5C2 9.0%,#FEE7C6 10.0%,#FEE9CA 11.0%,
    #FEEBCE 12.0%,#FEECD1 13.0%,#FEEED4 14.0%,#FEF0D8 15.0%,#FEF2DB 16.0%,#FEF3DE 17.0%,
    #FCF3E1 18.0%,#FAF4E5 19.0%,#F7F5E9 20.0%,#F4F5ED 21.0%,#F2F6F0 22.0%,#F1F6F1 23.0%,
    #F4F5E8 24.0%,#F8F3DF 25.0%,#FAF1D7 26.0%,#FBEECF 27.0%,#FBEBC8 28.0%,#FAE7C1 29.0%,
    #F9E3BB 30.0%,#F8E0B4 31.0%,#F8DCAD 32.0%,#F7D8A7 33.0%,#F7D4A2 34.0%,#F6D19E 35.0%,
    #F6CD9A 36.0%,#F5CA97 37.0%,#F5C693 38.0%,#F5C390 39.0%,#F5BF8C 40.0%,#F5BB89 41.0%,
    #F5B785 42.0%,#F4B282 43.0%,#F3AD7E 44.0%,#F1A87A 45.0%,#EFA175 46.0%,#EB9974 47.0%,
    #E28E79 48.0%,#D7877D 49.0%,#CB8081 50.0%,#BF7883 51.0%,#B07284 52.0%,#A06B84 53.0%,
    #8F6583 54.0%,#806082 55.0%,#725B7F 56.0%,#67577D 57.0%,#60547A 58.0%,#5B5177 59.0%,
    #575075 60.0%,#534E72 61.0%,#504C70 62.0%,#4C4A6E 63.0%,#48476B 64.0%,#444468 65.0%,
    #404164 66.0%,#3C3E61 67.0%,#383C5E 68.0%,#363A5C 69.0%,#343A5C 70.0%,#333B5D 71.0%,
    #31385A 72.0%,#2E3556 73.0%,#2B3251 74.0%,#282F4D 75.0%,#252D4A 76.0%,#232B47 77.0%,
    #202743 78.0%,#1E2540 79.0%,#282E4C 80.0%,#38365C 81.0%,#4B3E69 82.0%,#5D4774 83.0%,
    #70517A 84.0%,#825C7F 85.0%,#936882 86.0%,#A47485 87.0%,#B48187 88.0%,#C28F8B 89.0%,
    #CF9F90 90.0%,#DAAE95 91.0%,#E5BF9F 92.0%,#EFD0AC 93.0%,#F8E0C0 94.0%,#FFEDD9 95.0%,
    #FFEFDE 96.0%,#FFF1E0 97.0%,#FFF1E2 98.0%,#FFF2E4 99.0%,#FFF3E6 100.0%;

  --display:'Fraunces',Georgia,'Times New Roman',serif;
  --sans:'Jost','Century Gothic','Avenir Next',system-ui,sans-serif;

  --wrap:1200px;
  --pad:clamp(20px,4.4vw,60px);
  --nav-h:74px;
  --dial-lane:0px;

  /* the nav's own tone, swapped once per stage crossing by the day watcher */
  --nav-bg:rgba(255,246,232,.94);
  --nav-ink:#22303B;
  --nav-accent:#8A6329;
  --nav-line:rgba(34,48,59,.12);
}
@media (min-width:1024px){ :root{ --dial-lane:168px; } }

*,*::before,*::after{box-sizing:border-box}

html{
  -webkit-text-size-adjust:100%;
  background:var(--dawn);
  scroll-behavior:smooth;
}
@media (prefers-reduced-motion: reduce){ html{scroll-behavior:auto} }

body{
  margin:0;
  position:relative;
  font-family:var(--sans);
  font-weight:400;
  font-size:17px;
  line-height:1.6;
  color:var(--ink);
  background:transparent;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  /* NEVER `overflow-x:hidden` here: it silently kills position:sticky and has
     already falsified one performance run on this project. `clip` does not
     create a scroll container. */
  overflow-x:clip;
}

picture{display:contents}
img,svg,video{max-width:100%}
img{border-style:none}
h1,h2,h3{margin:0;font-family:var(--display);font-weight:600;font-variation-settings:'opsz' 144;letter-spacing:-.014em;line-height:1.04}
p{margin:0}
ul,ol,dl,dd{margin:0;padding:0}
li{list-style:none}
a{color:inherit}
button{font:inherit;color:inherit}

:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:2px}
.chapter--night :focus-visible,.hero :focus-visible{outline-color:var(--ember)}

.btn,.wa-pill,.burger,.dial-tick,.jua-nav-links a,.chip,.wa-badge,
.drawer-links a,.drawer-tel,.foot-contact a,.lang-switch{touch-action:manipulation}

.vh{
  position:absolute!important;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;
}

.skip-link{
  position:absolute;left:-9999px;top:0;z-index:300;
  background:var(--dawn-hi);color:var(--ink);padding:14px 20px;
  font-family:var(--sans);font-weight:500;
}
.skip-link:focus{left:12px;top:12px}

/* ==========================================================================
   THE SKY - one painted layer for the whole document, dawn to dawn.
   Painted ONCE per load / resize / refresh. Never scrubbed, never
   transitioned, never animated.
   ========================================================================== */
.sky{
  position:absolute; inset:0; z-index:-2; pointer-events:none;
  background:linear-gradient(180deg, var(--sky-ramp));
}
/* sliced-sky guard: if the document ever exceeds the compositor's texture
   limit the single layer is replaced by stacked panels of the same ramp */
.sky-panel{position:absolute;left:0;right:0;pointer-events:none}

/* ==========================================================================
   THE TRAVELLING MARK - the property's own sun crossing the day, and the
   moon it becomes after dark.

   TWO MASKED, FIXED, COMPOSITED LAYERS, not inline SVG. Animating opacity on
   a <g> inside an inline SVG is not a guaranteed compositor operation - the
   group is not its own layer, so a per-frame group-opacity write can force an
   SVG repaint, which is the banned category. Two fixed divs each carrying a
   static mask-image and a static background colour, moved by transform and
   faded by element opacity, are compositor-only by construction.

   All three mask files share ONE viewBox (0 0 124.63 123.28) and register
   pixel-exactly, so both layers render at the identical size with identical
   margins and receive the identical transform string. The composite IS the
   full mark, with the rays and the core independently fadeable. No scale
   factor, no registration calibration.

   Because the layers use mask-image, the files' own fill is used only for its
   ALPHA - the visible colour comes from .mark-ink's background, which is how
   the gold-by-day / ember-by-night swap works. Do not add colour plumbing.

   BANNED on these layers, forever: filter, drop-shadow, animated gradients,
   clip-path, per-frame background writes, any time-based motion. An animated
   painted surface is the 1,127ms frame.
   ========================================================================== */
.mark,.mark-halo{
  position:fixed; left:0; top:0; z-index:-1; pointer-events:none;
  --mark-size:clamp(300px, 58vmin, 700px);
  --mark-x:18vw; --mark-y:52vh; --mark-rot:0deg;
  transform:translate3d(var(--mark-x),var(--mark-y),0) rotate(var(--mark-rot));
  will-change:transform,opacity;
  /* ink and halo colours swap ONCE per stage crossing - a discrete paint,
     never an animated property */
  transition:none;
}
.mark{
  width:var(--mark-size); height:var(--mark-size);
  margin:calc(var(--mark-size)/-2) 0 0 calc(var(--mark-size)/-2);
  opacity:0;
}
.mark-ink{
  display:block;width:100%;height:100%;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
}
.mark--rays .mark-ink{
  background:var(--mark-ink-day,#8A6329);
  -webkit-mask-image:url('../img/jua-rays.svg');
          mask-image:url('../img/jua-rays.svg');
}
/* THE CORE IS THE CLIENT'S OWN SPIRAL BY DAY, THE MOON BY NIGHT.

   jua-core.svg is the bare spiral - exactly the client's mark, an OPEN
   centre. jua-moon.svg is that same path with a 0.55-alpha disc behind it,
   which exists only so the moon is legible at 0.16 on the night sky. Painting
   the disc in DAYLIGHT renders their logo plus a shape that is not in their
   logo, so the day core takes the bare spiral and the disc arrives only after
   dark. Brand fidelity outranks our own reading of the mark.

   The two files are the same path in the same viewBox - jua-core.svg IS
   jua-moon.svg with the <circle> deleted - so the swap cannot move the
   spiral by a pixel.

   The swap rides the SAME stage crossing as the ink swap (--mark-ink-core):
   one discrete attribute write per crossing, at most eight in a whole scroll.
   NEVER transition, animate or cross-fade it - an animated painted surface is
   the 1,127ms frame. Both URLs live in this stylesheet so they resolve the
   same from / and from /it/. */
.mark--core .mark-ink{
  background:var(--mark-ink-core,#8A6329);
  -webkit-mask-image:url('../img/jua-core.svg');
          mask-image:url('../img/jua-core.svg');
}
:root[data-mark-core="moon"] .mark--core .mark-ink{
  -webkit-mask-image:url('../img/jua-moon.svg');
          mask-image:url('../img/jua-moon.svg');
}

/* THE GLOW - painted ONCE, then only ever transformed and faded.
   No filter, no drop-shadow, no animated gradient, ever. */
.mark-halo{border-radius:50%;opacity:0}
.mark-halo--sun{
  width:calc(var(--mark-size)*1.6); height:calc(var(--mark-size)*1.6);
  margin:calc(var(--mark-size)*-0.8) 0 0 calc(var(--mark-size)*-0.8);
  background:radial-gradient(closest-side, rgba(255,217,160,1), rgba(255,217,160,.35) 42%, rgba(255,217,160,0) 72%);
}
.mark-halo--moon{
  width:calc(var(--mark-size)*0.9); height:calc(var(--mark-size)*0.9);
  margin:calc(var(--mark-size)*-0.45) 0 0 calc(var(--mark-size)*-0.45);
  background:radial-gradient(closest-side, rgba(245,239,228,1), rgba(245,239,228,.30) 40%, rgba(245,239,228,0) 70%);
}

/* ==========================================================================
   THE STARS - document-anchored, never viewport-fixed.

   They are authored into the night chapters' own open-sky zones, so they
   scroll with the sky and CANNOT cross a text run by construction: a star
   sprite behind a glyph measures 2.20:1 and no opacity value fixes that, so
   position has to. Side effect: the viewport-fixed moon travels THROUGH the
   anchored field as you scroll, which is what gives the sky depth.

   Each sprite is a soft radial falloff painted once - a glow point, not a
   dot. The large class carries a faint four-point cross glint drawn into the
   same painted background.
   ========================================================================== */
.stars-field{position:absolute;inset:0;z-index:-1;pointer-events:none;overflow:hidden}
/* the tomorrow field is capped to the deep-night span so no star survives
   into the pre-dawn return */
.stars-field--cap{inset:0 0 auto 0;height:22%}
.star{position:absolute;border-radius:50%;
  background:radial-gradient(closest-side, rgba(255,246,232,.95), rgba(255,246,232,.35) 30%, rgba(255,246,232,0) 70%)}
.star--l{width:22px;height:22px;opacity:.55;
  background:
    radial-gradient(closest-side, rgba(255,246,232,.95), rgba(255,246,232,.35) 30%, rgba(255,246,232,0) 70%),
    linear-gradient(rgba(255,246,232,.45),rgba(255,246,232,.45)) center/1.5px 100% no-repeat,
    linear-gradient(rgba(255,246,232,.45),rgba(255,246,232,.45)) center/100% 1.5px no-repeat}
.star--m{width:14px;height:14px;opacity:.45}
.star--s{width:9px;height:9px;opacity:.35}

/* TWINKLE - the one bounded exception to the no-idle rule, because
   scintillation is the depicted object's own physics rather than a drifting
   element. Position-static, opacity-only, six sprites per page: the L stars
   never twinkle (bright stars scintillate least, and the steady ones anchor
   the field). Killed entirely under reduced motion. */
@keyframes star-tw{0%,100%{opacity:var(--s-op)}50%{opacity:calc(var(--s-op) - .22)}}
.star.tw{animation:star-tw var(--s-per,5.4s) ease-in-out infinite;animation-delay:var(--s-del,0s)}
.star--s.tw{--s-op:.35;--s-per:4.6s}
.star--m.tw{--s-op:.45;--s-per:6.2s}
@media (prefers-reduced-motion:reduce){.star{animation:none!important}}
/* the outer gutters these sit in do not exist below 900px */
@media (max-width:900px){.st-gutter{display:none}}

/* ==========================================================================
   THE CONTENT COLUMN
   ========================================================================== */
.wrap{
  width:100%;
  max-width:calc(var(--wrap) + var(--dial-lane));
  margin-inline:auto;
  padding-left:var(--pad);
  padding-right:calc(var(--pad) + var(--dial-lane));
}
/* full-bleed blocks and centred runs drop the dial lane: nothing in them can
   reach under the fixed instrument */
.wrap--center{padding-right:var(--pad)}

.chapter{
  position:relative;z-index:1;
  scroll-margin-top:calc(var(--nav-h) + 14px);
}
/* the open-sky run that opens and closes a chapter. The ramp is visibly
   moving in these gaps, which is what makes the day read as one continuous
   sky rather than a stack of coloured bands. */
.pad-block{padding-block:clamp(56px,9vh,132px) clamp(48px,8vh,110px)}
.pad-top{padding-top:clamp(56px,9vh,132px)}
.pad-bottom{padding-bottom:clamp(48px,8vh,110px)}
.figure{margin:0}

/* ==========================================================================
   TYPE - the clock IS the section-head system
   ========================================================================== */
.skyhead{
  min-height:40vh;
  padding-block:clamp(56px,9vh,132px) clamp(24px,4vh,56px);
  display:flex;flex-direction:column;justify-content:center;
}
.skyhead--tight{min-height:36vh}
.hh{display:block;margin:0}
.hh-num{
  display:block;
  font-family:var(--display);font-weight:600;
  font-size:clamp(88px,14vw,200px);line-height:.9;letter-spacing:-.035em;
  color:var(--gold-ink);font-variation-settings:'opsz' 144;
}
.hh-place{
  display:block;margin-top:1.1em;
  font-family:var(--sans);font-weight:500;font-size:13px;line-height:1.4;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink);
}
.hh-line{
  margin-top:.7em;max-width:22ch;
  font-family:var(--display);font-style:italic;font-weight:400;
  font-size:clamp(22px,2.6vw,32px);line-height:1.24;color:var(--ink);
}
.chapter--night .hh-num{color:var(--ember)}
.chapter--night .hh-place,.chapter--night .hh-line{color:var(--ink-night)}
/* 19:30 opens on the warm crossing and closes on the violet evening, so its
   head takes DAY ink and its programme list takes NIGHT ink. The rule that
   binds is the measured ratio against the served pixels, not the stage's
   light/dark flag, which exists to swap the nav and the dial. */
/* The 19:30 numeral is the one hour on the page that cannot be gold. Measured
   against the served pixels the gold ink reads 1.95:1 on the rose crossing and
   2.5:1 on apricot; ember is worse still at 1.75:1. Nothing in the authored
   accent pair clears the 3.0 display floor on that ground, so this single
   numeral takes the day ink, which measures above 5:1 there. */
.skyhead--day .hh-num{color:var(--ink)}
.skyhead--day .hh-place,.skyhead--day .hh-line{color:var(--ink)}

.body-copy{
  max-width:62ch;font-size:17px;line-height:1.6;color:var(--ink);
}
.chapter--night .body-copy{color:var(--ink-night)}

.fact-line{
  margin-top:1.5em;
  font-family:var(--sans);font-weight:500;font-size:15px;letter-spacing:.06em;
  color:var(--gold-ink-body);
}

.cap{
  margin-top:14px;
  font-family:var(--sans);font-weight:400;font-size:12px;line-height:1.5;
  letter-spacing:.06em;color:var(--ink-soft);
}
.chapter--night .cap{color:rgba(245,239,228,.72)}

/* ==========================================================================
   BUTTONS
   ========================================================================== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.6em;
  font-family:var(--sans);font-weight:500;font-size:14px;letter-spacing:.08em;
  text-transform:uppercase;text-decoration:none;
  padding:15px 26px;min-height:48px;border-radius:2px;border:1px solid transparent;
  transition:background-color .3s ease,color .3s ease,border-color .3s ease,transform .3s ease;
}
.btn--solid{background:var(--panel);color:var(--ink);border-color:var(--panel)}
.btn--solid:hover{background:#fff;transform:translateY(-2px)}
.btn--ghost{background:transparent;color:#FFF7EB;border-color:rgba(255,247,235,.62)}
.btn--ghost:hover{border-color:#FFF7EB;background:rgba(255,247,235,.12);transform:translateY(-2px)}
.btn--gold{background:var(--gold-ink);color:var(--panel);border-color:var(--gold-ink)}
.btn--gold:hover{background:var(--ink);border-color:var(--ink);transform:translateY(-2px)}
.btn--night{background:var(--ember);color:#22190B;border-color:var(--ember)}
.btn--night:hover{background:#F3D0A2;border-color:#F3D0A2;transform:translateY(-2px)}
@media (prefers-reduced-motion: reduce){ .btn:hover{transform:none} }

/* ==========================================================================
   NAV
   ========================================================================== */
.jua-nav{
  position:fixed;inset:0 0 auto 0;z-index:120;min-height:var(--nav-h);
  display:flex;align-items:center;
  background:var(--nav-bg);
  border-bottom:1px solid var(--nav-line);
  -webkit-backdrop-filter:saturate(1.15) blur(10px);
  backdrop-filter:saturate(1.15) blur(10px);
  transition:background-color .5s ease,border-color .5s ease;
}
.jua-nav-inner{
  width:100%;max-width:calc(var(--wrap) + var(--dial-lane));
  margin-inline:auto;padding-inline:var(--pad);
  display:flex;align-items:center;gap:20px;position:relative;
}
.lockup{display:flex;align-items:center;gap:11px;text-decoration:none;flex:0 0 auto;min-height:44px}
.lockup-sun{width:auto;height:40px;display:block}
.lockup-type{display:flex;flex-direction:column;line-height:1}
.lockup-name{
  font-family:var(--display);font-style:italic;font-weight:600;
  font-size:24px;letter-spacing:-.02em;color:var(--nav-ink);
  font-variation-settings:'opsz' 96;transition:color .5s ease;
}
.lockup-rule{display:flex;align-items:center;gap:5px;margin:3px 0 4px}
.lockup-rule::before,.lockup-rule::after{content:"";height:1px;background:var(--nav-accent);flex:1}
.lockup-caps{
  font-family:var(--sans);font-weight:500;font-size:8.2px;letter-spacing:.30em;
  text-transform:uppercase;color:var(--nav-ink);white-space:nowrap;transition:color .5s ease;
}

.jua-nav-links{margin-left:auto;display:flex;gap:clamp(14px,1.9vw,30px)}
.jua-nav-links a{
  font-family:var(--sans);font-weight:400;font-size:12px;letter-spacing:.2em;
  text-transform:uppercase;text-decoration:none;color:var(--nav-ink);
  padding:14px 0;position:relative;transition:color .5s ease;
}
.jua-nav-links a::after{
  content:"";position:absolute;left:0;right:0;bottom:5px;height:1px;
  background:var(--nav-accent);transform:scaleX(0);transform-origin:left;
  transition:transform .38s cubic-bezier(.22,.61,.36,1);
}
.jua-nav-links a:hover::after,.jua-nav-links a:focus-visible::after{transform:scaleX(1)}

.lang-switch{
  font-family:var(--sans);font-weight:500;font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;text-decoration:none;color:var(--nav-ink);
  border:1px solid var(--nav-line);border-radius:2px;
  min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center;
  padding:0 12px;transition:color .5s ease,border-color .5s ease;
}
.lang-switch:hover{border-color:var(--nav-accent);color:var(--nav-accent)}

.wa-pill{
  display:inline-flex;align-items:center;gap:8px;text-decoration:none;
  background:var(--gold-ink);color:#FFF7EB;
  font-family:var(--sans);font-weight:500;font-size:11.5px;letter-spacing:.14em;
  text-transform:uppercase;padding:11px 16px;border-radius:2px;
  min-height:44px;min-width:44px;justify-content:center;
  transition:background-color .3s ease;
}
.wa-pill:hover{background:var(--ink)}
.wa-glyph{width:16px;height:16px;fill:currentColor;flex:0 0 16px}

.burger{
  display:none;width:46px;height:46px;margin-right:-10px;
  background:none;border:0;padding:0;cursor:pointer;
  flex-direction:column;justify-content:center;align-items:center;gap:6px;
}
.burger span{display:block;width:22px;height:1.5px;background:var(--nav-ink);transition:transform .35s ease,background-color .5s ease}
.burger[aria-expanded="true"] span:first-child{transform:translateY(3.75px) rotate(45deg)}
.burger[aria-expanded="true"] span:last-child{transform:translateY(-3.75px) rotate(-45deg)}

@media (max-width:1023px){
  .jua-nav-links{display:none}
  .burger{display:flex}
  .lang-switch{margin-left:auto}
}
@media (max-width:520px){
  .wa-pill span{display:none}
  .lockup-type{display:none}
}

.drawer{
  position:fixed;inset:var(--nav-h) 0 0 0;z-index:118;background:var(--dawn-hi);
  display:flex;flex-direction:column;justify-content:center;gap:18px;
  padding:28px var(--pad) 52px;overflow-y:auto;overscroll-behavior:contain;
}
.drawer[hidden]{display:none}
.drawer-links{display:flex;flex-direction:column;gap:2px}
.drawer-links a{
  font-family:var(--display);font-size:1.5rem;text-decoration:none;color:var(--ink);
  padding:9px 0;display:flex;align-items:baseline;gap:.7em;min-height:44px;
}
.drawer-links a i{
  font-family:var(--sans);font-style:normal;font-size:11px;letter-spacing:.18em;
  color:var(--gold-ink);flex:0 0 46px;
}
.drawer-cta{align-self:flex-start;margin-top:10px}
.drawer-tel{
  font-family:var(--sans);font-size:12.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-soft);text-decoration:none;padding:10px 0;display:inline-block;min-height:44px;
}

/* ==========================================================================
   THE OPENING CARD - the hotel has not opened yet, said the way this page
   says everything else: as a sunrise.

   THE CARD'S TOP EDGE IS A HORIZON. The property's own sun mark stands half
   risen on it, cut flat by that edge - which is the 18:28 device (a giant
   circle cut by a horizon line) played the other way round, and the one
   ornament on the card. Nothing else is decorated.

   THE CARD IS THE COMPOSER'S PANEL, VERBATIM: the same opaque dawn cream, the
   same gold hairline, the same square corners. It is a piece of this page, not
   a browser notification dropped onto it.

   THE SHADE IS WARM. A neutral grey scrim is a browser overlay; the ink here
   is the hero scrim's own warm dark and it opens up behind the card, so the
   page reads as standing in shade on a bright day.

   AUTHORED HIDDEN, and the hidden state is gated on `html.js`. A dead script
   leaves no overlay at all rather than a page that cannot be used - the same
   contract the drawer keeps.
   ========================================================================== */
.opening{
  position:fixed;inset:0;z-index:200;
  display:flex;align-items:center;justify-content:center;
  padding:clamp(64px,10vh,110px) var(--pad) clamp(28px,5vh,56px);
  /* R5: .50/.76 left the hero's own headline reading straight through, so the
     card never commanded the frame - a tint, not shade. Deepened at the RIM
     rather than flattened everywhere, so the photograph keeps its light where
     the card is lifted off it and the frame closes down at the edges the way
     shade actually falls. */
  background:radial-gradient(124% 92% at 50% 46%,
    rgba(38,25,10,.72) 0%,
    rgba(16,11,5,.93) 100%);
  /* the overlay owns every gesture that reaches it, so the day underneath
     cannot be scrolled out from behind the card. Paired with lenis.stop() in
     the script, which is what actually halts this page's scroll clock. */
  touch-action:none;overscroll-behavior:contain;
}
.opening[hidden]{display:none}

.opening-card{
  position:relative;
  /* R3: 512 forced the two actions to stack, which is the cookie-banner tell.
     The hero right behind this card sets its actions as a ROW - gold then
     ghost - and the card should read the same way. 600 is the width at which
     the longer Italian pair still stands on one line, and it is inside the
     page's own panel scale (the composer's card is 720). */
  width:100%;max-width:600px;
  background:var(--panel);
  border:1px solid rgba(138,99,41,.6);
  border-radius:0;
  padding:clamp(40px,6.4vw,56px) clamp(24px,4.4vw,44px) clamp(28px,4vw,40px);
  text-align:center;color:var(--ink);
  box-shadow:0 26px 74px rgba(24,14,4,.36);
}
.opening-card:focus{outline:none}

/* THE SUN ON THE CARD'S HORIZON. A window exactly half the mark's height,
   sitting on the card's top hairline, with the whole mark drawn inside it and
   aligned to the top: what shows is the upper half, flat-cut by the edge. No
   mask, no clip-path, no filter - one overflow and one image. */
.opening-rise{
  /* R2: 104px read as a squiggle above a 512px card. The mark has to be big
     enough that the flat cut is legible as a HORIZON rather than as a crop. */
  --rise:clamp(126px,17vw,168px);
  position:absolute;left:50%;bottom:100%;
  /* R4: .5175, not .5. Measured off the rendered mark, its ink runs 19-385 of
     400 and its WIDEST row - the disc's own centre line, which is the row a
     horizon has to land on - sits at .5275. Half the box cuts 11px above it
     and the disc reads clipped rather than risen. */
  width:var(--rise);height:calc(var(--rise) * .5175);
  margin-left:calc(var(--rise) / -2);
  overflow:hidden;pointer-events:none;
}
.opening-rise img{display:block;width:var(--rise);height:var(--rise)}

.opening-close{
  position:absolute;top:5px;right:5px;
  width:46px;height:46px;padding:0;
  display:flex;align-items:center;justify-content:center;
  background:none;border:0;cursor:pointer;color:var(--ink-soft);
  transition:color .3s ease;
}
.opening-close:hover{color:var(--gold-ink)}
.opening-close svg{width:13px;height:13px;stroke:currentColor;stroke-width:1.3;fill:none}

/* the page's own italic line, which is the voice every hour on this page
   speaks in. R4: the ceiling went 35 -> 40 because the card is 600 wide and a
   35px line sat in it like a caption rather than like a head. */
.opening-head{
  font-family:var(--display);font-style:italic;font-weight:400;
  font-size:clamp(28px,3.6vw,40px);line-height:1.16;letter-spacing:-.014em;
  color:var(--ink);
}
.opening-body{
  margin:1.05em auto 0;max-width:40ch;
  font-family:var(--sans);font-size:16px;line-height:1.62;color:var(--ink);
}
.opening-acts{
  margin-top:clamp(24px,3.6vh,32px);
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;
  gap:12px 16px;
}
/* .btn--ghost is authored for the hero's dark photograph. On the card's cream
   ground it takes the day ink, exactly the way .chapter--night re-tones type
   for its own ground. Geometry, type and transition are untouched: this is a
   context, not a fourth button. */
.opening .btn--ghost{color:var(--ink);border-color:rgba(34,48,59,.34)}
.opening .btn--ghost:hover{color:var(--ink);border-color:var(--ink);background:rgba(34,48,59,.06)}

/* ONE-SHOT ENTRANCE. It plays once, on the frame the card is revealed, and
   then stops. Nothing here loops, pulses or runs on a timer - the whole page
   holds that rule and the card is not an exception. */
html.js .opening{opacity:0;transition:opacity .32s ease}
html.js .opening-card{opacity:0;transform:translateY(14px)}
html.js .opening.is-in{opacity:1}
html.js .opening.is-in .opening-card{
  opacity:1;transform:none;
  transition:opacity .32s cubic-bezier(.22,.61,.36,1),
             transform .32s cubic-bezier(.22,.61,.36,1);
}
@media (prefers-reduced-motion: reduce){
  html.js .opening,html.js .opening-card{
    opacity:1!important;transform:none!important;transition:none!important;
  }
}

/* Measured: the pair stands on ONE row from 600px up in both languages and
   wraps below it. Where it wraps it goes full width, so it reads as a stack
   like the hero's own pair does on a phone, instead of two centred pills of
   different lengths sitting under each other. */
@media (max-width:599.98px){
  .opening-acts .btn{width:100%}
}
@media (max-width:420px){
  .opening-card{padding-left:20px;padding-right:20px}
}

/* ==========================================================================
   THE JUA DIAL - the instrument. Fixed, in its own reserved lane, never over
   a word. The sun's position IS the scroll position mapped onto the day.

   THE PANEL IS ITS OWN GROUND, fully opaque in both tones, so the contrast of
   the hour and the caption is a constant of two colours and not a function of
   whatever photograph happens to be behind it. No percentage of wash holds a
   floor; only opacity does. Static paint, no animation of any kind.
   ========================================================================== */
.dial{
  position:fixed;z-index:110;
  top:calc(var(--nav-h) + 14px);right:18px;
  width:136px;padding:6px 8px 8px;
  display:none;
  background:#FFF7EB;
  border:1px solid rgba(34,48,59,.16);
  border-radius:3px;
  transition:background-color .5s ease,border-color .5s ease;
}
@media (min-width:1024px){ .dial{display:block} }
.dial[data-tone="dark"]{background:#1A2138;border-color:rgba(232,184,122,.30)}

.dial-face{display:block;width:120px;height:88px;overflow:visible}
.dial-arc{fill:none;stroke:rgba(34,48,59,.30);stroke-width:1.1}
.dial-horizon{stroke:rgba(34,48,59,.38);stroke-width:1.1}
.dial[data-tone="dark"] .dial-arc{stroke:rgba(245,239,228,.34)}
.dial[data-tone="dark"] .dial-horizon{stroke:rgba(232,184,122,.44)}

.dial-disc{fill:var(--gold)}
.dial-ray{stroke:var(--gold);stroke-width:1.5;stroke-linecap:round}
.dial-spiral{fill:none;stroke:var(--gold);stroke-width:2.6;stroke-linecap:round;opacity:.6}
.dial[data-tone="dark"] .dial-disc{fill:var(--ember)}
.dial[data-tone="dark"] .dial-ray{stroke:var(--ember)}
.dial[data-tone="dark"] .dial-spiral{stroke:var(--ember);opacity:1}

/* The whole face takes the pointer once and the script hands it to the nearest
   hour, so two ticks can sit close together on the arc without ever
   overlapping each other's hit area. The buttons themselves stay keyboard
   only: focusable and operable by Enter and Space, never by a pointer, which
   is what makes the eight regions tile cleanly. Reverting to per-button
   pointer events reintroduces the unclickable-first-tick bug (c6299b4). */
.dial-ticks{position:absolute;top:6px;left:8px;width:120px;height:88px;pointer-events:auto;cursor:default}
.dial-ticks.is-aimed{cursor:pointer}
.dial-tick{
  position:absolute;width:24px;height:24px;margin:-12px 0 0 -12px;
  padding:0;border:0;background:none;cursor:pointer;pointer-events:none;
  border-radius:50%;
}
.dial-tick::before{
  content:"";position:absolute;left:50%;top:50%;width:3.4px;height:3.4px;
  margin:-1.7px 0 0 -1.7px;border-radius:50%;
  background:rgba(34,48,59,.42);transition:background-color .3s ease,transform .3s ease;
}
.dial-tick.is-hot::before,
.dial-tick:focus-visible::before{background:var(--gold-ink);transform:scale(1.5)}
.dial-tick[aria-current="true"]::before{background:var(--gold-ink);transform:scale(1.7)}
.dial[data-tone="dark"] .dial-tick::before{background:rgba(245,239,228,.5)}
.dial[data-tone="dark"] .dial-tick.is-hot::before,
.dial[data-tone="dark"] .dial-tick:focus-visible::before,
.dial[data-tone="dark"] .dial-tick[aria-current="true"]::before{background:var(--ember)}
.dial-tick:focus-visible{outline:2px solid var(--gold);outline-offset:0}

.dial-caption{
  margin-top:5px;min-height:30px;
  font-family:var(--sans);font-weight:500;font-size:9.5px;line-height:1.5;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink-soft);
  transition:color .5s ease;
}
.dial-caption b{display:block;font-weight:500;font-size:11.5px;letter-spacing:.14em;color:var(--gold-ink)}
.dial[data-tone="dark"] .dial-caption{color:rgba(245,239,228,.74)}
.dial[data-tone="dark"] .dial-caption b{color:var(--ember)}

/* the mobile answer: the nav's own bottom edge becomes the day line, and the
   sun rides it. Same two jobs, inside a lane that already exists. */
.dayline{
  position:absolute;left:0;right:0;bottom:-1px;height:2px;
  background:rgba(34,48,59,.16);pointer-events:none;
}
/* The sun rides the day line on TRANSFORM, never on `left`: a per-frame write
   to a layout property is both a paint the compositor cannot take and a real
   layout shift, and it was the entire CLS of the mobile page (0.0015) before
   this. The halo is kept in both states so the visual rect never changes size
   when the sun goes under the horizon, which was the rest of it. */
.dayline-sun{
  position:absolute;top:-3px;left:0;width:8px;height:8px;margin-left:-4px;
  border-radius:50%;background:var(--gold);
  box-shadow:0 0 0 3px rgba(185,138,68,.18);
  will-change:transform;
}
.dayline-sun.is-down{background:transparent;border:1.5px solid var(--gold)}
.nav-caption{
  font-family:var(--sans);font-weight:500;font-size:9px;line-height:1.4;
  letter-spacing:.16em;text-transform:uppercase;color:var(--nav-ink);opacity:.78;
  margin-left:auto;text-align:right;white-space:nowrap;transition:color .5s ease;
}
.nav-caption b{display:block;font-weight:500;font-size:10.5px;color:var(--nav-accent);letter-spacing:.12em;opacity:1}
@media (min-width:1024px){ .nav-caption,.dayline{display:none} }
@media (max-width:640px){ .nav-caption{display:none} }

/* ==========================================================================
   S1 · 06:31 · FIRST LIGHT
   Full-bleed video. The only text-on-photograph moment on the page, and it
   sits on a LOCAL anchor scrim clipped to the text block's own region, not a
   full-frame wash: the top-right of the frame keeps its light so the picture
   still reads as a sunrise. Tuned against the served pixels, not the average.
   ========================================================================== */
.hero{
  position:relative;min-height:100svh;display:flex;align-items:flex-end;
  padding:calc(var(--nav-h) + 40px) 0 clamp(76px,11vh,132px);
  overflow:hidden;isolation:isolate;
}
.hero-media{position:absolute;inset:0;z-index:0;overflow:hidden}
.hero-poster,.hero-video{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center 58%;display:block;
}
.hero-video{opacity:0;transition:opacity .6s ease}
.hero-video.is-live{opacity:1}
/* THE SCRIM, in two static paints and NOT a wash over the frame.

   A vertical ramp cannot answer this problem on its own: the copy block's
   height is a function of the viewport, so on a short screen the eyebrow rides
   up into whatever the ramp has already faded to, and that is exactly where a
   previous version measured 1.17:1. So the strong layer is anchored to the
   COPY BLOCK ITSELF and moves with it, and the frame layer underneath is only
   a light foot. The top and right of the picture, which carry the sky, the
   palms and the pool and no text at all, keep their light.
   Every alpha below is a measured value: raised until the worst glyph pixel of
   every hero run cleared its floor against the LIVE video, whose sunrise flare
   is brighter than the poster, at 1920, 1440, 1280x720, 768 and 390. */
.hero-scrim{
  position:absolute;left:0;bottom:0;z-index:1;pointer-events:none;
  width:100%;height:82%;
  background:linear-gradient(to top,
    rgba(20,15,8,.68) 0%,
    rgba(20,15,8,.44) 38%,
    rgba(20,15,8,.14) 66%,
    rgba(20,15,8,0) 88%);
}
.hero-block{position:relative}
.hero-block::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  /* the box is deliberately far larger than the ellipse inside it, so the
     gradient reaches zero on every side BEFORE the box ends. An ellipse that
     is still painting at its own box edge draws a hard seam across the
     photograph, which is the one thing worse than a wash.

     THE SEAM, FIXED (2026-08-02). The previous values broke that rule on the
     LEFT and nowhere else: the ellipse's horizontal radius was 58% of the box
     while its centre sat at 35%, so the paint was still at roughly .73 alpha
     when the box cut it off, and the cut was a dead-straight vertical line.
     It only surfaced above ~1455px because below that the box's own left edge
     falls outside the viewport, which is why review at 1440 never saw it.

     The rule is simply radius_x <= centre_x. Rather than shrink the radius
     into the copy (33% of the old box is 398px against the 699px the eyebrow
     was measured on, which halves the scrim exactly under the weakest glyph
     run), the BOX is extended 55% of the copy block further left and the
     centre moved to 50%. The painted ellipse then keeps its old size and its
     old position ON THE PHOTOGRAPH to within about 2%, and reaches zero
     32-63px inside its own left edge at every width. Nothing is clipped, so
     there is nothing to seam. Measured left-boundary alpha after the change:
     0/255 at 1440, 1920 and 2560. */
  left:calc(-55% - var(--pad) - 3vw);
  right:-70%; top:-55%; bottom:-45%;
  background:radial-gradient(46% 46% at 50% 52%,
    rgba(20,15,8,.90) 0%,
    rgba(20,15,8,.86) 44%,
    rgba(20,15,8,.66) 70%,
    rgba(20,15,8,.26) 88%,
    rgba(20,15,8,0) 100%);
}
.hero-copy{
  position:relative;z-index:2;width:100%;
  max-width:calc(var(--wrap) + var(--dial-lane));
  margin-inline:auto;
  padding-left:var(--pad);padding-right:calc(var(--pad) + var(--dial-lane));
  color:#FFF7EB;
}
.hero-block{max-width:640px}
.hero-eyebrow{
  font-family:var(--sans);font-weight:500;font-size:11.5px;line-height:1.6;
  letter-spacing:.24em;text-transform:uppercase;color:#FFF7EB;
}
.hero-h1{
  margin-top:.24em;
  font-family:var(--display);font-weight:600;
  font-size:clamp(56px,9vw,128px);line-height:1.02;letter-spacing:-.028em;
  color:#FFF7EB;text-wrap:balance;
}
.hero-sub{
  margin-top:1.1em;max-width:46ch;font-size:18px;line-height:1.55;color:#FFF7EB;
}
.hero-cta{display:flex;flex-wrap:wrap;gap:13px;margin-top:1.9em}
.hero-cap{
  margin-top:2em;
  font-family:var(--sans);font-size:11.5px;letter-spacing:.08em;color:rgba(255,247,235,.86);
}

/* TABLET AND PHONE. Two changes, and only below 1024px.
   1. The crop moves off centre. At a portrait aspect the centred frame lands on
      the dark thatch side, so a hotel whose name means SUN opens dark.
   2. The copy anchor stops being an ellipse and becomes a full-bleed vertical
      ramp. The ellipse is sized in PERCENTAGES OF THE COPY BLOCK, so on a narrow
      viewport it stops being a local anchor and tints the whole frame. */
@media (max-width:1023px){
  .hero-poster,.hero-video{ object-position:92% 58%; }
  .hero-block::before{
    left:calc(-1 * var(--pad)); right:auto; width:100vw;
    top:-110px; bottom:-140px;
    background:linear-gradient(to bottom,
      rgba(20,15,8,0) 0,
      rgba(20,15,8,.88) 110px,
      rgba(20,15,8,.88) calc(100% - 120px),
      rgba(20,15,8,0) 100%);
  }
}

/* ==========================================================================
   S2 · 07:00 · THE TERRACE - 5/7 asymmetric split on the sky
   ========================================================================== */
.split{display:grid;gap:clamp(28px,4.2vw,64px);align-items:center}
@media (min-width:900px){
  .split--57{grid-template-columns:5fr 7fr}
  .split--5545{grid-template-columns:55fr 45fr}
}
.split .skyhead{min-height:0;padding-block:0 0}
.split-copy > .body-copy{margin-top:1.6em}

/* A framed object standing ON the sky. Sharp corners, hairline gold inset
   frame, and NEVER cropped through a subject.

   The drift is bought with height, not with scale. A scaled image would trim
   both sides as well, and on the terrace portrait the left side is the spiral
   staircase. Instead the box is authored 4% shorter than the picture and the
   picture is anchored to whichever edge is safe to lose: the terrace loses
   sand at the bottom, the beach loses sky at the top. Full width is kept at
   every moment of the travel, and no vertical edge ever moves. */
.plate{position:relative;display:block;margin:0;overflow:hidden}
.plate img{display:block;width:100%;height:auto}
.plate--drift img{position:absolute;left:0;width:100%;height:auto}
.plate--up img{top:0}
.plate--dn img{bottom:0}
.plate::after{
  content:"";position:absolute;inset:12px;border:1px solid rgba(138,99,41,.72);
  pointer-events:none;
}
.chapter--night .plate::after{border-color:rgba(232,184,122,.55)}

/* ==========================================================================
   S3 · 12:00 · THE POOL - full-bleed chapter, no text on the photograph
   ========================================================================== */
.fullbleed{position:relative;width:100%;margin:0;overflow:hidden}
.fullbleed img{display:block;width:100%;height:100%;object-fit:cover}
@media (min-width:900px){ .fullbleed{height:100svh} }
/* On a phone a 100svh window of a 4:3 frame would throw away two thirds of the
   picture's width and behead the building. Below 900px the frame keeps its own
   aspect so no subject is edge-cut. */
@media (max-width:899px){ .fullbleed{aspect-ratio:4/3;height:auto} }
.fullbleed--top img{object-position:center top}
.fullbleed--pool img{object-position:center 62%}

.ledger{
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;
  gap:.9em 1.1em;
  font-family:var(--sans);font-weight:500;font-size:13px;line-height:1.6;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink);
}
.ledger li{display:flex;align-items:center;gap:1.1em}
.ledger li::after{
  content:"";width:5px;height:5px;border-radius:50%;background:var(--gold-ink);flex:0 0 5px;
}
.ledger li:last-child::after{display:none}
.pool-foot{padding-top:clamp(28px,4.5vh,60px)}
.cap--center{text-align:center;margin-inline:auto;max-width:60ch}
.body-copy--center{margin-inline:auto;text-align:center}

/* ==========================================================================
   S4 · 15:30 · THE BEACH - mirror of the terrace, 55/45, photo LEFT
   ========================================================================== */
.rail{margin-top:1.8em}
.rail li{
  padding:15px 0;border-top:1px solid rgba(34,48,59,.20);
  font-family:var(--sans);font-weight:500;font-size:15px;line-height:1.5;color:var(--ink);
}
.rail li:last-child{border-bottom:1px solid rgba(34,48,59,.20)}

.interlude{
  min-height:30vh;display:flex;align-items:center;justify-content:center;text-align:center;
  padding-block:clamp(28px,5vh,72px);
}
.interlude p{
  font-family:var(--display);font-style:italic;font-weight:400;
  font-size:clamp(22px,2.6vw,32px);line-height:1.3;max-width:26ch;color:var(--ink);
}

/* ==========================================================================
   S4b · 15:30 · THE WIND - the flag line, inside the beach chapter's span.

   THE NINTH GRAMMAR, and the only horizontal LANE on the page: a left copy
   column, then a row of upright plates read left to right at uneven heights.
   The other chapters own the 5/7 split, the mirrored 55/45, centred-copy-then-
   full-bleed, the circle cut by a horizon and the pinned slider; none of them
   is a lane, and a lane is what these photographs are, because the subject of
   all three is literally a row of flags standing in wind.

   THE TWO SMALL PLATES ARE SMALL ON PURPOSE. They are 563px and 462px wide at
   source and are capped below that, so the resolution is never asked to carry
   a frame it cannot. A short flag next to a tall one is composition; a
   stretched one is a failure, and the caps below are what keeps it the first.
   ========================================================================== */
.kite-band{padding-block:clamp(8px,1.6vh,28px) clamp(20px,3.4vh,52px)}
/* minmax(0,…) on EVERY track, and min-width:0 on the items. A grid track is
   `auto` by default, which is max-content, so the swipe rail below 900px
   reported its full 638px of flags as a width requirement and pushed the whole
   DOCUMENT sideways instead of scrolling inside itself. Measured at 390: the
   page went 637px wide. Do not drop these. */
.kite-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(26px,3.6vw,54px)}
.kite-copy,.kite-fig{min-width:0}
@media (min-width:1100px){
  .kite-grid{grid-template-columns:minmax(0,30%) minmax(0,1fr);align-items:center}
}
/* THE HEAD CARRIES NO CLOCK. This hour already exists on the dial as 15:30 and
   the day is an eight-stage instrument, so printing a ninth time here would be
   a fiction. The place label takes the gold the numeral usually carries, which
   keeps it inside the page's own head system while saying plainly that it is
   a marker and not an hour. */
#kite .skyhead{min-height:0;padding-block:0}
#kite .hh-place{
  margin-top:0;font-size:14px;letter-spacing:.2em;color:var(--gold-ink-body);
}
#kite .kite-copy > .body-copy{margin-top:1.4em}

.kite-lane{display:flex;align-items:flex-end;gap:clamp(14px,1.7vw,28px)}
/* the plates may shrink to fit the lane but never grow past their own source,
   and they never wrap: a wrapped flag line is a grid, which is the one thing
   this section must not become */
.kite-lane > .plate{flex:0 1 auto;min-width:0}
.kp--anchor{width:46vw;max-width:330px}
.kp--flags{width:30vw;max-width:205px}
.kp--hut{width:26vw;max-width:178px}
/* THE FEET SHARE ONE GROUND LINE. They used to come off it by 26px and 13px,
   on the reasoning that lifting them stopped the row reading as three cards.
   It did the opposite. Three plates whose bottoms sit 22px apart do not read
   as rhythm, they read as an alignment that missed - and the thing that stops
   a row reading as cards is not a broken baseline, it is three genuinely
   different heights, which these already have: 487, 257 and 336 at 1440.
   All three photographs are taken standing on the same sand, so the sand is
   the line, the eye travels straight along it, and the whole difference is
   spent on the skyline, where it can be seen. */
.kite-lane{align-items:flex-end}
/* the hairline frame comes in on the small plates in proportion */
.kp--flags::after,.kp--hut::after{inset:8px}
.kite-fig .cap{max-width:46ch}

/* THE AFTERNOON GRADE. Three hard midday phone snapshots - saturated blue sky,
   short shadows - landing on a page whose sky at this scroll point is warm
   afternoon gold. Ungraded they punch a cold hole straight through the ramp.
   So a little saturation comes out, and a warm wash - the ramp's OWN colour at
   this point in the day - sits on the top of each frame where the sky is and
   reaches zero before the sand starts, which is what keeps the white sand
   white. Static paint on a static element: never animated, never scrubbed.
   It rides ::before because .plate::after is already the gold frame. */
#kite .plate[data-grade="afternoon"] img{filter:saturate(.86)}
#kite .plate[data-grade="afternoon"]::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,
    rgba(247,203,150,.34) 0%,
    rgba(247,203,150,.22) 26%,
    rgba(247,203,150,.09) 48%,
    rgba(247,203,150,0) 66%);
}

/* wider gaps in the one-column band, where the lane has the whole page to
   stand in and the capped plates would otherwise huddle at the left */
@media (min-width:900px) and (max-width:1099.98px){
  .kite-lane{gap:clamp(26px,4.6vw,64px)}
}

/* PHONE ONLY: the lane becomes a real swipe rail, the same posture the rooms
   take below 1024px. The gust is switched off here in the script, because a
   transform inside a horizontal scroller fights the scroller.

   THE CUT IS AT 700, NOT 900. At 768 the three plates measure 741px against
   700px of column - they MISS by 41px - so the rail engaged with 41px of
   travel: the last plate sat cut off a hair inside the right edge, under the
   floating badge, and nothing about it read as swipeable. A rail that cannot
   be swiped is not a rail, it is a clipped layout.
   Above 700 the plates simply shrink to fit (flex:0 1 auto, and their
   proportions are a ratio of their base sizes, so the flag line keeps its
   own rhythm at every width) and all three stand in view. Below 700 the
   anchor plate would fall under ~278px, which is where the line stops being
   readable and a real swipe starts earning its place. */
@media (max-width:699.98px){
  .kite-lane{
    overflow-x:auto;overflow-y:hidden;
    scroll-snap-type:x mandatory;scroll-padding-inline:var(--pad);
    padding-inline:var(--pad);margin-inline:calc(var(--pad) * -1);
    padding-bottom:10px;-webkit-overflow-scrolling:touch;scrollbar-width:none;
  }
  .kite-lane::-webkit-scrollbar{display:none}
  .kite-lane > .plate{flex:0 0 auto;scroll-snap-align:center;margin-bottom:0}
  .kp--anchor{width:min(64vw,300px)}
  .kp--flags{width:min(44vw,205px)}
  .kp--hut{width:min(38vw,178px)}
}

/* ==========================================================================
   S5 · 18:28 · SUNDOWN AT THE BAR
   The one mask on the page, and it is nameable: a giant circle whose lower
   edge is cut by the horizon line. Below the line the circle does not exist.
   As you scroll the circle translates DOWN past the fixed line, so the sun
   visibly sets, enacted on a real photograph, transform only.
   ========================================================================== */
.sundown{--sun-d:min(72vh,60vw);position:relative}
.sundown-stage{
  position:relative;
  height:calc(var(--sun-d) * .88);
  overflow:hidden;
}
.sun-circle{
  position:absolute;left:50%;top:0;
  width:var(--sun-d);height:var(--sun-d);
  margin-left:calc(var(--sun-d) / -2);
  border-radius:50%;overflow:hidden;
  will-change:transform;
}
.sun-circle img{
  display:block;width:100%;height:100%;object-fit:cover;
  /* NO scale. The round master is square and the arc is its inscribed circle,
     so the curve is tangent to the picture's own four edges and everything the
     photograph frames whole stays whole. Zooming in was measured and rejected:
     every step inward walks the arc across the background thatch canopy and
     its pole at the left, and every step further in reaches the pavilion's own
     eaves. Tangent to the frame is the only crop where the curve crosses
     nothing the picture had not already cut for itself. */
}
.sun-horizon{width:100%;height:1px;background:var(--gold-ink);border:0}
.sundown-foot{padding-top:clamp(24px,4vh,52px);text-align:center}
.sundown-tag{
  font-family:var(--sans);font-weight:500;font-size:13px;letter-spacing:.16em;
  /* the spec sets this label in #22303B "while ground is still apricot", and
     measurement agrees: gold ink on apricot is 2.5:1 and cannot carry a label */
  text-transform:uppercase;color:var(--ink);margin-bottom:1.1em;
}
/* the trailing open-sky run: the ramp's warm-to-violet crossing happens here
   and over the table photograph, where no open-sky text ever sits. */
.skyrun{min-height:16vh}

/* ============= AMENDMENT 1 (2026-07-31) — 18:28 wide-width composition.
   This chapter is the page's one centered-axis chapter (centered circle,
   full-width horizon, centered foot), but its head kept the left-set strip
   grammar, which at wide widths strands a dead apricot field upper-right.
   The head now sits on the sun's own axis. Below 900px nothing changes.
   Scoped to #ch-sundown: the other four .skyhead--tight chapters keep the
   left-set grammar that their split layouts anchor. */
@media (min-width:900px){
  #ch-sundown .skyhead{align-items:center;text-align:center}
  #ch-sundown .hh-line{margin-inline:auto}
}
/* From 1600px the disc must command the frame: the diameter steps up.
   Element scale ONLY - the crop, mask and rim are untouched (the img is the
   inscribed circle of its own square master at every rendered size), and
   buildSundown()'s yPercent:12 descent scales with the element, so jua.js
   changes not at all. The stage height follows via its existing calc. */
@media (min-width:1600px){
  .sundown{--sun-d:min(84vh,56vw)}
}

/* ==========================================================================
   S6 · 19:30 · THE TABLE
   The head sits on the warm crossing and takes DAY ink; the programme sits
   below the photograph on the violet evening and takes NIGHT ink. Both are
   measured against the served pixels, which is the only rule that binds.
   ========================================================================== */
.programme{
  margin-top:clamp(28px,5vh,64px);
  display:grid;gap:0 clamp(28px,4vw,64px);
}
@media (min-width:760px){ .programme{grid-template-columns:1fr 1fr} }
.programme li{
  display:flex;align-items:baseline;gap:.9em;
  padding:15px 0;border-top:1px solid rgba(245,239,228,.22);
  font-family:var(--sans);font-weight:500;font-size:15px;line-height:1.5;
  color:var(--ink-night);
}
.programme li::before{
  content:"";width:5px;height:5px;border-radius:50%;background:var(--ember);flex:0 0 5px;
  transform:translateY(-2px);
}

/* ==========================================================================
   S7 · 22:00 · THE ROOMS - THE SPIRAL ROOM SLIDER, PORTED FROM V7.

   V8's own 22:00 chapter was a static three-plate grid with nothing behind
   it. The operator's ruling (2026-07-31): "starting the room section till the
   end in V7 is much better that V8, leave v8 as is but take the slider and
   following sections from v7." So the whole set piece comes across: a
   scroll-scrubbed GSAP timeline pinned to #roomsPin that crossfades three
   room panels through the SAME two grid cells, a real swipe-snap rail below
   1024px, and a fully stacked no-JS / reduced-motion fallback.

   EVERYTHING IS SCOPED TO #ch-rooms. V7's typographic vocabulary (.hour,
   .dia, .head, .body) is a different component set from V8's
   (.skyhead/.hh/.body-copy/.cap) and must not leak into V8's other seven
   chapters - the operator asked for V8 to be left as it is apart from this
   run.

   --cream DOES NOT EXIST IN V8: V8 renamed that exact colour (#F5EFE4) to
   --ink-night. Rather than alias it globally, it is re-declared inside this
   scope so every ported rule resolves verbatim and nothing outside can read
   it.
   ========================================================================== */
#ch-rooms{--cream:#F5EFE4}

/* --- V7's section-head vocabulary, scoped ---------------------------- */
#ch-rooms .hour{
  font-family:var(--sans);font-weight:500;font-size:12.5px;line-height:1.6;
  letter-spacing:.24em;text-transform:uppercase;color:var(--ember);
  display:flex;align-items:center;flex-wrap:wrap;gap:.1em;
}
#ch-rooms .hour .dia{margin-right:.85em}
#ch-rooms .hour b{font-weight:500;color:var(--ember);letter-spacing:.2em}
#ch-rooms .hour .sep{margin-inline:.6em;opacity:.5}
#ch-rooms .dia{
  display:inline-block;width:8px;height:8px;flex:0 0 8px;
  background:var(--ember);transform:rotate(45deg);
}
#ch-rooms .dia--sep{width:6px;height:6px;flex:0 0 6px;margin-inline:.85em;vertical-align:.06em}
#ch-rooms .head{
  font-family:var(--display);font-weight:600;line-height:1.05;letter-spacing:-.02em;
  font-size:clamp(2.15rem,4.5vw,3.9rem);
  margin-top:.4em;max-width:17ch;color:var(--cream);
}
#ch-rooms .head em{font-style:italic}
#ch-rooms .head--center{max-width:24ch;text-align:center;margin-inline:auto}

/* --- the head block --------------------------------------------------- */
#ch-rooms .rooms-head{text-align:center;padding-top:clamp(50px,8vh,104px)}
#ch-rooms .rooms-head .hour{justify-content:center}
#ch-rooms .rooms-rates{
  margin-top:1.5em;font-family:var(--sans);font-weight:400;font-size:13px;
  letter-spacing:.15em;text-transform:uppercase;color:var(--cream);
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;
}
/* .wrap reserves a 168px right lane for the fixed dial; three sections whose
   content is centred on the FULL page have to drop it or their centred
   heading sits 84px left of true centre. V7 keyed this to the literal id
   #rooms, which is #ch-rooms here. */
@media (min-width:1024px){
  #ch-rooms > .rooms-head{padding-right:var(--pad)}
}

/* ONE AXIS FOR THE WHOLE CHAPTER.
   The rule above drops the dial lane so the head centres on the page, but
   .rooms-stage below is a plain .wrap and keeps the lane, so the two sat on
   axes 84px apart inside one section: measured at 1920 the head's content box
   is 328..1576 (mid 952, the same axis as #ch-sundown and #ch-table) while the
   stage is 328..1408 (mid 868). That is what reads as the room block hanging
   left under a centred heading with a dead field down the right.
   From 1440 up the stage keeps its exact width and grid - the approved layout
   is untouched - and is simply re-centred onto the head's axis by splitting
   the lane evenly across both sides. Measured clearance from the stage's right
   edge to the dial panel: 259px at 1920, 99px at 1600, 19px at 1440.
   Below 1440 that clearance goes negative (the detail column would run under
   the dial), so there the HEAD joins the stage's lane axis instead. Either way
   the two agree. Below 1024 --dial-lane is 0 and both rules are no-ops. */
@media (min-width:1024px) and (max-width:1439.98px){
  #ch-rooms > .rooms-head{padding-right:calc(var(--pad) + var(--dial-lane))}
}
/* .rooms-stage is nested inside .rooms-pin, so it is NOT a child of the
   section - a `>` here silently matches nothing. */
@media (min-width:1440px){
  #ch-rooms .rooms-stage{
    padding-left:calc(var(--pad) + var(--dial-lane) / 2);
    padding-right:calc(var(--pad) + var(--dial-lane) / 2);
  }
}

#ch-rooms .rooms-pin{position:relative}
#ch-rooms .rooms-stage{display:flex;flex-direction:column;gap:24px;padding-top:clamp(26px,4vh,44px);padding-bottom:clamp(30px,5vh,60px)}

#ch-rooms .rooms-anchor{order:1;display:flex;gap:16px;align-items:flex-start}
#ch-rooms .anchor-shot{
  flex:0 0 34%;position:relative;aspect-ratio:5/6;overflow:hidden;
  --rise:.30; --foot:9%;
  border-radius:
    50% 50% var(--foot) var(--foot) /
    calc(var(--rise) * 100%) calc(var(--rise) * 100%) calc(var(--foot) * .6) calc(var(--foot) * .6);
  border:1.5px solid var(--gold);
}
#ch-rooms .anchor-shot img{display:block;width:100%;height:100%;object-fit:cover;object-position:26% 52%}
#ch-rooms .anchor-note{
  display:flex;gap:12px;align-items:flex-start;flex:1;
  font-family:var(--sans);font-size:12.5px;line-height:1.58;color:var(--cream);
}
#ch-rooms .anchor-spiral{width:34px;height:34px;flex:0 0 34px;opacity:.92}

#ch-rooms .rooms-panel{order:2;display:flex;flex-direction:column;gap:18px}
#ch-rooms .instrument{position:relative;display:flex;align-items:center;gap:18px}
#ch-rooms .instrument-svg{width:112px;height:112px;flex:0 0 112px;overflow:visible}
#ch-rooms .spiral-track{fill:none;stroke:rgba(245,239,228,.18);stroke-width:2.2;stroke-linecap:round}
#ch-rooms .spiral-draw{fill:none;stroke:var(--ember);stroke-width:2.8;stroke-linecap:round}
#ch-rooms .spiral-head{fill:var(--ember)}
#ch-rooms .instrument-index{
  font-family:var(--display);font-size:1.5rem;color:rgba(245,239,228,.7);
  font-variation-settings:'opsz' 60;letter-spacing:.02em;
}
#ch-rooms .idx-slash{color:var(--ember);margin-inline:.22em}

#ch-rooms .room-tabs{display:flex;flex-wrap:wrap;gap:8px}
#ch-rooms .room-tab{
  font-family:var(--sans);font-weight:500;font-size:12px;letter-spacing:.18em;
  text-transform:uppercase;color:rgba(245,239,228,.76);cursor:pointer;
  background:transparent;border:1px solid rgba(245,239,228,.26);border-radius:2px;
  padding:12px 16px;min-height:44px;transition:color .3s ease,border-color .3s ease,background-color .3s ease;
}
#ch-rooms .room-tab:hover{border-color:var(--ember);color:var(--cream)}
#ch-rooms .room-tab[aria-selected="true"]{background:var(--ember);border-color:var(--ember);color:#241C11}

#ch-rooms .rooms-media{order:3}
#ch-rooms .rooms-scroller{
  display:flex;gap:16px;overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;scroll-padding-inline:var(--pad);
  padding-inline:var(--pad);margin-inline:calc(var(--pad) * -1);
  padding-bottom:10px;-webkit-overflow-scrolling:touch;scrollbar-width:none;
}
#ch-rooms .rooms-scroller::-webkit-scrollbar{display:none}
#ch-rooms .room{flex:0 0 84vw;max-width:520px;scroll-snap-align:center;display:flex;flex-direction:column;gap:20px;margin:0}
#ch-rooms .room-shot{position:relative;margin:0}
#ch-rooms .room-shot .shot{
  position:relative;z-index:1;aspect-ratio:4/3;overflow:hidden;
  --rise:.30; --foot:11%;
  border-radius:
    50% 50% var(--foot) var(--foot) /
    calc(var(--rise) * 100%) calc(var(--rise) * 100%) calc(var(--foot) * .55) calc(var(--foot) * .55);
  border:1.5px solid var(--gold);
}
#ch-rooms .room-shot img{display:block;width:100%;height:100%;object-fit:cover}

#ch-rooms .room-detail{padding-top:4px}
#ch-rooms .room-name{font-family:var(--display);font-weight:600;font-size:clamp(2rem,3.9vw,2.85rem);line-height:1.05;color:var(--cream);margin:0}
#ch-rooms .room-name em{font-style:italic}
#ch-rooms .room-rate{
  margin-top:.5em;font-family:var(--sans);font-size:12.5px;letter-spacing:.18em;
  text-transform:uppercase;color:rgba(245,239,228,.7);
}
#ch-rooms .room-rate strong{font-weight:500;font-size:19px;color:var(--ember);letter-spacing:.06em}
#ch-rooms .room-facts{margin-top:1.4em;border-top:1px solid rgba(245,239,228,.22)}
#ch-rooms .room-facts > div{
  display:grid;grid-template-columns:38% 1fr;gap:14px;
  padding:11px 0;border-bottom:1px solid rgba(245,239,228,.14);
}
#ch-rooms .room-facts dt{
  font-family:var(--sans);font-weight:500;font-size:10.5px;letter-spacing:.19em;
  text-transform:uppercase;color:rgba(245,239,228,.62);padding-top:2px;
}
#ch-rooms .room-facts dd{font-size:15px;line-height:1.45;color:var(--cream);margin:0}
#ch-rooms .room-note{margin-top:1.25em;font-size:14.5px;line-height:1.6;color:var(--cream);max-width:42ch}
#ch-rooms .room-ask{margin-top:1.6em}
#ch-rooms .room-ask.btn--gold{background:var(--ember);border-color:var(--ember);color:#241C11}
#ch-rooms .room-ask.btn--gold:hover{background:var(--cream);border-color:var(--cream);color:#241C11}

#ch-rooms [data-grade="evening"]{position:relative}
#ch-rooms [data-grade="evening"]::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(180deg,
    rgba(28,36,64,.62) 0%,
    rgba(28,36,64,.44) 34%,
    rgba(28,36,64,.16) 66%,
    rgba(28,36,64,.04) 100%);
}
#ch-rooms [data-grade="evening"] img{filter:saturate(.82) brightness(.94)}
#ch-rooms .rooms-help{order:4;font-size:14px;line-height:1.6;color:var(--cream);max-width:44ch}

/* --- desktop grid + the one-room-at-a-time CSS floor ------------------ */
@media (min-width:1024px){
  #ch-rooms .rooms-stage{
    display:grid;
    grid-template-columns:170px minmax(0,1fr) 38%;
    grid-template-rows:auto auto auto;
    column-gap:clamp(26px,2.8vw,50px);row-gap:20px;
    align-items:start;min-height:calc(100svh - 16px);
    padding-top:calc(var(--nav-h) + 24px);padding-bottom:30px;align-content:center;
  }
  #ch-rooms .rooms-media,#ch-rooms .rooms-scroller,#ch-rooms .room{display:contents}

  /* ONE ROOM AT A TIME, FROM THE STYLESHEET - the floor that guards against a
     dead GSAP driver stacking all three panels. GSAP writes visibility and
     opacity INLINE, which outranks this rule while it is alive; the moment
     markActive() moves .is-active this rule is underneath it again.
     html.reduced is excluded on purpose: that posture stacks all three. */
  html.js:not(.reduced) #ch-rooms .room:not(.is-active) .room-shot,
  html.js:not(.reduced) #ch-rooms .room:not(.is-active) .room-detail{
    visibility:hidden;opacity:0;pointer-events:none;
  }

  #ch-rooms .rooms-anchor{grid-column:1;grid-row:1 / span 3;flex-direction:column;gap:13px;align-self:center}
  #ch-rooms .anchor-shot{flex:none;width:100%;aspect-ratio:3/5}
  #ch-rooms .anchor-note{flex-direction:column;gap:10px;font-size:12px}

  #ch-rooms .room-shot{grid-column:2;grid-row:1 / span 3;align-self:center;width:100%}
  #ch-rooms .room-shot .shot{aspect-ratio:1/1}

  #ch-rooms .rooms-panel{grid-column:3;grid-row:1;align-self:end;gap:20px}
  #ch-rooms .room-detail{grid-column:3;grid-row:2;align-self:start;width:100%}
  #ch-rooms .rooms-help{grid-column:3;grid-row:3;align-self:start;font-size:13px}

  #ch-rooms .instrument-svg{width:132px;height:132px;flex:0 0 132px}
  #ch-rooms .instrument-index{font-size:1.8rem}
}

/* short desktop viewports - the CTA must always be reachable, because a
   ScrollTrigger pin cannot give back scroll it has already consumed */
@media (min-width:1400px){
  #ch-rooms .rooms-stage{grid-template-columns:184px minmax(0,1fr) 37%}
}
@media (min-width:1024px) and (max-height:859px){
  #ch-rooms .rooms-stage{
    grid-template-columns:minmax(0,1fr) 40%;
    min-height:0;
    padding-top:calc(var(--nav-h) + 10px);padding-bottom:14px;row-gap:12px;
  }
  #ch-rooms .rooms-anchor{display:none}
  #ch-rooms .room-shot{grid-column:1}
  #ch-rooms .rooms-panel,#ch-rooms .room-detail,#ch-rooms .rooms-help{grid-column:2}
  #ch-rooms .room-shot .shot{aspect-ratio:4/3}
  #ch-rooms .instrument-svg{width:96px;height:96px;flex:0 0 96px}
  #ch-rooms .room-name{font-size:clamp(1.7rem,2.8vw,2.2rem)}
  #ch-rooms .room-facts{margin-top:1em}
  #ch-rooms .room-facts > div{padding:8px 0}
  #ch-rooms .room-note{margin-top:.9em}
  #ch-rooms .room-ask{margin-top:1.1em}
}
@media (min-width:1024px) and (max-height:719px){
  #ch-rooms .rooms-stage{padding-top:calc(var(--nav-h) + 6px);padding-bottom:8px;row-gap:8px}
  #ch-rooms .rooms-panel{gap:12px}
  #ch-rooms .instrument{gap:14px}
  #ch-rooms .instrument-svg{width:68px;height:68px;flex:0 0 68px}
  #ch-rooms .instrument-index{font-size:1.35rem}
  #ch-rooms .room-tabs{gap:6px}
  #ch-rooms .room-tab{padding:10px 13px;font-size:11px;letter-spacing:.14em}
  #ch-rooms .room-name{font-size:1.5rem}
  #ch-rooms .room-rate{margin-top:.35em;font-size:11.5px}
  #ch-rooms .room-facts{margin-top:.75em}
  #ch-rooms .room-facts > div{padding:5px 0;gap:10px}
  #ch-rooms .room-facts dd{font-size:13.5px;line-height:1.35}
  #ch-rooms .room-note{margin-top:.7em;font-size:13px;line-height:1.5}
  #ch-rooms .room-ask{margin-top:.8em}
  #ch-rooms .room-ask.btn{padding:12px 22px;min-height:44px;font-size:13px}
  #ch-rooms .rooms-help{font-size:11.5px;line-height:1.5}
}

/* tablet and phone */
@media (max-width:1023px){
  #ch-rooms .room-detail{max-width:none}
}
@media (max-width:900px){
  #ch-rooms .rooms-anchor{gap:14px}
  #ch-rooms .anchor-shot{flex:0 0 40%;aspect-ratio:4/5}
}
@media (max-width:560px){
  #ch-rooms .room{flex:0 0 86vw}
}

/* no-JS and reduced motion: all three rooms stacked, full content, no tabs
   (the tabs cannot do anything without a script, so they are not shown) */
html.reduced #ch-rooms .rooms-stage,html:not(.js) #ch-rooms .rooms-stage{display:flex;flex-direction:column;min-height:0;padding-top:clamp(26px,4vh,44px)}
html.reduced #ch-rooms .rooms-media,html:not(.js) #ch-rooms .rooms-media{display:block;width:100%}
html.reduced #ch-rooms .rooms-scroller,html:not(.js) #ch-rooms .rooms-scroller{display:flex;flex-direction:column;overflow:visible;scroll-snap-type:none;gap:54px;padding-inline:0;margin-inline:0}
html.reduced #ch-rooms .room,html:not(.js) #ch-rooms .room{display:flex;flex-direction:column;gap:20px;flex:none;max-width:760px;width:100%}
html.reduced #ch-rooms .room-shot,html:not(.js) #ch-rooms .room-shot{width:100%}
html.reduced #ch-rooms .room-shot .shot,html:not(.js) #ch-rooms .room-shot .shot{aspect-ratio:4/3}
html.reduced #ch-rooms .rooms-anchor,html:not(.js) #ch-rooms .rooms-anchor{flex-direction:row;width:100%}
html.reduced #ch-rooms .anchor-shot,html:not(.js) #ch-rooms .anchor-shot{flex:0 0 34%;aspect-ratio:4/5}
html.reduced #ch-rooms .anchor-note,html:not(.js) #ch-rooms .anchor-note{flex-direction:row}
html.reduced #ch-rooms .rooms-panel,html.reduced #ch-rooms .room-detail,html.reduced #ch-rooms .rooms-help,
html:not(.js) #ch-rooms .rooms-panel,html:not(.js) #ch-rooms .room-detail,html:not(.js) #ch-rooms .rooms-help{width:100%}
html:not(.js) #ch-rooms .room-tabs{display:none}
html.reduced #ch-rooms .spiral-draw{stroke-dasharray:none !important;stroke-dashoffset:0 !important}

/* ==========================================================================
   S8 · 06:29 · TOMORROW - the close, and THE TOMORROW COMPOSER.
   The composer's ground is FULLY OPAQUE, so its contrast is a constant of two
   colours and is independent of the pre-dawn sky crossing behind it.
   ========================================================================== */
.tomorrow-line{
  max-width:30ch;
  font-family:var(--display);font-style:italic;font-weight:400;
  font-size:clamp(22px,2.6vw,32px);line-height:1.3;color:var(--ink-night);
}
.composer{
  margin-top:clamp(32px,5vh,64px);
  max-width:720px;
  background:var(--panel);
  border:1px solid rgba(138,99,41,.6);
  border-radius:0;
  padding:clamp(20px,3.4vw,32px);
  color:var(--ink);
}
.composer-title{
  font-family:var(--display);font-weight:600;font-size:26px;line-height:1.15;color:var(--ink);
}
.chip-row{margin-top:1.5em}
.chip-row-label{
  font-family:var(--sans);font-weight:500;font-size:12px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--gold-ink);
}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:.8em}
.chip{
  font-family:var(--sans);font-weight:500;font-size:14px;letter-spacing:.06em;
  min-height:44px;padding:11px 16px;
  background:transparent;color:var(--ink);
  border:1px solid rgba(34,48,59,.28);border-radius:2px;cursor:pointer;
  transition:background-color .2s ease,border-color .2s ease,color .2s ease;
}
.chip:hover{border-color:var(--gold-ink);color:var(--gold-ink)}
.chip[aria-checked="true"]{background:var(--ink);border-color:var(--ink);color:var(--panel)}
.chip--month{padding:11px 13px;min-width:56px}

.preview{
  margin-top:1.7em;
  background:#FFFFFF;
  border:1px solid rgba(34,48,59,.16);
  border-radius:14px 14px 14px 3px;
  padding:16px 18px;
  font-size:16px;line-height:1.5;color:var(--ink);
}
.preview-label{
  font-family:var(--sans);font-weight:500;font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-soft);margin-bottom:.7em;
}
.composer-send{display:flex;flex-wrap:wrap;align-items:center;gap:14px 18px;margin-top:1.5em}
.composer-tel{
  font-family:var(--sans);font-size:14px;color:var(--ink);text-decoration:none;
  border-bottom:1px solid rgba(138,99,41,.55);padding-bottom:2px;
  min-height:44px;display:inline-flex;align-items:center;
}
.composer-note{margin-top:1em;font-size:13px;line-height:1.5;color:var(--ink-soft)}

.contacts{margin-top:clamp(32px,5vh,60px);display:flex;flex-wrap:wrap;gap:10px 28px}
.contacts a{
  font-family:var(--sans);font-weight:500;font-size:16px;color:var(--ink);
  text-decoration:none;border-bottom:1px solid rgba(138,99,41,.55);padding-bottom:2px;
  min-height:44px;display:inline-flex;align-items:center;
}
.contacts a:hover{border-color:var(--gold-ink);color:var(--gold-ink)}

/* ==========================================================================
   FOOTER - dawn-cream ground, the day has come back round
   ========================================================================== */
.jua-foot{
  position:relative;z-index:1;
  padding:clamp(56px,8vh,104px) 0 clamp(44px,6vh,72px);
}
.foot-inner{display:flex;flex-direction:column;align-items:center;text-align:center;gap:18px}
.foot-lockup{display:block;width:auto;height:clamp(112px,14vw,148px)}
.foot-plain{color:var(--ink-soft)}
.lockup--foot{flex-direction:column;gap:12px}
.lockup--foot .lockup-sun{height:88px}
.lockup--foot .lockup-type{align-items:center;display:flex}
.lockup--foot .lockup-name{font-size:46px;color:var(--ink)}
.lockup--foot .lockup-rule{width:180px}
.lockup--foot .lockup-rule::before,.lockup--foot .lockup-rule::after{background:var(--gold-ink)}
.lockup--foot .lockup-caps{font-size:10.5px;letter-spacing:.34em;color:var(--ink)}
.foot-place{
  font-family:var(--sans);font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-soft);
}
.foot-contact{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:6px 10px;font-size:15px}
.foot-contact a{text-decoration:none;border-bottom:1px solid rgba(138,99,41,.5);padding-bottom:2px;min-height:44px;display:inline-flex;align-items:center}
.foot-contact a:hover{border-color:var(--gold-ink)}
.foot-sep{color:var(--ink-soft)}
.foot-links{
  display:flex;gap:8px 24px;flex-wrap:wrap;justify-content:center;align-items:center;
  font-family:var(--sans);font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);
}
.foot-links a{color:var(--ink);text-decoration:none;border-bottom:1px solid transparent;min-height:44px;display:inline-flex;align-items:center}
.foot-links a:hover{border-bottom-color:var(--gold-ink);color:var(--gold-ink)}
.foot-note,.foot-legal{font-size:12.5px;line-height:1.55;color:var(--ink-soft);max-width:56ch}
.foot-legal{opacity:.8}

/* ==========================================================================
   THE FLOATING WHATSAPP BADGE - the persistent affordance, after the hero
   ========================================================================== */
.wa-badge{
  position:fixed;z-index:115;right:18px;bottom:18px;
  width:56px;height:56px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--panel);color:var(--gold-ink);
  border:1px solid rgba(138,99,41,.45);
  box-shadow:0 6px 22px rgba(34,24,10,.16);
  text-decoration:none;
  transition:opacity .35s ease,transform .35s ease,background-color .3s ease;
}
.wa-badge .wa-glyph{width:26px;height:26px;flex:0 0 26px}
.wa-badge:hover{background:#fff}
html.js .wa-badge{opacity:0;transform:translateY(14px);pointer-events:none}
html.js .wa-badge.is-on{opacity:1;transform:none;pointer-events:auto}
@media (min-width:1024px){ .wa-badge{right:22px;bottom:22px} }

/* ==========================================================================
   MOTION - everything below only ever SUBTRACTS from a finished state, and
   only once html.motion-on is set. Nothing is hidden with clip-path or
   visibility: a clip-path:inset(100%) element is invisible to an observer and
   never lazy-loads its image, which is a deadlock this project has hit twice.
   Reveals are driven off getBoundingClientRect (ScrollTrigger), never
   IntersectionObserver, and a failsafe reveals everything if the driver dies.
   ========================================================================== */
html.motion-on [data-reveal]{opacity:0;transform:translateY(24px)}
html.motion-on .hero-h1,
html.motion-on .hero-eyebrow,
html.motion-on .hero-sub,
html.motion-on .hero-cta,
html.motion-on .hero-cap{opacity:0}
html.motion-failed [data-reveal],
html.motion-failed .hero-h1,
html.motion-failed .hero-eyebrow,
html.motion-failed .hero-sub,
html.motion-failed .hero-cta,
html.motion-failed .hero-cap{opacity:1!important;transform:none!important}

@media (prefers-reduced-motion: reduce){
  html [data-reveal],
  html .hero-h1,html .hero-eyebrow,html .hero-sub,html .hero-cta,html .hero-cap{
    opacity:1!important;transform:none!important;
  }
  .hero-video{display:none}
  /* reduced motion is GENTLER, NOT GONE. The per-frame travel is skipped and
     the script instead parks the mark once per stage crossing (eight discrete
     writes across a whole scroll, the same budget class as the ink swaps).
     This rule is the starting posture before the first crossing lands, and the
     whole posture if the script never runs at all. */
  .mark{--mark-x:18vw;--mark-y:52vh;--mark-rot:0deg;opacity:.14;will-change:auto}
  .mark-halo{opacity:0;will-change:auto}
}
/* a dead motion driver parks identically to the no-JS page */
html.motion-failed .mark{--mark-x:18vw;--mark-y:52vh;--mark-rot:0deg;opacity:.14;will-change:auto}
html.motion-failed .mark-halo{opacity:0;will-change:auto}
/* with no script at all the complete mark simply sits where the morning sun
   sits, as a still watermark. The star fields are pure CSS and still render.
   Nothing on this page ever needs this element to be readable. */
html:not(.js) .mark{--mark-x:18vw;--mark-y:52vh;--mark-rot:0deg;opacity:.14;will-change:auto}
html:not(.js) .mark-halo{opacity:0;will-change:auto}

@media print{
  .jua-nav,.drawer,.dial,.wa-badge,.hero-video,.sky,
  .mark,.mark-halo,.stars-field{display:none!important}
  body{color:#000;background:#fff}
}
