/* ── Fonts ───────────────────────────────────────────────────────────────────
   No @import / @font-face here. Fonts are self-hosted and arrive via the
   per-tour theme.css (generated by src/tourTheme.ts, linked AFTER this file),
   which also overrides the :root tokens below. */

/* ── MetaTours — Neutral Design System ──────────────────────────────────
   Brand-agnostic warm-neutral palette so the same wrapper works for any
   listing agent without carrying a previous client's brand colours.
   Token names are kept (--tw-navy, --tw-gold) for backwards compatibility;
   the values inside are now neutrals. */

:root {
  /* Theme tokens — JSON semantic name in parens. applyTheme() in wrapper.js
     overrides BOTH the hex var and its -rgb triplet from published-tour.json;
     these defaults must stay equal to DEFAULT_THEME in src/tourTheme.ts. */
  --tw-navy: #2A2A2D;          /* surface — cards/pills        (token: surface) */
  --tw-navy-rgb: 42, 42, 45;
  --tw-navy-deep: #1A1A1C;     /* deep background/overlays (token: surfaceDeep) */
  --tw-navy-deep-rgb: 26, 26, 28;
  --tw-cream: #F4EDE5;         /* primary text/icons               (token: ink) */
  --tw-cream-rgb: 244, 237, 229;
  --tw-gold: #B8AFA3;          /* accents/active states         (token: accent) */
  --tw-gold-rgb: 184, 175, 163;
  --tw-line: #9A958F;          /* hairlines/secondary text        (token: line) */
  --tw-line-rgb: 154, 149, 143;
  --tw-serif: 'Parkinsans', sans-serif;
  --tw-sans: 'Poppins', sans-serif;
  --tw-ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* ── SPLASH ──────────────────────────────────────────────────────────────── */

#tw-splash {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--tw-navy-deep);
  transition: opacity 1.0s var(--tw-ease);
  overflow: hidden;
}

#tw-splash-pano {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  transform: scale(1);
  opacity: 0;
  /* Revealed ONLY by revealSplashPano() on the splash scene's first drawn frame.
     This used to ALSO run a timed 2.2s fade from the first paint; when the pano
     was slower than that, it showed half-faded, then the first-frame reveal
     snapped it back to 0 and faded again: a flash right as the splash opens
     (Danny, 2026-10-06). One mechanism now. */
  transition: opacity 1.1s ease-out, transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  background: var(--tw-navy-deep);
}
#tw-splash-pano canvas { display: block; }

.tw-splash-overlay {
  position: absolute;
  inset: 0;
  background: rgba(var(--tw-navy-deep-rgb), 0.65);
  z-index: 1;
  transition: background 0.5s var(--tw-ease);
}

/* The exit is driven per frame by enterTour() in wrapper.js (opacity, plus a
   gentle push-in on a still or a video only). A CSS transition on a splash
   child can freeze at its start value mid-exit, and a pano that scales while
   it dissolves reads as a zoom on the way in (Danny, Seaview Two, 2026-09-25),
   so the pano here holds its exact framing. */
#tw-splash.tw-hiding {
  pointer-events: none;
}

/* Splash backdrops other than the pano: a looping video (the MetaTours
   "banner") or a still photo. Both fade in on their first decoded frame
   rather than popping in (see the tw-backdrop-loaded toggle in init()). */
#tw-splash-video,
#tw-splash-hero {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  transform: scale(1);
  opacity: 0;
  transition: opacity 1.2s ease-out;
  user-select: none;
  pointer-events: none;
}
#tw-splash-video.tw-backdrop-loaded,
#tw-splash-hero.tw-backdrop-loaded { opacity: 1; }

#tw-splash.tw-hiding .tw-splash-overlay {
  background: rgba(var(--tw-navy-deep-rgb), 0.78);
}

#tw-splash.tw-gone {
  display: none;
}

.tw-splash-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 48px 36px;
  width: 100%;
  max-width: 720px;
  position: relative;
  z-index: 2;
}

.tw-splash-wordmark-img {
  width: clamp(180px, 18vw, 290px);
  height: auto;
  margin-bottom: clamp(14px, 1.4vw, 22px);
  opacity: 0;
  transform: translateY(24px);
  animation: tw-rise 1.5s 0.45s var(--tw-ease) forwards;
  user-select: none;
  pointer-events: none;
}

/* Unbranded mode: property name shown in place of agent wordmark.
   Cormorant Garamond italic to match the brand serif tone of the wordmark. */
.tw-splash-headline-text {
  font-family: var(--tw-serif);
  font-weight: 300;
  font-size: clamp(34px, 4.4vw, 58px);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--tw-cream);
  text-align: center;
  max-width: 14ch;
  margin: 0 auto clamp(14px, 1.4vw, 22px);
  opacity: 0;
  transform: translateY(24px);
  animation: tw-rise 1.5s 0.45s var(--tw-ease) forwards;
  text-shadow: 0 1px 4px rgba(0,0,0,0.7), 0 2px 22px rgba(0,0,0,0.55);
}

/* Branded ↔ Unbranded toggle. The flag is set on <html> by the wrapper
   based on the ?unbranded=1 URL param, so DOM stays consistent and the
   browser only paints what's needed. */
html.tw-unbranded .tw-branded-only { display: none !important; }
html:not(.tw-unbranded) .tw-unbranded-only { display: none !important; }

/* In unbranded mode, also hide the floating top-left agent logo and the
   top-right realtor button (and its popup). */
html.tw-unbranded #tw-logo-float,
html.tw-unbranded #tw-realtor-btn,
html.tw-unbranded #tw-realtor-popup { display: none !important; }

/* MLS rule: no clickable links to external sites. The Mapbox GL JS library
   injects attribution + logo links to mapbox.com / openstreetmap.org even
   with attributionControl: false. Hide them entirely + neuter pointer events
   so a strict reviewer can't surface them. */
html.tw-unbranded .mapboxgl-ctrl,
html.tw-unbranded .mapboxgl-ctrl-attrib,
html.tw-unbranded .mapboxgl-ctrl-attrib-inner,
html.tw-unbranded .mapboxgl-ctrl-logo { display: none !important; pointer-events: none !important; }

/* ── Splash "Presented By" broker block — bottom of splash, outside .tw-splash-inner ── */

.tw-splash-broker {
  position: absolute;
  bottom: clamp(24px, 4vh, 48px);
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  z-index: 2;
  opacity: 0;
  animation: tw-fade 1.1s 1.4s var(--tw-ease) forwards;
}

.tw-splash-presented-by {
  font-family: var(--tw-sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.40);
}

.tw-splash-broker-logos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
}

/* Greg Killip agent logo */
.tw-splash-broker-agent-logo {
  height: clamp(36px, 4.5vw, 60px);
  width: auto;
  max-width: 220px;
  object-fit: contain;
  filter: brightness(0) invert(1);
  opacity: 0.88;
}

/* Maxxam brokerage logo — coloured asset, show as-is */
.tw-splash-broker-bk-logo {
  height: clamp(30px, 3.5vw, 48px);
  width: auto;
  max-width: 180px;
  object-fit: contain;
  opacity: 0.88;
}

/* Vertical divider between logos */
.tw-splash-broker-divider {
  display: inline-block;
  width: 1px;
  height: clamp(28px, 3vw, 44px);
  background: rgba(var(--tw-cream-rgb), 0.22);
  flex-shrink: 0;
}

/* Text fallbacks when no logo images are set */
.tw-splash-broker-name {
  font-family: var(--tw-sans);
  font-size: clamp(15px, 1.4vw, 20px);
  font-weight: 500;
  letter-spacing: 0.04em;
  color: rgba(var(--tw-cream-rgb), 0.82);
}

.tw-splash-broker-bk-name {
  font-family: var(--tw-sans);
  font-size: clamp(12px, 1.1vw, 15px);
  font-weight: 400;
  letter-spacing: 0.06em;
  color: rgba(var(--tw-cream-rgb), 0.50);
}

.tw-splash-sub {
  font-family: var(--tw-sans);
  font-size: clamp(16.5px, 1.6vw, 24px);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.78);
  margin-top: 15px;
  opacity: 0;
  animation: tw-fade 0.8s 0.45s var(--tw-ease) forwards;
}

.tw-splash-rule {
  width: clamp(72px, 7vw, 108px);
  height: 1.5px;
  background: linear-gradient(90deg, transparent, var(--tw-gold), transparent);
  margin: clamp(18px, 1.8vw, 28px) auto;
  opacity: 0;
  animation: tw-fade 1.1s 0.9s var(--tw-ease) forwards;
}

/* ── FLOATING MAP CARD ───────────────────────────────────────────────────── */

#tw-map-card {
  position: fixed;
  bottom: 42px;
  right: 36px;
  z-index: 100;
  width: 340px;
  border-radius: 24px;
  overflow: hidden;
  border: 1px solid rgba(var(--tw-line-rgb), 0.2);
  box-shadow: 0 12px 60px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(var(--tw-line-rgb), 0.06) inset;
  background: rgba(var(--tw-navy-deep-rgb), 0.9);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  transition-delay: 0.3s;
}

/* Map card header — acts as collapse toggle */
.tw-map-header {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 16.5px 21px;
  background: transparent;
  border: none;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.18s;
}

.tw-map-header:hover { background: rgba(255, 255, 255, 0.04); }
.tw-map-header:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: -2px; }

.tw-map-header-icon {
  color: var(--tw-gold);
  flex-shrink: 0;
  display: flex;
  align-items: center;
}

.tw-map-header-text {
  font-family: var(--tw-sans);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.72);
  flex: 1;
  text-align: left;
}

.tw-map-chevron {
  color: rgba(var(--tw-cream-rgb), 0.25);
  flex-shrink: 0;
  transition: transform 0.28s var(--tw-ease), color 0.18s;
}

.tw-map-header:hover .tw-map-chevron { color: rgba(var(--tw-cream-rgb), 0.55); }

/* Collapsible map body */
#tw-map-body {
  max-height: 450px;
  overflow: hidden;
  transition: max-height 0.3s var(--tw-ease);
}

#tw-map-card.tw-map-collapsed #tw-map-body {
  max-height: 0;
}

#tw-map-card.tw-map-collapsed .tw-map-chevron {
  transform: rotate(180deg);
}

#tw-map {
  width: 100%;
  height: 218px;
  display: block;
  background: var(--tw-navy-deep);
  border-top: 1px solid rgba(var(--tw-line-rgb), 0.08);
}

/* Light tonal adjustment only — keep roads, labels, and POIs readable. */
#tw-map .mapboxgl-canvas {
  filter: brightness(0.96) saturate(0.92);
}

/* Small-map zoom controls — same dark glass language as the modal map. */
#tw-map .mapboxgl-ctrl-top-right > .mapboxgl-ctrl {
  margin: 8px 8px 0 0 !important;
}
#tw-map .mapboxgl-ctrl-group {
  background: rgba(var(--tw-navy-deep-rgb), 0.88) !important;
  border: 1px solid rgba(var(--tw-gold-rgb), 0.28) !important;
  border-radius: 10px !important;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45) !important;
  overflow: hidden;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
#tw-map .mapboxgl-ctrl-group button {
  width: 30px !important;
  height: 30px !important;
  background: transparent !important;
  border: none !important;
  border-bottom: 1px solid rgba(var(--tw-gold-rgb), 0.18) !important;
}
#tw-map .mapboxgl-ctrl-group button:last-child { border-bottom: none !important; }
#tw-map .mapboxgl-ctrl-group button:hover { background: rgba(var(--tw-gold-rgb), 0.14) !important; }
#tw-map .mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 18 18'%3E%3Cpath d='M9 3v12M3 9h12' stroke='%23F4EDE5' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") !important;
}
#tw-map .mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 18 18'%3E%3Cpath d='M3 9h12' stroke='%23F4EDE5' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") !important;
}

/* Preview map — suppress all Mapbox attribution controls entirely.
   pointer-events:none on #tw-map-card (via .tw-ui-el) does NOT cascade to
   children in CSS, so Mapbox <a> links inside remain clickable even when the
   card is opacity:0 pre-reveal, causing accidental ghost clicks.
   Full attribution is shown in the expanded modal — ToS requirement met there. */
#tw-map .mapboxgl-ctrl-logo { display: none !important; }
#tw-map .mapboxgl-ctrl-attrib { display: none !important; }
#tw-map .mapboxgl-ctrl-attrib-button { display: none !important; }
#tw-map .mapboxgl-ctrl-attrib a,
#tw-map .mapboxgl-ctrl-attrib button {
  pointer-events: none !important;
  display: none !important;
}

/* Snap controls to corner — override Mapbox's default 10px margin */
#tw-map .mapboxgl-ctrl-bottom-right > .mapboxgl-ctrl {
  margin: 0 8px 8px 0 !important;
}

/* Zoom controls — branded dark glass */
#tw-map .mapboxgl-ctrl-group {
  background: rgba(var(--tw-navy-deep-rgb), 0.88) !important;
  border: 1px solid rgba(var(--tw-line-rgb), 0.28) !important;
  border-radius: 10px !important;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45) !important;
  overflow: hidden;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
#tw-map .mapboxgl-ctrl-group button {
  width: 30px !important;
  height: 30px !important;
  background: transparent !important;
  border: none !important;
  border-bottom: 1px solid rgba(var(--tw-line-rgb), 0.18) !important;
}
#tw-map .mapboxgl-ctrl-group button:last-child {
  border-bottom: none !important;
}
#tw-map .mapboxgl-ctrl-group button:hover {
  background: rgba(var(--tw-line-rgb), 0.14) !important;
}
#tw-map .mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18'%3E%3Cpath d='M9 3v12M3 9h12' stroke='%23F4EDE5' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") !important;
}
#tw-map .mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18'%3E%3Cpath d='M3 9h12' stroke='%23F4EDE5' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") !important;
}

/* Gold location pin */
.tw-map-pin {
  width: 16.5px;
  height: 16.5px;
  border-radius: 50%;
  background: var(--tw-gold);
  border: 2px solid rgba(var(--tw-cream-rgb), 0.9);
  box-shadow: 0 0 0 6px rgba(var(--tw-line-rgb), 0.28), 0 3px 12px rgba(0,0,0,0.55);
  cursor: default;
}

/* Drone pin on map */
.tw-map-drone-pin {
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(var(--tw-navy-deep-rgb), 0.82);
  border: 1.5px solid rgba(var(--tw-gold-rgb), 0.35);
  border-radius: 50%;
  color: var(--tw-gold);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,0.5);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: transform 0.15s, border-color 0.15s;
}
.tw-map-drone-pin:hover { transform: scale(1.15); border-color: var(--tw-gold); }
.tw-map-drone-pin svg { width: 13px; height: 13px; }
.tw-map-drone-pin-lg { width: 36px; height: 36px; }
.tw-map-drone-pin-lg svg { width: 17px; height: 17px; }

/* Address popup on map */
.tw-map-popup .mapboxgl-popup-content {
  background: rgba(var(--tw-navy-deep-rgb), 0.88) !important;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.25);
  border-radius: 10px !important;
  padding: 8px 14px !important;
  box-shadow: 0 4px 16px rgba(0,0,0,0.5) !important;
}
.tw-map-popup .mapboxgl-popup-tip {
  border-top-color: rgba(var(--tw-navy-deep-rgb), 0.88) !important;
}
.tw-map-popup-text {
  font-family: var(--tw-sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tw-cream);
  white-space: nowrap;
}
.tw-map-popup-lg .mapboxgl-popup-content { padding: 10px 18px !important; }
.tw-map-popup-lg .tw-map-popup-text { font-size: 12px; }

/* ── Neighbourhood amenity pins ───────────────────────────────────────────
   A pin marks somewhere you can walk to, not somewhere the tour goes, so it
   is deliberately quieter than a scene marker: no fill, just an icon on the
   card surface. */
.tw-map-poi-chip {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 50%;
  background: rgba(var(--tw-navy-deep-rgb), 0.85);
  border: 1.5px solid rgba(var(--tw-gold-rgb), 0.45);
  color: var(--tw-gold);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: transform 0.15s var(--tw-ease), border-color 0.15s, background 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.tw-map-poi-chip:hover {
  transform: scale(1.14);
  border-color: var(--tw-gold);
  background: rgba(var(--tw-navy-deep-rgb), 0.95);
}
.tw-map-poi-chip:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: 2px; }
.tw-map-poi-chip svg { width: 14px; height: 14px; }
.tw-map-poi-chip-lg { width: 34px; height: 34px; }
.tw-map-poi-chip-lg svg { width: 17px; height: 17px; }

/* Amenity popup — the map card popup is a one-line address; a pin needs three. */
.tw-map-popup-wrap .mapboxgl-popup-content {
  background: rgba(var(--tw-navy-deep-rgb), 0.9) !important;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.25);
  border-radius: 10px !important;
  padding: 9px 14px !important;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5) !important;
}
.tw-map-popup-wrap .mapboxgl-popup-tip {
  border-top-color: rgba(var(--tw-navy-deep-rgb), 0.9) !important;
}
.tw-map-poi-cat {
  font-family: var(--tw-sans);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.55);
}
.tw-map-poi-name {
  font-family: var(--tw-sans);
  font-size: 12px;
  font-weight: 600;
  color: var(--tw-cream);
  white-space: nowrap;
}
.tw-map-poi-dist {
  font-family: var(--tw-sans);
  font-size: 10px;
  color: rgba(var(--tw-cream-rgb), 0.6);
  white-space: nowrap;
}

/* Filter chips — one row, wraps rather than scrolls so every chip stays tappable. */
.tw-map-filterbar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 10px 14px 9px;
  border-top: 1px solid rgba(var(--tw-line-rgb), 0.08);
}
.tw-map-filterbar-modal { border-top: none; padding: 0 2px 0 10px; flex: 1; }
.tw-map-filter-btn {
  font-family: var(--tw-sans);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: rgba(var(--tw-cream-rgb), 0.7);
  background: rgba(var(--tw-cream-rgb), 0.06);
  border: 1px solid rgba(var(--tw-line-rgb), 0.14);
  border-radius: 999px;
  padding: 5px 11px;
  cursor: pointer;
  white-space: nowrap;
  flex: 0 0 auto;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.tw-map-filter-btn:hover { color: var(--tw-cream); background: rgba(var(--tw-cream-rgb), 0.11); }
.tw-map-filter-btn.active {
  color: var(--tw-navy-deep);
  background: var(--tw-gold);
  border-color: var(--tw-gold);
  font-weight: 600;
}
.tw-map-filter-btn:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: 2px; }

/* Basemap switch — two words side by side with one lit, so it reads as a state
   you can change rather than a label describing the map you are looking at. */
.tw-map-style-switch {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  margin-left: auto;
  border: 1px solid rgba(var(--tw-line-rgb), 0.18);
  border-radius: 999px;
  overflow: hidden;
}
.tw-map-style-btn {
  font-family: var(--tw-sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.5);
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 5px 9px;
  white-space: nowrap;
  transition: color 0.15s, background 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.tw-map-style-btn:hover { color: var(--tw-cream); }
.tw-map-style-btn.active {
  color: var(--tw-navy-deep);
  background: var(--tw-cream);
}
.tw-map-filterbar-modal .tw-map-style-switch { margin-left: 12px; }

.tw-splash-location {
  font-family: var(--tw-sans);
  font-size: clamp(15px, 1.4vw, 21px);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.78);
  margin-top: 14px;
  opacity: 0;
  animation: tw-fade 1.0s 1.15s var(--tw-ease) forwards;
}

.tw-splash-enter {
  margin-top: clamp(24px, 2.4vw, 42px);
  font-family: var(--tw-sans);
  font-size: clamp(15px, 1.2vw, 18px);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--tw-navy-deep);
  background: var(--tw-gold);
  border: none;
  border-radius: 150px;
  padding: clamp(18px, 1.8vw, 24px) clamp(42px, 4vw, 66px);
  min-height: 72px;
  min-width: 66px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 18px;
  touch-action: manipulation;
  box-shadow: 0 4px 24px rgba(var(--tw-gold-rgb), 0.38);   /* the button's own colour, never another tour's */
  transition: background 0.22s, box-shadow 0.22s, filter 0.22s, transform 0.18s var(--tw-ease);
  opacity: 0;
  animation: tw-rise 1.1s 1.4s var(--tw-ease) forwards;
}

.tw-splash-enter:hover {
  background: var(--tw-gold);
  filter: brightness(1.12);
  box-shadow: 0 6px 32px rgba(var(--tw-gold-rgb), 0.55);
  transform: translateY(-1.5px);
}

.tw-splash-enter:focus-visible {
  outline: 2px solid var(--tw-gold);
  outline-offset: 4px;
}

.tw-splash-arrow {
  width: 21px;
  height: 21px;
  transition: transform 0.18s var(--tw-ease);
}

.tw-splash-enter:hover .tw-splash-arrow {
  transform: translateX(4.5px);
}

/* Devon Properties — pinned to bottom of splash, with label */
.tw-splash-devon-wrap {
  position: absolute;
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 11px;
  opacity: 0;
  animation: tw-fade 1.0s 1.65s var(--tw-ease) forwards;
  white-space: nowrap;
}

.tw-splash-devon-label {
  font-family: var(--tw-sans);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.42);
}

.tw-splash-devon-img {
  width: clamp(120px, 10vw, 168px);
  height: auto;
  filter: drop-shadow(0 1px 10px rgba(0,0,0,0.45));
  user-select: none;
  pointer-events: none;
}

/* ── ANIMATIONS ──────────────────────────────────────────────────────────── */

@keyframes tw-rise {
  from { opacity: 0; transform: translateY(21px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes tw-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ── VIGNETTES ───────────────────────────────────────────────────────────── */

#tw-vignette-top {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 195px;
  background: linear-gradient(to bottom,
    rgba(10, 16, 24, 0.45) 0%,
    rgba(10, 16, 24, 0.38) 20%,
    rgba(10, 16, 24, 0.24) 45%,
    rgba(10, 16, 24, 0.09) 72%,
    rgba(10, 16, 24, 0.02) 88%,
    transparent 100%
  );
  z-index: 98;
  pointer-events: none;
}

#tw-vignette-bottom {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 270px;
  background: linear-gradient(to top,
    rgba(10, 16, 24, 0.40) 0%,
    rgba(10, 16, 24, 0.33) 20%,
    rgba(10, 16, 24, 0.21) 45%,
    rgba(10, 16, 24, 0.08) 72%,
    rgba(10, 16, 24, 0.02) 88%,
    transparent 100%
  );
  z-index: 98;
  pointer-events: none;
}

/* Top-left vignette — kept very subtle so top darkness is consistent across
   the full width (the top linear vignette handles the primary coverage) */
#tw-vignette-tl {
  position: fixed;
  top: 0;
  left: 0;
  width: 480px;
  height: 280px;
  background: radial-gradient(ellipse at 0% 0%,
    rgba(10, 16, 24, 0.18) 0%,
    rgba(10, 16, 24, 0.12) 28%,
    rgba(10, 16, 24, 0.06) 48%,
    transparent 70%
  );
  z-index: 98;
  pointer-events: none;
}

/* Top-left vignette — behind the "Now Viewing" toast */
#tw-vignette-toast {
  position: fixed;
  top: 0;
  left: 0;
  width: 800px;
  height: 620px;
  background: radial-gradient(ellipse at 0% 0%,
    rgba(10, 16, 24, 0.88) 0%,
    rgba(10, 16, 24, 0.68) 18%,
    rgba(10, 16, 24, 0.44) 36%,
    rgba(10, 16, 24, 0.20) 54%,
    rgba(10, 16, 24, 0.06) 65%,
    transparent 75%
  );
  z-index: 98;
  pointer-events: none;
}

/* ── UI FLOAT VISIBILITY ─────────────────────────────────────────────────── */

.tw-ui-el {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.55s var(--tw-ease);
}

.tw-ui-el.tw-show {
  opacity: 1;
  pointer-events: all;
}

#tw-devon-logo-float { transition-delay: 0.04s; }
#tw-property-info    { transition-delay: 0.06s; }
#tw-logo-float       { transition-delay: 0.08s; }
#tw-cta-btn          { transition-delay: 0.12s; }
#tw-menu-bar         { transition-delay: 0.22s; }

/* ── FLOATING LOGOS ────────────────────────────────────────────────────────── */

/* Devon Properties — top left (developer / brokerage mark) */
#tw-devon-logo-float {
  position: fixed;
  top: 30px;
  left: 36px;
  z-index: 100;
}

.tw-devon-logo-img {
  display: block;
  height: 52px;
  width: auto;
  filter: drop-shadow(0 2px 14px rgba(0,0,0,0.55));
}

/* ── PROPERTY INFO (top-left listing identity) ────────────────────────────
   Shown in both branded + unbranded modes — listing location ≠ branding.
   Glass pill matching the bottom map/floorplan cards. */
#tw-property-info {
  position: fixed;
  top: 30px;
  left: 36px;
  z-index: 100;
  background: rgba(var(--tw-navy-deep-rgb), 0.55);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border: 1px solid rgba(var(--tw-line-rgb), 0.18);
  border-radius: 16px;
  padding: 14px 22px 15px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4);
  max-width: min(44vw, 420px);
}
.tw-property-logo {
  display: block;
  height: 26px;
  width: auto;
  margin-bottom: 9px;
  filter: drop-shadow(0 1px 8px rgba(0, 0, 0, 0.5));
}
.tw-property-name {
  font-family: var(--tw-serif);
  font-size: clamp(17px, 1.6vw, 22px);
  font-weight: 500;
  color: var(--tw-cream);
  letter-spacing: 0.005em;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tw-property-city {
  font-family: var(--tw-sans);
  font-size: 11px;
  font-weight: 500;
  color: rgba(var(--tw-cream-rgb), 0.66);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-top: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Thera — horizontally centred at top, shifted slightly below the top edge */
#tw-logo-float {
  position: fixed;
  top: 38px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 100;
}

/* ── The property mark: a fixed slot any logo scales into ───────────────────
   The slot, not the image, is the fixed thing, so a 2400px logo and a 400px
   one with the same shape land identically. Ported from the Devon skin so
   every tour gets it; the logo file and its treatment are per tour. */
:root {
  --tw-logo-w: min(38vw, 300px);
  --tw-logo-h: 46px;
  --tw-splash-logo-w: clamp(260px, 34vw, 480px);
  --tw-splash-logo-h: clamp(72px, 11vh, 120px);
}
.tw-logo-box { display: flex; align-items: center; justify-content: center; }
.tw-logo-box > img { width: 100%; height: 100%; object-fit: contain; max-width: none; max-height: none; }
.tw-logo-box.tw-top-mark { width: var(--tw-logo-w); height: var(--tw-logo-h); }
.tw-logo-box.tw-splash-mark {
  width: var(--tw-splash-logo-w);
  height: var(--tw-splash-logo-h);
  margin-bottom: clamp(10px, 1.2vw, 18px);
  opacity: 0;
  transform: translateY(24px);
  animation: tw-rise 1.5s 0.45s var(--tw-ease) forwards;
}
/* How the mark is coloured (theme.logos.treatment), so one asset survives any
   imagery: auto = as supplied with a soft shadow, light = white silhouette,
   dark = its own colour with a pale halo. */
.tw-logo-auto > img  { filter: drop-shadow(0 1px 10px rgba(0,0,0,0.38)); }
.tw-logo-light > img { filter: brightness(0) invert(1) drop-shadow(0 1px 8px rgba(8,14,22,0.55)); }
.tw-logo-dark > img  { filter: drop-shadow(0 0 9px rgba(255,255,255,0.72)) drop-shadow(0 1px 2px rgba(255,255,255,0.5)); }

.tw-logo-svg {
  display: block;
  /* Sized for a wide wordmark lockup (Seaview's is 2400x544) rather than a
     square icon: bounded by whichever dimension runs out first, so any logo a
     tour brings sits on the same optical line. */
  height: auto;
  max-height: 46px;
  max-width: min(38vw, 300px);
  width: auto;
  filter: drop-shadow(0 1px 4px rgba(0,0,0,0.9))
          drop-shadow(0 2px 22px rgba(0,0,0,0.65));
}

/* ── FLOATING CTA ─────────────────────────────────────────────────────────── */

#tw-cta-btn {
  position: fixed;
  top: 27px;
  right: 30px;
  z-index: 100;
  font-family: var(--tw-sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--tw-navy-deep);
  background: var(--tw-gold);
  border-radius: 150px;
  padding: 0 33px;
  height: 66px;
  min-width: 66px;
  display: flex;
  align-items: center;
  white-space: nowrap;
  transition: opacity 0.55s var(--tw-ease), filter 0.2s;
  transition-delay: 0.12s, 0s;
}

#tw-cta-btn:hover  { filter: brightness(1.1); }
#tw-cta-btn:focus-visible { outline: 2px solid var(--tw-cream); outline-offset: 3px; }

/* CTA shifts left when the realtor button shares the top-right corner */
#tw-cta-btn.tw-cta-offset { right: 84px; }

/* ── Powered by MetaTours (theme.poweredBy) ──────────────────────────────── */
/* Muted line riding the property-info pill */
.tw-powered-line {
  display: block;
  margin-top: 7px;
  font-family: var(--tw-sans);
  font-size: 8.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  color: rgba(var(--tw-cream-rgb), 0.42);
  transition: color 0.2s;
}
.tw-powered-line:hover { color: rgba(var(--tw-cream-rgb), 0.75); }

/* Standalone top-left badge (only when there is no property-info pill) */
#tw-powered {
  position: fixed;
  top: 27px;
  left: 30px;
  z-index: 100;
  font-family: var(--tw-sans);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  color: rgba(var(--tw-cream-rgb), 0.55);
  background: rgba(var(--tw-navy-deep-rgb), 0.6);
  border: 1px solid rgba(var(--tw-cream-rgb), 0.12);
  border-radius: 100px;
  padding: 8px 14px;
}
#tw-powered:hover { color: rgba(var(--tw-cream-rgb), 0.85); }

/* Splash badge — sits under the broker block */
.tw-splash-powered {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--tw-sans);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.45);
  z-index: 3;
}
.tw-splash-powered strong { font-weight: 700; color: rgba(var(--tw-cream-rgb), 0.7); }

/* ── BOTTOM MENU BAR ─────────────────────────────────────────────────────── */

#tw-menu-bar {
  position: fixed;
  bottom: 42px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 100;
}

.tw-menu-pill {
  display: flex;
  align-items: center;
  background: rgba(var(--tw-navy-deep-rgb), 0.84);
  backdrop-filter: blur(24px) saturate(170%);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  border: 1px solid rgba(var(--tw-line-rgb), 0.18);
  border-radius: 150px;
  padding: 0 9px;
  height: 78px;
  gap: 0;
  box-shadow: 0 12px 54px rgba(0, 0, 0, 0.4), 0 1.5px 0 rgba(var(--tw-line-rgb), 0.06) inset;
}

/* ── MENU TRIGGER BUTTONS ─────────────────────────────────────────────────── */

.tw-menu-group {
  position: relative;
}

.tw-menu-btn {
  display: flex;
  align-items: center;
  gap: 10.5px;
  font-family: var(--tw-sans);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: rgba(var(--tw-cream-rgb), 0.52);
  background: transparent;
  border: none;
  padding: 0 25.5px;
  height: 60px;
  border-radius: 150px;
  cursor: pointer;
  white-space: nowrap;
  touch-action: manipulation;
  transition: color 0.18s, background 0.18s;
}

.tw-menu-btn:hover {
  color: rgba(var(--tw-cream-rgb), 0.88);
  background: rgba(255, 255, 255, 0.05);
}

.tw-menu-btn[aria-expanded="true"] {
  color: var(--tw-cream);
  background: rgba(255, 255, 255, 0.07);
}

.tw-menu-btn.tw-active {
  color: var(--tw-gold);
}

.tw-menu-btn:focus-visible {
  outline: 2px solid var(--tw-gold);
  outline-offset: -2px;
  border-radius: 150px;
}

.tw-menu-chevron {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  opacity: 0.4;
  transition: transform 0.22s var(--tw-ease), opacity 0.18s;
}

.tw-menu-btn:hover .tw-menu-chevron { opacity: 0.65; }
.tw-menu-btn.tw-active .tw-menu-chevron { opacity: 0.65; }
.tw-menu-btn[aria-expanded="true"] .tw-menu-chevron {
  transform: rotate(180deg);
  opacity: 0.9;
}

/* ── SEPARATOR ───────────────────────────────────────────────────────────── */

.tw-menu-sep {
  width: 1.5px;
  height: 27px;
  background: rgba(var(--tw-cream-rgb), 0.1);
  flex-shrink: 0;
  margin: 0 3px;
}

/* ── DRONE / AERIAL BUTTON ───────────────────────────────────────────────── */

#tw-aerial {
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  width: 66px;
  height: 60px;
  border-radius: 150px;
  cursor: pointer;
  color: rgba(var(--tw-cream-rgb), 0.52);
  touch-action: manipulation;
  transition: color 0.18s, background 0.18s;
  margin: 0 3px;
}

#tw-aerial:hover {
  color: rgba(var(--tw-cream-rgb), 0.88);
  background: rgba(255, 255, 255, 0.05);
}

#tw-aerial.tw-active { color: var(--tw-gold); }

#tw-aerial svg {
  width: 24px;
  height: 24px;
}

#tw-aerial:focus-visible {
  outline: 2px solid var(--tw-gold);
  outline-offset: -2px;
  border-radius: 150px;
}

/* ── DROPDOWN CARDS ──────────────────────────────────────────────────────── */

.tw-dropdown {
  position: absolute;
  bottom: calc(100% + 24px);
  left: 50%;
  transform: translateX(-50%) translateY(12px);
  min-width: 277.5px;
  background: rgba(var(--tw-navy-deep-rgb), 0.92);
  backdrop-filter: blur(28px) saturate(160%);
  -webkit-backdrop-filter: blur(28px) saturate(160%);
  border: 1px solid rgba(var(--tw-line-rgb), 0.2);
  border-radius: 24px;
  padding: 9px;
  box-shadow: 0 30px 84px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(var(--tw-line-rgb), 0.06);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--tw-ease), transform 0.2s var(--tw-ease);
}

#tw-suites-dd {
  min-width: 290px;
  max-height: 62vh;
  overflow-y: auto;
}

.tw-dropdown.tw-open {
  opacity: 1;
  pointer-events: all;
  transform: translateX(-50%) translateY(0);
}

.tw-dropdown-label {
  font-family: var(--tw-sans);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.25);
  padding: 9px 21px 12px;
  display: block;
  border-bottom: 1px solid rgba(var(--tw-line-rgb), 0.1);
  margin-bottom: 6px;
}

/* Group header inside suite dropdown */
/* Empty state — shown in amenities dropdown until panos are added */
.tw-dropdown-empty {
  display: block;
  font-family: var(--tw-sans);
  font-size: 13.5px;
  font-weight: 400;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.28);
  padding: 14px 21px 18px;
  text-align: center;
}

.tw-dropdown-group-label {
  display: block;
  font-family: var(--tw-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(var(--tw-line-rgb), 0.65);
  padding: 14px 21px 5px;
}

.tw-dropdown-group-label:first-child { padding-top: 6px; }

.tw-dropdown-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  width: 100%;
  font-family: var(--tw-sans);
  font-size: 17px;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: rgba(var(--tw-cream-rgb), 0.55);
  background: transparent;
  border: none;
  padding: 11px 21px 11px 39px;
  border-radius: 15px;
  cursor: pointer;
  text-align: left;
  touch-action: manipulation;
  transition: color 0.15s, background 0.15s;
  position: relative;
}

/* Unit name — primary text in each suite item */
.tw-dd-unit-name {
  font-size: 17px;
  font-weight: 400;
  color: inherit;
  letter-spacing: 0.02em;
}

/* Metadata row: bed / bath / sqft */
.tw-dd-meta {
  display: flex;
  align-items: center;
  gap: 13px;
  opacity: 0.6;
  transition: opacity 0.15s;
}

.tw-dropdown-item:hover   .tw-dd-meta { opacity: 0.85; }
.tw-dropdown-item.tw-active .tw-dd-meta { opacity: 0.75; }

.tw-dd-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--tw-sans);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.75);
}

.tw-dropdown-item::before {
  content: '';
  position: absolute;
  left: 15px;
  top: 50%;
  transform: translateY(-50%);
  width: 4.5px;
  height: 4.5px;
  border-radius: 50%;
  background: var(--tw-gold);
  opacity: 0;
  transition: opacity 0.15s;
}

.tw-dropdown-item:hover {
  color: var(--tw-cream);
  background: rgba(255, 255, 255, 0.05);
}

.tw-dropdown-item.tw-active {
  color: var(--tw-cream);
  font-weight: 500;
}

.tw-dropdown-item.tw-active::before {
  opacity: 1;
}

.tw-dropdown-item:focus-visible {
  outline: 2px solid var(--tw-gold);
  outline-offset: -2px;
  border-radius: 15px;
}

/* ── ROOM NAME TOAST ─────────────────────────────────────────────────────── */

#tw-toast {
  position: fixed;
  bottom: 52px;
  left: 48px;
  z-index: 99;
  pointer-events: none;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s var(--tw-ease), transform 0.7s var(--tw-ease);
  max-width: 500px;
}

#tw-toast.tw-show {
  opacity: 1;
  transform: translateY(0);
}

.tw-toast-label {
  display: block;
  font-family: var(--tw-sans);
  font-size: clamp(22px, 1.6vw, 28px);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--tw-gold);
  margin-bottom: 12px;
  text-shadow: 0 1.5px 15px rgba(0,0,0,0.6);
}

.tw-toast-room {
  display: block;
  font-family: var(--tw-serif);
  font-size: clamp(54px, 4.2vw, 86px);
  font-weight: 300;
  color: var(--tw-cream);
  line-height: 1.05;
  text-shadow: 0 3px 30px rgba(0,0,0,0.55);
  letter-spacing: 0.01em;
}

.tw-toast-meta {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-top: 18px;
  font-family: var(--tw-sans);
  font-size: clamp(17px, 1.3vw, 22px);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.78);
  text-shadow: 0 1.5px 12px rgba(0,0,0,0.6);
}

.tw-toast-meta-item {
  display: inline-flex;
  align-items: flex-start;
  gap: 9px;
}

.tw-toast-meta-icon {
  color: var(--tw-gold);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  padding-top: 0.1em; /* optically align icon with cap height of first text line */
}

.tw-toast-meta-icon svg {
  width: 30px;
  height: 30px;
}

/* ── RESPONSIVE ──────────────────────────────────────────────────────────── */

/* Tablet — fires earlier (≤1199px) so mid-size laptops and iPads get
   a properly scaled layout before things start overlapping. */
@media (max-width: 1199px) and (min-width: 769px) {
  #tw-devon-logo-float { top: 22px; left: 26px; }
  .tw-devon-logo-img { height: 42px; }
  #tw-logo-float { top: 28px; }
  .tw-logo-svg { height: 64px; }
  #tw-cta-btn    { top: 22px; right: 22px; height: 56px; padding: 0 24px; font-size: 13.5px; }
  #tw-cta-btn.tw-cta-offset { right: 82px; }

  #tw-property-info { top: 22px; left: 22px; padding: 9px 16px 10px; max-width: min(34vw, 320px); }
  .tw-property-name { font-size: 15px; }
  .tw-property-city { font-size: 9.5px; letter-spacing: 0.16em; }

  #tw-menu-bar   { bottom: calc(22px + env(safe-area-inset-bottom)); }
  .tw-menu-pill  { height: 64px; padding: 0 6px; }
  .tw-menu-btn   { padding: 0 18px; height: 50px; font-size: 14px; gap: 8px; }
  .tw-menu-sep   { height: 24px; margin: 0 2px; }
  #tw-aerial     { width: 56px; height: 50px; margin: 0 2px; }

  #tw-toast      { top: calc(100px + env(safe-area-inset-top)); left: 24px; max-width: min(42vw, 420px); }
  .tw-toast-label { font-size: clamp(16px, 2vw, 20px); letter-spacing: 0.16em; margin-bottom: 9px; }
  .tw-toast-room  { font-size: clamp(36px, 5vw, 54px); }
  .tw-toast-meta  { gap: 16px; margin-top: 12px; font-size: clamp(13px, 1.4vw, 17px); }

  #tw-map-card   { bottom: calc(52px + env(safe-area-inset-bottom)); right: 22px; width: 280px; }
  #tw-map        { height: 200px; }
}

/* Mobile — all phones (portrait & landscape) and small tablets ≤768px.
   Radical layout: toast moves to top, map collapses to a circle FAB,
   menu pill goes full-width across the bottom.
   Minimum readable sizes enforced throughout — no text below 15px. */
@media (max-width: 768px) {
  /* Property info top-left, agent logo hidden in-tour on mobile (it's
     shown prominently in the splash, so there's no value in repeating it
     here at the cost of a cramped top bar). Realtor button stays top-right.
     Devon mark is hidden too — splash carries it. */
  #tw-devon-logo-float { display: none; }
  #tw-logo-float { display: none; }

  /* Property info — top-left, sized so it never crowds the realtor button */
  #tw-property-info {
    top: 14px;
    left: 14px;
    padding: 8px 13px 9px;
    border-radius: 12px;
    max-width: calc(100vw - 86px); /* leave room for top-right realtor btn */
  }
  .tw-property-name { font-size: 14.5px; line-height: 1.18; }
  .tw-property-city { font-size: 9px; letter-spacing: 0.16em; margin-top: 3px; }

  /* CTA */
  #tw-cta-btn {
    top: 16px;
    right: 16px;
    height: 52px;
    min-width: 0;
    padding: 0 24px;
    font-size: 14px;
    letter-spacing: 0.12em;
  }
  #tw-cta-btn.tw-cta-offset { right: 66px; }

  /* Menu pill — full-width, generous touch targets, readable text */
  #tw-menu-bar   { bottom: calc(16px + env(safe-area-inset-bottom)); width: calc(100vw - 28px); display: flex; justify-content: center; left: 14px; right: 14px; transform: none; }
  .tw-menu-pill  { height: 66px; padding: 0 6px; max-width: 100%; }
  .tw-menu-btn   { padding: 0 18px; height: 54px; font-size: 15px; gap: 7px; letter-spacing: 0.04em; }
  .tw-menu-sep   { height: 24px; margin: 0 2px; }
  #tw-aerial     { width: 56px; height: 54px; margin: 0 2px; }
  .tw-menu-chevron { width: 12px; height: 12px; }
  .tw-menu-pill::-webkit-scrollbar { display: none; }

  /* Toast — top of screen, below the logo/CTA bar.
     Min sizes: label ≥16px, room name ≥38px, meta ≥15px. */
  #tw-toast       { top: calc(100px + env(safe-area-inset-top)); left: 18px; right: 18px; max-width: none; transform: translateY(-10px); }
  #tw-toast.tw-show { transform: translateY(0); }
  .tw-toast-label { font-size: 16px; letter-spacing: 0.16em; margin-bottom: 10px; }
  .tw-toast-room  { font-size: clamp(38px, 10vw, 56px); line-height: 1.0; }
  .tw-toast-meta  { flex-direction: row; align-items: flex-start; gap: 20px; margin-top: 12px; font-size: 15px; letter-spacing: 0.08em; }
  .tw-toast-meta-item { gap: 8px; align-items: flex-start; }
  .tw-toast-meta-icon svg { width: 24px !important; height: 24px !important; }

  /* Map card → circle FAB — tap opens fullscreen modal.
     Positioned above the pill (66px tall + 16px base + 12px gap = 94px) */
  #tw-map-card {
    bottom: calc(94px + env(safe-area-inset-bottom));
    right: 18px;
    left: auto;
    width: 62px;
    height: 62px;
    border-radius: 50%;
    padding: 0;
    overflow: hidden; /* clip any Mapbox overflow that could create ghost tap targets */
  }
  .tw-map-header-row { width: 100%; height: 100%; }
  .tw-map-header { width: 100%; height: 100%; padding: 0; gap: 0; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
  .tw-map-header-text { display: none; }
  #tw-map-expand { display: none; }
  .tw-map-header-icon { display: flex; align-items: center; justify-content: center; }
  .tw-map-header-icon svg { width: 24px !important; height: 24px !important; stroke-width: 2.2 !important; }

  /* Hide inline map body — circle tap opens modal */
  #tw-map-body { display: none; }
  #tw-map-chevron-btn { display: none; }

  /* Kill all Mapbox ctrl elements inside the hidden preview map so they
     can't generate ghost tap targets that accidentally open Mapbox links */
  #tw-map .mapboxgl-ctrl-container,
  #tw-map .mapboxgl-ctrl-attrib,
  #tw-map .mapboxgl-ctrl-logo {
    display: none !important;
    pointer-events: none !important;
  }

  /* Splash — readable minimums: subtext ≥17px, enter button ≥17px */
  .tw-splash-inner { padding: 36px 30px; }
  .tw-splash-wordmark-img { width: clamp(170px, 46vw, 260px); margin-bottom: 14px; }
  .tw-splash-sub { font-size: 17px; letter-spacing: 0.16em; margin-top: 14px; }
  .tw-splash-location { font-size: 16px; letter-spacing: 0.12em; margin-top: 12px; }
  .tw-splash-enter {
    margin-top: 24px;
    font-size: 17px;
    padding: 20px 44px;
    min-height: 64px;
    gap: 18px;
  }
  .tw-splash-arrow { width: 22px; height: 22px; }
  .tw-splash-rule { margin: 16px auto; }
  .tw-splash-devon-wrap { bottom: 28px; gap: 9px; }
  .tw-splash-devon-img { width: clamp(100px, 28vw, 140px); }

  /* Vignettes — top vignette must cover full toast area (~280px).
     Holds opacity longer so the room name text stays readable
     even on bright white panorama backgrounds. Multi-stop for smooth falloff. */
  #tw-vignette-top {
    height: 320px;
    background: linear-gradient(to bottom,
      rgba(10, 16, 24, 0.80) 0%,
      rgba(10, 16, 24, 0.72) 18%,
      rgba(10, 16, 24, 0.54) 38%,
      rgba(10, 16, 24, 0.28) 60%,
      rgba(10, 16, 24, 0.08) 80%,
      rgba(10, 16, 24, 0.01) 92%,
      transparent 100%
    );
  }
  #tw-vignette-bottom {
    height: 200px;
    background: linear-gradient(to top,
      rgba(10, 16, 24, 0.40) 0%,
      rgba(10, 16, 24, 0.30) 22%,
      rgba(10, 16, 24, 0.16) 48%,
      rgba(10, 16, 24, 0.05) 74%,
      transparent 100%
    );
  }
  /* Toast is at the top on mobile — bottom-left vignette not needed */
  #tw-vignette-toast { display: none; }

  /* Dropdowns — fixed to viewport so they're always screen-centred and layer
     over the map FAB circle.  position:fixed escapes the menu bar's stacking
     context (both elements are z-index:100, later DOM order wins otherwise).
     bottom value: 16px base + 66px pill height + 14px gap = 96px */
  .tw-dropdown {
    position: fixed !important;
    left: 14px !important;
    right: 14px !important;
    bottom: calc(96px + env(safe-area-inset-bottom)) !important;
    top: auto !important;
    max-width: none;
    min-width: 0;
    width: auto;
    z-index: 200 !important;
    transform: translateY(12px) !important;
    max-height: 46vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    border-radius: 20px;
  }
  .tw-dropdown.tw-open {
    transform: translateY(0) !important;
  }
  .tw-dropdown-item { padding: 14px 18px 14px 30px; font-size: 16px; }
  .tw-dropdown-item::before { left: 10px; }
}

/* Compact layout for very short screens (iPhone landscape, small phones) */
@media (max-height: 680px) {
  .tw-splash-wordmark-img { width: clamp(120px, 18vw, 180px); margin-bottom: 16px; }
  .tw-splash-rule  { margin: 18px auto; }
  #tw-map          { height: 135px; }
  .tw-splash-enter { margin-top: 24px; font-size: 15px; min-height: 54px; padding: 16px 36px; }
  /* Tighten menu bar on short landscape screens but keep text readable */
  #tw-menu-bar     { bottom: calc(10px + env(safe-area-inset-bottom)); }
  .tw-menu-pill    { height: 58px; }
  .tw-menu-btn     { height: 46px; font-size: 14px; }
  /* Reduce top vignette height in landscape so toast doesn't overlap panorama too much */
  #tw-vignette-top { height: 220px; }
}

/* ── VIEWER TOUCH HANDLING ───────────────────────────────────────────────── */
/* Prevent browser from intercepting touch gestures before Marzipano handles them.
   touch-action: none tells the browser "don't scroll/zoom — the JS owns this" so
   the touch drag reaches Marzipano cleanly on real mobile devices. */
#viewer { touch-action: none; }
/* Say "you can grab this and turn it" with the cursor, and only say "you are
   turning it" once a turn has really started (markViewerDragging in wrapper.js
   sets the body class after 4px of travel). Ported from the Devon skin,
   2026-10-01, so every tour reads the same. */
#viewer { cursor: grab !important; }
body.tw-viewer-dragging #viewer,
body.tw-viewer-dragging #viewer * { cursor: grabbing !important; }

/* ── HIDE NATIVE 3DVISTA LOAD BAR & PRELOADER ───────────────────────────── */
#viewer div[style*="height: 3px"][style*="z-index: 2"] { visibility: hidden !important; }
#preloadContainer { display: none !important; }

/* ── BRANDED LOAD INDICATOR ─────────────────────────────────────────────── */

#tw-loader {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 200;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.25s var(--tw-ease);
}

#tw-loader.tw-loader-active { opacity: 1; }
#tw-loader.tw-loader-done   { opacity: 0; transition: opacity 0.3s var(--tw-ease) 0.15s; }

.tw-loader-fill {
  width: 100%;
  height: 100%;
  transform-origin: left center;
  transform: scaleX(0);
  background: linear-gradient(90deg, rgba(var(--tw-gold-rgb), 0), var(--tw-gold) 30%, var(--tw-cream) 70%, rgba(var(--tw-cream-rgb),0));
  box-shadow: 0 0 12px rgba(var(--tw-line-rgb), 0.5);
}

/* ── MAP CARD — HEADER ROW WITH ICON BUTTONS ─────────────────────────────── */

.tw-map-header-row {
  display: flex;
  align-items: center;
}

.tw-map-header { flex: 1; }

.tw-map-iconbtn {
  flex-shrink: 0;
  width: 54px;
  height: 54px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  color: rgba(var(--tw-cream-rgb), 0.55);
  transition: color 0.18s, background 0.18s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.tw-map-iconbtn:hover       { color: var(--tw-gold); background: rgba(255, 255, 255, 0.04); }
.tw-map-iconbtn:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: -4px; }

.tw-map-chevron-btn .tw-map-chevron { color: inherit; }

#tw-map-card.tw-map-collapsed .tw-map-chevron-btn .tw-map-chevron {
  transform: rotate(180deg);
}

/* ── FULLSCREEN MAP MODAL ────────────────────────────────────────────────── */

#tw-map-modal {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 0.2s var(--tw-ease);
}

#tw-map-modal.tw-map-modal-hidden {
  opacity: 0;
  pointer-events: none;
}

.tw-map-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(var(--tw-navy-deep-rgb), 0.72);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  cursor: pointer;
}

.tw-map-modal-card {
  position: relative;
  width: 92vw;
  height: 88vh;
  max-width: 2100px;
  background: rgba(var(--tw-navy-deep-rgb), 0.95);
  border: 1px solid rgba(var(--tw-line-rgb), 0.2);
  border-radius: 24px;
  box-shadow: 0 30px 120px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(var(--tw-line-rgb), 0.06) inset;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transform: scale(1);
  transition: transform 0.2s var(--tw-ease);
}

#tw-map-modal.tw-map-modal-hidden .tw-map-modal-card {
  transform: scale(0.96);
}

.tw-map-modal-topbar {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 21px 27px;
  border-bottom: 1px solid rgba(var(--tw-line-rgb), 0.12);
  background: rgba(var(--tw-navy-deep-rgb), 0.4);
}

.tw-map-modal-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--tw-sans);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.55);
  flex-shrink: 0;
}

.tw-map-modal-title .tw-map-header-icon { color: var(--tw-gold); }

.tw-map-filter {
  display: flex;
  gap: 3px;
  padding: 4.5px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(var(--tw-line-rgb), 0.1);
  border-radius: 15px;
  flex: 1;
  max-width: 630px;
  overflow-x: auto;
}

.tw-map-filter-btn {
  flex: 1;
  padding: 9px 21px;
  background: transparent;
  border: none;
  border-radius: 10.5px;
  font-family: var(--tw-sans);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.5);
  cursor: pointer;
  touch-action: manipulation;
  transition: background 0.18s, color 0.18s;
  white-space: nowrap;
}

.tw-map-filter-btn:hover { color: rgba(var(--tw-cream-rgb), 0.85); }
.tw-map-filter-btn.tw-active {
  background: rgba(var(--tw-line-rgb), 0.16);
  color: var(--tw-gold);
}

.tw-map-modal-close {
  width: 54px;
  height: 54px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(var(--tw-line-rgb), 0.30);
  border-radius: 15px;
  cursor: pointer;
  color: var(--tw-gold);
  transition: background 0.18s, color 0.18s, border-color 0.18s;
  flex-shrink: 0;
  margin-left: auto;
  -webkit-tap-highlight-color: transparent;
}

.tw-map-modal-close:hover {
  color: var(--tw-cream);
  background: rgba(var(--tw-line-rgb), 0.12);
  border-color: rgba(var(--tw-line-rgb), 0.55);
}

.tw-map-modal-body {
  position: relative;
  flex: 1;
  min-height: 0;
}

#tw-map-modal-canvas {
  position: absolute;
  inset: 0;
  background: var(--tw-navy-deep);
}

#tw-map-modal-canvas .mapboxgl-ctrl-logo { opacity: 0.35; }
#tw-map-modal-canvas .mapboxgl-ctrl-attrib { font-size: 13.5px; opacity: 0.35; }

/* Modal map zoom controls — same branded dark glass as preview map */
#tw-map-modal-canvas .mapboxgl-ctrl-top-right > .mapboxgl-ctrl {
  margin: 8px 8px 0 0 !important;
}
#tw-map-modal-canvas .mapboxgl-ctrl-group {
  background: rgba(var(--tw-navy-deep-rgb), 0.88) !important;
  border: 1px solid rgba(var(--tw-line-rgb), 0.28) !important;
  border-radius: 10px !important;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45) !important;
  overflow: hidden;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
#tw-map-modal-canvas .mapboxgl-ctrl-group button {
  width: 34px !important;
  height: 34px !important;
  background: transparent !important;
  border: none !important;
  border-bottom: 1px solid rgba(var(--tw-line-rgb), 0.18) !important;
}
#tw-map-modal-canvas .mapboxgl-ctrl-group button:last-child {
  border-bottom: none !important;
}
#tw-map-modal-canvas .mapboxgl-ctrl-group button:hover {
  background: rgba(var(--tw-line-rgb), 0.14) !important;
}
#tw-map-modal-canvas .mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18'%3E%3Cpath d='M9 3v12M3 9h12' stroke='%23F4EDE5' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") !important;
}
#tw-map-modal-canvas .mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18'%3E%3Cpath d='M3 9h12' stroke='%23F4EDE5' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") !important;
}

.tw-map-layer-toggle {
  position: absolute;
  bottom: 27px;
  left: 27px;
  z-index: 5;
  display: flex;
  gap: 3px;
  padding: 4.5px;
  background: rgba(var(--tw-navy-deep-rgb), 0.88);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(var(--tw-line-rgb), 0.18);
  border-radius: 15px;
  box-shadow: 0 9px 36px rgba(0, 0, 0, 0.55);
}

.tw-map-layer-btn {
  padding: 9px 18px;
  background: transparent;
  border: none;
  border-radius: 10.5px;
  font-family: var(--tw-sans);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.55);
  cursor: pointer;
  touch-action: manipulation;
  transition: background 0.18s, color 0.18s;
}

.tw-map-layer-btn:hover        { color: rgba(var(--tw-cream-rgb), 0.85); }
.tw-map-layer-btn.tw-active    { background: rgba(var(--tw-line-rgb), 0.16); color: var(--tw-gold); }

.tw-map-loading {
  position: absolute;
  top: 27px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  padding: 12px 24px;
  background: rgba(var(--tw-navy-deep-rgb), 0.9);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(var(--tw-line-rgb), 0.2);
  border-radius: 1498.5px;
  font-family: var(--tw-sans);
  font-size: 15px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.7);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--tw-ease);
}

.tw-map-loading.tw-show { opacity: 1; }

/* ── POI MARKERS + POPUP ─────────────────────────────────────────────────── */

.tw-map-poi-chip {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: rgba(var(--tw-navy-deep-rgb), 0.92);
  border: 1.5px solid rgba(var(--tw-line-rgb), 0.5);
  border-radius: 50%;
  color: var(--tw-cream);
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45), 0 0 0 1.5px rgba(255, 255, 255, 0.10);
  transition: transform 0.15s var(--tw-ease), border-color 0.18s, color 0.18s, background 0.18s;
}

.tw-map-poi-chip:hover {
  transform: scale(1.18);
  border-color: var(--tw-gold);
  background: rgba(var(--tw-navy-deep-rgb), 0.98);
  color: var(--tw-gold);
}

.tw-map-pin-large {
  width: 22px !important;
  height: 22px !important;
  border: 3px solid white !important;
  box-shadow: 0 0 0 6px rgba(var(--tw-line-rgb), 0.5), 0 0 0 12px rgba(var(--tw-line-rgb), 0.18), 0 4px 18px rgba(0, 0, 0, 0.45);
  animation: tw-pin-pulse 2.2s ease-in-out infinite;
}

/* Aerial (drone) pin — gold-filled square with drone icon + numeric badge */
.tw-map-aerial-pin {
  position: relative;
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--tw-gold);
  border: 1.5px solid rgba(var(--tw-navy-deep-rgb), 0.9);
  border-radius: 12px;
  color: var(--tw-navy-deep, #0b1520);
  cursor: pointer;
  box-shadow: 0 6px 21px rgba(0, 0, 0, 0.7), 0 0 0 4.5px rgba(var(--tw-line-rgb), 0.18);
  transition: transform 0.18s var(--tw-ease), box-shadow 0.18s;
}

.tw-map-aerial-pin:hover {
  transform: scale(1.12);
  box-shadow: 0 9px 27px rgba(0, 0, 0, 0.75), 0 0 0 7.5px rgba(var(--tw-line-rgb), 0.32);
}

.tw-map-aerial-num {
  position: absolute;
  top: -9px;
  right: -9px;
  min-width: 24px;
  height: 24px;
  padding: 0 6px;
  font: 700 15px/24px var(--tw-sans);
  color: var(--tw-gold);
  background: rgba(var(--tw-navy-deep-rgb), 0.96);
  border: 1px solid var(--tw-gold);
  border-radius: 15px;
  text-align: center;
  box-sizing: border-box;
}

@keyframes tw-pin-pulse {
  0%, 100% { box-shadow: 0 0 0 9px rgba(var(--tw-line-rgb), 0.28), 0 6px 24px rgba(0, 0, 0, 0.65); }
  50%      { box-shadow: 0 0 0 21px rgba(var(--tw-line-rgb), 0.05), 0 6px 24px rgba(0, 0, 0, 0.65); }
}

.tw-map-popup-wrap .mapboxgl-popup-content {
  background: rgba(var(--tw-navy-deep-rgb), 0.96);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  border: 1px solid rgba(var(--tw-line-rgb), 0.25);
  border-radius: 15px;
  padding: 15px 21px;
  box-shadow: 0 15px 60px rgba(0, 0, 0, 0.6);
  color: var(--tw-cream);
}

.tw-map-popup-wrap .mapboxgl-popup-tip { display: none; }

.tw-map-poi-popup .tw-map-poi-cat {
  font-family: var(--tw-sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--tw-gold);
}

.tw-map-poi-popup .tw-map-poi-name {
  font-family: var(--tw-serif);
  font-size: 24px;
  font-weight: 400;
  color: var(--tw-cream);
  margin-top: 3px;
  line-height: 1.25;
  max-width: 330px;
}

.tw-map-poi-popup .tw-map-poi-dist {
  font-family: var(--tw-sans);
  font-size: 15px;
  color: rgba(var(--tw-cream-rgb), 0.55);
  margin-top: 6px;
}

/* Prevent body scroll while modal is open */
body.tw-modal-open { overflow: hidden; }

/* ── RESPONSIVE — MODAL ──────────────────────────────────────────────────── */

@media (max-width: 768px) {
  /* Map modal — full bleed */
  .tw-map-modal-card {
    width: 100vw;
    height: 100dvh;
    max-width: none;
    border-radius: 0;
  }
  .tw-map-modal-topbar {
    flex-wrap: wrap;
    gap: 12px;
    padding: calc(12px + env(safe-area-inset-top)) 16px 12px;
  }
  .tw-map-modal-title { order: 1; flex: 1; font-size: 12px; gap: 8px; min-width: 0; }
  .tw-map-modal-title span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tw-map-modal-close { order: 2; width: 44px; height: 44px; }
  .tw-map-filter { order: 3; flex-basis: 100%; max-width: none; }
  .tw-map-filter-btn { padding: 9px 14px; font-size: 12.5px; }
  .tw-map-layer-toggle { bottom: calc(18px + env(safe-area-inset-bottom)); left: 18px; padding: 4px; }
  .tw-map-layer-btn { padding: 8px 14px; font-size: 12.5px; }
  .tw-map-popup-wrap .mapboxgl-popup-content { max-width: calc(100vw - 60px); }
  .tw-map-poi-popup .tw-map-poi-name { font-size: 19px; max-width: 240px; }

}

/* ── PANO-ANCHORED HOTSPOT OVERLAY ───────────────────────────────────────── */

#tw-hotspot-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 120;
  overflow: hidden;
}

.tw-hotspot-pin {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  pointer-events: auto;
  cursor: default;
  opacity: 0;
  transition: opacity 0.18s var(--tw-ease);
  user-select: none;
  transform: translate(-14998.5px, -14998.5px);
}

.tw-hotspot-dot {
  width: 21px;
  height: 21px;
  border-radius: 50%;
  background: var(--tw-gold);
  border: 2px solid rgba(var(--tw-navy-deep-rgb), 0.92);
  box-shadow: 0 0 0 6px rgba(var(--tw-line-rgb), 0.22),
    0 6px 18px rgba(0, 0, 0, 0.55);
  animation: tw-hotspot-pulse 2.6s ease-in-out infinite;
}

@keyframes tw-hotspot-pulse {
  0%, 100% { box-shadow: 0 0 0 6px rgba(var(--tw-line-rgb), 0.22), 0 6px 18px rgba(0, 0, 0, 0.55); }
  50%      { box-shadow: 0 0 0 12px rgba(var(--tw-line-rgb), 0.05), 0 6px 18px rgba(0, 0, 0, 0.55); }
}

.tw-hotspot-label {
  font-family: var(--tw-sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--tw-cream, #f4ece0);
  background: rgba(var(--tw-navy-deep-rgb), 0.78);
  border: 1px solid rgba(var(--tw-line-rgb), 0.32);
  padding: 6px 12px;
  border-radius: 6px;
  white-space: nowrap;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 6px 21px rgba(0, 0, 0, 0.45);
}

/* ── REDUCED MOTION ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .tw-splash-wordmark-img,
  .tw-splash-sub,
  .tw-splash-rule,
  .tw-splash-location,
  .tw-splash-enter {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .tw-ui-el,
  #tw-toast,
  .tw-dropdown,
  .tw-splash-enter,
  .tw-menu-chevron,
  #tw-map-body,
  .tw-map-chevron,
  #tw-loader,
  .tw-loader-fill,
  #tw-map-modal,
  .tw-map-modal-card,
  .tw-map-poi-chip,
  .tw-map-pin-large,
  .tw-map-aerial-pin,
  .tw-hotspot-pin,
  .tw-hotspot-dot { transition: none; animation: none; }
  .tw-loader-fill { transform: scaleX(1); }
}

/* ── Marzipano link hotspots ────────────────────────────────────────────── */
/* ── PANO ZOOM CONTROLS ──────────────────────────────────────────────────── */
.tw-pano-zoom-ctrl {
  position: fixed;
  top: 50%;
  right: 16px;
  transform: translateY(-50%);
  z-index: 50;
  display: flex;
  flex-direction: column;
  background: rgba(var(--tw-navy-deep-rgb), 0.88);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.28);
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  overflow: hidden;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.tw-pano-zoom-btn {
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  color: var(--tw-cream); /* zoom SVGs use currentColor */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.tw-pano-zoom-btn:first-child {
  border-bottom: 1px solid rgba(var(--tw-gold-rgb), 0.18);
}
.tw-pano-zoom-btn:hover { background: rgba(var(--tw-gold-rgb), 0.14); }
.tw-pano-zoom-btn:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: -2px; }
.tw-pano-zoom-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.tw-pano-zoom-btn:disabled:hover { background: transparent; }

/* Modal floorplan zoom: always visible (not hover-gated) */
.tw-plan-zoom-ctrl-modal {
  opacity: 1 !important;
  pointer-events: auto !important;
  top: 12px;
  right: 12px;
}
/* The enlarged plan fills the body it is given (see .tw-plan-modal-stage below),
   so the plan can never overflow the card and the zoomed plan is clipped here. */
.tw-plan-modal-zoom-layer {
  position: relative;
  margin: auto;
  aspect-ratio: var(--tw-plan-ar, 4 / 3);
  transform-origin: center center;
  transition: transform 0.18s ease;
  touch-action: none;
}

/* IMPORTANT: never put `transition: transform` on .tw-hs — Marzipano writes
   the element's transform every frame to position the hotspot, and a CSS
   transition tweens those writes into a laggy follow while the pano is
   dragged. Hover effects belong on the inner elements. will-change keeps the
   hotspot on its own compositor layer. */
.tw-hs {
  position: relative;
  /* The BOX is the hit area and the ring is drawn inside it, so the trigger can
     grow without the marker changing size (see .tw-hs-ring's inset). Widened
     from 56px to 78px to match the Devon skin (Danny, 2026-09-25: "the user
     doesn't have to be so accurate with their mouse placement"). */
  width: 78px;
  height: 78px;
  background: transparent;
  border: 0;
  padding: 0;
  margin-left: -39px;
  margin-top: -39px;
  cursor: pointer;
  font: inherit;
  color: var(--tw-cream);
  pointer-events: auto;
  outline: none;
  will-change: transform;
}
.tw-hs:focus-visible {
  outline: 2px solid var(--tw-gold);
  outline-offset: 4px;
  border-radius: 50%;
}
.tw-hs-ring {
  position: absolute;
  /* Pulled in from the edge of the 56px box, so the ring sits nearer the centre
     dot it is read against. Danny, 2026-09-19: "I feel like the rings need to be
     closer to the dot, or the dot needs to be a bit bigger, without changing the
     overall size of the hotspot in the tour, because it looks like the right
     size right now." The BOX is the hotspot's size (56px, and the hit area), so
     none of this moves anything in the room: the ring came in 4px and the dot
     grew, which halves the empty gap between them. The pulse below starts from
     the same inset and reaches the same outer diameter it always did. */
  /* 15px inside a 78px box keeps the ring the 48px it has always been drawn at
     (the box grew, the marker did not). */
  inset: 15px;
  border-radius: 50%;
  border: 3px solid rgba(var(--tw-cream-rgb), 0.74);
  background: transparent;
  /* The ring has to hold its edge on a white wall and on a pale floor as well
     as on a dark one (the 3DVista reference is white on a dark floor; this
     tour is white rings on light oak). The shadow does the contrasting, so the
     ring itself can stay neutral instead of carrying a dark fill. */
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.55));
  transition: border-color 0.24s var(--tw-ease), transform 0.24s var(--tw-ease);
  animation: tw-hs-swell 2.6s cubic-bezier(0.3, 0.6, 0.25, 1) infinite;
}
.tw-hs:hover .tw-hs-ring,
.tw-hs:focus-visible .tw-hs-ring {
  border-color: var(--tw-gold);
}
/* The floating ring turns accent AND scales together (Devon: "so it feels more
   graceful"). Scoped to the floating kind on purpose: the player's own page CSS
   (viewer/index.html) gives a FLOOR marker a 1.22 hover that is meant to land
   bigger than its approach ramp, and an unscoped rule here wins that tie on
   load order and would shrink it to 1.08. */
.tw-hs:not(.tw-hs-floor):hover .tw-hs-ring,
.tw-hs:not(.tw-hs-floor):focus-visible .tw-hs-ring {
  transform: scale(1.08);
}
/* …and the centre dot takes the accent with it, so hover lights the whole
   marker instead of leaving a white dot inside an accent ring (Danny,
   2026-09-19: "the floating hotspot has a dot in the middle of it. This should
   change to the accent colour when hovered over, not just the outer ring.").
   A media chip is a white tile carrying a glyph, not a centre dot, so it is
   excluded and keeps its own hover. */
.tw-hs:hover .tw-hs-dot:not(.tw-hs-glyph),
.tw-hs:focus-visible .tw-hs-dot:not(.tw-hs-glyph) {
  background: var(--tw-gold);
}
/* No hover variable any more: the swell animates `inset` and hover animates
   `transform`, so neither can stomp the other. They simply compose. */

/* ── The floating marker's loop ─────────────────────────────────────────────
   Two motions on one beat, chosen by Danny from the six drawn on the review page
   ("I like the swell"):

     tw-hs-swell  the ring itself breathes outwards and settles back
     tw-hs-ping   a pulse is born AT the ring's radius and only ever leaves it

   The swell is what makes the whole marker one outward gesture rather than a
   still ring with something moving past it. Cycle 2.6s: ~1.7s of travel, then a
   beat of nothing.

   The three rules the earlier passes settled on, all still true: one pulse per
   cycle so two rings never cross; born at the ring's own radius so nothing
   grows THROUGH it; and thinning as it goes (3px → 0.7px) so the outer edge is
   the faint one. */
@keyframes tw-hs-swell {
  0%, 100% { inset: 15px; border-width: 3px; }
  18%      { inset: 13.4px; border-width: 3.4px; }
  46%      { inset: 15px; border-width: 3px; }
}
@keyframes tw-hs-ping {
  0%   { transform: scale(1);    opacity: 0;    border-width: 3px; }
  10%  { opacity: 0.5; }
  65%  { opacity: 0.16; }
  100% { transform: scale(2.16); opacity: 0;    border-width: 0.7px; }
}
.tw-hs-ping {
  position: absolute;
  inset: 15px;                /* the same box as the ring, so the beat matches */
  border-radius: 50%;
  border: 3px solid rgba(var(--tw-cream-rgb), 0.9);
  /* The dark backing stroke rides with it, so the pulse stays legible on a
     white wall as well as on a dark one. */
  box-shadow: 0 0 0 1px rgba(12, 18, 26, 0.22);
  animation: tw-hs-ping 2.6s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
}
/* The centre the pulse comes out of. Static on purpose: it is the anchor the
   motion reads against, so it has to sit still. Bigger since 2026-09-19 so it
   holds its own against the ring. */
.tw-hs-dot {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: rgba(var(--tw-cream-rgb), 0.92);
  box-shadow: 0 0 0 1px rgba(12, 18, 26, 0.28);
  /* The ring eases into its accent on the same beat, so the two arrive
     together instead of the dot snapping ahead of the ring. */
  transition: background-color 0.18s var(--tw-ease);
}
@media (prefers-reduced-motion: reduce) {
  .tw-hs-ring { animation: none; }
  .tw-hs-ping { animation: none; opacity: 0; }
}
.tw-hs-label {
  position: absolute;
  left: 50%;
  top: calc(100% + 10px);
  transform: translateX(-50%);
  font-family: var(--tw-sans);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--tw-cream);
  background: rgba(var(--tw-navy-deep-rgb), 0.86);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.24);
  padding: 5px 11px;
  border-radius: 100px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--tw-ease);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
/* No text over a walk hotspot, floor or floating (Danny, 2026-09-19): the name
   is another per-tour variable to get right, and a ring reads as "go here" on
   its own. The element still carries an aria-label for screen readers.
   Info/media hotspots keep their title chip — they are not navigation. */

/* In-pano info/media hotspots (M6): a chip with a type glyph instead of a dot,
   because they are not navigation. Titles show on hover. */
a.tw-hs { display: block; text-decoration: none; }
.tw-hs-media .tw-hs-dot {
  width: 24px;
  height: 24px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--tw-sans);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  color: var(--tw-navy-deep);
  background: var(--tw-cream);
  box-shadow: 0 0 12px rgba(var(--tw-cream-rgb), 0.45);
}
.tw-hs-media .tw-hs-label { display: block; }
.tw-hs-media:hover .tw-hs-label,
.tw-hs-media:focus-visible .tw-hs-label { opacity: 1; }
/* Link hotspots are skipped at render time in unbranded (MLS) mode; this is
   the belt-and-braces guard in case that ever drifts. */
.tw-unbranded .tw-hs-link { display: none !important; }


/* ── Floor hotspots — the parallax "click and go" marker ───────────────────
   3DVista's flat hotspots are rings lying on the ground rather than rings
   hanging at eye level, so the visitor clicks the marker on the floor to walk
   somewhere. The player does the geometry (floorHotspotOptions in
   preview/index.html and viewer/index.html): the marker is placed with
   Marzipano's 3D matrix, tilted to 90deg - its own pitch so the surface is
   level, at a distance that makes it grow and shrink with the zoom the way a
   real object does.

   So there is NO squash and no fill in here: the foreshortening is real (a ring
   on a floor is an ellipse from head height and a circle when you look down at
   it), and the skin draws exactly the same ring as every other hotspot. The
   box is the marker's size in the room; how big that reads on screen is the
   placement's business, not CSS's. */
.tw-hs-floor {
  /* Square, and centred by Marzipano's own 3D transform (it carries the
     translate(-50%, -50%)), so no negative margins here, unlike every other
     .tw-hs. This is the marker's size IN THE ROOM: the placement magnifies it
     by 1/near, so the same box draws bigger when the link's neighbour is close
     and smaller when it is far away, and it grows with the zoom. */
  /* Widened 26px -> 44px with the ring pulled in to 16% so the DRAWN ring is
     the same 30px it always was (44 - 2x7.04 = 29.9). The box is invisible, so
     this buys target area and nothing else. Matches the Devon skin. */
  width: 44px;
  height: 44px;
  margin: 0;
}
.tw-hs-floor .tw-hs-ring {
  inset: 16%;              /* draws the same ring the old -8% of 26px did */
  /* Thicker than the floating ring, in the room's own units, so it survives
     the foreshortening that flattens it into an ellipse. */
  border-width: 2.2px;
  /* No swell here. The loop belongs to the marker that floats in front of the
     room; a marker lying in the room is still (see the rule in the floating
     block), and on the floor the breathing would read as the ring wandering. */
  animation: none;
}

/* ── Oriented hotspots — the general 3D plane ──────────────────────────────
   A link carrying an `orient` object is a plane the author aims at a surface:
   a door's face, a wall, the ground (see orientPlacement in
   preview/index.html and viewer/index.html). Same ring, no pulse — the rule is
   "in the room, still; floating, animated" — so all this class has to do is
   take the centring back off Marzipano's transform, exactly like the floor
   marker above.

   The box stays at the floating marker's 56px because an oriented hotspot sits
   at the SAME depth as an ordinary one by default (distance 1.0 = the
   projection distance), so it draws at its natural size and only the plane's
   angle changes. Pulling the distance slider down is what makes it grow and
   start to slide as the visitor turns. */
.tw-hs-3d {
  margin: 0;
}
/* ...and it is still: it is a thing lying in the room, not a marker floating in
   front of it, so it takes no part in the floating marker's loop. */
.tw-hs-3d .tw-hs-ring { animation: none; }

/* The one global hotspot popup (wrapper.js owns it; above UI, below splash) */
#tw-hs-popup-wrap { position: fixed; inset: 0; z-index: 200; display: none; }
#tw-hs-popup-wrap.tw-hs-popup-open { display: block; }
#tw-hs-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(var(--tw-navy-deep-rgb), 0.62);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
#tw-hs-popup {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(520px, 92vw);
  max-height: 84vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--tw-navy);
  color: var(--tw-cream);
  border: 1px solid rgba(var(--tw-cream-rgb), 0.12);
  border-radius: 16px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
  animation: tw-hs-popup-in 0.22s var(--tw-ease);
}
html.tw-v-cards-sharp #tw-hs-popup { border-radius: 4px; }
@keyframes tw-hs-popup-in {
  from { opacity: 0; transform: translate(-50%, -48%); }
  to   { opacity: 1; transform: translate(-50%, -50%); }
}
#tw-hs-popup-close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: rgba(var(--tw-navy-deep-rgb), 0.75);
  color: var(--tw-cream);
  font: 400 20px/1 var(--tw-sans);
  cursor: pointer;
}
#tw-hs-popup-close:hover { background: rgba(var(--tw-navy-deep-rgb), 0.95); }
#tw-hs-popup-media:empty { display: none; }
#tw-hs-popup-media img,
#tw-hs-popup-media video {
  display: block;
  width: 100%;
  max-height: 60vh;
  object-fit: contain;
  background: var(--tw-navy-deep);
  border-radius: 16px 16px 0 0;
}
html.tw-v-cards-sharp #tw-hs-popup-media img,
html.tw-v-cards-sharp #tw-hs-popup-media video { border-radius: 4px 4px 0 0; }
#tw-hs-popup-text { padding: 18px 22px 20px; }
#tw-hs-popup-title {
  margin: 0 0 6px;
  font-family: var(--tw-serif);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
#tw-hs-popup-body {
  margin: 0;
  font-family: var(--tw-sans);
  font-size: 13.5px;
  line-height: 1.65;
  color: rgba(var(--tw-cream-rgb), 0.85);
  white-space: pre-wrap;
}

/* ── FLOATING FLOORPLAN CARD ─────────────────────────────────────────────── */
/* Floorplan card — sized + styled to mirror #tw-map-card exactly. */
#tw-plan-card {
  position: fixed;
  bottom: 42px;
  left: 36px;
  z-index: 100;
  width: 340px;
  border-radius: 24px;
  overflow: hidden;
  border: 1px solid rgba(var(--tw-gold-rgb), 0.2);
  box-shadow: 0 12px 60px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(var(--tw-gold-rgb), 0.06) inset;
  background: rgba(var(--tw-navy-deep-rgb), 0.9);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  transition-delay: 0.3s;
}
.tw-plan-header-row {
  display: flex;
  align-items: center;
}
.tw-plan-header {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
  padding: 16.5px 21px;
  background: transparent;
  border: none;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.18s;
}
.tw-plan-header:hover { background: rgba(255, 255, 255, 0.08); }
.tw-plan-header:hover .tw-plan-header-text { color: rgba(var(--tw-cream-rgb), 0.95); }
.tw-plan-header:hover .tw-plan-header-icon { filter: brightness(1.25); }
.tw-plan-header:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: -2px; }
.tw-plan-header-icon {
  color: var(--tw-gold);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  transition: filter 0.18s;
}
.tw-plan-header-text {
  font-family: var(--tw-sans);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.72);
  flex: 1;
  text-align: left;
  transition: color 0.18s;
}
/* Icon buttons in the header row — same dims as .tw-map-iconbtn */
.tw-plan-iconbtn {
  flex-shrink: 0;
  width: 54px;
  height: 54px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  color: rgba(var(--tw-cream-rgb), 0.55);
  transition: color 0.18s, background 0.18s, transform 0.28s var(--tw-ease);
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.tw-plan-iconbtn:hover       { color: var(--tw-gold); background: rgba(255, 255, 255, 0.04); }
.tw-plan-iconbtn:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: -4px; }
/* #tw-plan-expand carries two glyphs and CSS picks one (see the phone block
   below): the expand arrows wherever the card is a mini viewer, the floorplan
   mark where the circle is the control. */
.tw-plan-expand-glyph { display: inline-flex; align-items: center; justify-content: center; }
.tw-plan-expand-plan { display: none; }
.tw-plan-chevron-btn .tw-plan-chevron { color: inherit; transition: transform 0.28s var(--tw-ease); }
#tw-plan-card.tw-plan-collapsed .tw-plan-chevron-btn .tw-plan-chevron { transform: rotate(180deg); }

#tw-plan-body {
  max-height: 450px;
  overflow: hidden;
  transition: max-height 0.3s var(--tw-ease);
  border-top: 1px solid rgba(var(--tw-gold-rgb), 0.08);
}
#tw-plan-card.tw-plan-collapsed #tw-plan-body { max-height: 0; border-top-color: transparent; }

.tw-plan-tabs {
  display: flex;
  gap: 2px;
  padding: 8px 8px 0;
  flex-wrap: wrap;
}
.tw-plan-tab {
  font-family: var(--tw-sans);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 10px;
  border-radius: 100px;
  background: transparent;
  border: 1px solid rgba(var(--tw-gold-rgb), 0.15);
  color: rgba(var(--tw-cream-rgb), 0.55);
  cursor: pointer;
  transition: all 0.15s ease;
}
.tw-plan-tab:hover { color: var(--tw-cream); border-color: rgba(var(--tw-gold-rgb), 0.4); }
.tw-plan-tab-active {
  background: rgba(var(--tw-gold-rgb), 0.18);
  border-color: rgba(var(--tw-gold-rgb), 0.55);
  color: var(--tw-cream);
}

.tw-plan-stage {
  position: relative;
  width: calc(100% - 24px);
  margin: 10px 12px 14px;
  background: rgba(var(--tw-cream-rgb), 0.04);
  border-radius: 8px;
  border: 1px solid rgba(var(--tw-gold-rgb), 0.08);
  overflow: hidden;
}
.tw-plan-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  filter: invert(1) hue-rotate(180deg) brightness(1.1) contrast(0.95);
  opacity: 0.86;
  user-select: none;
  pointer-events: none;
  -webkit-user-drag: none;
}
/* The plan box: sized in px by fitPlanBox() in wrapper.js, so the image and the
   marker layer are always the identical rectangle. The aspect-ratio custom
   property is the pre-JS fallback and keeps the box from collapsing if the fit
   has not run yet (or the JS never loads). */
.tw-plan-zoom-layer {
  position: relative;
  width: 100%;
  margin: 0 auto;
  aspect-ratio: var(--tw-plan-ar, 4 / 3);
  transform-origin: center center;
  transition: transform 0.2s var(--tw-ease);
  cursor: default;
  touch-action: none;
}
.tw-plan-zoom-layer[data-scale]:not([data-scale="1"]) { cursor: grab; }
.tw-plan-zoom-layer.tw-plan-panning { cursor: grabbing; transition: none; }

.tw-plan-zoom-ctrl {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  background: rgba(var(--tw-navy-deep-rgb), 0.88);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.28);
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  overflow: hidden;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--tw-ease);
}
.tw-plan-stage:hover .tw-plan-zoom-ctrl,
.tw-plan-zoom-ctrl:focus-within {
  opacity: 1;
  pointer-events: auto;
}
.tw-plan-zoom-btn {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  color: var(--tw-cream); /* zoom SVGs use currentColor */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.tw-plan-zoom-btn:first-child {
  border-bottom: 1px solid rgba(var(--tw-gold-rgb), 0.18);
}
.tw-plan-zoom-btn:hover { background: rgba(var(--tw-gold-rgb), 0.14); }
.tw-plan-zoom-btn:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: -2px; }
.tw-plan-zoom-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.tw-plan-zoom-btn:disabled:hover { background: transparent; }

.tw-plan-markers {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.tw-plan-marker {
  position: absolute;
  width: 0;
  height: 0;
  pointer-events: auto;
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 0;
  transition: left 0.35s var(--tw-ease), top 0.35s var(--tw-ease);
}
.tw-plan-dot {
  position: absolute;
  top: 0; left: 0;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--tw-gold);
  border: 1.5px solid rgba(var(--tw-cream-rgb), 0.95);
  box-shadow: 0 0 0 3px rgba(var(--tw-gold-rgb), 0.18), 0 1px 4px rgba(0,0,0,0.55);
  transform: translate(-50%, -50%);
  transition: width 0.18s, height 0.18s, box-shadow 0.18s;
}
.tw-plan-marker:hover .tw-plan-dot {
  width: 15px; height: 15px;
  box-shadow: 0 0 0 5px rgba(var(--tw-gold-rgb), 0.28), 0 2px 6px rgba(0,0,0,0.6);
}
.tw-plan-marker-active .tw-plan-dot {
  width: 17px;
  height: 17px;
  background: var(--tw-cream);
  border-color: var(--tw-gold);
  box-shadow: 0 0 0 4px rgba(var(--tw-gold-rgb), 0.32), 0 2px 8px rgba(0,0,0,0.55);
}
.tw-plan-cone {
  position: absolute;
  top: 0; left: 0;
  width: 50px;
  height: 56px;
  background: radial-gradient(ellipse at 50% 100%, rgba(var(--tw-gold-rgb), 0.6) 0%, rgba(var(--tw-gold-rgb), 0.18) 40%, transparent 75%);
  clip-path: polygon(50% 100%, 0% 0%, 100% 0%);
  transform-origin: 50% 100%;
  transform: translate(-50%, -100%);
  pointer-events: none;
}

/* Tour Start marker — distinct green-tinted ring */
.tw-plan-marker-start .tw-plan-dot {
  background: #5cdb7e;
  border-color: rgba(255, 255, 255, 0.95);
  box-shadow: 0 0 0 3px rgba(92, 219, 126, 0.25), 0 1px 4px rgba(0,0,0,0.55);
}
.tw-plan-marker-start.tw-plan-marker-active .tw-plan-dot {
  background: #5cdb7e;
  border-color: #fff;
  box-shadow: 0 0 0 4px rgba(92, 219, 126, 0.35), 0 2px 8px rgba(0,0,0,0.55);
}
.tw-plan-start-label {
  position: absolute;
  top: 10px; left: 50%;
  transform: translateX(-50%);
  font-family: var(--tw-sans);
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #5cdb7e;
  white-space: nowrap;
  pointer-events: none;
  text-shadow: 0 1px 3px rgba(0,0,0,0.8);
}

/* ── FULLSCREEN FLOORPLAN MODAL — mirrors #tw-map-modal ─────────────────── */
#tw-plan-modal {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 0.2s var(--tw-ease);
}
#tw-plan-modal.tw-plan-modal-hidden {
  opacity: 0;
  pointer-events: none;
}
/* 2026-09-28: same click-through fix as the devon skin's wrapper.css
   (T-20260928-01 QA). .tw-plan-marker sets pointer-events:auto explicitly, so
   the container's pointer-events:none above doesn't reach it — the dots stay
   clickable while the modal is closed. Pin it to the same hidden state. */
#tw-plan-modal.tw-plan-modal-hidden .tw-plan-marker { pointer-events: none !important; }
.tw-plan-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(var(--tw-navy-deep-rgb), 0.72);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  cursor: pointer;
}
.tw-plan-modal-card {
  position: relative;
  width: 92vw;
  height: 88vh;
  max-width: 2100px;
  background: rgba(var(--tw-navy-deep-rgb), 0.95);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.2);
  border-radius: 24px;
  box-shadow: 0 30px 120px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(var(--tw-gold-rgb), 0.06) inset;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transform: scale(1);
  transition: transform 0.2s var(--tw-ease);
}
#tw-plan-modal.tw-plan-modal-hidden .tw-plan-modal-card { transform: scale(0.96); }
.tw-plan-modal-topbar {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 21px 27px;
  border-bottom: 1px solid rgba(var(--tw-gold-rgb), 0.12);
  background: rgba(var(--tw-navy-deep-rgb), 0.4);
}
.tw-plan-modal-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--tw-sans);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.55);
  flex-shrink: 0;
}
.tw-plan-modal-title .tw-plan-header-icon { color: var(--tw-gold); }
/* Floor filter pills in modal — mirrors .tw-map-filter */
.tw-plan-filter {
  display: flex;
  gap: 3px;
  padding: 4.5px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.1);
  border-radius: 15px;
  flex: 1;
  max-width: 630px;
  overflow-x: auto;
}
.tw-plan-filter-btn {
  flex: 1;
  padding: 9px 21px;
  background: transparent;
  border: none;
  border-radius: 10.5px;
  font-family: var(--tw-sans);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.5);
  cursor: pointer;
  touch-action: manipulation;
  transition: background 0.18s, color 0.18s;
  white-space: nowrap;
}
.tw-plan-filter-btn:hover { color: rgba(var(--tw-cream-rgb), 0.85); }
.tw-plan-filter-btn.tw-active {
  background: rgba(var(--tw-gold-rgb), 0.16);
  color: var(--tw-gold);
}
.tw-plan-modal-close {
  width: 54px;
  height: 54px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(var(--tw-gold-rgb), 0.30);
  border-radius: 15px;
  cursor: pointer;
  color: var(--tw-gold);
  transition: background 0.18s, color 0.18s, border-color 0.18s;
  flex-shrink: 0;
  margin-left: auto;
  -webkit-tap-highlight-color: transparent;
}
.tw-plan-modal-close:hover {
  color: var(--tw-cream);
  background: rgba(var(--tw-gold-rgb), 0.12);
  border-color: rgba(var(--tw-gold-rgb), 0.55);
}
.tw-plan-modal-body {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 36px;
  background: rgba(var(--tw-navy-deep-rgb), 0.55);
}
.tw-plan-modal-stage {
  position: relative;
  /* Grows into whatever the modal body has left after the topbar, so the plan
     fits on both axes at any window size and can never overflow the card. */
  flex: 1 1 auto;
  align-self: stretch;
  min-width: 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.tw-plan-modal-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  filter: invert(1) hue-rotate(180deg) brightness(1.1) contrast(0.95);
  opacity: 0.92;
  user-select: none;
  pointer-events: none;
  -webkit-user-drag: none;
}
.tw-plan-modal-markers {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* ── REALTOR BUTTON + POPUP ──────────────────────────────────────────────── */
#tw-realtor-btn {
  position: fixed;
  top: 22px;
  right: 22px;
  z-index: 110;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid rgba(var(--tw-gold-rgb), 0.35);
  background: rgba(var(--tw-navy-deep-rgb), 0.84);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  color: var(--tw-cream);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 20px rgba(0,0,0,0.45);
  transition: all 0.2s var(--tw-ease);
}
#tw-realtor-btn:hover {
  background: rgba(var(--tw-navy-deep-rgb), 0.92);
  border-color: var(--tw-gold);
  color: var(--tw-gold);
  transform: scale(1.05);
}
#tw-realtor-btn:focus-visible { outline: 2px solid var(--tw-gold); outline-offset: 3px; }

#tw-realtor-popup {
  position: fixed;
  top: 78px;
  right: 22px;
  z-index: 111;
  width: 300px;
  padding: 22px 22px 18px;
  background: rgba(var(--tw-navy-deep-rgb), 0.94);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.22);
  border-radius: 16px;
  box-shadow: 0 12px 50px rgba(0, 0, 0, 0.6), 0 0 0 0.5px rgba(var(--tw-gold-rgb), 0.06) inset;
  color: var(--tw-cream);
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.22s var(--tw-ease), transform 0.22s var(--tw-ease);
}
#tw-realtor-popup.tw-realtor-hidden {
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;
}
.tw-realtor-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 30px;
  height: 30px;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: rgba(var(--tw-cream-rgb), 0.45);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s;
}
.tw-realtor-close:hover { color: var(--tw-cream); background: rgba(255,255,255,0.04); }
.tw-realtor-name {
  font-family: var(--tw-serif);
  font-size: clamp(22px, 1.6vw, 26px);
  font-weight: 400;
  margin-bottom: 16px;
  letter-spacing: 0.02em;
}
.tw-realtor-rows {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 14px;
}
.tw-realtor-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  font-family: var(--tw-sans);
  font-size: 12px;
  color: rgba(var(--tw-cream-rgb), 0.78);
  text-decoration: none;
  transition: all 0.15s;
}
.tw-realtor-row svg { color: var(--tw-gold); flex-shrink: 0; }
.tw-realtor-row:hover {
  background: rgba(var(--tw-gold-rgb), 0.08);
  color: var(--tw-cream);
}
.tw-realtor-bk {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid rgba(var(--tw-gold-rgb), 0.12);
}
/* Agent (personal) logo at top of realtor card */
.tw-realtor-agent-logo-wrap {
  margin-bottom: 16px;
}
.tw-realtor-agent-logo {
  height: 36px;
  width: auto;
  max-width: 160px;
  object-fit: contain;
  filter: brightness(0) invert(1);
  opacity: 0.9;
}

/* Brokerage logo in footer of realtor card — coloured asset, show as-is */
.tw-realtor-bk-logo {
  height: 26px;
  width: auto;
  flex-shrink: 0;
  max-width: 100px;
  object-fit: contain;
  opacity: 0.85;
}
.tw-realtor-bk-name {
  font-family: var(--tw-sans);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.55);
}

/* ── Flat floor list dropdown ────────────────────────────────────────────── */
.tw-dd-floor-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 12px 16px;
  background: transparent;
  border: 0;
  border-radius: 12px;
  cursor: pointer;
  font-family: var(--tw-sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: rgba(var(--tw-cream-rgb), 0.85);
  text-align: left;
  transition: background 0.15s;
}
.tw-dd-floor-btn:hover { background: rgba(255, 255, 255, 0.06); }
.tw-dd-floor-btn.tw-active {
  background: rgba(var(--tw-gold-rgb), 0.14);
  color: var(--tw-cream);
}
.tw-dd-floor-btn .tw-dd-floor-label { flex: 1; }
.tw-dd-floor-btn .tw-dd-floor-count {
  font-size: 9px;
  font-weight: 500;
  color: rgba(var(--tw-cream-rgb), 0.4);
  background: rgba(255, 255, 255, 0.05);
  border-radius: 100px;
  padding: 2px 8px;
}

/* ── Reveal-show for new elements ───────────────────────────────────────── */
#tw-realtor-btn.tw-show, #tw-plan-card.tw-show { opacity: 1; pointer-events: auto; }
#tw-realtor-btn, #tw-plan-card {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.55s var(--tw-ease);
}

/* ── Responsive: floorplan card → circle FAB on mobile (mirrors map FAB) ──── */
@media (max-width: 768px) {
  #tw-plan-card {
    bottom: calc(94px + env(safe-area-inset-bottom));
    left: 18px;
    right: auto;
    width: 62px;
    height: 62px;
    border-radius: 50%;
    padding: 0;
    overflow: hidden;
  }
  .tw-plan-header-row { width: 100%; height: 100%; }
  /* On a phone the circle IS the Expand button: the header never opens the
     enlarged plan, so the one visible control is the control that does. */
  .tw-plan-header { display: none; }
  .tw-plan-header-text { display: none; }
  #tw-plan-expand {
    display: inline-flex;
    flex: 1;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    color: var(--tw-gold);
  }
  #tw-plan-expand svg { width: 24px !important; height: 24px !important; stroke-width: 2.2 !important; }
  /* The circle is the FLOORPLAN control, so at this width it wears the
     floorplan mark instead of the expand arrows (Danny, 2026-09-24). The button
     is unchanged: same 100% hit area, same click, and its aria-label still
     names what it does. */
  .tw-plan-expand-glyph { display: none; }
  .tw-plan-expand-plan { display: inline-flex; align-items: center; justify-content: center; }
  .tw-plan-header-icon { display: flex; align-items: center; justify-content: center; }
  .tw-plan-header-icon svg { width: 24px !important; height: 24px !important; stroke-width: 2.2 !important; }
  /* No inline plan on a phone — the circle opens the full-screen plan. */
  #tw-plan-body { display: none; }
  #tw-plan-chevron-btn { display: none; }
  /* The inline plan is hidden, but the enlarged plan keeps its zoom buttons. */
  #tw-plan-zoom-ctrl { display: none; }
  /* Modal goes fullscreen on mobile and the topbar tightens up: title row
     gets the icon + close button, filter pills wrap onto their own row
     below so they're never clipped regardless of how many floors there are. */
  .tw-plan-modal-card { width: 100vw; height: 100vh; border-radius: 0; }
  .tw-plan-modal-topbar { padding: 14px 16px; gap: 10px; flex-wrap: wrap; }
  .tw-plan-modal-title span:not(.tw-plan-header-icon) { display: none; }
  .tw-plan-modal-title { flex-shrink: 0; }
  .tw-plan-filter { order: 3; flex-basis: 100%; max-width: 100%; font-size: 13px; }
  .tw-plan-filter-btn { padding: 8px 14px; font-size: 13px; letter-spacing: 0.10em; }
  .tw-plan-modal-close { width: 44px; height: 44px; }
  .tw-plan-modal-body { padding: 14px; }
  #tw-realtor-popup {
    top: auto;
    bottom: 96px;
    right: 12px;
    left: 12px;
    width: auto;
  }
  #tw-realtor-btn { top: 14px; right: 14px; width: 42px; height: 42px; }
}



/* ══ LAYOUT VARIANTS (M4) ═══════════════════════════════════════════════════
   Applied as html.tw-v-{component}-{name} classes by applyTheme() from
   theme.variants. The defaults (classic / pill / classic) have NO rules here —
   absence of a variant class IS the default look. nav + cards variants are
   CSS-only restyles (no DOM forks); splash `minimal` is CSS-only as well.
   QA: ?tw-debug=1&tw-variants=minimal,glass-bar,sharp on any preview URL. */

/* ── splash: minimal — lower-third, left-aligned, compact, no rule ───────── */
html.tw-v-splash-minimal #tw-splash { align-items: flex-end; justify-content: flex-start; }
html.tw-v-splash-minimal .tw-splash-inner {
  align-items: flex-start;
  text-align: left;
  max-width: 600px;
  padding: 0 36px clamp(96px, 14vh, 160px) clamp(28px, 5vw, 72px);
}
html.tw-v-splash-minimal .tw-splash-headline-text {
  text-align: left;
  margin-left: 0;
  margin-right: 0;
  font-size: clamp(26px, 3.1vw, 40px);
  max-width: 20ch;
}
html.tw-v-splash-minimal .tw-splash-rule { display: none; }
html.tw-v-splash-minimal .tw-splash-location { text-align: left; }

/* ── nav: glass-bar — full-width slim bottom bar, squared corners ────────── */
html.tw-v-nav-glass-bar #tw-menu-bar {
  left: 24px;
  right: 24px;
  bottom: 24px;
  transform: none;
  display: flex;
  justify-content: center;
}
html.tw-v-nav-glass-bar .tw-menu-pill {
  width: 100%;
  justify-content: center;
  border-radius: 14px;
  height: 64px;
}
/* keep clear of the bottom corner cards — lift them above the bar */
html.tw-v-nav-glass-bar #tw-plan-card,
html.tw-v-nav-glass-bar #tw-map-card { bottom: 110px; }

/* ── cards: sharp — squared corners, slimmer headers, tighter caps labels ── */
html.tw-v-cards-sharp #tw-map-card,
html.tw-v-cards-sharp #tw-plan-card { border-radius: 8px; }
html.tw-v-cards-sharp .tw-map-modal-card,
html.tw-v-cards-sharp .tw-plan-modal-card { border-radius: 10px; }
html.tw-v-cards-sharp #tw-realtor-popup { border-radius: 8px; }
html.tw-v-cards-sharp .tw-map-header,
html.tw-v-cards-sharp .tw-plan-header { padding: 11px 16px; }
html.tw-v-cards-sharp .tw-map-header-text,
html.tw-v-cards-sharp .tw-plan-header-text { font-size: 9px; letter-spacing: 0.26em; }
html.tw-v-cards-sharp #tw-hs-popup .tw-hsp-card { border-radius: 8px; } /* M6 hotspot popup */

/* ── Grouped nav (M5) — scene rows nested under group labels ─────────────── */
.tw-dropdown { max-height: min(62vh, 540px); overflow-y: auto; -webkit-overflow-scrolling: touch; }
.tw-dd-group-label {
  padding: 12px 16px 5px;
  font-family: var(--tw-sans);
  font-size: 8.5px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(var(--tw-line-rgb), 0.95);
}
.tw-dd-group-label:first-child { padding-top: 6px; }

/* The suite row — the plan's name, its unit chip and its numbers. This is the
   row a visitor taps first, so it carries the weight and the room list below
   stays quiet. */
.tw-dd-group { padding: 4px 0 2px; }
.tw-dd-group + .tw-dd-group { border-top: 1px solid rgba(var(--tw-line-rgb), 0.08); }
.tw-dd-suite-btn {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  width: 100%;
  padding: 13px 16px 9px;
  background: transparent;
  border: 0;
  border-radius: 12px;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.tw-dd-suite-btn:hover { background: rgba(255, 255, 255, 0.06); }
.tw-dd-suite-btn.tw-active { background: rgba(var(--tw-gold-rgb), 0.14); }
.tw-dd-suite-btn.tw-active .tw-dd-unit-name { color: var(--tw-cream); }
.tw-dd-unit-name {
  font-family: var(--tw-sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--tw-cream);
  white-space: nowrap;
}
.tw-dd-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  width: 100%;
}
.tw-dd-meta-item {
  font-family: var(--tw-sans);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.62);
  background: rgba(var(--tw-cream-rgb), 0.07);
  border-radius: 999px;
  padding: 3px 8px;
  white-space: nowrap;
}
.tw-dd-meta-item:first-child {
  color: var(--tw-navy-deep);
  background: var(--tw-gold);
}
.tw-dd-scene-list { padding-bottom: 4px; }

.tw-dd-scene-btn {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 11px 16px 11px 24px;
  background: transparent;
  border: 0;
  border-radius: 12px;
  cursor: pointer;
  font-family: var(--tw-sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: rgba(var(--tw-cream-rgb), 0.85);
  text-align: left;
  transition: background 0.15s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.tw-dd-scene-btn:hover { background: rgba(255, 255, 255, 0.06); }
.tw-dd-scene-btn.tw-active {
  background: rgba(var(--tw-gold-rgb), 0.14);
  color: var(--tw-cream);
  font-weight: 600;
}

/* ── "Now viewing" toast ──────────────────────────────────────────────────
   The room name plus the suite's chips. Top-left, under the property pill:
   every bottom corner is already taken (plan card left, map card right, menu
   centre), and a toast that covers the thing you just tapped is worse than no
   toast. pointer-events:none so it can never eat a drag. */
/* Top-left, under the logo (Danny, 2026-10-06): the bottom corners belong to the
   floorplan card and the map card. Same shape as the 3DVista Seaview wrapper: an
   accent eyebrow, the room in large light type, and the plan's numbers
   underneath. A tour can switch it off (theme.nowViewing === false). */
#tw-toast {
  position: fixed;
  top: calc(112px + env(safe-area-inset-top));
  bottom: auto;   /* the older rule above still sets bottom: 52px */
  left: 44px;
  z-index: 99;
  max-width: min(44vw, 460px);
  pointer-events: none;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s var(--tw-ease), transform 0.7s var(--tw-ease);
}
#tw-toast.tw-show { opacity: 1; transform: translateY(0); }
/* Its own soft shade, so the room name reads over a bright sky or a white wall. */
#tw-toast::before {
  content: "";
  position: absolute;
  inset: -36px -90px -36px -60px;
  background: radial-gradient(ellipse at 38% 45%, rgba(10, 16, 24, 0.5) 0%, rgba(10, 16, 24, 0.28) 45%, transparent 72%);
  z-index: -1;
  pointer-events: none;
}
.tw-toast-eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}
.tw-toast-label {
  display: inline-block;
  font-family: var(--tw-sans);
  font-size: clamp(11px, 0.85vw, 14px);
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--tw-gold);
  text-shadow: 0 1.5px 15px rgba(0, 0, 0, 0.6);
}
.tw-toast-unit {
  font-family: var(--tw-sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--tw-cream-rgb), 0.85);
  background: rgba(var(--tw-navy-deep-rgb), 0.72);
  border: 1px solid rgba(var(--tw-gold-rgb), 0.45);
  border-radius: 999px;
  padding: 3px 10px;
}
.tw-toast-room {
  display: block;
  font-family: var(--tw-serif, var(--tw-sans));
  font-size: clamp(32px, 3.4vw, 58px);
  font-weight: 300;
  line-height: 1.05;
  color: var(--tw-cream);
  text-shadow: 0 3px 30px rgba(0, 0, 0, 0.6);
}
.tw-toast-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.tw-toast-meta .tw-dd-meta-item {
  font-size: 9.5px;
  padding: 4px 10px;
  background: rgba(var(--tw-navy-deep-rgb), 0.72);
  border: 1px solid rgba(var(--tw-line-rgb), 0.2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.tw-toast-meta .tw-dd-meta-item:first-child {
  color: var(--tw-cream);
  background: rgba(var(--tw-navy-deep-rgb), 0.72);
  border-color: rgba(var(--tw-gold-rgb), 0.5);
}

@media (max-width: 768px) {
  #tw-toast {
    top: calc(96px + env(safe-area-inset-top));
    bottom: auto;
    left: 18px;
    right: 18px;
    max-width: none;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   HOW-TO-USE CARD (first visit) — ported from the Devon skin, 2026-10-05
   ══════════════════════════════════════════════════════════════════════════
   It teaches tour MECHANICS (drag to look, rings to move, symbols to open), so
   it is part of the standard player, not a brand: white frosted glass and a
   system font on every tour, whatever the tour's palette. Wording is neutral
   so it works for a home, bare land, rentals or commercial (Danny). A tour can
   switch it off with theme.howTo = false. */
:root {
  --hint-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --hint-bg: rgba(255, 255, 255, 0.58);
  --hint-border: rgba(255, 255, 255, 0.5);
  --hint-ink: rgba(22, 22, 26, 0.9);
  --hint-ink-soft: rgba(22, 22, 26, 0.62);
  --hint-ink-faint: rgba(22, 22, 26, 0.48);
}
/* ── ONBOARDING HINT ─────────────────────────────────────────────────────── */
/* Shown once per device after Explore Now (see maybeShowHintAutomatically()
   in the JS), teaching first-time visitors the pano is draggable. Both the
   overlay and card are pointer-events:none throughout — this is a pure
   visual layer that never intercepts a drag gesture aimed at the pano
   underneath (see showHint()'s dismiss listener for why). Only
   .tw-hint-link (the embedded-only "open in a new tab" line) re-enables
   pointer-events on itself, since it's the one genuinely clickable thing
   here.

   DELIBERATELY brand-neutral (Danny 2026-08-06: "I want this to feel like
   it works on any tour, no matter the colours, fonts, etc... like the
   animated hotspot designs we made") — every color/font here comes from
   the --hint-* tokens in :root, never from --sv-*. White frosted glass
   (0.58 alpha + heavy blur) rather than the dark navy glass the rest of
   the UI uses, specifically so this reads as universal tour CHROME (how
   the interface works) rather than this property's BRAND (which the rest
   of the floating UI already carries). Same reasoning the native 3DVista
   hotspot icons stay white/neutral regardless of client palette. */
#tw-hint-overlay {
  position: fixed;
  inset: 0;
  z-index: 250;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.45s var(--tw-ease);
}

#tw-hint-overlay.tw-show { opacity: 1; }

.tw-hint-card {
  pointer-events: none;
  position: relative; /* anchors .tw-hint-close */
  max-width: 320px;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* Even breathing room on every side. The Devon card ends on its
     availability line, which is what spaced Next off the bottom edge there;
     the standard card has no such line, so the card carries its own. */
  padding: 28px 28px 26px;
  border-radius: 22px;
  overflow: hidden;      /* the disclaimer band has square corners */
  background: var(--hint-bg);
  backdrop-filter: blur(32px) saturate(180%);
  -webkit-backdrop-filter: blur(32px) saturate(180%);
  border: 1px solid var(--hint-border);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.28), 0 1px 0 rgba(255, 255, 255, 0.6) inset;
  transform: scale(0.96) translateY(6px);
  transition: transform 0.45s var(--tw-ease);
}

#tw-hint-overlay.tw-show .tw-hint-card {
  transform: scale(1) translateY(0);
}

/* Explicit dismiss. `pointer-events: auto` is required — the overlay and card
   are both pointer-events:none so a drag aimed at the pano passes straight
   through, and each genuinely clickable child has to opt back in (same as
   .tw-hint-link). Deliberately quiet: it should read as a way out, not compete
   with the instruction the card is there to deliver. */
.tw-hint-close {
  pointer-events: auto;
  position: absolute;
  top: 10px;
  right: 10px;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--hint-ink);
  opacity: 0.4;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 0.18s, background 0.18s;
}

.tw-hint-close:hover { opacity: 0.85; background: rgba(0, 0, 0, 0.06); }
.tw-hint-close:focus-visible { opacity: 0.85; outline: 2px solid var(--hint-ink); outline-offset: 2px; }

.tw-hint-icon-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 34px;
  margin-bottom: 12px;
  color: var(--hint-ink);
}

.tw-hint-chevron {
  display: flex;
  opacity: 0.3;
}

.tw-hint-pointer {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  animation: tw-hint-drag 2.4s ease-in-out infinite;
}

/* Touch variant — HINT_HTML leaves this span genuinely empty (no cursor
   SVG) when IS_TOUCH, so a plain filled dot stands in for a fingertip. */
.tw-hint-pointer:empty {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 6px rgba(22, 22, 26, 0.08);
}

@keyframes tw-hint-drag {
  0%   { transform: translateX(-16px); opacity: 0.5; }
  50%  { transform: translateX(16px);  opacity: 1; }
  100% { transform: translateX(-16px); opacity: 0.5; }
}

/* ── The steps ──────────────────────────────────────────────────────────────
   One card, three panels. The panels are stacked and only the active one is
   shown, so the card is as tall as its tallest step and nothing jumps as the
   visitor moves through it. */
.tw-hint-steps { width: 100%; display: flex; flex-direction: column; }
.tw-hint-step { display: none; flex-direction: column; align-items: center; width: 100%; }
.tw-hint-step.is-active { display: flex; animation: tw-hint-step-in 0.32s var(--tw-ease) both; }
@keyframes tw-hint-step-in {
  from { opacity: 0; transform: translateX(8px); }
  to   { opacity: 1; transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
  .tw-hint-step.is-active { animation: none; }
}

/* The walk hotspot, previewed in the card's own ink (--hint-ink, the same dark
   grey as the cursor and chevrons on step one) rather than the tour accent, so
   the card stays brand-neutral. Same motion as the real one: the pulse is born
   at the ring and only travels outwards. */
.tw-hint-icon-slot {
  display: flex; align-items: center; justify-content: center;
  gap: 22px;
  /* Tall enough for the pulse, which is the widest thing in the card: the ring
     is a 38px box inside the 44px drawing and `tw-hint-hotspot-ping` takes it
     to 1.72x (about 65px), so 76px leaves it clear of the top and bottom edges.
     At 64px the pulse was being cut off square by the overflow below — Danny,
     2026-09-24: "keep the animated ring inside its container". */
  width: 100%; height: 76px; margin-bottom: 2px; overflow: hidden;
  /* The illustrations draw in currentColor; this is what makes that the card's
     own ink rather than the body's black. */
  color: var(--hint-ink);
}
.tw-hint-hotspot { position: relative; display: block; width: 44px; height: 44px; }
.tw-hint-hotspot-ring {
  /* Same proportions as the real floating marker, scaled to this 44px drawing:
     the ring came in off the edge and the dot grew, so the card shows the
     marker Danny will actually see. */
  position: absolute; inset: 3px; border-radius: 50%;
  border: 2.5px solid currentColor;
  animation: tw-hint-hotspot-swell 2.6s cubic-bezier(0.3, 0.6, 0.25, 1) infinite;
}
@keyframes tw-hint-hotspot-swell {
  0%, 100% { transform: scale(1);    border-width: 2.5px; }
  18%      { transform: scale(1.07); border-width: 2.8px; }
  46%      { transform: scale(1);    border-width: 2.5px; }
}
@keyframes tw-hint-hotspot-ping {
  0%   { transform: scale(1);    opacity: 0;    border-width: 3px; }
  10%  { opacity: 0.45; }
  65%  { opacity: 0.14; }
  /* 1.72, not the 2.1 the real marker reaches: the card is 320px wide and the
     pulse has to stay inside the slot above (see .tw-hint-icon-slot). The
     gesture — out from the ring, fading and thinning — is the same one. */
  100% { transform: scale(1.72); opacity: 0;    border-width: 0.7px; }
}
.tw-hint-hotspot-ping {
  position: absolute; inset: 3px; border-radius: 50%;
  border: 2.5px solid currentColor;
  animation: tw-hint-hotspot-ping 2.6s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
}
@keyframes tw-hint-hotspot-nudge {
  0%, 22% { transform: translate(-50%, 3px)  rotate(45deg); opacity: 0; }
  38%     { opacity: 0.9; }
  70%     { transform: translate(-50%, -9px) rotate(45deg); opacity: 0; }
  100%    { transform: translate(-50%, -9px) rotate(45deg); opacity: 0; }
}
/* The centre the pulse comes from: static, like the real one. */
.tw-hint-hotspot-dot {
  position: absolute; left: 50%; top: 50%; width: 10px; height: 10px; margin: -5px 0 0 -5px;
  border-radius: 50%; background: currentColor;
}
/* The floor marker, drawn the way the player draws it in the pano: the same
   ring, foreshortened onto the ground. Still, like the real one (the pulse
   belongs to the floating marker), and quieter than it, because in the tour a
   floor ring reads as a surface rather than a control floating in front of
   you. */
.tw-hint-hotspot-floor { width: 44px; height: 44px; }
.tw-hint-floor-ring {
  position: absolute; left: 50%; top: 50%;
  width: 42px; height: 20px; margin: -10px 0 0 -21px;
  border-radius: 50%;
  border: 2.5px solid currentColor;
  opacity: 0.72;
}
@media (prefers-reduced-motion: reduce) {
  .tw-hint-hotspot-ring { animation: none; }
  .tw-hint-hotspot-ping { animation: none; opacity: 0; }
}
/* The other kind of marker: a symbol instead of a ring (info / media hotspots,
   and the door toggles). */
.tw-hint-chip {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 8px;
  border: 1.6px solid currentColor;
  font: 700 13px/1 var(--hint-sans);
}

/* Dots + Back/Next. The buttons are the only things in the card that need the
   pointer back (the card is pointer-events:none so a drag passes through to the
   pano). */
.tw-hint-dots { display: flex; gap: 7px; justify-content: center; align-items: center; width: 100%; margin: 16px 0 12px; }
.tw-hint-dot {
  pointer-events: auto;
  width: 7px; height: 7px; padding: 0; border: 0; border-radius: 50%;
  background: var(--hint-ink-faint);
  cursor: pointer;
  transition: background 0.18s, transform 0.18s;
}
.tw-hint-dot.is-active { background: var(--hint-ink); transform: scale(1.25); }
.tw-hint-dot:focus-visible { outline: 2px solid var(--hint-ink); outline-offset: 3px; }
.tw-hint-nav { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; }
/* On the first step Back is hidden (see renderHintStep) but still in the flow,
   and a hidden button takes a button's width, which pushed Next off centre —
   Danny, 2026-09-24: "center Next when there is no other button beside it".
   Only the step that has no Back drops it from the flow; the others keep the
   reserved space so Next does not jump sideways. */
.tw-hint-nav.tw-hint-nav-solo #tw-hint-back { display: none; }
.tw-hint-btn {
  pointer-events: auto;
  font-family: var(--hint-sans);
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.02em;
  padding: 9px 16px;
  border-radius: 100px;
  border: 1px solid var(--hint-ink-faint);
  background: transparent;
  color: var(--hint-ink-soft);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.18s, color 0.18s, border-color 0.18s;
}
.tw-hint-btn:hover { background: rgba(22, 22, 26, 0.06); color: var(--hint-ink); }
.tw-hint-btn:focus-visible { outline: 2px solid var(--hint-ink); outline-offset: 2px; }
.tw-hint-btn-primary {
  background: var(--hint-ink);
  border-color: var(--hint-ink);
  color: #fff;
}
.tw-hint-btn-primary:hover { background: rgba(22, 22, 26, 0.85); color: #fff; }

.tw-hint-title {
  font-family: var(--hint-sans);
  font-size: 16px;
  font-weight: 600;
  color: var(--hint-ink);
  letter-spacing: 0.002em;
}

.tw-hint-sub {
  font-family: var(--hint-sans);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.4;
  color: var(--hint-ink-soft);
  margin-top: 8px;
  max-width: 26ch;
}

.tw-hint-sub b { font-weight: 600; color: var(--hint-ink); }

.tw-hint-footer {
  margin-top: 16px;
  padding-top: 13px;
  width: 100%;
  border-top: 1px solid rgba(22, 22, 26, 0.12);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Its own band across the full width of the card (Danny, 2026-09-19: "make
   the disclaimer at the bottom a bit smaller, and in it's own section with a
   slightly grey background, full width in the window, and change font to
   white"). Negative margins cancel the card's own side padding, and the card
   clips its corners. */
.tw-hint-disclaimer {
  font-family: var(--hint-sans);
  font-size: 10px;
  font-weight: 400;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.9);
  width: auto;
  margin: 14px -24px 0;
  padding: 10px 20px;
  background: rgba(22, 22, 26, 0.34);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  text-align: center;
}

.tw-hint-link {
  pointer-events: auto;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  font-family: var(--hint-sans);
  font-size: 10.5px;
  font-weight: 400;
  color: var(--hint-ink-faint);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.tw-hint-link span {
  color: var(--hint-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.tw-hint-link:hover span,
.tw-hint-link:focus-visible span { color: var(--hint-ink); opacity: 0.7; }
.tw-hint-link:focus-visible { outline: 2px solid var(--hint-ink); outline-offset: 2px; border-radius: 4px; }

@media (max-width: 768px) {
  .tw-hint-card { padding: 24px 22px 22px; border-radius: 18px; }
  .tw-hint-title { font-size: 15px; }
  .tw-hint-sub { font-size: 12px; }
  .tw-hint-footer { margin-top: 14px; padding-top: 11px; }
  .tw-hint-disclaimer,
  .tw-hint-link { font-size: 10px; }
}


/* The re-open button rides the bottom menu pill, beside the floor menu and
   the aerial button, so help sits with the other controls. */
#tw-hint-trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  margin-left: 2px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--tw-cream);
  opacity: 0.78;
  cursor: pointer;
  transition: opacity 0.2s var(--tw-ease), background 0.2s var(--tw-ease);
}
#tw-hint-trigger:hover,
#tw-hint-trigger:focus-visible { opacity: 1; background: rgba(var(--tw-gold-rgb), 0.14); }
#tw-hint-trigger svg { width: 17px; height: 17px; }

/* ── Map floors in the plan box (2026-10-05) ──────────────────────────────────
   A map floor shows a satellite site map in the same card and enlarged view
   the floorplan uses (see the map-floor block in wrapper.js). The plan image,
   its marker layer and its zoom buttons step aside; the map brings its own. */
.tw-plan-map { display: none; }
.tw-plan-mode-map .tw-plan-zoom-layer,
.tw-plan-mode-map .tw-plan-zoom-ctrl { display: none !important; }
.tw-plan-mode-map .tw-plan-map {
  display: block;
  position: relative;
  width: 100%;
  border-radius: 8px;
  overflow: hidden;
}
#tw-plan-card.tw-plan-mode-map .tw-plan-map { height: min(260px, 36vh); }
#tw-plan-modal.tw-plan-mode-map .tw-plan-modal-stage { align-items: stretch; }
#tw-plan-modal.tw-plan-mode-map .tw-plan-map { height: 100%; border-radius: 0; }
/* The plan's own dot and cone, placed by Mapbox. */
.tw-plan-map-marker { z-index: 1; }
.tw-plan-map-marker.tw-plan-marker-active { z-index: 2; }
.tw-plan-map .mapboxgl-ctrl-group { background: rgba(var(--tw-navy-deep-rgb), 0.86); }
.tw-plan-map .mapboxgl-ctrl-group button .mapboxgl-ctrl-icon { filter: invert(1); }

/* The enlarged plan takes a little more of the screen (Seaview Two,
   2026-09-25: every pixel of height goes into making a plan readable). */
.tw-plan-modal-card { height: 93vh; }
/* Over satellite imagery the plan's beige cone disappears into the trees, so
   on a map it is drawn in white, brightest away from the dot (the end that
   says which way you are looking), and a little larger. */
.tw-plan-map .tw-plan-cone {
  width: 62px;
  height: 74px;
  background: linear-gradient(to top,
    rgba(255, 255, 255, 0.72) 0%, rgba(255, 255, 255, 0.46) 45%,
    rgba(255, 255, 255, 0.18) 80%, rgba(255, 255, 255, 0.04) 100%);
}

/* Tour with the scene selector switched off (theme.sceneMenu === false): the bottom
   bar keeps the drone and how-to buttons only. */
html.tw-no-scene-menu .tw-menu-group,
html.tw-no-scene-menu .tw-menu-group + .tw-menu-sep { display: none; }

/* Drone stops: a white diamond, so the aerial panos never read as ground stops
   on the site map (the plan box and its Drone tab). The shape does the telling
   apart, not a colour of its own, so a neutral tour stays neutral. */
.tw-plan-marker-drone .tw-plan-dot {
  width: 14px; height: 14px;
  border-radius: 3px;
  background: #ffffff;
  border-color: var(--tw-gold, #B8AFA3);
  transform: translate(-50%, -50%) rotate(45deg);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25), 0 1px 4px rgba(0,0,0,0.55);
}
.tw-plan-marker-drone:hover .tw-plan-dot { width: 16px; height: 16px; box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.3), 0 2px 6px rgba(0,0,0,0.6); }
.tw-plan-marker-drone.tw-plan-marker-active .tw-plan-dot,
.tw-plan-marker-drone.tw-plan-marker-start .tw-plan-dot {
  width: 18px; height: 18px;
  background: #ffffff;
  border-color: var(--tw-gold, #B8AFA3);
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.4), 0 2px 8px rgba(0,0,0,0.55);
}
.tw-plan-tab[data-floor-id="drone"]::before, .tw-plan-filter-btn[data-floor-id="drone"]::before {
  content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 6px;
  background: #ffffff; transform: rotate(45deg); border-radius: 1px; vertical-align: 1px;
}
