/* The tour viewer. Deliberately close to the look Drew is replacing: the
   panorama is the whole page, and everything else is a translucent slab
   floating over it. Nothing here is a framework -- it is one page. */

:root {
  --panel: rgba(38, 40, 44, 0.82);
  --panel-solid: #26282c;
  --ink: #fff;
  --accent: #ff3b30;          /* the you-are-here dot and its view cone */
  --dot: #2f9ae0;             /* every other station */
  --radius: 14px;
  --shadow: 0 6px 28px rgba(0, 0, 0, 0.42);
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #111;
  font: 400 14px/1.4 Roboto, system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

#stage {
  position: fixed;
  inset: 0;
  touch-action: none;
  cursor: grab;
}
#stage.dragging { cursor: grabbing; }
#stage.overhotspot { cursor: pointer; }
#stage canvas { display: block; }

.pill {
  position: fixed;
  padding: 9px 20px;
  border-radius: 999px;
  background: var(--panel);
  backdrop-filter: blur(6px);
  box-shadow: var(--shadow);
  font-size: 14px;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

#address {
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  max-width: min(560px, calc(100vw - 140px));  /* clear of the menu button */
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ------------------------------------------------------------------- menu */

#menu {
  position: fixed;
  left: 16px;
  top: 16px;
  z-index: 4;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius);
  background: var(--panel);
  backdrop-filter: blur(6px);
  box-shadow: var(--shadow);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.15s;
}
#menu:hover { background: rgba(58, 61, 66, 0.92); }
#menu[aria-expanded="true"] { background: rgba(58, 61, 66, 0.92); }

#menupanel {
  position: fixed;
  left: 16px;
  top: 68px;
  z-index: 4;
  min-width: 248px;
  padding: 7px;
  display: grid;
  gap: 2px;
}
#menupanel[hidden] { display: none; }

.mitem {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s;
}
.mitem:hover { background: rgba(255, 255, 255, 0.12); }
.mitem[hidden] { display: none; }
.mitem:disabled { opacity: 0.55; cursor: default; }

/* The measurements toggle: an empty well that gains a check. */
.mitem .tick {
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.16);
}
.mitem[aria-pressed="true"] .tick {
  background: var(--accent)
    no-repeat center/12px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.8 9 10 3.2' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

#sizerow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px 6px;
  margin-top: 3px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 13px;
  opacity: 0.94;
}
#sizes { display: flex; gap: 4px; }
#sizes button {
  width: 30px;
  height: 28px;
  border: 0;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.12);
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background 0.15s;
}
#sizes button:hover { background: rgba(255, 255, 255, 0.24); }
#sizes button.on { background: var(--accent); }

/* ----------------------------------------------------- room measurements */

/* The page behind the menu's Room measurements item: every room, floor by
   floor, with its overall size. The whole screen -- it replaces the tour
   until Back to tour -- with the list in a readable centred column. */

#measures {
  position: fixed;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  background: rgba(24, 26, 29, 0.97);
  backdrop-filter: blur(10px);
}
#measures[hidden] { display: none; }

#measures header {
  flex: none;
  width: min(620px, 100%);
  margin: 0 auto;
  padding: 18px 16px 10px;
  display: flex;
  align-items: center;
  gap: 14px;
}
#measures h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
}
#measureback {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px 8px 10px;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: background 0.15s;
}
#measureback:hover { background: rgba(255, 255, 255, 0.26); }

/* The units tab: imperial or metric for the whole list, one always on. */
#units {
  flex: none;
  width: min(620px, 100%);
  margin: 0 auto;
  padding: 0 16px 10px;
  display: flex;
  gap: 4px;
}
#units button {
  flex: 1;
  padding: 7px 0;
  border: 0;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.12);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: background 0.15s;
}
#units button:hover { background: rgba(255, 255, 255, 0.24); }
#units button.on { background: var(--accent); }

#measurelist {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  width: min(620px, 100%);
  margin: 0 auto;
  padding: 0 16px 16px;
  display: grid;
  gap: 4px;
  align-content: start;
}

#measures footer {
  flex: none;
  width: min(620px, 100%);
  margin: 0 auto;
  padding: 4px 16px 16px;
}
#measures footer .mitem { width: 100%; }

.mfloor {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 12px 2px 3px;
}
.mfloor:first-child { margin-top: 2px; }
.mfloor .fname { font-size: 13px; font-weight: 600; }
.mfloor .farea { font-size: 12px; opacity: 0.6; white-space: nowrap; }

.mrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 11px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.07);
  font-size: 13px;
}
.mrow .size {
  opacity: 0.85;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* The one control on the page: draw these onto the little plan too. */
#showdims {
  padding-top: 11px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0;
}

#loading {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transition: opacity 0.25s;
}
#loading[hidden] { display: block; opacity: 0; pointer-events: none; }

.panel {
  background: var(--panel);
  backdrop-filter: blur(6px);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

#failed {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 18px 22px;
  max-width: 460px;
  line-height: 1.5;
}
#failed code {
  display: block;
  margin-top: 8px;
  opacity: 0.7;
  font-size: 12px;
  word-break: break-all;
}

/* -------------------------------------------------------------- stairways */

/* A button that belongs to a place in the house rather than to the screen. It
   is a DOM element and not something drawn into the panorama, because the two
   are worth exactly the same amount of immersion -- there is no geometry in the
   scene for a sprite to be occluded by, it is one photograph on a sphere -- and
   this way the lettering is crisp at any distance, it inherits the rest of the
   viewer's look, and it is a real <button> that tabs and reads out loud. The
   only thing viewer.js has to do is keep it over the right pixel. */

#stairnav {
  position: fixed;
  inset: 0;
  overflow: hidden;         /* a marker projected off-screen must not scroll it */
  pointer-events: none;     /* the panorama drags right through the gaps */
}

/* One per spot on the floor. A stacked stairwell -- the same footprint serving
   the flight up and the flight down, which is most houses -- puts two buttons
   on one spot, so they stack here rather than fighting over the same pixel. */
.stairmark {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
}
.stairmark[hidden] { display: none; }

.stairlink {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 8px 16px 8px 9px;
  border: 0;
  border-radius: 999px;
  background: var(--panel);
  backdrop-filter: blur(6px);
  box-shadow: var(--shadow);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s, transform 0.15s ease-out;
}
.stairlink:hover, .stairlink:focus-visible {
  background: rgba(58, 61, 66, 0.92);
  transform: scale(1.06);
}
.stairlink:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.stairlink .arrow { flex: none; }
.stairlink.down .arrow { transform: rotate(180deg); }

@media (max-width: 560px) {
  .stairlink { font-size: 12px; padding: 7px 13px 7px 8px; gap: 7px; }
}

/* ---------------------------------------------------------------- minimap */

#map {
  position: fixed;
  left: 16px;
  bottom: 16px;
  width: min(var(--map-w), calc(100vw - 32px));
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#map[hidden] { display: none; }

#map header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}
#map h1 {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.15;
  opacity: 0.92;
}

#collapse, #expand {
  flex: none;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: var(--ink);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s;
}
#collapse:hover, #expand:hover { background: rgba(255, 255, 255, 0.26); }

#expand {
  position: fixed;
  left: 16px;
  bottom: 16px;
  width: 44px;
  height: 44px;
  background: var(--panel);
  backdrop-filter: blur(6px);
  box-shadow: var(--shadow);
  border-radius: var(--radius);
}
#expand[hidden] { display: none; }

/* The rendered plan and the live overlay share one box and one viewBox, so a
   station dot drawn at plan-mm-through-`frame` lands exactly on its room. */
/* The plan DRAWING sets the height and the overlay is stretched over whatever
   that turns out to be. Anything else drifts: give the box its own height and
   the two layers letterbox their shared viewBox by different amounts, so the
   station dots sit lower than the rooms they mark -- by a distance that changes
   with the height of the window, which is a strange bug to look at.

   A floor plan can be any shape (this house's 2nd floor is twice as tall as it
   is wide) so the height still has to be capped, but the cap is applied to the
   WIDTH -- max-width = the tallest map we want, times the drawing's own aspect.
   Height then follows from the drawing and lands exactly on the cap, with no
   second constraint to disagree with it. --ar comes from the published frame.

   Both dimensions are variables because the menu offers three panel sizes:
   viewer.js writes --map-w and --map-max-h inline on the root, so the short-
   window media query below caps through --map-cap rather than overriding
   --map-max-h -- an inline style would win that fight every time. */
:root { --map-w: 330px; --map-max-h: 46vh; }

#stagemap {
  position: relative;
  width: 100%;
  max-width: calc(min(var(--map-max-h), var(--map-cap, 200vh)) * var(--ar, 1.6));
  margin: 0 auto;
  border-radius: 8px;
  overflow: hidden;
}
#mapsvg svg {
  display: block;
  width: 100%;
  height: auto;
}
/* inset alone: the overlay takes the box the drawing just defined, so the two
   share one geometry by construction rather than by both being told a size. */
#overlay { position: absolute; inset: 0; }

/* Hovering is driven by a class, not by :hover, so that pointing at a ring out
   in the panorama lights the matching dot on the plan as well -- which is the
   half that actually answers "where am I about to go?". */
/* Scaled about its own bounding box, so the whole mark grows in place. Putting
   the transform on the outer group avoids fighting the translate/scale that
   positions the mark -- in SVG those are the same property, and a CSS transform
   on that element would throw the placement away. */
.station {
  cursor: pointer;
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.16s ease-out;
}
.station.hovered { transform: scale(1.16); }

/* Invisible until hovered, but still hittable: on a small map the mark is only
   a few pixels across, and this quietly makes it a comfortable target. */
.station .halo {
  opacity: 0;
  transition: opacity 0.16s ease-out;
}
.station.hovered .halo { opacity: 0.34; }

#floorpick { display: block; }
#floors {
  width: 100%;
  padding: 9px 12px;
  border: 0;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.14) no-repeat right 10px center/12px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23fff' stroke-width='1.8'/%3E%3C/svg%3E");
  color: var(--ink);
  font: inherit;
  cursor: pointer;
  appearance: none;
}
#floors:focus-visible { outline: 2px solid var(--accent); }
#floorpick:has(#floors option:only-child) { display: none; }
#floors option { background: var(--panel-solid); }

/* ------------------------------------------------------------ agent card */

/* Who is selling the house. Everything in here is filled in from the branding
   endpoint at load; the markup is built in viewer.js so that an unbranded
   tour carries no empty scaffolding.

   It sits bottom-right because bottom-left is the floor plan. On a phone
   there is not room for both, so it starts as the chip below and the card is
   something you ask for. */

#agent {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 3;
  width: 264px;
  max-width: calc(100vw - 32px);
  padding: 14px;
  display: grid;
  gap: 11px;
}
#agent[hidden] { display: none; }
/* Below the menu button, which owns the very corner. */
#agent.left { right: auto; bottom: auto; left: 16px; top: 68px; }

#agent .note {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  opacity: 0.62;
}

#agent .who {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}
#agent .shot {
  flex: none;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  background: rgba(255, 255, 255, 0.14);
}
#agent .name { font-size: 15px; font-weight: 500; line-height: 1.25; }
#agent .title, #agent .brokerage { font-size: 12px; opacity: 0.7; line-height: 1.35; }
#agent .logo {
  max-width: 100%;
  max-height: 28px;
  object-fit: contain;
  object-position: left center;
}

#agent .links { display: flex; gap: 6px; }
#agent .links a {
  flex: 1;
  padding: 8px 4px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.14);
  color: var(--ink);
  font-size: 12px;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s;
}
#agent .links a:hover { background: rgba(255, 255, 255, 0.26); }
/* The one thing somebody is meant to do next. */
#agent .links a.call { background: var(--accent); }
#agent .links a.call:hover { background: var(--accent); filter: brightness(1.12); }

#agent .fold {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  font-size: 15px;
  line-height: 1;
  opacity: 0.55;
  cursor: pointer;
}
#agent .fold:hover { opacity: 1; background: rgba(255, 255, 255, 0.14); }

/* Folded away: a headshot you can tap. Same corner, so it does not move. */
#agentchip {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 3;
  width: 52px;
  height: 52px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  overflow: hidden;
  background: var(--panel);
  box-shadow: var(--shadow);
  color: var(--ink);
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
}
#agentchip[hidden] { display: none; }
#agentchip.left { right: auto; bottom: auto; left: 16px; top: 68px; }
#agentchip img { display: block; width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 560px) {
  /* The chosen size still applies, scaled down to phone proportions. */
  #map {
    width: min(calc(var(--map-w) * 0.72), calc(100vw - 24px));
    left: 12px;
    bottom: 12px;
  }
  #address { font-size: 13px; padding: 8px 14px; }
  #menu { left: 12px; top: 12px; }
  #menupanel { left: 12px; top: 64px; max-width: calc(100vw - 24px); }
  /* The map and the card cannot both have a bottom corner on a phone, so the
     card gets the full width and sits above the map only while it is open. */
  #agent { right: 12px; bottom: 12px; width: min(264px, calc(100vw - 24px)); }
  #agent.left { left: 12px; top: 64px; }
  #agentchip { right: 12px; bottom: 12px; }
  #agentchip.left { left: 12px; top: 64px; }
}

/* A short window is where the map crowds the tour most, so give it less --
   through its own variable, because --map-max-h is set inline by the size
   control and an inline style outranks anything written here. */
@media (max-height: 620px) {
  :root { --map-cap: 32vh; }
}
