/* ========================================
   MILNER HOUSE — Skeleton loaders
   ========================================

   Design rules this file follows, and why:

   1. NO WRAPPER ELEMENTS. The skeleton is painted as the background of the
      <img>/<iframe>/<video> itself. Wrapping media in a placeholder <div> would
      break the existing direct-child selectors (.gallery-item > img,
      .room-carousel__track > img, ...) and risks shifting layout.

   2. THE IMAGE IS NEVER HIDDEN. The usual implementation sets opacity:0 until
      onload and fades in — that delays the largest contentful paint, so it makes
      the real metric worse to make the perceived one better. Here the shimmer is
      *behind* the image, so pixels paint the moment they arrive.

   3. ZERO LAYOUT SHIFT. Skeletons only ever paint inside a box the element
      already reserves via its width/height attributes or CSS aspect-ratio. A
      skeleton that changes an element's size is worse than no skeleton at all.

   4. JS-GATED. The class is applied by assets/js/skeleton.js, and everything is
      scoped to html.js. If JS fails, media loads exactly as it does today.
*/

:root {
  --skeleton-base: #efece7;
  --skeleton-sheen: #f8f6f3;
  --skeleton-speed: 1.4s;
}

@keyframes mh-skeleton-shimmer {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -200% 0;
  }
}

/* Applied to img / iframe / video while the resource is in flight. */
.js .is-skeleton {
  background-color: var(--skeleton-base);
  background-image: linear-gradient(
    90deg,
    var(--skeleton-base) 0%,
    var(--skeleton-base) 35%,
    var(--skeleton-sheen) 50%,
    var(--skeleton-base) 65%,
    var(--skeleton-base) 100%
  );
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: mh-skeleton-shimmer var(--skeleton-speed) ease-in-out infinite;
}

/* Media that failed to load keeps a flat tint rather than shimmering forever. */
.js .is-skeleton-failed {
  background-color: var(--skeleton-base);
  background-image: none;
  animation: none;
}

/* ---- CSS background heroes -------------------------------------------------
   Hero sections paint their photo via background-image, so there is no load
   event to listen for. skeleton.js preloads the URL and removes the overlay
   when it resolves.

   This uses an injected child element rather than a pseudo-element on purpose:
   .guide-hero::before (guide.css) and .restaurant-hero__bg::after
   (restaurant.css) are both already taken, and page stylesheets load after this
   one, so a pseudo-element here would be silently overridden on exactly the
   pages that need it most.

   z-index:-1 puts the overlay above the host's background image but below its
   in-flow content, so headings and buttons stay readable throughout.
   isolation:isolate on the host guarantees that negative z-index resolves
   against the host rather than escaping to an ancestor. */
.js .has-skeleton-overlay {
  isolation: isolate;
}

.js .mh-skeleton-overlay {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-color: var(--skeleton-base);
  background-image: linear-gradient(
    90deg,
    var(--skeleton-base) 0%,
    var(--skeleton-base) 35%,
    var(--skeleton-sheen) 50%,
    var(--skeleton-base) 65%,
    var(--skeleton-base) 100%
  );
  background-size: 200% 100%;
  animation: mh-skeleton-shimmer var(--skeleton-speed) ease-in-out infinite;
  opacity: 1;
  transition: opacity 0.35s ease;
}

.js .mh-skeleton-overlay.is-settled {
  opacity: 0;
}

/* ---- Text skeletons --------------------------------------------------------
   Deliberately minimal. Every block of copy on this site is server-rendered and
   present in the HTML on first paint, so there is nothing to wait for — a text
   skeleton would have to HIDE real content to show a grey bar, which is slower
   and costs the crawler the text. These classes exist only for genuinely
   deferred content (none at present). */
.js .skeleton-text {
  display: block;
  height: 0.85em;
  margin: 0.4em 0;
  border-radius: var(--radius-sm, 0.25rem);
  background-color: var(--skeleton-base);
  background-image: linear-gradient(
    90deg,
    var(--skeleton-base) 0%,
    var(--skeleton-base) 35%,
    var(--skeleton-sheen) 50%,
    var(--skeleton-base) 65%,
    var(--skeleton-base) 100%
  );
  background-size: 200% 100%;
  animation: mh-skeleton-shimmer var(--skeleton-speed) ease-in-out infinite;
}

.js .skeleton-text--short { width: 40%; }
.js .skeleton-text--half  { width: 60%; }

/* ---- Accessibility ---------------------------------------------------------
   A looping gradient is exactly the kind of motion vestibular-disorder users
   ask to be spared. Honour the OS setting: keep the placeholder tint, drop the
   movement. */
@media (prefers-reduced-motion: reduce) {
  .js .is-skeleton,
  .js .mh-skeleton-overlay,
  .js .skeleton-text {
    animation: none;
    background-image: none;
    background-color: var(--skeleton-base);
  }

  .js .mh-skeleton-overlay {
    transition: none;
  }
}

/* Print: never waste ink on placeholders. */
@media print {
  .is-skeleton,
  .skeleton-text {
    animation: none !important;
    background: none !important;
  }

  .mh-skeleton-overlay {
    display: none !important;
  }
}
