/*
===============================================================================
SITE TEMPLATE — Main Stylesheet (styles.css)
===============================================================================

PURPOSE:
  This file contains ALL styles for the public-facing website template.
  It is organized into clearly labeled sections so you can find and modify
  any visual element quickly.

HOW TO CUSTOMIZE:
  - FONTS: Change the Google Fonts import at the top and update --font-serif
    and --font-sans in :root to use your own fonts.
  - COLORS: Modify the CSS custom properties in :root to change the color
    scheme. The site uses very few solid colors — mostly white text on
    dark/image backgrounds with varying opacity.
  - ANIMATIONS: Scroll down to the ANIMATIONS section to change transition
    durations, easing curves, and keyframe animations.
  - RESPONSIVE: The RESPONSIVE section at the bottom contains all media
    queries. Adjust breakpoints and sizes there.

SECTIONS:
  1. Fonts & Reset
  2. CSS Custom Properties (Colors, Fonts, Spacing)
  3. Base / Global Styles
  4. Scrollbar Hiding
  5. Landing Page — Snap Scroll Container
  6. Landing Page — Hero Section
  7. Landing Page — Highlights Grid
  8. Landing Page — Experiences Section
  9. Landing Page — Pricing Section
  10. Gallery / Explore View
  11. Gallery — Slide Content Overlay
  12. Gallery — Navigation (Dots, Arrows, Counter)
  13. Inquiry Modal
  14. Buttons & Interactive Elements
  15. Animations & Transitions
  16. Utility Classes
  17. Responsive Design

===============================================================================
*/


/* =============================================================================
   1. FONTS & RESET
   =============================================================================
   We import two Google Fonts:
   - Playfair Display: An elegant serif font for headings
   - DM Sans: A clean sans-serif for body text
   TO CHANGE FONTS: Replace these URLs and update --font-serif / --font-sans
============================================================================= */

/* Google Fonts are loaded dynamically: the server injects a single
   <link rel="stylesheet"> for the active theme's serif+sans pair (see
   _build_active_font_link in app.py + serve_index injection). This
   replaces the old static @import that always pulled Playfair+DM Sans
   even when the active pair was something else, eliminating the wasted
   font download on every page load. */

*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}


/* =============================================================================
   2. CSS CUSTOM PROPERTIES
   =============================================================================
   Change these variables to restyle the entire site.
   - Colors use rgba for transparency control.
   - Spacing uses rem for consistent scaling.
============================================================================= */

:root {
  /* Fonts — change these to swap the entire typography */
  --font-serif: 'Playfair Display', Georgia, serif;
  --font-sans: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;

  /* Colors — can be overridden by the Theme Editor in admin */
  --color-bg: #060b14;
  /* Space-separated RGB triple of --color-bg, used inside rgba() so the
     loading screen and any other tinted overlay can re-tint themselves
     when the admin swaps theme colors. Server injects this in the head
     <style> block from theme_bg; script.js keeps it in sync on live edit. */
  --color-bg-rgb: 6 11 20;
  --color-section-1: #0a0f1a;
  --color-section-2: #060b14;
  --color-accent: #c9a96e;
  --color-text: #e4e4e7;
  --glass-border: rgba(255, 255, 255, 0.08);
  --glass-bg: rgba(255, 255, 255, 0.03);

  /* Universal master visual tokens — one knob each, exposed in admin
     Themes editor, used everywhere a glass / loading / radius / motion
     value used to be hardcoded. */
  --glass-blur: 24px;
  --radius: 1rem;
  --loading-bg-alpha: 0.85;

  /* Dark backgrounds used in landing page sections */
  --bg-section-1: var(--color-section-1);
  --bg-section-2: var(--color-section-2);

  /* Transition timing — controls how fast animations feel.
     --transition-medium is the master; admin Themes editor exposes it
     as a single "motion speed" slider. */
  --transition-fast: 0.3s;
  --transition-medium: 0.6s;
  --transition-slow: 0.8s;
  --ease-smooth: cubic-bezier(0.22, 1, 0.36, 1);

  /* Gallery slide transition duration */
  --slide-transition: 0.35s;  /* Aligned with JS SCROLL_COOLDOWN_MS so the slide
                                  animation completes by the time the next wheel/swipe
                                  is accepted, preventing mid-animation flicker. */

  /* Scroll cooldown for wheel navigation (managed in JS, but CSS transition matches) */
  --ken-burns-duration: 12s;

  /* Spacing scale — multiplied by admin density (Task #63 / item 6). */
  --space-scale: 1;
  --space-xs:  calc(0.25rem * var(--space-scale, 1));
  --space-sm:  calc(0.5rem  * var(--space-scale, 1));
  --space-md:  calc(1rem    * var(--space-scale, 1));
  --space-lg:  calc(1.5rem  * var(--space-scale, 1));
  --space-xl:  calc(2rem    * var(--space-scale, 1));
  --space-2xl: calc(3rem    * var(--space-scale, 1));
  --space-3xl: calc(5rem    * var(--space-scale, 1));

  /* Section frame inset — 0..32px gutter widening the page-bg around
     each .landing-section (Task #63 / item 7). */
  --section-frame-inset: 0px;
}


/* =============================================================================
   2b. LOADING SCREEN
   =============================================================================
   Glassmorphic loading overlay shown while data loads.
   Fades out with scale transition when content is ready.
============================================================================= */

.loading-screen {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Tinted with the active theme background + admin-configurable alpha
     so the boot overlay always matches the site palette instead of
     flashing the default navy. */
  background: rgb(var(--color-bg-rgb) / var(--loading-bg-alpha));
  transition: opacity var(--transition-medium) var(--ease-smooth),
              transform var(--transition-medium) var(--ease-smooth);
}

.loading-screen.fade-out {
  opacity: 0;
  transform: scale(1.02);
  pointer-events: none;
}

.loading-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  padding: 2.5rem 3.5rem;
  border-radius: var(--radius);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

.loading-logo-badge {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.08);
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.35rem;
  color: #fff;
  animation: loadingPulse 2s ease-in-out infinite;
}

.loading-site-name {
  font-family: var(--font-serif);
  font-size: 1.125rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.8);
}

.loading-shimmer {
  width: 6rem;
  height: 2px;
  border-radius: 1px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
  position: relative;
}

.loading-shimmer-bar {
  position: absolute;
  inset: 0;
  width: 50%;
  border-radius: 1px;
  /* Shimmer travels in the active accent color so it always matches the
     site palette rather than locking to the original gold. */
  background: linear-gradient(90deg, transparent, var(--color-accent), transparent);
  opacity: 0.6;
  animation: loadingShimmer 1.5s ease-in-out infinite;
}

@keyframes loadingPulse {
  0%, 100% { opacity: 0.7; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.04); }
}

@keyframes loadingShimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(300%); }
}


/* =============================================================================
   2c. SURFACE TREATMENT PRESETS  (Task #62 — items 3, 5, 12, 13)
   =============================================================================
   Four owner-controlled surface treatments swap the personality of the
   public site without touching individual component styles:

     [data-card-style]    — radius / border / shadow / blur on every card.
     [data-easing]        — named cubic-bezier exposed as --ease-active.
     [data-photo-filter]  — global filter applied to background-image
                            surfaces (hero bg, card cover images).
     [data-loading-mode]  — what's visible inside the boot overlay.

   The data-* attributes are set on <html> by the server (serve_index)
   for first paint and re-applied live by script.js on theme save (so the
   admin doesn't need a reload). Each preset only OVERRIDES the
   properties it needs to change — anything not listed inherits from the
   per-component rules below, so adding new card types stays cheap.
============================================================================= */

/* --- Motion personality (via the existing transition timing tokens) ---
   styles.css currently uses `var(--ease-smooth)` in dozens of places.
   The server now also injects `--ease-active` on :root from theme_easing,
   so we just point --ease-smooth at it here. Falling back to the
   original gentle out-cubic keeps every existing rule working when the
   active theme leaves theme_easing at its default. */
:root {
  --ease-active: cubic-bezier(0.22, 1, 0.36, 1);
}
/* Override the legacy alias so every var(--ease-smooth) in the file
   automatically picks up the active easing on first paint. */
:root, html { --ease-smooth: var(--ease-active); }

/* --- Card style preset: shared card-class group selector ---
   Comprehensive list of every PUBLIC-FACING card class on the site
   (admin/dashboard/utility-prefix card classes are intentionally
   excluded; presets only style what visitors see). Adding a new card
   class? Append it to .surface-card-set and the four presets pick it
   up automatically. We use a CSS custom-property pseudo-grouping
   approach via :is() so each preset stays a single rule. */
[data-card-style="glass"] :is(.event-card, .blog-card, .experience-card,
                              .gallery-card, .sphere-card, .store-card,
                              .podcast-card, .glass-card, .service-card,
                              .testimonial-card, .team-card, .pricing-card,
                              .highlight-card, .av-card, .bk-card,
                              .biz-info-card, .checkout-card, .custom-card,
                              .rsvp-card, .voice-intro-card,
                              .sphere-section-card) {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  backdrop-filter: blur(calc(var(--glass-blur) * 1.25));
  -webkit-backdrop-filter: blur(calc(var(--glass-blur) * 1.25));
  border-radius: var(--radius);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
}
[data-card-style="brutal"] :is(.event-card, .blog-card, .experience-card,
                               .gallery-card, .sphere-card, .store-card,
                               .podcast-card, .glass-card, .service-card,
                               .testimonial-card, .team-card, .pricing-card,
                               .highlight-card, .av-card, .bk-card,
                               .biz-info-card, .checkout-card, .custom-card,
                               .rsvp-card, .voice-intro-card,
                               .sphere-section-card) {
  background: var(--color-section-1);
  border: 2px solid var(--color-text);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-radius: 0;
  box-shadow: 6px 6px 0 0 var(--color-accent);
}
[data-card-style="minimal"] :is(.event-card, .blog-card, .experience-card,
                                .gallery-card, .sphere-card, .store-card,
                                .podcast-card, .glass-card, .service-card,
                                .testimonial-card, .team-card, .pricing-card,
                                .highlight-card, .av-card, .bk-card,
                                .biz-info-card, .checkout-card, .custom-card,
                                .rsvp-card, .voice-intro-card,
                                .sphere-section-card) {
  background: transparent;
  border: 1px solid var(--glass-border);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-radius: calc(var(--radius) * 0.4);
  box-shadow: none;
}
/* "editorial" is the documented default — explicitly emit the rule too
   so re-saving the same preset (or live-switching back to it from
   another preset) restores the look without a page reload. */
[data-card-style="editorial"] :is(.event-card, .blog-card, .experience-card,
                                  .gallery-card, .sphere-card, .store-card,
                                  .podcast-card, .glass-card, .service-card,
                                  .testimonial-card, .team-card, .pricing-card,
                                  .highlight-card, .av-card, .bk-card,
                                  .biz-info-card, .checkout-card, .custom-card,
                                  .rsvp-card, .voice-intro-card,
                                  .sphere-section-card) {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border-radius: var(--radius);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
}

/* --- Photo filter: applied GLOBALLY to every <img> on the public
   site PLUS every CSS background-image surface. The :not() opt-out
   list excludes brand marks, icons, avatars, signatures, sponsor
   logos and admin-side images so the filter never warps the brand
   logo or a UI glyph. Add `data-no-photo-filter` (or the
   `.no-photo-filter` class) to any future <img> that should bypass
   the treatment. We apply the filter on the IMAGE itself rather than
   a wrapper so it works regardless of how the markup nests them.
   The full opt-out list lives in --photo-filter-skip below; each
   preset re-uses the same selector so the skip set stays one place. */
/* Comprehensive list of EVERY public-site CSS background-image surface.
   These are surfaces whose background-image (or <video>) carries real
   photographic content and should adopt the chosen filter. Keep this
   list in sync with new image-bearing classes added in script.js or
   templates. Anything wrapping a real photo can also opt in by
   carrying [data-photo-surface]. */
[data-photo-filter="warm"] img:not(.no-photo-filter, [data-no-photo-filter], .logo-img, .brand-mark, .icon, .avatar, .site-logo, .signature, [class*="logo"]),
[data-photo-filter="warm"] :is(.hero-bg, .hero-image, .section-hero,
    [class*="-image-bg"], .highlight-card-bg, .gallery-slide-bg, .gallery-slide-bg-video,
    .podcast-cover, .podcast-cover-empty,
    .video-gallery-thumb, .video-gallery-thumb-video,
    .custom-card-img, .custom-gallery-img, .custom-text-image,
    .team-photo, .team-photo-placeholder,
    .testimonial-photo, .testimonial-photo-placeholder,
    .presentation-image, .img-presentation-slide,
    .experience-image, .gallery-image, .sphere-image, .sphere-card-image,
    .split-slide, [data-photo-surface]) {
  filter: saturate(1.15) hue-rotate(-8deg) brightness(1.04);
}
[data-photo-filter="cool"] img:not(.no-photo-filter, [data-no-photo-filter], .logo-img, .brand-mark, .icon, .avatar, .site-logo, .signature, [class*="logo"]),
[data-photo-filter="cool"] :is(.hero-bg, .hero-image, .section-hero,
    [class*="-image-bg"], .highlight-card-bg, .gallery-slide-bg, .gallery-slide-bg-video,
    .podcast-cover, .podcast-cover-empty,
    .video-gallery-thumb, .video-gallery-thumb-video,
    .custom-card-img, .custom-gallery-img, .custom-text-image,
    .team-photo, .team-photo-placeholder,
    .testimonial-photo, .testimonial-photo-placeholder,
    .presentation-image, .img-presentation-slide,
    .experience-image, .gallery-image, .sphere-image, .sphere-card-image,
    .split-slide, [data-photo-surface]) {
  filter: saturate(0.92) hue-rotate(12deg) brightness(0.98);
}
[data-photo-filter="bw"] img:not(.no-photo-filter, [data-no-photo-filter], .logo-img, .brand-mark, .icon, .avatar, .site-logo, .signature, [class*="logo"]),
[data-photo-filter="bw"] :is(.hero-bg, .hero-image, .section-hero,
    [class*="-image-bg"], .highlight-card-bg, .gallery-slide-bg, .gallery-slide-bg-video,
    .podcast-cover, .podcast-cover-empty,
    .video-gallery-thumb, .video-gallery-thumb-video,
    .custom-card-img, .custom-gallery-img, .custom-text-image,
    .team-photo, .team-photo-placeholder,
    .testimonial-photo, .testimonial-photo-placeholder,
    .presentation-image, .img-presentation-slide,
    .experience-image, .gallery-image, .sphere-image, .sphere-card-image,
    .split-slide, [data-photo-surface]) {
  filter: grayscale(1) contrast(1.08);
}
[data-photo-filter="grain"] img:not(.no-photo-filter, [data-no-photo-filter], .logo-img, .brand-mark, .icon, .avatar, .site-logo, .signature, [class*="logo"]),
[data-photo-filter="grain"] :is(.hero-bg, .hero-image, .section-hero,
    [class*="-image-bg"], .highlight-card-bg, .gallery-slide-bg, .gallery-slide-bg-video,
    .podcast-cover, .podcast-cover-empty,
    .video-gallery-thumb, .video-gallery-thumb-video,
    .custom-card-img, .custom-gallery-img, .custom-text-image,
    .team-photo, .team-photo-placeholder,
    .testimonial-photo, .testimonial-photo-placeholder,
    .presentation-image, .img-presentation-slide,
    .experience-image, .gallery-image, .sphere-image, .sphere-card-image,
    .split-slide, [data-photo-surface]) {
  filter: contrast(1.1) saturate(0.95) brightness(0.96);
}
/* Grain overlay — a tiled SVG noise on top of the filtered image gives
   the look its texture without needing a real image asset. The
   ::after sits on the image wrapper because the *-bg layer itself is
   often `position:absolute; inset:0` and can't host its own pseudo. */
[data-photo-filter="grain"]
  :is(.event-card-image, .blog-card-image, .gallery-card,
      .sphere-card, .experience-card, .hero-section)::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 0.18;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/></svg>");
}

/* --- Loading mode: hide parts of the boot overlay per preset. The
   shimmer counts as the "spinner" because it is the only animated
   bar the loading panel ships with. The fade-only mode keeps just
   the overall tinted backdrop and removes the inner panel entirely. */
html[data-loading-mode="logo_only"] .loading-site-name,
html[data-loading-mode="logo_only"] .loading-shimmer { display: none; }

html[data-loading-mode="spinner_only"] .loading-logo-badge,
html[data-loading-mode="spinner_only"] .loading-site-name { display: none; }

html[data-loading-mode="fade_only"] .loading-panel {
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
}
html[data-loading-mode="fade_only"] .loading-logo-badge,
html[data-loading-mode="fade_only"] .loading-site-name,
html[data-loading-mode="fade_only"] .loading-shimmer { display: none; }


/* =============================================================================
   2d. LAYOUT & RHYTHM CONTROLS  (Task #63 / items 6, 7, 9, 16)
   ============================================================================= */

/* Density (first-paint override before the injected <style> arrives). */
html[data-density="compact"]     :root,
html[data-density="compact"]     { --space-scale: 0.75; }
html[data-density="comfortable"] :root,
html[data-density="comfortable"] { --space-scale: 1; }
html[data-density="spacious"]    :root,
html[data-density="spacious"]    { --space-scale: 1.25; }

/* Header alignment variants. */
html[data-header-align="left"] .section-header {
  text-align: left;
  align-items: flex-start;
  margin-left: 0;
  margin-right: auto;
}
html[data-header-align="left"] .section-header > * {
  text-align: left;
}

/* Numbered: left-aligned + CSS counter prefix on the eyebrow. */
html[data-header-align="numbered"] {
  counter-reset: landing-section;
}
html[data-header-align="numbered"] .landing-section {
  counter-increment: landing-section;
}
html[data-header-align="numbered"] .section-header {
  text-align: left;
  align-items: flex-start;
}
html[data-header-align="numbered"] .section-header > * {
  text-align: left;
}
html[data-header-align="numbered"] .landing-section .section-eyebrow::before {
  content: counter(landing-section, decimal-leading-zero) " — ";
  color: var(--color-accent, currentColor);
  font-weight: 600;
  margin-right: 0.15em;
}

/* Split: eyebrow column + title/intro column (>= 720px). */
@media (min-width: 720px) {
  html[data-header-align="split"] .section-header {
    display: grid;
    grid-template-columns: minmax(140px, 1fr) minmax(0, 3fr);
    gap: var(--space-lg);
    align-items: start;
    text-align: left;
  }
  html[data-header-align="split"] .section-header .section-eyebrow {
    grid-column: 1;
    text-align: left;
  }
  html[data-header-align="split"] .section-header .section-title,
  html[data-header-align="split"] .section-header .section-subtitle {
    grid-column: 2;
    text-align: left;
  }
}

/* Hero layout variants. Server-side branching emits the right markup
   per mode (see _render_hero_fragment in app.py); these rules style
   each variant. */

/* split — 50/50 grid (>= 720px). */
@media (min-width: 720px) {
  html[data-hero-layout="split"] .hero-section {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    align-items: stretch;
  }
  html[data-hero-layout="split"] .hero-section .hero-bg,
  html[data-hero-layout="split"] .hero-section .hero-overlay {
    position: relative !important;
    inset: auto !important;
    grid-column: 1;
    grid-row: 1;
    align-self: stretch;
    width: 100%;
    height: 100%;
    min-height: 60vh;
  }
  html[data-hero-layout="split"] .hero-section .hero-overlay {
    pointer-events: none;
  }
  html[data-hero-layout="split"] .hero-content {
    grid-column: 2;
    grid-row: 1;
    text-align: left;
    align-items: flex-start;
    padding: var(--space-3xl) var(--space-xl);
    max-width: none;
    align-self: center;
  }
  html[data-hero-layout="split"] .hero-content > * {
    text-align: left;
  }
  /* Nav spans both columns above the grid. */
  html[data-hero-layout="split"] .hero-section .hero-nav {
    grid-column: 1 / -1;
    grid-row: 1;
    z-index: 5;
  }
}

/* text_mesh — palette-driven mesh gradient, no photo. */
html[data-hero-layout="text_mesh"] .hero-section {
  background-image:
    radial-gradient(ellipse at 20% 10%, rgb(var(--color-bg-rgb, 6 11 20) / 0.4), transparent 60%),
    radial-gradient(ellipse at 80% 30%, color-mix(in srgb, var(--color-accent) 35%, transparent), transparent 65%),
    radial-gradient(ellipse at 50% 90%, color-mix(in srgb, var(--color-section-1) 70%, transparent), transparent 70%),
    linear-gradient(135deg, var(--color-bg), var(--color-section-2)) !important;
}
html[data-hero-layout="text_mesh"] .hero-section .hero-bg {
  display: none !important;
}

/* carousel — cross-fade on #hero-bg when JS swaps the background. */
html[data-hero-layout="carousel"] .hero-section .hero-bg {
  transition: background-image var(--transition-slow, 0.8s) var(--ease-active, ease) !important;
}

/* video — show <video>, hide image carrier. */
html[data-hero-layout="video"] .hero-section .hero-video {
  display: block !important;
  opacity: 1 !important;
}
html[data-hero-layout="video"] .hero-section .hero-bg {
  display: none !important;
}


/* =============================================================================
   2f. PERSONALITY CONTROLS  (Task #64 / items 10, 11, 14, 15)
   -----------------------------------------------------------------------------
   Four small admin-controlled knobs that tweak how the public site
   *feels* without changing colors, fonts, or copy:
     - cursor mode      : native | dot | magnetic
     - scroll-progress  : 0/1 (color via --scroll-progress-color)
     - nav style        : floating_glass | sticky | hamburger
                          | hidden_on_scroll | side_rail
     - chatbot placement: bottom_center | bottom_right | side_panel
                          | cmd_k | hidden_until_button
   All variants key off data-* attrs on <html> emitted by serve_index +
   re-applied by applyPersonality() on /api/theme reload, so a save in
   the admin panel flips the look on every open public-site tab without
   a reload.
============================================================================= */

/* ---- Cursor mode -------------------------------------------------------- */
/* Custom dot follows the pointer. The dot is the same DOM element for both
   `dot` and `magnetic`; magnetic just gets a slower lerp + grow-on-hover
   handled in JS. The dot stays out of the layout (pointer-events:none) so
   it can never block clicks even if z-index math goes sideways. */
#cursor-follower {
  position: fixed;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;       /* center on the cursor coords */
  border-radius: 50%;
  background: var(--color-accent, #c9a96e);
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transform: translate3d(-100px, -100px, 0);
  transition: opacity 0.2s ease, width 0.18s var(--ease-active, ease),
              height 0.18s var(--ease-active, ease),
              margin 0.18s var(--ease-active, ease),
              background 0.2s ease;
  mix-blend-mode: difference;  /* stays visible on light + dark surfaces */
  will-change: transform;
}
html[data-cursor-mode="dot"] #cursor-follower,
html[data-cursor-mode="magnetic"] #cursor-follower { opacity: 1; }
html[data-cursor-mode="dot"],
html[data-cursor-mode="dot"]   * ,
html[data-cursor-mode="magnetic"],
html[data-cursor-mode="magnetic"] * { cursor: none !important; }
/* Re-allow native caret in form fields so typing isn't broken. */
html[data-cursor-mode="dot"] input,
html[data-cursor-mode="dot"] textarea,
html[data-cursor-mode="dot"] [contenteditable],
html[data-cursor-mode="magnetic"] input,
html[data-cursor-mode="magnetic"] textarea,
html[data-cursor-mode="magnetic"] [contenteditable] { cursor: text !important; }
/* Magnetic mode grows the dot when hovering an interactive element
   (toggled by JS via .is-hover). */
#cursor-follower.is-hover {
  width: 36px;
  height: 36px;
  margin: -18px 0 0 -18px;
  background: color-mix(in srgb, var(--color-accent, #c9a96e) 70%, transparent);
}
/* Touch / coarse-pointer devices: never show the custom cursor or hide
   the native one. Mobile tap targets must keep the system cursor logic. */
@media (hover: none), (pointer: coarse) {
  #cursor-follower { display: none !important; }
  html[data-cursor-mode="dot"],
  html[data-cursor-mode="dot"]   *,
  html[data-cursor-mode="magnetic"],
  html[data-cursor-mode="magnetic"] * { cursor: auto !important; }
}

/* ---- Scroll-progress bar ----------------------------------------------- */
/* Thin bar pinned to the very top of the viewport. Width is set inline
   by applyPersonality()'s scroll listener; we never render width here so
   first paint lands at 0% even before JS attaches. */
#scroll-progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;                                 /* JS updates this */
  height: 3px;
  background: var(--scroll-progress-color, var(--color-accent, #c9a96e));
  z-index: 100;                              /* above hero, below modals */
  pointer-events: none;
  transition: width 0.08s linear,
              background 0.2s ease;
  display: none;
}
html[data-scroll-progress="1"] #scroll-progress-bar { display: block; }

/* ---- Nav style variants ------------------------------------------------- */
/* floating_glass = default (existing .hero-nav rules apply, no override). */

/* sticky: pin the nav to the top of the viewport with a frosted backdrop
   so it stays visible while the visitor scrolls .landing-container. */
html[data-nav-style="sticky"] .hero-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 80;
  background: rgb(var(--color-bg-rgb, 6 11 20) / 0.7);
  backdrop-filter: blur(var(--glass-blur, 16px));
  -webkit-backdrop-filter: blur(var(--glass-blur, 16px));
  border-bottom: 1px solid var(--glass-border, rgba(255,255,255,0.08));
  padding: var(--space-md, 0.75rem) var(--space-xl, 1.5rem);
  transition: transform var(--transition-medium, 0.35s) var(--ease-active, ease),
              opacity var(--transition-medium, 0.35s) var(--ease-active, ease);
}
/* Push the hero content down so the now-fixed nav doesn't overlap. */
html[data-nav-style="sticky"] .hero-section { padding-top: 4.5rem; }

/* hidden_on_scroll: behaves like sticky on first paint, but JS adds the
   .nav-hidden class while scrolling down and removes it while scrolling up. */
html[data-nav-style="hidden_on_scroll"] .hero-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 80;
  background: rgb(var(--color-bg-rgb, 6 11 20) / 0.7);
  backdrop-filter: blur(var(--glass-blur, 16px));
  -webkit-backdrop-filter: blur(var(--glass-blur, 16px));
  border-bottom: 1px solid var(--glass-border, rgba(255,255,255,0.08));
  padding: var(--space-md, 0.75rem) var(--space-xl, 1.5rem);
  transform: translateY(0);
  transition: transform var(--transition-medium, 0.35s) var(--ease-active, ease);
}
html[data-nav-style="hidden_on_scroll"] .hero-nav.nav-hidden {
  transform: translateY(-110%);
}
html[data-nav-style="hidden_on_scroll"] .hero-section { padding-top: 4.5rem; }

/* hamburger: hide every nav child EXCEPT (a) the toggle button and (b) any
   wrapper that contains the brand mark. The brand-mark detection uses
   :has() because the actual DOM nests .logo-badge / .logo-mark inside a
   wrapper <div class="flex items-center gap-md"> rather than placing them
   as direct children of .hero-nav. The toggle button is appended by
   applyPersonality() and reveals the hidden nav children inside a dropdown
   (.hero-nav.nav-open exposes them). */
html[data-nav-style="hamburger"] .hero-nav { position: relative; }
html[data-nav-style="hamburger"] .hero-nav > *:not(:has(.logo-badge, .logo-mark)):not(.nav-hamburger-toggle) {
  display: none;
}
html[data-nav-style="hamburger"] .hero-nav.nav-open > * { display: flex; }
html[data-nav-style="hamburger"] .hero-nav.nav-open {
  flex-wrap: wrap;
}
html[data-nav-style="hamburger"] .hero-nav.nav-open > *:not(:has(.logo-badge, .logo-mark)):not(.nav-hamburger-toggle) {
  flex-basis: 100%;
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-sm, 0.5rem);
}
.nav-hamburger-toggle {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--glass-border, rgba(255,255,255,0.18));
  color: var(--color-text, #fff);
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 0.5rem;
  display: none;                             /* shown only in hamburger mode */
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  margin-left: auto;
}
.nav-hamburger-toggle:hover {
  background: rgba(255, 255, 255, 0.14);
}
html[data-nav-style="hamburger"] .nav-hamburger-toggle { display: flex; }

/* ---- Section nav menu (Task #65) --------------------------------------
   Progressive-disclosure dropdown that lists every enabled landing
   section. Lives inside .hero-nav alongside the logo and Get Started
   button so it inherits all four nav-style placement variants
   (floating_glass, sticky, hidden_on_scroll, side_rail, hamburger)
   without bespoke positioning logic. */
.nav-section-menu {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.nav-section-menu-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--glass-border, rgba(255, 255, 255, 0.18));
  background: rgba(255, 255, 255, 0.06);
  color: var(--color-text, #fff);
  border-radius: 0.55rem;
  font-family: var(--font-sans);
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease,
              transform 0.12s ease;
}
.nav-section-menu-toggle:hover {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.32);
}
.nav-section-menu-toggle.is-active {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.4);
}
.nav-section-menu-toggle:focus-visible {
  outline: 2px solid var(--color-accent, #c9a96e);
  outline-offset: 2px;
}
.nav-section-menu-toggle-label {
  line-height: 1;
}

/* Dropdown panel — created lazily by renderSectionNavMenu(). Default
   anchoring drops the panel below and right-aligned to the toggle so
   it stays inside the viewport even when the nav sits in the corner. */
.nav-section-menu-panel {
  position: absolute;
  top: calc(100% + 0.55rem);
  right: 0;
  min-width: 14rem;
  max-height: min(70vh, 32rem);
  overflow-y: auto;
  padding: 0.5rem;
  background: rgb(var(--color-bg-rgb, 6 11 20) / 0.94);
  backdrop-filter: blur(var(--glass-blur, 16px));
  -webkit-backdrop-filter: blur(var(--glass-blur, 16px));
  border: 1px solid var(--glass-border, rgba(255, 255, 255, 0.14));
  border-radius: 0.75rem;
  box-shadow: 0 18px 38px rgba(0, 0, 0, 0.45);
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  z-index: 90;
  opacity: 0;
  transform: translateY(-6px) scale(0.98);
  transform-origin: top right;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.nav-section-menu-panel.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}
.nav-section-menu-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.7rem;
  border-radius: 0.45rem;
  color: var(--color-text, #fff);
  font-family: var(--font-sans);
  font-size: 0.92rem;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.14s ease, color 0.14s ease;
}
.nav-section-menu-item:hover,
.nav-section-menu-item:focus-visible {
  background: rgba(255, 255, 255, 0.1);
  outline: none;
}
/* mig 0260 — the classic multi-page nav lives in this SAME menu: page links (About/Services/Contact) sit
   alongside the section jumps, and the page the visitor is currently on is marked as the current one. */
.nav-section-menu-item.is-current {
  color: var(--color-accent, #c9a96e);
  font-weight: 600;
}
.nav-section-menu-item.is-current .nav-section-menu-item-label {
  border-bottom: 2px solid currentColor;
}
.nav-section-menu-item-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--color-accent, #c9a96e);
}
.nav-section-menu-item-label {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* side_rail mode — nav is a vertical 3.5rem column on the left edge.
   Drop the toggle's text label, square it into an icon button, and
   slide the panel out to the RIGHT of the rail instead of dropping
   it down (which would be off-screen above). The action-button row
   itself becomes a column too so the menu trigger can sit ABOVE the
   Get Started CTA without overflowing the 3.5rem rail width. We
   target the wrapper via :has(.nav-section-menu) so the logo /
   wordmark wrapper above it isn't affected. */
html[data-nav-style="side_rail"] .nav-section-menu-toggle {
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  justify-content: center;
}
html[data-nav-style="side_rail"] .nav-section-menu-toggle-label {
  display: none;
}
html[data-nav-style="side_rail"] .nav-section-menu-panel {
  top: 0;
  right: auto;
  left: calc(100% + 0.6rem);
  transform-origin: top left;
}
/* (Was: side_rail forced the OLD action-group flex wrapper into a
   vertical column. Since the section menu was hoisted out of that
   wrapper into its own .hero-nav child, this selector no longer
   matches. The vertical column is now handled by the .hero-nav rule
   below at L~1067 which sets flex-direction: column on the rail
   itself, so all 3 children stack naturally.) */

/* Desktop (>= 769px) — for the inline nav styles (floating_glass,
   sticky, hidden_on_scroll), expand the section nav into an always-
   visible horizontal pill bar styled to match the rest of the glass
   nav. The MENU toggle becomes redundant and hides itself. We
   intentionally skip side_rail (vertical column nav has no room for
   inline pills) and hamburger (whole point is to keep everything
   collapsed behind one button). */
@media (min-width: 769px) {
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-toggle {
    display: none;
  }
  /* Pill bar: inline, single row, NO scrollbar. JS
     (_applySectionNavDesktopOverflow in script.js) measures available
     width and folds excess pills behind a "More ▾" button rendered
     inside this same panel. overflow:visible lets the dropdown popup
     (which is appended as a sibling of this panel inside the
     .nav-section-menu wrapper) escape the pill bar bounds. */
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-panel {
    position: relative;
    top: auto;
    right: auto;
    left: auto;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    overflow: visible;
    max-width: min(56vw, 44rem);
    max-height: none;
    min-width: 0;
    padding: 0.3rem 0.45rem;
    background: rgb(var(--color-bg-rgb, 6 11 20) / 0.55);
    border-radius: 9999px;
    gap: 0.1rem;
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28);
    /* Always visible — no open/close transition on desktop. */
    opacity: 1;
    transform: none;
    pointer-events: auto;
    transition: none;
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-item {
    padding: 0.4rem 0.7rem;
    font-size: 0.78rem;
    border-radius: 9999px;
    white-space: nowrap;
    flex-shrink: 0;
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-item-icon {
    width: 14px;
    height: 14px;
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-item-label {
    overflow: visible;
    text-overflow: unset;
    white-space: nowrap;
  }

  /* "More ▾" overflow trigger — styled as a pill that visually matches
     the bar's items so the bar reads as one consistent strip. Sits at
     the right end of the pill bar; appended/removed dynamically. */
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-more {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.4rem 0.7rem;
    font-size: 0.78rem;
    line-height: 1;
    border-radius: 9999px;
    border: 0;
    background: transparent;
    color: var(--color-text, #fff);
    font-family: var(--font-sans);
    cursor: pointer;
    white-space: nowrap;
    flex-shrink: 0;
    transition: background 0.14s ease, color 0.14s ease;
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-more:hover,
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-more:focus-visible {
    background: rgba(255, 255, 255, 0.12);
    outline: none;
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-more[aria-expanded="true"] {
    background: rgba(255, 255, 255, 0.18);
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-more-icon {
    width: 14px;
    height: 14px;
    color: var(--color-accent, #c9a96e);
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-more[aria-expanded="true"] .nav-section-menu-more-icon {
    transform: rotate(180deg);
    transition: transform 0.18s ease;
  }

  /* Overflow popup — vertical dropdown of the pills that didn't fit.
     Sibling of .nav-section-menu-panel inside .nav-section-menu (which
     is position:relative), so right:0 anchors it to the right edge of
     the pill bar (where the More button sits). */
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-overflow {
    position: absolute;
    top: calc(100% + 0.55rem);
    right: 0;
    min-width: 14rem;
    max-height: min(70vh, 32rem);
    overflow-y: auto;
    padding: 0.5rem;
    background: rgb(var(--color-bg-rgb, 6 11 20) / 0.94);
    backdrop-filter: blur(var(--glass-blur, 16px));
    -webkit-backdrop-filter: blur(var(--glass-blur, 16px));
    border: 1px solid var(--glass-border, rgba(255, 255, 255, 0.14));
    border-radius: 0.75rem;
    box-shadow: 0 18px 38px rgba(0, 0, 0, 0.45);
    display: none;
    flex-direction: column;
    gap: 0.15rem;
    z-index: 90;
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-overflow.is-open {
    display: flex;
  }
  /* Pills inside the dropdown use the larger "panel" pill style, NOT
     the small bar pill style — they need to feel clickable in a list,
     not pinched as in the bar. */
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-overflow .nav-section-menu-item {
    padding: 0.55rem 0.7rem;
    font-size: 0.92rem;
    border-radius: 0.45rem;
    flex-shrink: 0;
  }
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .nav-section-menu-overflow .nav-section-menu-item-icon {
    width: 16px;
    height: 16px;
  }
}

/* Mobile — collapse the toggle to icon-only so it fits beside the CTA
   without wrapping. The panel keeps its dropdown-from-toggle position
   but widens slightly so labels don't truncate awkwardly. We also
   neutralise the side_rail panel-positioning rule on mobile because
   the rail itself collapses back to a horizontal bar at this width
   (see below) — keeping `left: calc(100% + 0.6rem)` would push the
   panel off-screen to the right. */
@media (max-width: 768px) {
  .nav-section-menu-toggle {
    width: 2.4rem;
    height: 2.4rem;
    padding: 0;
    justify-content: center;
  }
  .nav-section-menu-toggle-label {
    display: none;
  }
  .nav-section-menu-panel {
    min-width: 13rem;
  }
  html[data-nav-style="side_rail"] .nav-section-menu-panel {
    top: calc(100% + 0.6rem);
    left: auto;
    right: 0;
    transform-origin: top right;
  }
  /* (Was: side_rail forced the OLD action-group flex wrapper into a
     row on mobile. No longer needed — section menu is now a top-level
     .hero-nav child handled by the mobile fallback below.) */
}


/* side_rail: vertical column of nav items pinned to the left edge. The
   .hero-nav becomes a 3rem-wide rail; hero content gets a matching
   padding-left so nothing slides under it. */
html[data-nav-style="side_rail"] .hero-nav {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  z-index: 80;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  width: 3.5rem;
  padding: var(--space-lg, 1rem) 0.25rem;
  gap: var(--space-md, 0.75rem);
  background: rgb(var(--color-bg-rgb, 6 11 20) / 0.85);
  backdrop-filter: blur(var(--glass-blur, 16px));
  -webkit-backdrop-filter: blur(var(--glass-blur, 16px));
  border-right: 1px solid var(--glass-border, rgba(255,255,255,0.08));
}
html[data-nav-style="side_rail"] .hero-section,
html[data-nav-style="side_rail"] .landing-section {
  padding-left: calc(3.5rem + var(--space-md, 0.75rem)) !important;
}
@media (max-width: 768px) {
  /* Mobile fallback: side_rail collapses back to floating glass so it
     doesn't eat half the small viewport. */
  html[data-nav-style="side_rail"] .hero-nav {
    position: relative;
    flex-direction: row;
    width: auto;
    bottom: auto;
    border-right: none;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  html[data-nav-style="side_rail"] .hero-section,
  html[data-nav-style="side_rail"] .landing-section {
    padding-left: 0 !important;
  }
}

/* ---- Chatbot placement variants ---------------------------------------- */
/* bottom_center = default (existing .chatbot-container rules apply, no override). */

/* bottom_right: snap to the right corner. */
html[data-chatbot-placement="bottom_right"] .chatbot-container {
  left: auto;
  right: var(--space-lg, 1rem);
  transform: none;
  width: auto;
}

/* side_panel: tall panel docked to the right edge. */
html[data-chatbot-placement="side_panel"] .chatbot-container {
  top: 0;
  bottom: 0;
  left: auto;
  right: 0;
  transform: none;
  width: 360px;
  max-width: 90vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  background: rgb(var(--color-bg-rgb, 6 11 20) / 0.92);
  backdrop-filter: blur(var(--glass-blur, 16px));
  -webkit-backdrop-filter: blur(var(--glass-blur, 16px));
  border-left: 1px solid var(--glass-border, rgba(255,255,255,0.08));
  padding: var(--space-md, 0.75rem);
}
html[data-chatbot-placement="side_panel"] .chatbot-bar {
  border-radius: 0.75rem;
  margin-bottom: var(--space-sm, 0.5rem);
}

/* cmd_k + hidden_until_button: fully hide the chatbot until the visitor
   either presses ⌘K / Ctrl+K (cmd_k) or taps a small launcher button
   (hidden_until_button). applyPersonality() injects the launcher and
   the keyboard listener; CSS only owns the visibility. */
html[data-chatbot-placement="cmd_k"] .chatbot-container,
html[data-chatbot-placement="hidden_until_button"] .chatbot-container {
  display: none;
}
html[data-chatbot-placement="cmd_k"] .chatbot-container.is-summoned,
html[data-chatbot-placement="hidden_until_button"] .chatbot-container.is-summoned {
  display: block;
}

/* Floating launcher button injected for hidden_until_button mode. */
.chatbot-launcher {
  position: fixed;
  bottom: var(--space-lg, 1rem);
  right: var(--space-lg, 1rem);
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--color-accent, #c9a96e);
  color: var(--color-bg, #060b14);
  border: none;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  z-index: 71;
  display: none;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  line-height: 1;
  transition: transform 0.2s var(--ease-active, ease);
}
.chatbot-launcher:hover { transform: translateY(-2px); }
html[data-chatbot-placement="hidden_until_button"] .chatbot-launcher { display: flex; }


/* =============================================================================
   3. BASE / GLOBAL STYLES
============================================================================= */

html, body {
  height: 100%;
  width: 100%;
  overflow: hidden;
  overflow-x: hidden;
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background: var(--color-bg, #000);
  color: var(--color-text, #fff);
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-serif);
  font-weight: 600;
  letter-spacing: -0.02em;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  max-width: 100%;
  height: auto;
}

button {
  cursor: pointer;
  border: none;
  background: none;
  font-family: inherit;
  color: inherit;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

a {
  -webkit-tap-highlight-color: transparent;
}

input, select, textarea {
  font-family: var(--font-sans);
}

/* Prevent iOS auto-zoom on touch devices (applies to all viewport sizes including iPad) */
@media (hover: none) and (pointer: coarse) {
  input, select, textarea {
    font-size: 16px !important;
  }
}


/* =============================================================================
   4. SCROLLBAR HIDING
   =============================================================================
   Hides the scrollbar on the snap-scroll container for a cleaner look.
   The user can still scroll — the scrollbar is just invisible.
============================================================================= */

.scrollbar-hide::-webkit-scrollbar {
  display: none;
}
.scrollbar-hide {
  -ms-overflow-style: none;
  scrollbar-width: none;
}


/* =============================================================================
   5. LANDING PAGE — SNAP SCROLL CONTAINER
   =============================================================================
   The landing page is a vertical scroll container with snap points.
   Each section (Hero, Highlights, etc.) snaps into place when scrolled.

   HOW IT WORKS:
   - The container has `scroll-snap-type: y mandatory`
   - Each section has `scroll-snap-align: start`
   - This creates a "page-by-page" scrolling experience

   TO ADD A NEW SECTION:
   - Add a new <section> inside the container
   - Give it the class "snap-section" and "landing-section"
   - It will automatically snap into place
============================================================================= */

.landing-container {
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  overflow-x: hidden;
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
  scroll-snap-stop: always;
  -webkit-overflow-scrolling: touch;
}

.snap-section {
  scroll-snap-align: start;
}

/* -------- Smooth-scroll opt-out (admin toggle) -------- */
/* When the site_settings.scroll_mode column is set to 'smooth', script.js
   sets data-scroll-mode="smooth" on the <html> element. We then disable
   snap behavior so visitors can scroll the landing page continuously
   instead of having each section lock into place. The 'snap' default
   (column DEFAULT 'snap', also the absence of the attribute) keeps the
   original page-by-page experience untouched.                            */
html[data-scroll-mode="smooth"] .landing-container {
  scroll-snap-type: none;
  scroll-snap-stop: normal;
}
html[data-scroll-mode="smooth"] .snap-section {
  scroll-snap-align: none;
}

/* -------- Mobile: disable mandatory snap (was trapping touch scroll) --------
   On phones, single-column stacked content (highlights, pricing, FAQ,
   testimonials, blog, etc.) makes most sections taller than the viewport.
   Combined with `scroll-snap-type: y mandatory` + `scroll-snap-stop: always`,
   iOS Safari and Android Chrome interrupt finger drags and snap back to the
   section start, so visitors literally cannot scroll past the top of any
   tall section — what looks like "scroll is broken" on phones.

   The fix: turn off snap on small viewports. Sections still feel full-screen
   thanks to their `min-height: 100dvh`, but touch drag works normally. This
   override applies regardless of the smooth/snap admin toggle, because snap
   on mobile is unreliable across browsers no matter what mode is selected.
   Desktop keeps the original page-by-page snap experience untouched.        */
@media (max-width: 768px), (hover: none) and (pointer: coarse) {
  /* Drop the inner scroll-container trap. On phones — especially
     iOS Safari, where the dynamic URL bar resizes 100dvh on every
     scroll — making `.landing-container` the only scroll source
     (with html/body overflow:hidden) is fragile and frequently
     locks scroll entirely. Letting the body scroll naturally is
     the standard mobile-first behavior and what every visitor
     expects from a phone browser. Sections still feel full-screen
     because each `.landing-section` already has `min-height: 100dvh`. */
  html, body {
    height: auto;
    min-height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    /* Prevent rubber-band overscroll from chaining to the URL bar */
    overscroll-behavior-y: contain;
  }
  .landing-container {
    height: auto;
    min-height: 100dvh;
    overflow: visible;
    scroll-snap-type: none;
    scroll-snap-stop: normal;
  }
  .snap-section {
    scroll-snap-align: none;
  }
}

.snap-section.landing-section {
  position: relative;
}

.snap-section.landing-section::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 60%;
  max-width: 40rem;
  height: 1px;
  background: linear-gradient(
    to right,
    transparent 0%,
    rgba(201, 169, 110, 0.3) 30%,
    rgba(201, 169, 110, 0.35) 50%,
    rgba(201, 169, 110, 0.3) 70%,
    transparent 100%
  );
  pointer-events: none;
  z-index: 5;
}

.landing-section > .max-w-container {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.landing-section.section-in-view > .max-w-container {
  opacity: 1;
  transform: translateY(0);
}

.hero-section .hero-content {
  opacity: 0;
  transform: translateY(25px);
  transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.1s,
              transform 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.1s;
}

.hero-section.section-in-view .hero-content {
  opacity: 1;
  transform: translateY(0);
}

#site-footer {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

#site-footer.section-in-view {
  opacity: 1;
  transform: translateY(0);
}


/* =============================================================================
   6. LANDING PAGE — HERO SECTION
   =============================================================================
   The hero is a fullscreen section with a background image,
   gradient overlay, and centered text content.
============================================================================= */

.hero-section {
  position: relative;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* Background image — covers the entire hero area */
.hero-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

/* Video that fills a highlight card background */
.highlight-card-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Gradient overlay — darkens the image so text is readable */
.hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, 0.4) 0%,
    rgba(0, 0, 0, 0.3) 50%,
    rgba(0, 0, 0, 0.7) 100%
  );
}

/* Top navigation bar (logo + buttons) */
.hero-nav {
  position: relative;
  /* Sits above .hero-content (z:10) so the section-nav panel/pills are
     never painted under the hero title and always receive pointer
     events. Stays well below modals (60+) and chat (5345+). */
  z-index: 60;
  /* Flex with space-between pins the logo (first child) to the far
     left edge and the action group (last child) to the far right
     edge. The .nav-section-menu sits between them; on desktop it is
     pulled out of flex flow with `position: absolute; left: 50%`
     (rule below) so it's perfectly centred regardless of how wide the
     logo or CTAs grow. With the menu absolutely positioned, flex sees
     only 2 in-flow children and reliably pushes them to opposite
     edges. */
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-lg) var(--space-xl);
}
/* Centre the section menu on desktop for the inline nav styles
   (floating_glass / sticky / hidden_on_scroll). Absolute positioning
   removes it from flex flow so logo + CTAs can hug the edges. Skip
   side_rail (vertical column nav has no horizontal centring) and
   hamburger (whole nav collapses behind one toggle). */
@media (min-width: 769px) {
  html:not([data-nav-style="side_rail"]):not([data-nav-style="hamburger"]) .hero-nav > .nav-section-menu {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
  }
}

/* Logo home link — wraps the badge + text. Strips default anchor
   styling (underline / blue colour) so the badge and site name keep
   their existing typography. Inherits cursor: pointer from <a> so the
   user gets the standard click affordance. */
.logo-link {
  text-decoration: none;
  color: inherit;
  border-radius: 0.6rem;
  transition: opacity 0.15s ease;
}
.logo-link:hover { opacity: 0.85; }
.logo-link:focus-visible {
  outline: 2px solid var(--color-accent, #c9a96e);
  outline-offset: 4px;
}

/* Logo badge — circular with initials (default "monogram" mode) */
.logo-badge {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(12px);
  background: rgba(255, 255, 255, 0.1);
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.1rem;
  color: #fff;
}

/* ----------------------------------------------------------------------
   Brand-identity logo variants (Task #61). The body class
   .logo-mode-{monogram|image|wordmark|lockup} is set by script.js
   applyLogoTreatment() based on the active theme. Each variant simply
   restyles the existing #logo-badge / #footer-logo-badge elements so
   the public HTML doesn't need to change.
   ---------------------------------------------------------------------- */

/* Image mode: badge becomes a transparent square holding the uploaded
   logo image (rendered as a CSS background so we can swap via a CSS var
   without touching textContent). */
.logo-mode-image .logo-badge,
.logo-mode-lockup .logo-badge {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.35rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: var(--logo-image, transparent) center / contain no-repeat;
  backdrop-filter: none;
  color: transparent;       /* hide initials behind the image */
  font-size: 0;
  text-indent: -9999px;
  overflow: hidden;
}

/* Image mode is "uploaded image only" — hide the adjacent .logo-text
   site name so the brand reads as a clean image-only mark (header,
   footer, gallery, sphere — every .logo-text instance). Lockup mode
   keeps both image + text intentionally. */
.logo-mode-image .logo-text {
  display: none !important;
}

/* Wordmark mode: hide the badge entirely; the adjacent .logo-text
   site-name already shows the wordmark. */
.logo-mode-wordmark .logo-badge {
  display: none !important;
}

/* Lockup mode: image badge + sitename together. We just upsize the
   image badge slightly so it reads as the dominant element. */
.logo-mode-lockup .logo-badge {
  width: 2.75rem;
  height: 2.75rem;
}

/* Accent gradient (Task #61). When the theme defines an accent
   secondary AND the gradient toggle is on, --accent-gradient is set
   to a linear-gradient() string by the server / loadAndApplyTheme().
   Buttons and primary CTAs that read --accent-gradient pick it up.

   Coverage rationale (responding to code-review note that surfaces
   beyond buttons should also reflect the gradient):
     - Buttons / CTAs   -> background-image gradient (paint surface)
     - Eyebrows         -> background-clip:text gradient (text fill)
     - Dividers / <hr>  -> linear-gradient bar (decorative line)
   Eyebrow + divider rules use `background-clip:text` with transparent
   text color so the gradient flows through the typeface without
   needing extra wrapping markup. */
.accent-gradient,
body.theme-accent-gradient .btn-primary,
body.theme-accent-gradient .nav-cta {
  background: var(--accent-gradient, var(--color-accent)) !important;
  border-color: transparent !important;
}

body.theme-accent-gradient .section-eyebrow,
body.theme-accent-gradient .split-slide-eyebrow,
body.theme-accent-gradient .sphere-card-eyebrow {
  background: var(--accent-gradient, var(--color-accent));
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
          color: transparent;
}

body.theme-accent-gradient hr,
body.theme-accent-gradient .divider,
body.theme-accent-gradient .section-divider {
  background: var(--accent-gradient, var(--color-accent));
  border: 0;
  height: 2px;
}

.logo-text .site-name {
  font-family: var(--font-serif);
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  color: #fff;
  line-height: 1;
}

.logo-text .site-subtitle {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.6);
  margin-top: 0.25rem;
}

/* Hero centered content */
.hero-content {
  position: relative;
  z-index: 10;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 var(--space-lg);
  box-sizing: border-box;
  max-width: 100%;
  overflow: hidden;
}

.hero-tagline {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: rgba(255, 255, 255, 0.7);
  font-family: var(--font-sans);
  margin-bottom: var(--space-md);
}

.hero-title {
  font-size: clamp(3rem, 8vw, 6rem);
  font-weight: 700;
  color: #fff;
  margin-bottom: var(--space-lg);
  line-height: 1.1;
  overflow-wrap: break-word;
  word-break: break-word;
  max-width: 100%;
}

.hero-description {
  font-size: clamp(1rem, 2vw, 1.25rem);
  color: rgba(255, 255, 255, 0.8);
  font-weight: 300;
  max-width: 36rem;
  margin: 0 auto var(--space-xl);
  line-height: 1.6;
  transition: opacity 0.3s ease;
  min-height: 1.6em;
  overflow-wrap: break-word;
  word-break: break-word;
}

.hero-description.hero-typing {
  border-right: 2px solid var(--accent, #c9a96e);
  animation: heroCursorBlink 0.7s steps(1) infinite;
}

@keyframes heroCursorBlink {
  0%, 50% { border-right-color: var(--accent, #c9a96e); }
  51%, 100% { border-right-color: transparent; }
}

.hero-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  justify-content: center;
}

/* Scroll indicator — bouncing chevron at bottom of hero */
.scroll-indicator {
  position: relative;
  z-index: 10;
  display: flex;
  justify-content: center;
  padding-bottom: var(--space-xl);
  color: rgba(255, 255, 255, 0.55);
  animation: bounce 2s infinite;
}


/* =============================================================================
   7. LANDING PAGE — HIGHLIGHTS GRID
   =============================================================================
   A grid of image cards showing the property's rooms and spaces.
   Each card has a hover zoom effect on the background image.
============================================================================= */

.landing-section {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  /* Horizontal padding adds --section-frame-inset on top of --space-xl so
     the admin's "Section Frame Inset" slider (Task #63 / item 7) widens
     the visible page-bg gutter on either edge of every section without
     losing the existing comfortable text margin. Vertical padding stays
     on the spacing scale so density alone controls top/bottom rhythm. */
  padding: var(--space-3xl) calc(var(--space-xl) + var(--section-frame-inset, 0px));
  /* Extra vertical breathing room so the painted card edge never crowds
     the section eyebrow at the top or the trailing CTA button at the
     bottom. We deliberately decouple this from --space-scale (the
     admin density slider) and set an absolute floor — earlier
     multiplier-based attempts (1.3× → 2.2× of --space-3xl) still
     collapsed when the density slider was turned down, leaving the
     eyebrow visually pinched against the painted card edge. clamp()
     with viewport-height middle term lets the gap grow on tall
     monitors without ever shrinking below the comfortable 8rem floor.
     !important guards against narrower section-specific overrides. */
  padding-block: clamp(8rem, 14vh, 14rem) !important;
  /* Frame the section: clip the painted background to the content box so the
     existing padding becomes a visible border of the page background (body's
     --color-bg) instead of the section color extending edge-to-edge. The
     section still fills 100dvh so scroll-snap continues to lock one section
     per viewport — only the *painted* area shrinks, exposing the page bg
     around it. !important is required because each <section> carries an
     inline `style="background: var(--bg-section-X)"` shorthand which would
     otherwise reset background-clip back to its initial border-box value. */
  background-clip: content-box !important;
}

/* ---------------------------------------------------------------------------
   Per-section background image (Task #60)
   ---------------------------------------------------------------------------
   When the admin uploads a photo for a section on the Page Layout tab,
   public/script.js's applySectionBackground() sets the inline backgroundImage
   to a layered `linear-gradient(scrim) , url(photo)` AND adds the
   .has-bg-image class to the <section>. The rules below adjust the framing,
   text contrast, and per-image-card surface treatment so the photo reads as
   intentional rather than as a leaky background.

   We deliberately keep the inline `style="background: var(--bg-section-X)"`
   attribute on each section in index.html — that becomes the fallback color
   under the photo (and the visible color when bg_image is empty), while the
   JS-set backgroundImage layers the scrim + photo on top.
   --------------------------------------------------------------------------- */

/* Image-backed sections preserve the same content-box framing the rest
   of the site uses (per Task #60 step 4) — the photo is clipped to the
   inner padding box so the page's --color-bg shows around the edges,
   visually matching every other section instead of bleeding edge-to-edge.
   The base .landing-section rule above already sets
   `background-clip: content-box !important;`, so we don't restate it
   here — keeping it in one place avoids future drift. We only adjust
   text contrast for legibility over the scrim. */
.landing-section.has-bg-image {
  background-attachment: scroll;
  /* Force eyebrow / title / subtitle text to white so they stay legible
     over the scrim regardless of the active theme's --color-text. The
     inner card surfaces (testimonials, team, etc.) keep their own colors. */
  color: #fff;
}

.landing-section.has-bg-image .section-eyebrow,
.landing-section.has-bg-image .section-title,
.landing-section.has-bg-image .section-subtitle {
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

.section-header {
  text-align: center;
  margin-bottom: var(--space-3xl);
}

.section-eyebrow {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: var(--color-accent, #c9a96e);
  font-family: var(--font-sans);
  margin-bottom: 0.75rem;
}

.section-title {
  font-size: clamp(2rem, 5vw, 3rem);
  font-weight: 700;
  color: #fff;
  margin-bottom: var(--space-md);
}

.section-subtitle {
  color: rgba(255, 255, 255, 0.6);
  max-width: 32rem;
  margin: 0 auto;
  line-height: 1.5;
}

/* Card grid — responsive 1/2/3 column layout */
.highlights-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-lg);
  max-width: 72rem;
  margin: 0 auto;
}

/* Individual highlight card */
.highlight-card {
  position: relative;
  overflow: hidden;
  border-radius: 0.375rem;
  aspect-ratio: 4 / 3;
  cursor: pointer;
}

.highlight-card-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  transition: transform 0.7s ease;
}

.highlight-card:hover .highlight-card-bg {
  transform: scale(1.05);
}

.highlight-card-overlay {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top,
      rgba(0, 0, 0, 0.85) 0%,
      rgba(0, 0, 0, 0.45) 45%,
      rgba(0, 0, 0, 0.15) 75%,
      transparent 100%
    ),
    rgba(0, 0, 0, 0.10);
  transition: background 0.3s ease;
  pointer-events: none;
}
/* Darken further on hover so the title/subtitle stay legible even when the
   user is focusing on the card. */
.highlight-card:hover .highlight-card-overlay {
  background:
    linear-gradient(to top,
      rgba(0, 0, 0, 0.9) 0%,
      rgba(0, 0, 0, 0.6) 50%,
      rgba(0, 0, 0, 0.35) 100%
    ),
    rgba(0, 0, 0, 0.20);
}

.highlight-card-content {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 1.25rem;
}

.highlight-card-category {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.6);
}

.highlight-card-title {
  font-size: 1.25rem;
  font-weight: 700;
  color: #fff;
  margin-top: 0.25rem;
}

.highlight-card-subtitle {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.7);
  margin-top: 0.25rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.highlight-card-price {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.9);
  font-family: var(--font-serif);
  font-style: italic;
  margin-top: 0.5rem;
}


/* =============================================================================
   8. LANDING PAGE — EXPERIENCES SECTION
   =============================================================================
   Simple card-based layout for curated experiences.
   Each card has an icon, title, and short description.
============================================================================= */

.experiences-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-lg);
  max-width: 60rem;
  margin: 0 auto var(--space-3xl);
}

.experience-card {
  padding: var(--space-lg);
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
  transition: transform var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.experience-card:hover {
  transform: translateY(-3px);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 4px 20px rgba(255, 255, 255, 0.05);
}

.experience-icon {
  width: 1.25rem;
  height: 1.25rem;
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: var(--space-md);
}

.experience-name {
  font-size: 1.125rem;
  font-weight: 600;
  color: #fff;
  margin-bottom: var(--space-sm);
}

.experience-description {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.6;
}


/* =============================================================================
   9. LANDING PAGE — PRICING SECTION
============================================================================= */

.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-lg);
  max-width: 48rem;
  margin: 0 auto;
}

.pricing-card {
  text-align: center;
  padding: var(--space-lg);
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  transition: transform var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.pricing-card:hover {
  transform: translateY(-3px);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 4px 20px rgba(255, 255, 255, 0.05);
}

.pricing-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: var(--space-sm);
}

.pricing-dates {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.7);
  margin-bottom: 0.25rem;
}

.pricing-price {
  font-size: 1.125rem;
  font-family: var(--font-serif);
  font-weight: 700;
  color: #fff;
}


/* =============================================================================
   10. GALLERY / EXPLORE VIEW
   =============================================================================
   The gallery is a fullscreen slide-based view.
   Only one slide is visible at a time. Users navigate with:
   - Mouse wheel (scroll up/down)
   - Touch swipe (on mobile)
   - Keyboard arrows (up/down/left/right)
   - Click on dot navigation or arrow buttons

   HOW THE TRANSITIONS WORK:
   - When a new slide activates, the old slide fades out + translates vertically.
   - The new slide fades in + translates from the opposite direction.
   - This is done by toggling CSS classes: .slide-enter, .slide-active, .slide-exit
   - The Ken Burns effect (slow zoom) runs continuously on the background image.
============================================================================= */

.gallery-view {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: none; /* Hidden by default; shown when user clicks "Explore" */
  /* Opaque backdrop: the full-screen gallery is a slide DECK whose backgrounds come from each slide's
     image. A slide with NO image (or a broken/404 image URL) is transparent, so without a background of
     its own the gallery revealed the .site-footer stacked behind it (the footer is a body-level sibling,
     OUTSIDE the .landing-container that gets display:none while the gallery is open) — the "footer shows
     through the gallery" bug. A solid backdrop keeps the gallery a self-contained surface. */
  background: var(--color-bg, #060b14);
}

.gallery-view.active {
  display: block;
  /* The immersive gallery is a full-screen TAKEOVER. Pin it to the viewport (so body scroll can't drift
     the deck off-screen or reveal the footer below) and lift it ABOVE the chat widget
     (.chatbot-container is z-index:70) so on mobile the gallery shows IN FRONT OF the chat, not behind
     it. Closing the gallery (its own ✕) returns to the page + chat. */
  position: fixed;
  z-index: 90;
}

/* Keep the chat pill ON TOP of the open gallery, not hidden behind its opaque backdrop. The gallery is
   a full-screen z-index:90 takeover; without this its solid background covers the concierge pill
   (z-index:70) so it vanishes the moment the gallery opens. Lifting the chat ABOVE the deck lets the
   visitor still open the concierge to ask about what they're viewing. Scoped via :has() to the
   gallery-open state, so the chat's normal stacking is byte-identical everywhere else. */
/* Two selectors, same lift, for resilience: the `:has()` form works on modern browsers with no JS,
   and the `body.gallery-open` form (toggled by showGallery/showLanding in script.js) is the
   browser-independent fallback for engines that don't apply `:has()` — without it the pill silently
   drops back to z-index:70 BEHIND the opaque z-index:90 gallery and vanishes. */
body:has(.gallery-view.active) .chatbot-container,
body.gallery-open .chatbot-container { z-index: 95; }

/* Individual slide — fills the entire screen */
.gallery-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--slide-transition) var(--ease-smooth),
              transform var(--slide-transition) var(--ease-smooth);
}

.gallery-slide.slide-active {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  z-index: 1;
}

/* Slide entering from below (scrolling down / going to next) */
.gallery-slide.slide-enter-down {
  transform: translateY(60px);
}

/* Slide entering from above (scrolling up / going to previous) */
.gallery-slide.slide-enter-up {
  transform: translateY(-60px);
}

/* Background image with Ken Burns (slow zoom) effect */
.gallery-slide-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  animation: kenBurns var(--ken-burns-duration) ease-in-out infinite alternate;
}

/* When the slide background is a video, fill the same area without Ken Burns */
.gallery-slide-bg-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  animation: none;
  display: block;
}

/* Task 076 — unmute affordance for a sound-enabled video slide. Autoplay must start muted (browser
   policy), so a sound slide shows this control; the visitor taps it to unmute. Sits above the slide
   content + gradient (the bottom pill is z-70; this stays within the slide). */
.slide-unmute {
  position: absolute;
  top: 5rem;
  right: 1.25rem;
  z-index: 6;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 0.15s ease, transform 0.15s ease;
}
.slide-unmute:hover { background: rgba(0, 0, 0, 0.65); transform: scale(1.06); }
.slide-unmute.is-on { background: var(--color-accent, #c9a96e); color: #0b0b0b; border-color: transparent; }

/* Gradient overlay for text readability.
   The gallery is full-screen and not hover-able, so we use an always-on
   stronger overlay. The text sits in the lower-left, so the bottom is heavily
   darkened, fading smoothly toward the top so the imagery still shines.
   A subtle global tint (4th layer) keeps mid-tones consistent on bright
   images (skies, snow) and bright video frames. */
.gallery-slide-overlay {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top,
      rgba(0, 0, 0, 0.85) 0%,
      rgba(0, 0, 0, 0.55) 35%,
      rgba(0, 0, 0, 0.25) 60%,
      rgba(0, 0, 0, 0.10) 80%,
      transparent 100%
    ),
    linear-gradient(to right,
      rgba(0, 0, 0, 0.35) 0%,
      rgba(0, 0, 0, 0.15) 35%,
      transparent 60%
    ),
    rgba(0, 0, 0, 0.12);
  opacity: 1;
  pointer-events: none;
}


/* =============================================================================
   11. GALLERY — SLIDE CONTENT OVERLAY
   =============================================================================
   The text content shown over each gallery slide:
   category badge, title, subtitle, description, and detail grid.
============================================================================= */

.slide-content {
  position: absolute;
  bottom: 8rem;
  left: var(--space-xl);
  max-width: 36rem;
  color: #fff;
  z-index: 10;
  opacity: 0;
  transform: translateY(20px);
  /* Small delay so text appears just after the slide settles. Tuned to ~1/3
     of --slide-transition so it stays in proportion if the transition is
     re-tuned (was 0.3s when the transition was 0.8s — too late for a 0.35s
     transition, where text would have popped in at the very end). */
  transition: opacity var(--slide-transition) var(--ease-smooth) 0.1s,
              transform var(--slide-transition) var(--ease-smooth) 0.1s;
}

.slide-active .slide-content {
  opacity: 1;
  transform: translateY(0);
}

/* Category badge — small pill-shaped label */
.slide-badge-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: var(--space-md);
}

.slide-category-badge {
  padding: 0.25rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 9999px;
  backdrop-filter: blur(4px);
  background: rgba(255, 255, 255, 0.1);
}

.slide-price {
  font-size: 0.875rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.9);
  font-family: var(--font-serif);
  font-style: italic;
}

.slide-title {
  font-size: clamp(2rem, 5vw, 3.5rem);
  font-weight: 700;
  margin-bottom: var(--space-md);
  line-height: 1.1;
  text-shadow: 0 2px 20px rgba(0, 0, 0, 0.5);
}

.slide-subtitle {
  font-size: clamp(1rem, 2vw, 1.5rem);
  font-weight: 300;
  color: rgba(255, 255, 255, 0.9);
  margin-bottom: var(--space-lg);
  font-family: var(--font-sans);
  border-left: 2px solid rgba(255, 255, 255, 0.4);
  padding-left: var(--space-md);
}

.slide-description {
  font-size: clamp(0.875rem, 1.5vw, 1.125rem);
  color: rgba(255, 255, 255, 0.8);
  line-height: 1.6;
  margin-bottom: var(--space-xl);
  max-width: 32rem;
  font-weight: 300;
}

/* Detail bullets — 2-column grid of features/amenities */
.slide-details {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem 2rem;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.7);
}

.slide-detail-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.slide-detail-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.5);
  flex-shrink: 0;
}


/* =============================================================================
   12. GALLERY — NAVIGATION
   =============================================================================
   Navigation elements for the gallery view:
   - Back button (top-left, returns to landing page)
   - CTA button (top-right, opens inquiry modal)
   - Up arrow (top-center)
   - Down arrow + slide counter (bottom-center)
   - Dot navigation (right-side, one dot per slide)
============================================================================= */

/* Top bar — back button and branding */
.gallery-top-left {
  position: absolute;
  top: var(--space-lg);
  left: var(--space-lg);
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  animation: fadeIn var(--transition-slow) ease-out forwards;
}

.gallery-top-right {
  position: absolute;
  top: var(--space-lg);
  right: var(--space-lg);
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

/* Circular navigation buttons (back, up, down) */
.nav-circle-btn {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(12px);
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  transition: background var(--transition-fast);
  font-size: 1.25rem;
}

.nav-circle-btn:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.2);
}

.nav-circle-btn:disabled {
  border-color: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.2);
  cursor: not-allowed;
}

/* Up/Down arrow navigation */
.gallery-nav-up {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 4rem;
  z-index: 30;
}

.gallery-nav-down {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: var(--space-lg);
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
}

.slide-counter {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: 0.25rem;
}

/* Right-side dot navigation — one dot per slide */
.dot-nav {
  position: absolute;
  top: 50%;
  right: var(--space-lg);
  transform: translateY(-50%);
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.dot-nav-item {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0.25rem 0;
}

.dot-nav-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.5);
  background: transparent;
  transition: all 0.5s ease;
  cursor: pointer;
}

.dot-nav-dot.active {
  background: var(--color-accent, #c9a96e);
  border-color: var(--color-accent, #c9a96e);
  transform: scale(1.25);
}

.dot-nav-dot:hover:not(.active) {
  background: rgba(255, 255, 255, 0.5);
}

/* Tooltip label on hover */
.dot-nav-label {
  position: absolute;
  right: 1.5rem;
  font-size: 0.625rem;
  font-weight: 500;
  color: #fff;
  white-space: nowrap;
  background: rgba(0, 0, 0, 0.4);
  padding: 0.125rem 0.5rem;
  border-radius: 0.25rem;
  backdrop-filter: blur(4px);
  opacity: 0;
  transform: translateX(0.5rem);
  transition: opacity var(--transition-fast), transform var(--transition-fast);
  pointer-events: none;
}

.dot-nav-item:hover .dot-nav-label {
  opacity: 1;
  transform: translateX(0);
}


/* =============================================================================
   13. INQUIRY MODAL
   =============================================================================
   A centered modal overlay with a dynamic form.
   Opens when user clicks any CTA button on the site.
============================================================================= */

.modal-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 60;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
}

.modal-backdrop.active {
  display: flex;
}

.modal-content {
  width: 100%;
  max-width: 32rem;
  border-radius: 1rem;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
  overflow: hidden;
  animation: modalIn var(--transition-fast) var(--ease-smooth);
}

.modal-glass {
  background: rgba(15, 20, 35, 0.75);
  backdrop-filter: blur(24px) saturate(1.4);
  -webkit-backdrop-filter: blur(24px) saturate(1.4);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.multistep-progress {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 1.25rem var(--space-lg) 0;
}

.step-item {
  display: flex;
  align-items: center;
  gap: 0;
}

.step-dot {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 600;
  border: 2px solid rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.04);
  color: rgba(255, 255, 255, 0.35);
  transition: all 0.4s var(--ease-smooth);
  flex-shrink: 0;
}

.step-dot.active {
  border-color: var(--accent, #c9a96e);
  background: rgba(201, 169, 110, 0.15);
  color: var(--accent, #c9a96e);
  box-shadow: 0 0 12px rgba(201, 169, 110, 0.25);
}

.step-dot.completed {
  border-color: var(--accent, #c9a96e);
  background: var(--accent, #c9a96e);
  color: #000;
}

.step-line {
  width: 2.5rem;
  height: 2px;
  background: rgba(255, 255, 255, 0.1);
  transition: background 0.4s var(--ease-smooth);
}

.step-line.completed {
  background: var(--accent, #c9a96e);
}

.form-step {
  display: none;
  animation: stepFadeIn 0.35s var(--ease-smooth);
}

.form-step.active {
  display: block;
}

@keyframes stepFadeIn {
  from { opacity: 0; transform: translateX(12px); }
  to { opacity: 1; transform: translateX(0); }
}

.step-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: var(--space-md);
  gap: 0.75rem;
}

.btn-step-back {
  padding: 0.5rem 1.25rem;
  font-size: 0.8rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.5rem;
  background: transparent;
  cursor: pointer;
  transition: all var(--transition-fast);
}

.btn-step-back:hover {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.3);
}

.btn-step-next {
  padding: 0.5rem 1.5rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: #000;
  background: var(--accent, #c9a96e);
  border: none;
  border-radius: 0.5rem;
  cursor: pointer;
  transition: all var(--transition-fast);
  margin-left: auto;
}

.btn-step-next:hover {
  background: #d4b87a;
  transform: translateY(-1px);
}

.modal-header {
  padding: var(--space-lg);
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.modal-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: #fff;
}

.modal-subtitle {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.55);
  margin-top: 0.25rem;
}

.modal-close {
  padding: 0.5rem;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.6);
  transition: background var(--transition-fast);
  font-size: 1.25rem;
}

.modal-close:hover {
  background: rgba(255, 255, 255, 0.1);
}

.modal-body {
  padding: var(--space-lg);
}

/* Form layout within the modal */
.form-grid {
  display: grid;
  gap: var(--space-md);
}

.form-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-md);
}

.form-grid-3 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--space-md);
}

.form-group label {
  display: block;
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: 0.5rem;
}

.form-group input,
.form-group select {
  width: 100%;
  padding: 0.625rem 0.875rem;
  border-radius: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(8px);
  color: #fff;
  font-size: 0.875rem;
  outline: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
}

.form-group input:focus,
.form-group select:focus {
  border-color: var(--accent, #c9a96e);
  box-shadow: 0 0 0 3px rgba(201, 169, 110, 0.1);
  background: rgba(255, 255, 255, 0.08);
}

.form-group select option {
  background: #1a1f2e;
  color: #fff;
}

.glass-textarea {
  width: 100%;
  padding: 0.625rem 0.875rem;
  border-radius: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(8px);
  color: #fff;
  font-size: 0.875rem;
  font-family: inherit;
  resize: vertical;
  outline: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
}

.glass-textarea:focus {
  border-color: var(--accent, #c9a96e);
  box-shadow: 0 0 0 3px rgba(201, 169, 110, 0.1);
  background: rgba(255, 255, 255, 0.08);
}

.form-group input.field-error,
.form-group select.field-error,
.form-group textarea.field-error,
.glass-textarea.field-error {
  border-color: #ef4444;
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}

/* ─────────────────────────────────────────────────────────────────────────
   Custom-form fields (.cvf-*) — the shared themed field markup emitted by
   renderFormField() for BOTH the CTA popup modal AND the in-chat immersive
   form. The chat iframe inlines an equivalent copy (it's a separate document);
   THIS copy themes the modal in the MAIN document — without it the modal
   rendered raw white native inputs. HCI: ≥44px tap targets, clear labels,
   accent focus ring, roomy vertical rhythm. Inherits per-tenant accent.
   ───────────────────────────────────────────────────────────────────────── */
.cvf-field { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 1rem; }
.cvf-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--space-md, 1rem); }
.cvf-full { grid-column: 1 / -1; }
.cvf-half { grid-column: span 1; }
@media (max-width: 520px) { .cvf-half { grid-column: 1 / -1; } }
.cvf-l {
  font-size: 0.78rem; font-weight: 500; text-transform: uppercase;
  letter-spacing: 0.04em; color: rgba(255, 255, 255, 0.6);
}
.cvf-req { color: var(--accent, #c9a96e); }
.cvf-field input,
.cvf-field select,
.cvf-field textarea {
  width: 100%; box-sizing: border-box;
  min-height: 44px;                       /* HCI: comfortable tap target */
  padding: 0.7rem 0.9rem;
  border-radius: 0.6rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.06);
  color: #fff; font-family: inherit; font-size: 0.95rem;
  outline: none;
  transition: border-color var(--transition-fast, .15s), box-shadow var(--transition-fast, .15s), background var(--transition-fast, .15s);
}
.cvf-field textarea { min-height: 92px; resize: vertical; }
.cvf-field input:focus,
.cvf-field select:focus,
.cvf-field textarea:focus {
  border-color: var(--accent, #c9a96e);
  box-shadow: 0 0 0 3px rgba(201, 169, 110, 0.12);
  background: rgba(255, 255, 255, 0.09);
}
.cvf-field input.field-error,
.cvf-field select.field-error,
.cvf-field textarea.field-error {
  border-color: #ef4444; box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.12);
}
.cvf-field select option { background: #1a1f2e; color: #fff; }
.cvf-opts { display: flex; flex-direction: column; gap: 0.5rem; }
.cvf-opt {
  display: flex; align-items: center; gap: 0.6rem; min-height: 40px;
  font-size: 0.95rem; color: rgba(255, 255, 255, 0.9); cursor: pointer;
}
.cvf-opt input { width: auto; min-height: 0; }
.cvf-help { font-size: 0.8rem; color: rgba(255, 255, 255, 0.5); margin: 0.1rem 0 0; }

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
  padding-top: var(--space-md);
}


/* =============================================================================
   14. BUTTONS & INTERACTIVE ELEMENTS
============================================================================= */

/* Primary CTA — solid white button */
.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 2rem;
  background: #fff;
  color: #111;
  font-weight: 600;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  transition: background var(--transition-fast), transform var(--transition-fast);
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
}

.btn-primary:hover {
  background: rgba(255, 255, 255, 0.88);
  transform: translateY(-1px);
}

/* Secondary CTA — outlined/glass button */
.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 2rem;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(12px);
  color: #fff;
  font-weight: 500;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  transition: background var(--transition-fast);
}

.btn-secondary:hover {
  background: rgba(255, 255, 255, 0.2);
}

/* Small Reserve button for the gallery top-right */
.btn-reserve {
  padding: 0.5rem 1.25rem;
  background: #fff;
  color: #000;
  font-weight: 700;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  border-radius: 9999px;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
  transition: background var(--transition-fast);
}

.btn-reserve:hover {
  background: rgba(255, 255, 255, 0.9);
}

/* Cancel / text button in modal */
.btn-text {
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.55);
  transition: color var(--transition-fast);
}

.btn-text:hover {
  color: #fff;
}

/* Submit button in modal */
.btn-submit {
  padding: 0.5rem 1.5rem;
  background: var(--accent, #c9a96e);
  color: #000;
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 0.875rem;
  border-radius: 0.5rem;
  border: none;
  cursor: pointer;
  transition: background var(--transition-fast), transform var(--transition-fast);
}

.btn-submit:hover {
  background: #d4b87a;
  transform: translateY(-1px);
}


/* =============================================================================
   15. ANIMATIONS & TRANSITIONS
   =============================================================================
   TO CUSTOMIZE ANIMATIONS:
   - Change durations in the @keyframes or the CSS variables above.
   - The Ken Burns zoom can be made more/less dramatic by changing the scale().
   - Fade-in animations use the .fade-in-view class toggled by JavaScript's
     IntersectionObserver.
============================================================================= */

/* Bouncing scroll indicator */
@keyframes bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(8px); }
}

/* Ken Burns — slow zoom on gallery background images */
@keyframes kenBurns {
  0% { transform: scale(1); }
  100% { transform: scale(1.05); }
}

/* Fade in from below — used for elements appearing on scroll */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* General fade in */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Modal entrance */
@keyframes modalIn {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Fade-in-on-scroll class — elements start invisible, JS adds .visible */
.fade-in-view {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--transition-medium) ease-out,
              transform var(--transition-medium) ease-out;
}

.fade-in-view.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Staggered animation delays for grid children */
.stagger-1 { transition-delay: 0.1s; }
.stagger-2 { transition-delay: 0.2s; }
.stagger-3 { transition-delay: 0.3s; }
.stagger-4 { transition-delay: 0.4s; }
.stagger-5 { transition-delay: 0.5s; }
.stagger-6 { transition-delay: 0.6s; }


/* =============================================================================
   16. UTILITY CLASSES
============================================================================= */

.text-center { text-align: center; }
.flex { display: flex; }
.items-center { align-items: center; }
.gap-sm { gap: var(--space-sm); }
.gap-md { gap: var(--space-md); }
.mt-xl { margin-top: var(--space-xl); }
.mt-2xl { margin-top: var(--space-2xl); }
.mb-2xl { margin-bottom: var(--space-2xl); }
.max-w-container { max-width: 72rem; margin-left: auto; margin-right: auto; }
.hidden { display: none !important; }


/* =============================================================================
   17. RESPONSIVE DESIGN
   =============================================================================
   Breakpoints:
   - Small (mobile): < 640px
   - Medium (tablet): 640px - 1024px
   - Large (desktop): > 1024px

   TO ADJUST: Change the max-width values or add new @media rules.
============================================================================= */

@media (max-width: 768px) {
  .hero-nav {
    padding: var(--space-md);
  }

  .hero-content {
    padding: 0 var(--space-md);
  }

  .hero-title {
    font-size: clamp(2.25rem, 10vw, 3.5rem);
  }

  .hero-buttons {
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: 280px;
    margin: 0 auto;
  }

  .hero-buttons .btn-primary,
  .hero-buttons .btn-secondary {
    width: 100%;
    justify-content: center;
  }

  .landing-section {
    padding: var(--space-2xl) var(--space-md);
    /* Mirror the desktop breathing-room boost on mobile, but pin the
       gap with absolute units so it stays comfortable even when the
       admin density slider (--space-scale) is dialed down. clamp()
       with a 6rem floor guarantees the painted card edge never
       crowds the eyebrow / trailing CTA on phones. !important keeps
       any narrower section-level overrides from collapsing it. */
    padding-block: clamp(6rem, 18vw, 10rem) !important;
  }

  .highlights-grid {
    grid-template-columns: 1fr;
  }

  .experiences-grid {
    grid-template-columns: 1fr;
  }

  .pricing-grid {
    grid-template-columns: 1fr;
  }

  .form-grid-2,
  .form-grid-3 {
    grid-template-columns: 1fr;
  }

  .slide-content {
    left: var(--space-md);
    right: var(--space-md);
    bottom: 5rem;
  }

  .slide-details {
    grid-template-columns: 1fr;
  }

  .dot-nav {
    display: none;
  }

  .gallery-top-left .logo-text {
    display: none;
  }

  /* Ensure 44px minimum touch targets on navigation buttons */
  .nav-circle-btn {
    width: 2.75rem;
    height: 2.75rem;
    min-width: 44px;
    min-height: 44px;
  }

  .faq-question {
    min-height: 44px;
  }

  /* Modal close button — ensure 44px touch target */
  .modal-close {
    min-width: 44px;
    min-height: 44px;
  }

  /* Chat send buttons — ensure 44px touch target (incl. the collapsed-bar send + expand icons,
     which are the primary composer actions in the default non-bubble install). */
  .chatbot-send-panel-btn,
  .side-panel-send-btn,
  .chatbot-bar-btn {
    min-width: 44px;
    min-height: 44px;
  }

  /* Prevent iOS Safari auto-zoom on ALL inputs site-wide (must be >= 16px) */
  input[type="text"],
  input[type="email"],
  input[type="tel"],
  input[type="number"],
  input[type="date"],
  input[type="search"],
  input[type="password"],
  input[type="url"],
  select,
  textarea,
  .form-group input,
  .form-group select,
  .glass-textarea {
    font-size: 16px !important;
  }
}

@media (min-width: 769px) and (max-width: 1024px) {
  .highlights-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .experiences-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .slide-content {
    left: var(--space-xl);
    max-width: 28rem;
  }
}

@media (min-width: 1025px) {
  .hero-nav {
    padding: var(--space-lg) var(--space-2xl);
  }

  .slide-content {
    left: 6rem;
  }
}


/* =============================================================================
   17a. TESTIMONIALS SECTION
   =============================================================================
   A grid of frosted-glass review cards.
   Each card displays a star rating, quote text, reviewer name/role,
   and an optional circular photo.
   Matches the existing dark-glass design language.
============================================================================= */

.testimonials-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-lg);
  max-width: 72rem;
  margin: 0 auto;
}

/* Section-template POC — testimonials "carousel" variant. Active only when Admin sets the
   testimonials Layout to "Carousel" (renderTestimonials adds [data-tpl="carousel"] on the
   #testimonials-grid container). The default grid above is untouched. */
#testimonials-grid[data-tpl="carousel"] {
  display: block;            /* override the grid so the horizontal strip can span full width */
  max-width: 72rem;
  margin: 0 auto;
}
.tpl-testi-carousel {
  display: flex;
  gap: var(--space-lg);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding: 0.5rem 0.25rem 1.25rem;
  scrollbar-width: thin;
}
.tpl-testi-slide {
  flex: 0 0 min(82%, 460px);
  scroll-snap-align: center;
  margin: 0;
  padding: var(--space-lg);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 18px;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.tpl-testi-quote {
  margin: 0;
  font-size: 1.25rem;
  line-height: 1.55;
  font-style: italic;
}
.tpl-testi-by {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: auto;
}

/* Section-template variant (P2) — testimonials "marquee". A continuously scrolling ribbon of
   compact quote cards. The .tpl-testi-mq container carries data-fx="marquee"; the techniques
   engine (public/techniques.js) builds the seamless loop + pause-on-hover + reduced-motion freeze
   (see techniques.css .fx-marquee). This file only styles the cards + frees the grid to span. */
#testimonials-grid[data-tpl="marquee"] {
  display: block;            /* override the grid so the full-width ribbon can span */
  max-width: none;
}
.tpl-testi-mq-card {
  flex: 0 0 min(78vw, 340px);
  box-sizing: border-box;
  margin: 0;
  padding: var(--space-lg);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 18px;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.tpl-testi-mq-quote {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.5;
  font-style: italic;
  /* keep cards a consistent height so the ribbon scrolls evenly */
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.tpl-testi-mq-by {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: auto;
}

/* Section-template variant (P2) — testimonials "spotlight". The default grid of cards, but each
   carries data-fx="tilt" so it leans toward the cursor with a soft accent glow (techniques.css
   .fx-tilt / .fx-tilt-glow). Touch + reduced-motion flatten it automatically (engine guards). */
.tpl-testi-spot {
  /* give the 3D rotation a stable origin + ensure the ::after glow clips to the rounded card */
  transform-origin: center;
  overflow: hidden;
}
/* The base .testimonial-card:hover sets a translateY lift (specificity 0,2,0) that would mask the
   tilt's transform (.fx-tilt, 0,1,0). For spotlight cards, win on specificity (0,2,1) and apply the
   SAME transform the engine drives via --fx-rx/--fx-ry, so the lean shows instead of the lift. */
.testimonial-card.tpl-testi-spot:hover {
  transform: perspective(900px) rotateX(var(--fx-rx, 0deg)) rotateY(var(--fx-ry, 0deg));
}
@media (prefers-reduced-motion: reduce) {
  .testimonial-card.tpl-testi-spot:hover { transform: none; }
}

/* Section-template POC (Option B) — team "spotlight" variant (server-rendered Jinja partial). */
.tpl-team-spotlight {
  display: flex;
  flex-direction: column;
  grid-column: 1 / -1;   /* span the full width of the parent #team-grid (itself a CSS grid) */
  gap: var(--space-lg);
  max-width: 60rem;
  margin: 0 auto;
}
.tpl-team-spot-card {
  display: flex;
  gap: var(--space-lg);
  align-items: center;
  padding: var(--space-lg);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 18px;
}
.tpl-team-spot-photo {
  flex: 0 0 96px;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
}
.tpl-team-spot-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  font-weight: 700;
  background: rgba(255, 255, 255, 0.08);
}
.tpl-team-spot-name { margin: 0 0 0.15rem; font-size: 1.25rem; }
.tpl-team-spot-title { margin: 0 0 0.5rem; opacity: 0.8; }
.tpl-team-spot-bio { margin: 0; line-height: 1.55; opacity: 0.9; }
@media (max-width: 600px) {
  .tpl-team-spot-card { flex-direction: column; text-align: center; }
}

.testimonial-card {
  padding: var(--space-lg);
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  transition: transform var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.testimonial-card:hover {
  transform: translateY(-3px);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 4px 20px rgba(255, 255, 255, 0.05);
}

.testimonial-stars {
  display: flex;
  gap: 0.2rem;
}

.testimonial-star {
  width: 1rem;
  height: 1rem;
  color: #c9a96e;
}

.testimonial-star.empty {
  color: rgba(255, 255, 255, 0.15);
}

.testimonial-content {
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.8);
  line-height: 1.7;
  font-style: italic;
  position: relative;
  padding-left: var(--space-md);
  border-left: 2px solid rgba(255, 255, 255, 0.15);
}

.testimonial-reviewer {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: auto;
}

.testimonial-photo {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid rgba(255, 255, 255, 0.15);
  flex-shrink: 0;
}

.testimonial-photo-placeholder {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.55);
}

.testimonial-name {
  font-size: 0.875rem;
  font-weight: 600;
  color: #fff;
  line-height: 1.3;
}

.testimonial-role {
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
}


/* =============================================================================
   17b. TEAM / ABOUT SECTION
   =============================================================================
   A grid of team member cards.
   Each card features a circular photo, name, title/position, and bio.
   Cards use the same frosted-glass style as the rest of the site.
============================================================================= */

.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-lg);
  max-width: 72rem;
  margin: 0 auto;
}

.team-card {
  padding: var(--space-xl);
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  transition: transform var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.team-card:hover {
  transform: translateY(-3px);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 4px 20px rgba(255, 255, 255, 0.05);
}

.team-photo {
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(255, 255, 255, 0.15);
}

.team-photo-placeholder {
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  border: 2px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.5rem;
  color: rgba(255, 255, 255, 0.55);
}

.team-name {
  font-size: 1.125rem;
  font-weight: 700;
  color: #fff;
  font-family: var(--font-serif);
}

.team-title {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--color-accent, #c9a96e);
  font-weight: 500;
  margin-top: -0.25rem;
}

.team-bio {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.6;
}


/* =============================================================================
   17c. FAQ SECTION
   =============================================================================
   Accordion-style FAQ list.
   Each item has a clickable question row with a rotating chevron arrow.
   When active, the answer panel slides open beneath the question.
   Uses an accent-colored left border on the active item.
============================================================================= */

.faq-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  max-width: 48rem;
  margin: 0 auto;
}

.faq-item {
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 0.375rem;
  background: rgba(255, 255, 255, 0.03);
  overflow: hidden;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.faq-item:hover {
  background: rgba(255, 255, 255, 0.06);
}

.faq-item.active {
  border-color: rgba(201, 169, 110, 0.3);
  background: rgba(255, 255, 255, 0.05);
}

.faq-question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  cursor: pointer;
  transition: color var(--transition-fast);
  width: 100%;
  text-align: left;
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.9);
  line-height: 1.5;
}

.faq-question:hover {
  color: #fff;
}

.faq-arrow {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  color: rgba(255, 255, 255, 0.55);
  transition: transform var(--transition-fast), color var(--transition-fast);
}

.faq-item.active .faq-arrow {
  transform: rotate(180deg);
  color: var(--color-accent, #c9a96e);
}

.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.4s var(--ease-smooth), padding 0.4s var(--ease-smooth);
  padding: 0 var(--space-lg);
}

.faq-item.active .faq-answer {
  max-height: 500px;
  padding: 0 var(--space-lg) var(--space-lg);
}

.faq-answer-text {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.65);
  line-height: 1.7;
  padding-left: var(--space-md);
  border-left: 2px solid rgba(201, 169, 110, 0.3);
}


/* =============================================================================
   17c1. BUSINESS INFO & CONTACT SECTION
   =============================================================================
   Two-column layout: left side has contact info cards (phone, email, address,
   hours) plus optional map embed; right side has an embedded contact form.
   All data is pulled from the database via the admin panel.
   ============================================================================= */

.business-info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.5rem;
  align-items: start;
}

.biz-info-left {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.biz-info-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

.biz-info-card {
  background: var(--glass-bg, rgba(255,255,255,0.04));
  border: 1px solid var(--glass-border, rgba(255,255,255,0.08));
  border-radius: 1rem;
  padding: 1.5rem;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.biz-info-card:hover {
  border-color: rgba(255,255,255,0.15);
  transform: translateY(-2px);
}

.biz-info-card-wide {
  grid-column: 1 / -1;
}

.biz-info-icon {
  color: var(--color-accent, #c9a96e);
  margin-bottom: 0.75rem;
}

.biz-info-icon i,
.biz-info-icon svg {
  width: 1.25rem;
  height: 1.25rem;
}

.biz-info-label {
  font-family: var(--font-sans, 'DM Sans', sans-serif);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255,255,255,0.5);
  margin-bottom: 0.35rem;
}

.biz-info-value {
  font-family: var(--font-sans, 'DM Sans', sans-serif);
  font-size: 0.95rem;
  color: rgba(255,255,255,0.85);
  line-height: 1.5;
}

.biz-info-value a {
  color: var(--color-accent, #c9a96e);
  text-decoration: none;
  transition: opacity var(--transition-fast);
}

.biz-info-value a:hover {
  opacity: 0.8;
}

.biz-hours-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.biz-hours-list li {
  display: flex;
  justify-content: space-between;
  padding: 0.3rem 0;
  font-size: 0.85rem;
  color: rgba(255,255,255,0.7);
  border-bottom: 1px solid rgba(255,255,255,0.05);
}

.biz-hours-list li:last-child {
  border-bottom: none;
}

.biz-hours-day {
  font-weight: 500;
  color: rgba(255,255,255,0.85);
}

.biz-hours-time {
  color: rgba(255,255,255,0.55);
}

.biz-info-map {
  border-radius: 1rem;
  overflow: hidden;
  border: 1px solid var(--glass-border, rgba(255,255,255,0.08));
}

.biz-info-map iframe {
  width: 100%;
  height: 250px;
  border: none;
  display: block;
}

.biz-contact-form-wrapper {
  background: var(--glass-bg, rgba(255,255,255,0.04));
  border: 1px solid var(--glass-border, rgba(255,255,255,0.08));
  border-radius: 1rem;
  padding: 2rem;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.biz-contact-form-title {
  font-family: var(--font-serif, 'Playfair Display', serif);
  font-size: 1.35rem;
  font-weight: 600;
  color: #fff;
  margin-bottom: 1.5rem;
}

.biz-contact-form {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.biz-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.85rem;
}

.biz-form-input {
  width: 100%;
  padding: 0.75rem 1rem;
  font-family: var(--font-sans, 'DM Sans', sans-serif);
  font-size: 0.9rem;
  color: #fff;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 0.5rem;
  outline: none;
  transition: border-color var(--transition-fast);
  box-sizing: border-box;
}

.biz-form-input::placeholder {
  color: rgba(255,255,255,0.55);
}

.biz-form-input:focus {
  border-color: var(--color-accent, #c9a96e);
}

.biz-form-textarea {
  resize: vertical;
  min-height: 100px;
}

.biz-form-submit {
  padding: 0.75rem 2rem;
  font-family: var(--font-sans, 'DM Sans', sans-serif);
  font-size: 0.9rem;
  font-weight: 600;
  color: #111;
  background: var(--color-accent, #c9a96e);
  border: none;
  border-radius: 0.5rem;
  cursor: pointer;
  transition: opacity var(--transition-fast), transform var(--transition-fast);
  margin-top: 0.25rem;
}

.biz-form-submit:hover {
  opacity: 0.9;
  transform: translateY(-1px);
}

.biz-form-submit:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
}

.biz-contact-success {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1.5rem;
  color: var(--color-accent, #c9a96e);
  font-family: var(--font-sans, 'DM Sans', sans-serif);
  font-size: 0.95rem;
}

.biz-contact-success i,
.biz-contact-success svg {
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
}

@media (max-width: 768px) {
  .business-info-grid {
    grid-template-columns: 1fr;
    gap: 1.5rem;
  }

  .biz-info-cards {
    grid-template-columns: 1fr;
  }

  .biz-form-row {
    grid-template-columns: 1fr;
  }
}

/* =============================================================================
   17c2. BLOG SECTION — Gallery-Style Preview Cards
   =============================================================================
   A grid of frosted-glass blog preview cards.
   Each card shows a cover image with gradient overlay, category badge,
   title, excerpt, author/date metadata, and a "Read More" link.
   Matches the existing highlights/testimonials card pattern.
============================================================================= */

/* Blog card grid — responsive layout matching highlights grid */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-lg);
  max-width: 72rem;
  margin: 0 auto;
}

/* Individual blog card — frosted glass with hover effects */
.blog-card {
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.blog-card:hover {
  border-color: rgba(255, 255, 255, 0.2);
  transform: translateY(-2px);
}

/* Cover image container with aspect ratio */
.blog-card-image {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

/* Placeholder when no cover image is set */
.blog-card-image-empty {
  background: rgba(255, 255, 255, 0.03);
}

/* Background image — zooms on hover */
.blog-card-image-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  transition: transform 0.7s ease;
}

.blog-card:hover .blog-card-image-bg {
  transform: scale(1.05);
}

/* Gradient overlay on cover image for text readability */
.blog-card-image-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.1), transparent);
}

/* Category badge — positioned over the cover image */
.blog-card-category {
  position: absolute;
  top: var(--space-md);
  left: var(--space-md);
  padding: 0.2rem 0.625rem;
  font-size: 0.625rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--color-accent, #c9a96e);
  background: rgba(201, 169, 110, 0.1);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(201, 169, 110, 0.3);
  border-radius: 9999px;
  z-index: 2;
}

/* Card body — title, excerpt, metadata */
.blog-card-body {
  padding: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  flex: 1;
}

.blog-card-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: #fff;
  line-height: 1.3;
  font-family: var(--font-serif);
}

.blog-card-excerpt {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Author + date metadata row */
.blog-card-meta {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: var(--space-sm);
}

.blog-card-author {
  font-size: 0.75rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.7);
}

.blog-card-date {
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
}

/* Separator dot between author and date */
.blog-card-author + .blog-card-date::before {
  content: '\00B7';
  margin-right: var(--space-sm);
  color: rgba(255, 255, 255, 0.3);
}

/* "Read More" link */
.blog-card-readmore {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-accent, #c9a96e);
  margin-top: var(--space-xs);
  transition: color var(--transition-fast);
}

.blog-card:hover .blog-card-readmore {
  color: #fff;
}


/* =============================================================================
   17e. UPCOMING EVENTS GRID + CARDS
   =============================================================================
   Mirrors the blog-card frosted-glass aesthetic but adds an overlapping
   date pill on the cover image and a footer row with capacity hint + RSVP
   CTA. Cards link straight to /event/<slug>.
============================================================================= */

.events-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  gap: var(--space-lg);
  max-width: 72rem;
  margin: 0 auto;
}

.event-card {
  position: relative;
  border-radius: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.event-card:hover {
  border-color: rgba(201, 169, 110, 0.35);
  transform: translateY(-2px);
}

.event-card-image {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.event-card-image-empty {
  background: linear-gradient(135deg, rgba(201,169,110,0.08), rgba(255,255,255,0.02));
}

.event-card-image-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  transition: transform 0.7s ease;
}

.event-card:hover .event-card-image-bg {
  transform: scale(1.05);
}

.event-card-image-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.6), rgba(0,0,0,0.1) 60%, transparent);
}

/* Status badge in the top-right of the cover image */
.event-card-badge {
  position: absolute;
  top: var(--space-md);
  right: var(--space-md);
  padding: 0.25rem 0.7rem;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  border-radius: 9999px;
  backdrop-filter: blur(8px);
  z-index: 2;
}
.event-card-badge.cancelled {
  color: #ffb3b3;
  background: rgba(220, 80, 80, 0.18);
  border: 1px solid rgba(220, 80, 80, 0.4);
}
.event-card-badge.full {
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.25);
}

/* Date pill that sits over the bottom-left corner of the cover image,
   slightly overhanging into the body so it visually anchors the card */
.event-date-pill {
  position: absolute;
  bottom: -22px;
  left: var(--space-lg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 56px; height: 56px;
  background: rgba(6, 11, 20, 0.92);
  border: 1px solid rgba(201, 169, 110, 0.4);
  border-radius: 0.6rem;
  backdrop-filter: blur(10px);
  z-index: 3;
  pointer-events: none;
  box-shadow: 0 6px 18px rgba(0,0,0,0.35);
}
.event-date-day {
  font-family: var(--font-serif);
  font-size: 1.4rem;
  font-weight: 600;
  color: #fff;
  line-height: 1;
}
.event-date-month {
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--color-accent, #c9a96e);
  margin-top: 2px;
}

.event-card-body {
  padding: var(--space-lg);
  padding-top: calc(var(--space-lg) + 14px);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  flex: 1;
}

.event-card-title {
  font-size: 1.15rem;
  font-weight: 700;
  color: #fff;
  line-height: 1.3;
  font-family: var(--font-serif);
  margin-top: var(--space-xs);
}

.event-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.event-meta-pill {
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.7);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.08);
  padding: 0.2rem 0.6rem;
  border-radius: 9999px;
}
.event-meta-pill.price {
  color: var(--color-accent, #c9a96e);
  border-color: rgba(201, 169, 110, 0.25);
  background: rgba(201, 169, 110, 0.08);
}

.event-card-excerpt {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.55;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.event-card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: auto;
  padding-top: var(--space-sm);
  gap: var(--space-sm);
}

.event-spots-left {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.55);
  letter-spacing: 0.04em;
}

.event-card-cta {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-accent, #c9a96e);
  letter-spacing: 0.03em;
  transition: color var(--transition-fast), transform var(--transition-fast);
}
.event-card:hover .event-card-cta {
  color: #fff;
  transform: translateX(2px);
}


/* =============================================================================
   17d. SITE FOOTER
   =============================================================================
   A dark footer sitting outside the snap-scroll container.
   Multi-column layout with brand info, quick links, contact details,
   and social media icons. Responsive — stacks on mobile.
============================================================================= */

.site-footer {
  background: var(--color-bg, #060b14);
  border-top: 1px solid rgba(201, 169, 110, 0.2);
  padding: var(--space-3xl) var(--space-xl) var(--space-lg);
  font-family: var(--font-sans);
}

.footer-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-2xl);
  max-width: 72rem;
  margin: 0 auto;
}

.footer-column {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.footer-description {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.55);
  line-height: 1.6;
}

.footer-heading {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--color-accent, #c9a96e);
  font-weight: 600;
  font-family: var(--font-sans);
  margin-bottom: var(--space-xs);
}

.footer-links {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.footer-links a {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.55);
  transition: color var(--transition-fast);
}

.footer-links a:hover {
  color: #fff;
}

.footer-contact-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.footer-contact-list li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.55);
}

.footer-contact-list li i,
.footer-contact-list li svg {
  color: rgba(255, 255, 255, 0.5);
  flex-shrink: 0;
}

.footer-social-links {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

.footer-social-link {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.05);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.55);
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.footer-social-link:hover {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.25);
}

.footer-social-link svg {
  width: 1rem;
  height: 1rem;
}

.footer-bottom {
  text-align: center;
  padding-top: var(--space-2xl);
  margin-top: var(--space-2xl);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.footer-bottom p {
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.5);
}


/* =============================================================================
   17e. RESPONSIVE — New Sections (Mobile)
   =============================================================================
   Mobile overrides for testimonials, team, FAQ, and footer sections.
============================================================================= */

@media (max-width: 768px) {
  .testimonials-grid {
    grid-template-columns: 1fr;
  }

  .team-grid {
    grid-template-columns: 1fr;
  }

  .blog-grid {
    grid-template-columns: 1fr;
  }

  .footer-container {
    grid-template-columns: 1fr;
    gap: var(--space-xl);
  }

  .faq-question {
    font-size: 0.875rem;
    padding: var(--space-md);
  }

  .faq-answer {
    padding: 0 var(--space-md);
  }

  .faq-item.active .faq-answer {
    padding: 0 var(--space-md) var(--space-md);
  }
}

@media (min-width: 769px) and (max-width: 1024px) {
  .testimonials-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .team-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .blog-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}


/* =============================================================================
   17f. CUSTOM SECTION TEMPLATES
   =============================================================================
   Styles for admin-created custom sections rendered from templates.
============================================================================= */

.custom-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-lg);
  max-width: 72rem;
  margin: 0 auto;
}

/* Technique-baked block — logo marquee (P4). The container carries data-fx="marquee"; the SiteFX
   engine adds .fx-marquee + builds the scrolling track (see techniques.css). These rules just style
   the logo items: a desaturated rest state that lights up on hover. */
.custom-logo-marquee .custom-logo-item {
  height: 46px; width: auto; object-fit: contain;
  opacity: 0.62; filter: grayscale(1);
  transition: opacity 0.2s ease, filter 0.2s ease;
}
.custom-logo-marquee .custom-logo-link:hover .custom-logo-item,
.custom-logo-marquee .custom-logo-item:hover { opacity: 1; filter: grayscale(0); }
.custom-logo-marquee .custom-logo-text {
  font-weight: 800; letter-spacing: 0.1em; opacity: 0.55; white-space: nowrap; font-size: 1.2rem;
}
.custom-logo-marquee .custom-logo-link { display: inline-flex; align-items: center; }

.custom-card {
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.custom-card-img {
  width: 100%;
  aspect-ratio: 16 / 9;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.custom-card-body {
  padding: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.custom-card-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: #fff;
}

.custom-card-subtitle {
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.6);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.custom-card-content {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.65);
  line-height: 1.6;
}

.custom-card-link {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-accent, #c9a96e);
  margin-top: var(--space-xs);
  transition: color var(--transition-fast);
}

.custom-card-link:hover {
  color: #fff;
}

.custom-text-block {
  max-width: 48rem;
  margin: 0 auto var(--space-2xl);
}

.custom-text-heading {
  font-size: 1.5rem;
  font-weight: 700;
  color: #fff;
  margin-bottom: var(--space-sm);
}

.custom-text-subtitle {
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: var(--space-md);
}

.custom-text-body {
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.75);
  line-height: 1.8;
  white-space: pre-wrap;
}

.custom-text-image {
  width: 100%;
  border-radius: 0.375rem;
  margin-top: var(--space-lg);
}

.custom-image-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-lg);
  max-width: 72rem;
  margin: 0 auto;
}

.custom-gallery-item {
  border-radius: 0.375rem;
  overflow: hidden;
}

.custom-gallery-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.custom-gallery-caption {
  padding: var(--space-sm) var(--space-md);
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.6);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-top: none;
  border-radius: 0 0 0.375rem 0.375rem;
}

.custom-cta-banner {
  text-align: center;
  padding: var(--space-3xl) var(--space-xl);
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
  max-width: 48rem;
  margin: 0 auto;
}

.custom-cta-title {
  font-size: clamp(1.5rem, 4vw, 2.5rem);
  font-weight: 700;
  color: #fff;
  margin-bottom: var(--space-md);
}

.custom-cta-description {
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.65);
  line-height: 1.6;
  max-width: 32rem;
  margin: 0 auto var(--space-xl);
}

.custom-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-lg);
  max-width: 60rem;
  margin: 0 auto;
}

.custom-stat-item {
  text-align: center;
  padding: var(--space-lg);
}

.custom-stat-number {
  font-family: var(--font-serif);
  font-size: clamp(2rem, 5vw, 3rem);
  font-weight: 700;
  color: #fff;
  line-height: 1.1;
  margin-bottom: var(--space-sm);
}

.custom-stat-label {
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.55);
}

/* Statement block (headline_statement) — a centered editorial statement; the headline span
   carries a TEXT SiteFX effect set in settings.text_fx (gradient-text / glitch / typewriter / …). */
.custom-statement { max-width: 52rem; margin: 0 auto; text-align: center; }
.custom-statement-h {
  font-family: var(--font-serif);
  font-size: clamp(2rem, 5.5vw, 3.6rem);
  font-weight: 700; line-height: 1.08; letter-spacing: -0.01em; margin: 0;
}
.custom-statement-sub {
  margin: var(--space-md) auto 0; max-width: 38rem;
  font-size: 1.05rem; line-height: 1.6; color: rgba(255, 255, 255, 0.6);
}

/* Flip cards (flip_cards) — front/back faces flip on hover (fx-flip base in techniques.css). */
.custom-flip { height: 220px; border-radius: 16px; }
.custom-flip .fx-flip-inner { width: 100%; height: 100%; }
.custom-flip-face {
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
  padding: 1.5rem; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.1);
}
.custom-flip-front { background: rgba(255, 255, 255, 0.04); }
.custom-flip-back { background: linear-gradient(135deg, var(--color-accent), var(--color-accent-secondary, var(--color-accent))); color: #fff; }
.custom-flip-back p { margin: 0; font-size: 1rem; line-height: 1.5; }

/* Before / after slider (before_after). */
.custom-ba {
  position: relative; overflow: hidden; border-radius: 16px; max-width: 760px; margin: 0 auto;
  aspect-ratio: 16 / 9; touch-action: none; user-select: none; cursor: ew-resize;
}
.custom-ba-tag {
  position: absolute; bottom: 14px; padding: 4px 12px; border-radius: 999px;
  font-size: 0.75rem; background: rgba(0, 0, 0, 0.55); color: #fff;
}
.custom-ba-tag-l { left: 14px; } .custom-ba-tag-r { right: 14px; }

/* Bento feature grid (bento_features) — first tile is the large feature. */
.custom-bento-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md); }
.custom-bento-tile {
  border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; padding: var(--space-lg);
  background: rgba(255, 255, 255, 0.03);
}
.custom-bento-tile:first-child { grid-column: span 2; grid-row: span 2; }
@media (max-width: 720px) {
  .custom-bento-grid { grid-template-columns: 1fr 1fr; }
  .custom-bento-tile:first-child { grid-column: span 2; grid-row: auto; }
}

/* Metrics dashboard (metrics_dashboard) — headline ring + animated bars + KPI tiles. */
.custom-metrics { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 2.5rem; }
.custom-metrics-lead { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; }
.custom-metric-cap { font-size: 0.85rem; color: rgba(255, 255, 255, 0.6); }
.custom-metrics-bars { height: 120px; }
.custom-metrics-kpis { display: flex; flex-wrap: wrap; gap: var(--space-md); }
.custom-metric {
  border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 14px; padding: 1rem 1.4rem;
  background: rgba(255, 255, 255, 0.03); text-align: left; min-width: 130px;
}
.custom-metric-n { font-family: var(--font-serif); font-size: 1.8rem; font-weight: 700; color: #fff; }
.custom-metric-l { font-size: 0.8rem; color: rgba(255, 255, 255, 0.55); margin-top: 0.2rem; }

/* ── Per-section STYLE / THEME treatments (settings.style → .sx-<key>, see core.SECTION_STYLE_CATALOG).
   A universal visual look applied to ANY section; !important so the treatment wins over a section's
   own (sometimes inline) background. Each is independent of motion (settings.fx) + layout (variant). */
.sx-midnight { background: #090b11 !important; color: #e7e9f0; }
.sx-midnight .section-title, .sx-midnight h1, .sx-midnight h2, .sx-midnight h3 { color: #fff; }
.sx-midnight .section-subtitle, .sx-midnight .section-eyebrow ~ p, .sx-midnight > .max-w-container p { color: rgba(255, 255, 255, 0.72); }

.sx-accent { background: color-mix(in srgb, var(--color-accent) 12%, var(--color-bg, #0a0f1a)) !important; }

.sx-gradient { background: linear-gradient(135deg, color-mix(in srgb, var(--color-accent) 26%, var(--color-bg, #0a0f1a)), var(--color-bg, #0a0f1a) 72%) !important; }

.sx-spotlight { position: relative; background: var(--color-bg, #0a0f1a) !important; }
.sx-spotlight::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background: radial-gradient(62% 52% at 50% 0%, color-mix(in srgb, var(--color-accent) 22%, transparent), transparent 70%);
}
.sx-spotlight > * { position: relative; z-index: 1; }

.sx-glass {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.015)) !important;
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border-top: 1px solid rgba(255, 255, 255, 0.08); border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.sx-bordered { background: var(--color-bg, #0a0f1a) !important; }
.sx-bordered > .max-w-container {
  border: 1px solid color-mix(in srgb, var(--color-accent) 30%, transparent);
  border-radius: 18px; padding: clamp(1.5rem, 4vw, 3rem);
}

.sx-contrast { background: #f5f4f1 !important; color: #15151c; }
.sx-contrast .section-title, .sx-contrast h1, .sx-contrast h2, .sx-contrast h3 { color: #111; }
.sx-contrast .section-subtitle, .sx-contrast .section-eyebrow { color: rgba(0, 0, 0, 0.6); }

/* dim — a slightly darker band so a section recedes behind the rest of the page. */
.sx-dim { background: color-mix(in srgb, #000 16%, var(--color-bg, #0a0f1a)) !important; }

/* vignette — darkened edges that pull the eye to the centre (overlay, content above it). */
.sx-vignette { position: relative; background: var(--color-bg, #0a0f1a) !important; }
.sx-vignette::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background: radial-gradient(120% 100% at 50% 50%, transparent 52%, rgba(0, 0, 0, 0.55) 100%);
}
.sx-vignette > * { position: relative; z-index: 1; }

/* duotone — a diagonal accent→ink wash with a thin accent rule along the top edge. */
.sx-duotone {
  background: linear-gradient(135deg, color-mix(in srgb, var(--color-accent) 34%, #05070d), #05070d 78%) !important;
  border-top: 2px solid var(--color-accent, #c9a96e);
}
.sx-duotone .section-title, .sx-duotone h1, .sx-duotone h2, .sx-duotone h3 { color: #fff; }

/* panel — base bg stays; the content lifts onto a soft elevated card with a shadow. */
.sx-panel { background: var(--color-bg, #0a0f1a) !important; }
.sx-panel > .max-w-container {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 20px;
  padding: clamp(1.5rem, 4vw, 3rem);
  box-shadow: 0 24px 60px -28px rgba(0, 0, 0, 0.7);
}

/* sunrise — a warm accent glow rising from the top edge into the base bg. */
.sx-sunrise { background: linear-gradient(180deg, color-mix(in srgb, var(--color-accent) 22%, var(--color-bg, #0a0f1a)), var(--color-bg, #0a0f1a) 60%) !important; }

/* radiance — soft, multi-point brand-tinted radial glows over the base bg. */
.sx-radiance {
  background:
    radial-gradient(60% 50% at 20% 12%, color-mix(in srgb, var(--color-accent) 20%, transparent), transparent 70%),
    radial-gradient(50% 45% at 85% 92%, color-mix(in srgb, var(--color-accent) 14%, transparent), transparent 70%),
    var(--color-bg, #0a0f1a) !important;
}

/* grid — a faint blueprint grid behind the content (non-interactive ::before overlay). */
.sx-grid { position: relative; background: var(--color-bg, #0a0f1a) !important; }
.sx-grid::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0.5;
  background-image:
    linear-gradient(color-mix(in srgb, var(--color-accent) 8%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--color-accent) 8%, transparent) 1px, transparent 1px);
  background-size: 40px 40px;
}
.sx-grid > * { position: relative; }

/* frost — an accent-tinted frosted wash bounded by hairline accent rules. */
.sx-frost {
  background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg, #0a0f1a)) !important;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  border-top: 1px solid color-mix(in srgb, var(--color-accent) 22%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--color-accent) 22%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .sx-glass, .sx-frost { backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* ── Per-section ENTRANCE ANIMATIONS (settings.anim → .an-<key>, see core.SECTION_ANIM_CATALOG).
   SAFE BY DESIGN: the section is fully visible by default and the keyframe only plays when the site's
   IntersectionObserver adds `.section-in-view`. So if the observer never fires (chat mode, no-JS) the
   section is simply visible — it is NEVER stuck hidden. All transforms are vertical / scale / opacity /
   blur (no horizontal transform → no stray horizontal scrollbar on full-width sections). The `both`
   fill-mode holds the animated-from state during the run so there is no pre-play flash for the part of
   the timeline before .section-in-view lands (below-the-fold sections get observed before they scroll
   into view). Reduced-motion users skip the motion entirely (handled below). */
.an-fade-up.section-in-view { animation: an-fade-up 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.an-rise.section-in-view    { animation: an-rise 0.75s cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.an-zoom.section-in-view    { animation: an-zoom 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.an-blur.section-in-view    { animation: an-blur 0.8s ease both; }
.an-fade.section-in-view    { animation: an-fade 0.8s ease both; }
.an-drift.section-in-view   { animation: an-drift 0.85s cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.an-pop.section-in-view     { animation: an-pop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) both; }
.an-descend.section-in-view { animation: an-descend 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) both; }

@keyframes an-fade-up { from { opacity: 0; transform: translateY(40px); } to { opacity: 1; transform: none; } }
@keyframes an-rise    { from { opacity: 0; transform: translateY(48px) scale(0.985); } to { opacity: 1; transform: none; } }
@keyframes an-zoom    { from { opacity: 0; transform: scale(0.93); } to { opacity: 1; transform: none; } }
@keyframes an-blur    { from { opacity: 0; filter: blur(16px); } to { opacity: 1; filter: blur(0); } }
@keyframes an-fade    { from { opacity: 0; } to { opacity: 1; } }
@keyframes an-drift   { from { opacity: 0; transform: translateY(64px); filter: blur(8px); } to { opacity: 1; transform: none; filter: blur(0); } }
@keyframes an-pop     { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: none; } }
@keyframes an-descend { from { opacity: 0; transform: translateY(-36px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .an-fade-up.section-in-view, .an-rise.section-in-view, .an-zoom.section-in-view,
  .an-blur.section-in-view, .an-fade.section-in-view,
  .an-drift.section-in-view, .an-pop.section-in-view, .an-descend.section-in-view { animation: none !important; }
}

/* ── Per-section LAYOUT / ARRANGEMENT (settings.layout → [data-lyt] on the section element, see
   core.SECTION_LAYOUT_CATALOG). A CSS-only reflow of the section's EXISTING card grid, so it works on
   ANY section — built-in AND custom — with no renderer changes and no server rendering. The long :is()
   list is every known grid container (built-in #*-grid + custom .custom-*-grid); !important so the
   reflow wins over each grid's own grid-template-columns. Independent of the structural `variant`. */

/* rows — one full-width item per line, in a comfortable reading column */
[data-lyt="rows"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
  display: grid !important; grid-template-columns: 1fr !important; max-width: 52rem; margin-inline: auto;
}

/* duo — exactly two columns of larger cards */
[data-lyt="duo"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
  display: grid !important; grid-template-columns: repeat(2, 1fr) !important;
}

/* triple — a tidy three-column grid */
[data-lyt="triple"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
  display: grid !important; grid-template-columns: repeat(3, 1fr) !important;
}

/* duo/triple collapse to a single column on narrow screens so cards never crush */
@media (max-width: 700px) {
  [data-lyt="duo"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery),
  [data-lyt="triple"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
    grid-template-columns: 1fr !important;
  }
}

/* dense — smaller cards, more per row */
[data-lyt="dense"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
  display: grid !important; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)) !important;
}

/* wide — fewer, larger cards (a two-up feature grid) */
[data-lyt="wide"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
  display: grid !important; grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)) !important;
}

/* mosaic — a masonry grid of varied heights (CSS columns) */
[data-lyt="mosaic"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
  display: block !important; column-count: 3; column-gap: var(--space-lg, 1.5rem);
}
[data-lyt="mosaic"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) > * {
  break-inside: avoid; -webkit-column-break-inside: avoid; margin-bottom: var(--space-lg, 1.5rem); display: inline-block; width: 100%;
}
@media (max-width: 900px) { [data-lyt="mosaic"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#blog-grid,#events-grid,#video-gallery-grid,#store-grid,.custom-cards-grid,.custom-image-gallery) { column-count: 2; } }
@media (max-width: 560px) { [data-lyt="mosaic"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#blog-grid,#events-grid,#video-gallery-grid,#store-grid,.custom-cards-grid,.custom-image-gallery) { column-count: 1; } }

/* rail — a horizontal, swipeable scroll rail (scroll-snap) */
[data-lyt="rail"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) {
  display: flex !important; grid-template-columns: none !important; flex-wrap: nowrap;
  overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  gap: var(--space-lg, 1.5rem); padding-bottom: 0.8rem; scrollbar-width: thin;
}
[data-lyt="rail"] :is(#highlights-grid,#experiences-grid,#pricing-grid,#testimonials-grid,#team-grid,#blog-grid,#events-grid,#video-gallery-grid,#podcast-grid,#store-grid,#services-grid,.custom-cards-grid,.custom-stats-grid,.custom-bento-grid,.custom-icon-features-grid,.custom-image-gallery) > * {
  flex: 0 0 min(82%, 340px); scroll-snap-align: start;
}

.custom-icon-features-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-lg);
  max-width: 60rem;
  margin: 0 auto;
}

.custom-icon-feature {
  padding: var(--space-lg);
  border-radius: 0.375rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(4px);
}

.custom-feature-icon {
  width: 1.25rem;
  height: 1.25rem;
  color: var(--color-accent, #c9a96e);
  margin-bottom: var(--space-md);
}

.custom-feature-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: #fff;
  margin-bottom: var(--space-sm);
}

.custom-feature-subtitle {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: var(--space-sm);
}

.custom-feature-description {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.6;
}

@media (max-width: 768px) {
  .custom-cards-grid {
    grid-template-columns: 1fr;
  }

  .custom-image-gallery {
    grid-template-columns: 1fr;
  }

  .custom-icon-features-grid {
    grid-template-columns: 1fr;
  }

  .custom-stats-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 769px) and (max-width: 1024px) {
  .custom-cards-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .custom-image-gallery {
    grid-template-columns: repeat(2, 1fr);
  }

  .custom-icon-features-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}


/* =============================================================================
   18. CHATBOT — AI Concierge Bar & Chat Panel
   =============================================================================
   The chatbot UI consists of:
   1. A collapsed glass-panel bar (always visible at the bottom)
   2. An expanded chat panel (slides up from the bar)
   3. A split-screen overlay (for AI-controlled visuals)

   DESIGN PHILOSOPHY:
   - Uses backdrop-filter for the frosted glass effect
   - Dark translucent backgrounds to match the site's premium aesthetic
   - Smooth transitions for expand/collapse and split-screen
   - Responsive: full-width on mobile, centered on desktop

   TO CHANGE THE CHATBOT APPEARANCE:
   - Colors: Modify the rgba values below
   - Size: Change max-width and height values
   - Position: Change bottom/left/right in .chatbot-container
   - Glass effect: Adjust backdrop-filter blur amount
============================================================================= */

/* Container — positions the chatbot at the bottom center of the screen */
.chatbot-container {
  position: fixed;
  bottom: var(--space-lg);
  left: 50%;
  transform: translateX(-50%);
  z-index: 70;
  width: 92%;
  max-width: 540px;
  font-family: var(--font-sans);
}

/*
  COLLAPSED BAR — The floating pill that's always visible.
  Uses backdrop-filter for a frosted glass look.
  Contents: avatar, agent info, text input, send button, expand button.
*/
.chatbot-bar {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.625rem 0.5rem 0.75rem;
  /* Look is admin-themeable via CSS vars set by applyChatbotTheme(); each
     falls back to the original built-in values so an empty theme is a no-op. */
  background: var(--chatbot-surface-bg, rgba(255, 255, 255, 0.1));
  color: var(--chatbot-text, #fff);
  backdrop-filter: blur(var(--chatbot-blur, 16px));
  -webkit-backdrop-filter: blur(var(--chatbot-blur, 16px));
  border: 1px solid var(--chatbot-surface-border, rgba(201, 169, 110, 0.25));
  border-radius: var(--chatbot-radius, 9999px);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  transition: border-color var(--transition-fast), background var(--transition-fast);
  /* Admin-controllable chat-pill size. --chat-pill-scale is injected by
     the server (and updated live on save) — 1.0 = 100%. Using `zoom`
     scales the whole pill (avatar, text, input, buttons) uniformly. The
     expanded panel resets this below so only the pill is affected. */
  zoom: var(--chat-pill-scale, 1);
}

/* When the chat is expanded into the full panel, keep it at native size
   so the pill-size control never distorts the open conversation view. */
/* Task 077 — tooltip stacking fix: the control-button tooltips (`.chatbot-icon-btn::after`) open
   UPWARD into the space the expanded reply panel occupies. The panel (`.chatbot-panel`) is z-index:auto
   and later in the DOM, so it painted OVER the tooltip. Give the bar a positive stacking level so the
   bar — and its `::after` tooltips — paint ABOVE the auto-stacked panel. The bar and panel don't
   overlap spatially (the panel sits above the bar), so this only affects the tooltip region. */
.chatbot-container.expanded .chatbot-bar { zoom: 1; position: relative; z-index: 2; }

/* GRE-1 — avatar greeter video bubble. Floats just above the chat pill (the
   .chatbot-container is a positioned/fixed ancestor, so absolute anchors here).
   Shown by script.js only when /api/chatbot-settings carries greeting_video_url. */
.video-greeter-bubble {
  position: absolute;
  bottom: 100%;
  left: 0;
  margin-bottom: 0.6rem;
  width: 200px;
  max-width: 60vw;
  border-radius: 16px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.34);
  z-index: 71;
  animation: greeterIn 0.35s ease;
}
.video-greeter-video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 16px;
}
.video-greeter-close {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}
.video-greeter-close:hover { background: rgba(0, 0, 0, 0.78); }
@keyframes greeterIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .video-greeter-bubble { animation: none; } }

/* AV-2 (B2+B3) — the prominent, repositionable presenter. script.js lifts the bubble to <body> and
   adds .avatar-presenter, so fixed placement anchors to the VIEWPORT (left/center/right/bottom) — a
   focal point without covering the hero. .avatar-speaking adds a zero-cost glow + bob while the AI
   replies (box-shadow on the bubble itself, so the overflow:hidden video corners don't clip it). */
.video-greeter-bubble.avatar-presenter {
  position: fixed;
  bottom: 1.5rem; left: auto; right: auto; top: auto; margin: 0;
  width: 240px; max-width: 42vw;
}
.avatar-presenter[data-placement="left"]   { left: 1.5rem; }
.avatar-presenter[data-placement="right"]  { right: 1.5rem; }
.avatar-presenter[data-placement="center"] { left: 50%; bottom: 6rem; transform: translateX(-50%); }
.avatar-presenter[data-placement="bottom"] { left: 50%; bottom: 6.2rem; transform: translateX(-50%); }
.video-greeter-img { display: block; width: 100%; height: auto; border-radius: 16px; }
.video-greeter-glow { display: none; }
@media (max-width: 640px) {
  .video-greeter-bubble.avatar-presenter { width: 148px; max-width: 40vw; bottom: 1rem; }
  .avatar-presenter[data-placement="left"]  { left: 1rem; }
  .avatar-presenter[data-placement="right"] { right: 1rem; }
}
.avatar-presenter.avatar-speaking { animation: avatarSpeak 1.2s ease-in-out infinite; }
.avatar-presenter[data-placement="center"].avatar-speaking,
.avatar-presenter[data-placement="bottom"].avatar-speaking { animation: avatarSpeakC 1.2s ease-in-out infinite; }
/* M10 — the avatar "speaking" glow used a hardcoded indigo; derive it from the brand accent. */
@keyframes avatarSpeak {
  0%, 100% { box-shadow: 0 10px 34px rgba(0,0,0,.34), 0 0 16px 2px color-mix(in srgb, var(--chat-accent, #c9a96e) 25%, transparent); transform: translateY(0); }
  50%      { box-shadow: 0 10px 34px rgba(0,0,0,.34), 0 0 32px 7px color-mix(in srgb, var(--chat-accent, #c9a96e) 50%, transparent);  transform: translateY(-3px); }
}
@keyframes avatarSpeakC {
  0%, 100% { box-shadow: 0 10px 34px rgba(0,0,0,.34), 0 0 16px 2px color-mix(in srgb, var(--chat-accent, #c9a96e) 25%, transparent); transform: translateX(-50%) translateY(0); }
  50%      { box-shadow: 0 10px 34px rgba(0,0,0,.34), 0 0 32px 7px color-mix(in srgb, var(--chat-accent, #c9a96e) 50%, transparent);  transform: translateX(-50%) translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
  .avatar-presenter.avatar-speaking,
  .avatar-presenter[data-placement="center"].avatar-speaking,
  .avatar-presenter[data-placement="bottom"].avatar-speaking { animation: none; }
}

/* The floating launcher button (hidden-until-button placement) scales
   with the same control so the entry point matches the pill size. */
.chatbot-launcher { zoom: var(--chat-pill-scale, 1); }

.chatbot-bar:hover {
  border-color: rgba(201, 169, 110, 0.4);
  background: rgba(255, 255, 255, 0.14);
}

/* Agent avatar — circular badge with profile image */
.chatbot-avatar {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* M10 — the avatar fallback (no image set) used a hardcoded blue→purple gradient that ignored the
     brand accent; derive it from the accent so it matches the tenant's theme. */
  background: linear-gradient(135deg,
              color-mix(in srgb, var(--chat-accent, #c9a96e) 38%, transparent),
              color-mix(in srgb, var(--chat-accent, #c9a96e) 16%, transparent));
}

/* Smaller avatar variant used in chat panels and headers */
.chatbot-avatar-sm {
  width: 1.75rem;
  height: 1.75rem;
}

/* Profile image inside the avatar circle — fills the container */
.chatbot-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

/* Agent name and role text next to the avatar */
.chatbot-agent-info {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  min-width: 0;
}

.chatbot-agent-name {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--chatbot-text, #fff);
  line-height: 1.2;
}

.chatbot-agent-role {
  font-size: 0.625rem;
  color: color-mix(in srgb, var(--chatbot-text, #fff) 50%, transparent);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  line-height: 1.2;
}

/* Text input inside the collapsed bar */
.chatbot-bar-input {
  flex: 1;
  min-width: 0;
  padding: 0.375rem 0.75rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 9999px;
  color: var(--chatbot-text, #fff);
  font-size: 0.8125rem;
  font-family: inherit;
  outline: none;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.chatbot-bar-input::placeholder {
  color: color-mix(in srgb, var(--chatbot-text, #fff) 55%, transparent);
}

.chatbot-bar-input:focus {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.2);
}

/* Icon-only action buttons (Visualize / Full Screen) with hover tooltip */
.chatbot-icon-btn {
  position: relative;
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  /* M14 — the resting glyph was rgba(255,255,255,0.4) (~2.5:1 on the glass pill, below the WCAG 3:1
     minimum for UI controls); raise it so the mic/mute/fullscreen icons are actually perceptible. */
  color: rgba(255, 255, 255, 0.72);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast);
}

.chatbot-icon-btn:hover {
  transform: scale(1.1);
}

/* Tooltip — appears above the button on hover */
.chatbot-icon-btn::after,
.chatbot-close-btn[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: rgba(10, 15, 26, 0.92);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.85);
  font-family: var(--font-sans);
  font-size: 0.65rem;
  letter-spacing: 0.03em;
  padding: 0.3rem 0.6rem;
  border-radius: 0.4rem;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.chatbot-icon-btn:hover::after,
.chatbot-close-btn[data-tooltip]:hover::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Visualize button — gold accent on hover */
.chatbot-pill-visualize:hover {
  background: rgba(201, 169, 110, 0.15);
  border-color: rgba(201, 169, 110, 0.3);
  color: var(--color-accent, #c9a96e);
  box-shadow: 0 0 10px rgba(201, 169, 110, 0.1);
}

/* Full Screen button hover — M10: use the brand accent (was a hardcoded indigo that clashed with the
   adjacent Visualize button's gold hover on any non-indigo theme). */
.chatbot-pill-fullscreen:hover {
  background: color-mix(in srgb, var(--chat-accent, #c9a96e) 14%, transparent);
  border-color: color-mix(in srgb, var(--chat-accent, #c9a96e) 28%, transparent);
  color: var(--chat-accent, #c9a96e);
  box-shadow: 0 0 10px color-mix(in srgb, var(--chat-accent, #c9a96e) 18%, transparent);
}

/* "Think" toggle — a subtle deeper-answer opt-in. Hidden on the collapsed pill (no clutter); only
   shown once the chat panel is expanded. Active state uses the brand accent so it's clearly "on". */
.chatbot-think-toggle { display: none; }
/* Reveal only when the panel is expanded — !important so it also shows on ≤768px, where the generic
   `.chatbot-icon-btn` mobile-hide rule would otherwise keep it hidden even in the expanded panel. */
.chatbot-container.expanded .chatbot-think-toggle { display: inline-flex !important; }
.chatbot-think-toggle.active {
  color: var(--chat-accent, #c9a96e);
  background: color-mix(in srgb, var(--chat-accent, #c9a96e) 16%, transparent);
  border-color: color-mix(in srgb, var(--chat-accent, #c9a96e) 34%, transparent);
  box-shadow: 0 0 10px color-mix(in srgb, var(--chat-accent, #c9a96e) 22%, transparent);
}

/* Cookie / consent banner (mig 0234) — only injected when the operator enables cookie_consent_enabled.
   A small bottom-LEFT card so it never collides with the concierge pill (bottom-center/right). Theme-aware. */
.cs-cookie-consent {
  position: fixed; left: 1rem; bottom: 1rem; z-index: 80;
  max-width: 360px; width: calc(100% - 2rem);
  background: var(--color-section-1, #12161f); color: var(--color-text, #e7e9f0);
  border: 1px solid var(--glass-border, rgba(255, 255, 255, 0.12)); border-radius: 14px;
  padding: 1rem 1.1rem; box-shadow: 0 20px 50px -20px rgba(0, 0, 0, 0.7);
  font-size: 0.85rem; line-height: 1.5;
}
.cs-cookie-consent .cs-cc-text { margin: 0 0 0.8rem; }
.cs-cookie-consent a { color: var(--color-accent, #c9a96e); text-decoration: underline; }
.cs-cookie-consent .cs-cc-actions { display: flex; gap: 0.5rem; justify-content: flex-end; }
.cs-cc-btn {
  border-radius: 999px; padding: 0.45rem 1.1rem; font-size: 0.82rem; font-weight: 600; cursor: pointer;
  border: 1px solid var(--glass-border, rgba(255, 255, 255, 0.16)); background: transparent; color: inherit;
}
.cs-cc-accept { background: var(--color-accent, #c9a96e); border-color: transparent; color: #10131a; }
.cs-cc-btn:hover { filter: brightness(1.08); }
@media (max-width: 560px) {
  .cs-cookie-consent { left: 0.5rem; right: 0.5rem; bottom: 0.5rem; width: auto; max-width: none; }
}

/* Slightly smaller in inline panels (split-screen / side chat) */
.chatbot-icon-inline {
  width: 1.6rem;
  height: 1.6rem;
}

/* Small circular buttons in the bar (send, expand) */
.chatbot-bar-btn {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.6);
  background: none;
  border: none;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
  flex-shrink: 0;
}

.chatbot-bar-btn:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

/*
  EXPANDED CHAT PANEL — Full chat interface that slides up from the bar.
  Hidden by default; shown when chatbot-container has .expanded class.
*/
/* Per-surface background media (mig 0149) — an image/gif/video layer + a readable dark scrim behind a
   chat/form surface, with the surface's real content lifted above it. The surface keeps its glass tint
   (semi-transparent), so the media shows through softly. */
.chat-bg-layer { position: absolute; inset: 0; z-index: 0; overflow: hidden; border-radius: inherit; pointer-events: none; }
.chat-bg-layer .chat-bg-img { position: absolute; inset: 0; background-size: cover; background-position: center; }
.chat-bg-layer video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.chat-bg-scrim { position: absolute; inset: 0; }
.has-chat-bg > *:not(.chat-bg-layer) { position: relative; z-index: 1; }

.chatbot-panel {
  position: absolute;
  bottom: calc(100% + 0.5rem);
  left: 0;
  right: 0;
  height: 0;
  max-height: 70vh;
  /* Themed surface (see applyChatbotTheme) with the original glass as fallback. */
  background: var(--chatbot-surface-bg, rgba(255, 255, 255, 0.06));
  color: var(--chatbot-text, #fff);
  backdrop-filter: blur(var(--chatbot-blur, 24px));
  -webkit-backdrop-filter: blur(var(--chatbot-blur, 24px));
  border: 1px solid var(--chatbot-surface-border, rgba(255, 255, 255, 0.1));
  border-radius: 1rem;
  box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: height var(--transition-medium) var(--ease-smooth),
              opacity var(--transition-fast) ease;
}

/* When expanded, the panel becomes visible and takes height */
.chatbot-container.expanded .chatbot-panel {
  height: auto;
  opacity: 1;
  pointer-events: auto;
}

.panel-latest {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
}

.panel-latest-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
}

.panel-history {
  flex-direction: column;
  flex: 1;
  min-height: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.4s cubic-bezier(0.22, 1, 0.36, 1),
              opacity 0.3s ease;
}

.panel-history.visible {
  display: flex;
  max-height: 50vh;
  opacity: 1;
}

.panel-history .chatbot-messages {
  flex: 1;
  overflow-y: auto;
  padding: 0.5rem 1rem;
}

/* Rotate the expand arrow when panel is open */
.chatbot-container.expanded .chatbot-bar-btn:last-child svg {
  transform: rotate(180deg);
  transition: transform var(--transition-fast);
}

/* Panel header — agent info and close button */
.chatbot-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.875rem 1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
}

.chatbot-panel-header-info {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}

/* Close button */
.chatbot-close-btn {
  position: relative;   /* anchor the [data-tooltip] ::after bubble to this button */
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.55);
  background: none;
  border: none;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.chatbot-close-btn:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

/*
  MESSAGE AREA — Scrollable container for chat bubbles.
  Uses flex-direction: column so messages stack top-to-bottom.
  Auto-scrolls to the bottom when new messages arrive.
*/
.chatbot-messages {
  flex: 1;
  overflow-y: auto;
  /* Keep wheel/touch scrolling inside the chat — don't let it chain through
     to whatever is behind (e.g. the gallery card view when chat is open). */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}

.chatbot-messages::-webkit-scrollbar {
  width: 4px;
}

.chatbot-messages::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 2px;
}

/*
  MESSAGE BUBBLES — Two types:
  - .chat-msg-user: User messages (right-aligned, solid background)
  - .chat-msg-agent: Agent messages (left-aligned, subtle background)
*/
.chat-msg {
  max-width: 85%;
  padding: 0.625rem 0.875rem;
  border-radius: 1rem;
  font-size: 0.8125rem;
  line-height: 1.55;
  animation: fadeInUp 0.3s ease-out;
  /* A long unbroken token (a bare booking-confirm URL, a captured-lead email) must wrap inside
     the bubble instead of forcing the whole message column to scroll sideways on a phone.
     min-width:0 lets the bubble shrink as a flex item in the .chatbot-messages column. */
  overflow-wrap: anywhere;
  min-width: 0;
}

/* User message — right-aligned with solid white background */
.chat-msg-user {
  align-self: flex-end;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border-bottom-right-radius: 0.25rem;
}

/* Agent message — left-aligned with subtle dark background */
.chat-msg-agent {
  align-self: flex-start;
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.9);
  border-bottom-left-radius: 0.25rem;
}

/* Per-reply action row (Copy · Regenerate · 👍/👎) appended under a finished agent reply by the
   `chat:agent-message` hook in script.js. Subtle by default, brightens on hover — inherits the bubble's
   ink at low opacity so it works on any chat theme without a hard-coded color. */
.chat-reply-actions {
  display: flex;
  align-items: center;
  gap: 0.1rem;
  flex-wrap: wrap;
  margin-top: 0.45rem;
}
.chat-reply-actions-sp { flex: 1 1 auto; min-width: 0.5rem; }
.chat-reply-act {
  appearance: none;
  border: 0;
  background: transparent;
  cursor: pointer;
  font: inherit;
  font-size: 0.72rem;
  line-height: 1;
  color: currentColor;
  opacity: 0.5;
  padding: 0.28rem 0.42rem;
  border-radius: 0.4rem;
  transition: opacity 0.12s ease, background-color 0.12s ease;
}
.chat-reply-act:hover { opacity: 1; background: rgba(127, 127, 127, 0.16); }
.chat-reply-act:focus-visible { opacity: 1; outline: 2px solid var(--chat-accent, var(--color-accent, #c9a96e)); outline-offset: 1px; }
.chat-reply-act:disabled { cursor: default; opacity: 0.4; }
.chat-reply-act.is-picked { opacity: 1; }
.chat-reply-act[data-act="up"], .chat-reply-act[data-act="down"] { font-size: 0.86rem; padding: 0.2rem 0.32rem; }
.chat-reply-reasons { display: flex; gap: 0.3rem; flex-wrap: wrap; margin-top: 0.4rem; }
.chat-reply-reason {
  appearance: none;
  cursor: pointer;
  font: inherit;
  font-size: 0.7rem;
  padding: 0.24rem 0.58rem;
  border-radius: 1rem;
  border: 1px solid rgba(127, 127, 127, 0.4);
  background: transparent;
  color: currentColor;
  opacity: 0.82;
}
.chat-reply-reason:hover { opacity: 1; border-color: currentColor; }
.chat-reply-thanks { font-size: 0.72rem; opacity: 0.7; }

/* ═══════════════════════════════════════════════════════════════════════════
   CHAT APPEARANCE — operator-customizable look (chatbot_settings → body classes
   + the --chat-accent CSS var, applied in initChatbot). Defaults preserve the
   prior look; --chat-accent falls back to the site theme accent everywhere, so
   the chat is automatically on-brand and a chat_accent override re-colors it.
   ═══════════════════════════════════════════════════════════════════════════ */

/* SIDE — the base split layout is chat-LEFT; chat-side-right reverses the row so
   the page is on the left and the conversation on the right, and the divider
   border moves to the chat's left edge. (Default is now 'right'.) */
body.chat-side-right .split-overlay { flex-direction: row-reverse; }
body.chat-side-right .split-chat {
  border-right: none;
  border-left: 1px solid rgba(255, 255, 255, 0.08);
}

/* ACCENT — brand the visitor's own bubble + the send button + page CTAs with the
   chat accent (a subtle tint on the bubble so it reads on any theme). */
.chat-msg-user {
  background: color-mix(in srgb, var(--chat-accent, var(--color-accent, #c9a96e)) 24%, rgba(255, 255, 255, 0.10));
}
.chatbot-send-panel-btn, .side-panel-send-btn, .chatbot-bar-btn {
  background: var(--chat-accent, var(--color-accent, #c9a96e));
}
.sp-cta, .cvf-submit { background: var(--chat-accent, var(--color-accent, #c9a96e)); }

/* BUBBLE STYLE — rounded (default) | sharp (small radius) | minimal (outline only). */
body.chat-bubble-sharp .chat-msg { border-radius: 0.35rem; }
body.chat-bubble-sharp .chat-msg-user { border-bottom-right-radius: 0.1rem; }
body.chat-bubble-sharp .chat-msg-agent { border-bottom-left-radius: 0.1rem; }
body.chat-bubble-minimal .chat-msg { border-radius: 0.4rem; padding: 0.5rem 0.7rem; }
body.chat-bubble-minimal .chat-msg-user {
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--chat-accent, var(--color-accent, #c9a96e)) 55%, transparent);
}
body.chat-bubble-minimal .chat-msg-agent {
  background: transparent;
  border-left: 2px solid var(--chat-accent, var(--color-accent, #c9a96e));
  border-radius: 0 0.4rem 0.4rem 0;
}

/* ANIMATION — the base .chat-msg already fades in; this turns it OFF on request. */
body.chat-anim-off .chat-msg { animation: none !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   CHAT APPEARANCE round 2 (mig 0145) — launcher style, font, preset palette,
   entrance animation. Every DEFAULT (pill / theme / auto / fade) emits NO rule
   here, so an unconfigured site looks byte-identical to before.
   ═══════════════════════════════════════════════════════════════════════════ */

/* --- LAUNCHER STYLE (closed entry-point only; pill = current = no rule) --- */
body.chat-launcher-bar:not(.side-panel-active) .chatbot-container {
  left: 0; right: 0; bottom: 0; width: 100%; max-width: none; transform: none;
}
body.chat-launcher-bar:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-bar {
  border-radius: 0; border-bottom: none; padding: 0.6rem 1rem;
}
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) {
  left: auto; right: var(--space-lg, 1.5rem); bottom: var(--space-lg, 1.5rem);
  width: auto; max-width: none; transform: none;
}
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-bar {
  width: 3.5rem; height: 3.5rem; padding: 0; gap: 0; border-radius: 50%;
  justify-content: center; background: var(--chat-accent, var(--color-accent, #c9a96e));
}
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-agent-info,
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-bar-input,
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-icon-btn,
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-bar-btn { display: none; }
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) #chatbot-expand-btn {
  display: inline-flex; position: absolute; inset: 0; width: 100%; height: 100%;
  border-radius: 50%; background: none; color: var(--color-bg, #060b14); opacity: 0;
}
body.chat-launcher-bubble:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-avatar { width: 2.4rem; height: 2.4rem; }
body.chat-launcher-minimal:not(.side-panel-active) .chatbot-container:not(.expanded) {
  left: auto; right: var(--space-lg, 1.5rem); bottom: var(--space-lg, 1.5rem);
  width: auto; max-width: 22rem; transform: none;
}
body.chat-launcher-minimal:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-bar { padding: 0.4rem 0.5rem 0.4rem 0.6rem; gap: 0.4rem; }
body.chat-launcher-minimal:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-agent-info,
body.chat-launcher-minimal:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-icon-btn { display: none; }
body.chat-launcher-minimal:not(.side-panel-active) .chatbot-container:not(.expanded) .chatbot-avatar { width: 1.85rem; height: 1.85rem; }

/* --- FONT (theme = no rule = inherit site fonts; others are system stacks) --- */
body.chat-font-system { --chat-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; --chat-font-serif: Georgia, Cambria, 'Times New Roman', Times, serif; }
body.chat-font-grotesk { --chat-font-sans: 'Avenir Next', Avenir, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif; --chat-font-serif: 'Avenir Next', Avenir, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif; }
body.chat-font-editorial { --chat-font-sans: 'Iowan Old Style', Georgia, Cambria, 'Times New Roman', Times, serif; --chat-font-serif: 'Iowan Old Style', Georgia, Cambria, 'Times New Roman', Times, serif; }
body.chat-font-mono { --chat-font-sans: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Cascadia Code', ui-monospace, Menlo, Consolas, monospace; --chat-font-serif: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
body[class*="chat-font-"] .chat-msg,
body[class*="chat-font-"] .split-chat,
body[class*="chat-font-"] .chatbot-bar-input,
body[class*="chat-font-"] .sp-wrap { font-family: var(--chat-font-sans, inherit); }
body[class*="chat-font-"] .chat-msg-agent h3,
body[class*="chat-font-"] .chat-msg-agent h4,
body[class*="chat-font-"] .sp-title,
body[class*="chat-font-"] .sp-h { font-family: var(--chat-font-serif, inherit); }
body.chat-font-editorial .chat-msg { line-height: 1.6; }
body.chat-font-mono .chat-msg { font-size: 0.8rem; letter-spacing: -0.01em; }

/* --- PRESET PALETTE (auto = no rule = site theme accent) --- */
body.chat-theme-midnight { --chat-accent: #6366f1; --chat-surface-tint: 99 102 241; }
body.chat-theme-gold     { --chat-accent: #c9a96e; --chat-surface-tint: 201 169 110; }
body.chat-theme-ocean    { --chat-accent: #2dd4bf; --chat-surface-tint: 45 212 191; }
body.chat-theme-forest   { --chat-accent: #34d399; --chat-surface-tint: 52 211 153; }
body.chat-theme-rose     { --chat-accent: #fb7185; --chat-surface-tint: 251 113 133; }
body.chat-theme-mono     { --chat-accent: #d4d4d8; --chat-surface-tint: 212 212 216; }
body[class*="chat-theme-"] .chat-msg-agent { background: color-mix(in srgb, rgb(var(--chat-surface-tint, 255 255 255)) 8%, rgba(255, 255, 255, 0.06)); }

/* --- ENTRANCE ANIMATION (fade = current; honors reduced-motion) --- */
body.chat-anim-fade .chat-msg { animation: fadeInUp 0.3s ease-out; }
@keyframes chatMsgSlideInLeft { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: translateX(0); } }
@keyframes chatMsgSlideInRight { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: translateX(0); } }
body.chat-anim-slide .chat-msg-agent { animation: chatMsgSlideInLeft 0.28s ease-out; }
body.chat-anim-slide .chat-msg-user  { animation: chatMsgSlideInRight 0.28s ease-out; }
@keyframes chatMsgPop { 0% { opacity: 0; transform: scale(0.92); } 60% { opacity: 1; transform: scale(1.015); } 100% { opacity: 1; transform: scale(1); } }
body.chat-anim-pop .chat-msg { animation: chatMsgPop 0.26s cubic-bezier(0.34, 1.56, 0.64, 1); }
body.chat-anim-pop .chat-msg-user  { transform-origin: bottom right; }
body.chat-anim-pop .chat-msg-agent { transform-origin: bottom left; }
@keyframes chatMsgBounceIn { 0% { opacity: 0; transform: translateY(16px); } 55% { opacity: 1; transform: translateY(-4px); } 78% { transform: translateY(1px); } 100% { opacity: 1; transform: translateY(0); } }
body.chat-anim-bounce .chat-msg { animation: chatMsgBounceIn 0.42s cubic-bezier(0.22, 1, 0.36, 1); }
@media (prefers-reduced-motion: reduce) {
  body[class*="chat-anim-"] .chat-msg { animation: none !important; }
}

.chat-msg-streaming::after {
  content: '\25CF';
  color: rgba(255, 255, 255, 0.55);
  animation: blink-cursor 0.8s steps(2) infinite;
  margin-left: 2px;
}

@keyframes blink-cursor {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

/*
  FORMATTED MARKDOWN IN CHAT — Styles for rendered markdown
  inside agent message bubbles (headings, lists, bold, code, etc.)
*/
.chat-msg-agent p {
  margin: 0 0 0.5em 0;
}
.chat-msg-agent p:last-child {
  margin-bottom: 0;
}
.chat-msg-agent h3,
.chat-msg-agent h4 {
  font-family: var(--font-serif);
  color: #fff;
  margin: 0.75em 0 0.35em 0;
  font-size: 0.9rem;
  line-height: 1.3;
}
.chat-msg-agent h3:first-child,
.chat-msg-agent h4:first-child {
  margin-top: 0;
}
.chat-msg-agent strong {
  color: #fff;
  font-weight: 600;
}
.chat-msg-agent em {
  font-style: italic;
  color: rgba(255, 255, 255, 0.85);
}
.chat-msg-agent ul,
.chat-msg-agent ol {
  margin: 0.4em 0;
  padding-left: 1.25em;
}
.chat-msg-agent li {
  margin-bottom: 0.25em;
  line-height: 1.5;
}
.chat-msg-agent code {
  background: rgba(255, 255, 255, 0.1);
  padding: 0.1em 0.35em;
  border-radius: 0.25rem;
  font-size: 0.75rem;
  font-family: 'SF Mono', 'Fira Code', monospace;
}
.chat-msg-agent pre {
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-md);
  padding: 0.625rem;
  margin: 0.5em 0;
  overflow-x: auto;
}
.chat-msg-agent pre code {
  background: none;
  padding: 0;
  font-size: 0.75rem;
  line-height: 1.5;
}
.chat-msg-agent hr {
  border: none;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  margin: 0.75em 0;
}

/*
  IN-CHAT BOOKING CONFIRMATION CARD — A richer "you're booked" panel
  rendered inline in the conversation after a successful in-chat RSVP
  or contract booking. Mirrors the modal flow's confirmation panel so
  the visitor sees service / when / add-ons / total / next steps
  without leaving chat.
*/
.chat-msg-booking {
  max-width: 95%;
  background: transparent;
  padding: 0;
  border-radius: 0;
}
.chat-msg-booking .bk-card {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-left: 3px solid var(--accent, #c9a96e);
  border-radius: 0.875rem;
  padding: 0.875rem 1rem 0.9rem;
}
.bk-card-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}
.bk-card-check {
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--accent, #c9a96e);
  color: #0b0b0b;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.85rem;
  flex-shrink: 0;
}
.bk-card-title {
  font-family: var(--font-serif);
  margin: 0;
  font-size: 1rem;
  line-height: 1.2;
  color: #fff;
}
.bk-card-intro {
  margin: 0 0 0.6rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.9);
}
.bk-card-details {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding-top: 0.5rem;
  margin-bottom: 0.5rem;
}
.bk-card-row {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  font-size: 0.78125rem;
  line-height: 1.45;
}
.bk-card-label {
  flex: 0 0 5rem;
  color: rgba(255, 255, 255, 0.55);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.6875rem;
}
.bk-card-value {
  flex: 1 1 auto;
  color: #fff;
  font-weight: 500;
  word-break: break-word;
}
.bk-card-ref {
  font-family: 'SF Mono', 'Fira Code', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.85);
  font-weight: 400;
}
.bk-card-note {
  margin: 0.4rem 0 0;
  font-size: 0.75rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.75);
}
.bk-card-next {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.bk-card-next-text {
  margin-top: 0;
  margin-bottom: 0.5rem;
  color: rgba(255, 255, 255, 0.85);
}
.bk-card-cta {
  display: inline-block;
  background: var(--accent, #c9a96e);
  color: #0b0b0b !important;
  text-decoration: none;
  padding: 0.5rem 0.875rem;
  border-radius: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 600;
  transition: filter 0.15s ease;
}
.bk-card-cta:hover,
.bk-card-cta:focus {
  filter: brightness(1.08);
  text-decoration: none;
}

/*
  IN-CHAT AVAILABILITY CHIPS — Tap-to-pick open start times rendered
  inline after lookup_service_availability runs. Mirrors the booking
  modal's date-picker chips so the visitor doesn't have to type a time
  back into chat. Times are grouped by date (one row per day).
*/
.chat-msg-availability {
  max-width: 95%;
  background: transparent;
  padding: 0;
  border-radius: 0;
}
.chat-msg-availability .av-card {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-left: 3px solid var(--accent, #c9a96e);
  border-radius: 0.875rem;
  padding: 0.75rem 0.875rem 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.av-card-hint {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.55);
}
.av-day {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.av-day-label {
  font-size: 0.78125rem;
  font-weight: 600;
  color: #fff;
}
.av-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.av-chip {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.04);
  color: rgba(255, 255, 255, 0.92);
  padding: 0.35rem 0.7rem;
  border-radius: 999px;
  font-size: 0.78125rem;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease,
              color 0.15s ease, transform 0.05s ease;
}
.av-chip:hover,
.av-chip:focus-visible {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.45);
  outline: none;
}
.av-chip:active {
  transform: translateY(1px);
}
.av-chip:disabled {
  cursor: default;
  opacity: 0.45;
}
.av-chip.av-chip-picked {
  background: var(--accent, #c9a96e);
  border-color: var(--accent, #c9a96e);
  color: #0b0b0b;
  opacity: 1;
}

/* Calendar + time-slots booking picker (task 078) — a month grid on one side, that day's open times
   on the other. Used by the booking modal and inline in the chat. Wraps to a single column when the
   host is narrow (the chat pill / a phone). Theme-aware via the site accent + translucent surfaces. */
.svc-cal {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-start;
}
.svc-cal-grid-pane { flex: 1 1 240px; min-width: 220px; }
.svc-cal-slots-pane { flex: 1 1 160px; min-width: 150px; }
.svc-cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.svc-cal-month { font-weight: 600; font-size: 0.95rem; }
.svc-cal-nav {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.04);
  color: inherit;
  width: 30px; height: 30px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
}
.svc-cal-nav:hover { background: rgba(255, 255, 255, 0.12); }
.svc-cal-dow, .svc-cal-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
}
.svc-cal-dow { margin-bottom: 4px; }
.svc-cal-dow span {
  text-align: center;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.55;
}
.svc-cal-day {
  appearance: none;
  border: 1px solid transparent;
  background: rgba(255, 255, 255, 0.05);
  color: inherit;
  aspect-ratio: 1 / 1;
  border-radius: 8px;
  font-size: 0.82rem;
  font-family: inherit;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.svc-cal-day:hover { background: rgba(255, 255, 255, 0.14); }
.svc-cal-day.is-off {
  background: transparent;
  opacity: 0.28;
  cursor: default;
  border: none;
}
.svc-cal-day.is-blank { background: transparent; border: none; }
.svc-cal-day.is-sel {
  background: var(--accent, #c9a96e);
  border-color: var(--accent, #c9a96e);
  color: #0b0b0b;
  font-weight: 700;
}
.svc-cal-loading { grid-column: 1 / -1; text-align: center; opacity: 0.6; padding: 1.5rem 0; font-size: 0.85rem; }
.svc-cal-slots-title { font-weight: 600; font-size: 0.85rem; margin-bottom: 8px; opacity: 0.85; }
.svc-cal-slots { display: flex; flex-direction: column; gap: 6px; max-height: 240px; overflow-y: auto; }
.svc-cal-slot {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.04);
  color: inherit;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  font-size: 0.85rem;
  font-family: inherit;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.svc-cal-slot:hover { background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.4); }
.svc-cal-slot.is-sel {
  background: var(--accent, #c9a96e);
  border-color: var(--accent, #c9a96e);
  color: #0b0b0b;
  font-weight: 600;
}
.svc-cal-left { font-size: 0.7rem; opacity: 0.7; white-space: nowrap; }
.svc-cal-slot.is-sel .svc-cal-left { opacity: 0.85; }
.svc-cal-empty { opacity: 0.6; font-size: 0.82rem; margin: 0.5rem 0; }

/* Human-handoff option chips (task 045 multi-mode) — the ways to reach a person, rendered as
   tappable cards. Mirrors the availability picker theming; each chip stacks a bold label over a
   short hint so the choice is self-explanatory, with a 44px tap target for HCI. */
.chat-msg-handoff .hoff-card {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-left: 3px solid var(--accent, #c9a96e);
  border-radius: 0.8rem;
  padding: 0.55rem 0.7rem 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.hoff-card-hint {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.55);
}
.hoff-chips {
  display: flex;
  flex-direction: column;
  gap: 0.32rem;
}
.hoff-chip {
  appearance: none;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.04);
  color: rgba(255, 255, 255, 0.92);
  padding: 0.45rem 0.7rem;
  border-radius: 0.6rem;
  font-family: inherit;
  cursor: pointer;
  min-height: 40px;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
.hoff-chip:hover,
.hoff-chip:focus-visible {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.45);
  outline: none;
}
.hoff-chip:active { transform: translateY(1px); }
/* Clearly-unavailable disabled state (HCI: not just faded) + a11y. */
.hoff-chip:disabled { cursor: not-allowed; opacity: 1; background: rgba(255, 255, 255, 0.02); border-color: rgba(255, 255, 255, 0.10); }
.hoff-chip:disabled .hoff-chip-label { color: rgba(255, 255, 255, 0.38); }
.hoff-chip:disabled .hoff-chip-hint { color: rgba(255, 255, 255, 0.3); }
.hoff-chip-label { font-size: 0.82rem; font-weight: 600; color: #fff; }
.hoff-chip-hint { font-size: 0.71rem; color: rgba(255, 255, 255, 0.6); line-height: 1.2; }
.hoff-chip.hoff-chip-picked {
  background: var(--accent, #c9a96e);
  border-color: var(--accent, #c9a96e);
}
.hoff-chip.hoff-chip-picked .hoff-chip-label,
.hoff-chip.hoff-chip-picked .hoff-chip-hint { color: #0b0b0b; }

/* Handoff capture form (task 047) — name/email before connecting to any mode. */
/* The ad-hoc intake form (.intake-form) reuses the handoff capture-form styling. */
/* Compact in-chat sizing: short fields + tight gaps so the embedded card stays small in the widget. */
/* Responsive 2-up grid: fields flow TWO PER ROW when the card is wide enough (it usually is in the
   panel) and collapse to one column when narrow — no full-width 2:1 stacking on wide screens. */
.hoff-form, .intake-form { display: flex; flex-flow: row wrap; gap: 0.32rem 0.5rem; align-items: start; }
/* Title, error line and the action row always span the full width. */
.hoff-form > .hoff-form-title, .intake-form > .hoff-form-title,
.hoff-form > .hoff-form-err, .intake-form > .hoff-form-err,
.hoff-form > .hoff-form-actions, .intake-form > .hoff-form-actions { flex: 0 0 100%; }
/* Each field takes ~half the row (min ~12rem) → two fit side by side when there's room, one when not. */
.hoff-form > .hoff-field, .intake-form > .hoff-field { flex: 1 1 12rem; min-width: 0; }
/* A multi-line field (textarea) always spans the full width. */
.hoff-field:has(textarea) { flex-basis: 100%; }
.hoff-form-title { font-size: 0.82rem; color: #fff; font-weight: 600; line-height: 1.3; margin-bottom: 0.05rem; }
.hoff-field { display: flex; flex-direction: column; gap: 0.12rem; font-size: 0.7rem; color: rgba(255, 255, 255, 0.7); }
.hoff-field input, .hoff-field textarea, .hoff-field select.hoff-select {
  appearance: none; width: 100%; box-sizing: border-box;
  background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.25);
  color: #fff; font-family: inherit; font-size: 0.82rem;
  padding: 0.34rem 0.55rem; border-radius: 0.45rem; min-height: 34px;
}
.hoff-field select.hoff-select option { color: #111; }   /* native list renders on white */
.hoff-field select.hoff-select:focus-visible { outline: none; border-color: var(--accent, #c9a96e); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #c9a96e) 35%, transparent); }
.hoff-field textarea { min-height: 2.3rem; resize: vertical; }
.hoff-field input::placeholder, .hoff-field textarea::placeholder { color: rgba(255, 255, 255, 0.4); }
.hoff-field input:focus-visible, .hoff-field textarea:focus-visible { outline: none; border-color: var(--accent, #c9a96e); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #c9a96e) 35%, transparent); }
.hoff-field input[aria-invalid="true"], .hoff-field textarea[aria-invalid="true"] { border-color: #ef4444; }
.hoff-form-err { color: #fca5a5; font-size: 0.72rem; }
/* Actions sit on their own full-width row; buttons size to their CONTENT (no stretched Send). */
.hoff-form-actions { display: flex; gap: 0.5rem; margin-top: 0.25rem; justify-content: flex-start; align-items: center; }
.hoff-form-submit {
  appearance: none; flex: 0 0 auto; min-height: 36px; padding: 0 1.3rem;
  background: var(--accent, #c9a96e); border: 1px solid var(--accent, #c9a96e); color: #0b0b0b;
  font-family: inherit; font-weight: 700; font-size: 0.82rem; border-radius: 0.5rem; cursor: pointer;
}
.hoff-form-submit:hover { filter: brightness(1.06); }
.hoff-form-submit:disabled { opacity: 0.6; cursor: default; }
/* Both cancel buttons (handoff form .hoff-form-cancel + ad-hoc intake form .intake-form-cancel) share
   the same outline-button look, so Send + Cancel read as a balanced pair, not a big button + bare text. */
.hoff-form-cancel, .intake-form-cancel {
  appearance: none; flex: 0 0 auto; min-height: 36px; padding: 0 1.1rem;
  background: transparent; border: 1px solid rgba(255, 255, 255, 0.28); color: rgba(255, 255, 255, 0.85);
  font-family: inherit; font-weight: 600; font-size: 0.8rem; border-radius: 0.5rem; cursor: pointer;
}
.hoff-form-cancel:hover, .intake-form-cancel:hover { background: rgba(255, 255, 255, 0.08); }

/* Breathing room between an embedded in-pill card (intake form, handoff chips, next-step chips) and
   the chat components right below it (the quick-prompt suggestions / input bar) so they don't crowd. */
.panel-latest-handoff { margin-bottom: 0.85rem; }
.chat-msg-intake { margin-bottom: 0.4rem; }

/* FS-FIX4 / FS-A1 — the split-thread "writing…" placeholder shown while the full answer renders on the
   canvas. Shows a ROTATING status line + a subtle pulse so the wait is explained, not three frozen dots. */
.chat-msg-fs-writing { display: flex; align-items: center; gap: 0.5rem; }
.chat-msg-fs-writing .fs-writing-status { font-size: 0.86rem; color: rgba(255, 255, 255, 0.82); transition: opacity 0.25s ease; }
.chat-msg-fs-writing .fs-writing-dots { letter-spacing: 1px; animation: fsWritingPulse 1.2s ease-in-out infinite; }
@keyframes fsWritingPulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 0.85; } }

/* BR-3 — form branding. Give the intake card the same accent edge the handoff card has, and a centered
   logo header. The accent reads var(--accent) (now set per-tenant by _applyFormAccent). */
.chat-msg-intake .hoff-card, .intake-form-wrap { border-left: 3px solid var(--accent, #c9a96e); }
.intake-form-header { flex: 0 0 100%; display: flex; justify-content: center; margin-bottom: 0.3rem; }
.intake-form-logo { max-height: 34px; max-width: 60%; object-fit: contain; }
/* The per-form background layer (form_inline) sits behind the card content; keep card padding usable. */
.intake-form-wrap.has-chat-bg { overflow: hidden; }

/* Phone field: a country-code dropdown + number box sit on one row; combined into E.164 on submit. */
.hoff-tel { display: flex; gap: 0.35rem; align-items: stretch; }
.hoff-tel .hoff-cc {
  appearance: none; flex: 0 0 auto; max-width: 7.5rem; min-height: 34px;
  background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.25);
  color: #fff; font-family: inherit; font-size: 0.8rem; padding: 0.2rem 0.4rem; border-radius: 0.45rem;
}
.hoff-tel .hoff-cc option { color: #111; }   /* native dropdown list renders on white in most browsers */
/* min-width:0 lets the number box shrink so the country-code + number row never overflows the
   narrow chat bubble on a phone (a flex item's default min-width:auto would refuse to shrink). */
.hoff-tel input { flex: 1 1 auto; min-width: 0; }
.hoff-tel .hoff-cc:focus-visible { outline: none; border-color: var(--accent, #c9a96e); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #c9a96e) 35%, transparent); }

/* Touch phones (and narrow viewports) get a comfortable 40px tap target on the in-chat form
   controls; the desktop panel keeps its compact 34/36px. The coarse-pointer query covers real
   phones at any width; the max-width:480px query covers narrow viewports (and makes the rule
   testable in a desktop emulator). Either way desktop at normal width is untouched.
   .hoff-* + .intake-form-cancel are SHARED by the intake form AND the handoff form, so this one
   block raises tap targets on both surfaces at once. */
@media (max-width: 480px), (hover: none) and (pointer: coarse) {
  .hoff-field input, .hoff-field textarea, .hoff-field select.hoff-select { min-height: 40px; }
  .hoff-tel .hoff-cc { min-height: 40px; }
  .hoff-form-submit, .hoff-form-cancel, .intake-form-cancel { min-height: 40px; }
}

/* Proactive next-step chips (PN) — a tappable row under the concierge's answer that keeps the visitor
   moving. Horizontal-wrapping pills, compact, themed with the accent on hover. */
/* The next-step card carries .chat-msg .chat-msg-agent, which would pin it to max-width:85% and
   align-self:flex-start — leaving the "centered" chip row visibly off-center (left-shifted) in the
   chat log. Override both so the row can span the full column and the justify-content:center below
   actually reads as centered. Not mobile-scoped: the bug exists at every width. */
.chat-msg-nextsteps { background: transparent !important; padding: 0.5rem 0.25rem 0.35rem !important; box-shadow: none !important; max-width: 100% !important; align-self: stretch !important; }
.nextstep-row { display: flex; flex-wrap: wrap; gap: 0.45rem; justify-content: center; position: relative; z-index: 3; }
.nextstep-chip {
  appearance: none; cursor: pointer; font-family: inherit;
  font-size: 0.8rem; font-weight: 600; line-height: 1.15;
  color: var(--accent, #c9a96e);
  background: color-mix(in srgb, var(--accent, #c9a96e) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent, #c9a96e) 45%, transparent);
  padding: 0.4rem 0.7rem; border-radius: 999px; min-height: 34px;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.05s ease, color 0.15s ease;
}
.nextstep-chip:hover, .nextstep-chip:focus-visible {
  outline: none; background: var(--accent, #c9a96e); color: #0b0b0b;
  border-color: var(--accent, #c9a96e);
}
.nextstep-chip:active { transform: translateY(1px); }
.nextstep-chip:disabled { cursor: default; opacity: 0.45; }
.nextstep-chip.nextstep-chip-picked { background: var(--accent, #c9a96e); color: #0b0b0b; opacity: 1; }

/* "Stop waiting" escape button (task 047 HCI) — the one-tap out while waiting for a teammate to
   join an in-chat handoff, so the visitor is never trapped polling in silence. */
.hoff-stopwait { padding: 0.15rem; }
.hoff-stopwait-btn {
  appearance: none; width: 100%; min-height: 44px; padding: 0 0.9rem;   /* 44px tap target */
  background: rgba(255, 255, 255, 0.06); border: 1px dashed rgba(255, 255, 255, 0.32);
  color: rgba(255, 255, 255, 0.92); font-family: inherit; font-weight: 600; font-size: 0.82rem;
  border-radius: 0.55rem; cursor: pointer; transition: background 0.15s ease, border-color 0.15s ease;
}
.hoff-stopwait-btn:hover { background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.5); }
.hoff-stopwait-btn:focus-visible { outline: 2px solid var(--accent, #c9a96e); outline-offset: 2px; }

/* Live warm-transfer call bar (task 045 Phase 2) — a floating in-chat call control with
   status + mute/hold/hangup. Fixed bottom-center so it stays visible regardless of the chat
   panel state. Themed; the status dot pulses while connecting and goes solid when connected. */
.live-call-bar {
  position: fixed;
  left: 50%;
  bottom: 1.1rem;
  transform: translateX(-50%);
  z-index: 100000;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.6rem 0.9rem;
  background: rgba(15, 15, 18, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 0.85rem;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(8px);
  max-width: calc(100vw - 1.6rem);
}
.live-call-bar .lcb-row { display: flex; align-items: center; gap: 0.5rem; }
.live-call-bar .lcb-status { color: #fff; font-size: 0.85rem; font-weight: 500; white-space: nowrap; }
.live-call-bar .lcb-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent, #c9a96e);
  animation: lcbPulse 1.2s ease-in-out infinite;
}
.live-call-bar[data-state="connected"] .lcb-dot { background: #22c55e; animation: none; }
.live-call-bar[data-state="held"] .lcb-dot { background: #f59e0b; animation: none; }
.live-call-bar[data-state="error"] .lcb-dot,
.live-call-bar[data-state="ended"] .lcb-dot { background: #ef4444; animation: none; }
@keyframes lcbPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
.live-call-bar .lcb-controls { display: flex; align-items: center; gap: 0.4rem; }
.live-call-bar .lcb-btn {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.4);
  background: rgba(255, 255, 255, 0.20);   /* HCI: was 0.06 (~1.2:1) → ~4.6:1 so white text is legible */
  color: #fff;
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  padding: 0.45rem 0.75rem;
  border-radius: 0.55rem;
  cursor: pointer;
  min-height: 44px;   /* 44x44 tap target for mobile accessibility */
  min-width: 44px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.live-call-bar .lcb-btn:hover { background: rgba(255, 255, 255, 0.28); border-color: rgba(255, 255, 255, 0.55); }
.live-call-bar .lcb-btn.lcb-on { background: var(--accent, #c9a96e); border-color: var(--accent, #c9a96e); color: #0b0b0b; }
.live-call-bar .lcb-btn-end { background: #dc2626; border-color: #dc2626; }
.live-call-bar .lcb-btn-end:hover { background: #b91c1c; border-color: #b91c1c; }
@media (max-width: 480px) {
  .live-call-bar { flex-direction: column; gap: 0.5rem; left: 0.8rem; right: 0.8rem; transform: none; max-width: none; }
  .live-call-bar .lcb-controls { width: 100%; justify-content: center; }
  /* Next-step chips are one-tap conversion affordances — give them the full 44px touch target on
     phones (desktop keeps the compact 34px pill). The row already flex-wraps, so taller chips wrap fine. */
  .nextstep-chip { min-height: 44px; padding: 0.6rem 0.8rem; }
  /* During an active call the fixed bar sits at the bottom; reserve room beneath the chat input so it
     isn't covered (only when a call is active — see body.live-call-active toggled in script.js). */
  body.live-call-active .chatbot-input-bar { padding-bottom: calc(5.5rem + 1.1rem); }
  /* The stacked (column) call bar is taller on small phones — lift the collapsed pill further. */
  body.live-call-active .chatbot-container:not(.expanded) { bottom: calc(0.5rem + 6rem); }
}

/* Availability picker surfaced in the COLLAPSED preview ("pill") views — sits under the latest-
   message text. Give it breathing room and cap its height so a many-day result scrolls instead of
   pushing the input off-screen. Reuses the .av-card / .av-chip styling above. */
.panel-latest-availability {
  margin-top: 0.6rem;
  max-height: 9.5rem;
  overflow-y: auto;
}

/*
  TYPING INDICATOR — Three animated dots shown while waiting for a response.
  Uses a bouncing animation with staggered delays.
*/
.chat-typing {
  align-self: flex-start;
  display: flex;
  gap: 0.25rem;
  padding: 0.75rem 1rem;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 1rem;
  border-bottom-left-radius: 0.25rem;
}

.chat-typing-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.4);
  animation: typingBounce 1.2s ease-in-out infinite;
}

.chat-typing-dot:nth-child(2) { animation-delay: 0.2s; }
.chat-typing-dot:nth-child(3) { animation-delay: 0.4s; }

@keyframes typingBounce {
  0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
  40% { transform: translateY(-4px); opacity: 1; }
}

/*
  BAR THINKING INDICATOR — Sleek inline dots above the chat bar.
  Shown while the AI is processing when the panel is collapsed.
*/
.bar-thinking {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  padding: 0.4rem 1rem;
  margin-bottom: 0.35rem;
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-radius: 1.25rem;
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
  animation: barThinkFadeIn 0.25s ease;
}

.bar-thinking-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent, #c9a96e);
  animation: typingBounce 1.2s ease-in-out infinite;
}

.bar-thinking-dot:nth-child(2) { animation-delay: 0.2s; }
.bar-thinking-dot:nth-child(3) { animation-delay: 0.4s; }

@keyframes barThinkFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

/*
  QUICK PROMPT CHIPS — Clickable suggestion pills.
  Shown above the input bar to help users start a conversation.
*/
.chatbot-quick-prompts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  padding: 0 1rem 0.5rem;
  flex-shrink: 0;
}

/* Once the conversation has started, retire the empty-state starter prompts so each answer shows only
   ONE chip row (the per-answer next-steps) instead of two overlapping rows with duplicate labels.
   Set as a body class on first send (see chatSendMessage) so it survives the panel re-render. */
body.chat-convo-started .chatbot-quick-prompts { display: none !important; }

/* M12 / M13 — when the chat side panel overlays the gallery, hide the gallery nav controls it sits on
   top of, so the visitor isn't poking at dead controls hidden behind the panel: the top-right CTA +
   dot navigation on desktop, and the bottom-center slide counter / down-arrow on mobile. */
body.side-panel-active .gallery-top-right,
body.side-panel-active .dot-nav { display: none; }
@media (max-width: 768px) {
  body.side-panel-active .gallery-nav-down { display: none; }
}

/* H6 — persistent "AI" badge on the concierge avatar (the name/role can be human-branded, so this is
   the always-visible transparency cue). A small accent corner chip on the avatar circle. */
#chatbot-avatar { position: relative; }
.chatbot-ai-badge {
  position: absolute;
  bottom: -3px;
  right: -4px;
  font-size: 0.5rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
  padding: 0.12rem 0.22rem;
  border-radius: 0.35rem;
  background: var(--chat-accent, var(--color-accent, #c9a96e));
  color: var(--on-accent, #0b0b0b);
  border: 1px solid rgba(0, 0, 0, 0.25);
  pointer-events: none;
}

.chatbot-quick-prompt {
  padding: 0.375rem 0.8rem;
  /* M11 — was 0.6875rem / 60% white: it barely read as a tappable button. Bring it up to the
     baseline chip size + contrast so the starter prompts look clickable. */
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.82);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 9999px;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
  white-space: nowrap;
  font-family: inherit;
}

.chatbot-quick-prompt:hover {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
}

/* Input bar at the bottom of the expanded panel */
.chatbot-input-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
}

.chatbot-panel-input {
  flex: 1;
  padding: 0.5rem 0.875rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 9999px;
  color: var(--chatbot-text, #fff);
  font-size: 0.8125rem;
  font-family: inherit;
  outline: none;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.chatbot-panel-input::placeholder {
  color: color-mix(in srgb, var(--chatbot-text, #fff) 55%, transparent);
}

.chatbot-panel-input:focus {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.2);
}

/* Send button in the expanded panel */
.chatbot-send-panel-btn {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--on-accent, #0b0b0b);
  /* M9 — inherit the shared accent background (rule above) instead of a hardcoded blue, so the Send
     button is the SAME brand color on the pill, the panel, and the side rail. */
  border: none;
  cursor: pointer;
  flex-shrink: 0;
  transition: background var(--transition-fast);
}

.chatbot-send-panel-btn:hover {
  background: rgba(59, 130, 246, 0.8);
}


/* =============================================================================
   19. SPLIT-SCREEN OVERLAY — AI-Controlled Visual Display
   =============================================================================
   When the AI sends a visual command, this overlay takes over the screen.

   LAYOUT:
   - Desktop: Side-by-side (40% chat / 60% content)
   - Mobile: Stacked (content overlays the chat)

   THREE CONTENT TYPES:
   1. Navigate: Shows a gallery slide (image + text overlay)
   2. Show Slide: Structured presentation (title, points, etc.)
   3. Generate HTML: AI-created content on a blank canvas

   TO MODIFY THE SPLIT RATIO:
   - Change the flex values in .split-chat (2 = 40%) and .split-content (3 = 60%)

   TO CHANGE THE TRANSITION:
   - Modify the opacity/transform transition in .split-overlay
============================================================================= */

.split-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  background: rgba(0, 0, 0, 0.95);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-medium) ease;
}

/* Active state — overlay becomes visible */
.split-overlay.active {
  opacity: 1;
  pointer-events: auto;
}

/* Left side — Chat panel in split mode */
.split-chat {
  flex: 2;
  display: flex;
  flex-direction: column;
  background: rgba(15, 17, 23, 0.95);
  border-right: 1px solid rgba(255, 255, 255, 0.08);
  min-width: 0;
}
/* BR-2 — when a fullscreen background is configured, let it show through the chat panel's own fill. */
.split-chat.has-chat-bg { background: rgba(15, 17, 23, 0.62); }

/* Right side — Content display area */
.split-content {
  flex: 3;
  position: relative;
  overflow: hidden;
  min-width: 0;
}

/* Each content panel fills the entire right side */
.split-content-panel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* ── ENLARGE TOGGLE — chat full-screen vs. split ─────────────────────────────
   The "enlarge" control hides the content pane and lets the conversation take the
   whole screen; toggling again restores the split. */
.split-overlay.chat-enlarged .split-content { display: none; }
.split-overlay.chat-enlarged .split-chat {
  flex: 1 1 100%;
  max-width: 100%;
  border-right: none;
}
/* The enlarge button shows an "expand" glyph in split mode and a "restore" glyph
   once the chat is enlarged. */
.split-chat-actions { display: flex; align-items: center; gap: 0.25rem; }
.split-enlarge-btn .icon-restore { display: none; }
.split-overlay.chat-enlarged .split-enlarge-btn .icon-enlarge { display: none; }
.split-overlay.chat-enlarged .split-enlarge-btn .icon-restore { display: inline; }

/* ── OVERLAP FIX — hide the floating concierge bar while the split view is open ──
   The bar (z-70) otherwise renders ON TOP of the split overlay (z-60), showing a
   second chat input. The split has its own #split-chat-input, so the bar isn't
   needed; this also covers the page-archive bubble + greeter for a clean surface. */
body.split-active .chatbot-container,
body.split-active .page-archive-bubble,
body.split-active .video-greeter-bubble,
body.split-active #side-chat-panel { display: none !important; }

/* Floating back button on the content side of split-screen */
.split-back-btn {
  position: absolute;
  top: 1.25rem;
  left: 1.25rem;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.5rem 1rem 0.5rem 0.75rem;
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 2rem;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.8125rem;
  font-family: var(--font-sans);
  cursor: pointer;
  transition: all 0.2s ease;
}

.split-back-btn:hover {
  background: rgba(255, 255, 255, 0.14);
  color: var(--color-accent, #c9a96e);
}

/* Floating back button on the fullscreen canvas */
.canvas-close-btn {
  position: absolute;
  /* Keep the pill clear of the notch / status bar on notched phones (viewport-fit=cover is set).
     env() degrades to 0 off-notch and on desktop, so this preserves the exact current 20px there.
     .canvas-close-btn is shared with the immersive-page close button, so both get the inset. */
  top: calc(1.25rem + env(safe-area-inset-top, 0px));
  left: 1.25rem;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.5rem 1rem 0.5rem 0.75rem;
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 2rem;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.8125rem;
  font-family: var(--font-sans);
  cursor: pointer;
  transition: all 0.2s ease;
}

.canvas-close-btn:hover {
  background: rgba(255, 255, 255, 0.14);
  color: var(--color-accent, #c9a96e);
}

/* Small "Esc" hint pill inside the canvas Back button — tells visitors they
   can also press Escape to leave the full-screen canvas. */
.canvas-close-kbd {
  margin-left: 0.35rem;
  padding: 0.05rem 0.4rem;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 0.4rem;
  font-size: 0.65rem;
  line-height: 1.3;
  opacity: 0.7;
}

/*
  NAVIGATE MODE — Gallery slide in split-screen.
  Shows the card's background image with overlay text.
*/
.split-nav-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  animation: kenBurns var(--ken-burns-duration) ease-in-out infinite alternate;
}

.split-nav-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgba(0, 0, 0, 0.7) 0%,
    rgba(0, 0, 0, 0.3) 50%,
    transparent 100%
  );
}

.split-nav-content {
  position: absolute;
  bottom: 3rem;
  left: 2rem;
  right: 2rem;
  z-index: 5;
  color: #fff;
}

.split-nav-title {
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  font-weight: 700;
  margin: 0.5rem 0;
  line-height: 1.1;
}

.split-nav-subtitle {
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.8);
  font-weight: 300;
  margin-bottom: 0.75rem;
  border-left: 2px solid rgba(255, 255, 255, 0.4);
  padding-left: 0.75rem;
}

.split-nav-description {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.7);
  line-height: 1.6;
  max-width: 32rem;
}

/*
  SHOW SLIDE MODE — Structured presentation in split-screen.
  Elegant card with eyebrow text, title, subtitle, and bullet points.
*/
.split-slide-inner {
  padding: 3rem 4rem 3rem 3rem;
  height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: linear-gradient(135deg, rgba(10, 15, 26, 0.98), rgba(15, 20, 35, 0.95));
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}

.split-slide-eyebrow {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--color-accent, #c9a96e);
  font-weight: 700;
  margin-bottom: 1rem;
}

.split-slide-title {
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-family: var(--font-serif, 'Playfair Display', serif);
  font-weight: 700;
  color: #fff;
  margin-bottom: 0.5rem;
  line-height: 1.2;
}

.split-slide-subtitle {
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: 1.5rem;
}

.split-slide-points {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.split-slide-point {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.8);
  line-height: 1.5;
}

.split-slide-point-marker {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent, #c9a96e);
  flex-shrink: 0;
  margin-top: 0.4rem;
}

/*
  GENERATE HTML MODE — AI-created content canvas.
  A clean surface where the AI can render any HTML.
  Dark background matches the site theme.
*/
.split-canvas {
  background: #0a0f1a;
}

/* The split content renders in a sandboxed iframe (full-bleed, no border). */
.split-canvas-frame {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: #0a0f1a;
}

/* FS-A3 — the admin-configured empty-state filler (image / video / webpage). Full-bleed, behind a scrim. */
.split-filler { position: relative; overflow: hidden; background: #0a0f1a; }
.split-filler-img { position: absolute; inset: 0; background-size: cover; background-position: center; }
.split-filler-media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.split-filler-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.split-filler-scrim { position: absolute; inset: 0; pointer-events: none; }

.split-canvas-content {
  width: 100%;
  height: 100%;
  overflow-y: auto;
  padding: 1.75rem 0 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}

.split-canvas-content::-webkit-scrollbar {
  width: 4px;
}

.split-canvas-content::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 2px;
}

/*
  VISUAL TEMPLATE — Pre-built frosted glass card for AI-generated visual slides.
  The AI sends structured data (title, columns, rows) and the frontend renders
  it using this template — consistent, fast, always matches the site.
*/
.visual-card {
  background: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(40px) saturate(1.4);
  -webkit-backdrop-filter: blur(40px) saturate(1.4);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 1.5rem;
  padding: 2.5rem 3rem;
  max-width: 640px;
  width: 100%;
  color: #fff;
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.visual-title {
  font-family: var(--font-serif);
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 600;
  margin: 0 0 0.25rem;
  letter-spacing: -0.01em;
}

.visual-subtitle {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.55);
  margin: 0 0 1.75rem;
  font-weight: 400;
}

.visual-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 1.25rem;
}

.visual-th {
  text-align: left;
  font-family: var(--font-sans);
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.55);
  padding: 0 1rem 0.75rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.visual-tr {
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

.visual-tr:last-child {
  border-bottom: none;
}

.visual-td {
  font-family: var(--font-sans);
  font-size: 0.925rem;
  padding: 0.9rem 1rem 0.9rem 0;
  color: rgba(255, 255, 255, 0.75);
}

.visual-td-label {
  color: #fff;
  font-weight: 500;
}

.visual-list {
  margin-top: 1.25rem;
  display: flex;
  flex-direction: column;
}

.visual-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.9rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

.visual-item:last-child {
  border-bottom: none;
}

.visual-item-label {
  font-family: var(--font-sans);
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.55);
}

.visual-item-value {
  font-family: var(--font-sans);
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--color-accent, #c9a96e);
}

.visual-footer {
  font-family: 'DM Sans', sans-serif;
  font-size: 0.8rem;
  color: rgba(255, 255, 255, 0.35);
  margin-top: 1.5rem;
  font-style: italic;
}

@media (max-width: 768px) {
  .visual-card {
    padding: 1.5rem 1.25rem;
    border-radius: 1rem;
  }
}

/*
  FULLSCREEN CANVAS — Displays AI-generated visual behind the side panel.
  Matches the gallery layout: content fills the screen, side panel overlays on the right.
*/
.fullscreen-canvas {
  position: fixed;
  inset: 0;
  /* Sit ABOVE the site hero-nav (z-index:60) so the page header doesn't bleed through the top of a
     full-screen answer, but BELOW the chat widget (.chatbot-container z-index:70) so the composer
     stays usable on top of the canvas. Was 50 (under the nav) — a full takeover should cover it. */
  z-index: 65;
  background: #0c1220;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1);
  overflow: hidden;
}

.fullscreen-canvas::before {
  content: '';
  position: absolute;
  width: 600px;
  height: 600px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(99, 102, 241, 0.15) 0%, transparent 70%);
  top: -10%;
  left: -5%;
  pointer-events: none;
}

.fullscreen-canvas::after {
  content: '';
  position: absolute;
  width: 500px;
  height: 500px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(201, 169, 110, 0.12) 0%, transparent 70%);
  bottom: -10%;
  right: 10%;
  pointer-events: none;
}

.fullscreen-canvas.active {
  opacity: 1;
  pointer-events: auto;
}


/* =============================================================================
   IMMERSIVE PAGE OVERLAY — AI-generated animated full pages (generatePage)
   =============================================================================
   Renders inside a sandboxed iframe for full CSS freedom: animations,
   @keyframes, background-image, parallax, scroll effects. The site's theme
   is automatically injected so everything matches the design.
============================================================================= */

.immersive-page-overlay {
  position: fixed;
  inset: 0;
  /* Same fix as .fullscreen-canvas: above the hero-nav (60), below the chat widget (70), so a
     full-screen generated page covers the site header instead of letting it bleed through. */
  z-index: 65;
  background: #0c1220;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.85s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.85s cubic-bezier(0.22, 1, 0.36, 1);
  transform-origin: 0% 100%;
  overflow: hidden;
  will-change: transform, opacity;
}

.immersive-page-overlay.active {
  opacity: 1;
  pointer-events: auto;
}

/* Collapse animation: when the visitor hits Back, the overlay shrinks
   toward the bottom-left page-archive bubble before clearing.
   Slowed down so the motion reads as intentional, not as a glitch. */
.immersive-page-overlay.collapsing {
  pointer-events: none;
  opacity: 0;
  transform: scale(0.04) translate(-40vw, 45vh);
}

.immersive-page-frame {
  width: 100%;
  height: 100%;
  border: none;
  background: transparent;
  padding-right: 380px;
  transition: padding 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

@media (max-width: 768px) {
  .immersive-page-frame {
    padding-right: 0;
  }
  /* On phones the side chat panel sits along the bottom of the viewport
     (~40% tall when open, ~4rem when minimized). Shrink the iframe's
     visible height to match so the AI-generated page content doesn't
     end up rendered behind the panel and look like nothing came
     through. We use body.side-panel-active / body.side-panel-minimized
     (mirrored from JS) instead of :has() so this works in every
     browser, not just the ones that support :has(). */
  body.side-panel-active .immersive-page-frame {
    height: calc(100% - 40vh);
  }
  body.side-panel-active.side-panel-minimized .immersive-page-frame {
    height: calc(100% - 4rem - env(safe-area-inset-bottom, 0px));
  }
}

/* =============================================================================
   PAGE ARCHIVE BUBBLE — bottom-left button + popover listing pages built
   earlier in this browser session. Click to revisit any of them.
============================================================================= */

.page-archive-bubble {
  position: fixed;
  left: 1.25rem;
  bottom: 1.25rem;
  z-index: 60;
  font-family: var(--font-sans, system-ui, sans-serif);
}

/* On phones / small tablets the chatbot bar sits centered along the bottom
   and can visually crowd the bubble. Lift the bubble higher so they don't
   collide. We extend this through the full mobile breakpoint (768px) so
   the bubble is consistently above the chat bar on every phone size. */
@media (max-width: 768px) {
  .page-archive-bubble {
    bottom: 5.5rem;
  }
  /* When the AI's side chat panel is shown (during navigate / generatePage),
     it expands to ~40% of the viewport height across the bottom edge.
     Push the page-archive bubble above it so the visitor can always
     tap it. Uses the JS-mirrored body classes for cross-browser support. */
  body.side-panel-active .page-archive-bubble {
    bottom: calc(40vh + 1rem);
  }
  /* Minimized side panel only shows its slim header bar (~3rem). */
  body.side-panel-active.side-panel-minimized .page-archive-bubble {
    bottom: calc(5rem + env(safe-area-inset-bottom, 0px));
  }
}

.page-archive-bubble[hidden] {
  display: none;
}

/* When a full-panel view is open (split chat / slide, immersive AI page, or the
   full-screen visual canvas — all flagged by body.side-panel-active), that panel
   has its OWN input and controls, so the floating chat bar, the saved-page archive
   bubble, and the video-greeter bubble are redundant and OVERLAP it. Hide all three
   while a panel is active so nothing covers the panel's own input. (When the panel is
   only minimized, the floating bar comes back so the visitor can still type.) */
body.side-panel-active:not(.side-panel-minimized) .chatbot-bar,
body.side-panel-active .page-archive-bubble,
body.side-panel-active .video-greeter-bubble {
  display: none !important;
}

/* The landing top nav (.hero-nav, z-index 60) sits ABOVE the full-screen visual / immersive
   panels (z-index 50), so in a panel view it rendered on top of the visual and its logo collided
   with the panel's own close/back button (the "Back" text peeking out from behind the logo).
   A panel view is its own focused surface with its own controls, so hide the landing nav while one
   is open. Closing the panel restores the nav. */
body.side-panel-active .hero-nav {
  display: none !important;
}

.page-archive-bubble-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(20, 26, 44, 0.78);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35),
              inset 0 1px 0 rgba(255, 255, 255, 0.08);
  transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}

.page-archive-bubble-btn:hover {
  transform: translateY(-2px);
  background: rgba(28, 36, 60, 0.88);
  box-shadow: 0 14px 36px rgba(0, 0, 0, 0.45),
              inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

.page-archive-bubble-btn:active {
  transform: translateY(0);
}

.page-archive-bubble-count {
  position: absolute;
  top: -0.25rem;
  right: -0.25rem;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--color-accent, #c8a85a);
  color: #0c1220;
  font-size: 0.7rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
}

/* Pulse the bubble briefly the moment a new page is archived so the
   visitor notices where the page they were just looking at went. */
@keyframes pageArchiveBubblePulse {
  0%   { box-shadow: 0 0 0 0 rgba(200, 168, 90, 0.55); }
  70%  { box-shadow: 0 0 0 14px rgba(200, 168, 90, 0); }
  100% { box-shadow: 0 0 0 0 rgba(200, 168, 90, 0); }
}

.page-archive-bubble.pulsing .page-archive-bubble-btn {
  animation: pageArchiveBubblePulse 0.9s ease-out;
}

.page-archive-popover {
  position: absolute;
  left: 0;
  bottom: 3.75rem;
  min-width: 16rem;
  max-width: 22rem;
  background: rgba(14, 18, 32, 0.94);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.75rem;
  padding: 0.5rem;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5);
  color: #fff;
  font-size: 0.875rem;
}

.page-archive-popover[hidden] {
  display: none;
}

.page-archive-popover-header {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.55);
  padding: 0.5rem 0.75rem;
}

.page-archive-popover-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 60vh;
  overflow-y: auto;
}

.page-archive-popover-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.6rem 0.75rem;
  background: transparent;
  border: none;
  border-radius: 0.5rem;
  color: rgba(255, 255, 255, 0.92);
  text-align: left;
  cursor: pointer;
  font: inherit;
  transition: background 0.15s ease;
}

.page-archive-popover-item:hover,
.page-archive-popover-item:focus-visible {
  background: rgba(255, 255, 255, 0.06);
  outline: none;
}

.page-archive-popover-item-title {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.page-archive-popover-item-time {
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.5);
  flex-shrink: 0;
}

.fullscreen-canvas-content {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 4rem 26rem 6rem 4rem;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
  transition: padding 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/*
  CANVAS MARKDOWN — Styles for rendered markdown inside the
  fullscreen canvas overlay (long AI responses, itineraries, etc.)
*/
.canvas-markdown h3 {
  font-family: var(--font-serif);
  font-size: 1.3rem;
  color: #fff;
  margin: 1.75rem 0 0.75rem 0;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.canvas-markdown h3:first-child { margin-top: 0; }
.canvas-markdown h4 {
  font-family: var(--font-serif);
  font-size: 1.1rem;
  color: #fff;
  margin: 1.5rem 0 0.5rem 0;
}
.canvas-markdown p {
  margin: 0 0 0.75rem 0;
  color: rgba(255, 255, 255, 0.85);
}
.canvas-markdown strong {
  color: var(--color-accent, #c9a96e);
  font-weight: 600;
}
.canvas-markdown em {
  font-style: italic;
  color: rgba(255, 255, 255, 0.7);
}
.canvas-markdown ul {
  margin: 0.5rem 0 1rem 0;
  padding-left: 0;
  list-style: none;
}
.canvas-markdown ol {
  margin: 0.5rem 0 1rem 0;
  padding-left: 1.5rem;
}
.canvas-markdown ul li {
  margin-bottom: 0.6rem;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.85);
  padding-left: 1.25rem;
  position: relative;
}
.canvas-markdown ul li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent, #c9a96e);
  opacity: 0.7;
}
.canvas-markdown ol li {
  margin-bottom: 0.6rem;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.85);
}
.canvas-markdown blockquote {
  border-left: 3px solid var(--color-accent, #c9a96e);
  padding: 0.75rem 1.25rem;
  margin: 1.25rem 0;
  color: rgba(255, 255, 255, 0.7);
  font-style: italic;
  background: rgba(255, 255, 255, 0.02);
  border-radius: 0 0.5rem 0.5rem 0;
}
.canvas-markdown hr {
  border: none;
  border-top: 1px solid color-mix(in srgb, var(--color-accent, #c9a96e) 25%, transparent);
  margin: 1.5rem 0;
}
.canvas-markdown table {
  width: 100%;
  border-collapse: collapse;
  margin: 1rem 0;
  font-size: 0.9rem;
}
.canvas-markdown th {
  text-align: left;
  padding: 0.75rem 1rem;
  font-weight: 600;
  color: var(--color-accent, #c9a96e);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.canvas-markdown td {
  padding: 0.65rem 1rem;
  color: rgba(255, 255, 255, 0.85);
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.canvas-markdown tr:nth-child(even) td {
  background: rgba(255, 255, 255, 0.02);
}
.canvas-markdown code {
  background: rgba(255, 255, 255, 0.08);
  padding: 0.15em 0.4em;
  border-radius: 0.25rem;
  font-size: 0.9rem;
  font-family: 'SF Mono', 'Fira Code', monospace;
}
.canvas-markdown pre {
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-md);
  padding: 1rem;
  margin: 1rem 0;
  overflow-x: auto;
}
.canvas-markdown pre code {
  background: none;
  padding: 0;
}

.fullscreen-canvas-content::-webkit-scrollbar {
  width: 4px;
}

.fullscreen-canvas-content::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 2px;
}


/* =============================================================================
   20a. NAVIGATE SIDE-PANEL MODE
   =============================================================================
   When the AI uses a "navigate" command, the gallery stays interactive
   and a chat panel slides in from the right instead of covering the screen.
============================================================================= */

.gallery-view {
  inset: 0;
  transition: right 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.gallery-view.side-panel-active {
  right: 0 !important;
}

.landing-container {
  transition: margin-right 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.landing-container.side-panel-active {
  margin-right: 0;
}

.side-chat-panel {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  width: 380px;
  z-index: 55;
  display: flex;
  flex-direction: column;
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 1rem;
  opacity: 0;
  transform: translateY(12px) scale(0.97);
  pointer-events: none;
  transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

.side-chat-panel.active {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

.side-chat-panel.history-open {
  max-height: 70vh;
}

/* Minimized state — collapses panel to just the header bar */
.side-chat-panel.minimized .side-panel-latest-text,
.side-chat-panel.minimized .side-panel-input-row,
.side-chat-panel.minimized .side-panel-history {
  display: none;
}

.side-panel-minimize-btn {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.55);
  background: none;
  border: none;
  cursor: pointer;
  transition: color 0.2s, background 0.2s;
}

.side-panel-minimize-btn:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

.chatbot-container.side-panel-hidden {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.side-panel-latest {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
}

.side-panel-latest-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
}

.side-panel-agent-badge {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.side-panel-agent-name {
  font-size: 0.8125rem;
  font-weight: 600;
  color: #fff;
}

.side-panel-actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.side-panel-history-btn,
.side-panel-close-btn {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.55);
  background: none;
  border: none;
  cursor: pointer;
  transition: color 0.2s, background 0.2s;
}

.side-panel-history-btn:hover,
.side-panel-close-btn:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

.side-panel-latest-text {
  padding: 0 1rem 0.75rem;
  font-size: 0.875rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.92);
  /* L4 — bump 300 -> 400: this text sits over the gallery slideshow, where thin light type loses
     contrast on bright frames. */
  font-weight: 400;
  max-height: 200px;
  overflow-y: auto;
  /* Keep wheel/touch scrolling inside the chat panel — don't let it chain
     through to the gallery card view sitting behind it. */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}

.side-panel-latest-text:empty::before {
  content: "Ask me anything...";
  color: rgba(255, 255, 255, 0.35);
  font-style: italic;
}

/* When the chat is EXPANDED, the latest answer must grow to fit the response instead of being
   crammed into the fixed 200px peek box — that fixed cap forced an inner scrollbar on top of the
   page scroll (the "double scroll") and clipped longer answers mid-sentence. Let it use the room
   the panel already has (the panel itself still caps at 70vh and scrolls as one if needed); the
   small 200px peek is kept only for the COLLAPSED launcher pill. */
.chatbot-container.expanded #panel-latest-text,
body.chat-conversation-mode #panel-latest-text,
body.chat-conversation-mode .side-panel-latest-text {
  max-height: min(46vh, 460px);
}

.side-panel-latest-text[data-thinking]:empty::before,
#panel-latest-text[data-thinking]:empty::before {
  content: "Thinking...";
  color: rgba(255, 255, 255, 0.45);
  font-style: italic;
  animation: pulse-thinking 1.2s ease-in-out infinite;
}

@keyframes pulse-thinking {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 0.9; }
}

.side-panel-input-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem 0.75rem;
}

.side-panel-input {
  flex: 1;
  padding: 0.5rem 0.875rem;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 9999px;
  color: #fff;
  font-size: 0.8125rem;
  font-family: inherit;
  outline: none;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background 0.2s, border-color 0.2s;
}

.side-panel-input::placeholder {
  color: rgba(255, 255, 255, 0.55);
}

.side-panel-input:focus {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.25);
}

.side-panel-send-btn {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--on-accent, #0b0b0b);
  /* M9 — inherit the shared accent background (rule above) instead of a hardcoded white fill. */
  border: none;
  cursor: pointer;
  transition: background 0.2s, opacity 0.2s;
  flex-shrink: 0;
}

.side-panel-send-btn:hover {
  background: rgba(255, 255, 255, 0.2);
}

.side-panel-history {
  flex-direction: column;
  flex: 1;
  min-height: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.4s cubic-bezier(0.22, 1, 0.36, 1),
              opacity 0.3s ease;
}

.side-panel-history.visible {
  display: flex;
  max-height: 600px;
  opacity: 1;
}

.side-panel-history-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.625rem 1rem;
  flex-shrink: 0;
}

.side-panel-history-title {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.55);
  font-weight: 600;
}

.side-panel-history .chatbot-messages {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.5rem 1rem;
}


/* =============================================================================
   20. CHATBOT RESPONSIVE — Mobile adjustments
   =============================================================================
   On mobile screens:
   - Chatbot bar spans full width
   - Agent info text is hidden (just shows avatar)
   - Split-screen stacks vertically instead of side-by-side
   - Content area overlays the entire screen
============================================================================= */

@media (max-width: 768px) {
  /* Full width bar on mobile — sits close to the bottom edge */
  .chatbot-container {
    width: 94%;
    max-width: none;
    bottom: 0.5rem;
    transition: bottom 0.15s ease-out;
    will-change: bottom;
  }
  /* During an active live call the fixed call bar is bottom-anchored too; lift the COLLAPSED chat pill
     above it so the bar doesn't cover the pill's input/expand controls (the chips/capture form surface
     in the pill transiently, so this matters even without expanding). ≤480px overrides with a larger
     offset for the taller stacked bar. */
  body.live-call-active .chatbot-container:not(.expanded) { bottom: calc(0.5rem + 3.6rem); }

  /* When the mobile keyboard is open, reduce the expanded panel height
     so it doesn't overflow off the top of the screen */
  .chatbot-container.keyboard-open .chatbot-panel {
    max-height: 40vh;
  }

  /* Prevent iOS auto-zoom on ALL chat inputs across the site.
     iOS Safari zooms in on any input with font-size below 16px.
     This covers: main chat bar, expanded panel, split-screen chat, and side panel. */
  .chatbot-bar-input,
  .chatbot-panel-input,
  .side-panel-input {
    font-size: 16px;
  }

  /* Hide agent name/role and action icons on mobile to save space.
     Voice controls (mic + voice-reply toggle) stay visible because they're
     the primary affordance for the voice feature on touch devices. */
  .chatbot-agent-info,
  .chatbot-icon-btn:not(.voice-mic-btn):not(.voice-reply-toggle) {
    display: none;
  }

  /* Expanded panel takes more space on mobile */
  .chatbot-container.expanded .chatbot-panel {
    height: auto;
  }

  /* Split-screen stacks vertically on mobile */
  .split-overlay {
    flex-direction: column-reverse;
  }
  /* The chat-side-right desktop rule (row-reverse) has higher specificity than the line above,
     so re-assert the mobile stack for it here (same specificity, later in source → wins on mobile). */
  body.chat-side-right .split-overlay { flex-direction: column-reverse; }

  .split-chat {
    flex: 1;
    border-right: none;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
  }

  .split-content {
    flex: 1;
  }

  .side-chat-panel {
    width: 100%;
    bottom: 0;
    right: 0;
    max-height: 40%;
    border-radius: 1rem 1rem 0 0;
    border: none;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.3);
    /* Smooth transition when keyboard opens/closes and JS adjusts bottom */
    transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1),
                transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
                bottom 0.15s ease-out;
  }

  .side-chat-panel.history-open {
    max-height: 55%;
  }

  .fullscreen-canvas-content {
    padding: 3rem 1.5rem 5rem 1.5rem;
    align-items: flex-start;
  }

  /* Mobile canvas: let long tokens wrap, and give a wide markdown table its OWN horizontal scroll
     (display:block + overflow-x:auto) so a full-screen answer never forces the whole document
     sideways on a phone. Tighter cell padding buys back column width. */
  .fullscreen-canvas-content .canvas-markdown { overflow-wrap: break-word; word-break: break-word; }
  .fullscreen-canvas-content .canvas-markdown table {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
    white-space: nowrap;
  }
  .fullscreen-canvas-content .canvas-markdown th,
  .fullscreen-canvas-content .canvas-markdown td { padding: 0.4rem 0.6rem; }

  .side-panel-latest-text {
    max-height: 80px;
    font-size: 0.8125rem;
  }

  .gallery-view.side-panel-active {
    right: 0 !important;
    bottom: 0 !important;
  }

  .landing-container.side-panel-active {
    margin-right: 0;
  }

  /* Modal form — nearly fullscreen on mobile for easier input */
  .modal-content {
    max-width: 100%;
    max-height: 85vh;
    max-height: 85dvh;
    border-radius: 0.75rem;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  .modal-body {
    padding-bottom: calc(var(--space-xl) + env(safe-area-inset-bottom, 0px));
  }

  /* Safe area insets for notched phones (iPhone X+) */
  .chatbot-container {
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  .side-chat-panel {
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  /* Minimized launcher state — applied automatically when the visitor
     taps a navigation link on mobile so the destination section isn't
     covered by the chat bar. Tapping the launcher restores the full
     bar (handled by chatRestoreFromMinimized in script.js). */
  .chatbot-container.minimized {
    width: auto;
    left: auto;
    right: 0.75rem;
    /* !important so the inline `bottom` set by the mobile-keyboard
       handler can't push the launcher off the corner if the keyboard
       happens to close after we minimize. */
    bottom: 0.75rem !important;
    transform: none;
    transition: bottom 0.15s ease-out, right 0.15s ease-out;
  }
  /* Visible focus ring for keyboard users on the launcher. */
  .chatbot-container.minimized .chatbot-bar:focus-visible {
    outline: 2px solid rgba(201, 169, 110, 0.85);
    outline-offset: 2px;
  }
  .chatbot-container.minimized .chatbot-bar {
    padding: 0.35rem;
    gap: 0;
    border-radius: 9999px;
    cursor: pointer;
    background: rgba(255, 255, 255, 0.16);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.3);
  }
  /* Hide everything except the avatar so we get a clean launcher pill. */
  .chatbot-container.minimized .chatbot-bar > *:not(.chatbot-avatar) {
    display: none !important;
  }
  .chatbot-container.minimized .chatbot-avatar {
    width: 2rem;
    height: 2rem;
  }
  /* If the chat happens to be in the .expanded state when minimize
     fires we also force the panel hidden so the launcher stays small. */
  .chatbot-container.minimized .chatbot-panel {
    display: none !important;
  }
}


/* =====================================================================
   SMALL SCREEN — Extra adjustments for phones under 380px
   ===================================================================== */

@media (max-width: 380px) {
  .hero-title {
    font-size: clamp(1.75rem, 9vw, 2.5rem);
  }

  .hero-content {
    padding: 0 var(--space-sm);
  }

  .hero-buttons {
    max-width: 260px;
  }

  .hero-buttons .btn-primary,
  .hero-buttons .btn-secondary {
    font-size: 0.7rem;
    padding: 0.75rem 1rem;
    letter-spacing: 0.1em;
  }

  .landing-section {
    padding: var(--space-xl) var(--space-sm);
    /* Carry the breathing-room boost down to ultra-small phones too —
       without this re-declaration, the shorthand above resets the
       block padding set higher up and the eyebrow / trailing CTA crowd
       the painted card edge again at <380px. Absolute floor in rem
       keeps the gap from collapsing when the density slider is low. */
    padding-block: clamp(4.5rem, 16vw, 7rem) !important;
  }

  .chatbot-container {
    width: 96%;
  }

  .sphere-heading {
    font-size: clamp(1.5rem, 8vw, 2.5rem);
    padding: 0 var(--space-sm);
  }
}


/* =====================================================================
   SPHERE VIEW — Immersive 3D rotating image sphere
   =====================================================================
   A fullscreen interactive experience using Three.js.
   Particles + floating images orbit a sphere, with scroll-to-zoom
   and drag-to-rotate interaction.
   ===================================================================== */

.sphere-view {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: none;
  background: #000;
  overflow: hidden;
}

.sphere-view.active {
  display: block;
}

.sphere-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.sphere-css3d-container {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
}

.sphere-css3d-container > div {
  pointer-events: none;
}

/* Section cards rendered inside the CSS3D scene */
.sphere-section-card {
  width: 320px;
  padding: 1.5rem;
  border-radius: 1rem;
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.08);
  color: #fff;
  font-family: var(--font-sans, 'DM Sans', sans-serif);
  backface-visibility: hidden;
  pointer-events: none;
}

.sphere-card-eyebrow {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--accent, #c9a96e);
  margin-bottom: 0.5rem;
  font-weight: 600;
}

.sphere-card-title {
  font-family: var(--font-serif, 'Playfair Display', Georgia, serif);
  font-size: 1.1rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
  line-height: 1.3;
  color: #fff;
}

.sphere-card-body {
  font-size: 0.75rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.6);
}

.sphere-card-items {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.sphere-card-items li {
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.55);
  padding-left: 0.75rem;
  position: relative;
}

.sphere-card-items li::before {
  content: '·';
  position: absolute;
  left: 0;
  color: var(--accent, #c9a96e);
  font-weight: 700;
}

.sphere-card-image {
  width: 100%;
  height: 100px;
  object-fit: cover;
  border-radius: 0.5rem;
  margin-bottom: 0.75rem;
  opacity: 0.85;
}

.sphere-card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

.sphere-card-grid-item {
  background: rgba(255, 255, 255, 0.04);
  border-radius: 0.5rem;
  padding: 0.5rem;
  text-align: center;
}

.sphere-card-grid-item .grid-label {
  font-size: 0.6rem;
  color: rgba(255, 255, 255, 0.45);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.sphere-card-grid-item .grid-value {
  font-size: 0.8rem;
  font-weight: 600;
  color: #fff;
  margin-top: 0.15rem;
}

.sphere-card-stars {
  color: var(--accent, #c9a96e);
  font-size: 0.7rem;
  margin-bottom: 0.25rem;
}

.sphere-card-quote {
  font-style: italic;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.65);
  line-height: 1.5;
  margin-bottom: 0.5rem;
}

.sphere-card-reviewer {
  font-size: 0.65rem;
  color: rgba(255, 255, 255, 0.4);
}

.sphere-heading-container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
  pointer-events: none;
  z-index: 2;
}

.sphere-heading {
  font-family: var(--font-serif, 'Playfair Display', Georgia, serif);
  font-size: clamp(2rem, 5vw, 4rem);
  font-weight: 400;
  color: #fff;
  text-align: center;
  max-width: 750px;
  padding: 0 1.5rem;
  line-height: 1.2;
  letter-spacing: -0.02em;
  text-shadow: 0 2px 20px rgba(0, 0, 0, 0.6);
}

.sphere-top-left {
  position: absolute;
  top: 1.5rem;
  left: 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  z-index: 10;
}

.sphere-top-right {
  position: absolute;
  top: 1.5rem;
  right: 1.5rem;
  z-index: 10;
}

.sphere-scroll-hint {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  color: rgba(255, 255, 255, 0.4);
  font-family: var(--font-sans, 'DM Sans', sans-serif);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  z-index: 10;
  animation: sphereHintPulse 2s ease-in-out infinite;
  pointer-events: none;
  transition: opacity 0.5s ease;
}

.sphere-scroll-hint.hidden {
  opacity: 0;
}

@keyframes sphereHintPulse {
  0%, 100% { opacity: 0.4; transform: translateX(-50%) translateY(0); }
  50% { opacity: 0.7; transform: translateX(-50%) translateY(-5px); }
}

@media (max-width: 768px) {
  .sphere-heading {
    font-size: clamp(1.5rem, 7vw, 2.5rem);
    padding-top: 0;
  }

  .sphere-heading-container {
    padding-top: 15vh;
  }

  .sphere-top-left .logo-text {
    display: none;
  }

  .sphere-scroll-hint {
    bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
    font-size: 0.65rem;
  }
}


/* =========================================================================
 * VOICE AGENT — UI styles
 * =========================================================================
 * Three pieces of voice UI that need styling:
 *   1. .voice-intro-card — floating bottom-right "tap to listen" prompt
 *   2. .voice-mic-btn   — microphone button injected into chat input rows
 *   3. .voice-speaking  — pulse animation on avatars while TTS plays
 * Designed to match the existing frosted-glass + gold accent aesthetic.
 * ========================================================================= */

/* ---- Voice intro card (proactive welcome prompt) ------------------------ */
.voice-intro-card {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  z-index: 9999;
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.6rem 0.7rem;
  /* Frosted glass — softer + more neutral so it reads sleek on any site theme */
  background: rgba(22, 22, 26, 0.7);
  backdrop-filter: blur(26px) saturate(1.6);
  -webkit-backdrop-filter: blur(26px) saturate(1.6);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 16px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.25);
  color: #fff;
  cursor: pointer;
  animation: voice-intro-slide-in 0.5s cubic-bezier(0.16, 1, 0.3, 1);
  max-width: 300px;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

@keyframes voice-intro-slide-in {
  from { opacity: 0; transform: translateY(16px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.voice-intro-card:hover {
  transform: translateY(-2px);
  border-color: rgba(201, 169, 110, 0.55);
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.48), 0 2px 6px rgba(0, 0, 0, 0.25);
}

.voice-intro-card .voice-avatar {
  position: relative;
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--accent, #c9a96e), #a0824f);
  color: #1a1a1a;
  box-shadow: 0 2px 10px rgba(201, 169, 110, 0.35);
}

/* Soft pulse ring so the card feels alive without being noisy. */
.voice-intro-card .voice-avatar::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 2px solid var(--accent, #c9a96e);
  opacity: 0;
  animation: voice-intro-pulse 2.4s ease-out infinite;
}

@keyframes voice-intro-pulse {
  0%       { opacity: 0.45; transform: scale(0.85); }
  70%,100% { opacity: 0;    transform: scale(1.25); }
}

.voice-intro-body {
  flex: 1 1 auto;
  min-width: 0;
  padding-right: 2px;
}

.voice-intro-title {
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.voice-intro-sub {
  font-size: 0.73rem;
  opacity: 0.62;
  margin-top: 1px;
}

.voice-intro-play {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: none;
  background: var(--accent, #c9a96e);
  color: #1a1a1a;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 10px rgba(201, 169, 110, 0.40);
  transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}

.voice-intro-play:hover {
  transform: scale(1.09);
  background: #d8b878;
  box-shadow: 0 4px 16px rgba(201, 169, 110, 0.55);
}

.voice-intro-play:active { transform: scale(0.97); }

.voice-intro-close {
  position: absolute;
  top: 6px;
  right: 8px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: transparent;
  border: none;
  color: rgba(255, 255, 255, 0.55);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s ease, color 0.15s ease;
}

.voice-intro-close:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
}

/* ---- Microphone button (injected into chat input rows) ----------------- */
/* Inherits .chatbot-icon-btn so size/shape match the existing visualize/
   fullscreen icon buttons. We just add the active "listening" state. */
.voice-mic-btn.voice-mic-active {
  background: rgba(201, 169, 110, 0.2);
  color: var(--accent, #c9a96e);
  /* Subtle pulsing ring while the mic is live */
  animation: voice-mic-pulse 1.2s ease-in-out infinite;
}

@keyframes voice-mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(201, 169, 110, 0.5); }
  50%      { box-shadow: 0 0 0 6px rgba(201, 169, 110, 0); }
}

/* ---- Speaking indicator (pulse on avatars while TTS plays) ------------- */
.voice-speaking {
  animation: voice-speaking-pulse 1.4s ease-in-out infinite;
}

@keyframes voice-speaking-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(201, 169, 110, 0.4); }
  50%      { box-shadow: 0 0 0 8px rgba(201, 169, 110, 0); }
}

/* ---- AI voice reply toggle (injected next to chat send buttons) -------- */
/* Visitor-side master switch for AI voice replies. Lives next to the mic
   button so the chat input row reads as: [mic] [voice toggle] [send]. */
.voice-reply-toggle .voice-toggle-off { display: none; }
.voice-reply-toggle.voice-reply-muted .voice-toggle-on  { display: none; }
.voice-reply-toggle.voice-reply-muted .voice-toggle-off { display: inline; }
.voice-reply-toggle.voice-reply-muted {
  /* Dimmed appearance when muted so it's obvious voice is off */
  opacity: 0.55;
}
.voice-reply-toggle:not(.voice-reply-muted) {
  /* Subtle accent tint when active so visitors notice it's "live" */
  color: var(--accent, #c9a96e);
}

/* ---- Per-message speaker badge ----------------------------------------- */
/* Tiny pill rendered inside each agent message bubble. Click to replay or
   stop. Icons swap based on the bubble's voice-speaking state. */
.chat-msg-agent[data-voice-tagged="1"] {
  position: relative;
  /* Reserve a bit of bottom space so the badge doesn't overlap text */
  padding-bottom: calc(0.75rem + 1.5rem);
}
.voice-msg-badge {
  position: absolute;
  bottom: 0.4rem;
  right: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  font-size: 11px;
  line-height: 1;
  border-radius: 999px;
  border: 1px solid rgba(201, 169, 110, 0.35);
  background: rgba(201, 169, 110, 0.08);
  color: var(--accent, #c9a96e);
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, opacity 120ms ease;
}
.voice-msg-badge:hover {
  background: rgba(201, 169, 110, 0.18);
  border-color: rgba(201, 169, 110, 0.6);
}
.voice-msg-badge .voice-msg-icon-stop { display: none; }
/* While the bubble is speaking, swap play→stop and pulse softly */
.chat-msg-agent.voice-speaking .voice-msg-badge .voice-msg-icon-play { display: none; }
.chat-msg-agent.voice-speaking .voice-msg-badge .voice-msg-icon-stop { display: inline; }
.chat-msg-agent.voice-speaking .voice-msg-badge {
  background: rgba(201, 169, 110, 0.22);
  border-color: rgba(201, 169, 110, 0.7);
}
/* While we're fetching audio, show a quiet pulsing state */
.chat-msg-agent.voice-loading .voice-msg-badge {
  opacity: 0.6;
  animation: voice-msg-loading 1.1s ease-in-out infinite;
}
@keyframes voice-msg-loading {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 0.9; }
}
/* Autoplay was blocked → invite the visitor to tap */
.chat-msg-agent.voice-tap-to-play .voice-msg-badge::after {
  content: "Tap to play";
  margin-left: 2px;
}
.chat-msg-agent.voice-tap-to-play .voice-msg-badge .voice-msg-label {
  display: none;
}

/* ---- Mobile tweaks for the intro card ---------------------------------- */
@media (max-width: 600px) {
  .voice-intro-card {
    bottom: 0.75rem;
    right: 0.75rem;
    left: 0.75rem;
    max-width: none;
  }
}

/* ============================================================
   VIDEO GALLERY SECTION
   ============================================================ */
.video-gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.25rem;
  margin-top: 2rem;
}

.video-gallery-item {
  position: relative;
  aspect-ratio: 16/9;
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  background: #111;
  box-shadow: 0 4px 20px rgba(0,0,0,0.15);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.video-gallery-item:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 28px rgba(0,0,0,0.25);
}
.video-gallery-thumb {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  width: 100%; height: 100%;
}
.video-gallery-thumb-video { object-fit: cover; }
.video-gallery-overlay {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0.1) 50%, rgba(0,0,0,0) 100%);
  display: flex; align-items: center; justify-content: center;
  opacity: 0.85;
  transition: opacity 0.2s ease;
}
.video-gallery-item:hover .video-gallery-overlay { opacity: 1; }
.video-gallery-play {
  width: 64px; height: 64px;
  border-radius: 50%;
  background: rgba(255,255,255,0.92);
  color: #111;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.6rem;
  padding-left: 4px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.4);
}
.video-gallery-meta {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  padding: 1rem;
  color: #fff;
  z-index: 2;
}
.video-gallery-title { margin: 0; font-size: 1.05rem; font-weight: 600; }
.video-gallery-desc { margin: 0.25rem 0 0; font-size: 0.875rem; opacity: 0.9; }

/* Video lightbox */
.video-lightbox {
  position: fixed; inset: 0;
  z-index: 9999;
  display: none;
  align-items: center; justify-content: center;
}
.video-lightbox-backdrop {
  position: absolute; inset: 0;
  background: rgba(0,0,0,0.85);
}
.video-lightbox-frame {
  position: relative;
  width: min(92vw, 1100px);
  max-height: 90vh;
}
.video-lightbox-frame video {
  width: 100%;
  max-height: 90vh;
  border-radius: 8px;
  background: #000;
  display: block;
}
.video-lightbox-close {
  position: absolute;
  top: -2.5rem; right: 0;
  background: none; border: none;
  color: #fff;
  font-size: 2rem;
  cursor: pointer;
  line-height: 1;
}

/* ============================================================
   PODCAST SECTION
   ============================================================ */
.podcast-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 1.5rem;
  margin-top: 2rem;
}
.podcast-episode {
  display: flex;
  gap: 1rem;
  padding: 1rem;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 12px;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.podcast-episode:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
}
.podcast-cover {
  flex-shrink: 0;
  width: 96px; height: 96px;
  border-radius: 8px;
  background-size: cover;
  background-position: center;
  background-color: #222;
}
.podcast-cover-empty {
  display: flex; align-items: center; justify-content: center;
  font-size: 2.4rem;
  color: rgba(255,255,255,0.65);
}
.podcast-body { flex: 1; min-width: 0; }
.podcast-meta { font-size: 0.78rem; opacity: 0.7; margin-bottom: 0.25rem; }
.podcast-number { text-transform: uppercase; letter-spacing: 0.06em; }
.podcast-title { margin: 0 0 0.4rem; font-size: 1.05rem; font-weight: 600; }
.podcast-desc { margin: 0; font-size: 0.875rem; opacity: 0.85; }

/* ============================================================
   STORE — products grid, cart, checkout
   ============================================================ */

.store-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1.5rem;
  margin-top: 1.5rem;
}

.store-card {
  background: #fff;
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.store-card:hover { transform: translateY(-3px); box-shadow: 0 8px 28px rgba(0,0,0,0.08); }

.store-card-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: #f3f4f6;
}
.store-card-img-placeholder {
  display: flex; align-items: center; justify-content: center;
  color: #9ca3af; font-size: 0.875rem; letter-spacing: 0.05em; text-transform: uppercase;
}

.store-card-body {
  padding: 1rem 1.1rem 1.2rem;
  display: flex; flex-direction: column; gap: 0.5rem;
  flex: 1;
}
.store-card-title { font-size: 1.05rem; font-weight: 600; margin: 0; color: #111827; }
.store-card-desc { font-size: 0.9rem; color: #6b7280; margin: 0; flex: 1; }
.store-card-foot {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 0.5rem; gap: 0.5rem;
}
.store-card-price { font-weight: 700; color: #111827; }
.store-card-soldout { color: #ef4444; font-size: 0.85rem; font-weight: 600; }

/* Floating cart button (legacy / fallback when the header isn't on
   the current page — e.g. standalone routes). The default placement
   is INLINE in the top-right of the header next to "Get Started"
   (.cart-fab-inline below). */
.cart-fab {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  z-index: 1100;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  border: none;
  background: #111827;
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(0,0,0,0.25);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.cart-fab:hover { transform: scale(1.05); box-shadow: 0 10px 24px rgba(0,0,0,0.3); }

/* Hide the cart bubble while the visitor is in an overlay view (an
   AI-generated immersive page, the fullscreen canvas, or the side chat
   panel). The cart isn't relevant in those modes and just adds visual
   clutter to the corner where the Back button / page-archive bubble live. */
body:has(.immersive-page-overlay.active) .cart-fab,
body:has(.fullscreen-canvas.active) .cart-fab,
body.side-panel-active .cart-fab {
  display: none !important;
}

/* Inline placement in the top header next to the Get Started button.
   Same visual size / count badge as the FAB but drops the fixed
   positioning + heavy shadow so it sits naturally in the nav row. */
.cart-fab.cart-fab-inline {
  position: relative;
  bottom: auto;
  right: auto;
  width: 44px;
  height: 44px;
  background: rgba(255,255,255,0.08);
  color: inherit;
  border: 1px solid rgba(201,169,110,0.35);
  box-shadow: none;
}
.cart-fab.cart-fab-inline:hover {
  transform: none;
  background: rgba(255,255,255,0.16);
  box-shadow: none;
}
/* Keep at least a 44x44 touch target on small phones (WCAG 2.5.5). */
@media (max-width: 480px) {
  .cart-fab.cart-fab-inline { width: 44px; height: 44px; }
}

.cart-fab-count {
  position: absolute;
  top: -4px; right: -4px;
  min-width: 22px; height: 22px;
  padding: 0 6px;
  border-radius: 11px;
  background: #ef4444;
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}

/* Cart drawer */
.cart-drawer {
  position: fixed; inset: 0;
  z-index: 1200;
  pointer-events: none;
}
.cart-drawer-open { pointer-events: auto; }
.cart-drawer-backdrop {
  position: absolute; inset: 0;
  background: rgba(0,0,0,0.45);
  opacity: 0; transition: opacity 0.2s ease;
}
.cart-drawer-open .cart-drawer-backdrop { opacity: 1; }
.cart-drawer-panel {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: min(420px, 100%);
  background: #fff;
  /* Explicit dark text — the surrounding site uses light --color-text on
     dark backgrounds, so without this the inner text inherits and is unreadable
     on the white panel. */
  color: #111827;
  display: flex; flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.25s ease;
  box-shadow: -8px 0 30px rgba(0,0,0,0.15);
}
.cart-drawer-panel h1, .cart-drawer-panel h2, .cart-drawer-panel h3,
.cart-drawer-panel h4, .cart-drawer-panel p, .cart-drawer-panel span,
.cart-drawer-panel label, .cart-drawer-panel strong { color: inherit; }
.cart-drawer-open .cart-drawer-panel { transform: translateX(0); }
.cart-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.25rem; border-bottom: 1px solid #e5e7eb;
}
.cart-drawer-head h3 { margin: 0; font-size: 1.1rem; }
.cart-drawer-close {
  background: none; border: none; font-size: 1.6rem; line-height: 1;
  cursor: pointer; color: #6b7280;
}
.cart-drawer-body {
  flex: 1; overflow-y: auto; padding: 1rem 1.25rem;
}
.cart-empty { color: #6b7280; text-align: center; margin-top: 2rem; }
.cart-line {
  display: flex; gap: 0.85rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid #f3f4f6;
}
.cart-line-img {
  width: 64px; height: 64px;
  object-fit: cover;
  border-radius: 8px;
  background: #f3f4f6;
  flex-shrink: 0;
}
.cart-line-info { flex: 1; min-width: 0; }
.cart-line-name { font-weight: 600; color: #111827; font-size: 0.95rem; }
.cart-line-price { color: #6b7280; font-size: 0.85rem; margin: 0.15rem 0 0.5rem; }
.cart-line-qty { display: flex; align-items: center; gap: 0.4rem; }
.cart-line-qty button {
  width: 28px; height: 28px;
  border: 1px solid #d1d5db;
  background: #fff;
  border-radius: 6px;
  cursor: pointer;
  font-size: 1rem; line-height: 1;
}
.cart-line-qty span { min-width: 20px; text-align: center; font-weight: 600; }
.cart-line-remove {
  margin-left: auto;
  border: none; background: none; color: #ef4444;
  cursor: pointer; font-size: 0.8rem; padding: 0.15rem 0.35rem;
  border-radius: 4px;
  width: auto !important; height: auto !important;
}
.cart-line-remove:hover { color: #b91c1c; background: rgba(239,68,68,0.08); }
.cart-line-remove:focus { outline: none; }
.cart-line-remove:focus-visible {
  outline: 2px solid rgba(239,68,68,0.5); outline-offset: 2px;
}

/* ---- Generic button base + dark variant used on the storefront / cart ----
   The site previously only had `.btn-primary` / `.btn-secondary` / etc.
   Cart and checkout use `.btn` and `.btn-dark`, which were undefined and
   rendered as transparent-on-white (invisible). Define them here. */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 0.5rem;
  padding: 0.7rem 1.4rem;
  border-radius: 8px;
  border: 1px solid transparent;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
  text-decoration: none;
  white-space: nowrap;
}
.btn:focus { outline: none; }
.btn:focus-visible { outline: 2px solid rgba(17,24,39,0.5); outline-offset: 2px; }
.btn-dark {
  background: #111827;
  color: #fff;
  border-color: #111827;
}
.btn-dark:hover:not(:disabled) { background: #1f2937; border-color: #1f2937; }
.btn-dark:disabled { background: #9ca3af; border-color: #9ca3af; cursor: not-allowed; }
.btn-light {
  background: #fff;
  color: #111827;
  border-color: #d1d5db;
}
.btn-light:hover:not(:disabled) { background: #f3f4f6; }
.cart-drawer-foot {
  border-top: 1px solid #e5e7eb;
  padding: 1rem 1.25rem;
  display: flex; flex-direction: column; gap: 0.75rem;
}
.cart-total-row { display: flex; justify-content: space-between; font-size: 1rem; }
.cart-checkout-btn { width: 100%; }
.cart-checkout-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Checkout modal */
.checkout-modal {
  position: fixed; inset: 0;
  z-index: 1300;
  pointer-events: none;
  display: flex; align-items: center; justify-content: center;
}
.checkout-modal-open { pointer-events: auto; }
.checkout-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(0,0,0,0.5);
  opacity: 0; transition: opacity 0.2s ease;
}
.checkout-modal-open .checkout-modal-backdrop { opacity: 1; }
.checkout-modal-panel {
  position: relative;
  background: #fff;
  /* Same fix as cart drawer — explicit dark text for the white panel. */
  color: #111827;
  border-radius: 14px;
  width: min(540px, 92%);
  max-height: 92vh;
  display: flex; flex-direction: column;
  transform: translateY(20px); opacity: 0;
  transition: transform 0.2s ease, opacity 0.2s ease;
  box-shadow: 0 20px 60px rgba(0,0,0,0.25);
  overflow: hidden;
}
.checkout-modal-panel h1, .checkout-modal-panel h2, .checkout-modal-panel h3,
.checkout-modal-panel h4, .checkout-modal-panel p, .checkout-modal-panel span,
.checkout-modal-panel label, .checkout-modal-panel strong { color: inherit; }
.checkout-modal-open .checkout-modal-panel { transform: translateY(0); opacity: 1; }
.checkout-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.25rem; border-bottom: 1px solid #e5e7eb;
}
.checkout-modal-head h3 { margin: 0; font-size: 1.1rem; }
.checkout-modal-close {
  background: none; border: none; font-size: 1.6rem; cursor: pointer; color: #6b7280;
}
.checkout-modal-body {
  padding: 1.25rem;
  overflow-y: auto;
}
.checkout-summary {
  background: #f9fafb;
  border-radius: 10px;
  padding: 0.85rem 1rem;
  margin-bottom: 1.25rem;
  font-size: 0.9rem;
}
.checkout-summary-line { display: flex; justify-content: space-between; padding: 0.2rem 0; color: #374151; }
.checkout-summary-total {
  display: flex; justify-content: space-between;
  margin-top: 0.5rem; padding-top: 0.5rem;
  border-top: 1px solid #e5e7eb; font-size: 1rem;
}
.checkout-form { display: flex; flex-direction: column; gap: 0.85rem; }
.checkout-form label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.85rem; color: #374151; font-weight: 500; }
.checkout-form input {
  padding: 0.6rem 0.75rem;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  font-size: 0.95rem;
  font-family: inherit;
}
.checkout-form input:focus { outline: none; border-color: #111827; box-shadow: 0 0 0 3px rgba(17,24,39,0.1); }
.checkout-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.85rem; }
.checkout-card {
  border: 1px solid #d1d5db;
  border-radius: 8px;
  padding: 0.6rem 0.75rem 0.85rem;
  margin-top: 0.25rem;
}
.checkout-card legend { padding: 0 0.4rem; font-size: 0.85rem; color: #374151; font-weight: 500; }
.checkout-card-element { padding: 0.5rem 0.25rem; min-height: 36px; }
.checkout-card-errors { color: #ef4444; font-size: 0.85rem; min-height: 1.2em; margin-top: 0.25rem; }
.checkout-pay-btn { width: 100%; margin-top: 0.5rem; }
.checkout-pay-btn:disabled { opacity: 0.6; cursor: not-allowed; }
.checkout-note { font-size: 0.8rem; color: #6b7280; text-align: center; margin: 0.25rem 0 0; }
.checkout-success { text-align: center; padding: 1.5rem 0.5rem; }
.checkout-success h3 { margin: 0 0 0.75rem; }
.checkout-success p { color: #374151; margin: 0.25rem 0; }
.checkout-success .btn { margin-top: 1.25rem; }

@media (max-width: 480px) {
  .checkout-form-row { grid-template-columns: 1fr; }
  .cart-drawer-panel { width: 100%; }
}

/* =============================================================================
   SERVICE BOOKING MODAL
   =============================================================================
   Mobile-friendly defaults for the public-facing service booking modal.
   Inputs use 16px font to prevent iOS zoom-on-focus, slot buttons get
   larger tap targets, and the modal padding tightens up on small screens.
============================================================================= */

#service-booking-modal {
  /* Stay above sticky headers, snap-scroll containers, and ai_concierge */
  z-index: 99999 !important;
}

#service-booking-modal input,
#service-booking-modal select,
#service-booking-modal textarea {
  font-size: 16px;
  font-family: inherit;
  background: rgba(255, 255, 255, 0.06);
  color: inherit;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 6px;
  box-sizing: border-box;
  width: 100%;
  padding: 0.6rem 0.7rem;
  margin-top: 0.25rem;
}

#service-booking-modal input:focus,
#service-booking-modal select:focus,
#service-booking-modal textarea:focus {
  outline: none;
  border-color: var(--accent, #c9a96e);
  background: rgba(255, 255, 255, 0.1);
}

#service-booking-modal label {
  display: block;
  margin-bottom: 0.7rem;
  font-size: 0.9rem;
}

#service-booking-modal #svc-slots button {
  min-height: 44px; /* Apple HIG touch target */
  padding: 0.55rem 0.95rem;
  font-size: 1rem;
}

#service-booking-modal h2 {
  font-size: 1.4rem;
  line-height: 1.25;
}

@media (max-width: 480px) {
  #service-booking-modal { padding: 0.5rem !important; }
  #service-booking-modal > div {
    padding: 1rem !important;
    max-height: 95vh !important;
    border-radius: 10px !important;
  }
  #service-booking-modal h2 {
    font-size: 1.2rem;
    padding-right: 1.75rem; /* room for the X button */
  }
  #service-booking-modal fieldset { padding: 0.6rem !important; }
}

/* ── Custom "Form" section (task 140) — an operator's custom form embedded on the public page ──
   Theme-safe: transparent inputs + a mid-gray border + color:inherit read on light OR dark
   sections. The submit button reuses the existing .btn.btn-dark; these rules only lay out the
   fields + status message. */
.custom-form-host { max-width: 620px; margin: 0 auto; }
.custom-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem 1rem; }
.custom-form .cf-field { margin: 0.6rem 0 0.2rem; }
.custom-form .cf-full { grid-column: 1 / -1; }
.custom-form .cf-half { grid-column: span 1; }
@media (max-width: 560px) { .custom-form .cf-half { grid-column: 1 / -1; } }
.custom-form .cf-label { display: block; font-size: 0.82rem; margin: 0 0 0.35rem; opacity: 0.85; }
.custom-form .cf-req { color: var(--accent, #c9a96e); }
.custom-form .cf-input {
  width: 100%; box-sizing: border-box; padding: 0.65rem 0.75rem; font: inherit;
  color: inherit; background: transparent;
  border: 1px solid var(--border-color, rgba(127,127,127,0.4)); border-radius: 10px;
}
.custom-form .cf-input:focus { outline: none; border-color: var(--accent, #c9a96e); }
.custom-form textarea.cf-input { resize: vertical; }
.custom-form select.cf-input option { color: #111; }
.custom-form .cf-opts { display: flex; flex-direction: column; gap: 0.4rem; }
.custom-form .cf-opt { display: flex; align-items: center; gap: 0.5rem; font-size: 0.92rem; opacity: 0.9; }
.custom-form .cf-opt input { width: auto; }
.custom-form .cf-help { font-size: 0.78rem; opacity: 0.55; margin: 0.3rem 0 0; }
.custom-form .cf-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.custom-form .cf-submit { margin-top: 1.25rem; width: 100%; }
.custom-form .cf-msg { margin-top: 1rem; font-size: 0.95rem; text-align: center; }
.custom-form .cf-msg.cf-ok { color: #34d399; }
.custom-form .cf-msg.cf-err { color: #f87171; }
.custom-form .cf-cn { margin-top: 0.4rem; font-size: 0.82rem; opacity: 0.65; }

/* ==========================================================================
   PRESENTATION OVERLAY — full-screen immersive slide player.
   Frosted-glass aesthetic that mirrors the chatbot, edge-to-edge with
   minimal chrome so the slide IS the experience. Floating controls,
   floating progress pill, and an inline chat pill the visitor can use
   to ask questions without leaving the deck.
   ========================================================================== */
.presentation-overlay {
  position: fixed; inset: 0;
  background:
    radial-gradient(ellipse at center, rgba(20, 22, 32, 0.55) 0%, rgba(6, 7, 12, 0.92) 70%),
    rgba(6, 7, 12, 0.85);
  backdrop-filter: blur(24px) saturate(1.4);
  -webkit-backdrop-filter: blur(24px) saturate(1.4);
  display: flex; align-items: center; justify-content: center;
  z-index: 9500;
  padding: 0;
  animation: presentation-fade-in 220ms ease-out;
}
.presentation-overlay.hidden { display: none; }
@keyframes presentation-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.presentation-stage {
  position: relative;
  width: 100%; height: 100%;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  /* Inset the slide image so it has breathing room and the floating
     chat pill + controls live in dedicated bottom space below the
     slide rather than overlapping its content (e.g. stat cards on the
     bottom row of an imported deck). Top padding keeps the slide
     clear of the floating progress pill / close button; horizontal
     padding gives the image a card-like appearance. */
  padding: 64px 40px 168px;
  box-sizing: border-box;
  color: rgba(255, 255, 255, 0.94);
}

/* Top-left floating progress pill — small, glassy, unobtrusive */
.presentation-progress {
  position: absolute; top: 18px; left: 20px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.72);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  padding: 7px 14px;
  border-radius: 999px;
  z-index: 3;
  max-width: calc(100vw - 100px);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Top-right floating close — circular glass button */
.presentation-close {
  position: absolute; top: 14px; right: 16px;
  width: 38px; height: 38px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-radius: 50%;
  font-size: 22px; line-height: 1; cursor: pointer;
  color: rgba(255, 255, 255, 0.85);
  display: flex; align-items: center; justify-content: center;
  transition: background 160ms ease, transform 160ms ease;
  z-index: 3;
}
.presentation-close:hover {
  background: rgba(255, 255, 255, 0.12);
  transform: scale(1.05);
}

/* The slide image — fills the inset stage area (the stage's padding
   keeps it clear of the floating chat pill + controls below and the
   progress pill above). Subtle border + shadow gives a card feel
   without bezel-heavy chrome. */
.presentation-image {
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;                 /* allow flex child to shrink */
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  display: none;
  margin: 0;
  border-radius: 14px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
}
.presentation-image.has-image { display: block; }
.presentation-image.image-fill {
  background-size: contain;
}

/* Slide title/body — overlaid lower-third on a soft gradient.
   Hidden when the slide is image-only or display_mode=original. */
.presentation-text-block {
  position: absolute;
  /* Anchored inside the slide area — must sit ABOVE the inset edge of
     the slide image (which ends at ~168px from bottom due to stage
     padding) so the lower-third overlays the slide rather than
     floating in empty space between slide and chat pill. */
  left: 50%; bottom: 200px;
  transform: translateX(-50%);
  width: min(820px, calc(100% - 100px));
  text-align: center;
  pointer-events: none;
  z-index: 2;
}
.presentation-text-block.empty { display: none; }
.presentation-title {
  font-size: clamp(26px, 4vw, 42px);
  font-weight: 600;
  line-height: 1.18;
  margin: 0 0 14px;
  color: #fff;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.65);
  letter-spacing: -0.01em;
}
.presentation-body {
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.88);
  white-space: pre-wrap;
  margin: 0;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.6);
  max-height: 30vh;
  overflow: hidden;
}

/* Floating bottom controls — glass row, centered */
.presentation-controls {
  position: absolute;
  left: 50%; bottom: 24px;
  transform: translateX(-50%);
  display: flex; gap: 8px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  padding: 6px;
  border-radius: 999px;
  z-index: 4;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
.presentation-controls button {
  padding: 8px 18px;
  border-radius: 999px;
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.85);
  transition: background 140ms ease, color 140ms ease;
  letter-spacing: 0.01em;
}
.presentation-controls button:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
}
.presentation-controls button:disabled {
  opacity: 0.35; cursor: default;
}
.presentation-controls .presentation-toggle {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
}
.presentation-controls .presentation-toggle:hover {
  background: rgba(255, 255, 255, 0.24);
}

/* Inline chat pill — sits above the controls. Visitor can ask a
   question while the deck plays; focusing the input pauses narration
   via the existing chat-focus pause hook (script.js). The AI reply
   streams into .presentation-chat-bubble above the pill. */
.presentation-chat {
  position: absolute;
  left: 50%; bottom: 84px;
  transform: translateX(-50%);
  width: min(640px, calc(100% - 32px));
  z-index: 4;
  display: flex; flex-direction: column;
  align-items: center; gap: 10px;
  pointer-events: none;
}
.presentation-chat-bubble {
  max-width: 100%;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  color: rgba(255, 255, 255, 0.94);
  padding: 12px 18px;
  border-radius: 16px;
  font-size: 14px;
  line-height: 1.5;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
  display: none;
  pointer-events: auto;
  animation: presentation-bubble-in 200ms ease-out;
  white-space: pre-wrap;
}
.presentation-chat-bubble.visible { display: block; }
@keyframes presentation-bubble-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.presentation-chat-pill {
  width: 100%;
  display: flex; align-items: center; gap: 8px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(24px) saturate(1.4);
  -webkit-backdrop-filter: blur(24px) saturate(1.4);
  border-radius: 999px;
  padding: 6px 6px 6px 20px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
  pointer-events: auto;
  transition: border-color 160ms ease, background 160ms ease;
}
.presentation-chat-pill:focus-within {
  border-color: rgba(255, 255, 255, 0.24);
  background: rgba(255, 255, 255, 0.09);
}
.presentation-chat-input {
  flex: 1 1 auto;
  background: transparent;
  border: none; outline: none;
  color: #fff;
  font-size: 14px;
  font-family: inherit;
  padding: 10px 0;
  min-width: 0;
}
.presentation-chat-input::placeholder {
  color: rgba(255, 255, 255, 0.5);
}
.presentation-chat-send {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  cursor: pointer;
  font-size: 16px;
  display: flex; align-items: center; justify-content: center;
  transition: background 140ms ease, transform 140ms ease;
}
.presentation-chat-send:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.28);
  transform: scale(1.05);
}
.presentation-chat-send:disabled {
  opacity: 0.4; cursor: default;
}

/* Phone / narrow portrait — tighter horizontal insets so the slide
   uses every pixel of width, but a slightly larger BOTTOM inset so the
   stacked chat pill + controls can both breathe without overlapping
   the slide. The progress pill caps width to leave room for the
   close button on the right. */
@media (max-width: 600px) {
  .presentation-stage { padding: 52px 12px 168px; }
  .presentation-progress {
    font-size: 10px; padding: 6px 12px; top: 12px; left: 12px;
    max-width: calc(100vw - 70px);
  }
  .presentation-close { width: 34px; height: 34px; top: 9px; right: 12px; }
  .presentation-image { border-radius: 12px; box-shadow: 0 14px 36px rgba(0, 0, 0, 0.55); }
  .presentation-text-block { bottom: 200px; width: calc(100% - 28px); }
  .presentation-title { margin-bottom: 8px; }
  .presentation-body { max-height: 22vh; }
  .presentation-chat { bottom: 78px; width: calc(100% - 16px); gap: 8px; }
  .presentation-chat-bubble {
    padding: 10px 14px; font-size: 13px; border-radius: 14px;
    max-height: 32vh; overflow-y: auto;
  }
  .presentation-chat-pill { padding: 4px 4px 4px 14px; }
  .presentation-chat-input { font-size: 14px; padding: 9px 0; }   /* iOS won't zoom on focus when >=14px */
  .presentation-chat-send { width: 34px; height: 34px; font-size: 15px; }
  .presentation-controls { bottom: 14px; gap: 4px; padding: 4px; }
  .presentation-controls button { padding: 7px 12px; font-size: 12px; }
}

/* Very short viewports (landscape phone) — collapse the bottom inset
   so the slide doesn't get crushed into a sliver. The text-block hides
   automatically when image-only via the .empty class set by JS. */
@media (max-height: 520px) {
  .presentation-stage { padding: 44px 16px 128px; }
  .presentation-text-block { bottom: 160px; }
  .presentation-chat { bottom: 64px; }
  .presentation-controls { bottom: 12px; }
}

/* =============================================================================
   EMBED WIDGET MODE — served at /embed/concierge inside a cross-origin iframe
   =============================================================================
   When the real homepage is loaded in "widget mode" (html.aap-widget, set by an
   early inline script in index.html keyed on the /embed/concierge path), hide
   ALL the marketing chrome and make the page background transparent so only the
   floating AI concierge shows through. The concierge keeps its FULL capability:
   the expanded chat panel, split view, and generated-page / canvas overlays all
   still open normally because we only hide the landing / gallery / footer /
   sphere surfaces, not the concierge's own surfaces. The embed loader resizes
   the iframe to match (collapsed bar vs. fullscreen) via widget-bridge.js. */
html.aap-widget,
html.aap-widget body {
  background: transparent !important;
}
html.aap-widget body {
  overflow: hidden !important;
}
html.aap-widget #loading-screen,
html.aap-widget #landing-view,
html.aap-widget #gallery-view,
html.aap-widget #sphere-view,
html.aap-widget #site-footer {
  display: none !important;
}

/* …BUT when the AI's `navigate` command opens a gallery card (or the 3D sphere)
   these page-covering views become `.active`. The bridge then reports the iframe
   as fullscreen (isModal), so we must let the active view actually render —
   otherwise it stays hidden by the rule above and the fullscreen gallery card
   never appears in the embed. */
html.aap-widget #gallery-view.active,
html.aap-widget #sphere-view.active {
  display: block !important;
}

/* The concierge keeps its NATURAL layout in widget mode — the bar stays centered
   (max-width 540px) and the voice intro / side panel stay bottom-right, exactly
   like the main site. The loader sizes the iframe to a full-width bottom band
   that hugs whichever of those surfaces are visible (so the rest of the host page
   stays clickable), and switches to fullscreen for the modal surfaces (expanded
   chat panel, split view, generated-page / canvas overlays).

   Those frosted-glass surfaces are designed to float over the site's own dark
   background. In widget mode the page is transparent (it floats over the host
   site instead), so we give them that same dark backdrop — derived from the
   active theme's base color — so they read exactly like on the main site, over
   ANY host page (light or dark). */
html.aap-widget #chatbot-bar,
html.aap-widget #chatbot-panel,
html.aap-widget #side-chat-panel {
  /* Honor the admin theme color, but use the near-solid variant: over an
     arbitrary (often light) host page a translucent surface would wash out, so
     widget mode always uses ~0.96 opacity. Falls back to the theme base color
     when no theme is set. */
  background: var(--chatbot-surface-bg-solid, rgb(var(--color-bg-rgb, 6 11 20) / 0.96)) !important;
}

/* The chat pill carries a big soft drop-shadow (0 8px 32px) that reads as a
   grey halo around the pill when it floats over a LIGHT host page (on the dark
   main site it blends into the background). In widget mode the iframe is
   transparent, so kill that halo — only the pill itself should be visible, with
   nothing bleeding into the host page around it. */
html.aap-widget #chatbot-bar {
  box-shadow: none !important;
}

/* The expanded chat panel is capped at 70vh on the main site. Inside the widget
   iframe, vh = the iframe's OWN height — which the loader derives FROM the panel
   — so a vh cap creates a feedback deadlock (small band -> small 70vh -> small
   panel -> small band) and the panel renders clipped. Size it off the HOST
   viewport height instead: the loader posts it in and widget-bridge.js stores it
   in --aap-host-vh (px). Fallback to a fixed pixel cap until the host size
   arrives. The loader caps the iframe at the host height, so the panel never
   overflows the host viewport. */
html.aap-widget #chatbot-panel {
  max-height: calc(var(--aap-host-vh, 640px) * 0.72) !important;
}

/* SHADE FIX — every floating surface sits on a transparent iframe over an
   arbitrary host page, and the embed loader CLIPS the iframe tightly to each
   surface's box (so the host page stays clickable around them). A big soft
   drop-shadow then (a) reads as a grey halo over a light host and (b) gets hard-
   cut by that clip into an ugly rectangular "shade". So drop the shadows on the
   concierge's own floating surfaces in widget mode — only the surfaces
   themselves should show. (#chatbot-bar is already handled above.) */
html.aap-widget #chatbot-panel,
html.aap-widget #side-chat-panel,
html.aap-widget .voice-intro-card,
html.aap-widget .page-archive-bubble,
html.aap-widget .page-archive-bubble-btn,
html.aap-widget .page-archive-popover {
  box-shadow: none !important;
}

/* FLICKER FIX — the loader resizes + re-clips the iframe to hug whichever
   surfaces are currently open. If those surfaces slide/fade in over several
   frames (transitions), the clip chases them frame-by-frame and the edges
   flicker/glitch as the user opens/closes the panel or the saved-pages popover.
   In widget mode show/hide them INSTANTLY so the iframe resizes and re-clips in
   a single step — no chasing, no flicker. This only disables layout TRANSITIONS;
   keyframe animations (e.g. the typing dots) are left intact. The main site is
   unaffected — these rules are scoped to html.aap-widget. */
html.aap-widget #chatbot-bar,
html.aap-widget #chatbot-panel,
html.aap-widget #side-chat-panel,
html.aap-widget .voice-intro-card,
html.aap-widget .page-archive-bubble,
html.aap-widget .page-archive-bubble-btn,
html.aap-widget .page-archive-popover {
  transition: none !important;
}

/* =============================================================================
   OFFER POPUP (task 141 R2) — a small floating promo card, bottom-right, that an
   admin opts a single offer into (offers.show_in_popup). Uses the theme tokens so
   it follows the admin Theme editor (light/dark). Floating (no page-blocking
   backdrop) so the visitor can keep browsing; dismiss via the X or Esc.
   ============================================================================= */
.offer-popup { position: fixed; bottom: 20px; right: 20px; z-index: 1200; width: 340px;
  max-width: calc(100vw - 40px); opacity: 0; transform: translateY(16px);
  transition: opacity .25s ease, transform .25s ease; pointer-events: none; }
.offer-popup.offer-popup-open { opacity: 1; transform: translateY(0); pointer-events: auto; }
.offer-popup-card { position: relative; background: var(--color-section-1, #0a0f1a);
  color: var(--color-text, #e4e4e7); border: 1px solid var(--glass-border, rgba(255,255,255,0.08));
  border-radius: var(--radius, 1rem); padding: 1.5rem 1.4rem 1.35rem; box-shadow: 0 16px 48px rgba(0,0,0,0.45); }
.offer-popup-close { position: absolute; top: 6px; right: 12px; background: none; border: 0;
  color: inherit; font-size: 1.6rem; line-height: 1; cursor: pointer; opacity: .55; padding: 4px; }
.offer-popup-close:hover { opacity: 1; }
.offer-popup-emoji { font-size: 2rem; line-height: 1; margin-bottom: .5rem; }
.offer-popup-badge { display: inline-block; background: var(--color-accent, #c9a96e); color: #111;
  font-weight: 700; font-size: .7rem; letter-spacing: .04em; padding: .2rem .6rem; border-radius: 999px; margin-bottom: .55rem; }
.offer-popup-title { font-size: 1.2rem; margin: 0 0 .4rem; line-height: 1.25; }
.offer-popup-desc { font-size: .9rem; opacity: .78; margin: 0 0 1rem; }
.offer-popup-form { display: flex; flex-direction: column; gap: .5rem; }
.offer-popup-form input { padding: .6rem .75rem; border-radius: 8px;
  border: 1px solid var(--glass-border, rgba(255,255,255,0.15)); background: var(--glass-bg, rgba(255,255,255,0.05));
  color: inherit; font-size: .9rem; }
.offer-popup-hp { position: absolute !important; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.offer-popup-submit { padding: .65rem; border: 0; border-radius: 8px; background: var(--color-accent, #c9a96e);
  color: #111; font-weight: 600; font-size: .92rem; cursor: pointer; }
.offer-popup-submit:hover { filter: brightness(1.06); }
.offer-popup-submit:disabled { opacity: .6; cursor: default; }
.offer-popup-cta { display: block; text-align: center; text-decoration: none; margin-top: .25rem; }
.offer-popup-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 1.1rem;
  font-weight: 700; letter-spacing: .06em; text-align: center; margin: .85rem 0;
  background: var(--glass-bg, rgba(255,255,255,0.08)); border: 1px dashed var(--glass-border, rgba(255,255,255,0.25));
  border-radius: 8px; padding: .55rem; }
.offer-popup-msg { font-size: .82rem; min-height: 1em; opacity: .8; }
.offer-popup-msg.is-err { color: #f87171; opacity: 1; }
@media (max-width: 480px) {
  .offer-popup { right: 12px; left: 12px; bottom: 12px; width: auto; }
}

/* Offer code at checkout (task 141 R3) — promo row + discount line in the summary. The checkout
   modal panel is white with dark text (see .checkout-modal-panel), so these match its fields. */
.checkout-promo { display: flex; gap: .5rem; margin: .75rem 0 .25rem; }
.checkout-promo input { flex: 1 1 auto; min-width: 0; padding: .55rem .7rem; border-radius: 8px;
  border: 1px solid #d1d5db; font-size: .92rem; font-family: inherit; text-transform: uppercase; }
.checkout-promo input::placeholder { text-transform: none; }
.checkout-promo .btn { flex: 0 0 auto; padding: .55rem .9rem; }
.checkout-promo-msg { font-size: .8rem; min-height: 1em; margin: 0 0 .5rem; opacity: .9; }
.checkout-promo-msg.is-ok { color: #15803d; }
.checkout-promo-msg.is-err { color: #b91c1c; }
.checkout-summary-discount { color: #15803d; font-weight: 600; }

/* ═══════════════════════════════════════════════════════════════════════════
   HCI TIER 1 — accessibility hardening (from the 2026-06-26 HCI audit).
   Appended LAST so the cascade reliably wins; all rules are ADDITIVE (no existing
   rule is edited) and white-label (accent CSS var, system-color keywords).
   ═══════════════════════════════════════════════════════════════════════════ */

/* (a) Visible KEYBOARD focus on the chat chrome (WCAG 2.4.7). :focus-visible so a mouse click
   shows no ring. .voice-mic-btn inherits .chatbot-icon-btn, so it is covered automatically. */
.chatbot-bar-btn:focus-visible,
.chatbot-icon-btn:focus-visible,
.chatbot-close-btn:focus-visible,
.chatbot-send-panel-btn:focus-visible,
.side-panel-send-btn:focus-visible,
.side-panel-history-btn:focus-visible,
.side-panel-close-btn:focus-visible,
.chatbot-quick-prompt:focus-visible,
.split-back-btn:focus-visible,
.canvas-close-btn:focus-visible,
.nextstep-chip:focus-visible,
.chatbot-launcher:focus-visible {
  outline: 2px solid var(--color-accent, #c9a96e);
  outline-offset: 2px;
}

/* (b) A clearer focus ring on the chat TEXT INPUTS (WCAG 2.4.7 / 1.4.11) — the faint border tint
   alone was ~1.5:1. Same accent var the widget themes with, so it stays per-tenant. */
.chatbot-bar-input:focus,
.chatbot-panel-input:focus,
.side-panel-input:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--chat-accent, var(--color-accent, #c9a96e)) 55%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--chat-accent, var(--color-accent, #c9a96e)) 45%, transparent);
}

/* (c) PII-form consent line (handoff + intake share .hoff-consent; the structured form uses .cvf-cn,
   styled inline in renderFormPage). Small, low-emphasis. */
.hoff-consent { flex: 0 0 100%; margin: 0.15rem 0 0.1rem; font-size: 0.72rem; line-height: 1.35; opacity: 0.62; }
.hoff-consent-link { color: inherit; text-decoration: underline; }

/* (d) Live-call "waiting" state (after the visitor's own leg connects but BEFORE a human is bridged) —
   amber dot so it never reads as "done". Reuses the bar's existing pulsing-dot animation. */
.live-call-bar[data-state="waiting"] .lcb-dot { background: #f59e0b; }
/* The "Get a callback instead" escape is only relevant while ringing/connecting — hide it once a human
   is on the line or the call ended (Tier 2 live-call resilience). */
.live-call-bar[data-state="connected"] #lcb-callback,
.live-call-bar[data-state="held"] #lcb-callback,
.live-call-bar[data-state="ended"] #lcb-callback { display: none; }

/* (e) prefers-reduced-motion: stop the continuous / large-area visitor animations that ran unguarded
   (only ~3 of ~20 were honored). Vestibular safety — WCAG 2.3.3 / 2.2.2. */
@media (prefers-reduced-motion: reduce) {
  .chat-msg,
  .chat-typing-dot,
  .bar-thinking-dot,
  .chat-msg-streaming::after,
  .gallery-slide-bg,
  .split-nav-bg,
  .sphere-scroll-hint,
  .voice-mic-btn.voice-mic-active,
  .voice-speaking,
  .page-archive-bubble.pulsing .page-archive-bubble-btn { animation: none !important; }
  .chat-typing-dot, .bar-thinking-dot, .chat-msg-streaming::after { opacity: 1 !important; }
}

/* (f) Windows High-Contrast / forced-colors: the all-glass chat loses its borders. Give solid
   system-color separators so bubbles / inputs / buttons stay distinguishable (WCAG 1.4.3 / 1.4.11).
   System color keywords only → white-label-safe (no brand hex). */
@media (forced-colors: active) {
  .chatbot-panel, .chat-msg-user, .chat-msg-agent, .chatbot-input-bar,
  .chatbot-panel-input, .chatbot-send-panel-btn, .side-panel-send-btn, .chatbot-bar-btn {
    border: 1px solid CanvasText !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  .chatbot-send-panel-btn, .side-panel-send-btn {
    background: ButtonFace !important; color: ButtonText !important; border-color: ButtonText !important;
  }
  .chatbot-panel-input:focus, .chatbot-send-panel-btn:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
}

/* ── HCI Tier 2 — accessible booking-modal validation + a screen-reader-only utility. ── */
/* Visible, text-based field error (paired with aria-invalid + role=alert in validateStepPane).
   Stays collapsed until populated, so it never adds space to a valid form. */
.field-error-msg { display: block; color: #fca5a5; font-size: 0.75rem; line-height: 1.3; margin-top: 0.25rem; }
.field-error-msg:empty { display: none; }
/* Visually-hidden but screen-reader-available (no existing .sr-only in the file). */
.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Send button in "Stop generating" mode (Tier 2) — a universal stop red so it reads as cancel,
   regardless of the tenant's accent. */
.chatbot-bar-btn.is-stopping,
.chatbot-send-panel-btn.is-stopping,
.side-panel-send-btn.is-stopping {
  background: #dc2626 !important;
  color: #fff !important;
  border-color: #dc2626 !important;
}

/* ── HCI Tier 2 — readable ink on accent-backed controls (--on-accent is computed per-tenant from the
   accent luminance in JS; this :root value is the gold-default fallback when JS hasn't run yet). ── */
:root { --on-accent: #0b0b0b; }
/* The collapsed-bar send/expand glyphs sit on the accent fill — the rgba(255,255,255,0.6) default was
   ~2.24:1 on the gold accent. Pair them with the computed ink (dark on light accents, white on dark). */
.chatbot-bar-btn:not(.is-stopping) { color: var(--on-accent, #0b0b0b); }
/* Accent-backed chips also get the paired ink (their hover/picked state fills with the accent). */
.nextstep-chip:hover, .nextstep-chip:focus-visible, .nextstep-chip.nextstep-chip-picked { color: var(--on-accent, #0b0b0b) !important; }

/* Human-takeover reply (Tier 2) — a real teammate, visibly distinct from the AI: a left accent rail
   + a small attribution chip so the visitor knows who they're now talking to. */
.chat-msg-human { border-left: 3px solid var(--chat-accent, var(--color-accent, #22c55e)); }
.chat-msg-sender {
  display: block; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--chat-accent, var(--color-accent, #22c55e)); opacity: 0.95; margin: 0 0 0.2rem;
}

/* ── HCI Tier 3 ── */
/* AI-fallibility caption under the chat panel quick prompts (calibrated trust). Ambient, not alarming. */
.chatbot-disclaimer { margin: 0; padding: 0 1rem 0.5rem; font-size: 0.75rem; line-height: 1.35; color: rgba(255, 255, 255, 0.62); text-align: center; flex-shrink: 0; }
/* Empty / in-flight send button — presentational only (a CLASS, not native :disabled, so the existing
   in-flight guard still routes the click to chatStopStreaming when streaming). */
.chatbot-bar-btn.is-disabled { opacity: 0.4; cursor: default; pointer-events: none; }
/* Hidden-until-button launcher now shows a chat-bubble glyph instead of a literal "?". */
.chatbot-launcher svg { width: 1.5rem; height: 1.5rem; display: block; }
/* Greeter video with blocked autoplay → a tap-to-play overlay (not a dead black box). */
.video-greeter-bubble.greeter-needs-play { cursor: pointer; }
.video-greeter-bubble.greeter-needs-play::after {
  content: '\25B6'; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 2rem; color: #fff; background: rgba(0, 0, 0, 0.35); border-radius: inherit; pointer-events: none;
}
/* Echo of the visitor's own message in the collapsed-bar thinking pill (one truncated line). */
.bar-thinking .bar-user-echo {
  font-size: 0.78rem; color: rgba(255, 255, 255, 0.6); margin: 0 0 0.25rem;
  max-width: 22rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
