/* ============================================================
   Quartz Executive — main stylesheet
   Direction B "الكريم الراقي" · light editorial
   Built for continuous, cinematic scroll: no section owns a
   background colour, so there are no visible seams between
   them. Tonal shifts come from soft radial washes that drift
   at their own parallax speed.
   ============================================================ */

/* ---------------------------------------------------------- *
 * 1. Reset & base
 * ---------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The decorative washes deliberately bleed past the layout edges.
     `clip` contains them without creating a scroll container, so
     position:sticky keeps working — `hidden` here would break it.
     It must sit on <html>: overflow on <body> alone does not
     propagate once <html> is `visible`. */
  overflow-x: clip;
}

/* Lenis drives scrolling; native smooth would fight it */
html.lenis {
  scroll-behavior: auto;
}
html.lenis body {
  min-height: 100%;
}
.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}
.lenis.lenis-stopped {
  overflow: hidden;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--fg);
  font-family: var(--font-ar);
  font-weight: 300;
  font-size: var(--fs-body);
  line-height: 1.9;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Needed as well as the one on <html>: without it the blurred .wash
     blobs push the document 288px wider than the viewport. It is safe
     now only because the hero hover scales the photo *inside* its
     frame — the earlier hover moved the whole card outward, which this
     clip then trimmed. Keep hover effects inside their frames. */
  overflow-x: clip;
}

img,
svg,
iframe {
  display: block;
  max-width: 100%;
}

/* <picture> is an inline wrapper; make it transparent to layout so
   every `.frame img` / flex / grid rule keeps working unchanged */
picture {
  display: contents;
}

img {
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd {
  margin: 0;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

input,
textarea,
select {
  font: inherit;
  color: inherit;
}

::selection {
  background: var(--blush-lt);
  color: var(--ink);
}

:focus-visible {
  outline: 2px solid var(--blush-ink);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute;
  inset-inline-start: 50%;
  top: -100px;
  transform: translateX(-50%);
  z-index: 999;
  background: var(--ink);
  color: var(--paper);
  padding: 12px 22px;
  border-radius: 999px;
  font-size: var(--fs-small);
  transition: top var(--dur-fast) var(--ease);
}
.skip:focus {
  top: 14px;
}

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------- *
 * 2. Layout primitives
 * ---------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--pad);
}

.sec {
  position: relative;
  padding-block: var(--sec-y);
  /* sections are transparent on purpose — see .wash */
}

.sec--tight {
  padding-block: calc(var(--sec-y) * 0.6);
}

/* Soft tonal washes. These replace hard section backgrounds so
   the eye never meets an edge while scrolling. */
.wash {
  position: absolute;
  z-index: -1;
  pointer-events: none;
  border-radius: 50%;
  filter: blur(80px);
  will-change: transform;
}

/* Kept deliberately faint: these should read as the paper warming
   slightly, never as a visible shape. */
.wash--warm {
  background: radial-gradient(closest-side, var(--paper-2), transparent 70%);
  opacity: 0.75;
}
.wash--deep {
  background: radial-gradient(closest-side, var(--paper-3), transparent 68%);
  opacity: 0.6;
}
.wash--blush {
  background: radial-gradient(
    closest-side,
    rgba(208, 176, 168, 0.3),
    transparent 68%
  );
  opacity: 0.55;
}

/* ---------------------------------------------------------- *
 * 3. Typography
 * ---------------------------------------------------------- */

.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--font-ui);
  /* a step up from --fs-micro: at 11px the chapter label read as a
     footnote rather than the opening line of a section. The tracking
     eases slightly as it grows, so it stays a label and not a heading. */
  font-size: clamp(0.75rem, 0.95vw, 0.9375rem);
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--blush-ink);
}

.eyebrow::before {
  content: '';
  width: 1.75rem;
  height: 1px;
  background: currentColor;
  flex: none;
  transform-origin: inline-start;
  transform: scaleX(0);
  transition: transform var(--dur) var(--ease) var(--dur-fast);
}

.is-in .eyebrow::before,
.eyebrow.is-in::before {
  transform: scaleX(1);
}

.eyebrow--center {
  justify-content: center;
}
.eyebrow--center::after {
  content: '';
  width: 1.75rem;
  height: 1px;
  background: currentColor;
  flex: none;
}

.h1 {
  font-weight: 300;
  font-size: var(--fs-hero);
  line-height: 1.14;
  letter-spacing: var(--track-display);
}

.h2 {
  font-weight: 300;
  font-size: var(--fs-h2);
  line-height: 1.18;
  letter-spacing: var(--track-display);
  margin-top: 1.25rem;
}

/* Arabic letterforms connect, so aggressive negative tracking that
   flatters Latin display type damages legibility here. Ease it off.

   The leading is set from measured ink, not taste. Almarai's hamza and
   madda ride high above the cap line while ق ي ج ن drop well below the
   baseline, so two display lines need more room than the font's own
   box suggests. Across every heading pair on the site the deepest
   descender plus the tallest ascender comes to 1.352em: at the old
   1.26 the hero's "أبها،" and "كما ينبغي أن تكون" overlapped by 5.5px.
   1.42 clears the worst pair with about 4px to spare at hero size.
   Measure again before tightening this. */
[dir='rtl'] .h1,
[dir='rtl'] .h2 {
  letter-spacing: -0.015em;
  line-height: 1.42;
}

.h3 {
  font-weight: 400;
  font-size: var(--fs-h3);
  line-height: 1.4;
  letter-spacing: -0.01em;
}

/* The serif line — carries the "designed" signature of the page */
/* The accent line is the same typeface as the line above it, set in
   the blush. It used to switch to an italic serif for Latin, which
   read as a different voice mid-heading — and its Latin roman file was
   missing from the folder besides, so it fell back to the system's
   own serif. One family, two colours. */
.serif {
  font-family: inherit;
  font-style: normal;
  font-weight: inherit;
  color: var(--blush);
}

.lede {
  margin-top: 1.375rem;
  font-size: var(--fs-lede);
  color: var(--fg-soft);
  line-height: 2.05;
  max-width: 34rem;
}

.sec__head {
  max-width: 40rem;
}

/* ---------------------------------------------------------- *
 * 4. Motion primitives
 * ---------------------------------------------------------- */

/* Nothing hides until the script has proved it can run.
   `.js-anim` is the first statement inside motion.js, so a parse error
   — or a browser that never runs the file — leaves every element at its
   final state instead of an invisible page. */
.js-anim [data-reveal] {
  opacity: 0;
  transition:
    opacity var(--dur-slow) var(--ease),
    transform var(--dur-slow) var(--ease),
    clip-path var(--dur-slow) var(--ease);
  will-change: opacity, transform;
}

.js-anim [data-reveal='up'] {
  transform: translateY(1.375rem);
}
.js-anim [data-reveal='fade'] {
  transform: none;
}
.js-anim [data-reveal='start'] {
  transform: translateX(-1.75rem);
}
.js-anim [data-reveal='end'] {
  transform: translateX(1.75rem);
}
.js-anim [data-reveal='curtain'] {
  opacity: 1;
  clip-path: inset(0 0 100% 0);
}
.js-anim [data-reveal='iris'] {
  opacity: 1;
  clip-path: inset(8% 8% 8% 8%);
  transform: scale(1.02);
}

[dir='rtl'].js-anim [data-reveal='start'] {
  transform: translateX(1.75rem);
}
[dir='rtl'].js-anim [data-reveal='end'] {
  transform: translateX(-1.75rem);
}

/* `clip-path: inset(0 0 0 0)` clips to the border box, and an Arabic
   descender (ع ق ج ي at the end of a line) hangs below it — so every
   revealed heading came out shaved along the bottom. Only the two
   variants that animate a clip keep one; the rest release it. */
.js-anim [data-reveal].is-in {
  opacity: 1;
  transform: none;
}
.js-anim [data-reveal='curtain'].is-in,
.js-anim [data-reveal='iris'].is-in {
  clip-path: inset(-0.25em);
}

/* Word-by-word headline reveal.
   Padding + negative margin keeps Arabic ascenders, diacritics and
   descenders clear of the overflow mask. The bottom pad used to be
   0.08em, which was under half of what a ع or ق needs. */
.split-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-block: 0.2em 0.22em;
  margin-block: -0.2em -0.22em;
}

.js-anim .split-i {
  display: inline-block;
  transform: translateY(105%);
  transition: transform var(--dur-slow) var(--ease);
}

[data-split].is-in .split-i {
  transform: translateY(0);
}

/* Parallax: --py is written by JS each frame */
[data-parallax] {
  transform: translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}

/* Scrub: --p is 0→1 across the element's travel through the
   viewport. Used for slow image drift and depth. */
[data-scrub] {
  --p: 0;
}

/* Image frame with zoom-on-hover + scroll drift */
.frame {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-xl);
  background: var(--paper-3);
}

/* Sticky image column: the photo pins while its copy scrolls past.
   This is the single biggest contributor to the "watching a film"
   feel the client asked for — motion without anything jumping. */
.pin {
  position: sticky;
  top: calc(var(--header-h) + 1rem);
}

@media (max-width: 1024px) {
  .pin {
    position: static;
  }
}

.frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition:
    transform var(--dur-slow) var(--ease),
    filter var(--dur) ease;
}

.frame--drift img {
  /* the image is oversized then slid, so the crop moves with
     the scroll — the "camera pan" effect */
  height: 116%;
  position: absolute;
  inset: 0;
  transform: translateY(calc(var(--p, 0) * -14%));
}

.noanim {
  scroll-behavior: auto;
}

.noanim *,
.noanim *::before,
.noanim *::after {
  animation-duration: 0.001ms !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  transition-delay: 0ms !important;
}

.noanim [data-reveal] {
  opacity: 1 !important;
  transform: none !important;
  clip-path: none !important;
}
.noanim .split-i {
  transform: none !important;
}
.noanim .eyebrow::before {
  transform: scaleX(1) !important;
}
.noanim .frame--drift img {
  transform: none !important;
  height: 100%;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .split-i {
    transform: none !important;
  }
  .frame--drift img {
    transform: none !important;
    height: 100%;
  }
}

/* ---------------------------------------------------------- *
 * 5. Buttons
 * ---------------------------------------------------------- */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  font-family: var(--font-ar);
  font-size: var(--fs-small);
  font-weight: 400;
  letter-spacing: 0.02em;
  padding: 1rem 1.875rem;
  border-radius: var(--r-round);
  border: 1px solid var(--ink);
  color: var(--ink);
  overflow: hidden;
  transition: color var(--dur-fast) var(--ease);
  isolation: isolate;
}

.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: inline-end;
  transition: transform var(--dur) var(--ease);
}

.btn:hover {
  color: var(--paper);
}
.btn:hover::before {
  transform: scaleX(1);
  transform-origin: inline-start;
}

.btn--solid {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.btn--solid::before {
  background: var(--blush-ink);
}
.btn--solid:hover {
  color: #fff;
}

.btn--ghost {
  border-color: var(--line-strong);
}

.btn--invert {
  border-color: var(--blush-lt);
  color: var(--blush-lt);
}
.btn--invert::before {
  background: var(--blush-lt);
}
.btn--invert:hover {
  color: var(--ink);
}

.btn--lg {
  padding: 1.0625rem 2.125rem;
  font-size: 0.875rem;
}

.btn__ico {
  width: 1em;
  height: 1em;
  flex: none;
  transition: transform var(--dur-fast) var(--ease);
}
/* The arrow points the way the text runs, and nudges forward on hover.
   `transform` is one property: the hover rule used to replace the whole
   value, dropping the RTL mirror and flipping the arrow back to
   pointing right the moment the pointer arrived. Both parts travel
   together now. */
[dir='ltr'] .btn__ico {
  transform: translateX(0);
}
[dir='ltr'] .btn:hover .btn__ico {
  transform: translateX(0.25rem);
}
[dir='rtl'] .btn__ico {
  transform: scaleX(-1) translateX(0);
}
[dir='rtl'] .btn:hover .btn__ico {
  transform: scaleX(-1) translateX(0.25rem);
}

/* Text link with an underline that draws in */
.tlink {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-small);
  letter-spacing: 0.03em;
  padding-bottom: 0.3125rem;
  position: relative;
  transition: gap var(--dur-fast) var(--ease);
}
.tlink::after {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--blush);
  transform: scaleX(1);
  transform-origin: inline-end;
  transition: transform var(--dur) var(--ease);
}
.tlink:hover {
  gap: 1rem;
}

/* ---------------------------------------------------------- *
 * 6. Header
 * ---------------------------------------------------------- */

.hdr {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 90;
  /* Three tracks rather than space-between: the logo and the actions
     are different widths, so a flex row left the menu sitting off
     centre. Equal outer tracks put it in the true middle of the bar. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
  /* Beyond --maxw the page's content stops widening, so a header that
     keeps hugging the window edges drifts out of line with everything
     under it. This holds the logo and the actions on the same margin
     the sections use. */
  padding-block: 1.375rem;
  padding-inline: max(var(--pad), calc((100vw - var(--maxw)) / 2 + var(--pad)));
  transition:
    padding var(--dur) var(--ease),
    background var(--dur) ease,
    box-shadow var(--dur) ease;
}

.hdr::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(250, 247, 244, 0.86);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  border-bottom: 1px solid var(--line);
  opacity: 0;
  transition: opacity var(--dur) ease;
}

.hdr.is-stuck {
  padding-block: 0.75rem;
}
.hdr.is-stuck::before {
  opacity: 1;
}

/* hides on scroll-down, returns on scroll-up */
.hdr.is-away {
  transform: translateY(-105%);
  transition:
    transform var(--dur) var(--ease),
    padding var(--dur) var(--ease);
}

.hdr__logo {
  flex: none;
  display: block;
}
.hdr__logo img {
  height: 4.25rem;
  width: auto;
  transition: height var(--dur) var(--ease);
}
.hdr.is-stuck .hdr__logo img {
  height: 3.25rem;
}

.nav {
  display: flex;
  justify-content: center;
  gap: clamp(1rem, 1.9vw, 1.875rem);
}

.nav a {
  position: relative;
  font-size: 0.9375rem;
  white-space: nowrap;
  color: var(--ink-2);
  padding-block: 0.3125rem;
  transition: color var(--dur-fast) ease;
}

.nav a::after {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--blush);
  transform: scaleX(0);
  transform-origin: inline-end;
  transition: transform var(--dur-fast) var(--ease);
}

.nav a:hover,
.nav a[aria-current='true'] {
  color: var(--ink);
}
.nav a:hover::after,
.nav a[aria-current='true']::after {
  transform: scaleX(1);
  transform-origin: inline-start;
}

.hdr__side {
  display: flex;
  min-width: 0;
  align-items: center;
  /* end, not start: the actions belong on the outer margin opposite
     the logo. Hugging the menu left a hole at the far edge. */
  justify-content: flex-end;
  gap: 0.875rem;
}

/* The action never breaks across two lines: squeezed into the header's
   side track it was wrapping into a two-line pill. */
.hdr__side .btn {
  flex: none;
  white-space: nowrap;
}


.lang {
  display: flex;
  align-items: center;
  gap: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r-round);
  padding: 3px;
  font-family: var(--font-ui);
  font-size: 0.75rem;
}
.lang > * {
  padding: 0.25rem 0.6875rem;
  border-radius: 999px;
  line-height: 1.6;
}
.lang__on {
  background: var(--ink);
  color: var(--paper);
}
.lang__off {
  color: var(--fg-soft);
  transition: color var(--dur-fast) ease;
}
.lang__off:hover {
  color: var(--ink);
}

/* burger */
.burger {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 999px;
}
.burger i {
  display: block;
  width: 1.125rem;
  height: 1px;
  background: var(--ink);
  position: relative;
  transition: background var(--dur-fast) ease;
}
.burger i::before,
.burger i::after {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  width: 100%;
  height: 1px;
  background: var(--ink);
  transition: transform var(--dur-fast) var(--ease);
}
.burger i::before {
  top: -0.3125rem;
}
.burger i::after {
  top: 0.3125rem;
}

.nav-open .burger i {
  background: transparent;
}
.nav-open .burger i::before {
  transform: translateY(0.3125rem) rotate(45deg);
}
.nav-open .burger i::after {
  transform: translateY(-0.3125rem) rotate(-45deg);
}

/* mobile sheet */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: var(--paper);
  display: grid;
  place-items: center;
  /* The header sits above this panel and keeps the close button, so the
     centred list has to start below it or the first item lands under
     that button. Padding, not margin: it shifts the centring too. */
  padding-top: var(--header-h);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--dur-fast) var(--ease),
    visibility var(--dur-fast);
}
.nav-open .sheet {
  opacity: 1;
  visibility: visible;
}
.sheet ul {
  display: grid;
  gap: 0.25rem;
  text-align: center;
}
.sheet a {
  display: block;
  font-size: 1.375rem;
  font-weight: 300;
  padding: 0.5rem 1rem;
  opacity: 0;
  transform: translateY(1rem);
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.nav-open .sheet a {
  opacity: 1;
  transform: none;
}

/* ---------------------------------------------------------- *
 * 7. Chapter one — Arrival, and the chapter rail
 *
 *     There is no hero section. The page opens on its first chapter,
 *     carrying the same label, the same number and the same rhythm as
 *     every chapter after it, so nothing reads as a boundary between
 *     "the hero" and "the site".
 *
 *     `--rail-w` is the width the fixed rail reserves at the inline
 *     start. It is 0 until there is genuine room for it, and every
 *     full-bleed measurement in the stylesheet subtracts it, so the
 *     rail never overlaps and never shifts a centre line.
 * ---------------------------------------------------------- */

:root {
  --rail-w: 0px;
  --rail-gap: 0px;
}

main {
  counter-reset: chapter;
  /* the rail's own width plus a gutter: padded to exactly the rail
     width, the chapter list and the headings ended up touching, which
     on the English page read as one crowded block */
  padding-inline-start: var(--rail-gap, 0px);
}
/* every chapter is a direct child section of main — `.sec` alone would
   have skipped #dining, which carries its own layout class */
main > section {
  counter-increment: chapter;
}

/* The number belongs to the section, not to the copy, so it is drawn
   by a counter rather than written into the content. */
.ch-no {
  /* follows its eyebrow's colour: hard-coding the ink tone left the
     number invisible on the dining section, the page's one dark band */
  color: inherit;
  opacity: 0.62;
  font-variant-numeric: tabular-nums;
  margin-inline-end: 0.125rem;
}
.ch-no::before {
  content: counter(chapter, decimal-leading-zero) ' ·';
}

/* --- the rail --- */
.rail {
  position: fixed;
  /* visibility flips only after the fade finishes, and comes back
     instantly — so the links are never invisible but still focusable */
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    visibility 0s;
  inset-block-start: 50%;
  inset-inline-start: 0;
  z-index: 30;
  width: var(--rail-w);
  transform: translateY(-50%);
  display: none;
  padding-inline-start: clamp(1rem, 2.2vw, 2rem);
}
.rail__l {
  display: grid;
  gap: 0.9375rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.rail a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-ui);
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-soft);
  opacity: 0.5;
  transition:
    opacity var(--dur) var(--ease),
    color var(--dur) var(--ease);
}
.rail__n {
  flex: none;
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}
.rail__t {
  position: relative;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* the marker grows out of the number rather than sitting beside it */
.rail__t::before {
  content: '';
  position: absolute;
  inset-block-end: -0.25rem;
  inset-inline-start: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: inline-start;
  transition: transform var(--dur) var(--ease);
}
.rail a:hover,
.rail a:focus-visible {
  opacity: 0.85;
}
.rail a[aria-current='true'] {
  opacity: 1;
  color: var(--blush-ink);
}
.rail a[aria-current='true'] .rail__t::before {
  transform: scaleX(1);
}

/* --- chapter one --- */
.ch1 {
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding-block: calc(var(--header-h) + clamp(1.5rem, 3.5vh, 2.75rem))
    clamp(3rem, 7vh, 5rem);
}

.ch1__in {
  position: relative;
  z-index: 2;
}

.ch1__title {
  margin-top: 1.125rem;
  max-width: 16ch;
}
.ch1__title .serif {
  display: block;
}

/* Asymmetric on purpose: the copy column is the wider one, so the
   photograph reads as the second voice rather than the subject. */
.ch1__g {
  display: grid;
  grid-template-columns: 1.06fr 0.94fr;
  gap: clamp(1.75rem, 4.5vw, 4rem);
  /* start, not end: bottom-aligning the copy pushed the booking button
     below the fold on a 900px screen. Aligned to the top the actions
     sit well inside the first screen and the photograph is free to run
     past it — which is the point of the chapter, not a flaw. */
  align-items: start;
  margin-top: clamp(1.75rem, 4.5vh, 3.25rem);
}

.ch1__sub {
  font-size: var(--fs-lede);
  color: var(--fg-soft);
  max-width: 44ch;
  line-height: 2;
}

.ch1__cta {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 1.875rem;
}
.ch1__cta .btn svg {
  width: 1.0625rem;
  height: 1.0625rem;
  fill: currentColor;
}

.ch1__facts {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.25rem, 3vw, 2.75rem);
  margin: clamp(2rem, 5vh, 3.25rem) 0 0;
  padding-top: clamp(1.25rem, 3vh, 1.75rem);
  border-top: 1px solid var(--line);
  list-style: none;
}
.ch1__facts li {
  display: grid;
  gap: 0.125rem;
}
.ch1__facts b {
  font-weight: 300;
  font-size: clamp(1.125rem, 1.9vw, 1.5rem);
  letter-spacing: -0.02em;
  unicode-bidi: isolate;
}
.ch1__facts span {
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  color: var(--fg-soft);
}

.ch1__ph {
  margin: 0;
  position: relative;
}
.ch1__ph .frame {
  display: block;
  aspect-ratio: 4 / 5;
}
.ch1__ph img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ch1__cap {
  margin-top: 0.875rem;
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-soft);
}

/* The rail only appears once the page is wide enough to give it a
   column of its own. Below that the numbered headings alone carry the
   chapter structure, and the header nav does the navigating. */
/* over the dark footer the rail would read as blank space, so it
   steps aside a moment before the footer arrives */
.rail.is-retired {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-50%) translateY(-0.75rem);
  pointer-events: none;
  transition-delay: 0s, 0s, var(--dur);
}

@media (min-width: 1180px) {
  :root {
    --rail-w: clamp(8.5rem, 11vw, 12rem);
    --rail-gap: calc(var(--rail-w) + clamp(1.25rem, 2.5vw, 2.75rem));
  }
  .rail {
    display: block;
  }
}

@media (max-width: 820px) {
  .ch1__g {
    grid-template-columns: 1fr;
    align-items: start;
  }
  /* The photograph led here at first, which pushed the booking button
     to 749px — past the fold on a 667px phone. Most visitors arrive on
     a phone, so the copy and the action come first and the photograph
     follows within the same chapter. */
  .ch1__ph .frame {
    aspect-ratio: 4 / 3;
  }
  .ch1__facts {
    margin-top: clamp(1.5rem, 4vh, 2.25rem);
  }
  .ch1__title {
    max-width: 20ch;
  }
}

/* ---------------------------------------------------------- *
 * 8. About — heading one side, copy the other
 *
 *     Deliberately without photography: rooms, dining and nearby all
 *     carry images, so this chapter is left to the type. One hairline
 *     opens it and the two columns hang from that — the asymmetry is
 *     the entire device.
 * ---------------------------------------------------------- */

.about__g {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(1.75rem, 5vw, 4.5rem);
  align-items: start;
  padding-top: clamp(1.25rem, 3vh, 2rem);
  border-top: 1px solid var(--line);
}

.about__head {
  min-width: 0;
}
/* .sec__head's 40rem cap would crop the display line inside a column
   that is already narrower than that */
.about__head .h2 {
  margin-top: 0.875rem;
}

.about__copy {
  min-width: 0;
}

.about__body {
  color: var(--fg-soft);
  max-width: 46ch;
  font-size: var(--fs-body);
  line-height: 1.95;
}
.about__body p + p {
  margin-top: 1.125rem;
}

.about__copy .btn {
  margin-top: clamp(1.75rem, 4vh, 2.5rem);
}

@media (max-width: 860px) {
  .about__g {
    grid-template-columns: 1fr;
    gap: clamp(1.5rem, 4vh, 2.25rem);
  }
}

/* ---------------------------------------------------------- *
 * 9. Why — bordered matrix
 * ---------------------------------------------------------- */

.matrix {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--gap);
  margin-top: 3.75rem;
}

.cell {
  position: relative;
  padding: 2.25rem 1.875rem 2.5rem;
  border-radius: var(--r-xl);
  background: var(--paper-2);
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.cell::before {
  content: '';
  position: absolute;
  inset-inline-start: 1.875rem;
  top: 0;
  width: 2rem;
  height: 2px;
  border-radius: 2px;
  background: var(--blush);
  transform: scaleX(0);
  transform-origin: inline-start;
  transition: transform var(--dur) var(--ease);
}
.cell:hover {
  background: var(--paper-3);
  transform: translateY(-4px);
}
.cell:hover::before {
  transform: scaleY(1);
}

.cell__n {
  font-family: var(--font-ui);
  font-size: 0.8125rem;
  letter-spacing: 0.2em;
  color: var(--blush-ink);
}
.cell .h3 {
  font-size: 1.0625rem;
  margin-top: 1rem;
}
.cell p {
  font-size: 0.875rem;
  color: var(--fg-soft);
  margin-top: 0.5625rem;
  line-height: 1.95;
}

/* ---------------------------------------------------------- *
 * 10. Rooms — rows that fill and reveal a photo
 *     Pointing at a row floods it with plum and slides a photograph in
 *     from the leading edge. Nothing opens on press; where there is no
 *     pointer to hover with, the photograph is simply always there.
 * ---------------------------------------------------------- */

.rooms__hint {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.75rem;
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  color: var(--fg-soft);
}
/* One hint at a time: the pointer line on a mouse, the tap line on
   touch. This has to sit after .rooms__hint, never before it. Both are
   single-class selectors, so source order decides, and while it came
   first the base `display:flex` won and the web showed both lines. */
.rooms__hint--touch {
  display: none;
}

.rooms__hint-dot {
  width: 0.4375rem;
  height: 0.4375rem;
  flex: none;
  border-radius: var(--r-round);
  background: var(--blush-ink);
  animation: hintPulse 3.2s var(--ease-io) infinite;
}

/* This row travels much further than a normal hover — a full colour
   flood plus a photo sliding out of the edge — so it gets its own,
   longer duration rather than borrowing the global slow step. Tune
   the whole gesture from this one value. */
.rooms {
  --rm-dur: 2.2s;

  margin-top: 1.25rem;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  overflow: hidden;
}

.rm {
  position: relative;
  display: flex;
  align-items: stretch;
  width: 100%;
  padding: 0;
  text-align: start;
  background: transparent;
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  /* the fill and the photo reveal are the section's main gesture —
     they run on the slow step so the row unfolds rather than snaps */
  transition:
    background var(--rm-dur) var(--ease),
    color var(--rm-dur) var(--ease);
}
.rm:last-child {
  border-bottom: 0;
}

.rm:focus-visible,
.rm.is-live {
  background: var(--ink);
  color: var(--fg-invert);
}
.rm:focus-visible {
  outline-offset: -3px;
}

/* The photograph slides out of the leading edge, as before.

   It used also to drag the row's height with it: `height: 100%` on an
   image in normal flow has no definite height to resolve against, so a
   portrait source fell back to its own ratio — 320px of picture inside
   a 220px row. Positioned absolutely inside the strip it takes the
   row's height instead, and the row never moves. */
.rm__ph {
  position: relative;
  flex: none;
  width: 0;
  overflow: hidden;
  transition: width var(--rm-dur) var(--ease);
}
.rm:focus-visible .rm__ph,
.rm.is-live .rm__ph {
  width: clamp(8rem, 17vw, 15rem);
}

.rm__ph img {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: clamp(8rem, 17vw, 15rem);
  /* The global `img { max-width: 100% }` capped the picture at the
     strip's own width, so as the strip opened from 0 the picture was
     stretched open with it. Unset here: the picture sits at its full
     width from the start and the strip merely uncovers it. */
  max-width: none;
  height: 100%;
  object-fit: cover;
  display: block;
}

.rm__body {
  flex: 1;
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 0.4375rem;
  padding: clamp(1.75rem, 3.4vw, 2.5rem) clamp(1.25rem, 2.4vw, 2rem);
}

.rm__name {
  font-size: clamp(1.25rem, 2.4vw, 1.875rem);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.015em;
}

.rm__desc {
  font-size: 0.875rem;
  color: var(--fg-soft);
  line-height: 1.95;
  max-width: 46ch;
  transition: color var(--rm-dur) var(--ease);
}
.rm:focus-visible .rm__desc,
.rm.is-live .rm__desc {
  color: var(--fg-invert-soft);
}

.rm__tags {
  display: flex;
  gap: 0.4375rem;
  flex-wrap: wrap;
  margin-top: 0.25rem;
}
.rm__tags span {
  font-size: var(--fs-micro);
  padding: 0.3125rem 0.6875rem;
  border-radius: var(--r-round);
  background: var(--paper-2);
  color: var(--ink-2);
  transition:
    background var(--rm-dur) var(--ease),
    color var(--rm-dur) var(--ease);
}
.rm:focus-visible .rm__tags span,
.rm.is-live .rm__tags span {
  background: rgba(239, 234, 226, 0.14);
  color: var(--fg-invert);
}

/* trailing end: photo count + the number that turns into an arrow */
.rm__end {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.875rem;
  padding-inline: clamp(1rem, 2vw, 1.75rem);
}

.rm__badge {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  min-width: 3rem;
  height: 2rem;
  padding-inline: 0.875rem;
  border-radius: var(--r-round);
  background: var(--ink);
  color: var(--bone);
  font-family: var(--font-ui);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  transition:
    background var(--rm-dur) var(--ease),
    color var(--rm-dur) var(--ease);
}
.rm:focus-visible .rm__badge,
.rm.is-live .rm__badge {
  background: var(--bone);
  color: var(--ink);
}

/* The number used to fade out here so an arrow could take its place.
   The arrow went with the lightbox, so the swap left an empty badge on
   hover — the number simply stays now. */
.rm__n {
  grid-area: 1 / 1;
}

/* Touch, at any width. The strip is held open at a fixed size and the
   photograph fades in inside it.

   Two things rule out copying the desktop exactly. Animating the strip
   from 0 takes 40% of the copy's width on a phone: the description goes
   from three to five lines and the row grows 158px. And sliding the
   picture in with a transform depends on the writing direction, which
   is one more thing to get wrong. A reserved strip and a fade give the
   same result with nothing to resize and nothing to mirror. */
@media (max-width: 760px), (hover: none) {
  /* A reserved column is a column that is empty whenever the row is
     closed, and on a phone that gap is most of what you see. So the
     photograph leaves the flow entirely: it is absolutely positioned
     over the whole row, which means a closed row has no gap to
     explain and an open one shows the room across the full width.
     Nothing changes size in either direction.

     The width declarations here undo the base and focus rules, which
     size a strip that no longer exists at this width. */
  .rm__ph,
  .rm.is-live .rm__ph,
  .rm:focus-visible .rm__ph {
    position: absolute;
    inset: 0;
    width: auto;
    overflow: hidden;
    pointer-events: none;
    transition: none;
  }
  .rm__ph picture {
    display: block;
    height: 100%;
  }
  .rm__ph img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* the global img cap would hold the picture to the strip's old width */
    max-width: none;
    object-fit: cover;
    opacity: 0;
    transition: opacity var(--rm-dur) var(--ease);
  }
  /* The copy sits on the photograph, so it needs a scrim under it.
     Measured against the worst case, a blown-out white area of a
     photograph: at 0.66 the name came to 4.43:1 and the description,
     which is only 70% opaque, to 3.05:1, both under AA. 0.70 with the
     description lifted to 92% gives 5.06:1 and 4.58:1 and keeps the
     room visible. Darkening further buys contrast the photograph pays
     for, so measure before changing either number. */
  .rm__ph::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--ink);
    opacity: 0;
    transition: opacity var(--rm-dur) var(--ease);
  }
  .rm.is-live .rm__ph img,
  .rm:focus-visible .rm__ph img {
    opacity: 1;
  }
  .rm.is-live .rm__ph::after,
  .rm:focus-visible .rm__ph::after {
    opacity: 0.7;
  }
  /* the description is over a photograph here, not over flat plum */
  .rm.is-live .rm__desc,
  .rm:focus-visible .rm__desc {
    color: rgba(239, 234, 226, 0.92);
  }
  /* above the photograph */
  .rm__body,
  .rm__end {
    position: relative;
    z-index: 1;
  }
  .rm__body {
    padding-inline: 1rem;
  }
  /* each hint speaks to the input its device actually has */
  .rooms__hint--pointer {
    display: none;
  }
  .rooms__hint--touch {
    display: flex;
  }
  /* a tap target should say so */
  .rm {
    cursor: pointer;
  }
  /* The row needed two taps on iOS. Safari holds the first tap back
     while it waits to see whether a second one is coming, because a
     double tap means "zoom" on a page that has not opted out, and only
     releases the click when that wait expires. `manipulation` says this
     element has no double-tap gesture, so the click is dispatched at
     once. The other tap targets get it for the same reason. */
  .rm,
  .acc__p,
  .qa__q,
  .btn {
    touch-action: manipulation;
  }
  /* 2.2s is the pointer gesture: a colour flood plus a photograph
     sliding out of the edge, worth watching. On a phone the photograph
     is simply there, over the whole row, and a fade that long reads as
     the tap having missed. Short enough to feel answered, long enough
     to still be a fade. */
  .rooms {
    /* 2.2s was the pointer gesture and read as a missed tap; 0.65s
       answered at once but landed abruptly. --ease is front-loaded
       (0.22, 0.9), so most of the movement still happens in the first
       moments at this length and the rest is a long, soft settle. */
    --rm-dur: 1.15s;
  }
}


/* Pointer devices only. On a touch screen :hover sticks after a tap,
   which lit the row you touched at the same time as the one the
   scroll had made live — two rows shaded at once.

   The width floor matters as much as the hover test: under 761px the
   photograph is positioned over the whole row, and a hover rule that
   gave it a strip width would put the empty column back on a narrow
   desktop window. */
@media (hover: hover) and (min-width: 761px) {
  .rm:hover {
    background: var(--ink);
    color: var(--fg-invert);
  }
  .rm:hover .rm__ph {
    width: clamp(8rem, 17vw, 15rem);
  }
  .rm:hover .rm__desc {
    color: var(--fg-invert-soft);
  }
  .rm:hover .rm__tags span {
    background: rgba(239, 234, 226, 0.14);
    color: var(--fg-invert);
  }
  .rm:hover .rm__badge {
    background: var(--bone);
    color: var(--ink);
  }
}

/* ---------------------------------------------------------- *
 * 11. Amenities — typographic index
 *     No cards and no photography: the service names themselves
 *     are the composition, set large in one flowing line with the
 *     icon scaled in `em` so it grows with the type. Pointing at a
 *     name dims the rest and writes its detail underneath.
 * ---------------------------------------------------------- */

.svc {
  margin-top: clamp(1rem, 2vw, 1.5rem);
}

/* Four columns, two rows. Every cell shows its whole story at once —
   icon, name, what it is, whether it is included — and sits on its own
   soft tile. A hairline between the rows did the same job but read as
   dated; a tinted ground separates rows and columns at once and needs
   no ink at all. */
.svc__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(0.625rem, 1.2vw, 1rem);
  margin: clamp(1.75rem, 4vw, 3rem) 0 0;
  padding: 0;
  list-style: none;
}

.svc__i {
  display: grid;
  /* icon, name, description, state. The description row takes the
     slack so the state always sits on the floor of the tile: with a
     two-line description (the cafe and restaurant) its tag used to
     ride up and that one card read as a different shape from the rest. */
  grid-template-rows: auto auto 1fr auto;
  justify-items: start;
  min-width: 0;
  padding: clamp(1.125rem, 1.8vw, 1.625rem);
  border-radius: var(--r-l);
  background: var(--paper-2);
  transition:
    background var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.svc__i:hover {
  background: var(--paper-3);
  transform: translateY(-3px);
}

/* the chip inverts against the tile it now sits on */
.svc__ico {
  display: grid;
  place-items: center;
  width: 2.875rem;
  height: 2.875rem;
  margin-bottom: 0.875rem;
  border-radius: var(--r-round);
  background: var(--paper);
  color: var(--blush-ink);
  transition:
    background var(--dur) var(--ease),
    color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.svc__i:hover .svc__ico {
  background: var(--ink);
  color: var(--bone);
  transform: rotate(-8deg);
}

.svc__ico svg {
  width: 1.25rem;
  height: 1.25rem;
  stroke: currentColor;
  stroke-width: 1.3;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.svc__t {
  font-size: clamp(1rem, 1.35vw, 1.1875rem);
  font-weight: 300;
  line-height: 1.5;
  letter-spacing: -0.015em;
  color: var(--ink);
}

.svc__d {
  margin-top: 0.375rem;
  font-size: var(--fs-small);
  line-height: 1.8;
  color: var(--fg-soft);
  text-wrap: pretty;
}

.svc__state {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  margin-top: 0.875rem;
  padding: 0.3125rem 0.75rem;
  border-radius: var(--r-round);
  font-family: var(--font-ui);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  /* included: plum on its own faint tint */
  color: var(--plum);
  background: rgba(88, 72, 104, 0.12);
}
/* billed: the same chip in the accent, with the ✦ that the footnote
   under the grid refers to. The text is a step deeper than --blush-ink
   because that tone lands at 3.99:1 on this tint — under AA — while
   this one clears it on the tile and on hover alike. */
.svc__i--paid .svc__state {
  color: #684339;
  background: rgba(127, 84, 75, 0.16);
}
.svc__state-m {
  font-size: 0.6875rem;
  line-height: 1;
}

.pill {
  flex: none;
  font-family: var(--font-ui);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  white-space: nowrap;
  padding: 0.375rem 0.75rem;
  border-radius: var(--r-round);
}
.pill--free {
  background: rgba(88, 72, 104, 0.1);
  color: var(--plum);
}
.pill--paid {
  background: rgba(127, 84, 75, 0.13);
  color: var(--blush-ink);
}

.amen__note {
  margin-top: 1.125rem;
  font-size: var(--fs-small);
  color: var(--fg-soft);
}

/* ---------------------------------------------------------- *
 * 12. Dining — the one dark passage
 *     Masked top & bottom so it dissolves in and out of the
 *     paper instead of butting against it.
 * ---------------------------------------------------------- */

.dining {
  position: relative;
  color: var(--fg-invert);
  padding-block: clamp(5rem, 10vw, 9rem);
  margin: clamp(1.5rem, 4vw, 3.5rem) var(--pad);
  border-radius: var(--r-xl);
  overflow: hidden;
  isolation: isolate;
}

/* The light text here sits on .dining__bg. If that image ever fails to
   load, this keeps it on a dark base instead of cream-on-cream. It is
   masked identically so the seamless dissolve is preserved. */
.dining::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -2;
  background: var(--ink);
}

.dining__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
}

.dining__bg img {
  position: absolute;
  inset: -12% 0;
  width: 100%;
  height: 124%;
  object-fit: cover;
  filter: brightness(0.42) saturate(0.85);
  transform: translateY(calc(var(--p, 0) * -8%));
}

.dining__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(43, 34, 60, 0.55),
    rgba(43, 34, 60, 0.8)
  );
}

.dining__in {
  position: relative;
  max-width: 46rem;
}

.dining .eyebrow {
  color: var(--blush-lt);
}
/* at 0.62 the number sat at 3.9:1 on that background; full strength
   takes it to 7.6:1 */
.dining .ch-no {
  opacity: 1;
}
.dining .lede {
  color: var(--fg-invert-soft);
  max-width: 40rem;
}

.chips {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 2rem;
}
.chips li {
  font-size: var(--fs-small);
  padding: 0.5rem 1rem;
  border: 1px solid var(--line-invert);
  border-radius: var(--r-round);
  color: rgba(250, 247, 244, 0.85);
}

.dining__cta {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 2.25rem;
}
.dining__note {
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.16em;
  color: rgba(250, 247, 244, 0.45);
}

/* ---------------------------------------------------------- *
 * 13. Nearby
 * ---------------------------------------------------------- */

.nearby {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}

.places {
  display: grid;
  gap: 0.5rem;
}
.place {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1.125rem;
  align-items: baseline;
  padding: 1.25rem clamp(1.125rem, 2vw, 1.5rem);
  border-radius: var(--r-l);
  background: var(--paper-2);
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.place:hover {
  background: var(--paper-3);
  transform: translateY(-3px);
}
.place__n {
  font-family: var(--font-ui);
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  color: var(--blush-ink);
}
.place h3 {
  font-size: 1.0625rem;
  font-weight: 400;
}
.place p {
  font-size: 0.8125rem;
  color: var(--fg-soft);
  margin-top: 0.3125rem;
  line-height: 1.85;
}

.nearby__media .frame {
  aspect-ratio: 3 / 4;
  box-shadow: var(--shadow);
}

/* ---------------------------------------------------------- *
 * 14. Gallery — expanding panels
 *     Deliberately about the hotel's shared spaces, not the rooms:
 *     those already have their own photo switcher upstairs. One row,
 *     fixed height — the open panel grows, the rest give way.
 * ---------------------------------------------------------- */

.acc {
  display: flex;
  gap: clamp(0.375rem, 0.7vw, 0.625rem);
  height: clamp(19rem, 46vh, 27rem);
  margin-top: 2.75rem;
}

.acc__p {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  padding: 0;
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--paper-3);
  transition: flex-grow var(--dur) var(--ease);
}

/* the open panel takes roughly half the row */
.acc__p:hover,
.acc__p:focus-visible,
.acc__p[aria-expanded='true'] {
  flex-grow: 4.5;
}

.acc__p img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition:
    transform var(--dur-slow) var(--ease),
    filter var(--dur) var(--ease);
  filter: saturate(0.88) brightness(0.94);
}

.acc__p:hover img,
.acc__p:focus-visible img,
.acc__p[aria-expanded='true'] img {
  filter: none;
}

/* readable scrim only where the caption sits */
.acc__p::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 55%;
  background: linear-gradient(to top, rgba(24, 18, 32, 0.78), transparent);
  pointer-events: none;
}

/* The number and the expand mark sit as bare marks again: a blurred
   pill on every panel read as seven dark boxes stamped across the row.
   A scrim at the top instead — the same device the caption already uses
   at the bottom — carries them at 5.1:1 without adding an object. */
.acc__p::before {
  content: '';
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 38%;
  z-index: 1;
  background: linear-gradient(to bottom, rgba(24, 18, 32, 0.68), transparent);
  pointer-events: none;
}

/* number and mark hold opposite corners of the panel's top edge rather
   than sitting as one clump */
.acc__n {
  position: absolute;
  top: 0.9375rem;
  inset-inline: 1rem;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.16em;
  color: var(--bone);
}
.acc__n-d {
  unicode-bidi: isolate;
}
/* the mark that says a panel opens; the open one has nothing to promise */
.acc__n-i {
  width: 0.6875rem;
  height: 0.6875rem;
  flex: none;
  opacity: 0.72;
  transition:
    opacity var(--dur) var(--ease),
    max-width var(--dur) var(--ease);
}
.acc__p:hover .acc__n-i,
.acc__p:focus-visible .acc__n-i {
  opacity: 1;
}
.acc__p[aria-expanded='true'] .acc__n-i {
  opacity: 0;
  max-width: 0;
}

.acc__cap {
  position: absolute;
  z-index: 2;
  inset-inline: 1.125rem;
  bottom: 1.125rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

/* Collapsed panels are far too narrow for Arabic to set vertically, so
   the label simply fades in with the panel instead of rotating. */
.acc__cap-t {
  font-size: 0.9375rem;
  color: var(--bone);
  white-space: nowrap;
  opacity: 0;
  transform: translateY(0.5rem);
  transition:
    opacity var(--dur-fast) var(--ease) var(--dur-fast),
    transform var(--dur) var(--ease) var(--dur-fast);
}


.acc__p:hover .acc__cap-t,
.acc__p:focus-visible .acc__cap-t,
.acc__p[aria-expanded='true'] .acc__cap-t {
  opacity: 1;
  transform: none;
}
.gv__hint--touch {
  display: none;
}
.gv__hint {
  margin-top: 1.125rem;
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  color: var(--fg-soft);
  text-transform: uppercase;
}

/* ---------------------------------------------------------- *
 * 15. FAQ
 * ---------------------------------------------------------- */

.faq {
  display: grid;
  grid-template-columns: 0.72fr 1.28fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}

.faq__list {
  display: grid;
  gap: 0.625rem;
}

.qa {
  background: var(--paper-2);
  border-radius: var(--r-l);
  padding-inline: clamp(1.125rem, 2vw, 1.75rem);
  transition: background var(--dur-fast) var(--ease);
}
.qa[open] {
  background: var(--paper-3);
}

.qa__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  text-align: start;
  padding: 1.4375rem 0;
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.7;
  color: var(--ink);
  transition: color var(--dur-fast) ease;
}
.qa__q:hover {
  color: var(--blush-ink);
}

.qa__ico {
  position: relative;
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
}
.qa__ico::before,
.qa__ico::after {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  top: 50%;
  width: 100%;
  height: 1px;
  background: var(--blush-ink);
  transition: transform var(--dur-fast) var(--ease);
}
.qa__ico::after {
  transform: rotate(90deg);
}
.qa[open] .qa__ico::after {
  transform: rotate(0deg);
}

.qa__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur) var(--ease);
}
.qa[open] .qa__a {
  grid-template-rows: 1fr;
}
.qa__a > div {
  overflow: hidden;
}
.qa__a p {
  font-size: var(--fs-body);
  color: var(--fg-soft);
  line-height: 2.05;
  padding-bottom: 1.5rem;
  max-width: 46rem;
}

/* ---------------------------------------------------------- *
 * 16. Contact
 * ---------------------------------------------------------- */

.contact {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
  margin-top: 3rem;
}

.field {
  display: grid;
  gap: 0.5rem;
  margin-bottom: 1.125rem;
}
.field label {
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
.field label .req {
  color: var(--blush-ink);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  background: var(--paper-2);
  border: 1px solid transparent;
  border-radius: var(--r-m);
  padding: 0.9375rem 1.125rem;
  font-size: var(--fs-body);
  font-family: var(--font-ar);
  transition: border-color var(--dur-fast) var(--ease),
    background var(--dur-fast) var(--ease);
}
.field textarea {
  min-height: 7rem;
  resize: vertical;
  line-height: 1.9;
}
.field select {
  appearance: none;
  cursor: pointer;
}
.field input::placeholder,
.field textarea::placeholder {
  color: var(--fg-faint);
}

/* Chrome's own stylesheet forces `direction: ltr` on input[type=tel], so
   `text-align: start` resolved to the LEFT edge and the phone field was
   the only one in the Arabic form whose hint sat opposite the rest.
   The direction stays ltr on purpose: it keeps a leading "+" in front of
   the number instead of flipping it to the far end. Only the alignment
   is corrected. */
[dir='rtl'] .field input[type='tel'] {
  text-align: right;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--blush-ink);
  background: var(--bone);
}
.field :is(input, select, textarea)[aria-invalid='true'] {
  border-color: #b3261e;
}
.field__err {
  font-size: var(--fs-micro);
  color: #b3261e;
  min-height: 1em;
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 1.25rem;
}

.form__foot {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}

.form__msg {
  font-size: var(--fs-small);
  padding: 0.75rem 1rem;
  border-radius: var(--r-m);
  display: none;
}
.form__msg[data-state='ok'] {
  display: block;
  background: rgba(88, 72, 104, 0.1);
  color: var(--plum);
}
.form__msg[data-state='err'] {
  display: block;
  background: rgba(179, 38, 30, 0.1);
  color: #8c1d18;
}

/* info side */
.info {
  display: grid;
  gap: 1.5rem;
}
.info__row {
  display: grid;
  gap: 0.3125rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
}
.info__row dt {
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
.info__row dd {
  font-size: 1rem;
  color: var(--ink);
  line-height: 1.85;
}
.info__row a {
  transition: color var(--dur-fast) ease;
}
.info__row a:hover {
  color: var(--blush-ink);
}

/* Each platform's own mark, drawn in the page's own ink rather than in
   brand colour: four coloured app tiles read as a badge strip pasted
   onto the page. Tripadvisor and WhatsApp publish vectors, so those are
   inline SVG. Booking.com and Almosafer do not, so their marks are
   lifted off their own app icons as alpha masks and painted with
   currentColor, which keeps the real letterform and the real suitcase
   while letting them take the ink, the hover and the invert like every
   other icon here. */
.social {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.25rem;
}
.social a {
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-round);
  color: var(--ink-2);
  transition:
    background var(--dur-fast) ease,
    color var(--dur-fast) ease,
    border-color var(--dur-fast) ease,
    transform var(--dur-fast) var(--ease);
}
.social a:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  transform: translateY(-3px);
}
.social svg {
  width: 1.0625rem;
  height: 1.0625rem;
  fill: currentColor;
}
/* A relative url() inside a custom property resolves against the
   stylesheet, not the page that sets it, so an inline --mark written
   next to the markup pointed at /css/logos/. The paths live here
   instead, where ../logos/ is true for both locales. */
.social .ico-mask {
  /* a bare span is inline, and width and height do not apply to one */
  display: block;
  width: 1.125rem;
  height: 1.125rem;
  background: currentColor;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.social .ico-mask--booking {
  -webkit-mask-image: url(../logos/booking.png);
  mask-image: url(../logos/booking.png);
}
.social .ico-mask--almosafer {
  -webkit-mask-image: url(../logos/almosafer.png);
  mask-image: url(../logos/almosafer.png);
}

/* The footer is dark, so the marks take the inverted line and ink
   there. This used to be two inline styles on the anchor; it belongs
   with the rest of the component. */
.foot .social a {
  border-color: var(--line-invert);
  color: var(--fg-invert-soft);
}
.foot .social a:hover {
  background: var(--bone);
  border-color: var(--bone);
  color: var(--ink);
}

.map {
  margin-top: 1.5rem;
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  aspect-ratio: 16 / 11;
  background: var(--paper-3);
}
.map iframe {
  width: 100%;
  height: 100%;
  border: 0;
  filter: grayscale(0.35) contrast(1.02);
}

/* ---------------------------------------------------------- *
 * 17. Footer — fades from paper into plum, no seam
 * ---------------------------------------------------------- */

.foot {
  position: relative;
  color: var(--fg-invert);
  background: var(--ink);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  margin-top: clamp(2.5rem, 6vw, 5rem);
  padding: clamp(4rem, 7vw, 6.5rem) 0 2rem;
}

.foot__top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 2.75rem;
  padding-bottom: 2.75rem;
  border-bottom: 1px solid var(--line-invert);
}

.foot__logo img {
  height: 4rem;
  width: auto;
}
.foot__tag {
  margin-top: 1.125rem;
  font-size: 0.875rem;
  color: var(--fg-invert-soft);
  max-width: 32ch;
  line-height: 2;
}

.foot h4 {
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--blush-lt);
}
.foot li {
  margin-top: 0.75rem;
  font-size: 0.875rem;
  color: var(--fg-invert-soft);
}
.foot li a {
  transition: color var(--dur-fast) ease;
}
.foot li a:hover {
  color: #fff;
}

.foot__bot {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 1.125rem;
  align-items: center;
  padding-top: 1.375rem;
  font-size: var(--fs-small);
  color: var(--fg-invert-soft);
}
.foot__bot > :first-child {
  justify-self: start;
}
.foot__bot > :last-child {
  justify-self: end;
}

.totop {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--blush-lt);
  transition: gap var(--dur-fast) var(--ease);
}
.totop:hover {
  gap: 0.875rem;
}

/* Site credit. Colour-only hover: nothing here changes size. */
.foot__credit {
  /* Flex, not a text line: the link is an inline-flex box, so it sat on
     the text baseline and its icon rode below the middle of the words
     beside it. As flex items the label and the link are centred on each
     other instead. */
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-top: 1.25rem;
  font-size: var(--fs-small);
  color: var(--fg-invert-soft);
}
.foot__credit a {
  display: inline-flex;
  align-items: center;
  gap: 0.4375rem;
  color: var(--fg-invert);
  transition: color var(--dur-fast) var(--ease);
}
.foot__credit a:hover {
  color: var(--blush-lt);
}
.foot__credit svg {
  width: 14px;
  height: 14px;
  flex: none;
  fill: currentColor;
}

/* scroll progress hairline */
.progress {
  position: fixed;
  top: 0;
  inset-inline-start: 0;
  z-index: 100;
  height: 2px;
  width: 100%;
  transform: scaleX(var(--sp, 0));
  transform-origin: inline-start;
  background: linear-gradient(
    to inline-end,
    var(--blush),
    var(--plum)
  );
  pointer-events: none;
}

/* floating WhatsApp */
.wa {
  position: fixed;
  inset-inline-end: clamp(1rem, 2.5vw, 1.75rem);
  bottom: clamp(1rem, 2.5vw, 1.75rem);
  z-index: 85;
  width: 3.25rem;
  height: 3.25rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  box-shadow: var(--shadow-sm);
  transform: translateY(1.25rem) scale(0.9);
  opacity: 0;
  pointer-events: none;
  transition:
    transform var(--dur) var(--ease),
    opacity var(--dur) ease,
    background var(--dur-fast) ease,
    color var(--dur-fast) ease;
}
.wa.is-on {
  transform: none;
  opacity: 1;
  pointer-events: auto;
}
.wa:hover {
  background: var(--blush-ink);
}
/* Over the footer the disc and the surface behind it are both --ink.
   Inverted there: the page's own paper as the disc, the plum as the
   mark. Colour only, so nothing moves or changes size. */
.wa.is-invert {
  background: var(--paper);
  color: var(--ink);
}
.wa.is-invert:hover {
  background: var(--blush-lt);
  color: var(--ink);
}
.wa svg {
  width: 1.375rem;
  height: 1.375rem;
  fill: currentColor;
}

/* ---------------------------------------------------------- *
 * 18. Responsive
 * ---------------------------------------------------------- */

@media (max-width: 1180px) {
  /* Stay four across — wrapping to 2x2 doubled the section's height.
     The cards just get tighter. */
  .matrix {
    gap: clamp(0.5rem, 1.4vw, 1rem);
  }
  .cell {
    padding: 1.75rem 1.25rem 2rem;
  }
  .cell p {
    font-size: 0.8125rem;
  }
}

@media (max-width: 900px) {
  /* Two by two below this, with the card chrome pulled in so the block
     stays compact — four tall cards was what made the 2x2 feel bloated
     the first time round. */
  .matrix {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(0.5rem, 1.6vw, 0.875rem);
  }
  .cell {
    padding: 1.25rem 1.125rem 1.5rem;
    border-radius: var(--r-l);
  }
  .cell__n {
    font-size: 0.75rem;
  }
  .cell .h3 {
    font-size: 0.9375rem;
    margin-top: 0.625rem;
  }
  .cell p {
    font-size: 0.78125rem;
    line-height: 1.8;
    margin-top: 0.375rem;
  }
}

@media (max-width: 460px) {
  /* two columns of ~160px cannot hold Arabic body copy */
  .matrix {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 1024px) {
  :root {
    /* Measured, not estimated: the bar renders 112px at 375px wide,
       because the logo alone is 86px. At 4.75rem (76px) the first
       chapter's padding fell 8px SHORT of the header and the eyebrow
       rendered behind it. 7rem clears the bar and leaves the section's
       own clamp() as breathing room on top. */
    --header-h: 7rem;
  }
  .nav {
    display: none;
  }
  /* logo · menu button · booking, on one line. Without explicit
     tracks the button and the actions both landed in column 2 and the
     button was pushed onto a second row. */
  .hdr__logo {
    grid-column: 1;
  }
  .burger {
    display: grid;
    /* the row has to be explicit too: the button comes last in the
       markup, so auto-placement had already stepped past column 2 and
       dropped it onto a second line */
    grid-column: 2;
    grid-row: 1;
    justify-self: center;
  }
  .hdr__side {
    grid-column: 3;
  }
  .pin {
    position: static;
  }
  .nearby,
  .faq,
  .contact {
    grid-template-columns: 1fr;
  }
  /* Three blocks in two columns left the fourth cell empty, so the
     footer read as a column of content beside a hole. The three-column
     rule carries on down to 760px, where the brand takes the full width
     and the two lists pair off underneath. */
}

/* The row keeps its shape on touch: the same expanding panels in the
   same proportions, only smaller. It used to turn into a swipeable
   strip of equal cards, which read as a different design from the one
   on the desktop — and the last card was clipped at the edge. */
@media (max-width: 900px), (hover: none) {
  .acc {
    height: clamp(16rem, 58vw, 22rem);
    /* a tighter gap buys the panels back a few pixels each */
    gap: clamp(0.25rem, 1vw, 0.5rem);
  }
  /* tapping is the only way in here, so the open panel opens wider
     than it does under a pointer */
  .acc__p[aria-expanded='true'] {
    flex-grow: 5;
  }
  /* :hover can stick after a tap on some touch browsers and would
     leave two panels looking open at once */
  .acc__p:hover:not([aria-expanded='true']) {
    flex-grow: 1;
  }
  .acc__p:hover:not([aria-expanded='true']) img {
    filter: saturate(0.88) brightness(0.94);
    transform: none;
  }
}

/* Horizontal on a phone too, exactly as on a wide screen — one panel
   open, the rest waiting beside it. The only concession is the corner
   radius: 32px on a 29px-wide panel rounded it into a pill, so the
   collapsed ones take a radius their width can carry. */
@media (max-width: 760px) {
  .acc__p {
    border-radius: var(--r-m);
  }
  .acc__p[aria-expanded='true'] {
    border-radius: var(--r-l);
  }
  /* a collapsed panel is ~29px across here: no room for the marks, and
     the nowrap caption was running past the viewport edge inside its
     clipped panel */
  .acc__p:not([aria-expanded='true']) .acc__n,
  .acc__p:not([aria-expanded='true'])::before,
  .acc__p:not([aria-expanded='true']) .acc__cap {
    opacity: 0;
  }
  .acc__n {
    top: 0.75rem;
    inset-inline: 0.75rem;
  }

  /* each hint speaks to the input its device actually has */
  .gv__hint--pointer {
    display: none;
  }
  .gv__hint--touch {
    display: block;
  }
}

@media (max-width: 760px) {
  .room {
    grid-template-columns: auto 1fr;
  }
  .room__body {
    grid-column: 1 / -1;
  }
  .matrix {
    grid-template-columns: 1fr;
  }
  .svc__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .grid-2 {
    grid-template-columns: 1fr;
  }
  /* the two link lists sit side by side while they fit; the brand
     block takes the full width above them */
  .foot__top {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2.25rem 1.5rem;
  }
  .foot__brand {
    grid-column: 1 / -1;
  }
  /* Three tracks will not fit a phone. Wrapping put the location and
     "back to top" on one line and the copyright on another, which read
     as a cramped block rather than a list. One line each instead. */
  .foot__bot {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.875rem;
    text-align: center;
  }
  .foot__credit {
    margin-top: 0.875rem;
  }
}

@media (max-width: 340px) {
  /* below this the two lists start wrapping their own links */
  .foot__top {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 460px) {
  .room {
    grid-template-columns: 1fr;
  }
  .room__n {
    font-size: 2rem;
  }
  /* the action stays; the language pair moves into the menu sheet,
     where it is one tap away */
  .hdr__side .lang {
    display: none;
  }
  .hdr__side .btn {
    padding: 0.75rem 1rem;
    font-size: 0.78125rem;
  }
}

/* The switch itself is .lang, shared with the header; this only places
   it and sizes it for a thumb. It used to be a single underlined link
   tinted --blush-lt, which is the shade meant for dark surfaces and
   measured 1.68:1 on the sheet's bone background. */
.sheet__lang {
  display: none;
  margin-top: 1.75rem;
  font-size: 0.875rem;
}
.sheet__lang .lang__on,
.sheet__lang .lang__off {
  display: block;
  min-width: 2.75rem;
  padding: 0.5rem 0.875rem;
  border-radius: var(--r-round);
  text-align: center;
}

@media (max-width: 460px) {
  .sheet__lang {
    /* inline-flex, not inline-block: it is the two-part switch now, and
       it has to keep the header's own layout for it */
    display: inline-flex;
  }
}

/* Comfortable touch targets on pointer-coarse devices.
   The footer and contact links are standalone navigation, not prose,
   so WCAG 2.2's inline-text exemption does not cover them — they need
   the 24px minimum in their own right. */
@media (pointer: coarse) {
  /* The child combinator matters: the phone, mobile and email links sit
     directly in their <dd>, but the platform links are a level deeper,
     inside .social. Matching every descendant turned those anchors into
     inline-block too, which un-blockified the mask spans inside them and
     collapsed both marks to 0x0 on touch. */
  .foot li a,
  .info__row dd > a {
    display: inline-block;
    padding-block: 0.375rem;
  }
  .foot li {
    margin-top: 0.375rem;
  }
  .lang > * {
    padding-block: 0.5rem;
  }
  .tlink {
    padding-block: 0.625rem;
  }
  .field input,
  .field select,
  .field textarea {
    padding-block: 0.875rem;
  }
  /* These were 2.75rem squares when they held icons. They hold a name
     now, so the width comes from the word: pinning it squashed every
     pill to 44px and the text spilled out of its own border. */
  .social a {
    min-height: 2.75rem;
  }
}

.frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition:
    transform var(--dur-slow) var(--ease),
    filter var(--dur) ease;
}

.frame--drift img {
  /* the image is oversized then slid, so the crop moves with
     the scroll — the "camera pan" effect */
  height: 116%;
  position: absolute;
  inset: 0;
  transform: translateY(calc(var(--p, 0) * -14%));
}

.noanim {
  scroll-behavior: auto;
}

.noanim *,
.noanim *::before,
.noanim *::after {
  animation-duration: 0.001ms !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  transition-delay: 0ms !important;
}

.noanim [data-reveal] {
  opacity: 1 !important;
  transform: none !important;
  clip-path: none !important;
}
.noanim .split-i {
  transform: none !important;
}
.noanim .eyebrow::before {
  transform: scaleX(1) !important;
}
.noanim .frame--drift img {
  transform: none !important;
  height: 100%;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .split-i {
    transform: none !important;
  }
  .frame--drift img {
    transform: none !important;
    height: 100%;
  }
}

/* ---------------------------------------------------------------
   19. Arabic does not take tracking

   Arabic is cursive: the letters of a word are joined, and
   `letter-spacing` pushes those joins apart, so a word arrives
   visibly broken — "الـبـدايـة" instead of "البداية". The tracking
   below is right for the Latin page, where these same labels are
   short uppercase words, so each rule is undone only under
   [dir='rtl'] and the English page keeps its spacing untouched.

   The list is not guesswork: it is every element on the Arabic page
   that holds Arabic text AND resolved to a positive letter-spacing,
   collected by walking the rendered DOM.

   Elements holding only numerals keep their tracking on purpose:
   .place__n, .cell__n, .rm__badge, .acc__n are all '01'-'09'.
   --------------------------------------------------------------- */
[dir='rtl'] .eyebrow,
[dir='rtl'] .rail__t,
[dir='rtl'] .ch1__facts span,
[dir='rtl'] .ch1__cap,
[dir='rtl'] .rooms__hint,
[dir='rtl'] .svc__state,
[dir='rtl'] .dining__note,
[dir='rtl'] .gv__hint,
[dir='rtl'] .field label,
[dir='rtl'] .info__row dt,
[dir='rtl'] .foot h4,
[dir='rtl'] .btn {
  letter-spacing: normal;
}
