/* Hero — emotional entrance (LUXURY_EXPERIENCE_GUIDE). */

.fl-hero {
  position: relative;
  display: grid;
  align-items: end;
  /* Subtract the admin bar. WordPress adds html{margin-top:32px} while it is
     showing, so a plain 100svh hero overhangs the fold by exactly that much —
     and the part that falls off the bottom is the row of buttons. */
  min-height: calc(100vh - var(--wp-admin--admin-bar--height, 0px));
  min-height: calc(100svh - var(--wp-admin--admin-bar--height, 0px));
  overflow: hidden;
  color: var(--fl-text, #fff);
  background: var(--fl-bg, #0b0b0b);

  /* A horizontal drag changes the slide; a vertical one must still scroll the
     page. Without this the browser claims the gesture and pointermove never
     arrives on a phone — the slideshow would look draggable and not be. */
  touch-action: pan-y;
}

.fl-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.fl-hero__media--placeholder {
  background:
    radial-gradient(ellipse at 70% 30%, rgba(209, 43, 116, 0.30), transparent 55%),
    linear-gradient(135deg, #1a1016 0%, #0b0b0b 50%, #241018 100%);
}

.fl-hero__image,
.fl-hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 80% 40%;
  transform: scale(1.06);
  transform-origin: 80% 40%;
  /* VIS-01 — the global brightness lift is gone.
     It was added for a set of dark masters that have since been replaced.
     Measured against the current heroes it destroyed them: the SHOP image
     (mean luma 181) blew 72% of its pixels to pure white and erased the neon
     sign entirely, while PRODUCT (mean luma 34) is deliberately a dark neon
     night and loses its contrast when lifted.
     Per-image correction now lives on the block as --fl-hero-filter, set from
     the editor, so one page's exposure can never dictate another's. */
  filter: var(--fl-hero-filter, none);
  animation: fl-hero-media-in 1.4s var(--fl-ease) both;
}

.fl-hero__image--fallback {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.fl-hero__video {
  position: relative;
  z-index: 1;
}

.fl-hero__overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  background:
    radial-gradient(
      ellipse 55% 70% at 78% 42%,
      rgba(201, 161, 74, 0.16) 0%,
      transparent 55%
    ),
    linear-gradient(
      90deg,
      rgba(11, 11, 11, 0.72) 0%,
      rgba(11, 11, 11, 0.38) 34%,
      rgba(11, 11, 11, 0.08) 62%,
      rgba(11, 11, 11, 0.18) 100%
    ),
    linear-gradient(
      180deg,
      rgba(11, 11, 11, 0.45) 0%,
      rgba(11, 11, 11, 0.05) 42%,
      rgba(11, 11, 11, 0.62) 100%
    );
  pointer-events: none;
}

.fl-hero__content {
  position: relative;
  z-index: 3;
  width: 100%;
  /* Was 4.5–6.5rem at the bottom, with the scroll cue absolutely positioned
     below that again. On a short window those two stacked up and pushed the
     buttons past the fold. The cue is in the flow now, so the padding only
     has to be breathing room. */
  padding-block: clamp(6rem, 15vh, 9rem) clamp(2.5rem, 6vh, 4rem);
}

/*
 * Staged entrance — heading, subheading and actions rise in sequence
 * instead of the content fading as one block. Matches ANIMATION_GUIDE
 * ("soft fade on load" with distinct heading / button reveals) and reads
 * more deliberate without any extra cost (opacity + transform only).
 */
.fl-hero__heading,
.fl-hero__subheading,
.fl-hero__cta {
  animation: fl-hero-rise 1.15s var(--fl-ease) both;
}

.fl-hero__heading {
  animation-delay: 0.35s;
}

.fl-hero__subheading {
  animation-delay: 0.55s;
}

.fl-hero__cta {
  animation-delay: 0.75s;
}

.fl-hero__heading {
  margin: 0 0 1.5rem;
  max-width: 10ch;
  font-family: var(--fl-font-display, "Cormorant Garamond", serif);
  font-size: clamp(3.5rem, 9vw, 6.75rem);
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 0.96;

  /*
   * Outline only, hollow inside, so the slideshow runs through the letters.
   *
   * A filled wordmark this size covers a third of the picture — and the
   * picture is the point of the hero. The drop shadow does the work the fill
   * used to do: it keeps the edges legible over a bright frame without
   * putting anything back inside them.
   */
  color: transparent;
  /*
   * Proportional to the letter, not to the window.
   *
   * clamp(1px, 0.16vw, 2.5px) gave every page the same 2.5px hairline, so the
   * outline read three times heavier on the pages whose headline is a third
   * the size. 0.0136em x 184px = 2.5024px, which is the home headline's
   * present weight to within two thousandths of a pixel — home does not move.
   * max() keeps it from going sub-pixel on the smallest headlines.
   */
  -webkit-text-stroke: max(1px, 0.0136em) rgba(255, 255, 255, 0.94);
  text-shadow: none;
  filter: drop-shadow(0 2px 16px rgba(0, 0, 0, 0.62));
}

/* Old engines with no text-stroke would render nothing at all — give them
   the solid wordmark rather than an empty space where the brand should be. */
@supports not (-webkit-text-stroke: 1px #fff) {

  .fl-hero__heading {
    color: var(--fl-text, #fff);
    text-shadow: 0 2px 32px rgba(0, 0, 0, 0.5);
    filter: none;
  }
}

.fl-hero__subheading {
  margin: 0 0 2.75rem;
  max-width: 32ch;
  font-family: var(--fl-font-body, "Manrope", sans-serif);
  font-size: clamp(1rem, 2vw, 1.15rem);
  font-weight: 300;
  letter-spacing: 0.03em;
  line-height: 1.75;
  color: rgba(255, 240, 246, 0.9);
  text-shadow: 0 1px 20px rgba(0, 0, 0, 0.45);
}

.fl-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.25rem;
  margin: 0;
}

/* .fl-btn moved to main.css — the legal pages have no hero block and so
   never loaded this file, leaving their one button unstyled. */

/*
 * The cue used to be absolutely positioned at left:50% — the centre of the
 * window. The buttons are a left-aligned cluster, so the two centres never
 * agreed. Both now sit in .fl-hero__cta, which is only as wide as the
 * buttons, and the cue centres inside it.
 */
.fl-hero__cta {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.25rem, 3vh, 2rem);
}

.fl-hero__scroll {
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.65rem;
  /* Was 0.65rem at 55% white — under a bright frame that is a smudge, not a
     word. Bigger, brighter, and with less tracking so it reads as one word. */
  color: rgba(255, 255, 255, 0.82);
  font-family: var(--fl-font-body, "Manrope", sans-serif);
  font-size: clamp(0.8rem, 1vw, 0.95rem);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6);
  text-transform: uppercase;
  text-decoration: none;
  /* Rise with the CTA (~0.75s), then breathe — no long “frozen” pause */
  animation: fl-hero-scroll-pulse 2.4s ease-in-out 0.85s infinite;
}

.fl-hero__scroll:hover,
.fl-hero__scroll:focus-visible {
  color: #fff;
}

.fl-hero__scroll-line {
  width: 1px;
  height: 2.5rem;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.55), transparent);
}

@keyframes fl-hero-media-in {
  from {
    opacity: 0;
    transform: scale(1.12);
  }
  to {
    opacity: 1;
    transform: scale(1.06);
  }
}

@keyframes fl-hero-content-in {
  from {
    opacity: 0;
    transform: translateY(1.25rem);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fl-hero-rise {
  from {
    opacity: 0;
    transform: translateY(1.5rem);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Opacity + vertical breathe only.
 * translateX(-50%) was a leftover from absolute left:50% centering.
 * The cue now lives in a flex column — that -50% jumped it left ~1.9s after load. */
@keyframes fl-hero-scroll-pulse {
  0%,
  100% {
    opacity: 0.45;
    transform: translateY(0);
  }
  50% {
    opacity: 0.9;
    transform: translateY(0.35rem);
  }
}

@media (max-width: 767px) {
  .fl-hero__content {
    padding-block: 6rem 2.5rem;
  }

  .fl-hero__image,
  .fl-hero__video {
    object-position: 85% 38%;
    transform-origin: 85% 38%;
  }

  .fl-hero__heading {
    max-width: 9ch;
  }

  .fl-hero__actions {
    width: 100%;
  }

  .fl-btn {
    flex: 1 1 auto;
  }

  .fl-hero__scroll {
    bottom: 1rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fl-hero__image,
  .fl-hero__video,
  .fl-hero__content,
  .fl-hero__heading,
  .fl-hero__subheading,
  .fl-hero__actions,
  .fl-hero__scroll {
    animation: none;
  }

  .fl-hero__video {
    display: none;
  }

  .fl-hero__image--fallback {
    position: relative;
    z-index: 1;
  }

  .fl-btn,
  .fl-btn--primary:hover,
  .fl-btn--primary:focus-visible {
    transition: none;
    transform: none;
    box-shadow: none;
  }
}

/* Specification line (CNT-12).
   Small, low-chroma, widely tracked: it should be findable when looked for
   and invisible when not. The brief bans information density, so this is one
   line and never more. */
.fl-hero__spec {
  margin: clamp(1.1rem, 2.4vh, 1.8rem) 0 0;
  color: var(--fl-text-muted, #8a8a8a);
  font-family: var(--fl-font-body, "Manrope", sans-serif);
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

@media (min-width: 900px) {
  .fl-hero__spec {
    font-size: 0.74rem;
  }
}

/* ==========================================================================
   Hero slideshow

   The timing lives in assets/js/hero-slider.js, not here. A CSS clock cannot
   be told that an image has not arrived yet, and that is precisely what went
   wrong before: unloaded frames still took their turn, so the opening ran
   image — jump — long pause — normal.

   What CSS owns is what a slide looks like: the cross-fade, and the slow push
   in that keeps a still from reading as a still.
   ========================================================================== */

.fl-hero__slide {
  position: absolute;
  inset: 0;
  display: block;
  z-index: 0;
  opacity: 0;
  /* Follows the drag a little. A picture that does not move under the hand
     does not read as something you can move. */
  transform: translate3d(var(--fl-drag, 0px), 0, 0);
  pointer-events: none;
}

/*
 * Before the script runs — and if it never runs — the first frame is simply
 * the hero image. A still hero is a perfectly good hero; the slideshow is an
 * addition, never a dependency.
 */
.fl-hero--seq:not(.is-ready) .fl-hero__slide:first-of-type {
  opacity: 1;
  z-index: 1;
}

/*
 * linear, not the house curve. An eased cross-fade spends most of its time
 * near one end, so the two pictures are unevenly mixed through the middle and
 * the change reads as a switch. A flat ramp dissolves.
 */
.fl-hero__slide {
  transition: opacity 1.6s linear, transform 0.45s ease-out;
}

.fl-hero__slide.is-active {
  opacity: 1;
  z-index: 2;
}

.fl-hero__slide.is-leaving {
  opacity: 0;
  z-index: 1;
}

/* While a finger is down the picture must track it exactly, not glide. */
.fl-hero--seq.is-dragging .fl-hero__slide {
  transition: opacity 1.6s linear, transform 0s;
}

.fl-hero__seq-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--fl-img-x, 50%) var(--fl-img-y, 50%);
}

/* The entrance animation belongs to the hero opening, not to every frame —
   ten copies of it firing at once was ten images fading in behind each other. */
.fl-hero--seq .fl-hero__slide .fl-hero__image {
  animation: none;
  transform: scale(1.06);
  transform-origin: center;
}

.fl-hero--seq .fl-hero__media {
  animation: fl-hero-fade 1.2s var(--fl-ease) both;
}

@keyframes fl-hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: no-preference) {

  /*
   * Nine seconds against a five-and-a-half second turn, so the zoom never
   * arrives — the frame is always still moving when it hands over. Linear on
   * purpose: an eased zoom has a visible beginning and end, and a background
   * that starts and stops draws the eye away from the words in front of it.
   */
  /*
   * .is-leaving carries the identical declaration on purpose.
   *
   * With the animation on .is-active alone, losing that class removed the
   * animation, and the outgoing picture snapped from 1.14 back to 1.06 while
   * it was still on screen fading out. That snap — not the fade — was what
   * read as a hard cut. The animation-name is unchanged between the two
   * classes, so the zoom carries straight on through the hand-over.
   */
  .fl-hero--seq .fl-hero__slide.is-active .fl-hero__image,
  .fl-hero--seq .fl-hero__slide.is-leaving .fl-hero__image {
    animation: fl-hero-kenburns 11s linear both;
  }

  @keyframes fl-hero-kenburns {
    from { transform: scale(1.06); }
    to   { transform: scale(1.2); }
  }
}

/* A background film and a still sequence are the same promise; when one is
   playing the other must not show through. */
.fl-hero__video ~ .fl-hero__seq {
  display: none;
}

/* ==========================================================================
   Hero — slide controls

   Bottom right, not bottom centre: the scroll cue already lives in the middle
   and two clusters on the same line read as a toolbar. The right-hand corner
   is also where the eye finishes crossing the picture.
   ========================================================================== */

.fl-hero__nav {
  position: absolute;
  z-index: 4;
  inset-inline-end: clamp(1.25rem, 4vw, 3.5rem);
  /*
   * Measured from the hero's bottom, which sits below the fold: the section is
   * 100svh tall and starts under a header that takes its own height, so the
   * last ~76px of it are off screen. Anchoring at 3rem put the buttons in that
   * strip — present in the markup, invisible on the page.
   */
  inset-block-end: clamp(6rem, 14vh, 9rem);
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 1.25rem);
}

.fl-hero__nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px: the smallest target that can be hit reliably with a thumb. */
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(6, 6, 8, 0.35);
  border: 1px solid rgba(201, 161, 74, 0.45);
  border-radius: 50%;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(6px);
  transition: color 0.35s var(--fl-ease), border-color 0.35s var(--fl-ease), background-color 0.35s var(--fl-ease);
}

.fl-hero__nav-btn:hover,
.fl-hero__nav-btn:focus-visible {
  color: #0b0b0f;
  background: var(--fl-gold, #c9a14a);
  border-color: var(--fl-gold, #c9a14a);
}

.fl-hero__nav-count {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;   /* 01 and 10 must not shift the row */
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.72);
}

.fl-hero__nav-rule {
  width: clamp(1.5rem, 4vw, 3rem);
  height: 1px;
  background: linear-gradient(90deg, var(--fl-gold, #c9a14a), rgba(255, 255, 255, 0.25));
}

.fl-hero__nav-total {
  color: rgba(255, 255, 255, 0.45);
}

@media (max-width: 599px) {

  /* On a phone the cue and the controls cannot share the bottom edge. The
     controls move to the middle and the cue keeps its place below them. */
  .fl-hero__nav {
    inset-inline: 0;
    justify-content: center;
    inset-block-end: clamp(4.5rem, 12vh, 6rem);
  }
}

@media (prefers-reduced-motion: reduce) {

  .fl-hero__nav-btn {
    transition: none;
  }
}
