/* ==========================================================================
   Base
   ========================================================================== */

:root {
  --color-bg: #09080a;            /* sampled from the photo's dark edges */
  --color-text: #f3ece2;
  --color-text-muted: rgba(243, 236, 226, 0.72);
  --color-accent: #d9b27c;        /* lamp-light brass */
  --color-line: rgba(243, 236, 226, 0.22);

  --font-display: "Cormorant Garamond", "Iowan Old Style", "Times New Roman", serif;
  --font-body: "Jost", "Helvetica Neue", Arial, sans-serif;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

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

html {
  background: var(--color-bg);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}

img {
  display: block;
  max-width: 100%;
}

/* ==========================================================================
   Page loader
   Native port of the MorphingSquare component: 40px square, corners morph
   6% → 50% → 6% while rotating 0 → 180 → 360deg, 2s ease-in-out, looping.
   ========================================================================== */

.page-loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  background: var(--color-bg);
  transition: opacity 0.7s var(--ease-out), visibility 0s linear 0.7s;
  /* failsafe: never trap the page if the script can't run */
  animation: page-loader-failsafe 0.7s ease 10s forwards;
}

.page-loader.is-done {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.no-js .page-loader {
  display: none;
}

@keyframes page-loader-failsafe {
  to {
    opacity: 0;
    visibility: hidden;
  }
}

/* messagePlacement variants: bottom (default) | top | right | left */
.morphing-square {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  justify-content: center;
}

.morphing-square--bottom { flex-direction: column; }
.morphing-square--top { flex-direction: column-reverse; }
.morphing-square--right { flex-direction: row; }
.morphing-square--left { flex-direction: row-reverse; }

.morphing-square__shape {
  width: 2.5rem;
  height: 2.5rem;
  background: var(--color-accent);
  animation: morphing-square 2s ease-in-out infinite;
}

.morphing-square__message {
  margin-top: 0.75rem;
  color: var(--color-text-muted);
  font-size: 0.65rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
}

.morphing-square--top .morphing-square__message { margin: 0 0 0.75rem; }
.morphing-square--right .morphing-square__message,
.morphing-square--left .morphing-square__message { margin: 0 0.75rem; }

@keyframes morphing-square {
  0% {
    border-radius: 6%;
    transform: rotate(0deg);
  }
  50% {
    border-radius: 50%;
    transform: rotate(180deg);
  }
  100% {
    border-radius: 6%;
    transform: rotate(360deg);
  }
}

.page-loader.is-done .morphing-square {
  transform: scale(0.9);
  transition: transform 0.7s var(--ease-out);
}

/* ==========================================================================
   Button
   ========================================================================== */

.button {
  display: inline-flex;
  align-items: center;
  gap: 0.9rem;
  padding: 1rem 1.6rem 1rem 1.75rem;
  border: 1px solid rgba(217, 178, 124, 0.55);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  transition:
    background-color 0.5s var(--ease-out),
    border-color 0.5s var(--ease-out),
    color 0.5s var(--ease-out);
}

.button__arrow {
  width: 1.5rem;
  height: 0.625rem;
  transition: transform 0.5s var(--ease-out);
}

.button:hover {
  background-color: var(--color-accent);
  border-color: var(--color-accent);
  color: #120d09;
}

.button:hover .button__arrow {
  transform: translateX(4px);
}

.button:focus-visible {
  outline: 1px solid var(--color-accent);
  outline-offset: 4px;
}

/* ==========================================================================
   Hero — scroll container + sticky stage
   ========================================================================== */

.hero {
  position: relative;
  height: 380vh;
  height: 380svh;
}

.hero__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--color-bg);
  container-type: size;
  isolation: isolate;
}

/* --------------------------------------------------------------------------
   Scene geometry
   The scene box always has the photo's aspect ratio (1672 × 941). On wide
   screens it behaves like `object-fit: cover`, with a focal point that keeps
   the lamp + carpet in view and the left negative space for copy.
   -------------------------------------------------------------------------- */

.hero__scene {
  --ratio: 1.776833;           /* 1672 / 941 */
  /* cover the stage, but never more than 118% of stage height on ultra-wide
     screens (otherwise the carpet would be cropped top/bottom) */
  --scene-w: max(100cqh * var(--ratio), min(100cqw, 118cqh * var(--ratio)));
  --scene-h: calc(var(--scene-w) / var(--ratio));
  --focal-x: 0.82;
  --focal-y: 0.3;

  /* carpet anchor, in fractions of the photo — centred in the spotlight under the lamp */
  --carpet-x: 0.7;
  --carpet-y: 0.6;
  --carpet-w: 0.605;           /* width of the shared carpet canvas / photo width */

  position: absolute;
  z-index: 0;
  width: var(--scene-w);
  height: var(--scene-h);
  left: calc((100cqw - var(--scene-w)) * var(--focal-x));
  top: calc((100cqh - var(--scene-h)) * var(--focal-y));
  /* soften the photo's edges for the cases where it doesn't fill the stage */
  -webkit-mask-image:
    linear-gradient(to right, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image:
    linear-gradient(to right, transparent 0, #000 6%, #000 94%, transparent 100%);
}

.hero__background {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  user-select: none;
}

/* --------------------------------------------------------------------------
   Carpet
   One shared stage. Every variant fills it with `inset: 0`, so all three
   share identical geometry. Assets were pre-normalised to one canvas with a
   common footprint and centroid (tools/prepare-hero-assets.py).
   -------------------------------------------------------------------------- */

.carpet-stage {
  position: absolute;
  left: calc(var(--carpet-x) * 100%);
  top: calc(var(--carpet-y) * 100%);
  width: calc(var(--carpet-w) * 100%);
  aspect-ratio: 1332 / 424;
  translate: -50% -50%;
}

/* sine-like ease: no visible "turnaround" at the top or bottom of the float */
.carpet-float {
  --float-ease: cubic-bezier(0.37, 0, 0.63, 1);
  position: absolute;
  inset: 0;
  animation: carpet-float 8s var(--float-ease) infinite;
  will-change: transform;
}

/* --------------------------------------------------------------------------
   Carpet change — a two-beat slide
   Not scrubbed by scroll: when the scroll crosses a switch point, JS moves
   `is-active` and sets the slide vectors on `.carpet-stage`.

   Beat 1 (0 → 0.9s): the current rug starts slowly, then accelerates out of
                      frame (ease-in), fading only at the very end.
   Beat 2 (0.9s →):   once it has gone, the next rug glides in from the other
                      side and decelerates to rest under the lamp (ease-out).
   The two rugs are never on screen together.

   Scrolling down: exit right, enter from the left.
   Scrolling up:   exit left (short, so it fades before crossing the copy),
                   enter from the right.
   -------------------------------------------------------------------------- */

.carpet-stage {
  --exit-x: 90%;   /* where the outgoing rug travels to */
  --enter-x: -38%; /* where the incoming rug starts from */
  --exit-duration: 0.9s;
  --enter-delay: 0.9s;
}

.carpet-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  transform: translate3d(var(--enter-x), 0, 0) scale(0.97);
  transform-origin: 50% 60%;
  backface-visibility: hidden;
  will-change: opacity, transform;
  transition:
    opacity 0.4s ease,
    transform 0.4s ease;
}

/* beat 2: arrive — fast at first, settling softly into place */
.carpet-layer.is-active {
  z-index: 2;
  opacity: 1;
  transform: none;
  transition:
    opacity 0.7s cubic-bezier(0.25, 0.6, 0.35, 1) var(--enter-delay),
    transform 1.4s cubic-bezier(0.16, 1, 0.3, 1) var(--enter-delay);
}

/* beat 1: leave — slow to start, then accelerating away */
.carpet-layer.is-leaving {
  z-index: 1;
  opacity: 0;
  transform: translate3d(var(--exit-x), 0, 0) scale(0.97);
  transition:
    opacity calc(var(--exit-duration) * 0.4) cubic-bezier(0.55, 0, 1, 0.45) calc(var(--exit-duration) * 0.6),
    transform var(--exit-duration) cubic-bezier(0.6, 0, 0.9, 0.4);
}

/* first paint / refresh mid-scroll: land on the right rug without animating */
.is-instant .carpet-layer {
  transition: none !important;
}

.carpet-layer img {
  width: 100%;
  height: 100%;
  /* sits a touch brighter inside the cone of light */
  filter: brightness(1.04) contrast(1.03) saturate(1.02);
  user-select: none;
}

/* gentle rise and fall (~±4% of the rug's height) with a whisper of tilt */
@keyframes carpet-float {
  0%,
  100% {
    transform: translate3d(0, -4%, 0) rotate(-0.3deg);
  }
  50% {
    transform: translate3d(0, 4%, 0) rotate(0.3deg);
  }
}

/* soft contact shadow on the floor, breathing in sync with the float */
.carpet-shadow {
  position: absolute;
  left: 68%;
  top: 89%;
  width: 44%;
  height: 8%;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(150 104 70), rgb(205 160 120) 55%, #fff);
  mix-blend-mode: multiply;
  filter: blur(8px);
  animation: carpet-shadow 8s cubic-bezier(0.37, 0, 0.63, 1) infinite;
}

/* rug high → shadow smaller and fainter; rug low → tighter, darker */
@keyframes carpet-shadow {
  0%,
  100% {
    transform: scale(0.88);
    opacity: 0.55;
  }
  50% {
    transform: scale(1);
    opacity: 1;
  }
}

/* faint lamp haze falling across the top of the rug — reads as light in the air */
.hero__atmosphere {
  position: absolute;
  left: 68.7%;
  top: 42%;
  width: 46%;
  height: 34%;
  translate: -50% -50%;
  background: radial-gradient(closest-side, rgba(255, 196, 128, 0.16), rgba(255, 196, 128, 0.05) 60%, transparent);
  mix-blend-mode: screen;
  pointer-events: none;
}

.hero__shade {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* deepen the left negative space slightly for text contrast */
  background: linear-gradient(to right, rgba(9, 8, 10, 0.55) 0%, rgba(9, 8, 10, 0.25) 28%, transparent 46%);
}

/* ==========================================================================
   Hero content
   ========================================================================== */

.hero__content {
  position: absolute;
  z-index: 2;
  left: clamp(1.5rem, 9vw, 11rem);
  top: 50%;
  translate: 0 -50%;
  width: min(34rem, 40vw);
}

.hero__eyebrow {
  margin: 0 0 1.75rem;
  color: var(--color-accent);
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.34em;
  text-transform: uppercase;
}

.hero__heading {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.75rem, 5.2vw, 5.75rem);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.hero__heading em {
  font-style: italic;
  color: #e9d5b6;
}

.hero__description {
  max-width: 24rem;
  margin: 1.75rem 0 0;
  color: var(--color-text-muted);
  font-size: clamp(0.95rem, 1.05vw, 1.0625rem);
  line-height: 1.7;
}

.hero__cta {
  margin-top: 2.5rem;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Per-carpet info
   All panels share one grid cell, so the block keeps the height of the
   tallest panel and nothing below it moves when the copy swaps.
   -------------------------------------------------------------------------- */

.carpet-info {
  display: grid;
}

.carpet-info__panel {
  grid-area: 1 / 1;
}

.carpet-specs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 2rem;
  max-width: 25rem;
  margin: 2rem 0 0;
}

.carpet-specs div {
  padding: 0.8rem 0 0.7rem;
  border-top: 1px solid var(--color-line);
}

.carpet-specs dt {
  color: var(--color-text-muted);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.26em;
  text-transform: uppercase;
}

.carpet-specs dd {
  margin: 0.4rem 0 0;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 400;
  line-height: 1.2;
}

/* --------------------------------------------------------------------------
   Reveal
   Entry: lines of the active panel rise in with a slow stagger, then the CTA.
   Swap: the outgoing lines lift away quickly; the incoming lines follow.
   -------------------------------------------------------------------------- */

.carpet-info__panel > *,
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 16px, 0);
  transition:
    opacity 1.4s var(--ease-out),
    transform 1.4s var(--ease-out);
}

.is-ready .carpet-info__panel.is-active > *,
.is-ready [data-reveal] {
  opacity: 1;
  transform: none;
}

.is-ready .carpet-info__panel.is-active > * { transition-delay: calc(0.15s + var(--i, 0) * 0.15s); }
.is-ready .hero__cta[data-reveal] { transition-delay: 0.8s; }

.has-swapped .carpet-info__panel > * {
  transition-duration: 0.8s, 1s;
}

.has-swapped .carpet-info__panel.is-active > * {
  /* arrives with the incoming rug (beat 2), not before it */
  transition-delay: calc(0.8s + var(--i, 0) * 0.08s);
}

.carpet-info__panel.is-leaving > * {
  opacity: 0;
  transform: translate3d(0, -10px, 0);
  transition-duration: 0.35s, 0.45s;
  transition-delay: calc(var(--i, 0) * 0.03s);
}

/* without JS, never leave the copy invisible */
.no-js .carpet-info__panel > *,
.no-js [data-reveal] {
  opacity: 1;
  transform: none;
}

/* ==========================================================================
   Scroll cue
   ========================================================================== */

.scroll-cue {
  position: absolute;
  z-index: 2;
  left: clamp(1.5rem, 9vw, 11rem);
  bottom: clamp(1.75rem, 5vh, 3rem);
  display: flex;
  align-items: center;
  gap: 1rem;
  opacity: 0;
  transition: opacity 0.9s var(--ease-out);
}

.is-ready .scroll-cue {
  opacity: 0.7;
  transition-delay: 1.2s;
}

.is-ready .scroll-cue.is-hidden {
  opacity: 0;
  transition-delay: 0s;
}

.scroll-cue__line {
  position: relative;
  width: 1px;
  height: 2.75rem;
  overflow: hidden;
  background: var(--color-line);
}

.scroll-cue__line::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 40%;
  background: var(--color-accent);
  animation: scroll-cue 2.4s var(--ease-out) infinite;
}

@keyframes scroll-cue {
  0% { transform: translateY(-100%); }
  100% { transform: translateY(260%); }
}

.scroll-cue__label {
  font-size: 0.65rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* pause idle loops while the hero is off-screen */
.hero.is-offscreen .carpet-float,
.hero.is-offscreen .carpet-shadow,
.hero.is-offscreen .scroll-cue__line::after {
  animation-play-state: paused;
}

/* ==========================================================================
   Following section (placeholder)
   ========================================================================== */

.next-section {
  position: relative;
  padding: clamp(6rem, 16vh, 10rem) clamp(1.5rem, 9vw, 11rem);
  background: var(--color-bg);
}

.next-section__inner {
  max-width: 40rem;
}

.next-section h2 {
  margin: 0 0 1.5rem;
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.6vw, 3.5rem);
  font-weight: 300;
  line-height: 1.1;
}

.next-section p:last-child {
  color: var(--color-text-muted);
  line-height: 1.7;
}

/* ==========================================================================
   Responsive
   ========================================================================== */

/* Squarer landscape screens (4:3 tablets, 5:4 monitors): covering would
   blow the rug up into the copy, so fit the scene to the width instead and
   seat it on the bottom edge, nudged right. The cord fades into the dark. */
@media (min-aspect-ratio: 1/1) and (max-aspect-ratio: 29/20) {
  .hero__scene {
    --scene-w: 100cqw;
    left: 6cqw;
    top: auto;
    bottom: 0;
    -webkit-mask-image:
      linear-gradient(to bottom, transparent 0, #000 9%),
      linear-gradient(to right, transparent 0, #000 12%, #000 94%, transparent 100%);
    -webkit-mask-composite: source-in;
    mask-image:
      linear-gradient(to bottom, transparent 0, #000 9%),
      linear-gradient(to right, transparent 0, #000 12%, #000 94%, transparent 100%);
    mask-composite: intersect;
  }

  .hero__content { width: min(30rem, 38vw); }
}

/* Short landscape screens (small laptops, phones in landscape) */
@media (max-height: 640px) and (min-aspect-ratio: 1/1) {
  .hero__scene { --scene-w: max(100cqh * var(--ratio), min(100cqw, 105cqh * var(--ratio))); }
  .hero__content { left: 6vw; width: min(30rem, 36vw); }
  .hero__eyebrow { margin-bottom: 1rem; }
  .hero__heading { font-size: clamp(2rem, 8.5vh, 4rem); }
  .hero__description { display: none; }
  .carpet-specs { margin-top: 1rem; }
  .carpet-specs div { padding: 0.5rem 0; }
  .carpet-specs dd { font-size: 1rem; margin-top: 0.2rem; }
  .hero__cta { margin-top: 1.25rem; }
  .button { padding: 0.8rem 1.25rem; }
  .scroll-cue { display: none; }
}

/* Portrait (tablet + mobile): stack copy above the lamp/carpet composition.
   The scene is scaled to keep the full rug on screen rather than covering. */
@media (max-aspect-ratio: 1/1) {
  .hero {
    height: 260vh;
    height: 260svh;
  }

  .hero__scene {
    --scene-w: min(170cqw, 45cqh * var(--ratio));
    /* centre the lamp horizontally */
    left: calc(50cqw - var(--scene-w) * 0.692);
    top: auto;
    bottom: 9cqh;
    -webkit-mask-image:
      linear-gradient(to bottom, transparent 0, #000 9%, #000 86%, transparent 100%),
      linear-gradient(to right, transparent 0, #000 6%, #000 94%, transparent 100%);
    -webkit-mask-composite: source-in;
    mask-image:
      linear-gradient(to bottom, transparent 0, #000 9%, #000 86%, transparent 100%),
      linear-gradient(to right, transparent 0, #000 6%, #000 94%, transparent 100%);
    mask-composite: intersect;
  }

  .hero__shade {
    background: linear-gradient(to bottom, rgba(9, 8, 10, 0.6) 0%, transparent 45%);
  }

  .hero__content {
    left: clamp(1.5rem, 7vw, 4rem);
    right: clamp(1.5rem, 7vw, 4rem);
    top: clamp(4.5rem, 11svh, 8rem);
    translate: none;
    width: auto;
    max-width: 34rem;
  }

  .hero__eyebrow { margin-bottom: 1.1rem; }
  .hero__heading { font-size: clamp(2.5rem, 8vw, 3.75rem); }
  .hero__description { margin-top: 1.1rem; font-size: 0.95rem; line-height: 1.6; }
  .hero__cta { margin-top: 1.6rem; }

  .scroll-cue {
    left: 50%;
    bottom: 1.5rem;
    translate: -50% 0;
    flex-direction: column-reverse;
    gap: 0.75rem;
  }

  .scroll-cue__line { height: 2rem; }
}

/* Portrait: the specs carry the information; the description would push the
   copy down into the lamp, so it's dropped on stacked layouts. */
@media (max-aspect-ratio: 1/1) {
  .hero__description { display: none; }
  .carpet-specs { margin-top: 1.25rem; column-gap: 1.5rem; }
  .carpet-specs div { padding: 0.6rem 0 0.5rem; }
  .carpet-specs dd { font-size: 1.05rem; margin-top: 0.25rem; }
}

/* Small phones: tighter copy so it never meets the lamp */
@media (max-aspect-ratio: 1/1) and (max-height: 720px) {
  .hero__scene { --scene-w: min(160cqw, 42cqh * var(--ratio)); bottom: 6cqh; }
  .hero__content { top: 2.75rem; }
  .hero__eyebrow { margin-bottom: 0.8rem; }
  .hero__heading { font-size: clamp(2.1rem, 9.5vw, 2.75rem); }
  .hero__description { font-size: 0.875rem; }
  .carpet-specs div { padding: 0.45rem 0; }
  .carpet-specs dd { font-size: 0.95rem; }
  .hero__cta { margin-top: 1.25rem; }
  .button { padding: 0.85rem 1.3rem; }
}

@keyframes morphing-square-still {
  0%, 100% { border-radius: 6%; }
  50% { border-radius: 50%; }
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .carpet-float,
  .carpet-shadow,
  .scroll-cue__line::after {
    animation: none;
  }

  /* loader: keep the soft morph, drop the spin */
  .morphing-square__shape {
    animation-name: morphing-square-still;
    animation-duration: 3s;
  }

  .carpet-layer,
  .carpet-layer.is-active,
  .carpet-layer.is-leaving {
    transform: none;
    transition: opacity 0.8s ease;
  }

  .carpet-info__panel > *,
  .carpet-info__panel.is-leaving > *,
  [data-reveal] {
    transform: none;
    transition: opacity 0.6s linear;
  }

  .is-ready .carpet-info__panel.is-active > *,
  .is-ready [data-reveal] {
    transition-delay: 0s !important;
  }

  .button,
  .button__arrow {
    transition: none;
  }
}
