/* ==========================================================================
   Red Dunes — reset, typography, layout primitives
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

/* scroll-padding-top keeps EVERY in-page anchor clear of the sticky header (85px at
   desktop). It is set on the scroll container, so it covers targets added later too -
   the alternative is a scroll-margin-top per target, which is the same chase as
   .rd-flat was. Measured before: #compare, #camp-menus, #tours and #enquire all
   landed at top 0 with their section's top padding hidden behind the header. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 96px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  background: var(--rd-page);
  color: var(--rd-slate);
  font: 400 var(--rd-step-0)/var(--rd-leading-body) var(--rd-font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* No overflow-x here. `hidden` hides real sideways scroll from every check and
     makes body a scroll container; `clip` makes body a containing block for
     fixed descendants, which resizes the sticky action bar to the document.
     Overflow is fixed at the source instead. */
}

img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }

h1, h2, h3, h4 {
  color: var(--rd-espresso);
  /* a reader on a large default font size must get a broken word, not a
     headline that scrolls the page sideways */
  overflow-wrap: break-word;
  font-weight: 700;
  letter-spacing: var(--rd-tracking-tight);
  line-height: var(--rd-leading-snug);
  text-wrap: balance;
}
h1 { font-size: var(--rd-step-5); line-height: var(--rd-leading-tight); }
h2 { font-size: var(--rd-step-4); }
h3 { font-size: var(--rd-step-2); }
h4 { font-size: var(--rd-step-1); }
p  { text-wrap: pretty; }

a { color: var(--rd-rust); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--rd-rust-700); }

/* Focus: always visible, never removed. */
:focus-visible {
  outline: 3px solid var(--rd-rust);
  outline-offset: 2px;
  border-radius: 4px;
}

ul.clean { list-style: none; padding: 0; }

/* ---- Layout ------------------------------------------------------------ */
.wrap {
  width: 100%;
  max-width: var(--rd-wrap);
  margin-inline: auto;
  padding-inline: var(--rd-gutter);
}
.wrap--narrow { max-width: var(--rd-wrap-narrow); }
/* A reading measure that sits INSIDE a full `.wrap` instead of replacing it, so prose
   keeps the same left edge as the page head above it. `.wrap--narrow` centres itself,
   which under a left-aligned head reads as two different layouts stacked. */
.measure { max-width: var(--rd-wrap-narrow); }

.section { padding-block: var(--rd-section-y); }
.section--sand { background: var(--rd-sand); }
.section--tight { padding-block: clamp(32px, 4vw, 56px); }

.stack > * + * { margin-top: var(--rd-sp-4); }
.stack-lg > * + * { margin-top: var(--rd-sp-6); }
.stack > *, .stack-lg > * { min-width: 0; }

/* ---- Section headers --------------------------------------------------- */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--rd-sp-2);
  /* rust-700, not rust: #D53307 on sand is 4.39:1, just under AA for 14px */
  color: var(--rd-rust-700);
  font-size: var(--rd-step--1);
  font-weight: 650;
  letter-spacing: .08em;
  text-transform: uppercase;
}
/* The 22x2px rust rule that used to sit before every eyebrow was removed 9 Nov 2026
   at the user's request ("remove the em dashes before the little title"). The flex
   row and its gap are kept so an eyebrow carrying an icon still lines up. */
.section-head { max-width: 62ch; margin-bottom: var(--rd-sp-7); }
.section-head > * + * { margin-top: var(--rd-sp-3); }
/* :not(.eyebrow) — a bare descendant selector here (0,1,1) silently beat the
   .eyebrow component rule (0,1,0) and painted every eyebrow slate instead of
   rust, on some pages but not others. Same trap the handbook lists. */
.section-head p:not(.eyebrow) { color: var(--rd-slate-600); font-size: var(--rd-step-1); }

.head-row {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  justify-content: space-between; gap: var(--rd-sp-4);
  margin-bottom: var(--rd-sp-7);
}
.head-row .section-head { margin-bottom: 0; }

/* ---- Scroll reveal -----------------------------------------------------
   Sections rise into place as you reach them.

   Two rules make this safe, and they are the whole difference between this
   and the jarallax / waypoints / floating-effects scripts that make the
   current site stutter:

   1. NOTHING IS HIDDEN UNTIL JS SAYS IT CAN BE. `.reveal-enabled` is put on
      <html> by a two-line inline script in the head. With JS off, blocked, or
      broken, every section is simply visible — the content is never at the
      mercy of a script.
   2. NO SCROLL LISTENER. One IntersectionObserver callback fires once per
      element and then unobserves it. Nothing runs on the scroll thread, so
      there is nothing to make scrolling stutter.

   Only opacity and transform are animated — both composited, neither causes
   layout. Reduced motion turns it off completely.
   ----------------------------------------------------------------------- */
.reveal-enabled .reveal,
.reveal-enabled .reveal-stagger > * {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s var(--rd-ease), transform .8s var(--rd-ease);
}
.reveal-enabled .reveal.is-revealed,
.reveal-enabled .reveal-stagger.is-revealed > * { opacity: 1; transform: none; }

/* small groups arrive one after another; the 24-card listing moves as one
   block instead, or browsing it turns into a showreel */
.reveal-enabled .reveal-stagger > *:nth-child(2) { transition-delay: .05s; }
.reveal-enabled .reveal-stagger > *:nth-child(3) { transition-delay: .10s; }
.reveal-enabled .reveal-stagger > *:nth-child(4) { transition-delay: .15s; }
.reveal-enabled .reveal-stagger > *:nth-child(5) { transition-delay: .20s; }
.reveal-enabled .reveal-stagger > *:nth-child(6) { transition-delay: .25s; }
.reveal-enabled .reveal-stagger > *:nth-child(7) { transition-delay: .30s; }
.reveal-enabled .reveal-stagger > *:nth-child(n+8) { transition-delay: .35s; }

@media (prefers-reduced-motion: reduce) {
  .reveal-enabled .reveal,
  .reveal-enabled .reveal-stagger > * {
    opacity: 1; transform: none; transition: none;
  }
}

/* ---- Utility ----------------------------------------------------------- */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.skip-link {
  position: absolute; left: var(--rd-sp-4); top: -100px; z-index: 200;
  background: var(--rd-espresso); color: #fff;
  padding: var(--rd-sp-3) var(--rd-sp-4);
  border-radius: var(--rd-radius-sm); text-decoration: none;
}
.skip-link:focus { top: var(--rd-sp-4); color: #fff; }

.muted { color: var(--rd-slate-600); }
.small { font-size: var(--rd-step--1); }
.nowrap { white-space: nowrap; }

/* ---- Placeholder marking ----------------------------------------------
   Every invented figure on these pages carries .ph. Search the HTML for
   class="ph" to find everything the client still has to supply.
   ----------------------------------------------------------------------- */
/* Marked, but quiet: a dotted rule in the text's own colour, not a grey dash that
   shouts on a dark hero. Still visible, still carries the reason in the tooltip. */
.ph { border-bottom: 1px dotted rgba(140, 146, 155, .55); cursor: help; overflow-wrap: anywhere; }
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  .ph { border-bottom-color: color-mix(in srgb, currentColor 42%, transparent); }
}
.mock-note {
  background: var(--rd-espresso); color: #F3E9E2;
  font-size: var(--rd-step--1); line-height: 1.45;
  padding: var(--rd-sp-3) 0;
}
.mock-note b { color: #fff; }
.mock-note .wrap { display: flex; flex-wrap: wrap; gap: var(--rd-sp-2) var(--rd-sp-5); }

/* =========================================================================
   LONG-WORD BREAKING (12 Nov 2026, added with German/French/Spanish)
   German compounds do not break at a space - "Standard-Wüstensafari",
   "Abholzeitfenster", "STORNIERUNG" - so on a narrow or large-font viewport the
   word itself becomes wider than its column and the whole PAGE scrolls sideways.
   Measured on staging: English passed all 16 viewports, German failed 4.

   IT MUST BE `anywhere`, NOT `break-word`. The two wrap lines identically; the
   difference is that only `anywhere` reduces the element's intrinsic MIN-CONTENT
   width. A grid or flex item defaults to `min-width: auto`, which refuses to shrink
   below its longest word - so with `break-word` the German label still forced its
   column wide and the page still scrolled. Measured, not assumed: break-word left
   the overflow at exactly the same 290px.

   Neither value changes how text that already fits is rendered, so the English site
   is untouched. `hyphens` is deliberately NOT set: it would hyphenate running English
   prose too, which is a design change nobody asked for.
   ========================================================================= */
h1, h2, h3, h4, h5, h6,
p, li, dd, dt, figcaption, blockquote, summary, th, td, label,
b, strong, em, span, a,
.h1, .h2, .h3 { overflow-wrap: anywhere; }
