/* ==========================================================================
 * THE SKAGIT CASINO RESORT — MOTION LAYER
 * Restrained page motion for the "Midnight Brass" design system.
 * --------------------------------------------------------------------------
 * Enqueue handle: `skagit-motion`. MUST load after `skagit-header` (the last
 * design-system layer) so the few hover/press supplements in §6 win on source
 * order at equal specificity instead of reaching for !important.
 *
 * THE BRIEF WAS "MINIMAL". Everything here is deliberately below the
 * threshold of notice: 10px of travel, one duration token, no scale, no
 * blur, no rotation, no parallax, no attention-seeking easing. If a guest
 * perceives the motion as motion, this file has failed.
 *
 * --------------------------------------------------------------------------
 * MOTION CONTRACT  (identical in shape to skagit-jackpot.css §2 — read that
 * file's header too; the two layers are siblings, not competitors)
 *
 *   1. Nothing in this stylesheet can hide anything unless `html.sk-motion-js`
 *      is present. skagit-motion.js adds that class as its first statement,
 *      from the document HEAD, before <body> paints. If the script 404s,
 *      throws, is blocked by an extension, or is stripped by an optimiser,
 *      the class never lands and every element renders at full opacity.
 *   2. The hidden state is double-gated: it needs the flag AND
 *      `prefers-reduced-motion: no-preference`.
 *   3. §7 is a third, independent kill switch for reduce users, repeating the
 *      hidden-state selector list with `opacity: 1 !important`. Redundant by
 *      design — if either of the first two gates is ever edited away, no
 *      Skagit content can still be left invisible.
 *   4. The script drops the flag entirely (rather than trying to un-hide
 *      element by element) if its IntersectionObserver never reports. One
 *      class removal restores every element this file could possibly touch,
 *      so a selector drift between the CSS and the JS cannot strand content.
 *
 * OWNERSHIP / NON-DUPLICATION
 *   - `.skagit-jp-*` reveals belong to skagit-jackpot.css. Not touched, not
 *     re-observed, not listed below.
 *   - Button hover/press already lives in skagit-buttons.css and card hover
 *     already lives in skagit-components.css §7.1 and
 *     skagit-rooms-amenities.css §4. §6 below adds only the two states those
 *     files genuinely do not cover, using their own custom properties.
 *   - `scroll-behavior: smooth` and `scroll-padding-top` are already set on
 *     `html` by skagit-design-system.css §2. Deliberately NOT repeated here.
 *   - The focus ring is never animated, never delayed, never faded. There is
 *     no `:focus-visible` rule anywhere in this file, and no transition
 *     declared below names `outline`, `box-shadow` or `border-color` on a
 *     focus state.
 *
 * TECHNIQUE NOTE — why animations, not transitions
 *   Every reveal target already carries a `transition` shorthand of its own
 *   (cards transition transform + box-shadow for their hover lift). Declaring
 *   `transition` here would replace that list and break hover. Declaring
 *   `transform: none` on the settled state would out-specify `…:hover` and
 *   break it a second way. A keyframe animation with `animation-fill-mode:
 *   backwards` touches neither: it holds the from-state during the delay,
 *   runs, and then hands every property back to the normal cascade — so the
 *   card's own hover transform is intact the instant the reveal ends.
 *
 * `will-change` is used ZERO times. A running animation is promoted by the
 * compositor automatically and de-promoted when it ends, which is exactly the
 * lifetime we want; a persistent `will-change` on every card is not.
 *
 * Prefix: sk-motion / sk-reveal / sk-in / sk-img
 * ========================================================================== */


/* ==========================================================================
   1. TOKENS
   All borrowed from skagit-design-system.css §1.10. Only the two values that
   are specific to this layer are declared new.
   ========================================================================== */
:root {
  /* Matches the jackpot layer's reveal duration exactly, so on the home page —
     where both layers run — the two never read as two different systems.
     Fallbacks are literal copies of the design-system values: a custom
     property resolves lazily, so if this file were ever enqueued without
     skagit-design-system.css the whole `animation` shorthand would otherwise
     become invalid-at-computed-value and the reveal would never run — leaving
     `opacity: 0` in place. That is the one failure mode worth spelling out. */
  --sk-reveal-dur: var(--sk-dur-slow, 480ms);   /* 480ms */
  --sk-reveal-ease: var(--sk-ease-out, cubic-bezier(0.22, 0.68, 0.32, 1));
  /* Half the jackpot plate's travel. These are whole sections and full-width
     card rows; the larger the element, the less distance it needs to read as
     "settling" rather than "sliding". */
  --sk-reveal-shift: 10px;
}


/* ==========================================================================
   2. KEYFRAMES
   Declared unconditionally so they always resolve. `opacity` and `transform`
   only — nothing here can trigger layout.
   ========================================================================== */
@keyframes sk-reveal-in {
  from {
    opacity: 0;
    transform: translate3d(0, var(--sk-reveal-shift, 10px), 0);
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

@keyframes sk-img-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}


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

  /* ========================================================================
     3. SCROLL REVEAL — the hidden state
     ------------------------------------------------------------------------
     THE CANONICAL TARGET LIST. skagit-motion.js holds a byte-identical copy
     in its REVEAL constant; the two must be edited together. (If they ever do
     drift, §4 of the motion contract catches it: the script drops the flag
     and every selector below stops applying at once.)

     Every selector was grepped against the templates before it was added:
       .skagit-home-intro / -offers / -suites / -rewards  front-page.php
       .location-header                                   archive-entertainment.php
       .skagit-ra-group-header                            archive-room.php, archive-amenity.php
       .skagit-ra-more-header                             single-room.php, single-amenity.php
       .skagit-ra-gallery-section                         single-room.php, single-amenity.php
       .promotions-grid > .sno-card                       archive-promotion.php
       .ent-grid > .ent-card                              archive-entertainment.php
       .skagit-ra-grid > .skagit-ra-card                  archive-*.php, single-*.php

     DELIBERATELY ABSENT:
       - The hero ([skagit_hero]) and `.skagit-home-booking`. Above the fold,
         and the hero image is the LCP element on the home page. Nothing that
         could be the LCP is allowed to depend on JavaScript to become visible.
       - `.promo-text-header` on the archives — first thing on the page.
       - Slick tracks (`.random-offers-wrapper .offer-card`,
         `.modern-home-card`). Slick transforms the track and clones slides;
         a second transform on the slides is asking for a fight.
       - Everything `.skagit-jp-*`. That layer reveals itself.
       - Section wrappers whose children are also revealed. Only ever one of
         the two, never nested — a section fading in while its cards stagger
         inside it is exactly the "announced" motion the brief rules out.

     `:not(.sk-in)` on every selector means the settled rule in §4 does not
     have to out-specify this one.
     ==================================================================== */
  html.sk-motion-js .skagit-spaces__row:not(.sk-in),
html.sk-motion-js .skagit-section-card:not(.skagit-section-card--bare):not(.sk-in),
html.sk-motion-js .skagit-home-intro:not(.sk-in),
  html.sk-motion-js .skagit-home-offers:not(.sk-in),
  html.sk-motion-js .skagit-home-suites:not(.sk-in),
  html.sk-motion-js .skagit-home-rewards:not(.sk-in),
  html.sk-motion-js .skagit-lede:not(.sk-in),
  html.sk-motion-js .skagit-page-gallery:not(.sk-in),
  html.sk-motion-js .skagit-hours__table:not(.sk-in),
  html.sk-motion-js .skagit-page-figure:not(.sk-in),
  html.sk-motion-js .skagit-sections > .skagit-section-card:not(.sk-in),
  html.sk-motion-js .skagit-hours__strip:not(.sk-in),
  html.sk-motion-js .skagit-ra-amenities:not(.sk-in),
  html.sk-motion-js .skagit-menu__section:not(.sk-in),
  html.sk-motion-js .location-header:not(.sk-in),
  html.sk-motion-js .skagit-ra-group-header:not(.sk-in),
  html.sk-motion-js .skagit-ra-more-header:not(.sk-in),
  html.sk-motion-js .skagit-ra-gallery-section:not(.sk-in),
  html.sk-motion-js .promotions-grid > .sno-card:not(.sk-in),
  html.sk-motion-js .ent-grid > .ent-card:not(.sk-in),
  html.sk-motion-js .skagit-ra-grid > .skagit-ra-card:not(.sk-in) {
    opacity: 0;
  }


  /* ========================================================================
     4. SCROLL REVEAL — the settled state
     One generic rule. It supplies the animation and nothing else; `opacity`
     comes back from the normal cascade the moment `:not(.sk-in)` above stops
     matching, so there is no specificity race to lose.
     ==================================================================== */
  html.sk-motion-js .sk-in {
    animation: sk-reveal-in
               var(--sk-reveal-dur)
               var(--sk-reveal-ease)
               var(--sk-reveal-delay, 0ms)
               backwards;
  }

  /* Applied by the script to (a) anything already inside the viewport when
     the page boots and (b) anything a keyboard user tabs to before it has
     been scrolled into view. Both cases must appear NOW, not in 480ms. */
  html.sk-motion-js .sk-in.sk-in--instant {
    animation: none;
  }


  /* ========================================================================
     5. STAGGER
     50ms a step, five steps, then flat. 250ms is the entire budget for a row
     of cards — long enough to read as one gesture arriving, far too short to
     read as a sequence being performed.

     `:is()` is used only to assign a custom property. If a browser does not
     support it the whole rule is dropped, `--sk-reveal-delay` stays unset,
     the fallback in §4 resolves to 0ms and the row simply arrives together.
     A degraded stagger is not a bug.
     ==================================================================== */
  html.sk-motion-js :is(.promotions-grid, .ent-grid, .skagit-ra-grid, .skagit-sections) > :nth-child(1) { --sk-reveal-delay: 0ms; }
  html.sk-motion-js :is(.promotions-grid, .ent-grid, .skagit-ra-grid, .skagit-sections) > :nth-child(2) { --sk-reveal-delay: 50ms; }
  html.sk-motion-js :is(.promotions-grid, .ent-grid, .skagit-ra-grid, .skagit-sections) > :nth-child(3) { --sk-reveal-delay: 100ms; }
  html.sk-motion-js :is(.promotions-grid, .ent-grid, .skagit-ra-grid, .skagit-sections) > :nth-child(4) { --sk-reveal-delay: 150ms; }
  html.sk-motion-js :is(.promotions-grid, .ent-grid, .skagit-ra-grid, .skagit-sections) > :nth-child(5) { --sk-reveal-delay: 200ms; }
  html.sk-motion-js :is(.promotions-grid, .ent-grid, .skagit-ra-grid, .skagit-sections) > :nth-child(n+6) { --sk-reveal-delay: 250ms; }


  /* ========================================================================
     6. IMAGE FADE-IN
     ------------------------------------------------------------------------
     Safe by construction, unlike §3: BOTH classes below are added by the
     script and by nothing else, and the script only ever adds
     `sk-img-pending` to an image whose `complete` is already false — i.e. one
     that is painting nothing at that moment anyway. Hiding a blank box is not
     hiding content. An image that fails to load fires `error`, which settles
     it, so alt text is never suppressed.

     An animation rather than a transition again: `.ent-card:hover img` and
     `.skagit-ra-card:hover img` own these elements' `transition` shorthand for
     their 1.06 photo scale, and a transition here would delete it.

     Scope is the six verified photo containers only. Logos, icons, the hero
     and the jackpot plates are all excluded on purpose.
     ==================================================================== */
  html.sk-motion-js .promotions-grid .sno-card-image img.sk-img-pending,
  html.sk-motion-js .ent-grid .ent-card-image img.sk-img-pending,
  html.sk-motion-js .skagit-ra-media img.sk-img-pending,
  html.sk-motion-js .skagit-ra-single-media img.sk-img-pending,
  html.sk-motion-js .skagit-ra-gallery img.sk-img-pending,
  html.sk-motion-js .rewards-promo-visual img.sk-img-pending {
    opacity: 0;
  }

  html.sk-motion-js img.sk-img-in {
    animation: sk-img-fade var(--sk-reveal-dur) var(--sk-reveal-ease) both;
  }


  /* ========================================================================
     7. HOVER / PRESS SUPPLEMENTS
     ------------------------------------------------------------------------
     Checked first, and almost everything was already there:

       skagit-buttons.css   §1  transitions transform + box-shadow on .sk-btn
                            §2  --sk-btn-lift: -2px on primary hover, 0 on
                                primary :active
                            §3-5 -1px hover lift on secondary / cyan / on-dark
                                / ghost
                            §9  transform: none on :focus-visible
                            §10 full reduce block
       skagit-components.css §7.1 translateY(-6px) + --sk-shadow-lg on the
                                whole legacy card family, plus the brass
                                top-edge sweep on :hover AND :focus-within
       skagit-rooms-amenities.css §4 the same treatment for .skagit-ra-card
                                and an :active reset for .skagit-ra-btn--primary

     So exactly two gaps are filled here, both reusing the existing
     mechanism rather than introducing a parallel one:

       7.1  `:active` on the .sk-btn variants that never got one. Primary,
            .expand-main-btn, .subscribe-btn, .ent-card-btn, .sno-btn-solid
            and #sb-submit-btn already have it; secondary, cyan, ghost, link
            and the on-dark variants did not, so they stayed lifted while
            being pressed. Setting the SAME custom property the buttons file
            uses means the existing transform + transition carry it — nothing
            is overridden, nothing is duplicated.

       7.2  `:active` on the cards. They lift on hover but had no press, so a
            tap on a touch device produced the hover lift and then nothing.
            -2px against the -6px hover reads as the card taking the press.
            The cards already transition `transform`, so this eases for free.

     .skagit-ra-btn--ghost is intentionally left alone: its `transition` list
     has no `transform` entry, so adding a press there would mean rewriting
     that shorthand — i.e. fighting the file that owns it, which the brief
     forbids.
     ==================================================================== */

  /* 7.1 — (0,2,0), same as `.sk-btn--secondary:hover`. This file loads after
     skagit-buttons.css, so it wins the tie on source order. It does NOT
     out-specify the two (0,3,0) selectors `.sk-btn--secondary.sk-btn--on-dark:hover`
     and `.expand-actions .expand-main-btn:hover`; that is accepted rather than
     escalated, because both of those already behave acceptably and an
     escalation here would be the start of a specificity war. */
  .sk-btn:active { --sk-btn-lift: 0px; }

  /* 7.2 */
  .promotions-grid .sno-card:active,
  .ent-grid .ent-card:active,
  .skagit-ra-grid .skagit-ra-card:active {
    transform: translateY(-2px);
  }

}   /* end @media (prefers-reduced-motion: no-preference) */


/* ==========================================================================
   8. REDUCED MOTION  (independent kill switch)
   --------------------------------------------------------------------------
   Belt, braces and a second belt. skagit-motion.js already refuses to set the
   `sk-motion-js` flag when reduce is requested — and re-checks on
   `matchMedia` change, dropping the flag mid-session if the preference is
   turned on — and §3-§7 are gated on `no-preference` besides. This block
   exists so that if BOTH of those safeguards are ever edited away, this layer
   still cannot leave a single element invisible or in motion.

   Note it does not merely shorten anything. Reveals do not happen, images do
   not fade, cards do not press. Content is simply present and static.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {

  /* The bare selector already covers the `:not(.sk-in)` case, so the list is
     the canonical one from §3 with nothing appended. */
  html.sk-motion-js .skagit-home-intro,
  html.sk-motion-js .skagit-home-offers,
  html.sk-motion-js .skagit-home-suites,
  html.sk-motion-js .skagit-home-rewards,
  html.sk-motion-js .location-header,
  html.sk-motion-js .skagit-ra-group-header,
  html.sk-motion-js .skagit-ra-more-header,
  html.sk-motion-js .skagit-ra-gallery-section,
  html.sk-motion-js .promotions-grid > .sno-card,
  html.sk-motion-js .ent-grid > .ent-card,
  html.sk-motion-js .skagit-ra-grid > .skagit-ra-card,
  html.sk-motion-js img.sk-img-pending {
    opacity: 1 !important;      /* documented: the ONLY way to be certain no
                                   future edit above can strand content at
                                   opacity: 0 for a reduce user */
    animation: none !important;
    transform: none !important;
  }

  html.sk-motion-js .sk-in,
  html.sk-motion-js img.sk-img-in {
    animation: none !important;
    opacity: 1 !important;
  }

  /* The two supplements from §7 are inside `no-preference` and so never
     reach a reduce user. Listed again anyway, for the same reason as above. */
  .sk-btn:active,
  .promotions-grid .sno-card:active,
  .ent-grid .ent-card:active,
  .skagit-ra-grid .skagit-ra-card:active {
    transform: none !important;
  }
}


/* ==========================================================================
   9. PRINT
   Nothing revealed, nothing faded, nothing pending. A print stylesheet that
   inherits an opacity: 0 is a blank page.
   ========================================================================== */
@media print {
  html.sk-motion-js *,
  html.sk-motion-js *::before,
  html.sk-motion-js *::after {
    animation: none !important;
  }

  html.sk-motion-js .promotions-grid > .sno-card,
  html.sk-motion-js .ent-grid > .ent-card,
  html.sk-motion-js .skagit-ra-grid > .skagit-ra-card,
  html.sk-motion-js .skagit-home-intro,
  html.sk-motion-js .skagit-home-offers,
  html.sk-motion-js .skagit-home-suites,
  html.sk-motion-js .skagit-home-rewards,
  html.sk-motion-js .location-header,
  html.sk-motion-js .skagit-ra-group-header,
  html.sk-motion-js .skagit-ra-more-header,
  html.sk-motion-js .skagit-ra-gallery-section,
  html.sk-motion-js img.sk-img-pending {
    opacity: 1 !important;
    transform: none !important;
  }
}


/* ==========================================================================
   7. HOVER LIFT — the card families, site-wide

   The ETG cards get their lift from jQuery because that page was asked for
   jQuery specifically. Everywhere else it is done here in CSS, for three
   reasons: it costs no JavaScript, it cannot fight the reveal layer over the
   same property, and it degrades by simply not happening.

   `transform` is used rather than `margin-top` so the lift never reflows the
   grid row around it — the ETG version animates margin because jQuery cannot
   tween a transform without a step callback.

   Scoped to `(hover: hover) and (pointer: fine)`: on a touch screen a hover
   state sticks after the tap and reads as a stuck selection.
   ========================================================================== */
@media (hover: hover) and (pointer: fine) {

  .promotions-grid > .sno-card,
  .ent-grid > .ent-card,
  .skagit-ra-grid > .skagit-ra-card,
  .skagit-sections > .skagit-section-card,
  .random-offers-wrapper .offer-card {
    transition: transform var(--sk-dur-base) var(--sk-ease-out),
                box-shadow var(--sk-dur-base) var(--sk-ease-out);
    will-change: transform;
  }

  .promotions-grid > .sno-card:hover,
  .ent-grid > .ent-card:hover,
  .skagit-ra-grid > .skagit-ra-card:hover,
  .skagit-sections > .skagit-section-card:hover,
  .random-offers-wrapper .offer-card:hover,
  /* focus-within so a keyboard user gets the same affordance as a mouse. */
  .promotions-grid > .sno-card:focus-within,
  .ent-grid > .ent-card:focus-within,
  .skagit-ra-grid > .skagit-ra-card:focus-within,
  .skagit-sections > .skagit-section-card:focus-within,
  .random-offers-wrapper .offer-card:focus-within {
    transform: translateY(-4px);
    box-shadow: var(--sk-shadow-lg);
  }
}

/* The site-wide reduced-motion rule in §1 covers the reveal; the lift needs
   saying separately because it lives in its own hover media query. */
@media (prefers-reduced-motion: reduce) {

  .promotions-grid > .sno-card,
  .ent-grid > .ent-card,
  .skagit-ra-grid > .skagit-ra-card,
  .skagit-sections > .skagit-section-card,
  .random-offers-wrapper .offer-card {
    transition: none !important;
    will-change: auto;
  }

  .promotions-grid > .sno-card:hover,
  .ent-grid > .ent-card:hover,
  .skagit-ra-grid > .skagit-ra-card:hover,
  .skagit-sections > .skagit-section-card:hover,
  .random-offers-wrapper .offer-card:hover {
    transform: none;
  }
}
