/* ---------------------------------------------------------------
   Self-hosted webfonts.

   These used to load from fonts.googleapis.com. The font FILES were
   never the problem -- font-display:swap means they do not block text.
   The problem was the Google STYLESHEET: a render-blocking request that
   made the critical chain three deep (HTML -> googleapis css -> gstatic
   woff2). Moving the @font-face rules in here removes that hop entirely,
   because this file is already being fetched.

   Relocating the request to our own domain would NOT have helped: our
   origin TTFB is 441ms against Google's 235ms. The win is removing the
   request, not moving it.

   Only latin and latin-ext are included. The site is EN/FR/ES/DE, so the
   cyrillic, cyrillic-ext and vietnamese blocks Google serves are dead
   weight. unicode-range is copied verbatim from Google so the browser
   still fetches latin-ext only when a page actually needs it -- that is
   what keeps the real download near 58KB rather than the full 117KB.

   Plus Jakarta Sans is a variable font: 400, 600 and 700 all point at the
   same file, which is why there are 8 files and not 12.

   Licence: Anton, Plus Jakarta Sans and IBM Plex Mono are all released
   under the SIL Open Font License 1.1, which permits self-hosting.
   Full licence text: assets/fonts/OFL.txt
   --------------------------------------------------------------- */
@font-face{font-family:'Anton';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/anton-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Anton';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/anton-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/ibmplexmono-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/ibmplexmono-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/ibmplexmono-600-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/ibmplexmono-600-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/plusjakartasans-var-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/plusjakartasans-var-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/plusjakartasans-var-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/plusjakartasans-var-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:700;font-display:swap;src:url('../fonts/plusjakartasans-var-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:700;font-display:swap;src:url('../fonts/plusjakartasans-var-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}

/* ===================== TAGHAZOUT SURF TRIP — DESIGN SYSTEM ===================== */
:root{
  /* Palette "Taghazout Dusk". Warms and lifts the dark end so sections separate:
     the previous base and card tones (#031221 / #052442) sat so close that cards
     disappeared into the section behind them, and --teal-800 was a saturated
     corporate blue that competed with the photography instead of framing it.
     --terracotta is deliberately deeper than it looks like it wants to be: it is
     used as text on white in .pullquote, where the brighter #FF6B35 measured
     2.84:1 and failed the 3:1 large-text floor. #D64A20 gives 4.32:1. The vivid
     warm tone lives in --coral, which only ever appears on dark. */
  --teal-950:#101E2B;
  --teal-900:#1A2E40;
  --teal-800:#234156;
  --teal-700:#2E5A73;
  --teal-500:#3E7FA6;
  --teal-300:#8FB8D0;
  --sand-100:#FAF4EA;
  --sand-200:#F0E3CD;
  /* 2026-09-20 colour roles (gold-500 = action fill, gold-700 = gold as text on light, rust = small
     marks on light, coral = display on dark): docs/MOTION.md + worklogs/visual-upgrade-diagnosis-20260920.md */
  --gold-500:#F5B942;
  --gold-400:var(--gold-500);
  --rust:#B8452A;
  --gold-600:var(--rust);
  --gold-700:#8F5C00;   /* re-pinned 2026-09-23 (P1): 5.68:1 white, 5.19 sand-100, 4.48 sand-200 */
  --gold-deep:#DFA02B;
  --terracotta:#D64A20;
  --coral:#FF8A63;
  --ink-900:#131C24;
  --ink-600:#4C5A66;
  --white:#FFFFFF;
  --danger:#C0392B;
  --danger-deep:#8E2B20;   /* text on the tint: 6.28:1 (danger itself is 4.09:1 there) */
  --danger-tint:#F6D9D4;

  --font-display:'Anton', sans-serif;
  --font-body:'Plus Jakarta Sans', sans-serif;
  --font-mono:'IBM Plex Mono', monospace;

  --radius-tag: 4px 20px 4px 20px;
  --radius-tag-sm: 3px 12px 3px 12px;
  --container: 1200px;
  --container-narrow: 780px;
  --z-nav: 900;
  --z-overlay: 950;
}

*{box-sizing:border-box; margin:0; padding:0;}
html{scroll-behavior:smooth;}
body{
  font-family:var(--font-body);
  color:var(--ink-900);
  background:var(--sand-100);
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img,svg{max-width:100%; display:block;}
a{color:inherit; text-decoration:none;}
ul,ol{list-style:none;}
button{font-family:inherit; cursor:pointer; border:none; background:none;}
input,select,textarea{font-family:inherit; color:inherit;}
.wrap{max-width:var(--container); margin:0 auto; padding:0 24px;}
.wrap-narrow{max-width:var(--container-narrow); margin:0 auto; padding:0 24px;}


/* ---------- Accessibility ---------- */
.skip-link{
  position:fixed; top:-100px; left:16px; z-index:1200;
  background:var(--gold-500); color:var(--ink-900); padding:14px 22px;
  border-radius:var(--radius-tag-sm); font-weight:700;
}
.skip-link:focus{top:16px;}
:focus-visible{outline:3px solid var(--gold-500); outline-offset:3px; border-radius:3px;}

/* ---------- Progress bar ---------- */
/* Driven by transform:scaleX() from main.js, not width — scaling is handled
   on the compositor, whereas animating width relayouts the page every frame. */
.scroll-progress{
  position:fixed; top:0; left:0; height:3px; width:100%;
  transform:scaleX(0); transform-origin:0 50%;
  background:linear-gradient(90deg, var(--gold-500), var(--gold-400));
  z-index:1000; will-change:transform;
}

/* ---------- Nav ---------- */
.site-nav{
  position:fixed; top:0; left:0; right:0; z-index:var(--z-nav);
  padding:22px 0;
}
/* No backdrop-filter here: the background sits at .96 alpha, so a blur behind
   it would show through 4% — invisible, but it costs a real GPU pass every
   frame the nav is composited over scrolling content. */
.site-nav.scrolled{
  background:rgba(16,30,43,.96);
  padding:14px 0;
  box-shadow:0 8px 24px rgba(0,0,0,.25);
}
.nav-inner{display:flex; align-items:center; justify-content:space-between; gap:24px;}
.logo{display:flex; align-items:center; gap:10px; flex-shrink:0;}
.logo-mark{height:32px; width:auto; flex-shrink:0;}
.footer-brand{display:flex; align-items:center; gap:10px; margin-bottom:14px;}
.footer-brand .logo-mark{height:30px;}
.nav-links{display:flex; align-items:center; gap:22px;}
.nav-links a{
  font-size:14px; font-weight:600; color:var(--sand-100);
  opacity:.85; position:relative;
  padding-bottom:2px; border-bottom:1px solid transparent;
}
.nav-links a:not(.nav-cta){transition:opacity var(--dur) var(--ease-out);}
.nav-links a:hover{opacity:1; border-color:var(--gold-400);}
.nav-links a[aria-current="page"]{opacity:1; border-color:var(--gold-500);}
.nav-cta{
  display:inline-flex; align-items:center; line-height:1;
  font-family:var(--font-body); font-weight:700; font-size:13px;
  letter-spacing:.04em; text-transform:uppercase;
  background:var(--gold-500); color:var(--ink-900);
  padding:12px 22px; border-radius:var(--radius-tag-sm);
  white-space:nowrap;
}
.nav-cta:hover{background:var(--gold-deep); transform:translateY(-1px);}
.nav-links .nav-cta{padding-bottom:12px; border-bottom:none; color:var(--ink-900); opacity:1;}
.nav-toggle{
  display:none; flex-direction:column; align-items:center; justify-content:center;
  gap:5px; width:44px; height:44px; margin-right:-9px;
}
.nav-toggle span{width:26px; height:2px; background:var(--white); border-radius:2px;}
.mobile-menu{
  display:flex; position:fixed; inset:0; z-index:var(--z-overlay);
  background:var(--teal-950); padding:100px 24px 40px;
  flex-direction:column; gap:26px;
  transform:translateY(-100%);
  overflow-y:auto;
}
.mobile-menu.open{transform:translateY(0);}
.mobile-menu a{
  font-family:var(--font-display); font-weight:400; font-size:30px; color:var(--white);
  text-transform:uppercase;
}
.mobile-menu .nav-cta{align-self:flex-start; margin-top:12px; color:var(--ink-900) !important; font-size:14px; text-transform:uppercase;}
.mobile-close{position:absolute; top:26px; right:24px; color:var(--white); font-size:26px; width:44px; height:44px;}

.lang-switch{position:relative;}
.lang-switch button{
  display:flex; align-items:center; gap:6px; font-family:var(--font-mono); font-size:12px;
  letter-spacing:.06em; color:var(--sand-100); opacity:.85; border:1px solid rgba(255,255,255,.25);
  padding:9px 14px; border-radius:var(--radius-tag-sm);
}
.lang-switch button:hover{opacity:1; border-color:var(--gold-400);}
.lang-menu{
  position:absolute; top:calc(100% + 8px); right:0; background:var(--teal-900);
  border:1px solid rgba(255,255,255,.12); border-radius:var(--radius-tag-sm); padding:8px;
  min-width:170px; box-shadow:0 16px 32px rgba(0,0,0,.3);
  opacity:0; visibility:hidden;
}
.lang-switch[data-open="true"] .lang-menu{opacity:1; visibility:visible; transform:translateY(0);}
.lang-menu a{display:flex; justify-content:space-between; padding:9px 10px; border-radius:3px; font-size:13px; color:var(--sand-100);}
.lang-menu a:hover{background:rgba(255,255,255,.06); color:var(--gold-400);}

/* Six links plus the language switcher and CTA need ~1000px before the logo
   starts getting squeezed, so the burger takes over earlier than the 860px
   used elsewhere on the site. */
@media (max-width:900px){   /* P4: five links fit to 900px, so the burger fires there, not at 1080 */
  /* 2026-09-20: the Book pill stays on phones; the list dissolves (display:contents) and its other children hide. */
  .nav-links{display:contents;}
  .nav-links > :not(.nav-cta){display:none;}
  .nav-links > .nav-cta{margin-left:auto; min-height:44px; padding:0 14px; font-size:var(--fs-100);}
  .nav-inner{gap:12px;}
  .nav-toggle{display:flex;}
}
@media (max-width:640px){.logo-mark{height:26px;}}
@media (max-width:360px){.logo-mark{height:22px;}}
@media (max-width:340px){.nav-links > .nav-cta{padding:0 10px;}}

/* ---------- Buttons ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:10px;
  font-weight:700; font-size:14px; letter-spacing:.04em; text-transform:uppercase;
  padding:16px 30px; border-radius:var(--radius-tag); min-height:52px;
}
.btn:active{transform:scale(.97);}
.btn svg{width:16px; height:16px; flex-shrink:0;}
.btn-gold{background:var(--gold-500); color:var(--ink-900);}
.btn-gold:hover{background:var(--gold-deep); transform:translateY(-2px);}
.btn-outline{border:1.5px solid rgba(255,255,255,.4); color:var(--white);}
.btn-outline:hover{border-color:var(--gold-400); color:var(--gold-400);}
.btn-outline-dark{border:1.5px solid var(--ink-900); color:var(--ink-900);}
.btn-outline-dark:hover{background:var(--ink-900); color:var(--white);}
.btn-whatsapp{background:#25D366;}
.btn-whatsapp:hover{background:#1EBE5B; transform:translateY(-2px);}
.btn-link{padding:0; min-height:auto; border-radius:0; border-bottom:2px solid currentColor; font-weight:700; text-transform:none; letter-spacing:0; font-size:15px;}
.btn-link:hover{color:var(--gold-600);}
.btn-sm{padding:12px 22px; font-size:12px; min-height:44px;}

/* ---------- Eyebrow / labels ---------- */
.eyebrow{
  font-family:var(--font-mono); font-weight:600; font-size:12px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--gold-600);
  display:flex; align-items:center; gap:10px; margin-bottom:18px;
}
.eyebrow::before{content:''; width:26px; height:1.5px; background:var(--gold-600); flex-shrink:0;}
.eyebrow.on-dark{color:var(--gold-500);}
.eyebrow.is-centered::after{content:''; width:26px; height:1.5px; background:var(--gold-600); flex-shrink:0;}
.eyebrow.is-centered.on-dark::after{background:var(--gold-500);}
.eyebrow.on-dark::before{background:var(--gold-500);}

/* ---------- Hero ---------- */
/* .hero is a flex container (to vertically centre its content), which makes
   .wrap a flex item: without width:100% it shrink-wraps to its text and the
   `margin:0 auto` on .wrap then centres that shrunken box. The homepages and
   packages pages hid it because .hero-grid is wide enough to fill, but on the
   other 41 pages the breadcrumb, eyebrow and h1 floated into the middle of the
   page while the body below started at the gutter. */
.hero > .wrap{width:100%;}
.hero{
  position:relative; min-height:100vh; display:flex; align-items:center;
  background:radial-gradient(120% 90% at 15% 0%, #084887 0%, var(--teal-950) 55%);
  overflow:hidden; padding:140px 0 120px;
}
.hero h1{
  font-family:var(--font-display); font-weight:400; text-transform:uppercase;
  font-size:clamp(2.05rem, 6.2vw, 5.4rem); line-height:.94; letter-spacing:-.01em;
  color:var(--white); margin-bottom:26px;
}
.hero h1 span{color:var(--coral);}
/* Every .hero sits on the dark gradient, so a paragraph in one must not inherit
   the body's dark --ink-900. The EN, FR and DE packages heroes each carried an
   unstyled <p> that rendered dark-on-dark: invisible to visitors but readable by
   crawlers, which is wasted copy and reads as hidden keyword text. Scoped to the
   element rather than fixed in three files so it cannot come back. */
.hero p{color:var(--sand-200);}
.hero p.lead{
  font-size:18px; color:var(--sand-200); max-width:480px; margin-bottom:36px; line-height:1.65;
}
.hero-actions{display:flex; gap:18px; flex-wrap:wrap; margin-bottom:56px;}
/* 2x2, not a wrapping row. Each stat is as wide as its label, not its number
   ("7 nights, board incl. · 15% off" is 214px on its own), so all four across
   needs 655px — more than the column ever gets: 601px on desktop once the hero
   splits in two, 327px on a phone. Wrapping therefore left an orphan fourth
   stat at every width. A fixed 2x2 is even everywhere and holds in all four
   languages, where the labels differ in length. */
.hero-stats{display:grid; grid-template-columns:1fr 1fr; gap:22px 20px; max-width:480px;}
.hero-stat-num{font-family:var(--font-mono); font-size:26px; color:var(--gold-400); font-weight:600;}
.hero-stat-label{font-size:12px; color:var(--sand-200); opacity:.75; text-transform:uppercase; letter-spacing:.06em; margin-top:4px;}


/* ---------- Section base ---------- */
section{padding:110px 0;}
.section-dark{background:var(--teal-950); color:var(--sand-100);}
.section-mid{background:var(--teal-800); color:var(--sand-100);}
.section-light{background:var(--sand-100); color:var(--ink-900);}
.section-white{background:var(--white); color:var(--ink-900);}
h2.section-title{
  font-family:var(--font-display); font-weight:400; text-transform:uppercase;
  font-size:clamp(2rem, 4vw, 3.2rem); line-height:1; margin-bottom:20px; letter-spacing:-.01em;
}
h1.page-title{
  font-family:var(--font-display); font-weight:400; text-transform:uppercase;
  font-size:clamp(2.4rem, 5.4vw, 4.4rem); line-height:.98; letter-spacing:-.01em; margin-bottom:22px;
  color:var(--white);
}
.section-head{max-width:640px; margin-bottom:56px;}
.section-head p{font-size:17px; opacity:.8; line-height:1.6;}
.lede{font-size:17px; opacity:.85; line-height:1.65; max-width:60ch;}

.swell-line{color:var(--gold-600); margin-bottom:22px; display:block;}

/* ---------- Reveal on scroll (subtle, additive) ---------- */
[data-reveal]{opacity:0; transform:translateY(16px); transition:opacity 500ms var(--ease-out), transform 500ms var(--ease-out);}
[data-reveal].is-visible{opacity:1; transform:translateY(0);}
[data-reveal-group] > *{opacity:0; transform:translateY(14px); transition:opacity 420ms var(--ease-out), transform 420ms var(--ease-out);}
[data-reveal-group].is-visible > *{opacity:1; transform:translateY(0);}

/* ---------- Breadcrumb ---------- */
.breadcrumb{display:flex; flex-wrap:wrap; gap:8px; font-family:var(--font-mono); font-size:11px; text-transform:uppercase; letter-spacing:.06em; color:var(--sand-200); opacity:.7; margin-bottom:20px;}
.breadcrumb a:hover{opacity:1; color:var(--gold-400);}
.breadcrumb .sep{opacity:.5;}

/* ---------- Trust bar ---------- */
.trust-bar{
  display:flex; flex-wrap:wrap; gap:40px; justify-content:space-between;
  padding:36px 0; border-top:1px solid rgba(255,255,255,.12); border-bottom:1px solid rgba(255,255,255,.12);
}
.section-white .trust-bar,.section-light .trust-bar{border-color:rgba(12,25,23,.12);}
.trust-item{display:flex; align-items:baseline; gap:10px;}
.trust-num{font-family:var(--font-mono); font-size:22px; color:var(--gold-700); font-weight:600;}
.on-dark .trust-num,.section-dark .trust-num,.section-mid .trust-num{color:var(--gold-400);}
.trust-label{font-size:13px; opacity:.75; text-transform:uppercase; letter-spacing:.04em;}

/* ---------- Why cards ---------- */
.why-grid{display:grid; grid-template-columns:repeat(4,1fr); gap:24px;}
.why-card{
  background:var(--white); border-radius:var(--radius-tag); padding:32px 26px;
  border:1px solid rgba(12,25,23,.08);
}
.section-dark .why-card{background:var(--teal-800); border-color:rgba(255,255,255,.08);}
.section-mid .why-card{background:var(--teal-900); border-color:rgba(255,255,255,.08);}
.why-icon{
  width:46px; height:46px; border-radius:var(--radius-tag-sm); background:var(--teal-950);
  color:var(--gold-400); display:flex; align-items:center; justify-content:center; margin-bottom:20px;
  font-size:18px; font-family:var(--font-mono); font-weight:600; flex-shrink:0;
}
.why-icon svg{width:22px; height:22px; stroke-width:1.7;}
.why-card h2,.why-card h3{font-size:17px; margin-bottom:10px; font-weight:700; font-family:var(--font-body);}
.why-card p{font-size:14.5px; color:var(--ink-600); line-height:1.6;}
.section-dark .why-card p,.section-mid .why-card p{color:var(--sand-200); opacity:.85;}
.section-dark .why-card :is(h2,h3),.section-mid .why-card :is(h2,h3){color:var(--white);}

/* ---------- Package cards ---------- */
.pkg-grid{display:grid; grid-template-columns:repeat(4,1fr); gap:24px;}
.pkg-grid.cols-3{grid-template-columns:repeat(3,1fr);}
.pkg-card{
  background:var(--teal-800); border-radius:var(--radius-tag); overflow:hidden;
  border:1px solid rgba(255,255,255,.08); display:flex; flex-direction:column;
  position:relative;
}
.pkg-card.is-featured{border-color:var(--gold-500); border-width:1.5px;}
.pkg-badge{
  position:absolute; top:16px; right:16px; z-index:2;
  background:var(--teal-950); color:var(--gold-500); border:1px solid rgba(245,185,66,.6); font-family:var(--font-mono); font-weight:600;
  font-size:11px; letter-spacing:.04em; text-transform:uppercase; padding:6px 12px; border-radius:var(--radius-tag-sm);
}
.pkg-thumb{aspect-ratio:4/3; position:relative; overflow:hidden; background:linear-gradient(155deg, var(--teal-700), var(--teal-950));}
.pkg-thumb::after{content:''; position:absolute; inset:0; background-image:radial-gradient(circle at 25% 20%, rgba(255,255,255,.15), transparent 45%);}
.pkg-thumb img{width:100%; height:100%; object-fit:cover; position:relative;}
.pkg-thumb span{position:relative; z-index:1; font-family:var(--font-mono); font-size:10px; letter-spacing:.08em; text-transform:uppercase; color:var(--sand-200); opacity:.5; padding:16px; text-align:center; display:block;}
.pkg-body{padding:24px; display:flex; flex-direction:column; flex:1;}
.pkg-body h2,.pkg-body h3{font-size:19px; margin-bottom:8px; font-weight:700; color:var(--white);}
.pkg-body p{font-size:14px; opacity:.75; margin-bottom:20px; flex:1; line-height:1.55;}
/* Time-limited discount chip — ends 30 Sep 2026. One class, so removing the
   offer is a single search for `price-off` rather than hunting 44 inline
   styles. Dark text on gold: --gold-400 fails contrast as text on white, but
   is fine as a background behind --teal-950. Deliberately language-neutral —
   "-15%" reads identically in all four locales, which the wording it replaces
   ("15% off" / "15% Rabatt" / "15% dto.") did not.
   Fixed px, not em: it sits in contexts from 13px to 26px, so an em size would
   render it at 5.5px in the smallest of them. */
.price-off{
  display:inline-block; vertical-align:middle;
  font-family:var(--font-body); font-weight:700; font-size:10px; line-height:1;
  letter-spacing:.03em; background:var(--gold-400); color:var(--teal-950);
  padding:4px 6px; border-radius:4px; margin-left:8px;
}
.price-off.lg{font-size:12px; padding:5px 8px; margin-left:10px;}
.pkg-price{font-family:var(--font-mono); color:var(--gold-400); font-size:13px; margin-bottom:16px;}
.pkg-price b{font-size:var(--fs-600);}
.pkg-link{font-size:13px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--gold-400); display:flex; align-items:center; gap:6px;}
.pkg-list{display:flex; flex-direction:column; gap:10px; margin-bottom:20px;}
/* min-width:0 for the same reason as .field and .glance-grid > *: where this
   list is given two columns (accommodation uses an inline grid override), each
   li is a grid item defaulting to min-width:auto and will not shrink below the
   tick plus its longest word. */
.pkg-list li{display:flex; gap:10px; align-items:flex-start; font-size:14px; opacity:.9; min-width:0;}
.pkg-list svg{width:16px; height:16px; flex-shrink:0; margin-top:2px; color:var(--gold-400);}
.section-white .pkg-list svg,.section-light .pkg-list svg{color:var(--gold-600);}

/* ---------- Testimonials ---------- */
.testi-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:24px;}
.testi-card{background:var(--white); border-radius:var(--radius-tag); padding:30px; border:1px solid rgba(12,25,23,.08);}
.testi-stars{display:flex; align-items:center; gap:2px; margin-bottom:14px;}
/* Google's own star yellow, the same value as the G beside them (#FBBC05 in the logo path);
   flat, with no outline, because that is how Google draws a rating. */
.testi-stars svg:not(.testi-g){width:16px; height:16px; color:var(--google-star); stroke:none;}
.testi-card p{font-size:15px; line-height:1.65; color:var(--ink-600); margin-bottom:20px;}
.testi-name{font-weight:700; font-size:14px;}
.testi-loc{font-size:12px; color:var(--ink-600); opacity:.7;}

/* ---------- Glance ---------- */
.glance-grid{display:grid; grid-template-columns:1fr 1fr; gap:60px; align-items:center;}
/* Same reason as .field: grid items default to min-width:auto and will not
   shrink below their content's intrinsic minimum. German's longer compounds
   pushed a column past its own track on narrow phones (de/accommodation
   overflowed 12px at 320px while English fit), so let the columns shrink and
   the text wrap. */
.glance-grid > *{min-width:0;}
/* Zigzag: on a marked section the image sits left and the text right, so a run
   of sections alternates instead of stacking the same way down the page.
   Placement is explicit rather than flex `order` or `direction:rtl`, so the DOM
   order stays text-then-image — that is the reading order for screen readers and
   keyboard users, and it should not flip just because the visual sides do.
   Opt-in, because .glance-grid is used on 20 pages. Reset below 960px, where
   the grid collapses to one column and the columns no longer exist. */
.glance-grid.is-reversed > *:first-child{grid-column:2; grid-row:1;}
.glance-grid.is-reversed > *:last-child{grid-column:1; grid-row:1;}
.fact-label{font-family:var(--font-mono); font-size:11px; text-transform:uppercase; letter-spacing:.08em; opacity:.65; margin-bottom:6px;}
.glance-visual{aspect-ratio:1/1; border-radius:20px 80px 20px 80px; background:linear-gradient(150deg, var(--teal-700), var(--teal-950)); display:flex; align-items:center; justify-content:center; position:relative; overflow:hidden;}
.glance-visual::after{content:''; position:absolute; inset:0; background-image:radial-gradient(circle at 25% 20%, rgba(255,255,255,.15), transparent 45%);}
.glance-visual img{width:100%; height:100%; object-fit:cover; position:relative; z-index:1;}
/* "Taghazout at a glance" cards. The redesign shipped this markup with no CSS
   at all, so the icons had nothing constraining them and rendered at 546px —
   the SVGs carry a viewBox but no width/height, so they filled the container.
   Structurally this mirrors .keyfacts (icon chip + two-line label); it sits on
   .section-mid, so it takes the dark-card treatment already used by
   .section-mid .why-card rather than a new one.
   Two differences from .kf-txt on purpose: the label comes first and the value
   second here, and the values ("Cafés, rooftops, surf shops") are long enough to
   need wrapping, so no white-space:nowrap. */
.glance-cards{display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-top:28px;}
.glance-cards .gc{
  display:flex; align-items:center; gap:14px;
  background:var(--teal-900); border:1px solid rgba(255,255,255,.08);
  border-radius:16px; padding:14px 16px;
}
.gc-ico{
  flex-shrink:0; width:42px; height:42px; border-radius:12px;
  background:rgba(255,255,255,.08); color:var(--gold-400);
  display:flex; align-items:center; justify-content:center;
}
.gc-ico svg{width:21px; height:21px;}
.gc-txt{display:flex; flex-direction:column; min-width:0;}
.gc-txt em{
  font-style:normal; font-family:var(--font-mono); font-size:11px;
  letter-spacing:.06em; text-transform:uppercase; color:var(--sand-200); opacity:.7;
}
.gc-txt b{font-size:14px; color:var(--white); font-weight:600; line-height:1.35; margin-top:4px;}
@media (max-width:560px){.glance-cards{grid-template-columns:1fr;}}

/* ---------- Media frame (generic photo placeholder) ---------- */
.media-frame{position:relative; overflow:hidden; border-radius:var(--radius-tag); background:linear-gradient(155deg, var(--teal-700), var(--teal-950)); aspect-ratio:4/5; border:1px solid rgba(255,255,255,.08);}
.media-frame.is-wide{aspect-ratio:16/10;}
.media-frame::after{content:''; position:absolute; inset:0; background-image:radial-gradient(circle at 22% 20%, rgba(255,255,255,.16), transparent 45%);}
.media-frame img{width:100%; height:100%; object-fit:cover; position:relative; z-index:1;}
.media-caption{position:absolute; left:16px; bottom:16px; z-index:2; font-family:var(--font-mono); font-size:10px; letter-spacing:.08em; text-transform:uppercase; color:var(--sand-200); background:rgba(16,30,43,.75); backdrop-filter:blur(4px); padding:8px 12px; border-radius:var(--radius-tag-sm);}
/* Scrim at .75, not .6. This is 10px text sitting over a photograph, so the
   worst case is a bright image behind it: at .6 the caption measured 3.93:1
   against the old base and 3.54:1 against the lighter Dusk one, both under the
   4.5:1 needed at this size. .75 gives 5.89:1 even over pure white. */

/* ---------- FAQ ---------- */
/* 640px, not 760px, to match .section-head above it. The list was already
   centred, but being 120px wider than the heading made the questions overhang
   it on both sides, which read as misaligned rather than centred. Question text
   stays left-aligned: centring accordion rows hurts scanning and breaks the
   plus/minus alignment on the right. */
.faq-list{max-width:640px; margin:0 auto;}
.faq-item{border-bottom:1px solid rgba(12,25,23,.12);}
.section-dark .faq-item,.section-mid .faq-item{border-color:rgba(255,255,255,.12);}
.faq-q{
  width:100%; display:flex; justify-content:space-between; align-items:center; gap:20px;
  padding:24px 4px; font-size:17px; font-weight:700; text-align:left;
}
.faq-q .plus{font-family:var(--font-mono); font-size:20px; color:var(--gold-600); flex-shrink:0;}
.section-dark .faq-q .plus,.section-mid .faq-q .plus{color:var(--gold-400);}
.faq-item.open .plus{transform:rotate(45deg);}
.faq-a p{padding:0 4px 24px; font-size:15px; color:var(--ink-600); line-height:1.65; max-width:640px;}
.section-dark .faq-a p,.section-mid .faq-a p{color:var(--sand-200); opacity:.85;}
.faq-a p a{text-decoration:underline; text-decoration-color:var(--rust);}

/* ---------- Final CTA ---------- */
.final-cta{
  background:var(--teal-800); text-align:center; padding:120px 0;
  position:relative; overflow:hidden;
}
.final-cta h2{font-family:var(--font-display); font-weight:400; text-transform:uppercase; color:var(--white); font-size:clamp(2.2rem,5vw,4rem); line-height:1; margin-bottom:16px;}
.final-cta p{color:var(--sand-200); opacity:.8; margin-bottom:36px; font-size:17px; max-width:52ch; margin-left:auto; margin-right:auto;}
.final-cta .hero-actions{justify-content:center;}

/* ---------- Footer ---------- */
footer{background:var(--teal-950); color:var(--sand-100); padding:80px 0 30px; border-top:1px solid rgba(255,255,255,.08);}
.footer-grid{display:grid; grid-template-columns:1.4fr 1fr 1fr 1fr; gap:40px; padding-bottom:56px;}
.footer-col h2,.footer-col h4{font-size:13px; text-transform:uppercase; letter-spacing:.06em; color:var(--gold-400); margin-bottom:18px;}
.footer-col a,.footer-col p{font-size:14px; opacity:.75; line-height:2;}
.footer-col a:hover{opacity:1; color:var(--gold-400);}
.footer-social{display:flex; gap:12px; margin-top:18px;}
.footer-social a{width:38px; height:38px; border-radius:50%; border:1px solid rgba(255,255,255,.15); display:flex; align-items:center; justify-content:center; opacity:1;}
.footer-social a:hover{background:var(--gold-500); border-color:var(--gold-500); color:var(--ink-900);}
.footer-social svg{width:17px; height:17px;}
.footer-bottom{display:flex; justify-content:space-between; flex-wrap:wrap; gap:12px; padding-top:28px; border-top:1px solid rgba(255,255,255,.08); font-size:12.5px; opacity:.55;}

/* ---------- WhatsApp FAB ---------- */
.fab-whatsapp{
  position:fixed; right:20px; bottom:20px; z-index:var(--z-nav);
  width:56px; height:56px; border-radius:50%; background:#25D366;
  display:flex; align-items:center; justify-content:center; box-shadow:0 12px 28px rgba(0,0,0,.28);
}
/* Hidden while the hero is on screen. The hero already carries two CTAs, so a
   floating button adds nothing there — and being fixed to the bottom-right
   corner it lands squarely on the hero trust bar on every phone. main.js adds
   this class on load and removes it once the hero scrolls away, so the button
   turns up exactly when the inline CTAs are gone. Deliberately opt-out rather
   than opt-in: with JS off the class is never added and the button behaves
   exactly as it did before. */
.fab-whatsapp.is-hidden{opacity:0; visibility:hidden; pointer-events:none;}
.fab-whatsapp:hover{transform:scale(1.06);}
.fab-whatsapp svg{width:27px; height:27px;}

/* ---------- Sticky CTA ---------- */
.sticky-cta{
  position:fixed; bottom:0; left:0; right:0; z-index:800;
  background:rgba(16,30,43,.97); /* .97 alpha — a backdrop blur here would be invisible but composite every frame */
  padding:16px 0; transform:translateY(100%);
  border-top:1px solid rgba(255,255,255,.1);
}
.sticky-cta.show{transform:translateY(0);}
.sticky-inner{display:flex; align-items:center; justify-content:space-between; gap:20px; flex-wrap:wrap;}
.sticky-inner .info{display:flex; align-items:baseline; gap:14px; color:var(--white);}
.sticky-inner .info .p{font-family:var(--font-mono); color:var(--gold-400); font-size:18px;}

/* ---------- Package hero specifics ---------- */
.chip{
  display:inline-flex; align-items:center; gap:8px; font-family:var(--font-mono); font-size:11px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--ink-600); border:1px solid rgba(12,25,23,.15); border-radius:var(--radius-tag-sm); padding:7px 13px;
}
:is(.section-dark,.section-mid,.hero) .chip{color:var(--sand-200); border-color:rgba(255,255,255,.2);}

/* ---------- Timeline ---------- */
.timeline{max-width:640px; margin:0 auto; position:relative; padding-left:90px;}
.timeline::before{content:''; position:absolute; left:66px; top:6px; bottom:6px; width:2px; background:rgba(255,255,255,.15);}
.section-white .timeline::before,.section-light .timeline::before{background:rgba(12,25,23,.12);}
.tl-item{position:relative; padding-bottom:34px;}
.tl-time{position:absolute; left:-90px; top:0; width:66px; font-family:var(--font-mono); font-size:13px; color:var(--gold-400); text-align:right;}
.section-white .tl-time,.section-light .tl-time{color:var(--gold-600);}
.tl-dot{position:absolute; left:-30px; top:4px; width:10px; height:10px; border-radius:50%; background:var(--gold-500); border:2px solid var(--teal-950);}
.section-white .tl-dot,.section-light .tl-dot{border-color:var(--sand-100);}
.tl-item h3,.tl-item h4{font-size:16px; margin-bottom:6px; font-weight:700; color:var(--white);}
.section-white .tl-item :is(h3,h4),.section-light .tl-item :is(h3,h4){color:var(--ink-900);}
.tl-item p{font-size:14px; color:var(--sand-200); opacity:.8; line-height:1.55;}
.section-white .tl-item p,.section-light .tl-item p{color:var(--ink-600); opacity:1;}

/* ---------- Gallery ---------- */
.gallery-grid{display:grid; grid-template-columns:repeat(6,1fr); gap:14px;}
.gallery-item{aspect-ratio:1/1; border-radius:var(--radius-tag-sm); background:linear-gradient(150deg, var(--teal-500), var(--teal-900)); display:flex; align-items:center; justify-content:center; position:relative; overflow:hidden;}
.gallery-item::after{content:''; position:absolute; inset:0; background-image:radial-gradient(circle at 25% 20%, rgba(255,255,255,.13), transparent 45%);}
.gallery-item:nth-child(3n+1){grid-column:span 2; grid-row:span 2; aspect-ratio:1/1;}
.gallery-item span{position:relative; z-index:1; font-family:var(--font-mono); font-size:9px; color:rgba(255,255,255,.6); text-transform:uppercase; text-align:center; padding:8px;}
.gallery-item img{width:100%; height:100%; object-fit:cover; position:relative; z-index:1;}

/* ---------- Pricing / data table ---------- */
.price-table{width:100%; border-collapse:collapse; background:var(--white); border-radius:var(--radius-tag); overflow:hidden; border:1px solid rgba(12,25,23,.1);}
.price-table th,.price-table td{padding:18px 22px; text-align:left; font-size:14.5px; border-bottom:1px solid rgba(12,25,23,.08);}
.price-table th{font-family:var(--font-mono); font-size:11px; text-transform:uppercase; letter-spacing:.06em; background:var(--sand-200); color:var(--ink-600);}
.price-table td.price,.price-table td.mono-num{font-family:var(--font-mono); font-weight:600; color:var(--teal-800);}
.price-table tr:last-child td{border-bottom:none;}
.table-scroll{overflow-x:auto; -webkit-overflow-scrolling:touch; border-radius:var(--radius-tag);}

/* ---------- Forms ---------- */
/* min-width:0 because .field is a grid item inside .field-row, and grid items
   default to min-width:auto — they refuse to shrink below their content's
   intrinsic minimum. A <select> takes that minimum from its longest <option>,
   so the country-code list ("Bosnia y Herzegovina (+387)") forced the field to
   362px and pushed the whole form past a 360px viewport. English was 312px and
   fit, which is why only fr/es/de overflowed. */
.field{display:flex; flex-direction:column; gap:8px; margin-bottom:22px; min-width:0;}
.field select{max-width:100%;}
.field label{font-size:14px; font-weight:700;}
.field .hint{font-size:12px; color:var(--ink-600); opacity:.75;}
/* 16px, not 15: iOS Safari zooms the page on focus for anything below 16px,
   and it does so on every device, not only narrow ones -- the booking form has
   eight fields and a calendar, so it fired repeatedly during the one
   interaction on the site that matters. There used to be a 16px floor at
   max-width:640px only; this is that floor, unconditional. 2026-09-18. */
.field input,.field select,.field textarea{
  border:1.5px solid rgba(12,25,23,.48); border-radius:var(--radius-tag-sm); background:var(--white);
  padding:14px 16px; font-size:16px; min-height:52px; transition:border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
/* The guest count is forced up to six when Group & Family is selected. A number
   that changes by itself is easy to miss, so the field flashes once; the note
   beside it is announced (assets/js/booking.js). */
.field input.is-bumped{border-color:var(--gold-600); box-shadow:0 0 0 4px rgba(184,69,42,.16);}
.field textarea{min-height:140px; resize:vertical;}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--teal-700); box-shadow:0 0 0 4px rgba(22,97,88,.12); outline:none;}
.field.has-error input,.field.has-error textarea{border-color:var(--danger);}
.field .error-msg{display:none; color:var(--danger); font-size:12px; font-weight:600;}
.field.has-error .error-msg{display:block;}
.field-row{display:grid; gap:18px; grid-template-columns:1fr;}
@media (min-width:640px){.field-row.cols-2{grid-template-columns:1fr 1fr;}}
.honeypot{position:absolute; left:-9999px; opacity:0; height:0; width:0;}
.form-status{padding:16px; border-radius:var(--radius-tag-sm); font-size:14px; display:none; margin-bottom:22px;}
.form-status.is-visible{display:block;}
.form-status.is-success{background:#e4f0ea; color:#1f6b52;}
.form-status.is-error{background:var(--danger-tint); color:var(--danger-deep);}

/* ---------- Blog / prose ---------- */
.post-meta{display:flex; gap:12px; align-items:center; font-family:var(--font-mono); font-size:11px; text-transform:uppercase; letter-spacing:.05em; opacity:.7;}
/* Flush left, not centred. Every heading on the site sits on the 24px gutter
   (.section-head has a max-width but no auto margin), so an auto-centred prose
   column put the body text 202px right of the h2 above it on every page that
   uses it. The centred FAQ blocks are centred explicitly on the element and are
   unaffected. */
.prose{max-width:68ch; margin:0;}
.prose h2{font-family:var(--font-display); font-weight:400; text-transform:uppercase; font-size:clamp(1.6rem,3vw,2.2rem); margin-top:48px; margin-bottom:18px; letter-spacing:-.01em;}
.prose h3{font-size:19px; font-weight:700; margin-top:36px; margin-bottom:14px;}
.prose p{margin-bottom:20px; line-height:1.75; font-size:16px;}
.prose ul,.prose ol{margin-bottom:20px; padding-left:1.4rem; list-style:disc;}
.prose li{margin-bottom:8px; line-height:1.65;}
.prose blockquote{border-left:3px solid var(--gold-500); padding-left:20px; font-style:italic; font-size:18px; margin-block:24px; color:var(--ink-600);}
.prose a{text-decoration:underline; text-decoration-color:var(--rust); text-underline-offset:3px;}
.prose a:hover{color:var(--gold-600);}

/* ---------- Responsive ---------- */
@media (max-width:960px){
  .why-grid,.pkg-grid,.pkg-grid.cols-3{grid-template-columns:repeat(2,1fr);}
  .testi-grid{grid-template-columns:1fr;}
  .glance-grid{grid-template-columns:1fr; gap:32px;}
  /* One column here, so the explicit placement above must be released or the
     two children keep fighting over a column that no longer exists.
     The selectors must repeat :first-child/:last-child: the placement rules
     score (0,3,0) and a plain `.is-reversed > *` reset scores (0,2,0), so it
     loses and the section stays side-by-side on phones. */
  .glance-grid.is-reversed > *:first-child,
  .glance-grid.is-reversed > *:last-child{grid-column:auto; grid-row:auto;}
  .footer-grid{grid-template-columns:1fr 1fr;}
  .gallery-grid{grid-template-columns:repeat(4,1fr);}
}
@media (max-width:640px){
  section{padding:70px 0;}
  .hero{padding-top:120px;}
  .why-grid,.pkg-grid,.pkg-grid.cols-3{grid-template-columns:1fr;}
  .footer-grid{grid-template-columns:1fr;}
  .trust-bar{gap:24px;}
  /* Three short stats across, price on its own full-width row. The -15% chip
     needs 176px beside the price and a half-width cell is 154px, so in the 2x2
     it wrapped underneath. Shrinking .hero-stat-num to close that gap would
     shrink all four numbers to fix one. Giving the price the whole row keeps
     the number at 26px with the chip inline, and costs nothing in height: the
     three short labels wrap to two lines, so the block stays at 162px.
     Verified down to 320px in German, the tightest combination. */
  .hero-stats{grid-template-columns:repeat(3,1fr); gap:22px 14px; max-width:none;}
  .hero-stats > div:last-child{grid-column:1 / -1;}
  .gallery-grid{grid-template-columns:repeat(2,1fr);}
  .timeline{padding-left:70px;}
  .tl-time{width:50px; left:-70px; font-size:11px;}
  .tl-dot{left:-24px;}
  .fab-whatsapp{right:14px; bottom:14px; width:50px; height:50px;}
}


/* ---------- Cookie consent ---------- */
.consent-bar{
  position:fixed; left:16px; right:16px; bottom:16px; z-index:1100;
  max-width:var(--container); margin:0 auto;
  display:flex; flex-wrap:wrap; align-items:center; gap:14px 24px;
  background:var(--teal-900); color:var(--sand-100);
  border:1px solid rgba(255,255,255,.14); border-radius:var(--radius-tag-sm);
  padding:18px 22px; box-shadow:0 16px 40px rgba(0,0,0,.35);
}
.consent-bar p{flex:1 1 320px; font-size:14px; line-height:1.55;}
.consent-bar a{color:var(--gold-400); text-decoration:underline;}
.consent-actions{display:flex; gap:12px; flex:0 0 auto;}
.consent-bar button{
  font-family:var(--font-body); font-weight:700; font-size:13px;
  letter-spacing:.04em; text-transform:uppercase;
  padding:12px 22px; border-radius:var(--radius-tag-sm); min-height:44px;
  transition:background-color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}
.consent-accept{background:var(--gold-500); color:var(--ink-900);}
.consent-accept:hover{background:var(--gold-deep);}
.consent-decline{border:1.5px solid rgba(255,255,255,.4); color:var(--sand-100);}
.consent-decline:hover{border-color:var(--gold-400); color:var(--gold-400);}
/* Save carries the same outline weight as Reject so the three buttons read as
   equals. Nothing here may make accepting look easier than refusing. */
.consent-save{border:1.5px solid rgba(255,255,255,.4); color:var(--sand-100);}
.consent-save:hover{border-color:var(--gold-400); color:var(--gold-400);}
/* Two consent categories. Neither checkbox is pre-ticked; see main.js. */
.consent-cats{display:flex; flex-wrap:wrap; gap:10px 22px; flex:1 1 100%; margin:-2px 0 2px;}
.consent-cat{display:flex; gap:9px; align-items:flex-start; flex:1 1 260px;
  font-size:13px; line-height:1.45; cursor:pointer;}
.consent-cat input{flex:0 0 auto; width:16px; height:16px; margin:2px 0 0;
  accent-color:var(--gold-500); cursor:pointer;}
.consent-cat b{display:block; font-weight:700; color:var(--sand-100);}
.consent-cat span span{color:rgba(255,255,255,.7);}
/* Lift the WhatsApp button clear of the bar. Two body-scoped selectors so this
   beats .fab-whatsapp.is-raised, which the scroll handler owns independently. */
body.consent-open .fab-whatsapp,
body.consent-open .fab-whatsapp.is-raised{translate:0 -130px;}
@media (max-width:600px){
  .consent-bar{padding:16px; gap:12px;}
  .consent-actions{width:100%;}
  .consent-actions button{flex:1;}
}

/* ===================== Home hero immersivo (solo homepage) ===================== */
.hero-immersive{overflow:hidden;}
.hero-immersive .hero-bg{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:0;
}
.hero-immersive .hero-overlay{
  position:absolute; inset:0; z-index:1;
  background:
    linear-gradient(180deg, rgba(16,30,43,.45) 0%, rgba(16,30,43,.30) 42%, rgba(16,30,43,.88) 100%),
    linear-gradient(90deg, rgba(16,30,43,.82) 0%, rgba(16,30,43,.30) 55%, rgba(16,30,43,0) 80%),
    radial-gradient(130% 80% at 50% 118%, rgba(214,74,32,.42), transparent 60%);
}
.hero-immersive > .wrap{position:relative; z-index:2; width:100%;}
.hero-content{max-width:900px;}
.hero-immersive h1{font-size:clamp(2rem, 5.2vw, 4.5rem); line-height:.92; text-wrap:balance;}
.hero-immersive h1 .h1-lead{display:block; color:var(--white); font-size:.46em; line-height:1; letter-spacing:.01em; margin-bottom:13px;}
.hero-immersive .hero-actions{margin-bottom:40px;}
.hero-trustbar{
  display:flex; flex-wrap:wrap; align-items:flex-start;
  border-top:1px solid rgba(255,255,255,.2); padding-top:22px;
}
.hero-trustbar > div{padding:2px 26px; border-right:1px solid rgba(255,255,255,.2);}
.hero-trustbar > div:first-child{padding-left:0;}
.hero-trustbar > div:last-child{border-right:none;}
.hero-trustbar b{display:block; font-family:var(--font-mono); font-size:21px; color:var(--gold-400); font-weight:600; line-height:1.1; white-space:nowrap;}
.hero-trustbar s{font-weight:400; font-size:.7em; margin-right:6px;}
.hero-trustbar .price-off{margin-left:8px; margin-top:0;}
.hero-trustbar > div > span{display:block; margin-top:5px; font-size:11px; color:var(--sand-200); opacity:.82; text-transform:uppercase; letter-spacing:.05em;}
@media (max-width:640px){
  .hero-trustbar{gap:14px 0;}
  .hero-trustbar > div{width:50%; padding:0 12px 0 0; border-right:none;}
  /* Note on the WhatsApp button overlapping the hero trust bar on phones:
     tried and reverted. Padding below the trust bar only grows the hero (it
     already exceeds 100vh), and trimming the hero's top padding lifts the
     English content clear but not fr/es/de, whose longer lead paragraphs put
     the trust bar up to 176px lower — while also pulling the eyebrow under the
     fixed nav. A fixed button will overlay whatever sits in the bottom-right
     corner at any scroll position; this is pre-existing, not new to the
     redesign. Fixing it properly means raising the button on mobile or
     shortening the localised lead copy, both of which are design decisions. */
}

/* ===================== "Why Morocco": numeri-chiave + pull-quote ===================== */
.keyfacts{display:grid; grid-template-columns:1fr 1fr; gap:14px; margin:0 0 42px;}
.keyfacts .kf{
  display:flex; align-items:center; gap:15px;
  background:var(--sand-200); border:1px solid rgba(12,25,23,.07);
  border-radius:16px; padding:16px 18px;
}
.kf-ico{
  flex-shrink:0; width:46px; height:46px; border-radius:13px;
  background:rgba(214,74,32,.10); color:var(--terracotta);
  display:flex; align-items:center; justify-content:center;
}
.kf-ico svg{width:23px; height:23px;}
.kf-txt{display:flex; flex-direction:column; min-width:0;}
.kf-txt b{font-family:var(--font-mono); font-size:clamp(17px,1.9vw,21px); color:var(--teal-900); font-weight:600; line-height:1; white-space:nowrap;}
.kf-txt em{font-style:normal; margin-top:6px; font-size:12.5px; color:var(--ink-600); line-height:1.35;}
@media (max-width:560px){.keyfacts{grid-template-columns:1fr;}}
.pullquote{
  font-family:var(--font-display); font-weight:400; text-transform:uppercase;
  font-size:clamp(1.5rem,3vw,2.15rem); line-height:1.04; letter-spacing:-.01em;
  color:var(--teal-900); border-left:4px solid var(--terracotta); padding-left:24px;
  margin:8px 0 40px; max-width:22ch;
}
.pullquote span{color:var(--rust);}

/* ===================== Home package cards (rich) ===================== */
.pkg-card.is-rich .pkg-body p{flex:0 0 auto; margin-bottom:16px;}
.pkg-card.is-rich .pkg-price{margin-top:auto;}
.pkg-card.is-rich .pkg-body .btn{width:100%; margin-top:4px;}
.pkg-meta{display:flex; flex-wrap:wrap; gap:8px; margin-bottom:14px;}
.pkg-chip{
  font-family:var(--font-mono); font-size:10.5px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--sand-200); background:rgba(255,255,255,.07); border:1px solid rgba(255,255,255,.16);
  padding:5px 10px; border-radius:var(--radius-tag-sm);
}
.pkg-chip.lvl{color:var(--gold-400); border-color:rgba(245,185,66,.45);}
/* Same tick as .pkg-list on the packages and accommodation pages — same inline
   SVG, same 16px, same stroke — so the mark is identical everywhere and only
   its colour adapts to the background. It was previously a CSS border tick at
   5x10px, which read thin and homemade next to the real one. Coral rather than
   --gold-600 because these cards sit on .section-dark, where the rust used on
   light backgrounds would not hold contrast. */
.pkg-incl{display:flex; flex-direction:column; gap:10px; margin:0 0 22px;}
.pkg-incl li{display:flex; gap:10px; align-items:flex-start; font-size:13.5px; color:var(--sand-200); opacity:.92; line-height:1.4;}
.pkg-incl svg{width:16px; height:16px; flex-shrink:0; margin-top:1px; color:var(--coral);}
.pkg-card.is-featured{box-shadow:0 22px 50px rgba(0,0,0,.38);}

/* ===================== Why Morocco — layout a due colonne ===================== */
.wm-grid{display:grid; grid-template-columns:1fr 380px; gap:60px; align-items:start;}
.wm-text .prose{max-width:62ch;}
.wm-media{position:sticky; top:108px;}
.wm-media img{width:100%; height:auto; aspect-ratio:4/5; object-fit:cover; border-radius:20px 80px 20px 80px; border:1px solid rgba(12,25,23,.08);}
@media (max-width:900px){
  .wm-grid{grid-template-columns:1fr; gap:30px;}
  .wm-media{position:static; order:-1; margin-bottom:6px;}
  .wm-media img{aspect-ratio:16/10; border-radius:16px 48px 16px 48px;}
}


/* --- booking configurator -------------------------------------------------
   New classes only where the existing components genuinely do not cover it:
   a stepper (number input with the spinners suppressed), an option row, and
   the running summary. Everything else reuses .field, .field-row, .btn,
   .form-status and the existing tokens. */
.bk-grid{display:grid; grid-template-columns:1fr 340px; gap:40px; align-items:start;}
@media (max-width:900px){.bk-grid{grid-template-columns:1fr; gap:28px;}}

.bk-step{border-top:1px solid rgba(19,28,36,.10); padding-top:26px; margin-top:26px; min-width:0;}
.bk-step:first-child{border-top:0; padding-top:0; margin-top:0;}
.bk-step > h2{font-size:1.05rem; letter-spacing:.02em; margin:0 0 4px;}
.bk-step > .hint{display:block; color:var(--ink-600); font-size:13px; margin-bottom:16px;}

.bk-opt{display:flex; align-items:center; gap:16px; padding:12px 0;
  border-bottom:1px solid rgba(19,28,36,.07); min-width:0;}
.bk-opt:last-child{border-bottom:0;}
.bk-opt-main{flex:1 1 auto; min-width:0;}
.bk-opt-name{font-weight:600; font-size:14px; color:var(--ink-900);}
.bk-opt-note{font-size:12.5px; color:var(--ink-600); margin-top:2px;}

/* 16px for the same reason as .field input above: below it, iOS zooms. */
.bk-num{flex:0 0 auto; width:72px; min-height:44px; padding:8px 10px; text-align:center;
  font-family:var(--font-mono); font-size:16px;
  border:1px solid rgba(19,28,36,.48); border-radius:4px; background:var(--white); color:var(--ink-900);}
.bk-num::-webkit-outer-spin-button,.bk-num::-webkit-inner-spin-button{opacity:1;}

.bk-pay{display:flex; gap:12px; flex-wrap:wrap;}
.bk-pay label{flex:1 1 200px; display:flex; gap:10px; align-items:flex-start; cursor:pointer;
  border:1.5px solid rgba(19,28,36,.16); border-radius:6px; padding:14px 16px; min-width:0;}
.bk-pay label:has(input:checked){border-color:var(--gold-600); background:var(--sand-100);}
.bk-pay input{margin-top:3px; flex:0 0 auto;}
.bk-pay b{display:block; font-size:14px; color:var(--ink-900);}
.bk-pay span{display:block; font-size:12.5px; color:var(--ink-600); margin-top:2px;}

.bk-summary{position:sticky; top:100px; background:var(--sand-200); border:1px solid rgba(12,25,23,.08); box-shadow:0 2px 8px rgba(12,25,23,.06);
  border-radius:var(--radius-tag); padding:24px; min-width:0;}
@media (max-width:900px){.bk-summary{position:static;}}
.bk-summary h2{font-size:.95rem; letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink-600); margin:0 0 14px;}
.bk-row{display:flex; justify-content:space-between; gap:14px; padding:7px 0;
  font-size:14px; color:var(--ink-600); min-width:0;}
.bk-row span:last-child{font-family:var(--font-mono); white-space:nowrap;}
.bk-row.is-strong{color:var(--ink-900); font-weight:700; font-size:15px;}
.bk-split{height:1px; background:rgba(19,28,36,.14); margin:10px 0;}
.bk-note{font-size:12.5px; line-height:1.55; color:var(--ink-600); margin-top:16px;}
.bk-summary .btn{width:100%; margin-top:16px; justify-content:center;}

/* summary detail: what is being booked, and each add-on itemised */
.bk-meta{font-family:var(--font-mono); font-size:12px; letter-spacing:.02em;
  color:var(--ink-600); padding-bottom:10px; margin-bottom:6px;
  border-bottom:1px solid rgba(19,28,36,.14); overflow-wrap:anywhere;}
.bk-row.is-sub{font-size:13px; padding:5px 0 5px 12px; color:var(--ink-600);}
.bk-row.is-sub b{font-weight:600; color:var(--ink-900);}
.bk-tip{margin:14px 0 0; padding:10px 12px; background:var(--white);
  border-left:3px solid var(--gold-400); border-radius:3px;
  font-size:12.5px; line-height:1.55; color:var(--ink-600);}

/* ── arrival calendar on the booking page ─────────────────────────────────
   Pick a check-in day; the stay fills in from the nights already chosen, and
   anything the camp cannot sleep the party on is struck out before the guest
   reaches their card. Shares the admin panel's reading: weeks across, months
   down, one scrollable column. */
.field[data-field="arrival"]{ grid-column: 1 / -1; }

.bk-cal{ margin-top:12px; }
.bk-cal[hidden]{ display:none; }
.bk-cal-note{
  margin:0 0 10px; font-size:.82rem; line-height:1.45; color:var(--ink-600);
}
/* One month, arrows to move. No inner scroll: a fixed-height scrolling box
   inside a long form steals the swipe that was meant for the page. */
.bk-cal-box{
  padding:10px 12px 12px; border:1px solid rgba(12,25,23,.2);
  border-radius:10px; background:var(--white);
  /* On a phone the calendar wants the full column. On a desktop the same
     rule made 104px day cells -- a calendar the size of a wall planner. Cap
     it and leave it left-aligned; the mobile layout is untouched. */
  max-width:420px;
}
.bk-cal-nav{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  margin-bottom:10px;
}
.bk-cal-arrow{
  flex:0 0 auto; width:44px; height:44px; border-radius:50%; cursor:pointer;
  border:1px solid var(--sand-200); background:var(--white); position:relative;
}
.bk-cal-arrow::before{
  content:''; position:absolute; top:50%; left:50%; width:8px; height:8px;
  border-left:2px solid var(--ink-900); border-bottom:2px solid var(--ink-900);
  transform:translate(-30%,-50%) rotate(45deg);
}
.bk-cal-arrow.next::before{ transform:translate(-70%,-50%) rotate(-135deg); }
.bk-cal-arrow:hover:not(:disabled){ background:var(--sand-100); }
.bk-cal-arrow:disabled{ opacity:.3; cursor:not-allowed; }
.bk-cal-wd,.bk-cal-d{ display:grid; grid-template-columns:repeat(7,1fr); gap:3px; }
.bk-cal-wd{ margin-bottom:4px; }
.bk-cal-wd span{
  text-align:center; font-size:.66rem; font-weight:700; color:var(--ink-600);
  text-transform:uppercase;
}
.bk-cal-pad{ display:block; }

.bk-cal-day{
  appearance:none; font:inherit; font-size:.82rem; font-weight:600; cursor:pointer;
  border:1px solid var(--sand-200); background:var(--white); color:var(--ink-900);
  border-radius:8px; padding:0; aspect-ratio:1/1;
  display:flex; align-items:center; justify-content:center;
}
.bk-cal-day:hover:not(:disabled){ background:var(--sand-100); }
.bk-cal-day:disabled{ cursor:not-allowed; }
.bk-cal-day.is-past{ opacity:.32; border-color:transparent; }
/* Red, not merely greyed: "we cannot sleep you that week" has to jump out,
   and a pale struck-through cell read as "past" at a glance (owner, 2026-09-10). */
.bk-cal-day.is-full{
  border-color:var(--danger); background:var(--danger); color:var(--white);
  text-decoration:line-through; text-decoration-color:rgba(255,255,255,.7);
}
.bk-cal-day.is-stay{
  background:var(--sand-200); border-color:var(--sand-200); color:var(--ink-900);
}
.bk-cal-day.is-start{
  background:var(--teal-900); border-color:var(--teal-900); color:var(--white);
}
/* The departure morning: touched by the stay, but still sellable to the next
   guest, so it is outlined rather than filled. */
.bk-cal-day.is-end{
  border-color:var(--teal-900); border-style:dashed; background:var(--white);
  color:var(--ink-900); text-decoration:none;
}

.bk-cal-legend{
  display:flex; gap:16px; flex-wrap:wrap; margin-top:10px;
  font-size:.72rem; color:var(--ink-600);
}
.bk-cal-legend span{ display:inline-flex; align-items:center; gap:6px; }
.bk-cal-legend i{ width:13px; height:13px; border-radius:4px; display:inline-block; }
.bk-cal-legend .sw-stay{ background:var(--sand-200); border:1px solid rgba(12,25,23,.25); }
.bk-cal-legend .sw-full{ background:var(--danger); border:1px solid var(--danger); }


@media (max-width:600px){
  .bk-cal-day{ font-size:.78rem; }
}

/* The floating WhatsApp button sits over the bottom-right of the arrival
   calendar on a phone, exactly where the last week of the month is. The
   booking page has its own WhatsApp routes in the copy, so it stands down
   here and nowhere else. */
body:has([data-booking]) .fab-whatsapp{ display:none; }

/* Label above the calendar, standing in for the date field's own label now
   that the typed input is gone. */
.bk-cal-label{
  display:block; margin-bottom:6px;
  font-size:var(--fs-200); font-weight:700; color:var(--ink-900);
}

/* 2026-09-07: nightly-rate booking. .field is display:flex, and an author
   display beats the UA [hidden] rule, so the pack-count / guest-count swap
   needs this or both boxes show at once. */
.field[hidden]{ display:none; }
/* Custom stay, arrival chosen: the days that could be the departure. */
.bk-cal-day.is-option{ border-color:var(--teal-900); }
.bk-sub{ font-weight:400; opacity:.7; font-size:.92em; }

/* 2026-09-18: the replacement for the flip. A price that moves while it is
   being read is the one element on a page that should never move, so the two
   tiers sit side by side and both are readable at once. Same .price-tier
   children, so every size, colour and label rule above and below still
   applies. The .price-flip rules and price-flip.js were removed on 2026-09-20
   once the last page had been converted.

   The divider is a neutral grey at low alpha rather than a token, so the same
   rule reads correctly on the dark hero and on a white card. It is dropped
   when the pair wraps onto two lines on a narrow phone, where a left border
   would sit under the first tier instead of between the two. */
.price-pair{ display:flex; flex-wrap:wrap; align-items:baseline; gap:16px; }
.price-pair > .price-tier{ display:inline-flex; flex-wrap:wrap; align-items:baseline; opacity:1; }
.price-pair > .price-tier + .price-tier{ padding-left:16px; border-left:1px solid rgba(127,127,127,.35); }
@media (max-width:520px){
  .price-pair > .price-tier + .price-tier{ padding-left:0; border-left:0; }
}

/* 2026-09-07 follow-up: the tier label read thin (mono, 600, 70% opacity) and
   the hero cell clipped "INTERMEDIATE" on a phone because .hero-trustbar b is
   white-space:nowrap and the flip inherits it. Body face, bold, full opacity;
   the hero puts the label on its own line under the price and lets it wrap. */
.price-tier-label{
  font-family:var(--font-body); font-size:11px; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; opacity:1; margin-left:.45em; font-style:normal;
}
.hero-trustbar .price-tier-label{ flex-basis:100%; margin:4px 0 0; font-size:12px; }
.pkg-price .price-tier-label{ color:var(--gold-400); }
/* The "/ 5 nights" tail of a card price on its own line under the figure
   (owner, 2026-09-07, from the phone). */
.pkg-price-note{ display:block; margin-top:5px; font-size:12px; opacity:.85; }

/* =====================================================================
   2026-09-08  UI PHASE 2+3 -- SITE-WIDE (scoped to the homepage until Phase 3)
   Tokens are global and inert until used. Everything that changes what a
   visitor sees is scoped to so no other page moves before the
   owner has approved the homepage. Phase 3 lifts the scope.
   ===================================================================== */
:root{
  /* Type scale, major third (x1.25) from a 16px base. Every heading level
     maps to one of these; nothing new gets an ad-hoc px size. */
  --fs-100:.75rem;   /* 12  captions, chips, eyebrows -- the floor */
  --fs-200:.875rem;  /* 14  small UI */
  --fs-300:1rem;     /* 16  body */
  --fs-400:1.125rem; /* 18  lead */
  --fs-500:1.25rem;  /* 20  card titles */
  --fs-600:1.5625rem;/* 25  h3 */
  --fs-700:1.953rem; /* 31  h2 phone */
  --fs-800:2.441rem; /* 39  h1 phone */
  --fs-900:3.052rem; /* 49  h2 desktop */
  --fs-1000:3.815rem;/* 61  h1 desktop, hero goes above this by design */
  /* Spacing scale. Section padding and component gaps come from here. */
  --google-star:#FBBC05;   /* Google's rating yellow: the review stars only, never a site accent */
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:24px;
  --space-6:32px; --space-7:48px; --space-8:64px; --space-9:96px; --space-10:128px;
  /* Muted text as COLOUR, not opacity. Opacity on text made the rendered
     contrast unknowable from the tokens (hint text landed at 3.6:1, the
     Instagram link at 3.8:1). These are the measured-safe equivalents:
     --sand-muted 9.4:1 on teal-950, --ink-muted 6.5:1 on sand-100. */
  --sand-muted:#C9C0B0;
  --ink-muted:#4C5A66;
  /* Motion: fast, ease-out, transform/opacity/colour only. */
  --ease-out:cubic-bezier(.2,.7,.2,1);
  --dur-fast:150ms;
  --dur:200ms;
}

/* ---- type: the phone gets a hierarchy again --------------------------- */
/* Hero h1 and section h2 both floored at 2rem, so at 375px they were the same
   32px. The hero now floors at --fs-800 and clears the h2 by a full step. */
.hero h1{font-size:clamp(var(--fs-800), 6.2vw, 5.4rem);}
h2.section-title{font-size:clamp(var(--fs-700), 4vw, var(--fs-900));}
/* 10-11px captions come up to the 12px floor. */
.pkg-chip{font-size:var(--fs-100); padding:6px 11px;}
.pkg-badge{font-size:var(--fs-100);}
.price-off{font-size:var(--fs-100); padding:4px 7px;}
.price-off.lg{font-size:var(--fs-100);}
.price-tier-label{font-size:var(--fs-100);}
.hero-trustbar > div > span{font-size:var(--fs-100); color:var(--sand-muted); opacity:1;}
.hero-trustbar s{color:var(--sand-muted); opacity:1;}
.pkg-body p{font-size:15px; opacity:1; color:var(--sand-muted);}
.why-card p{font-size:15px;}
.testi-loc{opacity:1; color:var(--ink-muted);}
.section-head p{opacity:1; color:var(--ink-muted);}
:is(.section-dark,.section-mid,.final-cta) .section-head p{color:var(--sand-muted);}
.section-dark .why-card p,.section-mid .why-card p{opacity:1; color:var(--sand-muted);}
.final-cta p{opacity:1; color:var(--sand-muted);}
/* Two intro paragraphs ran together as one block. */
.section-head p + p{margin-top:var(--space-3);}
/* The old price. The element may be a <span> or an <s> -- <s> is the honest
   tag for a superseded price and the markup is moving to it -- so the rule
   names the class, not the tag, and the strike is declared once. A nested <s>
   inside it is cleared, because two line-throughs on the same text draw two
   lines. 2026-09-18. */
.price-was,s.price-was{text-decoration:line-through; color:var(--sand-muted); margin-right:6px; font-weight:400;}

/* ---- spacing: padding by role, not one number for every section -------- */
#packages{padding:var(--space-10) 0;}          /* the sale */
.final-cta{padding:var(--space-10) 0;}         /* the close */
#why,#crew,#why-morocco{padding:var(--space-9) 0;}
.section-mid{padding:var(--space-8) 0;}
#faq{padding:var(--space-8) 0;}                /* a teaser, not the page */
@media (max-width:640px){
  #packages,.final-cta{padding:var(--space-8) 0;}
  #why,#crew,#why-morocco{padding:var(--space-7) 0;}
  .section-mid,#faq{padding:var(--space-7) 0;}
}

/* ---- interaction: rest / hover / focus-visible / active ----------------- */
.btn{
  transition:transform var(--dur) var(--ease-out), background-color var(--dur) var(--ease-out),
             color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.btn:hover{transform:translateY(-1px);}
.btn:active{transform:translateY(0) scale(.98); transition-duration:var(--dur-fast);}
.btn-gold:active{background:var(--gold-deep);}
/* Focus ring: 2px, offset so the ground shows through as a gap; teal on light
   grounds (6.2:1 on sand), gold on dark (9.6:1). A shape, not a colour cue. */
:focus-visible{outline:2px solid var(--teal-700); outline-offset:3px; border-radius:4px;}
:is(.hero,.section-dark,.section-mid,.final-cta,.site-nav,.mobile-menu,.consent-bar,.pkg-card,footer) :focus-visible{outline-color:var(--gold-400);}
.nav-links a:active,.btn-link:active,.footer-col a:active{opacity:.6;}
/* WhatsApp: ink on the green, 8.7:1. White on it was 1.98:1. */
.btn-whatsapp,.fab-whatsapp{color:var(--teal-950);}
.btn-whatsapp:hover{color:var(--teal-950);}

/* ---- consent bar: a strip on phones, not the first screen ---------------
   Same words, same order. Was 323px of a 375x812 screen (40%).
   2026-09-08, owner: on phones the two category rows and "Save choices" are
   hidden -- Reject all / Accept all only. main.js is untouched: the rows are
   still in the DOM, unticked, so Reject and Accept behave exactly as before.
   Desktop keeps the full bar. */
@media (max-width:640px){
  .consent-cats, .consent-save{display:none;}
  .consent-bar{left:8px; right:8px; bottom:8px; padding:12px 14px; gap:8px 14px; border-radius:10px;}
  .consent-bar p{font-size:13px; line-height:1.4; flex:1 1 100%;}
  .consent-cats{gap:6px 14px; margin:0;}
  .consent-cat{flex:1 1 140px; font-size:12px; line-height:1.35; gap:8px;}
  .consent-cat input{width:18px; height:18px; margin-top:1px;}
  .consent-cat span span{color:var(--sand-muted);}
  .consent-actions{gap:8px; width:100%;}
  .consent-bar button{padding:10px 6px; font-size:12px; letter-spacing:.02em; min-height:44px;}
  /* body. so this outranks the 640px rule above; the strip is ~132px now */
  body.consent-open .fab-whatsapp,
  body.consent-open .fab-whatsapp.is-raised{translate:0 -138px;}
}

/* =====================================================================
   2026-09-08  UI PHASE 3 -- ROLL-OUT TO EVERY PAGE AND LOCALE
   ===================================================================== */
/* ---- muted text as colour, everywhere. Each rule below replaces an
   opacity that made the rendered contrast unknowable; the token pairs are
   measured (sand-muted 9.4:1 on teal-950, ink-muted 6.5:1 on sand-100). */
.lang-switch > button{opacity:1;}
.hero-stat-label{opacity:1; color:var(--sand-muted);}
.lede{opacity:1; color:var(--ink-muted);}
:is(.hero,.section-dark,.section-mid,.final-cta) .lede{color:var(--sand-muted);}
.breadcrumb{opacity:1; color:var(--sand-muted); font-size:var(--fs-100);}
.trust-label{opacity:1; color:var(--ink-muted);}
.pkg-list li{opacity:1;}
.fact-label{opacity:1; color:var(--ink-muted); font-size:var(--fs-100);}
.section-dark .faq-a p,.section-mid .faq-a p{opacity:1; color:var(--sand-muted);}
.footer-col a,.footer-col p{opacity:1; color:var(--sand-muted);}
.footer-bottom{color:var(--sand-muted);}
.tl-item p{opacity:1; color:var(--sand-muted);}
.field .hint{opacity:1; color:var(--ink-muted); font-size:13px;}
.post-meta{opacity:1; color:var(--ink-muted); font-size:var(--fs-100);}
:is(.hero,.section-dark,.section-mid) .post-meta{color:var(--sand-muted);}
.pkg-incl li{opacity:1; color:var(--sand-200);}
.bk-sub{opacity:1; color:var(--ink-muted);}
.pkg-price-note{opacity:1; color:var(--sand-muted);}
/* Struck-through "was" prices. Four inline variants across 56 spans became
   one class with two size modifiers; the colour follows the ground. */
.price-was.xs{font-size:.55em; margin-right:10px;}
.price-was.sm{font-size:.8em;}
:is(.section-white,.section-light,.prose,.faq-a,.testi-card) .price-was{color:var(--ink-muted);}

/* ---- rhythm: a default for pages that are all content, by role on top --- */
section{padding:var(--space-9) 0;}
.final-cta{padding:var(--space-10) 0;}
@media (max-width:640px){
  section{padding:var(--space-7) 0;}
  .final-cta{padding:var(--space-8) 0;}
}

/* ---- forms: a focus ring that survives the field's own :focus{outline:none}.
   The 16px floor that used to live here as a max-width:640px media query is now
   in the base rules themselves (.field input and .bk-num), because iOS zooms
   below 16px at every viewport width, not only narrow ones. 2026-09-18. ---- */
.field input:focus-visible,.field select:focus-visible,.field textarea:focus-visible,
.bk-num:focus-visible{outline:2px solid var(--teal-700); outline-offset:2px;}

.faq-q{transition:color var(--dur) var(--ease-out);}
.faq-q:active{opacity:.7;}

/* ---- 768: three package cards in a two-column grid left one orphan. The
   third card spans the row and lays out sideways, thumb left. ------------- */
@media (min-width:641px) and (max-width:960px){
  .pkg-grid.cols-3 > .pkg-card:nth-child(3):last-child{grid-column:1 / -1; flex-direction:row; align-items:stretch;}
  .pkg-grid.cols-3 > .pkg-card:nth-child(3):last-child .pkg-thumb{flex:0 0 42%; aspect-ratio:auto; min-height:260px;}
  .pkg-grid.cols-3 > .pkg-card:nth-child(3):last-child .pkg-body{flex:1 1 auto;}
}
.gc-txt em{opacity:1; color:var(--sand-muted); font-size:var(--fs-100);}
/* Phase 3 sweep: two captions still under the 12px floor on phones. */
.media-caption{font-size:var(--fs-100);}
.price-table th{font-size:var(--fs-100);}
.chip{font-size:var(--fs-100);}
.price-table td.price .price-was,.price-table td.price > span{font-size:.85em;}
.price-note{font-size:.85em; color:var(--ink-muted);}
.bk-sub{font-size:var(--fs-100);}

/* ---- Move 2 (2026-09-08): the phone can see its price ------------------
   booking.js appends .bk-bar inside [data-booking]; it mirrors the summary's
   due-now / total and its button scrolls to the summary. Hidden above 900px,
   where the summary column is sticky anyway, and while the consent bar is up
   so two fixed bars never stack. */
.bk-bar{display:none;}
@media (max-width:900px){
  .bk-bar{position:fixed; left:0; right:0; bottom:0; z-index:var(--z-nav);
    display:flex; align-items:center; justify-content:space-between; gap:12px;
    padding:10px 16px calc(10px + env(safe-area-inset-bottom));
    background:var(--teal-950); color:var(--sand-100);
    border-top:1px solid rgba(255,255,255,.14); box-shadow:0 -8px 24px rgba(0,0,0,.25);}
  .bk-bar[hidden]{display:none;}
  .bk-bar-lbl{display:block; font-size:var(--fs-100); color:var(--sand-muted); text-transform:uppercase; letter-spacing:.05em;}
  .bk-bar-amt{font-family:var(--font-mono); font-size:18px; color:var(--gold-400); font-variant-numeric:tabular-nums;}
  .bk-bar-total{font-size:13px; color:var(--sand-muted); font-weight:400;}
  .bk-bar .btn-sm{min-height:44px; flex:0 0 auto;}
  body:has(.bk-bar:not([hidden])) main{padding-bottom:76px;}   /* last form row and the summary stay reachable */
  body:has(.bk-bar:not([hidden])) .bk-summary{scroll-margin-top:96px;}
  body.consent-open .bk-bar{display:none;}
}
/* The month caption keeps the h4's look; it is a <p> now (heading order). */
.bk-cal-month{margin:0; font-family:var(--font-body); font-size:.92rem; font-weight:700; color:var(--ink-900); text-transform:capitalize; text-align:center; flex:1 1 auto;}

/* =====================================================================
   2026-09-13  CRITIQUE FIXES (emil-design-eng / impeccable / taste review)
   Appended, not edited in place: every rule below wins on the cascade by
   coming last at equal specificity, so the earlier blocks stay readable
   as history. Motion: exact properties, ease-out token, under 300ms for
   UI, exits faster than entries, hover gated to hover-capable devices.
   ===================================================================== */

/* ---- motion: nav, menus, bars ------------------------------------------ */
.skip-link{top:16px; transform:translateY(-140px); transition:transform var(--dur-fast) var(--ease-out);}
.skip-link:focus{transform:none;}
/* Padding is layout on a fixed element; let it snap, animate colour and shadow only. */
.site-nav{transition:background-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);}
.nav-cta{transition:background-color var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);}
.nav-cta:active{transform:scale(.97); transition-duration:var(--dur-fast);}
/* Full-screen drawer: iOS drawer curve in, faster out. */
.mobile-menu{transition:transform var(--dur) var(--ease-out);}
.mobile-menu.open{transition-duration:280ms;}
/* Popover scales from its trigger (top right), never from centre; visibility
   waits for the fade on exit so the menu does not vanish before it fades. */
.lang-menu{
  transform-origin:top right; transform:scale(.96) translateY(-4px);
  transition:opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out),
             visibility 0s linear var(--dur-fast);
}
.lang-switch[data-open="true"] .lang-menu{transform:none; transition-delay:0s;}
.sticky-cta{transition:transform 240ms var(--ease-out);}
/* The later token block dropped the `bottom` transition, so the raised state
   jumped 120px. Individual translate/scale properties compose instead. */
.fab-whatsapp{
  transition:translate var(--dur) var(--ease-out), scale var(--dur) var(--ease-out),
             opacity var(--dur) var(--ease-out), visibility var(--dur) var(--ease-out);
}
.fab-whatsapp.is-raised{translate:0 -120px;}
.fab-whatsapp:hover{transform:none;}
.fab-whatsapp:active{transform:none; scale:.96;}

/* ---- motion: reveals ---------------------------------------------------- */
[data-reveal].is-visible,[data-reveal-group].is-visible > *{transform:none;}
[data-reveal-group].is-visible > *:nth-child(n){transition-delay:calc(var(--i, 0) * 60ms);}
[data-reveal-group] > *:nth-child(2){--i:1;} [data-reveal-group] > *:nth-child(3){--i:2;}
[data-reveal-group] > *:nth-child(4){--i:3;} [data-reveal-group] > *:nth-child(5){--i:4;}
[data-reveal-group] > *:nth-child(6){--i:5;} [data-reveal-group] > *:nth-child(7){--i:6;}
[data-reveal-group] > *:nth-child(8){--i:7;}

@media (hover:hover) and (pointer:fine){
  a.pkg-card,.pkg-card:has(.btn){transition:transform var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);}
  a.pkg-card:hover,.pkg-card:has(.btn):hover{transform:translateY(-2px);}
  .btn:hover{transform:translateY(-1px);}
  .fab-whatsapp:hover{scale:1.06;}
  .bk-cal-day:hover:not(:disabled){background:var(--sand-100);}
  .bk-cal-arrow:hover:not(:disabled){background:var(--sand-100);}
}
@media (hover:none){
  .btn:hover,.nav-cta:hover{transform:none;}
  .bk-cal-day:hover:not(:disabled),.bk-cal-arrow:hover:not(:disabled){background:var(--white);}
}
/* A featured card carried a 1.5px border and a 50px shadow: pick the border. */
.pkg-card.is-featured{box-shadow:0 10px 24px rgba(0,0,0,.22);}

/* ---- FAQ: interruptible accordion, no JS measurement ---------------------
   height 0 -> auto via interpolate-size (Chrome 129+, Safari 26). Browsers
   without it open instantly, which is the reduced-motion behaviour anyway.
   (grid-template-rows 0fr -> 1fr was tried first: Chrome 152 refused to
   resolve the open track while a transition was declared on it.) */
.faq-a{max-height:none; overflow:hidden; height:0; interpolate-size:allow-keywords; transition:height 220ms var(--ease-out);}
.faq-item.open .faq-a{height:auto;}
.faq-q .plus{transition:transform var(--dur) var(--ease-out);}

/* ---- booking calendar: press feedback, 45px cells on a phone -------------- */
.bk-cal-d{gap:2px;}
.bk-cal-box{padding:8px;}
.bk-cal-day{transition:background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);}
.bk-cal-day:active:not(:disabled){transform:scale(.92);}
.bk-cal-arrow{transition:background-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);}
.bk-cal-arrow:active:not(:disabled){transform:scale(.9);}
/* While the feed loads every day is drawn disabled and muted, not "open". */
.bk-cal.is-loading .bk-cal-day:not(.is-past){opacity:.55; cursor:progress;}
.bk-cal-note a{text-decoration:underline; text-decoration-color:var(--rust); text-underline-offset:3px; color:var(--ink-900);}

/* ---- nothing appears from nothing ---------------------------------------- */
.bk-bar,.consent-bar{transition:transform 240ms var(--ease-out), opacity 240ms var(--ease-out);}
@starting-style{
  .bk-bar:not([hidden]){transform:translateY(100%);}
  .consent-bar{opacity:0; transform:translateY(12px);}
}


/* ---- type and contrast fixes from the detector ---------------------------- */
.hero{min-height:100vh; min-height:100dvh; padding-top:120px;}
.hero-immersive h1 .h1-lead{font-size:max(.95rem, .46em);}
.pullquote{line-height:1.12;}
:is(.section-dark,.section-mid,.final-cta) .prose a:hover{color:var(--gold-400);}
/* Booking-terms prose sits on dark: the rust link hover was 3.2:1 there. */
.page-terms .prose a:hover{color:var(--gold-400);}
/* Icon tiles: the icon alone, no 46px square stacked above every heading. */
.why-icon{background:transparent; color:var(--gold-600); width:auto; height:auto; margin-bottom:14px; font-size:15px; letter-spacing:.06em;}
.why-icon svg{width:26px; height:26px;}
.section-dark .why-icon,.section-mid .why-icon{color:var(--gold-400);}

/* ---- classes the pages were already using, or that the fixes need --------- */
.footer-tagline{font-family:var(--font-display); font-weight:400; text-transform:uppercase; font-size:1.55rem; line-height:1; color:var(--white); margin:14px 0 12px; letter-spacing:-.01em;}
.footer-tagline span{color:var(--coral);}
/* Contact page sidebar, was styled inline. */
.stack{display:flex; flex-direction:column; gap:32px;}
.stack .contact-lines{display:flex; flex-direction:column; gap:16px;}
.stack .contact-line{display:flex; gap:12px; align-items:center;}
.stack .contact-line svg{width:20px; height:20px; flex-shrink:0; color:var(--gold-600);}
/* Journal: two related articles and a link, not three equal cards. */
.keep-reading{display:grid; grid-template-columns:1fr 1fr; gap:24px; align-items:start;}
.keep-reading .pkg-card{background:var(--white); border-color:rgba(12,25,23,.08);}
.keep-reading .pkg-card h3{color:var(--ink-900);}
.keep-reading .pkg-link{color:var(--gold-600);}
.keep-reading-more{margin-top:28px;}
@media (max-width:640px){.keep-reading{grid-template-columns:1fr;}}
/* FAQ: grouped, with jump links. */
.faq-jump{display:flex; flex-wrap:wrap; gap:10px; justify-content:center; margin:0 auto 48px; max-width:760px;}
.faq-jump a{font-family:var(--font-mono); font-size:var(--fs-100); text-transform:uppercase; letter-spacing:.06em; color:var(--ink-900); border:1px solid rgba(12,25,23,.18); border-radius:var(--radius-tag-sm); padding:9px 14px; transition:background-color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);}
.faq-jump a:hover{background:var(--sand-200); border-color:var(--sand-200);}
.faq-group{max-width:640px; margin:0 auto 56px; scroll-margin-top:110px;}
.faq-group > h2{font-family:var(--font-display); font-weight:400; text-transform:uppercase; font-size:clamp(1.4rem, 2.6vw, 1.9rem); letter-spacing:-.01em; margin-bottom:8px;}
.faq-group .faq-list{margin:0;}
/* Booking success: the recap of what was just paid for. */
.bk-recap{background:var(--sand-100); border-radius:var(--radius-tag); padding:22px 24px; margin:0 0 28px;}
.bk-recap .bk-meta{margin-bottom:8px;}
/* Booking form: per-field error text under the input. */
.field[data-field] .error-msg{margin-top:-2px;}
.bk-cal-error{display:none; color:var(--danger); font-size:12px; font-weight:600; margin:0 0 10px;}
.field.has-error .bk-cal-error{display:block;}
/* Coach cards: role as a plain line, not an eyebrow (homepage, about). */
.pkg-body p.pkg-role{font-size:13px; font-weight:600; color:var(--ink-muted); margin:-4px 0 10px;}
/* Yoga page: the price on its own line under the lead, not inside the sentence. */
.hero-price{font-family:var(--font-mono); font-size:18px; color:var(--gold-400); margin:-18px 0 32px;}
.hero-price s{color:var(--sand-muted); font-size:.8em; margin-right:8px; font-weight:400;}
/* Packages: struck-through prices inside the dark Group band, and a three-card
   add-on row now that the Extra-night card is gone. */
.why-grid.cols-3{grid-template-columns:repeat(3,1fr);}
@media (max-width:960px){.why-grid.cols-3{grid-template-columns:repeat(2,1fr);}}
@media (max-width:560px){.why-grid.cols-3{grid-template-columns:1fr;}}
/* Timeline labels that are words ("Morning", "Midday") ran into the dot; the
   original labels were two digits. Narrow the label box so it stops short of
   the dot at left:-30px. 2026-09-14. */
.tl-time{width:56px; left:-92px; font-size:12px;}

/* .post-meta was a flex row, so on a 375px phone each span wrapped inside itself
   ("SPOT-" / "GUIDE") and the comma floated as its own flex item. Plain inline
   text wraps at the separators instead; the &nbsp;·&nbsp; in the markup keeps
   the spacing. 2026-09-14. */
.post-meta{display:block; line-height:1.8;}
.post-meta > span{white-space:nowrap;}

/* The Group & Family price block sits on a white section without the inline
   colour override the Solo block carries, so its gold-400 numbers and sand-muted
   labels read 1.8:1 on white. Section-aware defaults instead. 2026-09-17. */
:is(.section-white,.section-light) .hero-stat-num{color:var(--gold-700);}
:is(.section-white,.section-light) .hero-stat-label{color:var(--ink-muted);}

/* Sticky booking bar on phones: the 3-night price string wrapped inside itself
   ("… / 3 nights" on one line, "-25%" on the next). Let the label and the price
   wrap as whole units instead, and drop the strike-through there. 2026-09-17. */
@media (max-width:600px){
  .sticky-inner{flex-wrap:nowrap; gap:12px;}
  .sticky-inner .info{flex:1 1 auto; min-width:0; flex-wrap:wrap; row-gap:2px;}
  .sticky-inner .info .p{font-size:14px; white-space:nowrap;}
  .sticky-inner .info .price-was,.sticky-inner .info .price-off{display:none;}
  .sticky-inner .btn{flex:0 0 auto;}
}

/* The hero trust bar sets its <b> to block, which beat .price-pair (lower
   specificity) and stacked the two tiers. 2026-09-18. */
.hero-trustbar b.price-pair{display:flex;}

/* 2026-09-19: Google "G" before the stars on every review card, and the
   booking-page rotator: the three cards share one grid cell so the box keeps
   the height of the longest review and the form below never jumps. Exit keeps
   visibility for the length of the fade; the entry clears that delay. */
.testi-stars .testi-g{width:18px; height:18px; margin-right:6px; flex:0 0 auto;}
.testi-track{display:grid;}
.testi-track > .testi-card{grid-area:1 / 1; opacity:0; visibility:hidden; transform:translateY(6px);
  transition:opacity 180ms var(--ease-out), transform 180ms var(--ease-out), visibility 0s linear 180ms;}
.testi-track > .testi-card.is-on{opacity:1; visibility:visible; transform:none; transition-duration:300ms,300ms,0s; transition-delay:0s;}
.testi-dots{display:none; justify-content:center; gap:0; margin-top:6px;}
.testi-rotator.is-live .testi-dots{display:flex;}
.testi-dots button{width:44px; height:44px; padding:0; border:0; background:none; cursor:pointer; display:grid; place-items:center; border-radius:50%;}
.testi-dots button::before{content:""; width:8px; height:8px; border-radius:50%; background:var(--ink-muted); opacity:.75;
  transition:opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out), background-color var(--dur) var(--ease-out);}
.testi-dots button[aria-current="true"]::before{opacity:1; background:var(--gold-600); transform:scale(1.3);}
.testi-dots button:focus-visible{outline:2px solid var(--gold-600); outline-offset:2px;}
/* quote at the top, name and date pinned to the bottom, so a one-line review
   sits in the same frame as a five-line one (home grid and rotator alike). */
.testi-card{display:flex; flex-direction:column;}
.testi-card .testi-name{margin-top:auto;}

/* = */

/* P2-02: interior heroes stop eating the phone fold */
@media (max-width:640px){
  .hero:not(.hero-immersive){min-height:0 !important; padding-top:108px !important; padding-bottom:var(--space-7) !important;}
}

/* P2-05: size before colour */
@media (min-width:960px){
  .hero .hero-actions .btn{min-height:56px; padding:18px 34px; font-size:15px;}
  .hero-trustbar b{font-size:26px;}
}

/* P2-08: cards step off their section */
.why-card,.testi-card,.keep-reading .pkg-card{box-shadow:0 2px 8px rgba(12,25,23,.06);}
/* Interactive cards keep their hover transition from the hover-capable block */

/* P2-09: a required field says so; an error carries a glyph, not only a colour */
.field:has([required]) > :is(label,.bk-cal-label)::after{content:" *"; color:var(--rust);}
.field.has-error .error-msg::before{content:"!"; display:inline-grid; place-items:center; width:16px; height:16px; margin-right:6px; border-radius:50%; background:var(--danger); color:var(--white); font-size:11px; font-weight:700; line-height:1; vertical-align:-3px;}

/* P2-10: gold underlines stay on dark grounds only */
:is(.section-dark,.section-mid,.final-cta,.page-terms) :is(.prose a,.faq-a p a){text-decoration-color:var(--gold-500);}
:is(.section-dark,.section-mid,.final-cta) .btn-link:hover{color:var(--gold-500);}

/* P2-12: the comparison table on small screens */
.table-scroll{
  background:
    linear-gradient(90deg, var(--white) 30%, rgba(255,255,255,0)),
    linear-gradient(90deg, rgba(255,255,255,0), var(--white) 70%) 100% 0,
    linear-gradient(90deg, rgba(12,25,23,.16), rgba(12,25,23,0)),
    linear-gradient(90deg, rgba(12,25,23,0), rgba(12,25,23,.16)) 100% 0;
  background-repeat:no-repeat; background-size:40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-attachment:local, local, scroll, scroll; background-color:var(--white);
}
.table-scroll .price-table{background:transparent; overflow:clip;}
.price-table th:first-child,.price-table td:first-child{position:sticky; left:0; background:var(--white); box-shadow:1px 0 0 rgba(12,25,23,.08);}
.price-table th:first-child{background:var(--sand-200);}
@media (max-width:640px){
  .table-scroll:has([data-label]){background:none; overflow:visible; border-radius:0;}
  .price-table:has([data-label]){display:block; border:0; border-radius:0; background:transparent;}
  .price-table:has([data-label]) thead{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap;}
  .price-table:has([data-label]) tbody,.price-table:has([data-label]) tr{display:block;}
  .price-table:has([data-label]) tr{background:var(--white); border:1px solid rgba(12,25,23,.1); border-radius:var(--radius-tag); overflow:hidden; margin-bottom:16px;}
  .price-table:has([data-label]) td{display:flex; justify-content:space-between; align-items:baseline; gap:14px; padding:10px 16px; border-bottom:1px solid rgba(12,25,23,.06); text-align:right; position:static; box-shadow:none;}
  .price-table:has([data-label]) td::before{content:attr(data-label); flex:0 0 38%; text-align:left; font-family:var(--font-mono); font-size:var(--fs-100); text-transform:uppercase; letter-spacing:.06em; color:var(--ink-muted);}
  .price-table:has([data-label]) td:first-child{display:block; background:var(--sand-200); font-weight:700; font-size:var(--fs-400); text-align:left;}
  .price-table:has([data-label]) td:first-child::before{display:none;}
  .price-table:has([data-label]) td:nth-child(2),.price-table:has([data-label]) td:nth-child(5){display:none;}
  .price-table:has([data-label]) td.price{display:block; text-align:left; border-bottom:0;}
  .price-table:has([data-label]) td.price::before{display:block; margin-bottom:6px;}
  .price-table:has([data-label]) tr:last-child td{border-bottom:1px solid rgba(12,25,23,.06);}
  .price-table:has([data-label]) tr:last-child td.price{border-bottom:0;}
}

/* P2-13: 44px hit areas without moving anything (padding cancelled by margin) */
.btn-link{padding:13px 0; margin:-13px 0; border-bottom:0; text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px;}
.breadcrumb a{display:inline-block; padding:13px 0; margin:-13px 0;}
.footer-col a:not(.footer-social a){display:inline-block; padding:8px 0; margin:-8px 0;}
.footer-social a{width:44px; height:44px;}
.logo{padding:6px 0; margin:-6px 0;}
@media (max-width:640px){.logo{padding:9px 0; margin:-9px 0;}}

/* P2-14: one fixed bar at a time; the footer stays readable under the sticky bar */
body.consent-open .sticky-cta{transform:translateY(100%);}
body:has(.sticky-cta.show) footer{padding-bottom:calc(30px + 76px);}

/* P2-15: the static arrival hint yields to the calendar's own note */
.field:has(.bk-cal:not([hidden])) [data-cal-hint]{display:none;}

/* P2-16: ticks and eyebrows follow the ground they sit on */
:is(.section-white,.section-light) .pkg-card:not([style*="var(--white)"]) .pkg-list svg{color:var(--coral);}
:is(.section-dark,.section-mid) .eyebrow{color:var(--gold-500);}
:is(.section-dark,.section-mid) .eyebrow::before,:is(.section-dark,.section-mid) .eyebrow::after{background:var(--gold-500);}

/* P3-01: nothing in the first section after an interior hero starts */
.hero:not(.hero-immersive) + section [data-reveal]{opacity:1; transform:none; transition:none;}
/* P3-02: the observer's first batch reveals without a fade (main.js) */
[data-reveal].is-instant,[data-reveal-group].is-instant > *{transition:none;}

/* P3-05: the consent bar leaves the way it came (main.js adds the class, */
.consent-bar.is-leaving{opacity:0; transform:translateY(12px);}
@media (max-width:640px){.fab-whatsapp.is-raised{translate:0 -126px;}}

/* Review fixes, 2026-09-20 ---- */
/* A chip in a hero is a sentence, not metadata: body face, no caps, white */
.hero .chip{font-family:var(--font-body); font-size:var(--fs-200); font-weight:600; letter-spacing:0; text-transform:none; color:var(--white); border-color:rgba(255,255,255,.35); padding:8px 16px;}
/* Bare links inside an intro paragraph read as body text; give them the rust underline */
.glance-grid p > a:not([class]),.section-head p > a:not([class]){text-decoration:underline; text-decoration-color:var(--rust); text-underline-offset:3px;}
/* A shortened phone hero whose last child is the lead paragraph ends on the padding, not on the le */
@media (max-width:640px){.hero:not(.hero-immersive) p.lead:last-child{margin-bottom:0;}}
/* Under 340px the German pill would squeeze the burger; the mobile menu still carries Book */
@media (max-width:339px){.nav-links > .nav-cta{display:none;}}
/* The leaving consent bar takes no clicks */
.consent-bar.is-leaving{pointer-events:none;}

/* On phones the accommodation rooftop photo keeps the fade-in the observer gives it (data-reveal="scroll"):
   shown at first paint it becomes the LCP element and costs 200-450ms; the headline stays the LCP instead. Desktop shows it at once. */
@media (max-width:640px){
  .hero:not(.hero-immersive) + section [data-reveal="scroll"]{opacity:0; transform:translateY(16px); transition:opacity 500ms var(--ease-out), transform 500ms var(--ease-out);}
  .hero:not(.hero-immersive) + section [data-reveal="scroll"].is-visible{opacity:1; transform:none;}
}

/* P4 follow-up: the booking summary is filled by booking.js after first */
.bk-summary [data-summary]{min-height:175px;}

/* ===== 2026-09-20 NIGHTLY PREVIEW: the integrator appends each work package's rules here (before the reduced-motion block) ===== */
/* wp:_wp-premium.css (integrated 2026-09-20) */
/* ===== wp-premium (2026-09-20): buttons, layout, motion. Appended before the reduced-motion block; tokens only. ===== */

/* ---------- 1. BUTTONS: three roles, one state model (docs/MOTION.md) ---------- */
/* every button-like control shares one transition list: colour/border 200ms, transform 200ms; the press retimes to 150ms below */
.btn,.nav-cta,.consent-bar button,.faq-jump a,.bk-step-actions .btn{transition:background-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);}
/* rest: no transform; the lift lives only in the hover-capable block, so a tap never leaves a button floating */
.btn:hover,.nav-cta:hover,.consent-bar button:hover,.faq-jump a:hover{transform:none;}
/* press: scale .98 in 150ms on every role, primary darkens to gold-deep (ink-900 on it 7.55:1) */
.btn:active,.nav-cta:active,.consent-bar button:active,.faq-jump a:active{transform:scale(.98); transition-duration:var(--dur-fast);}
.btn-gold:active,.nav-cta:active,.consent-accept:active{background:var(--gold-deep);}
/* text link: colour 200ms, press dims 150ms (the existing opacity .6) */
.btn-link{transition:color var(--dur) var(--ease-out), opacity var(--dur-fast) var(--ease-out);}
/* secondary on light: hover inverts (white on ink-900 17.22:1), press keeps the fill */
.btn-outline-dark:active{background:var(--ink-900); color:var(--white);}
/* segmented control (chooser): colour 200ms, press .98 in 150ms, no lift (a lifted segment breaks the strip); pressed = gold-500 fill (9.76:1) */
.lvl-seg button{transition:background-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out), transform var(--dur-fast) var(--ease-out);}
.lvl-seg button:active{transform:scale(.98);}
/* hover, mouse only: 1px lift + colour on the three roles; the segmented control and the calendar arrows change colour only */
@media (hover:hover) and (pointer:fine){
  .btn:hover,.nav-cta:hover,.consent-bar button:hover,.faq-jump a:hover{transform:translateY(-1px);}
  .btn:active,.nav-cta:active,.consent-bar button:active,.faq-jump a:active{transform:translateY(0) scale(.98);}
  .btn-gold:hover,.nav-cta:hover,.consent-accept:hover{background:var(--gold-deep);}
  .btn-outline:hover,.consent-decline:hover,.consent-save:hover{border-color:var(--gold-500); color:var(--gold-500);}
  .btn-outline-dark:hover{background:var(--ink-900); color:var(--white);}
  .btn-link:hover{color:var(--rust);}
  :is(.section-dark,.section-mid,.final-cta,.hero,.pkg-card) .btn-link:hover{color:var(--gold-500);}
  .faq-jump a:hover{background:var(--sand-200); border-color:var(--sand-200);}
}
/* touch: the secondary's hover colours must not stick after a tap */
@media (hover:none){
  .btn-outline:hover{border-color:rgba(255,255,255,.4); color:var(--white);}
  .btn-outline-dark:hover{background:transparent; color:var(--ink-900);}
  .btn-link:hover{color:inherit;}
  .faq-jump a:hover{background:transparent; border-color:rgba(12,25,23,.18);}
}
/* focus-visible: the site's 2px ring (teal-700 on light 7.43:1 white / 6.79:1 sand-100; gold-500 on dark 9.58:1), restated for the new controls */
.lvl-seg button:focus-visible,.faq-jump a:focus-visible,.bk-step-actions .btn:focus-visible,.bk-step-actions .btn-link:focus-visible,.lvl-cta:focus-visible{outline:2px solid var(--teal-700); outline-offset:3px;}
:is(.section-dark,.section-mid,.final-cta,.hero,.consent-bar,.pkg-card) :is(.btn,.btn-link,.nav-cta,button):focus-visible{outline-color:var(--gold-500);}
/* the small buttons reach the 44px floor everywhere (U12) */
.btn-sm{min-height:44px;}

/* ---------- 2. LAYOUT ---------- */
/* /packages, the three package sections: --space-9 between sections, one step smaller inside; phones --space-7 */

@media (max-width:640px){#solo,#couple,#group{padding:var(--space-7) 0;}}
/* the text column becomes a two-column grid so the two price lines sit side by side (one dominant unit with the button under it);
   every other child spans both columns; phones stack */



/* a price line is a padded box whose text stays on the column edge (negative margin); the chooser's gold outline hugs the box */



@media (max-width:640px){:is(#solo,#couple,#group) .glance-grid > div:has(.lvl-price-line) > .hero-stats{grid-column:1 / -1;}}
/* dominant: the sell price at --fs-800 (39px) on desktop, --fs-700 on phones, gold-700 (5.00:1 white); the struck list price at --fs-300 */

@media (min-width:960px){:is(#solo,#couple,#group) .hero-stat-num{font-size:var(--fs-800);}}



/* the caption under the price is a sentence, not a label: body face, no caps, --fs-200, ink-muted (7.09:1 white) */



/* support: the included list at --fs-200 in ink-muted (sand-muted on the dark band), tighter within itself (--space-2) than to its neighbours */



/* the lede steps down to body size so the h2 and the price carry the section */

/* the button is the unit's last line and books the section, not the left card: the full width of the price pair at every size,
   the hero button's footprint (56px, 15px) from 960px so it holds its own against the --fs-800 figures */

@media (min-width:960px){:is(#solo,#couple,#group) .hero-actions .btn{min-height:56px; padding:18px 34px; font-size:15px;}}

/* comparison table: the price column and the Best-for row carry the table; every other cell is support */





/* the price cell: sand-100 tint (a column band), sell number at --fs-500 in gold-700 (4.57:1 on sand-100), the rest one step down */




/* Best-for: the row that answers the visitor's question gets body size, ink-900 and a gold-500 rule above it */


/* phones (stacked cards): the row header keeps its band, the price block keeps the tint */
@media (max-width:640px){
  .price-table:has([data-label]) td{padding:var(--space-2) var(--space-4);}
  .price-table:has([data-label]) td:first-child{padding:var(--space-3) var(--space-4);}
  .price-table:has([data-label]) td.price{padding:var(--space-3) var(--space-4) var(--space-4);}
  .price-table:has([data-label]) .tr-bestfor td{border-top:2px solid var(--gold-500);}
}
/* the compare section keeps the same rhythm as the package sections */
section:has(> .wrap > .section-head + .table-scroll){padding:var(--space-9) 0;}
@media (max-width:640px){section:has(> .wrap > .section-head + .table-scroll){padding:var(--space-7) 0;}}

/* homepage sale (#packages): in each card the price line is the dominant element, the list and the blurb are support;
   the price block reads in the body face (sentence, "From", the note), the figures keep the mono face */
.pkg-card.is-rich .pkg-price b{font-size:var(--fs-700); line-height:1; font-family:var(--font-mono);}
.pkg-card.is-rich .pkg-price{font-size:var(--fs-200); font-family:var(--font-body); color:var(--sand-muted);}
.pkg-card.is-rich .pkg-price .price-was{font-family:var(--font-mono);}
.pkg-card.is-rich .pkg-price-note{font-size:var(--fs-200); opacity:1; color:var(--sand-muted);}
.pkg-card.is-rich .pkg-body > p{font-size:var(--fs-200); color:var(--sand-muted);}
.pkg-card.is-rich .pkg-incl{gap:var(--space-2); margin-bottom:var(--space-5);}
.pkg-card.is-rich .pkg-incl li{font-size:var(--fs-200); color:var(--sand-muted); line-height:1.5;}
.pkg-card.is-rich .pkg-body h3{font-size:var(--fs-500);}

/* chooser cards: the sentence around the price moves to the body face (mono for the figures only, as on /packages), the price
   keeps --fs-700, the included items step back to ink-muted so the price line is the one ink-900 + gold mass in the card */
.lvl-price{font-family:var(--font-body); color:var(--ink-muted);}
.lvl-price b,.lvl-price .price-was{font-family:var(--font-mono);}
.lvl-incl li{color:var(--ink-muted);}
.lvl-incl{gap:var(--space-2);}

/* ---------- 3. MOTION (additions; every value in scratchpad/nightly/motion-additions.md) ---------- */
/* "Your level" mark on /packages: fades in with a 4px rise (state indication, once per switch), 200ms ease-out */


/* faq-jump chips: the same colour transition and press as the buttons (declared above); nothing else */

/* ---------- reduced motion: movement off, colour kept (the site's global block follows and covers .btn / .nav-cta) ---------- */
@media (prefers-reduced-motion: reduce){
  .btn,.nav-cta,.consent-bar button,.faq-jump a,.bk-step-actions .btn,.lvl-seg button{transition-property:background-color,color,border-color;}
  :is(.btn,.nav-cta,.consent-bar button,.faq-jump a,.lvl-seg button):is(:hover,:active){transform:none;}
  .lvl-price-line::before{transform:none; transition:opacity var(--dur) var(--ease-out);}
}
/* ===== /wp-premium ===== */
/* /wp:_wp-premium.css */

/* wp:_wp-langpill.css (integrated 2026-09-23) */
/* ===== wp-langpill (2026-09-23): the language control in the mobile drawer ===== */
/* The drawer listed the other languages as three 30px display links among the nav
   links, so "Français Español Deutsch" read as three more destinations. They become
   one compact pill showing the language you are in; tapping it expands the others to
   its right. Desktop keeps the existing dropdown (.lang-menu) untouched. */

/* The wrapper also carries .lang-switch, so main.js's existing toggle, its
   outside-click close and its aria-expanded handling drive this control too. */
.lang-pill{align-self:flex-start; display:flex; align-items:center; gap:var(--space-2); max-width:100%;}

/* Trigger: inherits .lang-switch button (mono, bordered, tag radius) and only adds
   the 44px touch target, full opacity and the open state. */
.mobile-menu .lang-pill-btn{
  min-height:44px; padding:0 14px; opacity:1;
  background:rgba(255,255,255,.04); flex:none;
}
.lang-pill-globe{width:16px; height:16px; flex:none;}
.lang-pill[data-open="true"] .lang-pill-btn{border-color:var(--gold-500); color:var(--gold-500);}

/* The answers: laid out to the RIGHT of the trigger, hidden until it is tapped.
   visibility keeps them out of the tab order while closed. */
.lang-pill-menu{display:flex; align-items:center; gap:var(--space-2); min-width:0; opacity:0; visibility:hidden;}
.lang-pill[data-open="true"] .lang-pill-menu{opacity:1; visibility:visible;}

/* Two-letter codes, not the 30px display links the drawer gives every other <a>. */
.mobile-menu .lang-pill-menu a{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:44px; min-height:44px; padding:0 12px;
  /* weight 400: the 600 cut of the mono face is not loaded on most pages, and asking for it
     here would pull a fourth font file onto all 93 of them for three two-letter chips. */
  font-family:var(--font-mono); font-size:var(--fs-100); font-weight:400;
  letter-spacing:.08em; text-transform:uppercase;
  color:var(--sand-100); background:rgba(255,255,255,.06);
  border:1px solid rgba(255,255,255,.18); border-radius:var(--radius-tag-sm);
}
/* the language's own name, for screen readers and for translation tools */
.lang-pill-name{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;}

/* ---------- motion (docs/MOTION.md: transform and opacity only, one easing) ---------- */
/* The pill opens rightwards: each answer slides in from the trigger's edge, 40ms
   apart, so the row reads left to right instead of appearing at once. */
.lang-pill-menu{transition:opacity var(--dur) var(--ease-out), visibility 0s linear var(--dur);}
.lang-pill[data-open="true"] .lang-pill-menu{transition:opacity var(--dur) var(--ease-out), visibility 0s;}
.mobile-menu .lang-pill-menu a{
  transform:translateX(calc(-1 * var(--space-3)));
  transition:transform var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out),
             background-color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
             color var(--dur) var(--ease-out);
}
.lang-pill[data-open="true"] .lang-pill-menu a{transform:none;}
.lang-pill[data-open="true"] .lang-pill-menu a:nth-child(2){transition-delay:40ms;}
.lang-pill[data-open="true"] .lang-pill-menu a:nth-child(3){transition-delay:80ms;}
/* pressed state matches every other control in the system (150ms, .98) */
.mobile-menu .lang-pill-menu a:active,.mobile-menu .lang-pill-btn:active{transform:scale(.98); transition-duration:var(--dur-fast);}
@media (hover:hover) and (pointer:fine){
  .mobile-menu .lang-pill-menu a:hover{background:rgba(255,255,255,.12); border-color:var(--gold-500); color:var(--gold-500);}
}
@media (prefers-reduced-motion: reduce){
  .mobile-menu .lang-pill-menu a{transform:none; transition-property:opacity,background-color,border-color,color; transition-delay:0s;}
  .lang-pill[data-open="true"] .lang-pill-menu a{transition-delay:0s;}
  .mobile-menu .lang-pill-menu a:active,.mobile-menu .lang-pill-btn:active{transform:none;}
}
/* ===== /wp-langpill ===== */
/* /wp:_wp-langpill.css */

/* wp:_wp-owner-20260923 (integrated 2026-09-23) */
/* ---------- /packages: one price at a time ---------- */
/* The chooser hides the level you did not pick (main.js sets [hidden] on the other
   price line). Without JavaScript nothing is hidden, so both prices still show. */

/* the one that stays reads as the package's price, not as one of a pair */

/* ---------- booking summary: air before the review card ---------- */
/* It sat directly under the Stripe note, so the card read as part of the sentence. */
.bk-summary .testi-rotator{margin-top:var(--space-5);}
/* ===== /wp-owner-20260923 ===== */

/* wp:_wp-contrast-20260923 (integrated 2026-09-23) */
/* Two contrast failures Lighthouse raised on the preview. Both are in rules this build did not
   write and both are on the live site today; the figures are the blended values axe computes.
   1. The footer's bottom line: sand-muted at .55 over teal-950 reads 3.75:1 at 12.5px (needs 4.5).
      Raising the opacity to .72 gives 5.3:1 and keeps it visibly quieter than the links above it. */
.footer-bottom{opacity:.72;}
/* 2. The Instagram line under the gallery: rust at .7 over the cream page reads 2.93:1. The
      sentence stays quiet; the link inside it comes back to full strength (rust on cream, 4.89:1). */
.gallery-note-link{opacity:1;}
/* ---------- booking summary: the figures carry the weight ---------- */
/* Everything here already passed (5.6:1 muted, 13.6:1 strong), but the amounts read in the same
   colour and weight as their labels, so the panel looked pale and the money was the last thing
   the eye found. The label stays quiet; the figure goes to full ink. The struck list price stays
   quiet on purpose - it is a reference, not what anyone pays. */
.bk-summary .bk-row > span:last-child{color:var(--ink-900);}
.bk-summary .bk-row:not(.is-strong) > span:first-child{color:var(--ink-600);}
.bk-summary .bk-row .price-was{color:var(--ink-muted); font-weight:400;}
.bk-summary .bk-row.is-sub > span:last-child{font-weight:400;}
/* ===== /wp-contrast-20260923 ===== */

/* wp:_wp-ladder-20260923 (P2, approved) */
/* The mono face is for figures. A figure inside a sentence keeps it; the sentence around it
   stays prose, so the two never swap roles. Size and colour are inherited on purpose. */
.fig{font-family:var(--font-mono); font-weight:600; font-style:normal;}
/* ===== /wp-ladder-20260923 ===== */

/* wp:_wp-jrnband-20260923 (P3, approved) */
/* The journal's booking band: one dark-on-sand block between the article and keep-reading.
   Centred, one dominant line, the price under it, the two existing buttons. */
.jrn-band-in{max-width:720px; margin-inline:auto; text-align:center;}
.jrn-band-in .eyebrow{justify-content:center; font-weight:400;}   /* see the note above: no 600 cut on these pages */
/* .section-mid is a DARK band (teal-800), so the on-dark tokens apply: sand for prose,
   gold-500 for the figure (6.07:1), sand-muted for the quiet lines (5.94:1). */
.jrn-band-lede{color:var(--sand-muted); margin:0 auto var(--space-4); max-width:56ch;}
.jrn-band-price{font-family:var(--font-mono); font-size:var(--fs-300); color:var(--sand-100); margin:0 0 var(--space-5);}
.jrn-band-price b{font-size:var(--fs-600); font-weight:400; color:var(--gold-500); margin-inline:var(--space-2) var(--space-2);}
.jrn-band-price .price-was{color:var(--sand-muted); font-weight:400;}
.jrn-band-note{display:block; font-family:var(--font-body); font-size:var(--fs-200); color:var(--sand-muted); margin-top:var(--space-2);}
.jrn-band-note .fig{color:var(--sand-100);}
.jrn-band .hero-actions{justify-content:center;}
/* ===== /wp-jrnband-20260923 ===== */

/* ===== /wp-integration ===== */

/* P3-04: reduced motion means fewer and gentler, not none */
@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto !important;}
  *{animation:none !important;}
  [data-reveal],[data-reveal-group] > *,.hero:not(.hero-immersive) + section [data-reveal="scroll"]{opacity:1; transform:none; transition:none;}
  .mobile-menu,.mobile-menu.open,.sticky-cta,.bk-bar,.consent-bar,.consent-bar.is-leaving,.skip-link,.testi-track > .testi-card,.testi-track > .testi-card.is-on{transition-duration:0s;}
  .lang-menu{transform:none; transition:opacity var(--dur-fast) var(--ease-out), visibility 0s linear var(--dur-fast);}
  .btn,.nav-cta,.bk-cal-day,.bk-cal-arrow,a.pkg-card,.pkg-card:has(.btn){transition-property:background-color,color,border-color,opacity,box-shadow;}
  :is(.btn,.nav-cta,.bk-cal-day,.bk-cal-arrow,a.pkg-card,.pkg-card:has(.btn)):is(:hover,:active){transform:none;}
  .fab-whatsapp{transition:opacity var(--dur) var(--ease-out), visibility var(--dur) var(--ease-out);}
  .fab-whatsapp:is(:hover,:active){scale:none;}
  .faq-a{transition:none;}
  .faq-q .plus,.testi-dots button::before{transition:none;}
}
