/*
Theme Name: Anastasia Dahlia
Theme URI: https://anastasiadahlia.com
Author: Built for Anastasia Dahlia
Description: A dark, sultry, luxury block theme for a high-end London companion. Full-Site-Editing: edit sections, text and photos in the visual Site Editor. Committed dark aesthetic with a copperplate-script wordmark.
Version: 1.1.0
Requires at least: 6.6
Tested up to: 7.0
Requires PHP: 7.4
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: anastasia-dahlia
Update URI: false
Tags: full-site-editing, block-patterns, one-column, custom-colors, editor-style, featured-images, translation-ready

Requires at least 6.6, not 6.4: theme.json is "version": 3, which WordPress only
understands from 6.6. On 6.4/6.5 the defaultFontSizes and defaultSpacingSizes
locks are ignored and core's own presets appear in the editor alongside hers.

The disabled update URI above stops WordPress asking wordpress.org for updates
to a theme whose slug it does not own. Without it, anyone publishing a theme
called "anastasia-dahlia" in the public directory could have their version
offered as an update over the top of this one.

(Written that way round deliberately: a line here beginning "Update URI:" would
itself look like a header to WordPress's parser.)

Anastasia Dahlia WordPress Theme, (C) 2026
Anastasia Dahlia is distributed under the terms of the GNU GPL v2 or later.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 2 of the License, or (at your option) any later
version. This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.

Bundled third-party assets and their licences are listed in LICENSES.md.

NOTE: The "Tempting" script font bundled in assets/fonts is a PERSONAL-USE DEMO.
Purchase a commercial licence (RGB Studio) before using this theme on a live commercial site.
*/

/* The wordmark face lives in assets/css/wordmark.css, inlined as a data URI
   so it is present before first paint and can never swap. */

/* ---------- DESIGN TOKENS ----------
   These are aliases, not values. Every real value now lives in theme.json, so
   editing the palette or the fonts under Appearance > Editor > Styles changes
   the whole site - the ~450 lines of CSS below never needed to know.

   The literal after each comma is a fallback for the case where WordPress has
   not emitted its preset variables (a raw preview, or the stylesheet loaded
   outside WordPress). Keep them in step with theme.json. */
:root {
  /* Committed dark world - the mood is the design */
  --ground:      var(--wp--preset--color--ground, #140A0F);
  --ground-2:    var(--wp--preset--color--ground-2, #1E0F16);
  --panel:       var(--wp--preset--color--panel, #24131B);
  --oxblood:     var(--wp--preset--color--oxblood, #7A1F35);
  --oxblood-lit: var(--wp--preset--color--oxblood-lit, #9C2A45);
  --gold:        var(--wp--preset--color--gold, #C9A96A);
  --gold-soft:   var(--wp--preset--color--gold-soft, #A98C55);
  --blush:       var(--wp--preset--color--blush, #E7C6C6);
  --ivory:       var(--wp--preset--color--ivory, #F3EAE4);
  --ivory-dim:   var(--wp--preset--color--ivory-dim, #C9B7AE);
  --hairline:    var(--wp--custom--hairline, rgba(201,169,106,0.24));

  --serif:  var(--wp--preset--font-family--serif, "Didot", "Bodoni 72", "Bodoni MT", "Playfair Display", Georgia, serif);
  --body:   var(--wp--preset--font-family--body, "Baskerville", "Baskerville Old Face", "Hoefler Text", Georgia, serif);
  --label:  var(--wp--preset--font-family--label, "Optima", "Gill Sans Nova", "Gill Sans", "Futura", system-ui, sans-serif);
  --script: var(--wp--preset--font-family--script, "Tempting", "Tempting Fallback", "Didot", Georgia, serif);

  --measure: var(--wp--custom--measure, 62ch);
  --edge:    var(--wp--custom--edge, clamp(1.25rem, 5vw, 6rem));
}

* { box-sizing: border-box; }

/* Off-screen until focused, then a proper visible target. Lets a keyboard or
   screen-reader user jump the header instead of tabbing the whole nav first. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 0.9rem 1.4rem;
  background: var(--gold); color: var(--ground);
  font-family: var(--label); text-transform: uppercase;
  letter-spacing: 0.2em; font-size: 0.68rem; text-decoration: none;
}
.skip-link:focus { left: 0; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ivory);
  font-family: var(--body);
  font-size: clamp(1.02rem, 0.55vw + 0.9rem, 1.18rem);
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

::selection { background: var(--oxblood); color: var(--ivory); }

h1, h2, h3 { font-family: var(--serif); font-weight: 400; text-wrap: balance; margin: 0; }

.eyebrow {
  font-family: var(--label);
  text-transform: uppercase;
  letter-spacing: 0.34em;
  font-size: 0.72rem;
  color: var(--gold);
  margin: 0;
}

a { color: inherit; }

/* ---------- NAV ---------- */
nav {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.15rem var(--edge);
  background: linear-gradient(to bottom, rgba(20,10,15,0.85), rgba(20,10,15,0));
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background 0.4s ease;
}
nav.scrolled { background: rgba(20,10,15,0.92); border-bottom: 1px solid var(--hairline); backdrop-filter: blur(12px); }

/* The fixed nav sits under the admin bar when she is logged in and viewing
   her own site, hiding the wordmark and the menu button. */
.admin-bar nav { top: 32px; }
@media (max-width: 782px) { .admin-bar nav { top: 46px; } }
/* The wordmark is a paragraph containing a link, so that the text stays
   editable in the header and footer template parts. */
.wordmark {
  font-family: var(--script); font-size: 1.95rem; letter-spacing: 0.02em;
  color: var(--ivory); text-decoration: none; white-space: nowrap; margin: 0;
}
.wordmark a { color: inherit; text-decoration: none; }
.wordmark em { color: var(--gold); font-style: normal; }
.nav-left { display: flex; align-items: baseline; gap: 1.2rem; min-width: 0; }
.nav-tag {
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.24em;
  font-size: 0.62rem; color: var(--gold-soft); white-space: nowrap; margin: 0;
}
@media (max-width: 900px) { .nav-tag { display: none; } }
.nav-links { display: flex; gap: 2.2rem; list-style: none; margin: 0; padding: 0; }
.nav-links a {
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.2em;
  font-size: 0.68rem; text-decoration: none; color: var(--ivory-dim);
  transition: color 0.3s ease; padding-bottom: 2px; border-bottom: 1px solid transparent;
}
.nav-links a:hover { color: var(--gold); border-bottom-color: var(--gold); }

/* ---------- MOBILE NAVIGATION ----------
   Below 720px the inline link bar is replaced by a full-screen panel. The
   toggle and panel are built by theme.js from the header's own links, so the
   markup stays editable and there is only one list to maintain. */
.nav-toggle { display: none; }

@media (max-width: 720px) {
  .nav-links { display: none; }

  .nav-toggle {
    display: flex; align-items: center; justify-content: center;
    position: relative;
    width: 44px; height: 44px;            /* full touch target */
    margin: -0.5rem -0.5rem -0.5rem 0;
    padding: 0; border: 0; background: none; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  /* Three hairlines: the middle one is the element, the outer two pseudos. */
  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after {
    content: ""; display: block; position: absolute;
    width: 26px; height: 1px; background: var(--gold);
    transition: transform 0.34s cubic-bezier(.2,.7,.2,1), opacity 0.2s ease;
  }
  .nav-toggle-bars::before { transform: translateY(-8px); }
  .nav-toggle-bars::after  { transform: translateY(8px); }

  .nav-toggle.is-open .nav-toggle-bars { background: transparent; }
  .nav-toggle.is-open .nav-toggle-bars::before { transform: rotate(45deg); }
  .nav-toggle.is-open .nav-toggle-bars::after  { transform: rotate(-45deg); }

  .nav-toggle:focus-visible { outline: 1px solid var(--gold); outline-offset: 6px; }
}

/* z-index sits *below* the nav's 50 on purpose: the nav is position:fixed and
   creates its own stacking context, so a higher z-index on the button inside
   it cannot lift it above a panel that also sits at 50. Keeping the panel
   underneath leaves the wordmark and the close button visible and clickable. */
.nav-panel {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(90% 70% at 50% 30%, rgba(122,31,53,0.42), transparent 62%),
    linear-gradient(170deg, #1b0d14 0%, #100a0d 100%);
  opacity: 0;
  transition: opacity 0.32s ease;
}
.nav-panel.is-open { opacity: 1; }
.nav-panel[hidden] { display: none; }

.nav-panel-inner { width: 100%; padding: 0 var(--edge); }

.nav-panel-links { list-style: none; margin: 0; padding: 0; text-align: center; }
.nav-panel-links li { border-bottom: 1px solid var(--hairline); }
.nav-panel-links li:first-child { border-top: 1px solid var(--hairline); }
.nav-panel-links a {
  display: block; padding: 1.25rem 0.5rem;
  font-family: var(--serif); font-size: 1.6rem; letter-spacing: 0.02em;
  color: var(--ivory); text-decoration: none;
  opacity: 0; transform: translateY(14px);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(.2,.7,.2,1), color 0.3s ease;
}
.nav-panel.is-open .nav-panel-links a { opacity: 1; transform: none; }
/* Stagger, so the list settles rather than snapping in. */
.nav-panel.is-open li:nth-child(1) a { transition-delay: 0.06s; }
.nav-panel.is-open li:nth-child(2) a { transition-delay: 0.12s; }
.nav-panel.is-open li:nth-child(3) a { transition-delay: 0.18s; }
.nav-panel.is-open li:nth-child(4) a { transition-delay: 0.24s; }
.nav-panel.is-open li:nth-child(5) a { transition-delay: 0.30s; }
.nav-panel-links a:hover,
.nav-panel-links a:focus-visible { color: var(--gold); }
.nav-panel-links a:focus-visible { outline: 1px solid var(--gold); outline-offset: -4px; }

/* Stop the page scrolling behind the open panel. */
body.nav-open { overflow: hidden; }

/* ---------- HERO ---------- */
.hero {
  position: relative; min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 8rem var(--edge) 4rem;
  overflow: hidden;
}
/* Hero atmospherics are pure decoration, so they live in CSS rather than as
   empty divs in the markup - that keeps them out of the block editor, where
   they were only ever clutter she could delete by accident. */
.hero::before {   /* glow */
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  /* Anchored to the hero's top edge, not a percentage of its height. At `top:
     42%` this 90vmax element moved whenever the hero's height changed - which
     it does on a phone the moment the wordmark font swaps in - and a shift
     that large scored 0.171 CLS on its own. Anchored here it cannot move. */
  width: 90vmax; height: 90vmax; left: 50%; top: 0;
  transform: translate(-50%, -8%);
  background:
    radial-gradient(circle at 50% 50%, rgba(122,31,53,0.55) 0%, rgba(122,31,53,0.18) 32%, transparent 62%),
    radial-gradient(circle at 62% 40%, rgba(156,42,69,0.30) 0%, transparent 45%);
  filter: blur(10px);
  animation: drift 18s ease-in-out infinite alternate;
}
.hero::after {    /* vignette */
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 30%, transparent 40%, rgba(10,5,8,0.72) 100%);
}
@keyframes drift {
  from { transform: translate(-52%, -10%) scale(1); }
  to   { transform: translate(-48%, -4%) scale(1.12); }
}
.hero-inner {
  position: relative; z-index: 2; width: 100%; max-width: 1300px; margin: 0 auto;
  display: grid; grid-template-columns: 1.5fr 0.85fr; gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
.hero-text { min-width: 0; text-align: center; }
.hero-portrait {
  position: relative; aspect-ratio: 3 / 4; align-self: center; margin: 0;
  margin-top: calc(clamp(1.5rem, 5vh, 4rem) + 0.5in);
  border: 1px solid var(--gold-soft); overflow: hidden;
  box-shadow: 0 30px 80px -30px rgba(0,0,0,0.8);
  display: flex; align-items: flex-end;
  transform: scaleY(1.1); transform-origin: bottom center;
}
.hero-portrait .ph {
  position: relative; z-index: 1; width: 100%; padding: 1rem; margin: 0;
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.24em;
  font-size: 0.6rem; color: var(--blush);
  background: linear-gradient(to top, rgba(15,8,11,0.7), transparent);
}
.hero-portrait::before {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(75% 55% at 40% 25%, rgba(156,42,69,0.5), transparent 60%),
    radial-gradient(70% 70% at 70% 85%, rgba(122,31,53,0.4), transparent 55%),
    linear-gradient(160deg, #2c1722 0%, #150b11 100%);
}
/* The frame is a flex container so the placeholder caption can sit at the
   bottom; an Image block dropped in its place has to stretch to fill instead. */
.hero-portrait .wp-block-image { position: relative; z-index: 1; width: 100%; align-self: stretch; margin: 0; }
.hero-portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 860px) {
  .hero-inner { grid-template-columns: 1fr; }
  /* The portrait used to be hidden entirely on mobile, which removed the
     single most important image on the page for most visitors. Show it under
     the wordmark instead, at a size that does not push the tagline off screen. */
  .hero-portrait {
    max-width: 300px; margin: 2.5rem auto 0;
    transform: none;   /* the desktop scaleY stretch reads as distortion small */
  }
  /* ...except as a backdrop, where it must stay full bleed. */
  .hero-style-background .hero-portrait { max-width: none; margin: 0; }
}
/* The wordmark is two separate blocks rather than one heading with a nested
   span: the block editor strips spans it does not recognise as a format, so a
   single-heading version would lose its gold second line the first time anyone
   edited it. Two blocks also let her retitle each line independently. */
.hero-line-1, .hero-line-2 {
  font-family: var(--script); font-weight: 400;
  font-size: clamp(3.1rem, 9vw, 7.7rem);
  line-height: 1.26; letter-spacing: 0.01em;
  margin: 0;
}
/* nowrap so the line count cannot change between the fallback and the real
   script face on a narrow screen, which is the other way a swap could move the
   hero. Measured to fit at 320px, the narrowest phone worth supporting. */
.hero-line-1, .hero-line-2 { white-space: nowrap; }
.hero-line-1 { margin-top: 0.45em; }
.hero-line-2 { font-style: normal; color: var(--gold); margin-top: 0.12em; transform: translateY(5mm); }
.hero-tag {
  margin: 3.6rem auto 0; max-width: 34ch;
  font-size: clamp(1.1rem, 1vw + 0.9rem, 1.4rem);
  color: var(--ivory-dim); line-height: 1.6;
}
.scroll-cue {
  position: absolute; bottom: 2.2rem; left: var(--edge); z-index: 2; margin: 0;
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.28em;
  font-size: 0.62rem; color: var(--gold-soft);
  display: flex; align-items: center; gap: 0.8rem;
}
.scroll-cue::before { content: ""; width: 46px; height: 1px; background: var(--gold-soft); animation: pull 2.4s ease-in-out infinite; transform-origin: left; }
@keyframes pull { 0%,100% { transform: scaleX(0.4); opacity: 0.5; } 50% { transform: scaleX(1); opacity: 1; } }

/* ---------- HERO LAYOUTS ----------
   Two looks from identical markup, chosen at Settings > General. Because only
   CSS differs, switching never touches her content and is always reversible.
   `background` is the shipped default. `classic` has no rules of its own
   because the base hero CSS above *is* the classic layout - so the default
   costs one extra body class, not a second copy of the hero. */

/* BACKGROUND - photo fills the hero behind the wordmark.
   .hero-inner drops to position:static so the portrait's inset:0 resolves
   against .hero (full bleed) rather than the 1300px inner column.
   Height is set explicitly rather than left to the insets: with a replaced
   image inside, `height:auto` was resolving from the image's intrinsic size
   and overflowing the hero by more than double. */
.hero-style-background .hero-inner { position: static; max-width: none; grid-template-columns: 1fr; }
.hero-style-background .hero-text { position: relative; z-index: 2; text-align: center; }
.hero-style-background .hero-portrait {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; max-width: none; aspect-ratio: auto;
  margin: 0; border: 0; box-shadow: none; transform: none;
  display: block; overflow: hidden;
}
.hero-style-background .hero-portrait::before { opacity: 0.35; }
.hero-style-background .hero-portrait .wp-block-image { width: 100%; height: 100%; margin: 0; }
.hero-style-background .hero-portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The caption is a placeholder prompt; meaningless once it is a backdrop. */
.hero-style-background .hero-portrait .ph { display: none; }
/* Deepen the vignette so the wordmark stays legible over any photo. */
.hero-style-background .hero::after {
  background: radial-gradient(120% 90% at 50% 30%, rgba(10,5,8,0.42), rgba(10,5,8,0.86) 100%);
}

/* ---------- SECTION SHELL ---------- */
.section { position: relative; padding: clamp(4.5rem, 10vw, 9rem) var(--edge); }
.section-head { display: flex; align-items: baseline; gap: 1rem; margin-bottom: 3rem; }
.section-head .eyebrow::before { content: "\275B  "; color: var(--oxblood-lit); }

/* ---------- INTRODUCTION ---------- */
.intro { background: var(--ground-2); }
.intro-grid { display: grid; grid-template-columns: 0.8fr 1.4fr; gap: clamp(2rem, 5vw, 5rem); align-items: start; }
@media (max-width: 820px) { .intro-grid { grid-template-columns: 1fr; } }
.intro h2 { font-size: clamp(2rem, 4vw, 3.2rem); line-height: 1.05; }
.intro h2 em { color: var(--gold); font-style: italic; }
/* :not(.eyebrow) throughout: the section eyebrows are paragraphs now, so a
   bare descendant `p` rule silently repaints them body-colour. */
.intro p:not(.eyebrow) { max-width: var(--measure); color: var(--ivory-dim); }
.intro p:not(.eyebrow) + p:not(.eyebrow) { margin-top: 1.3rem; }
.intro .lead { color: var(--ivory); }
.signature { font-family: var(--serif); font-style: italic; font-size: 1.9rem; color: var(--gold); margin-top: 2rem; }

/* ---------- GALLERY CAROUSEL ---------- */
.carousel { position: relative; max-width: 1160px; margin: 0 auto; }
.carousel-viewport { overflow: hidden; }
.carousel-track { display: flex; transition: transform 0.95s cubic-bezier(.19,.72,.16,1); }
.slide {
  flex: 0 0 100%; display: flex; justify-content: center;
  padding: 0 clamp(0.5rem, 4vw, 3.5rem);
}
.frame {
  position: relative; width: 100%; max-width: 430px; aspect-ratio: 3 / 4;
  overflow: hidden; background: var(--panel);
  display: flex; align-items: flex-end;
  box-shadow: 0 40px 90px -40px rgba(0,0,0,0.85);
}
.frame::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(80% 60% at 30% 20%, rgba(156,42,69,0.42), transparent 60%),
    radial-gradient(70% 70% at 75% 80%, rgba(122,31,53,0.30), transparent 55%),
    linear-gradient(160deg, #2a1620 0%, #170c12 100%);
}
.frame img { position: relative; z-index: 1; width: 100%; height: 100%; object-fit: cover; display: block; }
.frame .ph {
  position: relative; z-index: 1; width: 100%;
  padding: 1.4rem 1.2rem 1rem; font-family: var(--label); text-transform: uppercase;
  letter-spacing: 0.24em; font-size: 0.6rem; color: var(--blush);
  background: linear-gradient(to top, rgba(15,8,11,0.82), transparent);
}
.carousel-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 3rem; height: 3rem; border: 1px solid var(--gold-soft); border-radius: 50%;
  background: rgba(20,10,15,0.55); color: var(--gold); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--serif); font-size: 1.3rem; line-height: 1;
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease;
  backdrop-filter: blur(4px);
}
.carousel-arrow:hover { background: var(--gold); color: var(--ground); }
.carousel-arrow.prev { left: clamp(-0.5rem, 2vw, 1.5rem); }
.carousel-arrow.next { right: clamp(-0.5rem, 2vw, 1.5rem); }
.carousel-arrow:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.carousel-foot {
  display: flex; align-items: center; justify-content: center; gap: 1.5rem;
  margin-top: 2rem;
}
.carousel-count {
  font-family: var(--serif); font-size: 1.05rem; color: var(--gold);
  font-variant-numeric: tabular-nums; letter-spacing: 0.08em; min-width: 5.5rem; text-align: center;
}
.carousel-dots { display: flex; gap: 0.7rem; }
.carousel-dots button {
  width: 26px; height: 2px; padding: 0; border: 0; cursor: pointer;
  background: var(--hairline); transition: background 0.4s ease;
}
.carousel-dots button[aria-current="true"] { background: var(--gold); }
.carousel-dots button:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }
.gallery-note {
  margin-top: 1.6rem; text-align: center; font-family: var(--label); font-size: 0.72rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--gold-soft);
}

/* ---------- LIGHTBOX ---------- */
.lightbox {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(8, 4, 6, 0.94);
  opacity: 0; transition: opacity 0.26s ease;
}
.lightbox.is-open { opacity: 1; }
.lightbox[hidden] { display: none; }
.lightbox-img {
  max-width: 100%; max-height: 100%;
  object-fit: contain; display: block;
  border: 1px solid var(--hairline);
  box-shadow: 0 40px 90px -40px rgba(0,0,0,0.9);
}
.lightbox-close {
  position: absolute; top: clamp(0.75rem, 3vw, 1.75rem); right: clamp(0.75rem, 3vw, 1.75rem);
  width: 44px; height: 44px; padding: 0;
  background: none; border: 1px solid var(--hairline); border-radius: 50%;
  color: var(--gold); font-size: 1.5rem; line-height: 1; cursor: pointer;
  transition: border-color 0.3s ease, color 0.3s ease;
}
.lightbox-close:hover { border-color: var(--gold); }
.lightbox-close:focus-visible { outline: 1px solid var(--gold); outline-offset: 3px; }

/* ---------- ENGAGEMENTS ---------- */
.engagements { background: var(--ground-2); }
.rate-list { display: flex; flex-direction: column; gap: 0; max-width: 900px; }
.rate {
  display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 1.5rem;
  padding: 1.7rem 0; border-top: 1px solid var(--hairline);
}
.rate:last-child { border-bottom: 1px solid var(--hairline); }
.rate-name { font-family: var(--serif); font-size: clamp(1.4rem, 2.5vw, 2rem); }
.rate-name small { display: block; font-family: var(--label); text-transform: uppercase; letter-spacing: 0.2em; font-size: 0.62rem; color: var(--ivory-dim); margin-top: 0.5rem; }
.rate-price { font-family: var(--serif); font-size: clamp(1.4rem, 2.5vw, 2rem); color: var(--gold); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rate-foot { margin-top: 2rem; color: var(--ivory-dim); font-size: 0.95rem; max-width: var(--measure); }

/* ---------- AVAILABILITY (optional section) ----------
   Shares the rate list's shape on purpose: two sections that both read as
   "label on the left, value on the right" should look like siblings, and it
   means she only has one editing habit to learn for both.

   No background band, so it takes the page colour and alternates correctly
   whichever side of an .engagements or .intro block she drops it. */
.avail-status {
  margin: 0 0 2.5rem; max-width: var(--measure);
  font-family: var(--serif); font-size: clamp(1.25rem, 2.2vw, 1.7rem);
  line-height: 1.4; color: var(--ivory);
}
.avail-status em { color: var(--gold); font-style: italic; }
.tour-list { display: flex; flex-direction: column; gap: 0; max-width: 900px; }
.tour {
  display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 1.5rem;
  padding: 1.5rem 0; border-top: 1px solid var(--hairline);
}
.tour:last-child { border-bottom: 1px solid var(--hairline); }
.tour-place { font-family: var(--serif); font-size: clamp(1.3rem, 2.2vw, 1.75rem); margin: 0; }
.tour-place small {
  display: block; font-family: var(--label); text-transform: uppercase;
  letter-spacing: 0.2em; font-size: 0.62rem; color: var(--ivory-dim); margin-top: 0.5rem;
}
.tour-dates {
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.14em;
  font-size: 0.74rem; color: var(--gold); white-space: nowrap; margin: 0;
}
/* Dates are free text, so they run longer than a price ever does. Below this
   the two columns start colliding, so stack them and let the date wrap. */
@media (max-width: 560px) {
  .tour { grid-template-columns: 1fr; gap: 0.4rem; }
  .tour-dates { white-space: normal; }
}
.tour-foot { margin-top: 2rem; color: var(--ivory-dim); font-size: 0.95rem; max-width: var(--measure); }

/* ---------- IMPRESSIONS / TESTIMONIALS (optional section) ----------
   Selectors are doubled up (.testimonials .tstm rather than .tstm) to outrank
   core's block-library quote styling, which sets its own border-left, padding
   and margins. Equal specificity would leave the winner decided by stylesheet
   order, which is not ours to control. */
.testimonials { background: var(--ground-2); }
.tstm-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 4vw, 3rem); }
@media (max-width: 900px) { .tstm-grid { grid-template-columns: 1fr; } }
.testimonials .tstm {
  position: relative; margin: 0; padding: 2.4rem 1.9rem 2rem;
  background: var(--panel); border: 1px solid var(--hairline); border-left-width: 1px;
}
/* The opening quotation mark, set large and low-contrast as an ornament. */
.testimonials .tstm::before {
  content: "\201C"; position: absolute; top: 0.35rem; left: 1.1rem;
  font-family: var(--serif); font-size: 4.5rem; line-height: 1;
  color: var(--oxblood-lit); opacity: 0.55; pointer-events: none;
}
.testimonials .tstm p {
  position: relative; margin: 0;
  font-family: var(--serif); font-style: italic;
  font-size: 1.05rem; line-height: 1.7; color: var(--ivory);
}
.testimonials .tstm cite {
  display: block; margin-top: 1.5rem; font-style: normal;
  font-family: var(--label); text-transform: uppercase;
  letter-spacing: 0.2em; font-size: 0.62rem; color: var(--gold-soft);
}
.tstm-foot {
  margin-top: 2.2rem; color: var(--ivory-dim);
  font-size: 0.88rem; max-width: var(--measure);
}

/* ---------- ETIQUETTE ---------- */
.etq-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 4vw, 3.5rem); }
@media (max-width: 820px) { .etq-grid { grid-template-columns: 1fr; } }
.etq h3 { font-size: 1.5rem; margin-bottom: 0.8rem; color: var(--ivory); }
.etq h3 .num { font-family: var(--label); font-size: 0.7rem; letter-spacing: 0.2em; color: var(--oxblood-lit); display: block; margin-bottom: 0.7rem; }
.etq p:not(.eyebrow) { color: var(--ivory-dim); font-size: 0.98rem; max-width: 40ch; }
/* The 40ch measure keeps lines readable in the three-column desktop grid, but
   on one column it is narrower than the screen and reads as a right-hand gap. */
@media (max-width: 820px) {
  .etq p:not(.eyebrow) { max-width: none; }
}

/* ---------- ENQUIRY ---------- */
.enquiry { background: var(--ground-2); }
.enquiry-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 6vw, 5rem); align-items: start; }
@media (max-width: 820px) { .enquiry-grid { grid-template-columns: 1fr; } }
.enquiry h2 { font-size: clamp(2rem, 4vw, 3rem); line-height: 1.05; margin-bottom: 1.4rem; }
.enquiry h2 em { color: var(--gold); font-style: italic; }
.enquiry .intro-note { color: var(--ivory-dim); max-width: 46ch; }
/* Each contact row is a label block + a value block rather than one line with
   a nested span, for the same reason as the hero wordmark - and it means the
   labels themselves are editable. */
.contact-line { margin-top: 2.2rem; display: flex; flex-direction: column; gap: 0.9rem; }
/* margin: 0 because .contact-line spaces its rows with `gap`; core's flow
   layout would otherwise add its own 24px on top and double the pitch. */
.contact-row { display: flex; gap: 0.9rem; align-items: center; margin: 0; }
.contact-row .lbl {
  font-family: var(--label); color: var(--gold-soft); text-transform: uppercase;
  font-size: 0.64rem; letter-spacing: 0.2em; min-width: 5.5rem; margin: 0;
}
.contact-value {
  font-family: var(--label); letter-spacing: 0.12em;
  color: var(--ivory); font-size: 0.95rem; margin: 0;
}
.contact-value a { text-decoration: none; color: inherit; }
.enquiry-eyebrow { margin-bottom: 1.4rem; }
form.enquiry-form { display: flex; flex-direction: column; gap: 1.1rem; }
.field { display: flex; flex-direction: column; gap: 0.5rem; }
.field label { font-family: var(--label); text-transform: uppercase; letter-spacing: 0.2em; font-size: 0.62rem; color: var(--gold-soft); }
.field input, .field textarea, .field select {
  background: var(--ground); border: 1px solid var(--hairline); color: var(--ivory);
  font-family: var(--body); font-size: 1rem; padding: 0.85rem 1rem; border-radius: 0;
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold);
}
.field textarea { resize: vertical; min-height: 120px; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
@media (max-width: 480px) { .row { grid-template-columns: 1fr; } }
button.submit {
  margin-top: 0.6rem; align-self: flex-start;
  background: transparent; color: var(--gold); border: 1px solid var(--gold);
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.24em; font-size: 0.72rem;
  padding: 1rem 2.4rem; cursor: pointer; transition: all 0.35s ease;
}
button.submit:hover { background: var(--gold); color: var(--ground); }
button.submit:focus-visible { outline: 1px solid var(--gold); outline-offset: 4px; }

/* ---------- CUSTOM SELECT ----------
   The native control is kept in the DOM for submission and validation but
   visually removed; theme.js draws this listbox over the top. */
.select { position: relative; }
.select .select-native.is-enhanced {
  position: absolute; opacity: 0; pointer-events: none;
  width: 1px; height: 1px; padding: 0; margin: 0; border: 0;
}
.select-button {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; cursor: pointer; text-align: left;
  background: var(--ground); border: 1px solid var(--hairline); border-radius: 0;
  color: var(--ivory); font-family: var(--body); font-size: 1rem;
  padding: 0.85rem 1rem;
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.select-button:hover { border-color: var(--gold-soft); }
.select-button:focus-visible,
.select.is-open .select-button {
  outline: none; border-color: var(--gold);
  box-shadow: 0 0 0 1px rgba(201,169,106,0.35);
}
.select-caret {
  width: 7px; height: 7px; flex: 0 0 auto; margin-bottom: 3px;
  border-right: 1px solid var(--gold); border-bottom: 1px solid var(--gold);
  transform: rotate(45deg); transition: transform 0.3s ease;
}
.select.is-open .select-caret { transform: rotate(-135deg); margin-bottom: -3px; }

.select-list {
  position: absolute; z-index: 20; top: calc(100% + 6px); left: 0; right: 0;
  margin: 0; padding: 0.4rem 0; list-style: none;
  background: #1a0e14; border: 1px solid var(--gold-soft);
  box-shadow: 0 26px 60px -24px rgba(0,0,0,0.9);
  max-height: min(20rem, 50vh); overflow-y: auto;
}
.select-list[hidden] { display: none; }
.select-option {
  padding: 0.7rem 1rem; cursor: pointer;
  font-family: var(--body); font-size: 0.98rem; color: var(--ivory-dim);
  transition: background 0.2s ease, color 0.2s ease;
}
.select-option:hover,
.select-option:focus { outline: none; background: rgba(201,169,106,0.10); color: var(--ivory); }
.select-option[aria-selected="true"] { color: var(--gold); }
.select-option[aria-selected="true"]::after {
  content: "\2022"; float: right; color: var(--gold);
}

/* Honeypot: off-screen rather than display:none, which some bots detect. */
.ad-hp {
  position: absolute !important; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.field-consent { margin: 0; }
.field-consent label {
  display: flex; align-items: flex-start; gap: 0.7rem; cursor: pointer;
  font-family: var(--label); font-size: 0.72rem; line-height: 1.7;
  letter-spacing: 0.06em; color: var(--ivory-dim);
}
/* Custom checkbox: the native box is hidden but still focusable and still
   carries `required`, so validation and keyboard use are untouched. */
.field-consent input[type="checkbox"] {
  position: absolute; opacity: 0; width: 17px; height: 17px; margin: 0;
}
.field-consent .box {
  position: relative; flex: 0 0 auto; margin-top: 0.2em;
  width: 17px; height: 17px;
  border: 1px solid var(--gold-soft); background: var(--ground);
  transition: border-color 0.3s ease, background 0.3s ease;
}
.field-consent .box::after {
  content: ""; position: absolute; left: 5px; top: 1px;
  width: 5px; height: 10px;
  border-right: 1px solid var(--ground); border-bottom: 1px solid var(--ground);
  transform: rotate(45deg) scale(0.6); transform-origin: center;
  opacity: 0; transition: opacity 0.2s ease, transform 0.2s cubic-bezier(.2,.7,.2,1);
}
.field-consent label:hover .box { border-color: var(--gold); }
.field-consent input:checked ~ .box { background: var(--gold); border-color: var(--gold); }
.field-consent input:checked ~ .box::after { opacity: 1; transform: rotate(45deg) scale(1); }
.field-consent input:focus-visible ~ .box {
  outline: 1px solid var(--gold); outline-offset: 3px;
}
.field-consent a { color: var(--gold); }

.form-notice {
  margin: 0; padding: 0.9rem 1rem; border: 1px solid var(--hairline);
  font-family: var(--label); font-size: 0.74rem; letter-spacing: 0.1em;
  line-height: 1.6;
}
.form-notice.is-good { border-color: var(--gold-soft); color: var(--gold); }
.form-notice.is-bad { border-color: var(--oxblood-lit); color: var(--blush); }

/* ---------- SECONDARY PAGES ----------
   404, search, archives, single posts and generic pages. The home page is the
   whole product here, so these are deliberately quiet: same palette and type,
   no atmospherics competing with it. */
.page-shell {
  max-width: 860px; margin: 0 auto;
  padding: calc(7rem + 4vw) var(--edge) clamp(5rem, 10vw, 8rem);
  min-height: 60vh;
}
.page-head { margin-bottom: 3rem; }
.page-head .eyebrow { margin-bottom: 1.2rem; }
.page-title {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(2.3rem, 4.5vw, 3.6rem); line-height: 1.15;
  margin: 0;
}
.page-title em { color: var(--gold); font-style: italic; }
.page-lede { color: var(--ivory-dim); max-width: var(--measure); margin: 1.6rem 0 0; }

.page-actions { margin-top: 2.6rem; }
.page-actions a {
  display: inline-block; padding: 0.9rem 2rem;
  border: 1px solid var(--gold-soft); color: var(--gold);
  font-family: var(--label); text-transform: uppercase;
  letter-spacing: 0.24em; font-size: 0.68rem; text-decoration: none;
  transition: background 0.35s ease, color 0.35s ease;
}
.page-actions a:hover { background: var(--gold); color: var(--ground); }

.page-body > * { margin-block: 1.5rem; }
.page-body > *:first-child { margin-block-start: 0; }
.page-feature { margin-bottom: 2.5rem; }
.page-feature img { width: 100%; height: auto; display: block; border: 1px solid var(--hairline); }

/* Post listings */
.post-list .wp-block-post-template { list-style: none; margin: 0; padding: 0; }
.post-list li { padding: 2.2rem 0; border-top: 1px solid var(--hairline); }
.post-list li:last-child { border-bottom: 1px solid var(--hairline); }
.post-list-title { font-family: var(--serif); font-size: 1.6rem; line-height: 1.3; margin: 0; }
.post-list-title a { text-decoration: none; transition: color 0.3s ease; }
.post-list-title a:hover { color: var(--gold); }
.post-list-date {
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.2em;
  font-size: 0.62rem; color: var(--gold-soft); margin: 0.7rem 0 0;
}
.post-list-excerpt { color: var(--ivory-dim); margin: 0.9rem 0 0; max-width: var(--measure); }

/* Search field + pagination */
.page-search { margin-bottom: 3rem; }
.page-search .wp-block-search__label {
  display: block; margin-bottom: 0.5rem;
  font-family: var(--label); font-weight: 400; text-transform: uppercase;
  letter-spacing: 0.2em; font-size: 0.62rem; color: var(--gold-soft);
}
.page-search .wp-block-search__input {
  background: var(--ground); border: 1px solid var(--hairline); color: var(--ivory);
  font-family: var(--body); font-size: 1rem; padding: 0.85rem 1rem; border-radius: 0;
}
.page-search .wp-block-search__button {
  background: none; border: 1px solid var(--gold-soft); color: var(--gold);
  font-family: var(--label); text-transform: uppercase; letter-spacing: 0.2em;
  font-size: 0.66rem; padding: 0.85rem 1.6rem; border-radius: 0; cursor: pointer;
  transition: background 0.35s ease, color 0.35s ease;
}
.page-search .wp-block-search__button:hover { background: var(--gold); color: var(--ground); }

.page-pagination {
  display: flex; gap: 1.4rem; align-items: center; flex-wrap: wrap;
  margin-top: 3rem; font-family: var(--label);
  text-transform: uppercase; letter-spacing: 0.2em; font-size: 0.66rem;
}
.page-pagination a { text-decoration: none; color: var(--ivory-dim); transition: color 0.3s ease; }
.page-pagination a:hover { color: var(--gold); }
.page-pagination .current { color: var(--gold); }

/* ---------- FOOTER ---------- */
.site-footer { padding: 3.5rem var(--edge); text-align: center; border-top: 1px solid var(--hairline); }
.site-footer .wordmark { font-size: 2.2rem; margin-bottom: 1rem; }
/* :not(.wordmark) because the footer wordmark is now a paragraph too, and this
   rule would otherwise override its script face with the uppercase label one. */
.site-footer p:not(.wordmark) { font-family: var(--label); text-transform: uppercase; letter-spacing: 0.18em; font-size: 0.62rem; color: var(--ivory-dim); margin: 0.4rem 0; }
.site-footer .age { color: var(--gold-soft); }

/* ---------- REVEAL ----------
   Gated on .has-js, which an inline snippet in <head> sets. Without that gate
   a JS failure - or a blocked script - left most of the page permanently at
   opacity 0, i.e. invisible to the visitor. Default is now visible, and the
   animation is opt-in. */
.has-js .reveal { opacity: 0; transform: translateY(28px); transition: opacity 1s ease, transform 1s cubic-bezier(.2,.7,.2,1); }
.has-js .reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .hero::before, .scroll-cue::before { animation: none; }
  .has-js .reveal { opacity: 1; transform: none; transition: none; }
  .nav-panel, .nav-panel-links a, .nav-toggle-bars,
  .nav-toggle-bars::before, .nav-toggle-bars::after { transition: none; }
  * { scroll-behavior: auto !important; }
}
html { scroll-behavior: smooth; }

/* Neutralise WP defaults that would fight the design.
   Wrapped in :where() so they carry zero specificity. Without it these sit
   later in the file than the component rules and silently win - which is
   exactly what flattened .section-head's margin-bottom and .contact-line's
   margin-top once those became Group blocks. */
:where(.wp-block-group) { margin: 0; }
:where(figure) { margin: 0; }
