/* =========================================================
   Bluez360 — Home.
   Four places, each one full bleed and live. The chrome
   never argues with the photograph.
   ========================================================= */

:root {
  --sc-canvas:     #06090D;
  --sc-surface:    #0C1219;
  --sc-ink:        #FFFFFF;
  --sc-ink-soft:   #C2D0DC;
  --sc-accent:     #4FB0FF;
  --sc-accent-ink: #04121F;
  --sc-font-display: "Archivo", system-ui, sans-serif;
  --sc-font-text:    "Instrument Sans", system-ui, sans-serif;
  --sc-shadow-color: 212 45% 3%;
}

html { background: #000; }
body { background: var(--sc-canvas); }

/* ---------------------------------------------------------
   A room: a live panorama that fills the screen.
   Nothing above it may steal a drag, so every copy layer is
   pointer-transparent and only links take the pointer back.
   --------------------------------------------------------- */
/* The four rooms are stacked in one pinned viewport rather than laid out
   one after another down the page. Laid out, each room's photograph slid
   past the next one's with a hard horizontal edge between them, and four
   of those edges travelling up the screen is what made the page look
   partitioned. Stacked, a room dissolves into the one behind it and there
   is no edge at all.

   The reel's height is what buys the scrolling: one screen for each room's
   turn, plus the screen the viewport itself occupies. js/pano360.js reads
   that height and nothing else to know where the reel has got to, so the
   pace of the whole sequence is this one number. */
.rooms { --room-run: 1.7; position: relative; }
.rooms { height: calc((4 * var(--room-run) + 1) * 100vh); }
@supports (height: 100svh) {
  .rooms { height: calc((4 * var(--room-run) + 1) * 100svh); }
}

.rooms__view {
  position: sticky; top: 0;
  height: 100vh; height: 100svh;
  overflow: hidden;
}

/* Opacity is written every frame from script, so it must not be
   transitioned as well -- a transition would chase the value it is already
   being given and turn a crossfade into a lag. `visibility` is what keeps
   a faded-out room's links out of the tab order. */
.room {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden;
  transition: none;
}
.room__stage { position: absolute; inset: 0; overflow: hidden; background: #000; }

/* Our own canvas now, not an embed. It fills the stage exactly, never
   takes the pointer, and has no chrome of its own to hide -- which is why
   there is no longer a chip to push off the top, no shield to catch the
   finger, and nothing in the corner that belongs to somebody else.

   It fades up rather than snapping in: the texture arrives a moment after
   the element does, and an unpainted canvas is a black rectangle.

   The still behind it is the same photograph the canvas would have drawn.
   It is only fetched where WebGL is missing, and a picture of the place
   you cannot turn beats an empty room. */
.room__pano {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; display: block; z-index: 0;
  pointer-events: none;
  opacity: 0; transition: opacity 900ms var(--sc-ease-out);
}
.room--painted .room__pano { opacity: 1; }

html.no-pano .room__stage {
  background-image: var(--still);
  background-size: cover; background-position: center;
}

/* Density in the corner the copy stands in — not a sheet over the photo. */
.room__scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(125% 95% at 0% 100%,
      rgba(3,6,9,0.95) 0%,
      rgba(3,6,9,0.88) 26%,
      rgba(3,6,9,0.58) 52%,
      rgba(3,6,9,0.14) 76%,
      rgba(3,6,9,0) 90%);
}
/* ---------------------------------------------------------
   The count. Where you are in the four, and nothing more.
   The place is the chapter; it does not need a chapter name
   invented on top of it.
   --------------------------------------------------------- */
.plate__num {
  margin: 0 0 var(--sc-4);
  display: flex; align-items: center; gap: var(--sc-3);
  font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; color: #B9C8D6;
  text-shadow: 0 1px 12px rgba(0,0,0,0.85);
}
.plate__num b {
  font-family: var(--sc-font-display); font-weight: 700;
  font-size: var(--sc-t-base); color: #fff;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
/* The dash between the number and "of four" doubles as the room's playhead.
   Street View will not be scrubbed, so the only honest way to say "this shot
   is running" is to show how far through it the reader is. */
.plate__num i {
  position: relative; display: block; overflow: hidden;
  width: 64px; height: 2px; border-radius: 2px;
  background: rgba(255,255,255,0.22);
}
.plate__num i::after {
  content: ""; position: absolute; inset: 0;
  background: var(--sc-accent);
  transform: scaleX(var(--sc-p, 0)); transform-origin: left center;
}

/* ---------------------------------------------------------
   The plate. One schema for every room, no exceptions.
   --------------------------------------------------------- */
.plate {
  position: absolute; z-index: 4; pointer-events: none;
  left: var(--sc-gutter); bottom: clamp(2.5rem, 9vh, 6rem);
  max-width: min(46ch, calc(100% - var(--sc-gutter) * 2));
}
.plate a, .plate button { pointer-events: auto; }

.plate__name {
  font-family: var(--sc-font-display);
  font-size: var(--sc-t-2xl); font-weight: 700;
  letter-spacing: var(--sc-track-tight); line-height: 0.98;
  margin: 0; color: #fff; text-wrap: balance;
  text-shadow: 0 2px 24px rgba(0,0,0,0.6);
}
.plate__name--sm { font-size: var(--sc-t-xl); }
.plate__fact {
  margin: var(--sc-4) 0 0; font-size: var(--sc-t-lg); line-height: 1.4;
  color: #EAF2F9; max-width: 34ch;
  text-shadow: 0 1px 16px rgba(0,0,0,0.65);
}
.plate__meta {
  margin: var(--sc-5) 0 0; display: flex; flex-wrap: wrap; gap: var(--sc-2) var(--sc-4);
  font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; color: #CBD9E6;
  text-shadow: 0 1px 12px rgba(0,0,0,0.7);
}
.plate__meta a {
  font-weight: 600; color: var(--sc-accent); text-decoration: none;
  border-bottom: 1px solid rgba(79, 176, 255, 0.45);
}
.plate__meta a:hover { color: #fff; border-bottom-color: #fff; }

/* ---------------------------------------------------------
   Top chrome. Sits clear of Google's own controls, which draw
   a title chip top-left and a fullscreen button top-right.
   --------------------------------------------------------- */
.topbar {
  position: fixed; z-index: var(--sc-z-chrome);
  left: var(--sc-gutter); right: var(--sc-gutter);
  top: clamp(0.9rem, 2.4vh, 1.5rem);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sc-4);
  padding: 0.45rem 0.5rem 0.45rem 0.6rem;
  border-radius: var(--sc-r-pill);
  background: linear-gradient(180deg, rgba(12,20,28,0.9), rgba(6,11,16,0.86));
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.13),
    inset 0 1px 0 0 rgba(255,255,255,0.09),
    0 14px 40px rgba(0,0,0,0.45);
}

.mark {
  display: inline-flex; align-items: center; gap: var(--sc-3);
  flex: none; text-decoration: none;
  padding: 0.2rem 0.7rem 0.2rem 0.2rem;
}
.mark img {
  display: block; width: auto; height: clamp(30px, 4.2vw, 38px);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(255,255,255,0.22), 0 4px 14px rgba(0,0,0,0.5);
}
.mark__word {
  font-family: var(--sc-font-display); font-weight: 700;
  font-size: var(--sc-t-base); letter-spacing: -0.02em; color: #fff;
  white-space: nowrap;
}
.mark__word b { color: var(--sc-accent); font-weight: 700; }

.topnav { display: none; gap: var(--sc-1); align-items: center; }
@media (min-width: 1120px) { .topnav { display: flex; } }
.topnav a {
  position: relative;
  padding: 0.5rem 0.75rem; border-radius: var(--sc-r-pill);
  font-size: var(--sc-t-xs); font-weight: 500;
  letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; color: #B9C8D6; text-decoration: none;
  transition: color var(--sc-d-fast) var(--sc-ease-out),
              background var(--sc-d-fast) var(--sc-ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .topnav a:hover { color: #fff; background: rgba(255,255,255,0.08); }
}
/* The page you are on wears the accent, so the bar always answers
   "where am I" before it answers "where can I go". */
.topnav a[aria-current="page"] {
  color: #fff;
  background: rgba(79, 176, 255, 0.22);
  box-shadow: inset 0 0 0 1px rgba(79, 176, 255, 0.5);
}
.book-top {
  flex: none;
  font-size: var(--sc-t-xs); font-weight: 600;
  letter-spacing: var(--sc-track-wide); text-transform: uppercase;
  padding: 0.6rem 1.1rem; border-radius: var(--sc-r-pill);
  background: var(--sc-accent); color: var(--sc-accent-ink); text-decoration: none;
  box-shadow: 0 6px 22px rgba(79, 176, 255, 0.28);
  transition: transform 140ms var(--sc-ease-out), filter 140ms var(--sc-ease-out);
}
.book-top:active { transform: translateY(1px); }
@media (hover: hover) and (pointer: fine) { .book-top:hover { filter: brightness(1.08); } }

/* On a phone the booking button gives its place to the menu; the menu
   carries the same button as its last item, so nothing is lost. */
.burger {
  display: grid; gap: 5px; padding: 10px; margin: -10px;
  background: none; border: 0; cursor: pointer;
}
.burger span {
  display: block; width: 24px; height: 2px; background: #fff;
  box-shadow: 0 1px 6px rgba(0,0,0,0.7);
  transition: transform 240ms var(--sc-ease-out), opacity 160ms var(--sc-ease-out);
}
/* Nothing behind an open panel scrolls -- the phone menu and the quote
   form both set this. On a phone the panel scrolls inside itself and
   the two were fighting over the same finger; on a desktop the page
   sliding behind a full-screen menu just reads as broken. */
html.locked, html.locked body { overflow: hidden; }

body.menu-open .burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
body.menu-open .burger span:nth-child(2) { opacity: 0; }
body.menu-open .burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (min-width: 1120px) { .burger { display: none; } }
@media (max-width: 1119px) { .book-top { display: none; } }

.drawer {
  position: fixed; inset: 0; z-index: calc(var(--sc-z-chrome) - 1);
  display: flex; flex-direction: column; justify-content: center; gap: var(--sc-5);
  padding: var(--sc-gutter);
  background: rgba(4, 8, 12, 0.96);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.drawer[hidden] { display: none; }
.drawer__logo {
  width: 56px; height: 56px; border-radius: 50%;
  margin-bottom: var(--sc-4);
  box-shadow: 0 0 0 1px rgba(255,255,255,0.2);
}
.drawer a {
  font-family: var(--sc-font-display); font-weight: 600;
  font-size: var(--sc-t-xl); letter-spacing: var(--sc-track-tight);
  color: #EAF2F8; text-decoration: none;
}
.drawer a[aria-current="page"] { color: var(--sc-accent); }
.drawer__cta {
  align-self: flex-start; margin-top: var(--sc-4);
  font-family: var(--sc-font-text) !important; font-size: var(--sc-t-base) !important;
  padding: 0.75rem 1.4rem; border-radius: var(--sc-r-pill);
  background: var(--sc-accent); color: var(--sc-accent-ink) !important;
}

/* ---------------------------------------------------------
   The close.
   --------------------------------------------------------- */
.close__cta {
  display: inline-block; margin-top: var(--sc-5);
  font-size: var(--sc-t-lg); font-weight: 600;
  padding: 0.85rem 1.6rem; border-radius: var(--sc-r-pill);
  background: var(--sc-accent); color: var(--sc-accent-ink); text-decoration: none;
  box-shadow: 0 10px 34px rgba(0,0,0,0.5);
  transition: transform 140ms var(--sc-ease-out), filter 140ms var(--sc-ease-out);
}
.close__cta:active { transform: translateY(1px); }
@media (hover: hover) and (pointer: fine) { .close__cta:hover { filter: brightness(1.08); } }
.close__lines {
  margin: var(--sc-5) 0 0; display: grid; gap: var(--sc-1);
  font-size: var(--sc-t-sm); color: #DCE7F1; text-shadow: 0 1px 12px rgba(0,0,0,0.8);
}
.close__lines a { color: #DCE7F1; text-decoration: none; border-bottom: 1px solid rgba(255,255,255,0.34); }
.close__lines a:hover { color: #fff; }

/* Where the story hands off to the other pages. */
.doors { display: flex; flex-wrap: wrap; gap: var(--sc-3); margin-top: var(--sc-5); }
.door {
  font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); text-transform: uppercase;
  padding: 0.5rem 1rem; border-radius: var(--sc-r-pill);
  background: rgba(6,11,16,0.82); color: #EAF2F8; text-decoration: none;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.2);
  transition: background var(--sc-d-fast) var(--sc-ease-out), color var(--sc-d-fast) var(--sc-ease-out);
}
.door:hover { background: rgba(79, 176, 255, 0.18); color: #fff; }

/* ---------------------------------------------------------
   Phones. A 100vh room with Google's own chrome in two
   corners leaves a narrow band for ours, so the plate keeps
   the bottom, the chapter mark keeps the top, and everything
   between them belongs to the photograph.
   --------------------------------------------------------- */
@media (max-width: 760px) {
  .topbar { top: max(0.9rem, calc(env(safe-area-inset-top) + 0.6rem)); }
}

@media (max-width: 760px) {
  .plate {
    left: var(--sc-gutter); right: var(--sc-gutter); max-width: none;
    bottom: max(2.6rem, calc(env(safe-area-inset-bottom) + 2.2rem));
  }
  .plate__name { font-size: var(--sc-t-lg); line-height: 1.12; }
  .plate__fact { font-size: var(--sc-t-sm); max-width: none; }
  .plate__meta { margin-top: var(--sc-4); }
  .plate__num { margin-bottom: var(--sc-3); }

  .doors { gap: var(--sc-2); }
  .door { padding: 0.45rem 0.8rem; }
  .close__cta { font-size: var(--sc-t-base); padding: 0.75rem 1.35rem; }

  .room__scrim {
    background: linear-gradient(to top,
      rgba(3,6,9,1) 0%, rgba(3,6,9,0.98) 26%, rgba(3,6,9,0.58) 43%, rgba(3,6,9,0) 62%);
  }
}

/* =========================================================
   BELOW THE PANORAMAS

   The four rooms are the argument. Everything under them is
   the answer sheet: why, what else, who, and how to reach
   him. It stops moving here on purpose — after four screens
   of live photography, stillness is the premium note.
   ========================================================= */

.band { position: relative; background: var(--sc-canvas); padding: clamp(3.5rem, 8vh, 6rem) 0; }
.band + .band { border-top: 1px solid var(--sc-hairline); }
.wrap {
  position: relative; z-index: 1;
  width: 100%; max-width: 76rem; margin: 0 auto;
  padding-inline: var(--sc-gutter);
}

/* ---------------------------------------------------------
   The places, behind the copy.

   Below the reel the page was flat: dark panels of text that
   could have belonged to any business. Each band now stands
   in one of the panoramas and turns slowly through it as you
   scroll, so the whole page keeps looking around rather than
   stopping the moment the heroes end.

   They cost nothing to load. These are the same four 2048s
   the reel already fetched, so the browser serves them from
   cache, and a different one goes behind each band so the
   page travels through the city instead of circling one car
   park.

   The layer is wider than the band and slides within it, so
   there is no edge to catch however far it travels. It moves
   by transform, which the compositor handles on its own --
   panning `background-position` instead would repaint the
   band on every frame.
   --------------------------------------------------------- */
/* Faded off at the top and bottom rather than cut. A backdrop that stops
   on a straight line announces itself as a rectangle pasted behind the
   words; dissolved into the page at either end it reads as depth. The
   mask sits on the wrapper so the darkening scrim goes with it and the
   edges land on the band's own colour, not on a half-lit strip. */
.band__pan {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden; pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 13%, #000 87%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 13%, #000 87%, transparent 100%);
}
.band__pan i {
  position: absolute; inset: -4% -16%;
  background-position: center; background-size: cover;
  transform: translate3d(calc(var(--sc-p, 0) * 11% - 5.5%), 0, 0);
  /* Held well down. This is the room the words are standing in, not a
     picture competing with them -- at any strength where you would call it
     a photograph, the body copy stops being readable. */
  opacity: 0.26;
}
/* Darkest where the copy starts, clearing towards the far edge, so the
   band reads as lit from one side rather than as a flat tint. */
.band__pan::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(105deg,
    rgba(3, 6, 9, 0.90) 0%,
    rgba(3, 6, 9, 0.70) 42%,
    rgba(3, 6, 9, 0.46) 78%,
    rgba(3, 6, 9, 0.38) 100%);
}

@media (prefers-reduced-motion: reduce) {
  .band__pan i { transform: none; }
}

.band__kicker {
  margin: 0 0 var(--sc-4);
  font-size: var(--sc-t-xs); font-weight: 500;
  letter-spacing: var(--sc-track-wide); text-transform: uppercase;
  color: var(--sc-accent);
}
.band__head {
  margin: 0; max-width: 22ch;
  font-family: var(--sc-font-display); font-weight: 700;
  font-size: var(--sc-t-2xl); line-height: 1.04;
  letter-spacing: var(--sc-track-tight); color: var(--sc-ink);
  text-wrap: balance;
}
.band__text {
  margin: var(--sc-6) 0 0; max-width: 60ch;
  font-size: var(--sc-t-base); line-height: 1.65; color: var(--sc-ink-soft);
}

/* The one button shape on the page below the fold. */
.btn {
  display: inline-block; margin-top: var(--sc-6);
  font-size: var(--sc-t-xs); font-weight: 600;
  letter-spacing: var(--sc-track-wide); text-transform: uppercase;
  padding: 0.8rem 1.5rem; border-radius: var(--sc-r-pill);
  color: var(--sc-ink); text-decoration: none;
  /* Spelled out because this is worn by <button> as well as <a>, and a
     button's own default ground is near-white -- which with white type
     on it is an invisible label. */
  background: transparent; border: 0;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.22);
  transition: background var(--sc-d-fast) var(--sc-ease-out),
              box-shadow var(--sc-d-fast) var(--sc-ease-out);
}
.btn:hover { background: rgba(255,255,255,0.07); box-shadow: inset 0 0 0 1px rgba(255,255,255,0.4); }
.btn--solid {
  background: var(--sc-accent); color: var(--sc-accent-ink);
  box-shadow: 0 8px 26px rgba(79, 176, 255, 0.26);
}
.btn--solid:hover { background: var(--sc-accent); filter: brightness(1.08); box-shadow: 0 8px 26px rgba(79, 176, 255, 0.34); }

/* ---------------------------------------------------------
   Page heads. Home opens on a full screen of photograph;
   there is no room for that anywhere else, and a screenful
   before the first real thing on the page is a toll charged
   on the way to it. One short band instead, deep enough to
   clear the fixed bar and to read as an opening rather than
   as the section that happens to be first.
   --------------------------------------------------------- */
.pagehead {
  position: relative;
  padding: calc(var(--sc-9) + 4.5rem) 0 var(--sc-8);
  background: var(--sc-canvas);
  overflow: hidden;
}
.pagehead__pan {
  position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
}
/* Held further down than a band's backdrop. A heading has less around it
   to hold it up, so the picture behind has to give more ground. */
.pagehead__pan i {
  position: absolute; inset: -6% -10%;
  background-position: center; background-size: cover;
  transform: translate3d(calc(var(--sc-p, 0) * 7% - 3.5%), 0, 0);
  opacity: 0.3;
}
/* Two scrims: one down, to hand the photograph over to the page colour so
   the first band starts on solid ground; one across, to keep the side the
   words are on the darker one. */
.pagehead__pan::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to bottom, rgba(3, 6, 9, 0.92) 0%, rgba(3, 6, 9, 0.5) 55%, var(--sc-canvas) 100%),
    linear-gradient(100deg, rgba(3, 6, 9, 0.84) 0%, rgba(3, 6, 9, 0.42) 62%, rgba(3, 6, 9, 0.28) 100%);
}
.pagehead__title {
  margin: 0; max-width: 18ch;
  font-family: var(--sc-font-display); font-weight: 700;
  font-size: var(--sc-t-3xl); line-height: 1.02;
  letter-spacing: var(--sc-track-tight); color: var(--sc-ink);
}
.pagehead__text {
  margin: var(--sc-6) 0 0; max-width: 54ch;
  font-size: var(--sc-t-base); line-height: 1.65; color: var(--sc-ink-soft);
}

/* And the tail every one of them ends on. Nobody who has reached the
   bottom of a page wants more of it -- they want to know what it costs
   or how to start. */
.band--ask .wrap { text-align: center; }
.band--ask .band__head { max-width: 24ch; margin-inline: auto; }
.band--ask .band__text { margin-inline: auto; }
.band--ask .band__acts {
  display: flex; flex-wrap: wrap; gap: var(--sc-4);
  justify-content: center; margin-top: var(--sc-7);
}

/* ------------------------------------------------- why -- */
.reasons { list-style: none; margin: var(--sc-7) 0 0; padding: 0; display: grid; gap: var(--sc-5); }
@media (min-width: 780px) { .reasons { grid-template-columns: 1fr 1fr; gap: var(--sc-6) var(--sc-8); } }
.reasons li {
  border-top: 1px solid var(--sc-hairline); padding-top: var(--sc-5);
  font-size: var(--sc-t-base); line-height: 1.6; color: var(--sc-ink-soft);
  transition: border-color 420ms var(--sc-ease-out);
}
.reasons li b { color: var(--sc-ink); font-weight: 600; }
.reasons__row { display: flex; gap: var(--sc-4); align-items: flex-start; }

/* --- the four reasons, moving at four speeds ---------------------------

   Each row drifts at its own rate as the band goes by, so the block
   breaks apart on the way past instead of sliding as one slab. That is
   the whole of the parallax: a grid where every cell has a slightly
   different distance from the reader.

   The <li> carries the drift and the wrapper inside it carries the
   entry. They have to be separate elements, because the drift is
   rewritten on every frame and the entry is a transition -- put both on
   one element and the transition chases a value that has already moved
   on, which lags the scroll instead of tracking it.

   Rates are measured either side of the band's midpoint, so the four
   rows line up as they cross the middle of the screen and separate again
   on the way out. --sc-p defaults to 0.5 so an engine that never ran
   leaves them exactly where the layout put them. */
/* Listed twice on purpose. The engine's own `[data-sc-stagger] > .sc-in`
   sets `transform: none` and outranks a single class, so the drift has to
   be claimed again for the revealed state or it is switched off at the
   exact moment the row appears. */
.reasons li,
.reasons li.sc-in {
  --rate: 0px;
  transform: translate3d(0, calc((0.5 - var(--sc-p, 0.5)) * var(--rate)), 0);
}

/* The rise on entry lives here, one level in, where a transition is safe. */
.reasons__row {
  transform: translate3d(0, 22px, 0);
  transition: transform 1000ms var(--sc-ease-out);
}
.reasons li.sc-in .reasons__row { transform: none; }
html:not(.sc-ready) .reasons__row { transform: none; }
.reasons li:nth-child(1) { --rate: 110px; }
.reasons li:nth-child(2) { --rate: -45px; }
.reasons li:nth-child(3) { --rate: 155px; }
.reasons li:nth-child(4) { --rate: 40px; }

@media (prefers-reduced-motion: reduce) {
  /* The drift is parallax and goes. The row still fades in, in order. */
  .reasons li, .reasons li.sc-in { transform: none; }
  .reasons__row { transform: none; }
}

.reasons__icon { flex: none; color: var(--sc-accent); }
.reasons__icon svg {
  width: 30px; height: 30px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform 420ms var(--sc-ease-out);
}

/* Every shape carries pathLength="1", so one dash length draws them all
   in step however long the real outline is. Without that the circle and
   the three-stroke globe inside it would finish at different times. */
.reasons__icon svg > * {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1100ms var(--sc-ease-out) 220ms;
}
.reasons li.sc-in .reasons__icon svg > * { stroke-dashoffset: 0; }

/* An engine that never mounted must not leave four blank squares where
   the icons are. */
html:not(.sc-ready) .reasons__icon svg > * { stroke-dashoffset: 0; }


@media (hover: hover) and (pointer: fine) {
  .reasons li:hover { border-color: var(--sc-accent); }
  .reasons li:hover .reasons__icon svg { transform: scale(1.12); }
}

/* ----------------------------------------------- tours -- */
.band--tours .wrap:last-child { padding-top: 0; }
.tours { position: relative; margin: var(--sc-7) 0 var(--sc-6); }
/* Three at a time, inside the same column as everything else on the page.
   A card cut off at the window edge reads as an accident; a rail that ends
   where the text ends reads as a decision. */
.tours__track {
  display: flex; gap: var(--sc-5);
  width: 100%; max-width: 76rem; margin: 0 auto;
  padding-inline: var(--sc-gutter); padding-block: var(--sc-2);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: none;
}
.tours__track::-webkit-scrollbar { display: none; }

/* On a phone the card stops short of the full width so the next one's
   edge is always in frame. A card that fills the screen exactly reads as
   the whole of the section; an edge showing past it reads as a rail, and
   a thumb can find the rest without being told. */
.tour {
  flex: 0 0 84%; scroll-snap-align: center;
  border-radius: var(--sc-r-lg); overflow: hidden;
  background: var(--sc-surface);
  box-shadow: inset 0 0 0 1px var(--sc-hairline);
}
@media (min-width: 700px)  { .tour { flex-basis: calc((100% - var(--sc-5)) / 2); } }
@media (min-width: 1080px) { .tour { flex-basis: calc((100% - var(--sc-5) * 2) / 3); } }

/* A card is a reel, not a letterbox. At three across, a 16:10 frame left
   roughly 200px of height for a photograph that Google covers with a title
   chip, a compass, a zoom pad and an attribution bar. Portrait doubles the
   picture and the chrome stops being most of the card. */
.tour__frame { position: relative; aspect-ratio: 4 / 5; background: #000; }
/* Same trick as the hero: grow the frame past the top of its window so
   Google's grey title chip and its "View on Google Maps" line sit above the
   crop. The bottom edge does not move, so the Google logo and terms stay. */
.tour__frame iframe {
  position: absolute; left: 0; right: 0; bottom: 0;
  top: calc(var(--card-chip) * -1);
  width: 100%; height: calc(100% + var(--card-chip));
  border: 0;
}
:root { --card-chip: 74px; }
/* A YouTube frame carries no title chip to crop away, and it is the
   wrong shape for a portrait window -- letterboxed into a 4:5 card it is
   mostly black bars. It gets its own proportions. */
.tour__frame--video { aspect-ratio: 16 / 9; }
.tour__frame--video iframe { top: 0; height: 100%; }

.tour__name {
  margin: 0; padding: var(--sc-4) var(--sc-5) var(--sc-5);
  font-size: var(--sc-t-sm); font-weight: 500; line-height: 1.45; color: var(--sc-ink);
}

.tours__arrow {
  position: absolute; top: 50%; translate: 0 -50%; z-index: 2;
  width: 44px; height: 44px; border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(6, 11, 16, 0.82); color: var(--sc-ink); font-size: 1rem;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.2), 0 8px 26px rgba(0,0,0,0.5);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.tours__arrow:hover { background: rgba(79, 176, 255, 0.25); }
.tours__arrow--prev { left: max(0.5rem, calc((100% - 76rem) / 2 - 3.4rem)); }
.tours__arrow--next { right: max(0.5rem, calc((100% - 76rem) / 2 - 3.4rem)); }
@media (max-width: 700px) { .tours__arrow { display: none; } }

/* The rail indicator. Sized to the cards' own column rather than the
   full bleed -- the gutters come out of the width instead of being padded
   in, because an absolutely positioned thumb is laid out against the
   padding box and would ignore them. */
.tours__bar {
  position: relative; height: 3px;
  width: calc(100% - var(--sc-gutter) * 2);
  max-width: calc(76rem - var(--sc-gutter) * 2);
  margin: var(--sc-5) auto 0;
  border-radius: 3px; background: rgba(255, 255, 255, 0.13);
  cursor: grab; touch-action: none;
  -webkit-user-select: none; user-select: none;
}
/* A 6px ribbon is the right weight to look at and the wrong one to catch
   with a thumb, so the grab area reaches well past what is drawn. */
.tours__bar::before { content: ""; position: absolute; inset: -13px 0; }
.tours__bar--held { cursor: grabbing; }
.tours__bar i {
  position: absolute; top: -1.5px; bottom: -1.5px; left: 0; width: 20%;
  border-radius: 6px; background: var(--sc-accent);
  transition: transform 220ms var(--sc-ease-out), width 220ms var(--sc-ease-out);
}
.tours__bar:hover i { box-shadow: 0 0 0 1px rgba(79, 176, 255, 0.45); }
/* Under a finger the thumb has to be where the finger is, not easing
   toward where it was 220ms ago. */
.tours__bar--held i { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .tours__bar i { transition: none; }
}

/* ----------------------------------------------- about -- */
.about { display: grid; gap: var(--sc-8); }
@media (min-width: 900px) { .about { grid-template-columns: 1fr 1fr; gap: var(--sc-9); align-items: start; } }
.card {
  border-radius: var(--sc-r-lg); padding: var(--sc-7);
  background: var(--sc-surface);
  box-shadow: inset 0 0 0 1px var(--sc-hairline);
}
.card__head {
  margin: 0 0 var(--sc-5);
  font-family: var(--sc-font-display); font-weight: 600;
  font-size: var(--sc-t-lg); line-height: 1.2; color: var(--sc-ink);
}
.card p { margin: 0 0 var(--sc-4); font-size: var(--sc-t-sm); line-height: 1.7; color: var(--sc-ink-soft); }
.card p:last-child { margin-bottom: 0; }
.card b { color: var(--sc-ink); font-weight: 600; }

/* --------------------------------------------- contact -- */
.contact { display: grid; gap: var(--sc-8); }
@media (min-width: 900px) { .contact { grid-template-columns: 1fr 1fr; gap: var(--sc-9); align-items: start; } }
.contact__list { margin: var(--sc-7) 0 0; display: grid; gap: var(--sc-5); }
.contact__list div { border-top: 1px solid var(--sc-hairline); padding-top: var(--sc-3); }
.contact__list dt {
  font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; color: #9BAEBE;
}
.contact__list dd { margin: var(--sc-2) 0 0; font-size: var(--sc-t-base); color: var(--sc-ink); }
.contact__list a { color: var(--sc-ink); text-decoration: none; border-bottom: 1px solid rgba(255,255,255,0.3); }
.contact__list a:hover { color: var(--sc-accent); border-color: var(--sc-accent); }
.contact__map {
  border-radius: var(--sc-r-lg); overflow: hidden;
  min-height: clamp(18rem, 42vh, 30rem);
  box-shadow: inset 0 0 0 1px var(--sc-hairline);
}
/* Stretch it to the column beside it rather than leaving a stub of a map
   floating next to a full height block of text. */
@media (min-width: 900px) { .contact { align-items: stretch; } }
.contact__map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ---------------------------------------------- footer -- */
.foot {
  position: relative;
  background: var(--sc-canvas); border-top: 1px solid var(--sc-hairline);
  padding: clamp(3rem, 8vh, 5rem) 0 var(--sc-7);
}
.foot__grid {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sc-5) var(--sc-8);
}
.foot__links { flex: 1 1 24rem; }
.mark--foot { padding: 0; }
.foot__links { display: flex; flex-wrap: wrap; gap: var(--sc-3) var(--sc-5); }
.foot__links a {
  font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; color: #9BAEBE; text-decoration: none;
  transition: color var(--sc-d-fast) var(--sc-ease-out);
}
.foot__links a:hover { color: var(--sc-ink); }

/* Five destinations, five marks. The name is still there for a screen
   reader and in the tooltip; the row just stops shouting it. */
.foot__social { display: flex; flex-wrap: wrap; gap: var(--sc-3); }
.foot__social a {
  display: grid; place-items: center;
  width: 42px; height: 42px; border-radius: 50%;
  color: #9BAEBE;
  box-shadow: inset 0 0 0 1px var(--sc-hairline);
  transition: color var(--sc-d-fast) var(--sc-ease-out),
              background var(--sc-d-fast) var(--sc-ease-out),
              box-shadow var(--sc-d-fast) var(--sc-ease-out);
}
.foot__social a:hover {
  color: var(--sc-accent-ink); background: var(--sc-accent);
  box-shadow: 0 6px 20px rgba(79, 176, 255, 0.3);
}
/* The badge was held back in weight while there was nothing behind it --
   dimmed, cursor default, no hover. The app is published, so it is an
   ordinary link now and takes the same ring and the same hover as the
   rest of the row. */

/* Every mark in the row names itself the same way. It used to be the Play
   badge alone: the other four carried a plain `title`, so the row had two
   different tooltips -- one styled and instant, four grey boxes that the
   browser draws in its own font after a second of waiting, in a position
   we do not control. `title` is gone from them; the accessible name was
   never coming from it anyway, it comes from the .sr-only span. */
.foot__social [data-tip] { position: relative; }
/* The Play mark is a solid silhouette, not an outline -- the seams that
   make it read as Play are gaps between filled pieces, and traced as
   lines it comes out a plain triangle. */
.foot__social .play svg { fill: currentColor; stroke: none; width: 18px; height: 18px; }
.foot__social [data-tip]::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 9px); left: 50%; translate: -50% 0;
  padding: 5px 9px; border-radius: 7px; white-space: nowrap;
  font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide);
  color: var(--sc-ink); background: rgba(6, 11, 16, 0.95);
  box-shadow: inset 0 0 0 1px var(--sc-hairline), 0 8px 22px rgba(0,0,0,0.5);
  opacity: 0; pointer-events: none;
  transition: opacity var(--sc-d-fast) var(--sc-ease-out);
}
.foot__social [data-tip]:hover::after,
.foot__social [data-tip]:focus-visible::after { opacity: 1; }
/* Centred over a 42px mark, a tooltip is wider than the thing it points at
   and hangs off both sides. In the middle of the row that is fine. At the
   ends it is not: "Coming soon" is 104px over a mark whose centre sits 44px
   from the edge of a phone screen, so eight pixels of it were being cut off
   before any of this -- the badge has always been first in the row. The two
   marks at the ends give up being centred and hang inward instead. */
.foot__social > :first-child[data-tip]::after { left: 0; translate: 0 0; }
.foot__social > :last-child[data-tip]::after { left: auto; right: 0; translate: 0 0; }

.foot__social svg {
  width: 20px; height: 20px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.foot__note {
  position: relative; z-index: 1;      /* it sits outside .wrap, over the pan */
  margin: var(--sc-7) auto 0; max-width: 76rem;
  padding-inline: var(--sc-gutter);
  font-size: var(--sc-t-xs); color: #7E8F9E;
}


/* ---------------------------------------------------------
   The brand name, printed the way the old About section did.
   --------------------------------------------------------- */
.band__brand {
  font-family: var(--sc-font-display); font-weight: 700;
  font-size: var(--sc-t-2xl); line-height: 1.05;
  letter-spacing: var(--sc-track-tight);
  color: #fff; margin: 0 0 var(--sc-2);
}
.band__brand b { color: var(--sc-accent); font-weight: 700; }

/* ---------------------------------------------------------
   Go to top. Held back until the panoramas are behind the
   reader, because over a full-bleed photograph it is noise.
   --------------------------------------------------------- */
.totop {
  position: fixed; z-index: var(--sc-z-chrome);
  right: var(--sc-gutter);
  bottom: max(var(--sc-gutter), calc(env(safe-area-inset-bottom) + 0.9rem));
  width: 46px; height: 46px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(6, 11, 16, 0.72);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.16), 0 10px 30px rgba(0,0,0,0.5);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  opacity: 0; visibility: hidden; transform: translateY(10px);
  transition: opacity 240ms var(--sc-ease-out), transform 240ms var(--sc-ease-out),
              visibility 0s linear 240ms;
}
.totop svg {
  width: 20px; height: 20px; fill: none;
  stroke: #EAF2F8; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
body.past-rooms .totop {
  opacity: 1; visibility: visible; transform: none;
  transition-delay: 0s;
}
.totop:active { transform: translateY(1px); }
@media (hover: hover) and (pointer: fine) {
  .totop:hover { background: rgba(79, 176, 255, 0.9); }
  .totop:hover svg { stroke: var(--sc-accent-ink); }
}


/* ---------------------------------------------------------
   Anchors. Every in-page link lands under a fixed bar unless
   the target keeps room for it, and the bar is opaque glass.
   --------------------------------------------------------- */
.band, .foot { scroll-margin-top: clamp(4.75rem, 12vh, 6.5rem); }

/* ---------------------------------------------------------
   Phones, part two: the parts below the panoramas.
   --------------------------------------------------------- */
@media (max-width: 760px) {
  /* The go-to-top button is fixed over this corner, so the colophon
     needs somewhere else to sit. */
  .foot { padding-bottom: calc(var(--sc-7) + 3.5rem); }

  /* A 375px column reads better with the eyebrow, the headline and the
     body on a tighter ladder than the desktop one. */
  .band__brand { font-size: var(--sc-t-xl); }
  .foot__links { flex-basis: 100%; }
  .foot__grid { gap: var(--sc-5); }

  /* Two taps per row instead of five in a line that wraps awkwardly. */
  .foot__social { gap: var(--sc-2); }
}


/* ---------------------------------------------------------
   Phones, part three: the last room.

   Panorama 04 carries the booking button and the way down as
   well as its own copy, and 812px of phone will not hold all
   of that plus a photograph. So the three door links go —
   they repeat the menu and the footer — and the plate leaves
   the bottom strip free for "keep reading", which is the one
   control on this screen a reader cannot afford to miss.
   --------------------------------------------------------- */
@media (max-width: 760px) {
  #p4 .doors { display: none; }
  #p4 .plate { bottom: max(5.4rem, calc(env(safe-area-inset-bottom) + 5rem)); }

}


/* ---------------------------------------------------------
   Story motion.

   The turn itself belongs to js/pano360.js, which redraws the
   photograph at a new heading as the room scrolls. Nothing
   here scales the picture: a canvas that is transformed is
   only resampling pixels the shader has already placed, so it
   costs a repaint and buys blur.
   --------------------------------------------------------- */

/* The copy arrives with the room. Keyed to .room--here, set by
   js/pano360.js, and gated on .sc-ready so a page whose engine never
   mounted shows everything. Room one is exempt: it carries the h1 and has
   to be readable in the first paint, not one frame after whichever handler
   runs first.

   There is no matching fade-out. The room itself dissolves now, and a
   second fade underneath that one only washes the copy out early. */

html.sc-ready .plate > * {
  transition: opacity 620ms var(--sc-ease-out), transform 620ms var(--sc-ease-out);
}
html.sc-ready .room:not(.room--here):not(#p1) .plate > * {
  opacity: 0; transform: translateY(16px);
}
html.sc-ready .room--here .plate > * { opacity: 1; transform: none; }

/* Staggered, so the number lands, then the name, then the sentence — the
   way a lower third is built rather than dropped in one piece. */
.room--here .plate > *:nth-child(1) { transition-delay:  40ms; }
.room--here .plate > *:nth-child(2) { transition-delay: 150ms; }
.room--here .plate > *:nth-child(3) { transition-delay: 260ms; }
.room--here .plate > *:nth-child(4) { transition-delay: 370ms; }
.room--here .plate > *:nth-child(5) { transition-delay: 480ms; }
.room--here .plate > *:nth-child(6) { transition-delay: 590ms; }

@media (prefers-reduced-motion: reduce) {
  html.sc-ready .plate > * { transition-duration: 200ms; transform: none !important; }
}


/* If the engine never runs at all, nothing should be hidden by it. */
html:not(.sc-ready) [data-sc-in],
html:not(.sc-ready) [data-sc-stagger] > * { opacity: 1; transform: none; }

/* ---------------------------------------------------------
   And if the scripts never run at all.

   Everything below here is the page with its motor removed.
   js/home.js stamps .js-ready as its last act and pano360
   stamps .has-pano or .no-pano as one of its first, so the
   absence of either says that file threw, or never arrived.
   The page has to stay usable through that: a visitor with a
   blocked script does not know to blame one.
   --------------------------------------------------------- */

/* The reel is four rooms deep and every one of them starts invisible,
   waiting for a scroll handler to raise it. With no handler that is
   eight screens of black before the first word of the page. Collapse it
   to one screen and show the opening shot, which is a still anyway. */
html:not(.has-pano):not(.no-pano) .rooms { height: 100vh; }
html:not(.has-pano):not(.no-pano) .room:first-child {
  opacity: 1; visibility: visible;
}
html:not(.has-pano):not(.no-pano) .room:first-child .room__stage {
  background-image: var(--still); background-size: cover; background-position: center;
}
html:not(.has-pano):not(.no-pano) .room:not(:first-child) { display: none; }

/* The cards are built from the data files, so an unbuilt rail is an
   empty strip under a heading promising work. Take the strip away and
   say where the work actually lives -- it is all on Google either way. */
.tours__off { display: none; }
html:not(.js-ready) .tours { display: none; }
html:not(.js-ready) .tours__off {
  display: block; margin: var(--sc-6) 0 0;
  font-size: var(--sc-t-sm); line-height: 1.65; color: var(--sc-ink-soft);
}
html:not(.js-ready) .tours__off a { color: var(--sc-accent); }

/* ---------------------------------------------------------
   How the copy below the reel arrives.

   The panoramas dissolve over most of a screen of scrolling.
   Underneath them the engine's default entry -- 620ms over
   14 pixels -- read as a flicker: fast enough to notice,
   too fast to be a movement, and belonging to a different
   page from the one above it. Slowed to a little over a
   second with a longer travel, it becomes the same gesture.

   Only opacity and transform move. Both are composited, so a
   whole band arriving costs no layout and no repaint.
   --------------------------------------------------------- */
[data-sc-in], [data-sc-stagger] > * {
  transform: translate3d(0, 26px, 0);
  transition: opacity 1150ms var(--sc-ease-out),
              transform 1150ms var(--sc-ease-out);
}

/* A heading built out of words, each rising out of a mask cut to its own
   line. The mask is the whole trick: without `overflow: hidden` the words
   slide up from nowhere, and with it they appear to be revealed by the
   line itself.

   `padding-bottom` on the mask is not decoration -- descenders in g, y and
   p sit below the baseline and a mask cut exactly to the line clips them.

   The heading keeps its fade but gives up its rise: the words are already
   moving, and two movements on one element only blur each other. */
[data-kin] { transform: none; }
[data-kin] .kin {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.09em;
}
[data-kin] .kin__i {
  display: inline-block;
  transform: translate3d(0, 108%, 0);
  transition: transform 980ms var(--sc-ease-out);
}
[data-kin].sc-in .kin__i { transform: none; }

/* Someone who has asked for less movement still gets the copy, and still
   gets it in order -- it just stops travelling. */
@media (prefers-reduced-motion: reduce) {
  /* The travel goes. The fade stays, and stays slow -- it is the thing
     that makes the page feel unhurried, and it moves nothing. */
  [data-sc-in], [data-sc-stagger] > * { transform: none; }

  /* The heading still builds a word at a time. The words stop rising and
     fade in place instead, so the sequence survives without the travel
     that was the objectionable part. */
  [data-kin] .kin { overflow: visible; }
  [data-kin] .kin__i {
    transform: none;
    opacity: 0;
    transition: opacity 620ms var(--sc-ease-out);
  }
  [data-kin].sc-in .kin__i { opacity: 1; }
}

/* If the script never runs the words are never made, so this only has to
   cover the case where they exist but the class never lands. */
html:not(.sc-ready) [data-kin] .kin__i { transform: none; }
