/* ==========================================================================
   Infinity Room
   Palette: two neutrals + one pink. Everything else is photography.
   ========================================================================== */

@font-face {
  font-family: 'Inter';
  src: url('../assets/fonts/inter-var-latin.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

:root {
  --ink:      #08080A;
  --well:     #050506;
  --pink:     #FF2AA7;
  --bone:     #F2EFEC;
  --bone-dim: rgba(242, 239, 236, 0.56);
  --hair:     rgba(242, 239, 236, 0.12);
  --hair-hot: rgba(255, 42, 167, 0.42);

  --gut:  clamp(1.25rem, 5vw, 5rem);   /* page gutter */
  --sec:  clamp(5rem, 12vw, 10rem);    /* section rhythm */

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* --------------------------------------------------------------- reset -- */

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

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* tells the UA to render scrollbars and native controls dark */
  color-scheme: dark;
  /* keeps in-page anchors clear of the fixed header */
  scroll-padding-top: 6rem;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--bone);
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: clamp(1rem, 0.95rem + 0.2vw, 1.0625rem);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
ul, ol, dl, dd, figure { margin: 0; padding: 0; }
li { list-style: none; }
h1, h2, h3, p { margin: 0; }
address { font-style: normal; }

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

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

/* no 300ms double-tap delay, no grey flash on tap */
a, button, [role="button"] {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3 { text-wrap: balance; }

:focus-visible {
  outline: 2px solid var(--pink);
  outline-offset: 3px;
  border-radius: 2px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.skip {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -120%);
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--pink); color: var(--ink);
  font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 700;
}
.skip:focus { transform: translate(-50%, 0); }

/* ---------------------------------------------------------- typography -- */

.h2 {
  font-size: clamp(2.5rem, 7vw, 5.5rem);
  line-height: 0.95;
  letter-spacing: -0.035em;
  font-weight: 800;
  text-transform: uppercase;
}

.sec-head { margin-bottom: clamp(2.5rem, 6vw, 4.5rem); }

/* --------------------------------------------------------------- logos -- */
/* SVGs are masked so CSS `color` drives them; no inline markup needed.      */

.logo {
  display: block;
  background: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
}
.logo--word {
  aspect-ratio: 712 / 242;
  -webkit-mask-image: url('../assets/logo/wordmark.svg');
  mask-image: url('../assets/logo/wordmark.svg');
}
.logo--badge {
  aspect-ratio: 1;
  -webkit-mask-image: url('../assets/logo/mark.svg');
  mask-image: url('../assets/logo/mark.svg');
}

/* --------------------------------------------------------------- overlay --*/

.grain, .scan {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 90;
}
.grain {
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.scan {
  opacity: 0.55;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255,255,255,0.018) 0 1px,
    transparent 1px 3px
  );
}

.trail {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: 95;
  mix-blend-mode: screen;
}

/* ----------------------------------------------------------------- nav -- */

/*
   Hidden while the hero is on screen, revealed once it scrolls past (see the nav
   module in js/main.js).

   visibility — not just opacity — is what takes the links out of the tab order
   and out of the accessibility tree. Without it a keyboard user would tab into
   an invisible bar over the hero. It is transitioned with a delay on the way out
   so the slide-up finishes before the bar becomes unfocusable, and with no delay
   on the way in.
*/
.nav {
  position: fixed; top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex; align-items: center; gap: 2rem;
  padding: 1.15rem max(var(--gut), env(safe-area-inset-right)) 1.15rem max(var(--gut), env(safe-area-inset-left));
  border-bottom: 1px solid transparent;

  transform: translateY(-100%);
  opacity: 0;
  visibility: hidden;
  transition:
    transform 0.45s var(--ease),
    opacity 0.3s var(--ease),
    background 0.4s var(--ease),
    border-color 0.4s var(--ease),
    padding 0.4s var(--ease),
    visibility 0s linear 0.45s;
}

.nav.is-stuck {
  transform: none;
  opacity: 1;
  visibility: visible;
  background: rgba(8, 8, 10, 0.78);
  border-bottom-color: var(--hair);
  padding-block: 0.85rem;
  transition:
    transform 0.45s var(--ease),
    opacity 0.3s var(--ease),
    background 0.4s var(--ease),
    border-color 0.4s var(--ease),
    padding 0.4s var(--ease),
    visibility 0s linear 0s;
}
@supports (backdrop-filter: blur(1px)) {
  .nav.is-stuck { backdrop-filter: blur(14px) saturate(1.3); }
}

.nav__logo { color: var(--pink); flex: none; }
.nav__logo .logo { width: clamp(104px, 12vw, 140px); }

.nav__links {
  display: flex; gap: clamp(1.25rem, 2.5vw, 2.25rem);
  margin-inline: auto;
  font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase; font-weight: 600;
}
.nav__links a,
.nav__links .navlink { color: var(--bone-dim); transition: color 0.25s; font: inherit; letter-spacing: inherit; text-transform: inherit; padding: 0; }
.nav__links a:hover,
.nav__links .navlink:hover { color: var(--bone); }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.85rem 1.6rem;
  border: 1px solid var(--hair);
  font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase; font-weight: 700;
  transition: border-color 0.3s, color 0.3s, background 0.3s;
}
.btn:hover { border-color: var(--pink); color: var(--pink); }

.btn--solid {
  background: var(--pink); border-color: var(--pink); color: var(--ink);
}
.btn--solid:hover { background: transparent; color: var(--pink); }

.nav__cta { flex: none; padding: 0.7rem 1.25rem; }
/* Below 860px the links are hidden, and with them the auto margin that was
   pushing the CTA across. Give the CTA its own auto margin so it stays hard
   right instead of sitting against the logo. */
@media (max-width: 860px) {
  .nav__links { display: none; }
  .nav__cta   { margin-left: auto; }
}

/* ---------------------------------------------------------------- hero -- */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid; place-items: center;
  padding: 8rem max(var(--gut), env(safe-area-inset-right)) max(6rem, env(safe-area-inset-bottom)) max(var(--gut), env(safe-area-inset-left));
  overflow: hidden;
  isolation: isolate;
}
.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__media img {
  width: 100%; height: 100%; object-fit: cover;
  animation: drift 28s var(--ease) infinite alternate;
}
@keyframes drift { from { transform: scale(1.02); } to { transform: scale(1.12); } }

.hero::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(120% 80% at 50% 45%, transparent 30%, rgba(8,8,10,0.72) 100%),
    linear-gradient(to bottom, rgba(8,8,10,0.66) 0%, rgba(8,8,10,0.2) 32%, rgba(8,8,10,0.86) 100%);
}

.hero__inner { text-align: center; max-width: 46rem; position: relative; z-index: 1; }
.hero__inner > * { position: relative; z-index: 1; }

/* Soft halo so the badge stays legible over the bright ceiling bars. */
.hero__inner::before {
  content: '';
  position: absolute; z-index: 0;
  left: 50%; top: -22%;
  width: min(520px, 88vw); aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle,
    rgba(8,8,10,0.78) 0%,
    rgba(8,8,10,0.52) 42%,
    transparent 70%);
}

.hero__badge {
  width: clamp(160px, 26vw, 300px);
  margin: 0 auto clamp(2.5rem, 6vw, 4rem);
  color: var(--pink);
  filter: drop-shadow(0 0 44px rgba(255, 42, 167, 0.5));
}

.hero__cta {
  margin-top: clamp(2rem, 4vw, 3rem);
  display: flex; gap: 0.75rem; justify-content: center; flex-wrap: wrap;
}
.hero__cta .btn {
  border-color: rgba(242,239,236,0.3);
  background: rgba(8,8,10,0.3);
}

.hero__cue {
  position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%);
  width: 1px; height: 56px; overflow: hidden;
  background: var(--hair);
}
.hero__cue span {
  display: block; width: 100%; height: 40%;
  background: var(--pink);
  animation: cue 2.4s var(--ease) infinite;
}
@keyframes cue { 0% { transform: translateY(-100%); } 100% { transform: translateY(250%); } }

/* ------------------------------------------------------------- marquee -- */

.marquee {
  --dir: -1;
  position: relative;
  border-block: 1px solid var(--hair-hot);
  padding-block: clamp(0.9rem, 2vw, 1.4rem);
  overflow: hidden;
  background: var(--well);
}
.marquee__track {
  display: flex; width: max-content;
  animation: slide 42s linear infinite;
  animation-direction: var(--marq-dir, normal);
}
.marquee--sm .marquee__track { animation-duration: 30s; }
.marquee__track span {
  font-size: clamp(1.75rem, 5vw, 3.75rem);
  font-weight: 800; text-transform: uppercase;
  letter-spacing: -0.02em;
  color: rgba(242, 239, 236, 0.14);
  white-space: nowrap;
  padding-right: 0.4em;
}
.marquee--sm .marquee__track span { font-size: clamp(0.9rem, 2vw, 1.5rem); letter-spacing: 0.1em; }
.marquee__track em { font-style: normal; color: var(--pink); }
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }

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

.room {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2.5rem, 6vw, 6rem);
  align-items: center;
  padding: var(--sec) var(--gut);
}
.room__text p + p { margin-top: 1.25rem; }
.room__text > p { color: var(--bone-dim); max-width: 34rem; }
.room__text .h2 { margin-bottom: 2rem; }

.room__media { position: relative; }
.room__shot { overflow: hidden; }
.room__shot img { width: 100%; }
.room__shot--a { width: 82%; }
.room__shot--b {
  width: 54%;
  margin: -18% 0 0 auto;
  position: relative;
  border: 1px solid rgba(8,8,10,0.9);
}
@media (max-width: 900px) {
  .room { grid-template-columns: 1fr; }
}

/* -------------------------------------------------------------- nights -- */

.nights { padding: var(--sec) var(--gut); background: var(--well); }

.sub-head {
  font-size: 0.6875rem; letter-spacing: 0.2em; text-transform: uppercase;
  font-weight: 600;
  color: var(--bone-dim);
  padding-bottom: 1rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
  border-bottom: 1px solid var(--hair);
}
.sub-head--gap { margin-top: clamp(3.5rem, 8vw, 6rem); }

/* weekly residencies -------------------------------------------------------- */

.weeklies {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

.weekly { display: grid; gap: 1.35rem; }

.weekly__art {
  position: relative;
  aspect-ratio: 1;
  isolation: isolate;
}
.weekly__art img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(0.92) contrast(1.03);
  transition: filter 0.5s var(--ease), transform 0.6s var(--ease);
}
.weekly__leak {
  position: absolute; inset: 0; z-index: -1;
  background-size: cover; background-position: center;
  filter: blur(40px) saturate(1.8);
  opacity: 0.45;
  transform: scale(1.12);
  transition: opacity 0.5s var(--ease), transform 0.6s var(--ease);
}
.weekly:hover .weekly__art img { filter: saturate(1.1) contrast(1); transform: scale(1.02); }
.weekly:hover .weekly__leak  { opacity: 0.8; transform: scale(1.2); }

.weekly__body { display: grid; gap: 0.4rem; }
.weekly__day {
  font-size: 0.6875rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--pink); font-weight: 700;
}
.weekly__name {
  font-size: clamp(1.35rem, 2.6vw, 1.85rem);
  font-weight: 800; letter-spacing: -0.025em; text-transform: uppercase;
  line-height: 1.05;
}
.weekly__meta {
  font-size: 0.8125rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--bone-dim);
  font-variant-numeric: tabular-nums;
}

.nights__note {
  margin-top: 2rem;
  font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--bone-dim);
}

/* ------------------------------------------------- booking embeds -- */
/* Mr. Black renders inside a cross-origin iframe, so its interior cannot be
   styled from here. We control the frame around it and let it size itself
   via the postMessage height handshake in js/main.js. */

/* The Mr. Black widget's document is genuinely transparent — html and body are
   both rgba(0,0,0,0) and nothing inside paints a page background. It composites
   over whatever is behind it.

   The frames must therefore be opted OUT of a colour scheme. When a frame has a
   used `color-scheme`, the engine paints an OPAQUE base for it rather than
   compositing, and on a cross-origin frame that base comes out white — which is
   exactly the white panel this embed used to sit in.

   `color-scheme` is an INHERITED property, and this page sets `color-scheme:
   dark` on <html> for native scrollbars and form controls. So it is not enough
   to avoid declaring it here: the frames inherit it. They have to explicitly
   reset to `normal` to go back to compositing.

   Likewise, do not give the iframe a background: it has nothing to hide. */
.embed {
  position: relative;
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
  border: 0;
  background: transparent;
}
.embed iframe {
  display: block;
  width: 100%;
  border: 0;
  background: transparent;
  color-scheme: normal;          /* opt out of the inherited dark — see above */
  transition: height 0.35s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .embed iframe { transition: none; }
}

.embed[hidden] { display: none; }
/* The reserve-table view is themed dark by the venue, so its panel stays dark. */
.embed--book { margin-top: clamp(2rem, 4vw, 3rem); }

@media (prefers-reduced-motion: reduce) {
  .embed iframe { transition: none; }
}

/* full-screen checkout layer */
.embed-modal {
  position: fixed; inset: 0; z-index: 10000;
  display: grid; place-items: center;
  background: rgba(5, 5, 6, 0.96);
  overscroll-behavior: contain;
}
.embed-modal[hidden] { display: none; }
.embed-modal__box {
  position: relative;
  width: min(1100px, 96vw);
  height: 90svh;
}
.embed-modal__frame { width: 100%; height: 100%; border: 0; }
.embed-modal__close {
  position: absolute; top: 0.75rem; right: 0.75rem;
  width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center;
  font-size: 1.75rem; line-height: 1;
  color: var(--bone);
  background: rgba(8, 8, 10, 0.85);
  border: 1px solid var(--hair);
  border-radius: 50%;
  transition: border-color 0.3s, color 0.3s;
}
.embed-modal__close:hover { border-color: var(--pink); color: var(--pink); }

/* ------------------------------------------------------------- gallery -- */
/* Continuously scrolling strip of portrait cards. The track holds two
   identical runs and translates by exactly -50%, so the loop is seamless. */

.gallery { padding: var(--sec) 0; }

.strip {
  position: relative;
  overflow: hidden;
  padding-block: clamp(1rem, 2vw, 2rem);
  /* fade the ends so cards enter and leave rather than being cut off */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}

.strip__track {
  display: flex;
  gap: clamp(0.75rem, 1.5vw, 1.35rem);
  width: max-content;
  animation: strip var(--strip-duration, 90s) linear infinite;
}

@keyframes strip { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }

.strip__item { flex: none; }

.strip__frame {
  position: relative;
  display: block;
  width: clamp(190px, 22vw, 300px);
  aspect-ratio: 3 / 4;
  border-radius: 14px;
  overflow: hidden;
  isolation: isolate;
}
.strip__frame img {
  width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 32%;
  filter: saturate(0.88) contrast(1.05);
}

/* the light leak: the photograph itself, blurred, bleeding onto the page */
.strip__leak {
  position: absolute; inset: 0; z-index: -1;
  background-size: cover; background-position: center;
  filter: blur(26px) saturate(1.7);
  opacity: 0.42;
  transform: scale(1.15);
}

@media (max-width: 700px) {
  .strip__frame { width: min(58vw, 260px); }
}

@media (prefers-reduced-motion: reduce) {
  /* no auto-scroll — becomes a normal horizontal scroller the user drives */
  .strip { overflow-x: auto; scroll-snap-type: x proximity; }
  .strip__track { animation: none; }
  .strip__item { scroll-snap-align: center; }
}

/* -------------------------------------------------------- reservations -- */

.res { padding: var(--sec) var(--gut); background: var(--well); }

.link {
  font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase; font-weight: 700;
  color: var(--pink);
  display: inline-flex; gap: 0.5rem; align-items: center;
  transition: gap 0.3s var(--ease);
}
.link:hover { gap: 0.85rem; }

/* --------------------------------------------------------------- visit -- */

.visit { padding: var(--sec) var(--gut); }

.visit__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: clamp(2rem, 5vw, 4rem);
}
.visit__label {
  font-size: 0.625rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--bone-dim);
  padding-bottom: 1rem; margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--hair);
  font-weight: 600;
}
.visit__block address,
.visit__block p { color: var(--bone-dim); }
.visit__block .link { margin-top: 1.25rem; }

.plain li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: 0.55rem 0;
  color: var(--bone-dim);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  border-bottom: 1px solid rgba(242,239,236,0.06);
}
.plain li span:first-child { color: var(--bone); }
.visit__note {
  margin-top: 1.25rem;
  font-size: 0.8125rem;
  color: var(--bone-dim);
}

/* -------------------------------------------------------------- footer -- */

.foot {
  padding: clamp(3.5rem, 8vw, 6rem) var(--gut) max(3rem, env(safe-area-inset-bottom));
  border-top: 1px solid var(--hair);
  text-align: center;
  display: grid; justify-items: center; gap: 1.5rem;
  background: var(--well);
}
.foot__badge { width: 76px; color: var(--pink); }
.foot__links {
  display: flex; gap: 1.75rem; flex-wrap: wrap; justify-content: center;
  font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase; font-weight: 600;
}
.foot__links a,
.foot__links .navlink { color: var(--bone-dim); transition: color 0.25s; font: inherit; letter-spacing: inherit; text-transform: inherit; padding: 0; }
.foot__links a:hover,
.foot__links .navlink:hover { color: var(--pink); }
.foot__legal { font-size: 0.6875rem; letter-spacing: 0.1em; color: rgba(242,239,236,0.32); }

/* --------------------------------------------------- corporate form -- */
/*
   Elfsight contact form, shown as a slide-out pane. We supply our own triggers
   in the nav and footer via data-elfsight-show-form, so the widget's built-in
   floating button is hidden — delete this rule to bring it back.

   The inner class names are Elfsight's own (styled-components), so this is
   matched on a substring rather than an exact hash. If an Elfsight update
   renames the component the button reappears; it does not break the form.
*/
/* Elfsight renders the floating button into a portal on <body>, NOT inside our
   mount div, so this rule cannot be scoped to .elf-mount. It is global because
   this page has exactly one Elfsight widget — if a second one is ever added and
   should show its own floating button, scope this to the widget id instead. */
[class*="FloatingButton__FloatingButtonContainer"] { display: none !important; }

/* The pane is portalled to <body>; keep it above our own fixed overlays
   (grain, scanlines, the cursor canvas). */
[class*="es-portal-root"] { z-index: 300; }

/* ------------------------------------------------------------- reveals -- */

[data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  transition-delay: var(--d, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* ----------------------------------------------------- reduced motion -- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  .nav           { transform: none; }
  .hero__media img { animation: none; transform: scale(1.04); }
  .marquee__track  { animation: none; }
  .hero__cue       { display: none; }
  .trail           { display: none; }

  [data-reveal] { opacity: 1; transform: none; }
}
