/* ==========================================================================
   CROWN RIDES — BASE
   Reset, document defaults, typography primitives, layout, utilities.
   ========================================================================== */

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

* { margin: 0; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--s-5));
}

body {
  background-color: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: var(--fw-regular);
  line-height: var(--lh-relaxed);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, video, picture {
  display: block;
  max-width: 100%;
  height: auto;
}

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

button { background: none; border: none; cursor: pointer; }

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

ul, ol { list-style: none; }

/* The [hidden] attribute must always win. Any component that sets
   `display: flex/grid/block` otherwise out-specifies the UA rule and stays
   visible while marked hidden — which is how empty error badges, the saved
   notice and the lead-time notice all leaked onto the booking page. */
[hidden] { display: none !important; }

::selection {
  background: var(--c-gold);
  color: var(--c-black);
}

/* --------------------------------------------------------------------------
   FOCUS — visible, always. Never removed.
   -------------------------------------------------------------------------- */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}
:focus:not(:focus-visible) { outline: none; }

.skip-link {
  position: absolute;
  top: -100%;
  left: var(--s-4);
  z-index: var(--z-modal);
  padding: var(--s-3) var(--s-5);
  background: var(--c-gold);
  color: var(--c-black);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  transition: top var(--d-fast) var(--e-ui);
}
.skip-link:focus { top: 0; }

/* ==========================================================================
   TYPOGRAPHY PRIMITIVES
   Size comes from a class. The tag communicates structure only.
   ========================================================================== */

.t-hero,
.t-d1,
.t-d2,
.t-d3 {
  font-family: var(--font-display);
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-display);
  line-height: var(--lh-tight);
  text-wrap: balance;
}

.t-hero { font-size: var(--fs-hero); }
.t-d1   { font-size: var(--fs-d1); }
.t-d2   { font-size: var(--fs-d2); font-weight: var(--fw-regular); line-height: var(--lh-snug); }
.t-d3   { font-size: var(--fs-d3); font-weight: var(--fw-regular); line-height: var(--lh-snug); }

/* Display italic accent — the brand's signature typographic gesture */
.t-accent {
  font-style: italic;
  font-weight: var(--fw-regular);
  color: var(--text-accent);
}

.t-lead {
  font-size: var(--fs-xl);
  font-weight: var(--fw-light);
  line-height: var(--lh-normal);
  color: var(--text-muted);
  max-width: var(--measure);
  text-wrap: pretty;
}

.t-body   { font-size: var(--fs-md); max-width: var(--measure); text-wrap: pretty; }
.t-body-lg{ font-size: var(--fs-lg); max-width: var(--measure); text-wrap: pretty; }
.t-sm     { font-size: var(--fs-sm); }
.t-xs     { font-size: var(--fs-xs); }
.t-muted  { color: var(--text-muted); }

/* The single most important luxury detail on the site. */
.t-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  line-height: 1;
  color: var(--text-accent);
}

/* Gold hairline that draws in on scroll */
.t-eyebrow::before {
  content: "";
  width: 40px;
  height: 1px;
  background: var(--rule-gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--d-slow) var(--e-out) 120ms;
}
.is-revealed .t-eyebrow::before,
.t-eyebrow.is-revealed::before { transform: scaleX(1); }

.t-eyebrow--center::before { display: none; }

/* Oversized ghost numeral used in editorial rows */
.t-numeral {
  font-family: var(--font-display);
  font-size: clamp(3.5rem, 2rem + 6vw, 7rem);
  font-weight: var(--fw-light);
  line-height: 0.8;
  color: transparent;
  -webkit-text-stroke: 1px var(--border-strong);
  letter-spacing: -0.04em;
  transition: -webkit-text-stroke-color var(--d-base) var(--e-ui),
              color var(--d-base) var(--e-ui);
}

/* ==========================================================================
   LAYOUT
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--wide { max-width: var(--container-wide); }
.container--text { max-width: var(--container-text); }

.section {
  position: relative;
  padding-block: var(--section-y);
}
.section--lg { padding-block: var(--section-y-lg); }
.section--flush-top { padding-top: 0; }

.section__head {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  margin-bottom: var(--section-gap);
  max-width: 42rem;
}
.section__head--center {
  align-items: center;
  text-align: center;
  margin-inline: auto;
}
.section__head--split {
  max-width: none;
  flex-direction: row;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-7);
}
.section__head--split > * { max-width: 38rem; }

.grid {
  display: grid;
  gap: var(--s-5);
}

/* Hairline divider with a gold centre tick */
.rule {
  height: 1px;
  background: var(--border);
  border: 0;
}

/* ==========================================================================
   SCROLL REVEAL
   Only active when JS has run — content is fully visible without it.
   ========================================================================== */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity var(--d-slow) var(--e-out),
    transform var(--d-slow) var(--e-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* Photographs deliberately have NO separate reveal. They use the plain
   opacity fade above, exactly like the headings and body copy around them.

   There used to be a `clip-path` curtain here. It failed in the field: the
   About photograph never appeared, while every heading and paragraph beside
   it — same [data-reveal], same observer — faded in correctly. That is the
   tell. The opacity reveal works; the clip-path variant did not.

   It also failed invisibly. A clipped element shows no broken-image icon,
   logs no error, and never even requests its lazy src, so there is nothing
   to find in the console or the network panel. It just reads as a gap in
   the layout, which is exactly how the client reported it.

   Third time this codebase has been bitten by animating whether something
   EXISTS rather than how it looks — see the ride-type arrow in DECISIONS.md.
   Animate appearance, never existence. Do not reintroduce a clip reveal. */

/* ==========================================================================
   UTILITIES
   ========================================================================== */

.u-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.u-noise::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

.u-flex-center { display: flex; align-items: center; justify-content: center; }
.u-stack { display: flex; flex-direction: column; }
