/* ==========================================================================
   Motion — the site-wide layer.

   Three rules govern everything here:

   1. CONTENT IS NEVER HIDDEN BY DEFAULT. Every reveal rule is nested under
      .hdc-motion, a class assets/motion.js puts on <html> only once it is
      running and has decided motion is wanted. With JS broken, blocked or slow,
      the page renders exactly as it did before this file existed. A reveal
      system that hides content first and shows it later is one script error
      away from a blank site.

   2. TRANSFORM AND OPACITY ONLY. Both are composited, so nothing here triggers
      layout or paint on scroll. No animating height, top, margin or width.

   3. REDUCED MOTION IS AN EXIT, NOT A DIMMER. motion.js does not even add the
      class when the user has asked for less motion, so the rules below never
      apply and nothing has to be un-done.
   ========================================================================== */

/* Scroll reveal -------------------------------------------------------------
   A rise and a fade, once, then the element is left alone. Elements are tagged
   by motion.js rather than by hand in templates — see that file for what it
   selects and how to opt out.
   -------------------------------------------------------------------------- */
.hdc-motion [data-reveal] {
  opacity: 0;
  transform: translateY(var(--hdc-rise));
  transition:
    opacity var(--hdc-dur-slow) var(--hdc-ease),
    transform var(--hdc-dur-slow) var(--hdc-ease);
  /* Nudges the compositor to promote this before it moves, so the first frame
     is not the janky one. Dropped again on arrival — a permanently promoted
     layer costs memory on every element for no benefit once it has stopped. */
  will-change: opacity, transform;
}

.hdc-motion [data-reveal].is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Stagger. Small and capped: past the fourth step the last element is waiting
   long enough that the group stops reading as one movement. */
.hdc-motion [data-reveal][data-reveal-i="1"] { transition-delay: 60ms; }
.hdc-motion [data-reveal][data-reveal-i="2"] { transition-delay: 120ms; }
.hdc-motion [data-reveal][data-reveal-i="3"] { transition-delay: 180ms; }


/* Page load -----------------------------------------------------------------
   The first screen does not wait for a scroll it is already at. motion.js marks
   whatever is above the fold so it rises immediately on arrival instead of
   appearing to pop in when the observer catches up.
   -------------------------------------------------------------------------- */
.hdc-motion [data-reveal][data-reveal-now] {
  transition-delay: 0ms;
}


/* Press feedback ------------------------------------------------------------
   The one thing the site had no motion for at all: nothing acknowledged a
   click. A 1px drop is under the threshold most people consciously notice and
   over the threshold they feel — which is the whole point of press feedback.

   :active only, never :focus — a keyboard user tabbing through should not see
   every control twitch.
   -------------------------------------------------------------------------- */
.btn,
.chip,
.hdc-dot,
.cc-work__arrow,
.area-car__arrow {
  transition:
    background var(--hdc-dur-fast) var(--hdc-ease),
    color var(--hdc-dur-fast) var(--hdc-ease),
    border-color var(--hdc-dur-fast) var(--hdc-ease),
    transform var(--hdc-dur-fast) var(--hdc-ease);
}

.btn:active,
.chip:active,
.cc-work__arrow:active,
.area-car__arrow:active {
  transform: translateY(1px);
}

/* A dot is 8px. Moving it 1px is a wobble, so it presses by shrinking. */
.hdc-dot:active { transform: scale(0.88); }

@media (prefers-reduced-motion: reduce) {
  .btn:active,
  .chip:active,
  .hdc-dot:active,
  .cc-work__arrow:active,
  .area-car__arrow:active { transform: none; }
}


/* Hover on media ------------------------------------------------------------
   Photographs inside a link lift very slightly. scale() rather than a filter or
   a box-shadow: both of those repaint, and this runs on cards that appear a
   dozen at a time on Find Your Home.

   Scoped to the card components that already own their own photo frame with
   overflow:hidden — applied blind, a scale on any img would break every
   unclipped image on the site.
   -------------------------------------------------------------------------- */
.hdc-motion .home-card__ph img,
.hdc-motion .community-card__ph img,
.hdc-motion .feature-card__ph img {
  transition: transform var(--hdc-dur-slow) var(--hdc-ease);
}
.hdc-motion .home-card:hover .home-card__ph img,
.hdc-motion .community-card:hover .community-card__ph img,
.hdc-motion .feature-card:hover .feature-card__ph img {
  transform: scale(1.03);
}


/* ==========================================================================
   Loader — the emblem, filling band by band.

   Used for waits the VISITOR STARTED and cannot predict the end of: the map
   loading, a video facade opening, a form submitting. Deliberately not used for
   page load — a full-page loader hides content the browser could already paint
   and makes a fast first paint into a slow one.
   ========================================================================== */
.hdc-loader { display: inline-flex; align-items: center; justify-content: center; }
.hdc-loader__mark { width: 100%; height: 100%; display: block; overflow: visible; }

/* Each band sits at the muted tone and lights to brand blue as the sweep passes.
   Colour is the whole animation — nothing moves, so this cannot cause layout
   work no matter how many are on screen. */
.hdc-loader__band {
  fill: var(--hdc-loader-off, var(--hdc-line-strong));
  animation: hdc-loader-sweep 1.5s var(--hdc-ease) infinite;
  /* 70ms per band × 12 = 840ms for the sweep to travel the mark, inside a 1.5s
     cycle — so there is a beat of rest before it starts again rather than a
     continuous shimmer. */
  animation-delay: calc(var(--i) * 70ms);
}

@keyframes hdc-loader-sweep {
  0%            { fill: var(--hdc-loader-off, var(--hdc-line-strong)); }
  /* Short peak: a band is lit briefly and fades, which is what makes the sweep
     read as travelling rather than as the whole mark pulsing. */
  18%           { fill: var(--hdc-loader-on, var(--hdc-color-primary)); }
  55%, 100%     { fill: var(--hdc-loader-off, var(--hdc-line-strong)); }
}

/* Sizes. The mark is square, so one value does both. */
.hdc-loader { width: 56px; height: 56px; }
.hdc-loader--sm { width: 22px; height: 22px; }
.hdc-loader--lg { width: 84px; height: 84px; }

/* On a dark ground — the video facade, and the map's dark placeholder. */
.hdc-loader--on-dark {
  --hdc-loader-off: color-mix(in srgb, var(--hdc-color-on-dark) 26%, transparent);
  --hdc-loader-on: var(--hdc-color-on-dark);
}

/* Sits next to a label, as on a submit button. */
.hdc-loader.is-inline { width: 1.15em; height: 1.15em; vertical-align: -0.18em; }

@media (prefers-reduced-motion: reduce) {
  /* No sweep. The mark still says "something is happening" by being present and
     half-toned; it just does not move. Removing the loader entirely would leave
     the visitor staring at nothing. */
  .hdc-loader__band {
    animation: none;
    fill: var(--hdc-loader-off, var(--hdc-line-strong));
  }
  .hdc-loader__band:nth-child(-n+6) {
    fill: var(--hdc-loader-on, var(--hdc-color-primary));
  }
}


/* Map loading overlay -------------------------------------------------------
   Dim and blur the page behind the emblem while Google's script and its first
   tiles come down. Fixed to the viewport, not to the map pane: the results list
   is about to be re-drawn with pins, so it should not be clickable mid-load.

   backdrop-filter does the blur, and a tint sits under it for browsers that do
   not support it — without that fallback the overlay would be nearly invisible
   there and the loader would float on live content.
   -------------------------------------------------------------------------- */
/* ⚠️ SCOPED TO THE MAP PANE, not the viewport, and that follows from the map no
   longer being gated. A full-page dim was right when loading was something the
   visitor CHOSE — it framed a wait they had asked for. Now the map loads on
   arrival, so the same overlay would blanket the whole page for ~3.5s of every
   Find Your Home visit, hiding the results list that is already rendered and
   readable. That is the page-load loader this component exists specifically to
   avoid being.
   The pane is position:relative, so `absolute` fills exactly it. */
.fyh-mapload {
  position: absolute; inset: 0; z-index: 3;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--hdc-space-5);
  background: color-mix(in srgb, var(--hdc-surface-ink) 38%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  /* Fades in so a fast connection does not flash a dark panel and remove it. */
  animation: hdc-mapload-in var(--hdc-dur) var(--hdc-ease) both;
}
.fyh-mapload[hidden] { display: none; }

@keyframes hdc-mapload-in { from { opacity: 0; } to { opacity: 1; } }

/* The emblem reads on the blurred page beneath, so it keeps the light treatment
   (grey → blue) rather than the on-dark one. */
.fyh-mapload .hdc-loader { width: 84px; height: 84px; }

.fyh-mapload__note {
  margin: 0; font-family: var(--hdc-font-ui); font-size: var(--hdc-fs-300);
  letter-spacing: var(--hdc-tracking-eyebrow); text-transform: uppercase;
  color: var(--hdc-color-on-dark);
}

/* ⚠️ NO overflow:hidden SCROLL LOCK HERE, and it is not an oversight.
   Find Your Home renders the .is-static / position:STICKY header, and theme.css
   documents what overflow:hidden does to it: sticky dies the moment an ancestor
   is clipped, so the header drops to its document position and disappears —
   measured at -1568px off-screen when the mega-menu made the same mistake. That
   lock is scoped to fixed-header pages for exactly this reason, and this overlay
   only ever appears on a sticky-header one.

   The overlay is fixed and covers the viewport, so it already absorbs clicks;
   the page being scrollable behind it for the second or two Google takes is a
   far smaller problem than a header that vanishes. Locking also removes the
   scrollbar, which shifts the whole page 15px sideways as it appears. */

/* Covers the map pane only; the results list beside it stays usable throughout. */
.fyh-mapload { pointer-events: auto; }

@media (prefers-reduced-motion: reduce) {
  .fyh-mapload { animation: none; }
}


/* Submit spinner ------------------------------------------------------------
   A plain ring, not the emblem. The emblem sweep is a 1.5s cycle built to be
   looked at; a submit button is a half-second wait glanced at out of the corner
   of an eye, and the mark would not complete a single pass.

   ⚠️ Hooked to Fluent Forms' OWN state, deliberately. On submit Fluent adds
   .ff_submitting to the form and .ff-working + .disabled to .ff-btn-submit
   (verified in its bundle, not assumed). Driving the spinner off that class
   means it appears and disappears exactly when a submission starts and ends —
   no JS of ours, and nothing to desync if the request fails or Fluent changes
   its flow.

   .btn is inline-flex with a gap, so the pseudo-element becomes a flex item and
   spaces itself against the label without any extra rule.
   -------------------------------------------------------------------------- */
.ff-btn-submit.ff-working::after {
  content: "";
  width: 1em; height: 1em;
  flex: 0 0 auto;
  border-radius: 50%;
  /* currentColor, so it works on the primary button and on any variant that
     changes the label colour without needing a second rule. */
  border: 2px solid color-mix(in srgb, currentColor 28%, transparent);
  border-top-color: currentColor;
  animation: hdc-spin 0.7s linear infinite;
}

@keyframes hdc-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  /* The ring stays — it is the only signal that the press registered, since
     Fluent also disables the button and the label does not change. It just
     does not turn. */
  .ff-btn-submit.ff-working::after { animation: none; }
}
