/* ==========================================================================
   Red Dunes — BLOCK ADAPTER layer
   Loaded LAST, after components.css.

   The mockups are hand-written HTML. The block editor cannot produce some of
   that DOM — most importantly it has no "link wrapper" block, so a card that
   was `<a class="family">…</a>` has to become a group with a link inside it.
   This file bridges those differences. It must stay SMALL: anything that is a
   design decision belongs in components.css, not here.

   Rule: every block in here names the mockup construct it is standing in for.
   ========================================================================== */

/* ---- Whole-card links --------------------------------------------------
   Mockup: <a class="family">img + h3 + p + span</a>
   Block:  group.family containing an inner link.
   `.family::after` is already the gradient scrim, so the stretch hook goes on
   the LINK's ::after instead, above the scrim but below nothing else.
   ----------------------------------------------------------------------- */
/* 9 Nov 2026: `.vehicle` was missing from all three of these groups, so the fleet
   cards had a stretch-link with NO stretched ::after - the clickable area was the
   27px title line, not the card, and the focus ring never appeared. The mockup made
   the whole card an <a>; the block conversion turned it into a div and nobody added
   the component to this list. */
.family, .tile, .card, .hero-tile, .vehicle { position: relative; }

.family .stretch-link::after,
.tile   .stretch-link::after,
.card   .stretch-link::after,
.vehicle .stretch-link::after,
.hero-tile .stretch-link::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
}

/* The card is a group now, so :focus-visible never fires on it. Mirror the
   mockup's focus ring from the link inside. */
.family:has(.stretch-link:focus-visible),
.tile:has(.stretch-link:focus-visible),
.vehicle:has(.stretch-link:focus-visible),
.card:has(.stretch-link:focus-visible) {
  outline: 2px solid var(--rd-rust); outline-offset: 3px;
}
.family .stretch-link:focus-visible,
.tile .stretch-link:focus-visible,
.vehicle .stretch-link:focus-visible,
.card .stretch-link:focus-visible { outline: none; }

/* ---- Core block resets -------------------------------------------------
   Core wraps almost everything in .wp-block-group with its own layout classes
   and adds margins the mockup never had. Neutralise only where our components
   already own the spacing.
   ----------------------------------------------------------------------- */
.site-header > .wp-block-group,
.hero > .wp-block-group,
.section > .wp-block-group { margin-block: 0; }

.wp-block-group.wrap { margin-inline: auto; }

/* ---- core/image's <figure> inside our media boxes ----------------------
   core/image wraps every <img> in a <figure class="wp-block-image">. The mockups
   style the <img> DIRECTLY, so rules like `.hero__media img { height: 100% }` now
   resolve 100% against the figure instead of the media box. The figure has no
   height, so the image falls back to its natural ratio at full width:
   measured 1905x1426 inside a 1905x691 hero, overflowing by 735px.

   Fix: make the figure fill its media box, then let the mockup's own img rules work.

   The figure is absolutely positioned to fill its box. `height: 100%` alone is not
   enough — `.hero__media`'s height comes from inset:0 and the percentage did not
   resolve, leaving the image at 1905x1426 in a 691px box. But `.about__media` has
   aspect-ratio + overflow:hidden and NO position:relative, so an absolute figure
   escaped it (1905x901 in a 549x439 box). Hence BOTH: give every media box a
   positioning context first, then fill it. */
/* ONLY the boxes components.css does not already position. `.hero__media` is
   `position: absolute; inset: 0` there and `.card__media`/`.featured__media` are
   already relative — re-declaring `relative` on the hero collapsed it to 0 height. */
.about__media,
.map-frame { position: relative; }

.hero__media > figure.wp-block-image,
.about__media > figure.wp-block-image,
.featured__media > figure.wp-block-image,
.card__media > figure.wp-block-image,
.map-frame > figure.wp-block-image {
  position: absolute; inset: 0; margin: 0; width: 100%; height: 100%;
}
.hero__media > figure.wp-block-image img,
.about__media > figure.wp-block-image img,
.featured__media > figure.wp-block-image img,
.card__media > figure.wp-block-image img,
.map-frame > figure.wp-block-image img {
  width: 100%; height: 100%; object-fit: cover;
}

/* Cards position the image themselves behind the content (z-index -2), so those
   keep the absolute-image treatment rather than an absolute figure. */
.family > figure.wp-block-image,
.tile   > figure.wp-block-image { margin: 0; position: static; }
.family > figure.wp-block-image img,
.tile   > figure.wp-block-image img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }

/* ---- Links inside cards ------------------------------------------------
   theme.json's elements.link paints every <a> rust. In the mockup the whole card
   WAS the anchor, so there was no inner link to colour. The stretch link must
   inherit the card's own colour instead, or the "from" price turns rust on the photo.
   ----------------------------------------------------------------------- */
.family .stretch-link,
.tile .stretch-link,
.card .stretch-link,
.hero-tile .stretch-link { color: inherit; text-decoration: none; }

/* ---- Core flow margins inside OUR grid/flex components -----------------
   Core's flow layout puts `margin-block-start: 24px` on every child after the
   first. Our components lay their children out with grid/flex and own the gaps,
   so that margin lands INSIDE the grid area: it pushed family cards 2+3 down 24px
   while card 1 (:first-child) sat high, and blew `.strip__item`'s 2px gap out to 24px.

   `.rd-flat` is the fix going forward: put it on ANY group in a pattern whose
   children are laid out by our CSS. One rule instead of chasing each component.
   The explicit list below covers components whose class comes from components.css.
   ----------------------------------------------------------------------- */
.rd-flat > *,
.families > *,
.strip > *,
.strip__item > *,
.cards > *,
.tiles > *,
.fleet > *,
.gallery > *,
.trust > *,
.btn-row > *,
.footer-grid > * { margin-block-start: 0; }

/* ---- Top-level sections: no gap between them -------------------------
   Found 4 Nov 2026 while measuring the homepage after the comparison table
   went in. Every top-level <section> is a flow child of .entry-content, so
   core was adding `margin-block-start: 24px` at EVERY section boundary -
   384px down a 17-section homepage, and a visible seam of body colour
   wherever two sand sections met (compare -> adventures).

   Sections own their vertical rhythm through `padding-block: var(--rd-section-y)`
   and the mockup has exactly zero gap between them, so zeroing this is what
   matches the approved design. Scoped to direct children of .entry-content, so
   it cannot reach the flow spacing inside a section. */
.entry-content > section { margin-block-start: 0; }
/* NOT .section-head: eyebrow -> h2 -> intro are spaced by their own margins, and
   flattening them cost 24px per section head. Only GRID/FLEX containers belong in
   the list above - on a flow container `rd-flat` destroys the component's rhythm.
   That was the whole of the remaining hero (-71px), about (-75px) and gallery
   (-85px) drift.

   VERIFIED AGAINST THE MOCKUP, do not guess: of every container the patterns touch,
   only `.stack` (display:block, `> * + * { margin-top: 16px }`) spaces by child
   margin. `.wrap`, `.faq`, `.step`, `.hero__media`, `.about__media` are block but
   their children carry no margin, so rd-flat is a no-op there. Everything else
   (.about .enquiry .cta-band .families .strip .tile-grid .tour-grid .steps
   .review-grid .gallery-strip .vehicle-row .btn-row .stat-row .head-row
   .rating-summary .hero__inner .review .cta-band__actions .strip__item) is grid or
   flex with a real `gap`, where rd-flat is correct and necessary. */

/* ---- FAQ: core/details vs the mockup's <details> ----------------------
   The mockup wraps each answer in `.faq__answer`; core/details puts the content
   straight inside <details>. Map the component's answer styles onto the direct
   children instead of adding a wrapper that staff could delete.
   ----------------------------------------------------------------------- */
.faq .wp-block-details > :not(summary) { /* inherits .faq__answer spacing */ }
.faq .wp-block-details { border-bottom: 1px solid var(--rd-line); }
.faq .wp-block-details > summary { cursor: pointer; list-style: none; }
.faq .wp-block-details > summary::-webkit-details-marker { display: none; }

/* ---- First-child margin kills deliberate negative margins --------------
   Core zeroes `margin-block-start` on the first child of a flow group. `.strip` is
   the first child of its `.wrap` and relies on `margin-top: -48px` to overlap the
   hero — it was computing to 0, so the strip sat 48px lower and its section was
   62px taller than the design. Restored with enough specificity to win.
   ----------------------------------------------------------------------- */
.wrap > .strip { margin-top: calc(var(--rd-sp-7) * -1); }

/* ---- core/navigation vs the mockup's .nav -----------------------------
   The mockup is `.nav > ul > li > a`. core/navigation inserts a
   `.wp-block-navigation__responsive-container` between the <nav> and the <ul>,
   so `.nav > ul` stops matching and the menu rendered as a stacked block list
   (7 rows, 206px-tall header). Re-point the same rules at core's container.
   ----------------------------------------------------------------------- */
.site-header .nav ul.wp-block-navigation__container {
  display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end;
  gap: var(--rd-sp-1) var(--rd-sp-2); list-style: none; margin: 0; padding: 0;
}
.site-header .nav ul.wp-block-navigation__container > li > a {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 0 var(--rd-sp-3); border-radius: var(--rd-radius-pill);
  color: var(--rd-espresso); font-weight: 600; text-decoration: none;
}
@media (hover: hover) {
  .site-header .nav ul.wp-block-navigation__container > li > a:hover { background: var(--rd-sand); }
}
/* core adds its own container padding/gap that fights the pill spacing */
.site-header .nav .wp-block-navigation__responsive-container,
.site-header .nav .wp-block-navigation__responsive-container-content { min-width: 0; }

/* Footer menu: a plain vertical list, like the mockup's footer columns. */
.site-footer .wp-block-navigation ul.wp-block-navigation__container {
  display: grid; gap: var(--rd-sp-2); list-style: none; margin: 0; padding: 0;
}

/* ---- core/button vs .btn ----------------------------------------------
   theme.json's `elements.button` paints `.wp-block-button__link` rust. The mockup's
   `.btn--wa` sits on the WRAPPER, so a core/button rendered a RUST pill inside a
   GREEN wrapper. Header CTAs are plain anchors now; this covers any core/button that
   still carries a .btn-- modifier.
   ----------------------------------------------------------------------- */
.btn--wa > .wp-block-button__link { background: var(--rd-wa); color: #06281A; }
.btn--wa > .wp-block-button__link:hover { background: #1FBE5B; color: #06281A; }
.btn--ghost > .wp-block-button__link { background: transparent; color: var(--rd-espresso); border: 1px solid var(--rd-line); }
.btn--on-dark > .wp-block-button__link { background: rgba(255,255,255,.1); color: #fff; border: 1px solid rgba(255,255,255,.4); }

/* ---- core/site-logo vs the mockup's .logo -----------------------------
   core renders `.wp-block-site-logo > a.custom-logo-link > img.custom-logo`; the
   mockup styles `.logo__img` directly. Give the core image the same 44px height.
   ----------------------------------------------------------------------- */
.site-header .wp-block-site-logo { margin-right: auto; min-width: 0; line-height: 0; }
.site-header .wp-block-site-logo a { display: inline-flex; align-items: center; min-height: 44px; }
.site-header .wp-block-site-logo img { height: 44px; width: auto; max-width: none; }
@media (max-width: 29.99em) { .site-header .wp-block-site-logo img { height: 38px; } }

/* ---- Template-part wrapper breaks position:sticky ---------------------
   Core wraps every template part in its own element (`header.wp-block-template-part`).
   `position: sticky` can only move within its PARENT's box, and that wrapper is only
   as tall as the header itself — measured 73px — so `.site-header` scrolled clean away
   (top -1476 at scrollY 1476) despite computing as `position: sticky`.
   `display: contents` removes the wrapper's box so `.site-header` becomes a flow child
   of <body> and sticks for the whole page, as in the mockup. The scrim is
   position:fixed and is unaffected.
   ----------------------------------------------------------------------- */
header.wp-block-template-part { display: contents; }

/* ---- Headings on the dark footer --------------------------------------
   theme.json sets every heading to espresso, and the footer background IS espresso,
   so the footer column headings measured 1.00:1 - literally invisible.
   ----------------------------------------------------------------------- */
.site-footer h1, .site-footer h2, .site-footer h3,
.site-footer h4, .site-footer h5, .site-footer h6 { color: var(--rd-on-dark); }

/* ---- core/post-template wraps every card in an <li> -------------------
   The mockup's grid items ARE the cards. core/post-template inserts
   `li.wp-block-post` between the grid and the card, so the grid stretches the
   WRAPPER to the row height while the card keeps its own content height —
   measured 697 / 674 / 674 in one row, so the price rows did not line up.
   Flex the wrapper and let the card fill it. Not `display: contents`, which
   can drop the list-item semantics.
   ----------------------------------------------------------------------- */
.tour-grid > li.wp-block-post,
.tile-grid > li.wp-block-post,
.families > li.wp-block-post { display: flex; min-width: 0; }

.tour-grid > li.wp-block-post > .card,
.tile-grid > li.wp-block-post > .tile,
.families > li.wp-block-post > .family { flex: 1 1 auto; min-width: 0; }

/* Footer column headings are h2 (they are top-level sections of the footer, and an
   h3 there created an h1 -> h3 jump on pages whose content has no h2). The mockup
   styles `.site-footer h3`, so give h2 the same treatment. */
.site-footer .footer-grid h2 {
  font-size: var(--rd-step--1); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--rd-on-dark-dim); margin-bottom: var(--rd-sp-3);
}

/* ---- single-tour hero (core/post-featured-image) -----------------------
   `.tour-hero` had NO CSS at all, so the featured image rendered at its own
   intrinsic size up to the wrap width and the hero's height was whatever the
   photo's ratio happened to be: vip-desert-safari (1280x1140) came out 1012px
   tall, jet-ski-adventure is portrait 960x1280, global-village only 600px wide.
   Every tour page was a different height and the hero dwarfed the page.

   The approved mockup has a 3-up `.gallery` here, not one image, and we hold only
   one photo per tour - so this is a single image in a box the same height as that
   gallery. At the 1136px content width the mockup's gallery measures 1136x478
   (2fr/1fr columns, two 16:10 thumbs stacked), i.e. 2.38:1 -> 12/5.
   Below 47.5em the mockup's first figure is 16:10, and the same breakpoint is used
   here so the two agree.

   CONSEQUENCE FOR SOURCE IMAGES: one file serves both ratios, so export 16:10 and
   keep the subject in the middle 67% vertically - the desktop band is cropped out
   of the centre. Target 1600x1000, floor 1136x710. See tour-heroes-to-resize/.

   The class sits ON the figure (post-featured-image puts it there), so unlike the
   core/image boxes above there is no inner figure to neutralise - but the UA's
   `figure { margin: 1em 40px }` would inset the hero, hence the explicit margin.
   ----------------------------------------------------------------------- */
.tour-hero {
  margin: var(--rd-sp-5) 0 0;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: var(--rd-radius-card);
  background: var(--rd-sand-200);
}
/* 6 Nov, SAME DAY: the 12/5 band was right while the hero spanned the full 1136px
   wrap. The rebuilt layout moves it into the ~670px left column, where 12/5 is only
   280px tall and reads as a letterbox strip. One ratio at every width now - which
   also means the source image is never centre-cropped, so 16:10 in is 16:10 out. */
.tour-hero img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
}

/* ---- Post lists: blog index, archive, search (9 Nov 2026) ---------------
   These four templates were still the raw scaffold - no `.wrap`, no section, a
   bare core/query - so every one of them rendered hard against the viewport
   edge. They now use `.card` + `.tour-grid` like the rest of the site, which
   needs three adapters, all the same family of problem as the hero figure:
   core wraps things our CSS expects to style directly. */

/* `isLink` puts an <a> between the figure and the <img>, and that <a> has no
   height - so `.card__media img { height: 100% }` resolved against nothing and
   the image fell back to its natural ratio inside a 4/3 box. */
.card__media > a { display: block; width: 100%; height: 100%; }

/* core/post-excerpt and core/post-date bring their own wrappers; `.card__body`
   is a flex column with a real gap, so zero their margins rather than fight. */
.card .wp-block-post-excerpt,
.card .wp-block-post-excerpt__excerpt,
.card .wp-block-post-date { margin: 0; }
.card .wp-block-post-excerpt__excerpt { color: var(--rd-slate-600); }
.card .wp-block-post-date { font-size: var(--rd-step--1); color: var(--rd-slate-600); }
.card__title.wp-block-post-title { margin: 0; }

/* core/query-pagination: a plain row of links with no styling of its own. */
.pagination {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--rd-sp-2); margin-top: var(--rd-sp-6);
}
.pagination .wp-block-query-pagination-numbers { display: flex; flex-wrap: wrap; gap: var(--rd-sp-2); }
.pagination a,
.pagination .page-numbers {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0 var(--rd-sp-3);
  border: 1px solid var(--rd-line); border-radius: var(--rd-radius-pill);
  color: var(--rd-slate); font-size: var(--rd-step--1); font-weight: 650;
  text-decoration: none;
}
.pagination a:hover { background: var(--rd-sand); color: var(--rd-espresso); }
.pagination .page-numbers.current {
  background: var(--rd-rust-050); border-color: var(--rd-rust-050); color: var(--rd-rust-700);
}

/* The empty state carries a button, so it needs to stack rather than run on. */
.empty-state .btn { margin-top: var(--rd-sp-4); }

/* ---- Fleet card: core puts the name and the meta in ONE paragraph -------
   `.vehicle` is a grid and the mockup fed it `img`, `b` and `span` as separate
   children, one per row. The block editor cannot emit a bare `b` + `span`, so the
   conversion wrapped both in a single <p> and they ran together on one line:
   "Land CruiserDesert safari - 6 seats". Give that paragraph its own rows. */
.vehicle > p { display: grid; gap: 2px; margin: 0; }
.vehicle > p > a { color: inherit; text-decoration: none; }
.vehicle > p > a:hover b { color: var(--rd-rust); }

/* ---- Decorative icons in FLOW context ----------------------------------
   base.css resets `img, svg, video { display: block }`, which is right for media
   and invisible everywhere an icon sits in a flex row - a flex item's display is
   blockified anyway. In an ordinary <li> or <p> it is not: the icon took a line of
   its own above its own label. `inline-block` changes nothing inside flex and fixes
   flow, so it is safe to set on the component itself. */
.icon { display: inline-block; vertical-align: -0.18em; }
