/* ── Fonts ───────────────────────────────────────────────────────────────── */

/* Sorelle’s live site uses Inter and Inter Tight. These local copies come
   from the exact Google Fonts stylesheet referenced by that site, so the
   preview has no inherited external font dependency. */
@font-face { font-family: 'Inter'; src: url('fonts/Inter-Light.ttf') format('truetype'); font-weight: 300; font-style: normal; font-display: swap; }
@font-face { font-family: 'Inter'; src: url('fonts/Inter-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: 'Inter Tight'; src: url('fonts/InterTight-Light.ttf') format('truetype'); font-weight: 300; font-style: normal; font-display: swap; }
@font-face { font-family: 'Inter Tight'; src: url('fonts/InterTight-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; font-display: swap; }

/* ── Sorelle Residences Virtual Tour — Design System ───────────────────── */
/* Official Sorelle site CSS defines graphite #1C1C1C as its heading, text and
   primary colour; it pairs that base with sand #E2BA96, warm paper #FCF9F5,
   and muted sand #B59578. The colour-reverse logo independently confirms the
   sand accent. These are the only Sorelle palette sources used below. */
:root {
  --sr-ink:       #1C1C1C;
  --sr-ink-rgb:   28, 28, 28;
  --sr-sand:      #E2BA96;
  --sr-sand-rgb:  226, 186, 150;
  --sr-sand-muted:#B59578;
  --sr-paper:     #FCF9F5;
  --sr-paper-rgb: 252, 249, 245;
  --sr-white:     #FFFFFF;
  --tw-serif: 'Inter Tight', Arial, sans-serif;
  --tw-sans:  'Inter', Arial, sans-serif;
  --tw-ease:  cubic-bezier(0.25, 0.46, 0.45, 0.94);
  /* Symmetric ease-in-out for the splash exit — see enterTour() in the JS,
     which now drives this fade directly via requestAnimationFrame rather
     than relying on this CSS transition (confirmed elsewhere in the product
     line that a CSS opacity transition here can simply never start
     interpolating under real-world conditions — see spencer-block.md round
     3/4). This value is kept only as a declared fallback. */
  --tw-ease-inout: cubic-bezier(0.65, 0, 0.35, 1);

  /* Onboarding hint — deliberately independent of every --sr-* token above.
     This teaches tour MECHANICS ("drag to look around"), not brand, so it's
     designed to look identical on any project regardless of that project's
     palette or fonts — same reasoning as the native 3DVista hotspot icons
     staying white/neutral across every client (see the metatours-3dvista
     skill). Portable as-is: copy this whole block into another project's
     CSS and it needs zero adjustment. System font stack on purpose, not
     --tw-sans — this component shouldn't depend on whatever custom webfont
     a given project happens to load. */
  --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);
}

/* Paints the instant the CSS is parsed, before the splash <div> even exists
   in the DOM (only inserted once the 3DVista player is ready) — closes the
   "blank/white flash before anything splash-colored shows up" gap on a slow
   initial load. */
html, body { background: var(--sr-ink); }

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

#tw-splash {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Solid Sorelle graphite, now purely a fallback behind #tw-splash-video. It
     paints instantly, so it covers the beat before the video's first frame
     decodes and any case where the video fails to load. Deliberately NOT a
     static hero image: the video usually decodes fast enough that an
     image-then-crossfade sequence reads as a glitch rather than a reveal. */
  background: var(--sr-ink);
  transition: opacity 1.6s var(--tw-ease-inout);
  overflow: hidden;
}

/* The static official hero starts invisible over the graphite fallback and
   crossfades in once decoded, avoiding a hard first-frame change. */
#tw-splash-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  transform: scale(1);
  opacity: 0;
  transition: opacity 1.4s var(--tw-ease-inout);
  user-select: none;
  pointer-events: none;
}

#tw-splash-video.tw-video-loaded { opacity: 1; }

#tw-splash-hero {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  transform: scale(1);
  opacity: 0;
  transition: opacity 1s var(--tw-ease-inout), transform 1.6s var(--tw-ease-inout);
  user-select: none;
  pointer-events: none;
}

#tw-splash-hero.tw-hero-loaded { opacity: 1; }

/* Kept in step with .tw-splash-wordmark-img below so the two never disagree
   if the rule order ever changes; that one is what actually applies to the
   splash lockup. Sized down 2026-09-17 (Danny: "too big on the splash
   screen") — the stacked badge + wordmark lockup is far taller than a
   horizontal lockup, so it needed to be narrower than the CTA pill to stop
   dominating the frame. */
.tw-sorelle-wordmark { width: clamp(196px, 20vw, 300px); }
.tw-sorelle-float-wordmark { height: 64px; width: auto; }

/* The raised-cosine veil is darkest behind the lockup and eases toward its
   farthest edges, keeping the colour-reverse logo legible over the approved
   Sorelle interior image without introducing an inherited accent colour. */
.tw-splash-overlay {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 78% 62% at 50% 42%, rgba(var(--sr-ink-rgb), 0.62) 0%, rgba(var(--sr-ink-rgb), 0.42) 55%, rgba(var(--sr-ink-rgb), 0.30) 100%),
    linear-gradient(180deg, rgba(var(--sr-ink-rgb), 0.52) 0%, rgba(var(--sr-ink-rgb), 0.22) 45%, rgba(var(--sr-ink-rgb), 0.60) 100%);
  z-index: 1;
}

#tw-splash.tw-hiding {
  pointer-events: none;
}

#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-icon-img {
  width: clamp(76px, 7.2vw, 116px);
  height: auto;
  margin-bottom: clamp(14px, 1.4vw, 20px);
  opacity: 0;
  transform: translateY(20px);
  animation: tw-rise 1.3s 0.3s var(--tw-ease) forwards;
  user-select: none;
  pointer-events: none;
}

.tw-splash-wordmark-img {
  width: clamp(196px, 20vw, 300px);
  height: auto;
  opacity: 0;
  transform: translateY(24px);
  animation: tw-rise 1.5s 0.45s var(--tw-ease) forwards;
  user-select: none;
  pointer-events: none;
}

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

.tw-splash-location {
  font-family: var(--tw-sans);
  font-size: clamp(15px, 1.4vw, 21px);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(var(--sr-paper-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(13px, 1.05vw, 15px);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sr-ink);
  background: var(--sr-sand);
  border: none;
  border-radius: 150px;
  padding: clamp(14px, 1.4vw, 18px) clamp(30px, 3vw, 46px);
  min-height: 58px;
  min-width: 66px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  touch-action: manipulation;
  box-shadow: 0 4px 24px rgba(var(--sr-sand-rgb), 0.30);
  transition: background 0.22s, box-shadow 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(--sr-sand-muted);
  box-shadow: 0 6px 32px rgba(var(--sr-sand-rgb), 0.45);
  transform: translateY(-1.5px);
}

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

.tw-splash-arrow {
  width: 18px;
  height: 18px;
  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(--sr-paper-rgb), 0.42);
}

.tw-splash-devon-img {
  width: clamp(100px, 8vw, 138px);
  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 ───────────────────────────────────────────────────────────── */
/* Raised-cosine ease (alpha(t) = peak * 0.5 * (1 + cos(pi*t))), not hand-
   picked linear steps — a linear ramp ending in a flat 0 still has a slope
   discontinuity right at that last stop, visible as a Mach band over a
   large flat bright surface (a ceiling). Cosine has zero slope at both
   ends. Cornered radials use `farthest-side`, not the `farthest-corner`
   default — farthest-corner over-sizes the ellipse ~41% along the box's
   straight edges, leaving a visible rectangular edge at the box boundary
   before alpha reaches true 0. Both fixes applied from day one here (see
   CLAUDE.md's Ellis writeup for the two bugs this avoids). */
#tw-vignette-top {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 195px;
  background: linear-gradient(to bottom,
    rgba(var(--sr-ink-rgb), 0.45) 0%, rgba(var(--sr-ink-rgb), 0.44) 15%, rgba(var(--sr-ink-rgb), 0.36) 30%,
    rgba(var(--sr-ink-rgb), 0.26) 45%, rgba(var(--sr-ink-rgb), 0.16) 60%, rgba(var(--sr-ink-rgb), 0.07) 75%,
    rgba(var(--sr-ink-rgb), 0.01) 90%, rgba(var(--sr-ink-rgb), 0) 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(var(--sr-ink-rgb), 0.40) 0%, rgba(var(--sr-ink-rgb), 0.38) 15%, rgba(var(--sr-ink-rgb), 0.32) 30%,
    rgba(var(--sr-ink-rgb), 0.23) 45%, rgba(var(--sr-ink-rgb), 0.14) 60%, rgba(var(--sr-ink-rgb), 0.06) 75%,
    rgba(var(--sr-ink-rgb), 0.01) 90%, rgba(var(--sr-ink-rgb), 0) 100%
  );
  z-index: 98;
  pointer-events: none;
}

#tw-vignette-tl {
  position: fixed;
  top: 0; left: 0;
  width: 480px;
  height: 280px;
  background: radial-gradient(ellipse farthest-side at 0% 0%,
    rgba(var(--sr-ink-rgb), 0.18) 0%, rgba(var(--sr-ink-rgb), 0.17) 15%, rgba(var(--sr-ink-rgb), 0.14) 30%,
    rgba(var(--sr-ink-rgb), 0.10) 45%, rgba(var(--sr-ink-rgb), 0.06) 60%, rgba(var(--sr-ink-rgb), 0.03) 75%,
    rgba(var(--sr-ink-rgb), 0.005) 90%, rgba(var(--sr-ink-rgb), 0) 100%
  );
  z-index: 98;
  pointer-events: none;
}

#tw-vignette-toast {
  position: fixed;
  bottom: 0; left: 0;
  width: 850px;
  height: 680px;
  background: radial-gradient(ellipse farthest-side at 0% 100%,
    rgba(var(--sr-ink-rgb), 0.95) 0%, rgba(var(--sr-ink-rgb), 0.90) 15%, rgba(var(--sr-ink-rgb), 0.75) 30%,
    rgba(var(--sr-ink-rgb), 0.55) 45%, rgba(var(--sr-ink-rgb), 0.33) 60%, rgba(var(--sr-ink-rgb), 0.14) 75%,
    rgba(var(--sr-ink-rgb), 0.02) 90%, rgba(var(--sr-ink-rgb), 0) 100%
  );
  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-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 (property manager 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));
}

/* Sorelle — horizontally centred at top. Icon + wordmark side by side,
   matching the feature sheet's own real lockup composition (icon left of
   wordmark) — these are two separately-extracted assets (no single
   pre-composed horizontal file exists), composed here via flex. */
#tw-logo-float {
  position: fixed;
  top: 30px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 100;
  display: flex;
  align-items: center;
  gap: 14px;
}

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

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

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

#tw-cta-btn {
  position: fixed;
  top: 27px;
  right: 30px;
  z-index: 100;
  font-family: var(--tw-sans);
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  /* Sorelle graphite text on the official sand accent. */
  color: var(--sr-ink);
  background: var(--sr-sand);
  border-radius: 150px;
  padding: 0 26px;
  height: 54px;
  min-width: 54px;
  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.06); }
#tw-cta-btn:focus-visible { outline: 2px solid var(--sr-white); outline-offset: 3px; }

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

#tw-menu-bar {
  position: fixed;
  bottom: 42px;
  left: 50%;
  transform: translateX(-50%);
  /* Higher than #tw-map-card's z-index:100 — NOT a redundant belt-and-
     suspenders alongside .tw-dropdown's own z-index:200. A fixed-position
     descendant's z-index only competes within its NEAREST ancestor stacking
     context: #tw-menu-bar (position:fixed + z-index:100) already establishes
     one, so .tw-dropdown's z-index:200 only wins against OTHER children of
     #tw-menu-bar — it never escapes to compete against #tw-map-card (a
     separate top-level stacking context, also z-index:100, later in DOM
     order so it wins the tie and paints over the entire #tw-menu-bar
     subtree, dropdown included). Confirmed live on Ellis's deployed tour,
     2026-08-06: bumping the child alone did nothing; bumping this container
     past #tw-map-card's 100 fixed it immediately. */
  z-index: 150;
}

.tw-menu-pill {
  display: flex;
  align-items: center;
  background: rgba(var(--sr-ink-rgb), 0.84);
  backdrop-filter: blur(24px) saturate(170%);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  border: 1px solid rgba(var(--sr-sand-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(--sr-sand-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(--sr-paper-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(--sr-paper-rgb), 0.88);
  background: rgba(255, 255, 255, 0.05);
}

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

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

.tw-menu-btn:focus-visible {
  outline: 2px solid var(--sr-sand);
  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;
}

.tw-menu-sep {
  width: 1.5px;
  height: 27px;
  background: rgba(var(--sr-paper-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(--sr-paper-rgb), 0.52);
  touch-action: manipulation;
  transition: color 0.18s, background 0.18s;
  margin: 0 3px;
}

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

#tw-aerial.tw-active { color: var(--sr-sand); }
#tw-aerial svg { width: 24px; height: 24px; }
#tw-aerial:focus-visible {
  outline: 2px solid var(--sr-sand);
  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(--sr-ink-rgb), 0.96);
  backdrop-filter: blur(28px) saturate(160%);
  -webkit-backdrop-filter: blur(28px) saturate(160%);
  border: 1px solid rgba(var(--sr-sand-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(--sr-sand-rgb), 0.06);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--tw-ease), transform 0.2s var(--tw-ease);
  max-height: 62vh;
  overflow-y: auto;
  scroll-behavior: smooth;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--sr-sand-rgb), 0.32) transparent;
}

#tw-suites-dd { min-width: 290px; }

/* Wider than the base 277.5px — rows pair a label with a status tag,
   which clips at the narrower width. */
#tw-amenities-dd { min-width: 320px; }

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

.tw-dropdown::-webkit-scrollbar { width: 10px; }
.tw-dropdown::-webkit-scrollbar-track { background: transparent; }
.tw-dropdown::-webkit-scrollbar-thumb {
  background: rgba(var(--sr-sand-rgb), 0.3);
  border-radius: 99px;
  border: 3px solid transparent;
  background-clip: padding-box;
}
.tw-dropdown::-webkit-scrollbar-thumb:hover {
  background: rgba(var(--sr-sand-rgb), 0.55);
  background-clip: padding-box;
}

.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(--sr-paper-rgb), 0.25);
  padding: 9px 21px 12px;
  display: block;
  border-bottom: 1px solid rgba(var(--sr-sand-rgb), 0.1);
  margin-bottom: 6px;
}

.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(--sr-paper-rgb), 0.28);
  padding: 14px 21px 18px;
  text-align: center;
}

/* Per-item pending-tour row — every suite until the shoot lands, plus every
   practical building feature without an explorable pano. */
.tw-dropdown-item-soon {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  font-family: var(--tw-sans);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: rgba(var(--sr-paper-rgb), 0.32);
  padding: 11px 21px;
  border-radius: 15px;
  cursor: default;
  user-select: none;
}

.tw-dropdown-soon-tag {
  flex-shrink: 0;
  font-family: var(--tw-sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--sr-sand-rgb), 0.85);
  border: 1px solid rgba(var(--sr-sand-rgb), 0.35);
  border-radius: 999px;
  padding: 3px 9px;
  white-space: nowrap;
}

.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(--sr-paper-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;
}

.tw-dd-unit-name {
  font-size: 17px;
  font-weight: 400;
  color: inherit;
  letter-spacing: 0.02em;
}

.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; }

/* Confirmed unit identifiers may appear here later. Provisional Sorelle rows deliberately show none. */
.tw-dd-unit-tag {
  padding: 2px 7px;
  border-radius: 5px;
  background: rgba(var(--sr-sand-rgb), 0.16);
  color: var(--sr-sand);
  font-weight: 600;
}

.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(--sr-paper-rgb), 0.75);
  /* Without this, two-word meta ("2 Bed") breaks mid-item onto a second line
     the instant the row runs out of width — reads as a layout bug, not a
     wrap. Paired with flex-wrap on the row itself at the mobile breakpoint
     (see .tw-toast-meta below for the same fix on the toast). */
  white-space: nowrap;
}

.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(--sr-sand);
  opacity: 0;
  transition: opacity 0.15s;
}

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

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

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

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

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

/* Bottom-left is reserved for the viewing toast; the neutral help trigger
   sits separately at bottom-right. */
#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(--sr-sand);
  /* Spacing below now belongs to .tw-toast-eyebrow, the flex row that wraps
     this label and the unit chip — a bottom margin on a flex ITEM would offset
     it against the chip beside it instead of spacing the group. */
  margin-bottom: 0;
  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(--sr-white);
  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(--sr-paper-rgb), 0.78);
  text-shadow: 0 1.5px 12px rgba(0,0,0,0.6);
}

.tw-toast-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  /* Same backstop as .tw-dd-meta-item above — without this, "2 Bed" breaks
     mid-item on a narrow screen. Paired with flex-wrap on the row itself at
     the mobile breakpoint below (nowrap alone just trades a mid-item break
     for a silent horizontal overflow — both halves are required together). */
  white-space: nowrap;
}

/* Eyebrow row: "NOW VIEWING" plus the unit number chip. The chip sits here
   rather than in the meta row below because a 4th meta chip pushed the toast
   wide enough to hit the centred nav pill at desktop widths (measured). */
.tw-toast-eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.tw-toast-unit {
  padding: 3px 9px;
  border-radius: 6px;
  background: rgba(var(--sr-sand-rgb), 0.16);
  color: var(--sr-sand);
  font-family: var(--tw-sans);
  font-size: 0.66em;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.tw-toast-meta-icon {
  color: var(--sr-sand);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
}

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

/* ── 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 --sr-*. White frosted glass
   (0.58 alpha + heavy blur) rather than a cool-blue glass treatment.
   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;
  padding: 26px 24px 18px;
  border-radius: 22px;
  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; }
}

.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;
}

.tw-hint-disclaimer {
  font-family: var(--hint-sans);
  font-size: 10.5px;
  font-weight: 400;
  line-height: 1.4;
  color: var(--hint-ink-faint);
}

.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: 22px 20px 16px; 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; }
}

/* ── FLOATING MAP PILL ───────────────────────────────────────────────────── */
/* Bottom-right glass pill — a single button styled like the other floating
   pills, opening the fullscreen map modal directly. */

/* Back to sitting in the same row as the nav pill (Danny 2026-08-10): stacking
   it above #tw-hint-trigger read as "Location belongs to the help button",
   the opposite of the intent — Location IS one of the branded controls, help
   is the thing that should read as separate from it. `bottom: 42px` matches
   #tw-menu-bar's own bottom exactly, so the two sit on a shared baseline. */
#tw-map-card {
  position: fixed;
  bottom: 42px;
  right: 36px;
  z-index: 100;
  border-radius: 999px;
  overflow: hidden;
  border: 1px solid rgba(var(--sr-sand-rgb), 0.18);
  box-shadow: 0 12px 60px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(var(--sr-sand-rgb), 0.06) inset;
  background: rgba(var(--sr-ink-rgb), 0.84);
  backdrop-filter: blur(24px) saturate(170%);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  transition-delay: 0.3s;
}

/* `width: 100%` is load-bearing, not cosmetic: #tw-map-card carries all the
   pill styling (background, border, radius) while this button is the only
   clickable thing inside it. If the card is ever given a width larger than
   this button's content width, the difference becomes a dead zone that still
   looks clickable. Stretching the button to the card guarantees the hit area
   and the visible pill are always the same rectangle. */
.tw-map-header {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 12px;
  padding: 16.5px 24px;
  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(--sr-sand); outline-offset: -2px; }

/* ── RE-OPEN ONBOARDING HINT ─────────────────────────────────────────────── */
/* Bottom-RIGHT corner, with the Location pill sitting inboard of it. Viewer
   help stays separate from branded controls. */
#tw-hint-trigger {
  position: fixed;
  /* A small, independent corner affordance keeps this viewer help separate
     from the property controls. */
  bottom: 14px;
  right: 16px;
  left: auto;
  z-index: 100;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  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 10px 34px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.6) inset;
  color: var(--hint-ink);
  opacity: 0.82;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 0.55s var(--tw-ease), background 0.18s, transform 0.15s var(--tw-ease);
  transition-delay: 0.3s, 0s, 0s;
}

#tw-hint-trigger svg { width: 13px; height: 13px; }

#tw-hint-trigger:hover { opacity: 1; transform: scale(1.06); }
#tw-hint-trigger:focus-visible { opacity: 1; outline: 2px solid var(--hint-ink); outline-offset: 2px; }

/* Hover label sits to the LEFT of the button, which now leaves it sitting
   neatly underneath the Location pill rather than colliding with it — the
   collision was only a problem back when the two shared a row. Vertically
   centred on the button. Pointer-events off so it can never swallow a click
   meant for the button. */
#tw-hint-trigger::after {
  content: 'How to use';
  position: absolute;
  right: calc(100% + 9px);
  top: 50%;
  transform: translateY(-50%) translateX(4px);
  padding: 7px 12px;
  border-radius: 999px;
  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 8px 26px rgba(0, 0, 0, 0.26);
  color: var(--hint-ink);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s var(--tw-ease), transform 0.18s var(--tw-ease);
}

#tw-hint-trigger:hover::after,
#tw-hint-trigger:focus-visible::after {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}

/* Touch devices have no hover state, so the label would either never appear
   or stick after a tap. The icon alone carries it there. */
@media (hover: none) {
  #tw-hint-trigger::after { display: none; }
}

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

@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: 24px; gap: 11px; }
  .tw-sorelle-float-wordmark { height: 54px; }
  .tw-logo-icon-img { height: 36px; }
  .tw-logo-wordmark-img { height: 30px; }
  #tw-cta-btn    { top: 22px; right: 22px; height: 48px; padding: 0 20px; font-size: 12.5px; }

  #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; }

  /* Clears the centred nav pill, which occupies 22..88px from the bottom on
     this breakpoint. Unlike desktop — where the toast stays narrow enough to
     sit beside the pill — the room name and its beds/baths/sq.ft. row get wide
     enough here to reach the pill's left edge, so they have to stack instead. */
  #tw-toast      { bottom: calc(104px + env(safe-area-inset-bottom)); left: 24px; max-width: min(42vw, 420px); }
  .tw-toast-label { font-size: clamp(16px, 2vw, 20px); letter-spacing: 0.16em; }
  .tw-toast-eyebrow { margin-bottom: 9px; gap: 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); }

  /* No fixed width. A hardcoded `width: 280px` here made the card render far
     wider than the button inside it (which is content-sized), so ~100px of the
     pill was visually part of the control but dead to clicks — and the live
     button was the size the pill should have been all along. Let it hug its
     content exactly like the desktop rule does. */
  /* Matches #tw-menu-bar's own bottom on this breakpoint — same reasoning as
     the desktop rule, same shared baseline. */
  #tw-map-card   { bottom: calc(22px + env(safe-area-inset-bottom)); right: 22px; }
  /* Beside Location rather than stacked below it — Location's own bottom
     offset here (22px) leaves too little room to fit anything beneath it and
     still clear its ~59px height (the desktop/mobile "stack below" approach
     needs the anchor sitting higher than that to have somewhere to stack
     into). Tucked into the narrow strip between Location's right edge and the
     true screen edge instead: still separate from it, still corner-anchored,
     just arranged left-right here rather than top-bottom. Vertically centred
     on Location (22 + 59/2 - 16/2 ≈ 44px). */
  #tw-hint-trigger { bottom: calc(44px + env(safe-area-inset-bottom)); right: 2px; left: auto; width: 16px; height: 16px; }
  #tw-hint-trigger svg { width: 10px; height: 10px; }
  /* Base rule already points the tooltip LEFT (toward Location/the canvas) —
     correct here too and left alone on purpose: the button sits only 2px
     from the true edge, so a right-pointing tooltip would run off-screen. */
}

/* Mobile — all phones (portrait & landscape) and small tablets ≤768px. */
@media (max-width: 768px) {
  #tw-devon-logo-float { display: none; }

  /* Sorelle lockup sits beside the CTA with a compact but still prominent
     mark on phones. */
  #tw-logo-float { top: 16px; left: 20px; transform: none; }
  .tw-logo-wordmark-img { display: none; }
  .tw-sorelle-float-wordmark { display: block !important; height: 48px; }
  .tw-logo-icon-img { height: 48px; }

  #tw-cta-btn {
    top: 18px;
    right: 20px;
    height: 46px;
    min-width: 0;
    padding: 0 20px;
    font-size: 13px;
    letter-spacing: 0.12em;
  }

  #tw-menu-bar   { bottom: calc(18px + env(safe-area-inset-bottom)); width: calc(100vw - 40px); display: flex; justify-content: center; left: 20px; right: 20px; transform: none; }
  /* backdrop-filter (like transform/filter/perspective/will-change) makes an
     element the containing block for its position:fixed descendants — and
     .tw-dropdown switches to position:fixed at this breakpoint specifically
     to span the full viewport instead of just this pill. With the blur left
     on, the dropdown's left/right below would resolve against the PILL's
     narrower, centered box instead of the viewport. Solid fill instead of
     blur here fixes it; desktop/tablet dropdowns use position:absolute
     anchored via .tw-menu-group's own position:relative, which resolves
     first and never reaches this rule, so their glass look is untouched. */
  .tw-menu-pill  { height: 70px; padding: 0 6px; max-width: 100%; backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(var(--sr-ink-rgb), 0.94); }
  .tw-menu-btn   { padding: 0 20px; height: 58px; font-size: 16px; gap: 8px; letter-spacing: 0.04em; }
  .tw-menu-sep   { height: 26px; margin: 0 2px; }
  #tw-aerial     { width: 58px; height: 58px; margin: 0 2px; }
  .tw-menu-chevron { width: 13px; height: 13px; }
  .tw-menu-pill::-webkit-scrollbar { display: none; }

  #tw-toast       { bottom: auto; top: calc(104px + env(safe-area-inset-top)); left: 20px; right: 20px; max-width: none; transform: translateY(-10px); }
  #tw-toast.tw-show { transform: translateY(0); }
  .tw-toast-label { font-size: 16px; letter-spacing: 0.16em; }
  .tw-toast-eyebrow { margin-bottom: 10px; gap: 8px; }
  .tw-toast-room  { font-size: clamp(38px, 10vw, 56px); line-height: 1.0; }
  /* At 375px the row has ~335px, but the widest suite label ("2 Bedroom +
     Den") needs more than that alongside its meta. nowrap alone (on
     .tw-toast-meta-item above) prevents a mid-item break but trades it for a
     silent horizontal overflow — wrapping the ROW instead lets an item that
     doesn't fit drop to a clean second line as a whole unit. */
  .tw-toast-meta  { flex-direction: row; flex-wrap: wrap; align-items: center; column-gap: 14px; row-gap: 6px; margin-top: 12px; font-size: 15px; letter-spacing: 0.08em; }
  .tw-toast-meta-item { gap: 7px; align-items: center; }
  .tw-toast-meta-icon svg { width: 24px !important; height: 24px !important; }

  /* Floats above the nav pill on this breakpoint out of necessity — the pill
     goes full-width here, so there's no shared row to align Location into
     the way the wider breakpoints do. Back to the original 100px gap now
     that #tw-hint-trigger (below) no longer stacks underneath it. */
  #tw-map-card {
    bottom: calc(100px + env(safe-area-inset-bottom));
    right: 20px;
    left: auto;
    width: 68px;
    height: 68px;
    border-radius: 50%;
  }
  .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-header-icon { display: flex; align-items: center; justify-content: center; }
  .tw-map-header-icon svg { width: 26px !important; height: 26px !important; stroke-width: 2.2 !important; }

  /* Genuinely in the true bottom-right corner (Danny 2026-08-10, repeated
     ask — the previous "stacked between the pill and Location" placement
     still read as inset, part of the branded cluster rather than the tour
     itself). The nav pill's rendered shape (checked against `.tw-menu-pill`
     itself, not `#tw-menu-bar`'s full-width wrapper) spans nearly edge to
     edge at this width, so there's no empty margin to tuck into — this
     deliberately sits low enough that their bounding boxes overlap, and
     relies on z-index (170, above #tw-menu-bar's 150) plus the pill's own
     rounded end-cap curving away from the true corner to keep it visually
     clear and on top rather than fighting for genuinely empty space that
     doesn't exist here. Verify this on a real phone, not just devtools —
     confirm it doesn't sit under the pill's rounded cap at whatever width
     actually ships. */
  #tw-hint-trigger {
    bottom: calc(10px + env(safe-area-inset-bottom));
    right: 10px;
    left: auto;
    width: 32px;
    height: 32px;
    z-index: 170;
  }
  #tw-hint-trigger svg { width: 15px; height: 15px; }

  .tw-splash-inner { padding: 36px 30px; }
  .tw-splash-icon-img { width: clamp(60px, 15vw, 84px); margin-bottom: 12px; }
  .tw-splash-wordmark-img { width: clamp(168px, 52vw, 244px); }
  .tw-splash-location { font-size: 16px; letter-spacing: 0.12em; margin-top: 12px; }
  .tw-splash-enter {
    margin-top: 32px;
    font-size: 15px;
    padding: 16px 32px;
    min-height: 54px;
    /* Tighter than the desktop 14px gap — reads as oddly separated between
       icon and text at mobile button scale. */
    gap: 10px;
  }
  .tw-splash-arrow { width: 19px; height: 19px; }
  .tw-splash-rule { margin: 16px auto; }
  /* Sized down and pushed up slightly so the "Leasing By" lockup clears the
     bottom safe area on real phones instead of crowding it. */
  .tw-splash-devon-wrap { bottom: 34px; gap: 9px; }
  .tw-splash-devon-img { width: clamp(85px, 24vw, 119px); }

  #tw-vignette-top {
    height: 240px;
    background: linear-gradient(to bottom,
      rgba(var(--sr-ink-rgb), 0.82) 0%, rgba(var(--sr-ink-rgb), 0.78) 15%, rgba(var(--sr-ink-rgb), 0.65) 30%,
      rgba(var(--sr-ink-rgb), 0.47) 45%, rgba(var(--sr-ink-rgb), 0.28) 60%, rgba(var(--sr-ink-rgb), 0.12) 75%,
      rgba(var(--sr-ink-rgb), 0.02) 90%, rgba(var(--sr-ink-rgb), 0) 100%
    );
  }
  #tw-vignette-bottom {
    height: 200px;
    background: linear-gradient(to top,
      rgba(var(--sr-ink-rgb), 0.40) 0%, rgba(var(--sr-ink-rgb), 0.38) 15%, rgba(var(--sr-ink-rgb), 0.32) 30%,
      rgba(var(--sr-ink-rgb), 0.23) 45%, rgba(var(--sr-ink-rgb), 0.14) 60%, rgba(var(--sr-ink-rgb), 0.06) 75%,
      rgba(var(--sr-ink-rgb), 0.01) 90%, rgba(var(--sr-ink-rgb), 0) 100%
    );
  }
  #tw-vignette-toast { display: none; }

  .tw-dropdown {
    position: fixed !important;
    left: 20px !important;
    right: 20px !important;
    bottom: calc(104px + env(safe-area-inset-bottom)) !important;
    top: auto !important;
    max-width: none !important;
    min-width: 0 !important;
    width: auto !important;
    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: 16px 20px 16px 32px; font-size: 16px; }
  .tw-dropdown-item::before { left: 12px; }
  .tw-dropdown-item-soon { padding: 16px 20px; }
}

@media (max-height: 680px) {
  .tw-splash-icon-img { width: clamp(50px, 10vw, 70px); margin-bottom: 10px; }
  .tw-splash-wordmark-img { width: clamp(140px, 16vw, 190px); }
  .tw-splash-rule  { margin: 18px auto; }
  .tw-splash-enter { margin-top: 22px; font-size: 13.5px; min-height: 46px; padding: 13px 28px; }
  #tw-menu-bar     { bottom: calc(10px + env(safe-area-inset-bottom)); }
  .tw-menu-pill    { height: 58px; }
  .tw-menu-btn     { height: 46px; font-size: 14px; }
  #tw-vignette-top { height: 180px; }
}

/* Danny 2026-08-10: "the unit selector pill can block the text here for some
   units/screen sizes." Real gap, not just a longer-unit-name issue — the
   query above drops the nav pill to bottom:10px/height:58px (a 10..68px
   band), but nothing had ever adjusted #tw-toast for short viewports, so it
   was still sitting at the desktop base bottom:52px, landing squarely inside
   that band. Horizontal separation (toast left-anchored vs. pill centered)
   hides this on wide desktop windows, which is why it only showed up "for
   some screen sizes" — a short-but-still-desktop-width browser window (a
   smaller laptop, or Chrome just not maximized vertically) is exactly where
   width alone doesn't give enough of a horizontal gap to save it.
   Scoped to desktop width on purpose: the ≤1199px tablet breakpoint already
   bumps #tw-toast to bottom:104px with its own comment explaining exactly
   this clearance math, and the ≤768px mobile breakpoint moves the toast to
   the TOP of the screen entirely (bottom:auto) — folding this into the
   shared max-height query above would win the cascade on any viewport
   matching both max-width and max-height (any phone in landscape, for one)
   and silently reinstate a bottom value on a toast meant to stay top-anchored. */
@media (max-height: 680px) and (min-width: 1200px) {
  #tw-toast { bottom: 92px; }
}

/* ── 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(--sr-sand-rgb), 0), var(--sr-sand) 30%, var(--sr-white) 70%, rgba(var(--sr-paper-rgb), 0));
  box-shadow: 0 0 12px rgba(var(--sr-sand-rgb), 0.5);
}

/* ── 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(--sr-ink-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(--sr-ink-rgb), 0.95);
  border: 1px solid rgba(var(--sr-sand-rgb), 0.2);
  border-radius: 24px;
  box-shadow: 0 30px 120px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(var(--sr-sand-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(--sr-sand-rgb), 0.12);
  background: rgba(var(--sr-ink-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(--sr-paper-rgb), 0.55);
  flex-shrink: 0;
}

.tw-map-modal-title .tw-map-header-icon { color: var(--sr-sand); }
.tw-map-header-icon { color: var(--sr-sand); 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(--sr-paper-rgb), 0.72);
  text-align: left;
  white-space: nowrap;
}

.tw-map-filter {
  display: flex;
  gap: 3px;
  padding: 4.5px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(var(--sr-sand-rgb), 0.1);
  border-radius: 15px;
  flex: 1;
  max-width: 630px;
  overflow-x: auto;
  /* Branded scroller. Left unstyled, this renders as the OS default bar — a
     thick light-grey slab spanning the pill, which is what Danny caught on
     mobile. Matches the .tw-dropdown scrollbar treatment: transparent track,
     translucent sand thumb. */
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--sr-sand-rgb), 0.34) transparent;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}

.tw-map-filter::-webkit-scrollbar { height: 5px; }
.tw-map-filter::-webkit-scrollbar-track { background: transparent; }
.tw-map-filter::-webkit-scrollbar-thumb {
  background: rgba(var(--sr-sand-rgb), 0.34);
  border-radius: 99px;
}
.tw-map-filter::-webkit-scrollbar-thumb:hover { background: rgba(var(--sr-sand-rgb), 0.6); }

.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(--sr-paper-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(--sr-paper-rgb), 0.85); }
.tw-map-filter-btn.tw-active {
  background: rgba(var(--sr-sand-rgb), 0.16);
  color: var(--sr-sand);
}

.tw-map-modal-close {
  width: 54px;
  height: 54px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(var(--sr-sand-rgb), 0.30);
  border-radius: 15px;
  cursor: pointer;
  color: var(--sr-sand);
  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(--sr-white);
  background: rgba(var(--sr-sand-rgb), 0.12);
  border-color: rgba(var(--sr-sand-rgb), 0.55);
}

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

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

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

#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(--sr-ink-rgb), 0.88) !important;
  border: 1px solid rgba(var(--sr-sand-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(--sr-sand-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(--sr-sand-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='%23F5F8FC' 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='%23F5F8FC' 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(--sr-ink-rgb), 0.88);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(var(--sr-sand-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(--sr-paper-rgb), 0.55);
  cursor: pointer;
  touch-action: manipulation;
  transition: background 0.18s, color 0.18s;
}

.tw-map-layer-btn:hover     { color: rgba(var(--sr-paper-rgb), 0.85); }
.tw-map-layer-btn.tw-active { background: rgba(var(--sr-sand-rgb), 0.16); color: var(--sr-sand); }

/* ── 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(--sr-ink-rgb), 0.92);
  border: 1.5px solid rgba(var(--sr-sand-rgb), 0.5);
  border-radius: 50%;
  color: var(--sr-white);
  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(--sr-sand);
  background: rgba(var(--sr-ink-rgb), 0.98);
  color: var(--sr-sand);
}

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

.tw-map-aerial-pin {
  position: relative;
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--sr-sand);
  border: 1.5px solid rgba(var(--sr-ink-rgb), 0.9);
  border-radius: 12px;
  color: var(--sr-ink);
  cursor: pointer;
  box-shadow: 0 6px 21px rgba(0, 0, 0, 0.7), 0 0 0 4.5px rgba(var(--sr-sand-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(--sr-sand-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(--sr-sand);
  background: rgba(var(--sr-ink-rgb), 0.96);
  border: 1px solid var(--sr-sand);
  border-radius: 15px;
  text-align: center;
  box-sizing: border-box;
}

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

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

.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(--sr-sand);
}

.tw-map-poi-popup .tw-map-poi-name {
  font-family: var(--tw-serif);
  font-size: 24px;
  font-weight: 400;
  color: var(--sr-white);
  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(--sr-paper-rgb), 0.55);
  margin-top: 6px;
}

body.tw-modal-open { overflow: hidden; }

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

@media (max-width: 768px) {
  .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; }
  /* The five filter labels don't fit at phone width, so this row scrolls. Two
     things make that read as intentional rather than broken: the buttons stop
     stretching (`flex: 0 0 auto`) so each keeps its natural width instead of
     being squeezed, and the trailing edge fades out — a half-cut chip under a
     fade says "there's more" far better than a scrollbar does. Extra
     padding-bottom leaves room for the slim scroller without it sitting on
     top of the buttons. */
  .tw-map-filter {
    order: 3;
    flex-basis: 100%;
    max-width: none;
    padding-bottom: 7px;
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
  }
  .tw-map-filter-btn { flex: 0 0 auto; 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; }
}

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

@media (prefers-reduced-motion: reduce) {
  .tw-splash-icon-img,
  .tw-splash-wordmark-img,
  .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-loader,
  .tw-loader-fill,
  #tw-map-modal,
  .tw-map-modal-card,
  .tw-map-poi-chip,
  .tw-map-pin-large,
  .tw-map-aerial-pin,
  #tw-hint-overlay,
  .tw-hint-card,
  .tw-hint-pointer { transition: none; animation: none; }
  .tw-loader-fill { transform: scaleX(1); }
}
