/* polish.css — load order: AFTER ngor-surfcamp.min.css
 * Impeccable UX polish layer. Overrides only — no new components.
 * Each block answers a specific impeccable critique (see comments).
 */

/* ──────────────────────────────────────────────────────────
 * Stats hierarchy: invert color emphasis.
 * Was: big number in navy (cool), label/desc in navy/slate.
 * Now: big number in fire (warm, attention-grabbing), labels tinted neutral.
 * ────────────────────────────────────────────────────────── */
.home-proof-fact-n {
  color: var(--fire) !important;
  font-size: clamp(28px, 4vw, 44px) !important;
  letter-spacing: -.02em;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
}
.home-proof-fact-t {
  color: var(--navy) !important;
  letter-spacing: -.005em;
}
.home-proof-fact-d {
  color: #475569 !important; /* slate-600, slightly darker than original #64748b for legibility */
}

/* ──────────────────────────────────────────────────────────
 * Trust badges grouping.
 * Was: 3 separated pills floating with margins.
 * Now: contained band with vertical dividers, more compact, more design-system feel.
 * ────────────────────────────────────────────────────────── */
.hero-trust {
  display: inline-flex !important;
  flex-wrap: wrap;
  gap: 0 !important;
  padding: 6px 4px !important;
  background: rgba(12, 28, 48, .58) !important;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .08);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.hero-trust .trust-badge {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 6px 18px !important;
  position: relative;
}
.hero-trust .trust-badge + .trust-badge::before {
  content: '';
  position: absolute;
  left: 0; top: 25%; bottom: 25%;
  width: 1px;
  background: rgba(255, 255, 255, .14);
}
.hero-trust .trust-badge:hover {
  transform: none !important;
  color: rgba(255, 255, 255, 1) !important;
}
@media (max-width: 600px) {
  .hero-trust {
    flex-direction: column;
    padding: 6px 8px !important;
    border-radius: 14px;
  }
  .hero-trust .trust-badge + .trust-badge::before {
    left: 18%; right: 18%;
    top: auto;
    width: auto;
    height: 1px;
    bottom: 0;
  }
}

/* ──────────────────────────────────────────────────────────
 * Home destination cards — bento asymmetric.
 * Was: identical 3 cards (forbidden by shared design law).
 * Now: 1st card spans 2 cols on desktop (Surf House = the flagship product),
 *      2nd + 3rd stack to its right. On tablet: 2 cols. On mobile: stack.
 * Surgical: only .home-section .grid-3 (not all grid-3 instances).
 * ────────────────────────────────────────────────────────── */
/* Destination cards — uniform 3-col with forced equal heights + uniform
 * image aspect ratio. Bento ratio reverted (was visually messy with
 * mixed portrait/landscape source images). */
.grid-3:has(.card-h3) {
  display: grid !important;
  grid-template-columns: repeat(3, 1fr) !important;
  gap: 22px !important;
  align-items: stretch;
}
.grid-3:has(.card-h3) > .card {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: visible;
}
/* Force every card image into a fixed 4:3 frame, cover-fit, no matter
 * the source aspect ratio. Kills the portrait/landscape mismatch. */
.grid-3:has(.card-h3) > .card > picture {
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  flex-shrink: 0;
}
.grid-3:has(.card-h3) > .card .card-img,
.grid-3:has(.card-h3) > .card > picture img,
.grid-3:has(.card-h3) > .card > picture > img {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  display: block;
  aspect-ratio: 4 / 3;
}
/* Card body grows to fill remaining height, CTA pinned to bottom */
.grid-3:has(.card-h3) > .card .card-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.grid-3:has(.card-h3) > .card .card-text {
  flex: 1 1 auto;
}
.grid-3:has(.card-h3) > .card .card-cta,
.grid-3:has(.card-h3) > .card .btn-deep,
.grid-3:has(.card-h3) > .card .btn.btn-deep {
  margin-top: auto !important;
}
@media (max-width: 900px) {
  .grid-3:has(.card-h3) {
    grid-template-columns: 1fr 1fr !important;
  }
}
@media (max-width: 600px) {
  .grid-3:has(.card-h3) {
    grid-template-columns: 1fr !important;
  }
}

/* ──────────────────────────────────────────────────────────
 * Flatten card-h3 nested padding.
 * Was: <a.card> > <picture> + <div.card-body> > h3 + p + span.btn-deep.
 *      Nested cards-in-cards visual reflex.
 * Now: card-body padding reduced + h3 tightened, btn-deep becomes inline arrow.
 * ────────────────────────────────────────────────────────── */
.card .card-body {
  padding: 20px 22px 22px !important;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.card .card-h3 {
  margin: 0 !important;
  font-size: clamp(18px, 2vw, 22px);
  letter-spacing: -.01em;
}
.card .card-text {
  margin: 0 !important;
  color: #475569;
  font-size: 14px;
  line-height: 1.55;
}
/* Pillar card CTA — orange filled button */
.grid-3:has(.card-h3) > a.card .card-cta.btn.btn-fire,
.card .card-cta.btn.btn-fire,
a.card > .card-body > .card-cta.btn.btn-fire {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  margin-top: auto !important;
  padding: 10px 18px !important;
  background: linear-gradient(135deg, #ff6b35, var(--fire)) !important;
  color: #fff !important;
  font-weight: 700;
  border: 0 !important;
  border-radius: var(--r-sm, 10px);
  box-shadow: 0 4px 16px rgba(255,90,31,0.28) !important;
  letter-spacing: .04em;
  font-size: 13px;
  text-transform: uppercase;
  line-height: 1.4;
  text-decoration: none !important;
  position: relative;
  overflow: hidden;
  transition: transform .14s ease, box-shadow .14s ease, filter .14s ease;
}
.card .card-cta.btn.btn-fire::before,
a.card:hover .card-cta.btn.btn-fire::before {
  content: none !important;
  display: none !important;
}
.card .card-cta.btn.btn-fire::after {
  content: '→' !important;
  display: inline-block !important;
  margin-left: 0;
  transition: transform .2s cubic-bezier(.16,1,.3,1);
}
a.card:hover .card-cta.btn.btn-fire {
  color: #fff !important;
  text-decoration: none !important;
  filter: brightness(1.06);
  box-shadow: 0 6px 22px rgba(255,90,31,0.38) !important;
  transform: translateY(-1px) !important;
}
a.card:hover .card-cta.btn.btn-fire::after {
  transform: translateX(4px);
}
/* Legacy markup still using .btn-deep inside pillar cards */
.card .btn-deep,
.card .btn.btn-deep {
  align-self: flex-start;
  margin-top: 4px !important;
  padding: 0 !important;
  background: transparent !important;
  color: var(--fire) !important;
  font-weight: 700;
  border: 0 !important;
  box-shadow: none !important;
  letter-spacing: .04em;
  font-size: 12px;
  text-transform: uppercase;
  line-height: 1.4;
  position: relative;
}
.card .btn-deep::before,
.card .btn.btn-deep::before {
  display: none !important;
  content: none !important;
}
.card .btn-deep::after,
.card .btn.btn-deep::after {
  content: '→';
  margin-left: 6px;
  display: inline-block;
  transition: transform .2s cubic-bezier(.16,1,.3,1);
}
a.card:hover .btn-deep::after,
a.card:hover .btn.btn-deep::after {
  transform: translateX(4px);
}

/* ──────────────────────────────────────────────────────────
 * Section labels — slightly tighter, more editorial.
 * Was: scattered 1em letter-spacing, 11px.
 * Now: 10.5px + .14em letter, 800 weight in fire.
 * ────────────────────────────────────────────────────────── */
.s-label {
  font-size: 10.5px !important;
  letter-spacing: .14em !important;
  font-weight: 800 !important;
  color: var(--fire);
}

/* NOTE: hero-video-wrap aspect-ratio override removed — base CSS uses
 * position:absolute;inset:0 to fill section.hero. */

/* Fix QA #3 + #3b — focal pad on hero-video-wrap.
 * The wrap MUST be position:absolute;inset:0 so the focal-pad overlay
 * (inset:0 absolute child) fills the entire section.hero. Some build
 * variants computed it as position:relative → wrap 0px wide → focal
 * pad invisible. Force the original spec + min-height fallback. */
.hero-video-wrap {
  position: absolute !important;
  inset: 0 !important;
  width: auto !important;
  height: auto !important;
  min-height: 240px;
}

/* ──────────────────────────────────────────────────────────
 * Surf House page — section background harmony.
 * Original sequence (jarring): WHITE → NAVY → WHITE → BROWN(rgb 26,14,5) → NAVY → light → light → CTA-band.
 * The brown (.sh2-meals-section) was an outlier vs the rest of the
 * site's navy/white/sand palette + clashed visually with adjacent
 * white split section above.
 * Fix: align brown to the same navy as .sh2-feats-section so dark
 * sections feel like one consistent depth tier; subtle radial gradient
 * for breath; add scrim padding-bottom so the section→section join
 * doesn't feel like a flat color rectangle on wide screens.
 * ────────────────────────────────────────────────────────── */
.sh2-meals-section {
  background:
    radial-gradient(ellipse at 50% 20%, rgba(255, 138, 75, .08) 0%, transparent 55%),
    #0a2540 !important;
  position: relative;
}
/* Smooth transition WHITE→NAVY between split-right (pool) and meals */
.sh2-split-section.sh2-split-right + .sh2-meals-section::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 80px;
  background: linear-gradient(180deg, rgba(255,255,255,.04) 0%, transparent 100%);
  pointer-events: none;
}
/* Soften stats strip → meals join (dark+dark stacked) */
.sh2-meals-section + .sh2-stats-strip {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}

/* Standardize all dark sections to the same navy family.
 * Removes random brown/black variations across pages. */
.sh2-feats-section,
.sh2-meals-section,
.sh2-stats-strip {
  /* keep their individual gradients but enforce the navy base */
  background-color: #0a2540 !important;
}

/* Section padding harmony — guarantee 80-120px vertical rhythm on
 * every full-bleed section so transitions feel deliberate.
 * Sweep covers all top-level <section> across the site (home, surf-house,
 * island, surf, booking, faq, blog). Audit revealed mix of 56/56, 64/80,
 * 88/88, 100/60, 100/100, 104/104, 48/48 → unified rhythm below.
 * Exempt: .cta-band keeps 104 (slightly louder bottom CTA), stats strips
 * keep their 0/0 or 48/48 (intentionally tight). */
main > section.section,
main > section.sh2-split-section,
main > section.sh2-meals-section,
main > section.sh2-feats-section,
main > section.sh2-ni-section,
main > section.surf-story-sec,
main > section.surf-spots-sec,
main > section.island-guides-hub-section,
main > section.ig-section {
  padding-block: 100px !important;
}
@media (max-width: 768px) {
  main > section.section,
  main > section.sh2-split-section,
  main > section.sh2-meals-section,
  main > section.sh2-feats-section,
  main > section.sh2-ni-section,
  main > section.surf-story-sec,
  main > section.surf-spots-sec,
  main > section.island-guides-hub-section,
  main > section.ig-section {
    padding-block: 64px !important;
  }
}
/* Exempt narrow strips (stats) — keep their intentional tight rhythm */
main > section.sh2-stats-strip,
main [class*="stats-strip"] {
  padding-block: 48px !important;
}
/* Exempt booking page — form-heavy, large vertical padding would
 * push the form below the fold and hurt conversion. */
body[data-stem="book_online"] main > section.section {
  padding-block: 48px !important;
}

/* ──────────────────────────────────────────────────────────
 * Typography hierarchy harmony.
 * Audit found 6 different h2 sizes (34, 36, 40, 42, 44, 50) + 2 weight
 * variants (700 vs 900) across pages. No clear hierarchy.
 * Now: 2 tiers max — primary h2 50px / weight 800 / .s-title-like,
 * secondary section h2 (page-specific) 38px / 800. Same letter-spacing
 * tightening (-.02em) for editorial feel.
 * ────────────────────────────────────────────────────────── */
main h2.s-title,
main h2.sh2-feats-h2,
main h2.sh2-meals-h2,
main h2.sh2-ni-h2 {
  font-size: clamp(28px, 4.5vw, 50px) !important;
  font-weight: 800 !important;
  line-height: 1.12 !important;
  letter-spacing: -.02em !important;
}
main h2.sh2-split-h2,
main h2.hg-title {
  font-size: clamp(24px, 3.5vw, 38px) !important;
  font-weight: 800 !important;
  line-height: 1.15 !important;
  letter-spacing: -.015em !important;
}
/* Card h3 — already harmonized via grid:has rule above, keep 22px */
main h3.card-h3,
main h3.sh-feat-title,
main h3.surf-spot-name,
main h3.surf-feat-title {
  font-size: clamp(18px, 1.8vw, 22px) !important;
  font-weight: 700 !important;
  line-height: 1.3 !important;
  letter-spacing: -.01em !important;
}

/* ──────────────────────────────────────────────────────────
 * Button system harmony.
 * Inventory across pages: btn-fire, btn-glass, btn-outline, btn-outline-white,
 * btn-navy, btn-ocean, btn-deep, btn-wa, btn-wa-green, google-cta-btn +
 * size modifiers btn-lg/md/sm. Too many variants for the same intents.
 * Lock primary / secondary / size grammar below — keep aliases working
 * (existing markup unchanged), but normalize their computed look.
 * ────────────────────────────────────────────────────────── */
.btn { transition: transform .14s cubic-bezier(.16,1,.3,1), box-shadow .14s ease, background-color .14s ease; }
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
/* Sizes — ensure btn-lg / btn-md / btn-sm are predictable */
.btn-lg { padding: 14px 28px !important; font-size: 14px !important; min-height: 50px; }
.btn-md { padding: 11px 22px !important; font-size: 13px !important; min-height: 42px; }
.btn-sm { padding: 8px 16px !important; font-size: 12px !important; min-height: 34px; }
/* Primary fire — single source of truth shadow */
.btn-fire {
  background: var(--fire, #ff5a1f) !important;
  color: #fff !important;
  box-shadow: 0 6px 18px rgba(255, 90, 31, .35), 0 1px 2px rgba(0,0,0,.12) !important;
}
.btn-fire:hover {
  background: #ff7546 !important;
  box-shadow: 0 8px 22px rgba(255, 90, 31, .45), 0 2px 4px rgba(0,0,0,.18) !important;
}
/* Glass / outline-white / navy / ocean → unify as one "secondary on dark" */
.btn-glass, .btn-outline-white {
  background: rgba(255,255,255,.10) !important;
  color: #fff !important;
  border: 1px solid rgba(255,255,255,.35) !important;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.btn-glass:hover, .btn-outline-white:hover {
  background: rgba(255,255,255,.18) !important;
  border-color: rgba(255,255,255,.55) !important;
}
/* Outline (secondary on light) */
.btn-outline {
  background: transparent !important;
  color: var(--navy, #0a2540) !important;
  border: 1.5px solid var(--navy, #0a2540) !important;
}
.btn-outline:hover {
  background: var(--navy, #0a2540) !important;
  color: #fff !important;
}
/* WhatsApp — unify btn-wa + btn-wa-green */
.btn-wa, .btn-wa-green {
  background: #25d366 !important;
  color: #fff !important;
  border: 0 !important;
  box-shadow: 0 4px 14px rgba(37, 211, 102, .35), 0 1px 2px rgba(0,0,0,.12) !important;
}
.btn-wa:hover, .btn-wa-green:hover {
  background: #1faa54 !important;
}

/* ──────────────────────────────────────────────────────────
 * Card / grid gap harmony — 24px desktop, 18px mobile.
 * Audit: 0px, 6px, 14px, 16px, 22px, 24px, 32px. Too varied.
 * Exempt: ig-grid (intentional dense 6px), strips with 0px (children
 * handle internal spacing).
 * ────────────────────────────────────────────────────────── */
.grid-3, .grid-2,
.home-proof-grid,
.sh2-feats-grid { gap: 24px !important; }
@media (max-width: 768px) {
  .grid-3, .grid-2,
  .home-proof-grid,
  .sh2-feats-grid { gap: 18px !important; }
}

/* ============================================================
 * WAHOU LAYER — premium micro-interactions
 * Respects prefers-reduced-motion (block at top of file already).
 * Hardware-accelerated only (transform/opacity), no layout animations.
 * ============================================================ */

/* Cards: lift + image zoom + shadow growth on hover.
 * .card, .review-card, .faq-item, .polaroid, .island-guide-card */
.card, .review-card, .island-guide-card {
  transform: translateZ(0);
  transition:
    transform .42s cubic-bezier(.16, 1, .3, 1),
    box-shadow .42s cubic-bezier(.16, 1, .3, 1);
  will-change: transform;
}
.card:hover, .review-card:hover, .island-guide-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 24px 48px rgba(10, 37, 64, .14), 0 4px 12px rgba(10, 37, 64, .08);
}
.card picture,
.island-guide-card picture {
  overflow: hidden;
}
.card picture img,
.card .card-img,
.island-guide-card picture img {
  transition: transform .8s cubic-bezier(.16, 1, .3, 1);
  will-change: transform;
}
.card:hover picture img,
.card:hover .card-img,
.island-guide-card:hover picture img {
  transform: scale(1.06);
}

/* Buttons: gradient shine sweep on hover (the "wahou" oil-slick effect) */
.btn-fire, .btn-glass, .btn-outline-white, .btn-wa, .btn-wa-green {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.btn-fire::after,
.btn-glass::after,
.btn-outline-white::after,
.btn-wa::after,
.btn-wa-green::after {
  content: '';
  position: absolute;
  top: 0; left: -120%;
  width: 70%;
  height: 100%;
  background: linear-gradient(115deg,
    transparent 30%,
    rgba(255, 255, 255, .28) 50%,
    transparent 70%);
  transform: skewX(-22deg);
  transition: left .65s cubic-bezier(.16, 1, .3, 1);
  pointer-events: none;
  z-index: 1;
}
.btn-fire:hover::after,
.btn-glass:hover::after,
.btn-outline-white:hover::after,
.btn-wa:hover::after,
.btn-wa-green:hover::after {
  left: 130%;
}

/* Stats numbers: subtle pulse when viewport-entered (via reveal class) */
@keyframes nsc-stat-glow {
  0% { text-shadow: 0 0 0 rgba(255, 90, 31, 0); }
  50% { text-shadow: 0 0 28px rgba(255, 90, 31, .35); }
  100% { text-shadow: 0 0 0 rgba(255, 90, 31, 0); }
}
.reveal.is-visible .home-proof-fact-n,
.is-visible .home-proof-fact-n {
  animation: nsc-stat-glow 1.6s cubic-bezier(.16, 1, .3, 1) 1;
}

/* Section eyebrows: animated underline draw on enter */
@keyframes nsc-eyebrow-line {
  from { transform: scaleX(0); transform-origin: left center; }
  to   { transform: scaleX(1); transform-origin: left center; }
}
.s-label::before {
  animation: nsc-eyebrow-line .9s cubic-bezier(.16, 1, .3, 1) .15s both;
}

/* H1/H2 entrance: subtle slide-fade staggered with description */
@keyframes nsc-headline-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
.hero-h1,
section.section .s-title,
section.sh2-split-section h2,
section.sh2-meals-section h2,
section.sh2-feats-section h2 {
  animation: nsc-headline-in .8s cubic-bezier(.16, 1, .3, 1) both;
}
section.section .s-title { animation-delay: .12s; }
section .s-sub, section .sh2-split-lead { animation: nsc-headline-in .8s cubic-bezier(.16, 1, .3, 1) .22s both; }

/* Image fade-in REMOVED — was breaking gallery carousels (.hg-img,
 * ig-grid, polaroid stacks) by forcing opacity:0 on all lazy imgs
 * while their JS toggles .hg-active for opacity-based slideshow.
 * Net effect: black gallery frames since the override always wins.
 * Restore default browser behavior on imgs (instant paint). */

/* Nav: subtle backdrop blur tightening on scroll (already glassy) */
.nav,
nav.nav,
header.nav,
.site-header {
  transition: backdrop-filter .3s ease, background-color .3s ease, box-shadow .3s ease;
}

/* Magnetic-feel hover on icon buttons */
.nsc-wa-fab,
.live-edit-btn,
.live-edit-btn-change,
.live-edit-btn-focus {
  transition:
    transform .22s cubic-bezier(.16, 1, .3, 1),
    box-shadow .22s cubic-bezier(.16, 1, .3, 1),
    background-color .14s ease;
}

/* Reduced motion: kill all the wahou layer */
@media (prefers-reduced-motion: reduce) {
  .card, .review-card, .island-guide-card,
  .card picture img, .card .card-img, .island-guide-card picture img,
  .btn-fire::after, .btn-glass::after, .btn-outline-white::after,
  .btn-wa::after, .btn-wa-green::after,
  .s-label::before,
  .hero-h1, .s-title, .sh2-split-h2, .sh2-feats-h2, .sh2-meals-h2,
  .s-sub, .sh2-split-lead {
    animation: none !important;
    transition: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
}

/* Eyebrow labels — bump weight + slight glow on dark bg for legibility.
 * "POOL & COMMON AREAS" / "KITCHEN & DINING" / "POOL & COMMON AREAS"
 * were 11px and washed out at distance. */
.sh2-split-section .s-label,
.sh2-meals-section .s-label,
.sh2-feats-section .s-label,
.sh2-ni-section .s-label,
.section .s-label {
  font-size: 11px !important;
  font-weight: 800 !important;
  letter-spacing: .16em !important;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
/* Replace the existing ::before bullet with a wider, brand-orange line */
.s-label::before {
  content: '';
  display: inline-block;
  width: 28px;
  height: 2px;
  background: var(--fire, #ff5a1f);
  border-radius: 2px;
  margin-right: 2px;
}

/* Fix QA #4 — horizontal overflow 8px mobile (375px).
 * REVERTED .container max-width:100vw override — was breaking the
 * site-wide centered layout (original .container = max-width 1100px
 * via --max var). Elements flushed to viewport edge instead of
 * centered. Keep only the defensive html/body scroll guard + the
 * specific known overflow culprits clamped to 100% of their parent. */
html, body { overflow-x: hidden; }
.sh2-duo, .sh2-split-media { max-width: 100% !important; overflow: hidden; }

/* Fix QA #4 (suite) — polaroid tribe board uniformity.
 * Original: variable widths/heights driven by inline rotate transforms.
 * Now: enforce 3-column grid with fixed aspect-ratio 3:4. The polaroids
 * keep their rotation transforms — applied AFTER the layout is decided,
 * so they tilt without changing the slot box. */
.tribe-board {
  display: grid !important;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
  justify-items: center;
  align-items: start;
  padding: 28px 0 8px;
  overflow: visible;
}
.tribe-board .polaroid {
  width: 100% !important;
  max-width: 280px;
  aspect-ratio: 3 / 4;
  margin: 0 !important;
  /* Preserve inline rotate transform via custom prop fallback */
  transform: rotate(var(--polaroid-tilt, 0deg)) !important;
}
.tribe-board .polaroid:nth-child(odd)  { --polaroid-tilt: -2.5deg; }
.tribe-board .polaroid:nth-child(even) { --polaroid-tilt: 2.5deg; }
.tribe-board .polaroid:nth-child(3n)   { --polaroid-tilt: -1deg; }
.tribe-board .polaroid img {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover;
}
@media (max-width: 900px) {
  .tribe-board { grid-template-columns: repeat(2, 1fr); gap: 22px; }
}
@media (max-width: 540px) {
  .tribe-board { grid-template-columns: 1fr; gap: 18px; }
  .tribe-board .polaroid { max-width: 240px; }
}

/* ──────────────────────────────────────────────────────────
 * Reco #6 — Hero vignette overlay (text readability over any video frame)
 * ────────────────────────────────────────────────────────── */
.hero-video-wrap::after {
  content: '' !important;
  display: block !important;
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(6,16,30,.15) 0%, transparent 30%, transparent 55%, rgba(6,16,30,.55) 100%),
    radial-gradient(ellipse at 50% 70%, transparent 30%, rgba(6,16,30,.3) 100%);
}

/* ──────────────────────────────────────────────────────────
 * Reco #11 — Sticky WhatsApp mobile button (right-bottom FAB)
 * ────────────────────────────────────────────────────────── */
.nsc-wa-fab {
  position: fixed;
  bottom: 18px;
  right: 18px;
  z-index: 100;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #25d366;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 18px rgba(37, 211, 102, .45), 0 2px 4px rgba(0, 0, 0, .12);
  text-decoration: none;
  transition: transform .2s cubic-bezier(.16,1,.3,1), box-shadow .2s;
  /* Animated pulse ring */
  animation: nsc-wa-pulse 2.4s ease-out infinite;
}
.nsc-wa-fab:hover {
  transform: scale(1.08);
  box-shadow: 0 8px 24px rgba(37, 211, 102, .55), 0 4px 8px rgba(0, 0, 0, .18);
}
.nsc-wa-fab svg { width: 28px; height: 28px; }
.nsc-wa-fab::before {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 2px solid #25d366;
  opacity: .6;
  animation: nsc-wa-ring 2.4s ease-out infinite;
}
@keyframes nsc-wa-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.04); }
}
@keyframes nsc-wa-ring {
  0% { transform: scale(1); opacity: .6; }
  100% { transform: scale(1.35); opacity: 0; }
}
/* Hide FAB on booking page (user is already converting) */
body[data-stem="book_online"] .nsc-wa-fab { display: none; }
/* Hide on small screens if standard WA button already in nav */
@media (min-width: 1024px) {
  .nsc-wa-fab { bottom: 22px; right: 22px; }
}

/* ──────────────────────────────────────────────────────────
 * Reco #16 — Reading progress bar (top of viewport, scroll-linked)
 * ────────────────────────────────────────────────────────── */
.nsc-progress-bar {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 0;
  background: linear-gradient(90deg, var(--fire, #ff5a1f), var(--sand, #f0c060));
  z-index: 101;
  pointer-events: none;
  transition: width .12s linear;
  box-shadow: 0 0 8px rgba(255, 90, 31, .4);
}

/* ──────────────────────────────────────────────────────────
 * Reco #19 — Reduced motion respect (system preference)
 * Disables count-up, GSAP scroll, video autoplay, all transitions.
 * ────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .nsc-wa-fab,
  .nsc-wa-fab::before { animation: none !important; }
  #hero-video { /* pause autoplay visually — JS handles actual pause */ }
}

/* ──────────────────────────────────────────────────────────
 * Reco #20 — View Transitions API (Chrome 111+ progressive enhancement)
 * Cross-fade between same-origin navigation (FR home ↔ surf-house etc).
 * ────────────────────────────────────────────────────────── */
@view-transition {
  navigation: auto;
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .35s;
  animation-timing-function: cubic-bezier(.16, 1, .3, 1);
}

/* ──────────────────────────────────────────────────────────
 * Reco #1 — Lazy gallery non-hero with skeleton shimmer
 * (Hero stays loading="eager" — it's the LCP candidate).
 * ────────────────────────────────────────────────────────── */
.hg-img:not(.hg-active) {
  background:
    linear-gradient(90deg, #e2e8f0 0%, #f1f5f9 50%, #e2e8f0 100%);
  background-size: 200% 100%;
  animation: nsc-shimmer 1.4s ease-in-out infinite;
}
.hg-img:not(.hg-active)[src],
.hg-img:not(.hg-active).is-loaded {
  animation: none;
  background: none;
}
@keyframes nsc-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ══════════════════════════════════════════════════════════
 * VISUAL AUDIT 2026-05-14 — Fixes A–J
 * All pages FR live. 10 bugs fixed, 2 deferred (L effort).
 * ══════════════════════════════════════════════════════════ */

/* ──────────────────────────────────────────────────────────
 * FIX A — Footer email overflow · all pages · mobile
 * info@surfcampsenegal.com is 179px in a 154px .footer-col.
 * overflow-wrap breaks the address at column boundary.
 * ────────────────────────────────────────────────────────── */
.footer-col a {
  overflow-wrap: break-word;
  word-break: break-word;
  min-width: 0;
}

/* ──────────────────────────────────────────────────────────
 * FIX B — Footer container scroll-width bleed · all pages · mobile
 * .footer-links-row is 365px wide inside a 339px container at 375px.
 * overflow:hidden + min-width:0 on flex children clamps it.
 * ────────────────────────────────────────────────────────── */
@media (max-width: 660px) {
  .footer-links-row {
    overflow: hidden;
  }
  .footer-col {
    min-width: 0;
    overflow: hidden;
  }
}

/* ──────────────────────────────────────────────────────────
 * FIX C — body overflow-x clip · all pages · mobile
 * Prevents fixed/absolute children (nsc-wa-fab ::before ring,
 * hg-frame) from widening documentElement.scrollWidth.
 * `overflow-x: clip` differs from hidden: it clips without
 * creating a new BFC that breaks position:sticky.
 * ────────────────────────────────────────────────────────── */
html {
  overflow-x: clip;
}

/* ──────────────────────────────────────────────────────────
 * FIX D — .vb-summary / vb-tip / vb-fact / vb-expert padding · article · mobile
 * 32px 36px = 72px horizontal padding in a 327px container.
 * Reduce to 20px sides on narrow screens.
 * ────────────────────────────────────────────────────────── */
@media (max-width: 600px) {
  .vb-summary,
  .vb-tip,
  .vb-fact,
  .vb-expert {
    padding: 22px 20px !important;
  }
}

/* ──────────────────────────────────────────────────────────
 * FIX E — .persona-chip overflow · article · mobile
 * Chip text label overflows column. Clamp chip width to parent,
 * ellipsis the text span, keep avatar visible.
 * ────────────────────────────────────────────────────────── */
@media (max-width: 600px) {
  .persona-bar {
    padding: 14px 16px !important;
    gap: 8px !important;
  }
  .persona-chip {
    max-width: 100%;
    min-width: 0;
  }
  .persona-chip > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1;
  }
}

/* ──────────────────────────────────────────────────────────
 * FIX F — .polaroid tribe board · pin/tape must overflow the frame.
 * overflow:hidden on .polaroid was clipping pin (-24px) and tape (-18px).
 * Clip the photo only via img clip-path; keep decorative elements visible.
 * ────────────────────────────────────────────────────────── */
.polaroid {
  overflow: visible !important;
}
.polaroid img {
  border-radius: 2px !important;
  clip-path: inset(0 round 2px);
}

/* ──────────────────────────────────────────────────────────
 * FIX G — Section vertical rhythm · home · desktop
 * .reviews-section and .ig-section use padding-top:80px while
 * all other .section blocks use 100px. Align them.
 * ────────────────────────────────────────────────────────── */
.reviews-section {
  padding-top: 100px !important;
}
.ig-section {
  padding-top: 100px !important;
  padding-bottom: 100px !important;
}

/* ──────────────────────────────────────────────────────────
 * FIX H — .hg-frame overflow · home · mobile
 * Frame is 356px in a 343px column. max-width:100% + overflow:hidden
 * prevents the frame from stretching the gallery section.
 * ────────────────────────────────────────────────────────── */
.hg-frame {
  max-width: 100%;
  overflow: hidden;
  box-sizing: border-box;
}

/* ──────────────────────────────────────────────────────────
 * FIX I — .art-lang-bar pill row · article · mobile
 * 9 language pills wrap to 3+ rows at 375px (~120px height waste).
 * Collapse to a single horizontally scrollable row with a fade mask.
 * ────────────────────────────────────────────────────────── */
@media (max-width: 600px) {
  .art-lang-bar {
    flex-wrap: nowrap !important;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 10px 14px !important;
    gap: 6px !important;
    -webkit-mask-image: linear-gradient(to right, #000 75%, transparent 100%);
    mask-image: linear-gradient(to right, #000 75%, transparent 100%);
  }
  .art-lang-bar::-webkit-scrollbar {
    display: none;
  }
  .lang-pill {
    flex-shrink: 0;
  }
}

/* ──────────────────────────────────────────────────────────
 * FIX J — .faq-item height variance · FAQ · mobile
 * Short questions render at 53px, long ones at 72px (26% delta).
 * min-height:72px makes all closed rows visually uniform.
 * ────────────────────────────────────────────────────────── */
.faq-item {
  min-height: 72px;
}

/* ──────────────────────────────────────────────────────────
 * FIX — .split-img hover artifact + baked-in dark stripe
 * Bug 1: thin dark line on top edge (perceived as black bar between nav
 *        and hero image on homepage "Live the essence" section).
 * Bug 2: perceived "dézoom" on hover-out.
 * Cause:
 *   - The source aerial photo has ~5px of dark terrain/rock pixels at
 *     the very top edge (sampled RGB ~(45,45,45)). At rendered 480px
 *     height this surfaces as a ~3-4px dark band at the top.
 *   - Previous scale(1.01) only cropped ~2.4px per side — not enough
 *     to hide the dark stripe.
 *   - Img dimensions matched container exactly → scale(1.0)<->scale(1.03)
 *     transition exposed subpixel gap at edges, reading as a reveal.
 * Fix:
 *   1. Baseline scale(1.05) crops ~12px from each side of the rendered
 *      image — fully hides the baked-in dark stripe and any subpixel gap.
 *   2. Hover scale up to 1.09 (keeps a perceptible ~4% zoom-in delta).
 *   3. object-position: center 50% kept implicit (center crop) so the
 *      composition stays balanced after the additional overscan.
 *   4. Solid white bg on container as safety net for GPU compositing.
 *   5. transform-origin: center (default) kept — symmetric growth.
 * ────────────────────────────────────────────────────────── */
.split-img {
  background-color: #ffffff;
  isolation: isolate;
}
.split-img img {
  transform: scale(1.05);
  transform-origin: center center;
  will-change: transform;
  backface-visibility: hidden;
}
.split-img:hover img {
  transform: scale(1.09) !important;
}
@media (prefers-reduced-motion: reduce) {
  .split-img img,
  .split-img:hover img {
    transform: none !important;
  }
}

/* ──────────────────────────────────────────────────────────
 * FIX GLOBAL — hover-zoom image artifacts across landing pages
 * Extends .split-img fix to ALL rounded image containers that
 * use a hover zoom-in pattern: pillars (.card), life-gallery
 * (.ig-cell), blog/article teasers (.blog-card), island guide
 * cards (.island-guide-card), gallery items (.gallery-item).
 *
 * Pattern applied uniformly:
 *   1. Container: overflow hidden, solid bg, isolation:isolate
 *      so no dark page-bg can leak through a subpixel gap.
 *   2. Image: baseline scale(1.01) → permanent overflow → no
 *      edge can ever expose a 1px dark line (subpixel rounding).
 *   3. Image: backface-visibility:hidden + transform-origin
 *      center to avoid GPU compositing artifacts.
 *   4. Hover: scale up to 1.06 (zoom IN; never < 1).
 *   5. prefers-reduced-motion respected.
 * ────────────────────────────────────────────────────────── */
.card,
.blog-card,
.island-guide-card,
.gallery-item,
.ig-cell {
  background-color: #ffffff;
  isolation: isolate;
  overflow: hidden;
}
/* .ig-cell uses tinted bg per design; keep its declared bg */
.ig-cell {
  background-color: #e8ecf0;
}

.card picture,
.blog-card picture,
.blog-card .blog-card-img-wrap,
.island-guide-card picture,
.gallery-item picture {
  overflow: hidden;
  display: block;
  background-color: transparent;
}

.card picture img,
.card .card-img,
.blog-card picture img,
.blog-card .blog-card-img-wrap .card-img,
.island-guide-card picture img,
.gallery-item img,
.gallery-item img.is-loaded,
.ig-cell .ig-cell-img {
  transform: scale(1.01);
  transform-origin: center center;
  will-change: transform;
  backface-visibility: hidden;
  display: block;
}

.card:hover picture img,
.card:hover .card-img,
.blog-card:hover picture img,
.blog-card:hover .blog-card-img-wrap .card-img,
.island-guide-card:hover picture img,
.gallery-item:hover img,
.gallery-item:hover img.is-loaded,
.ig-cell:hover .ig-cell-img {
  transform: scale(1.06) !important;
}

/* Preserve explicit opt-out (island-discover-card disables zoom) */
.island-discover-card .card-img,
.island-discover-card:hover .card-img {
  transform: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .card picture img,
  .card .card-img,
  .blog-card picture img,
  .blog-card .blog-card-img-wrap .card-img,
  .island-guide-card picture img,
  .gallery-item img,
  .ig-cell .ig-cell-img,
  .card:hover picture img,
  .card:hover .card-img,
  .blog-card:hover picture img,
  .blog-card:hover .blog-card-img-wrap .card-img,
  .island-guide-card:hover picture img,
  .gallery-item:hover img,
  .ig-cell:hover .ig-cell-img {
    transform: none !important;
  }
}

/* ──────────────────────────────────────────────────────────
 * Client 2026-06-15 — Island-guide grid cards: uniform image
 * size + zero layout shift on load. The <img class="card-img">
 * sits DIRECTLY in .island-guide-card (no <picture> wrapper), so
 * the picture-targeted rules never gave it a fixed box → images
 * rendered at their natural height (mismatched rows = the "décalage")
 * and reserved no space before load (the ~1s reflow "superposition").
 * An aspect-ratio box fixes BOTH: same height in every cell, and
 * space reserved up-front so nothing jumps on load.
 * ────────────────────────────────────────────────────────── */
.grid-3:has(.card-h3) > .card.island-guide-card .card-img,
.grid-3:has(.card-h3) > .card.island-guide-card > .card-img,
.island-guide-card > .card-img,
.island-guide-card .card-img {
  /* The .grid-3:has(.card-h3) > .card .card-img rule sets height:100% !important
   * (specificity 0,0,4,0) → the image stretched to the card height, which varies
   * with text length → mismatched rows + reflow on load. We out-specify it with
   * the .card.island-guide-card context (0,0,5,0) and force height:auto + a fixed
   * aspect-ratio, so every card gets the SAME image box and the space is reserved
   * before load (no jump). 4/3 matches the other site grid cards. */
  width: 100% !important;
  aspect-ratio: 4 / 3 !important;
  height: auto !important;
  object-fit: cover;
  display: block;
}

/* ──────────────────────────────────────────────────────────
 * FIX R — Responsive audit 2026-05-25
 * Booking reviews grid, gallery filter bar, form iOS zoom,
 * surf-house hero dvh, touch targets.
 * ────────────────────────────────────────────────────────── */

/* J1 — Booking social-proof cards: no horizontal bleed on 360px */
.booking-rv-grid {
  display: grid !important;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)) !important;
  gap: 20px;
  max-width: 1100px;
  margin-left: auto;
  margin-right: auto;
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
}
.booking-rv-card {
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
}

/* J2 — Gallery filter pills: contain scroll inside bar (tablet 768px bleed) */
@media (max-width: 900px) {
  .gallery-filter-bar {
    overflow-x: auto;
    overflow-y: hidden;
    max-width: 100%;
    min-width: 0;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap;
  }
  .gallery-filter-bar::-webkit-scrollbar {
    display: none;
  }
  .gallery-tag-btns {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
  }
}

/* J3 — Booking form: 16px inputs on mobile (prevents iOS Safari zoom on focus) */
@media (max-width: 768px) {
  .form-input,
  .form-select,
  .form-textarea,
  #booking-form input,
  #booking-form select,
  #booking-form textarea {
    font-size: 16px !important;
  }
}

/* J4 — Surf-house v2 hero: dynamic viewport height (iOS browser chrome) */

/* J5 — Touch targets: nav logo + language menu items (WCAG 2.5.5) */
.nav-logo {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}
.lang-dd-item {
  min-height: 44px;
  display: flex;
  align-items: center;
  box-sizing: border-box;
}
.skip-to-content {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding-top: 6px;
  padding-bottom: 6px;
  box-sizing: border-box;
}

/* J6 — Forecast strip: scroll stays inside component, not page-wide */
.sc-forecast-strip {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
}

/* ──────────────────────────────────────────────────────────
 * FIX V — FOUC guard leak (images invisible site-wide)
 * Inline #nsc-visuals-guard had img[data-slot]:not([data-img-ready])
 * WITHOUT html.nsc-visuals-pending → permanent opacity:0. Loaded after
 * polish on many pages, so override here with equal specificity + !important.
 * ────────────────────────────────────────────────────────── */
img[data-slot]:not([data-img-ready]) {
  opacity: 1 !important;
}
video[data-poster-slot]:not([data-poster-ready]) {
  opacity: 1 !important;
}
html.nsc-visuals-pending img[data-slot]:not([data-img-ready]):not([data-img-hydrated]) {
  opacity: 0 !important;
}
html.nsc-visuals-pending [data-bg-slot]:not([data-bg-ready]) {
  background-image: none !important;
}
html.nsc-visuals-pending video[data-poster-slot]:not([data-poster-ready]) {
  opacity: 0 !important;
}
