/* ==========================================================================
   WestCanna BC — motion.css (build 06 "the real mark, and motion")

   Everything here is additive on top of site.css/tools.css: hover primitives
   defined once and applied everywhere, the mark used as animated material,
   and the section-level motion the brief asks for. Loaded after both sheets
   so equal-specificity rules here win without needing !important.

   Two hard rules shape every line below:
   1. Every :hover effect that changes on a real pointer also has a bare
      :focus-visible / :focus-within rule outside any (hover:hover) guard, so
      keyboard users get the same feedback — and a plain :active rule for a
      tap, so touch never gets stuck mid-hover.
   2. Only transform, opacity, clip-path and mask-position are animated on
      anything that runs continuously or on scroll. Short, discrete state
      changes (a border or background settling into place on hover) reuse
      color/border/background/box-shadow transitions exactly as the rest of
      this codebase already does — nothing here introduces a new class of
      layout-affecting animation, and nothing animates width, height, top or
      left. prefers-reduced-motion is handled once, globally, in site.css
      (every transition/animation is collapsed to .001ms); the rules below
      only need to avoid animating anything that would still be visible at
      that speed as a jump-cut a reduced-motion visitor didn't ask for, which
      transform/opacity/mask-position/clip-path never are.
   ========================================================================== */

:root {
  --m-fast: .16s;
  --m-med:  .34s;
  --m-slow: .6s;
  --ease-out: cubic-bezier(.16, .8, .24, 1);
  --ease-soft: cubic-bezier(.22, .7, .3, 1);
}

/* ==========================================================================
   1. THE MARK, USED AS MATERIAL
   ========================================================================== */

/* ---------- the hero lockup: a soft bottom-up wipe reveal, once ---------- */
/* The mask is a tall (200%) soft-edged gradient; sliding its mask-position
   from 0% to 100% sweeps the feathered edge up through the logo once. The
   resting, non-animated state (no class, no JS, or a reduced-motion visitor)
   is mask-position 100% — fully visible — so the artwork is never hidden by
   CSS alone. JS only ever animates FROM 0% at runtime, matching how every
   other entrance in js/site.js works. */
.hero-lockup .lockup {
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 46%, transparent 56%, transparent 100%);
  mask-image: linear-gradient(to top, #000 0%, #000 46%, transparent 56%, transparent 100%);
  -webkit-mask-size: 100% 220%;
  mask-size: 100% 220%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: 0 100%;
  mask-position: 0 100%;
}
.hero-lockup .lockup.wc-reveal {
  animation: wc-lockup-reveal .9s var(--ease-out) both;
}
@keyframes wc-lockup-reveal {
  from { -webkit-mask-position: 0 0%; mask-position: 0 0%; }
  to   { -webkit-mask-position: 0 100%; mask-position: 0 100%; }
}

/* ---------- the sheen: a slow light sweep through the mask on hover ------
   One mask layer only — the logo's own alpha, fixed — clipping a diagonal
   band of light. A two-layer mask-composite:intersect (mask against the
   silhouette AND a moving band, so only mask-position ever animates) was
   tried first and verified against this build's own Chrome: the intersect
   composited to nothing in practice, so the sheen never painted. This is the
   pragmatic, verified-working fallback — background-position moves the band
   instead of a second mask layer. It is a paint-only property (no layout
   participation, nothing else on the page reflows) even though it sits
   outside the literal transform/opacity/clip-path/mask-position list; the
   outer clip against the real artwork still comes from mask-image as
   instructed, and reduced-motion still switches it off (site.css's blanket
   rule collapses the animation to .001ms). */
.hero-lockup, .foot-lockup, .mark-frame { position: relative; }
/* the footer's grid column (site.css) runs up to 300px but the lockup image
   inside it caps at 280px, left-aligned — a 20px gap the sheen's mask,
   sized to the whole column via inset:0, would otherwise scale into and
   render as a faint offset ghost of the mark. Capping the column at the
   image's own max-width keeps the two in registration. */
.foot-lockup { max-width: 280px; }
.hero-lockup::after, .foot-lockup::after, .mark-frame::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(100deg, transparent 38%, rgba(255,255,255,.95) 50%, transparent 62%);
  background-size: 300% 100%;
  background-position: -110% 0;
  background-repeat: no-repeat;
  opacity: 0;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-position: center;
  mask-position: center;
}
.hero-lockup::after, .foot-lockup::after {
  -webkit-mask-image: url('/assets/brand/wc-lockup-mask.png');
  mask-image: url('/assets/brand/wc-lockup-mask.png');
  /* the lockup is printed in bone — already near-white — so a pure white
     sheen has almost no luminance to show against it. A warm cedar glint
     reads as a highlight through colour instead, the way light warms cream
     paper rather than bleaching it. */
  background: linear-gradient(100deg, transparent 34%, rgba(184, 134, 91, .8) 50%, transparent 66%);
  background-size: 300% 100%;
  background-position: -110% 0;
  mix-blend-mode: hard-light;
}
.mark-frame::after {
  -webkit-mask-image: url('/assets/brand/wc-mark-mask.png');
  mask-image: url('/assets/brand/wc-mark-mask.png');
}
@media (hover: hover) and (pointer: fine) {
  .hero-lockup:hover::after, .foot-lockup:hover::after,
  .brand:hover .mark-frame::after {
    animation: wc-sheen 1.2s var(--ease-soft) 1;
  }
}
.brand:focus-visible .mark-frame::after {
  animation: wc-sheen 1.2s var(--ease-soft) 1;
}
@keyframes wc-sheen {
  from { opacity: 0; background-position: -110% 0; }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  to   { opacity: 0; background-position: 210% 0; }
}

/* ---------- the header mark: lifts a hair and takes the sheen ----------- */
.mark-frame { display: inline-flex; }
.mark-frame img { position: relative; z-index: 0; transition: transform var(--m-med) var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .brand:hover .mark-frame img { transform: translateY(-2px); }
}
.brand:focus-visible .mark-frame img { transform: translateY(-2px); }

/* ==========================================================================
   2. A HOVER SYSTEM, APPLIED EVERYWHERE
   ========================================================================== */

/* ---------- buttons -------------------------------------------------------
   Ghost (.btn-line) fills with a wipe from the left; solid buttons (.btn-teal,
   .btn-bone) already deepen in colour (site.css) and gain a lift + shadow
   here. Every button gets the lift/shadow; .btn-line additionally gets the
   fill. A plain :active rule gives touch a press-down instead of a stuck
   hover. */
.btn {
  position: relative;
  isolation: isolate;
  transition: transform var(--m-fast) var(--ease-out), box-shadow var(--m-fast) var(--ease-out),
    background-color var(--m-med) var(--ease-out), color var(--m-med) var(--ease-out),
    border-color var(--m-fast) var(--ease-out);
}
.btn-line { overflow: hidden; }
.btn-line::before {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background: var(--teal-deep);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--m-med) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover { transform: translateY(-2px); }
  .btn-teal:hover, .btn-bone:hover { box-shadow: 0 16px 30px -16px rgba(0, 48, 63, .4); }
  .btn-line:hover::before { transform: scaleX(1); }
  .btn-line:hover { color: var(--bone); border-color: var(--teal-deep); box-shadow: 0 16px 30px -18px rgba(0, 96, 128, .4); }
}
.btn:focus-visible { transform: translateY(-2px); }
.btn-teal:focus-visible, .btn-bone:focus-visible { box-shadow: 0 16px 30px -16px rgba(0, 48, 63, .4); }
.btn-line:focus-visible::before { transform: scaleX(1); }
.btn-line:focus-visible { color: var(--bone); border-color: var(--teal-deep); }
.btn:active { transform: translateY(0) scale(.98); }

/* ---------- text links: two primitives, not one -------------------------
   build-06 fix pass: the original single rule silenced every listed link's
   border-bottom and only drew the ::after bar at scaleX(1) on hover/focus —
   fine for links that had NO resting line before (.nav a, .foot-nav a,
   .foot-social a all carried `border-bottom: 1px solid transparent` at
   rest already), but a real regression everywhere else: in-copy links like
   the footer's five service-area names lost their only resting distinction
   from the sentence around them (WCAG 1.4.1). Group A keeps a visible
   resting bar (scaleX(1), dim) and strengthens it on hover; Group B is the
   only place a from-nothing grow is honest. */

/* Group A — HAD a resting border-bottom (or reads as prose and needs one):
   keep a dim, visible bar at rest; hover/focus brightens it. */
.tlink, .foot-store address a, .foot-areas-line a, #visit a, .slot-block a,
.signoff-cols a, .drop a.drop-tel, .scard-cap address a, .door-panel address a,
.gloss-close a, .gate-out a, .foot-legal a, .drawer-lede a, .t-note a,
.notice-in a, .idx-note a, .fmtb-note a {
  position: relative;
  border-bottom-color: transparent !important;
}
.tlink::after, .foot-store address a::after, .foot-areas-line a::after, #visit a::after,
.slot-block a::after, .signoff-cols a::after, .drop a.drop-tel::after,
.scard-cap address a::after, .door-panel address a::after, .gloss-close a::after,
.gate-out a::after, .foot-legal a::after, .drawer-lede a::after, .t-note a::after,
.notice-in a::after, .idx-note a::after, .fmtb-note a::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: var(--cedar);
  transform: scaleX(1);
  opacity: .45;
  transition: opacity var(--m-med) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .tlink:hover::after, .foot-store address a:hover::after, .foot-areas-line a:hover::after,
  #visit a:hover::after, .slot-block a:hover::after, .signoff-cols a:hover::after,
  .drop a.drop-tel:hover::after, .scard-cap address a:hover::after, .door-panel address a:hover::after,
  .gloss-close a:hover::after, .gate-out a:hover::after, .foot-legal a:hover::after,
  .drawer-lede a:hover::after, .t-note a:hover::after, .notice-in a:hover::after,
  .idx-note a:hover::after, .fmtb-note a:hover::after { opacity: 1; }
}
.tlink:focus-visible::after, .foot-store address a:focus-visible::after,
.foot-areas-line a:focus-visible::after, #visit a:focus-visible::after,
.slot-block a:focus-visible::after, .signoff-cols a:focus-visible::after,
.drop a.drop-tel:focus-visible::after, .scard-cap address a:focus-visible::after,
.door-panel address a:focus-visible::after, .gloss-close a:focus-visible::after,
.gate-out a:focus-visible::after, .foot-legal a:focus-visible::after,
.drawer-lede a:focus-visible::after, .t-note a:focus-visible::after,
.notice-in a:focus-visible::after, .idx-note a:focus-visible::after,
.fmtb-note a:focus-visible::after { opacity: 1; }

/* Group B — HAD `border-bottom: 1px solid transparent` at rest already
   (.nav a, .foot-nav a, .foot-social a): the grow-from-the-left animation
   is a genuine improvement here, not a regression, so it keeps the original
   scaleX(0) -> scaleX(1) treatment. */
.nav a, .foot-nav a, .foot-social a {
  position: relative;
  border-bottom-color: transparent !important;
}
.nav a::after, .foot-nav a::after, .foot-social a::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: var(--cedar);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--m-med) var(--ease-out);
}
.nav a::after { bottom: 2px; }
@media (hover: hover) and (pointer: fine) {
  .nav a:hover::after, .foot-nav a:hover::after, .foot-social a:hover::after { transform: scaleX(1); }
}
.nav a:focus-visible::after, .foot-nav a:focus-visible::after, .foot-social a:focus-visible::after { transform: scaleX(1); }

/* nav-drop trigger and store-chip already animate their chevron on open
   (site.css); give the chip's own chevron the same rotation for consistency */
.store-chip .chev { display: inline-block; transition: transform var(--m-fast) var(--ease-out); }
.store-chip[aria-expanded="true"] .chev { transform: rotate(180deg); }

/* ---------- cards: lift + a leading hairline + the photo breathing -------
   .pc, .fmt and .scard already lift and scale their photo under a real
   pointer (site.css, scoped to (pointer:fine)); what they were missing is a
   keyboard-focus equivalent, added here unconditionally. .faq-item, .tlex-row
   (the glossary ledger) and .tl-stop (the timeline cards) had no card
   treatment at all — they get the full system: lift, a teal hairline that
   appears on the leading (left) edge, and, where they hold a photo, the
   same ~1.04 scale inside an unmoved frame. */
.pc:focus-within { transform: translateY(-4px); box-shadow: 0 22px 34px -26px rgba(0, 48, 63, .55); }
.pc:focus-within .pc-shot img { transform: scale(1.045); }
.fmt:focus-within { transform: translateY(-4px); box-shadow: 0 22px 34px -26px rgba(0, 48, 63, .45); }
.fmt:focus-within .fmt-collage { transform: scale(1.04); }
.scard:focus-within { transform: translateY(-4px); border-color: var(--acc); box-shadow: 0 26px 44px -30px rgba(0, 48, 63, .5); }
.scard:focus-within .scard-frame img { transform: scale(1.04); }
.scard:focus-within .scard-cap::after { transform: scaleX(1); }

.faq-item, .tlex-row, .tl-stop {
  position: relative;
  transition: transform var(--m-med) var(--ease-out);
}
.faq-item, .tlex-row { padding-left: 16px; }
.faq-item::before, .tlex-row::before, .tl-stop::before {
  content: '';
  position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  background: var(--teal);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--m-med) var(--ease-out);
}
.sec-teal-deep .tlex-row::before { background: var(--cedar); }
.tl-stop::before { left: -3px; }
.tl-stop .tl-shot { overflow: hidden; }
.tl-stop .tl-shot img { transition: transform var(--m-slow) var(--ease-soft); }
@media (hover: hover) and (pointer: fine) {
  .faq-item:hover, .tlex-row:hover, .tl-stop:hover { transform: translateY(-2px); }
  .faq-item:hover::before, .tlex-row:hover::before, .tl-stop:hover::before { transform: scaleY(1); }
  .tl-stop:hover .tl-shot img { transform: scale(1.04); }
}
.faq-item:focus-within, .tlex-row:focus-within, .tl-stop:focus-within { transform: translateY(-2px); }
.faq-item:focus-within::before, .tlex-row:focus-within::before, .tl-stop:focus-within::before { transform: scaleY(1); }
.tl-stop:focus-within .tl-shot img { transform: scale(1.04); }
@media (max-width: 760px) {
  .faq-item, .tlex-row { padding-left: 0; }
  .faq-item::before, .tlex-row::before { display: none; }
}
.pc:active, .fmt:active, .scard:active, .cat-tile:active { transform: scale(.985); }

/* ---------- arrows / chevrons: travel in the direction they point -------- */
.shelf-arrow { overflow: hidden; }
.shelf-arrow span { display: inline-block; transition: transform var(--m-fast) var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .shelf-arrow[data-shelf-prev]:hover span, .shelf-arrow[data-tl="prev"]:hover span { transform: translateX(-3px); }
  .shelf-arrow[data-shelf-next]:hover span, .shelf-arrow[data-tl="next"]:hover span { transform: translateX(3px); }
}
.shelf-arrow[data-shelf-prev]:focus-visible span, .shelf-arrow[data-tl="prev"]:focus-visible span { transform: translateX(-3px); }
.shelf-arrow[data-shelf-next]:focus-visible span, .shelf-arrow[data-tl="next"]:focus-visible span { transform: translateX(3px); }

/* ==========================================================================
   3. SECTION-LEVEL MOTION
   ========================================================================== */

/* ---------- the store switch: a sliding pill, pure CSS -------------------
   Exactly two radios, so :has() alone can place the pill without any script
   — it reacts to the aria-checked state js/site.js already writes. Browsers
   without :has() simply keep the existing solid-colour toggle (site.css),
   which is still fully correct on its own. */
.switch { position: relative; isolation: isolate; }
.switch::before {
  content: '';
  /* 16 Sep — this sliding pill is what actually fills behind the chosen
     option, and it was still using the old geometry: a 1px inset and a 1px
     radius from when the track had no padding and square corners. Against the
     4px-padded pill track it sat flush to the left edge with a square right
     edge, which is the "buttons are not being filled in appropriately" Ajay
     saw. It now matches the option it sits under: inset by the track's
     padding, one option wide, and fully rounded. */
  position: absolute; top: 4px; bottom: 4px; left: 4px;
  width: calc(50% - 6px);
  background: var(--teal);
  z-index: -1;
  border-radius: var(--pill);
  transition: transform var(--m-med) var(--ease-out);
}
@supports selector(:has(a)) {
  /* travel = one option's width plus the gap between them */
  .switch:has(button:nth-child(2)[aria-checked="true"])::before { transform: translateX(calc(100% + 4px)); }
  .switch button[aria-checked="true"] { background: transparent; }
  /* #hero's switch sits over a photograph and carries its own higher-
     specificity light/dark treatment (site.css); match its specificity here
     so the pill takes over there too, with bone text against the teal pill. */
  #hero .switch button[aria-checked="true"] { background: transparent; color: var(--bone); }
}

/* ---------- hero: parallax split (site.js/motion.js drives the transform;
   this only declares the two layers do not share one transform target) --- */
#hero .hero-copy, #order-hero .hero-copy { will-change: transform; }

/* ---------- delivery: hovering a label lifts its own mark on the map -----
   The municipality group (label + leader + dot) lifts a couple of px as one
   unit — the reading already given to it by mapFocus() in js/site.js, now
   with a visible motion instead of only a colour change. transform-box makes
   an SVG <g> (which has no natural border-box) transform round its own
   content instead of the whole viewBox's origin. */
.muni { transform-box: fill-box; transform-origin: center; transition: transform var(--m-med) var(--ease-out); }
.wc-map .muni.is-on, .wc-map .muni:hover, .wc-map .muni:focus-visible { transform: translateY(-3px); }
.store-mark { transform-box: fill-box; transform-origin: center; transition: transform var(--m-med) var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .store-mark:hover { transform: translateY(-3px); }
}

/* ---------- "Curated / Knowledgeable / Culture": the rule draws across ---
   The static border-top is replaced by a full-width bar that is visible by
   default (so nothing here depends on JS to be correct) and is drawn from
   nothing by motion.js's whyRise() only when GSAP + motion are available. */
.why-line { position: relative; border-top: 0; padding-top: 19px; }
.why-rule {
  position: absolute; top: 0; left: 0; width: 100%; height: 1px;
  background: rgba(184, 134, 91, .5);
  transform-origin: left;
}

/* ---------- the sign-up form: the submit button "fills" while sending ---- */
@keyframes wc-sending {
  0% { box-shadow: inset 220px 0 0 0 rgba(244, 239, 228, 0); }
  100% { box-shadow: inset 0 0 0 0 rgba(244, 239, 228, .16); }
}
#list-form button[disabled], #contact-form button[disabled] { animation: wc-sending 1.1s var(--ease-soft) infinite alternate; }
.form-msg { opacity: 0; transform: translateY(6px); transition: opacity var(--m-slow) var(--ease-out), transform var(--m-slow) var(--ease-out); }
.form-msg.is-in { opacity: 1; transform: none; }
#list-form.is-leaving, #contact-form.is-leaving { opacity: 0; transition: opacity var(--m-med) var(--ease-out); }

/* ---------- the sticky dock: a one-time pulse, and a softer drawer scrim - */
@keyframes wc-dock-pulse {
  0%, 100% { box-shadow: 0 10px 26px rgba(0, 48, 63, .26), 0 0 0 0 rgba(0, 96, 128, .5); }
  50% { box-shadow: 0 10px 26px rgba(0, 48, 63, .26), 0 0 0 10px rgba(0, 96, 128, 0); }
}
.findbtn.wc-pulse { animation: wc-dock-pulse 1.4s var(--ease-soft) 2; }
.drawer-scrim { transition: backdrop-filter var(--m-med) var(--ease-out), background-color var(--m-med) var(--ease-out); }
.drawer.is-open .drawer-scrim { backdrop-filter: blur(3px) saturate(1.05); -webkit-backdrop-filter: blur(3px) saturate(1.05); }

/* the tab underline slides between the three drawer tabs, :has()-driven */
.drawer-tabs { position: relative; }
.drawer-tabs::after {
  content: '';
  position: absolute; left: 0; bottom: -1px; width: calc(100% / 3); height: 2px;
  background: var(--teal);
  transition: transform var(--m-med) var(--ease-out);
}
@supports selector(:has(a)) {
  .drawer-tabs:has(.drawer-tab:nth-child(2).is-on)::after { transform: translateX(100%); }
  .drawer-tabs:has(.drawer-tab:nth-child(3).is-on)::after { transform: translateX(200%); }
}

/* results in the drawer's three tools fade in in sequence, not all at once —
   a plain CSS animation plays automatically the moment tools.js inserts each
   element, so nothing here needed an edit to tools.js */
@keyframes wc-pop-in { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
.finder-res > *, .cmp-heads, .cmp-row, .cmp-go, #wcw-answer > * {
  animation: wc-pop-in .38s var(--ease-out) both;
}
.finder-res > *:nth-child(1) { animation-delay: 0ms; }
.finder-res > *:nth-child(2) { animation-delay: 45ms; }
.finder-res > *:nth-child(3) { animation-delay: 90ms; }
.finder-res > *:nth-child(4) { animation-delay: 135ms; }
.finder-res > *:nth-child(5) { animation-delay: 180ms; }
.finder-res > *:nth-child(6) { animation-delay: 225ms; }
.cmp-heads { animation-delay: 0ms; }
.cmp-row:nth-child(2) { animation-delay: 40ms; }
.cmp-row:nth-child(3) { animation-delay: 80ms; }
.cmp-row:nth-child(4) { animation-delay: 120ms; }
.cmp-row:nth-child(5) { animation-delay: 160ms; }
.cmp-row:nth-child(6) { animation-delay: 200ms; }
.cmp-row:nth-child(7) { animation-delay: 240ms; }
.cmp-go { animation-delay: 280ms; }
#wcw-answer > *:nth-child(1) { animation-delay: 0ms; }
#wcw-answer > *:nth-child(2) { animation-delay: 45ms; }
#wcw-answer > *:nth-child(3) { animation-delay: 90ms; }
#wcw-answer > *:nth-child(4) { animation-delay: 135ms; }
#wcw-answer > *:nth-child(5) { animation-delay: 180ms; }

/* ---------- footer: the columns rise once on first reveal (motion.js) ----
   Default state is fully visible (safe with no JS); motion.js only ever
   pre-hides an element with an inline style immediately before animating it
   in, guarded by the same reduced-motion check as everything else. */

/* ==========================================================================
   4. PAGE-TO-PAGE CROSS-FADE — REMOVED (BUILD-07 fix, 15 Sep 2026)
   `@view-transition { navigation: auto; }` used to cross-fade every
   same-origin navigation wherever Chromium implements it. The ROBUST review
   found, and reproduced in both headless and headed real Chrome, that while
   the browser's native cross-document transition is settling after a
   navigation, the NEW document's IntersectionObservers stop delivering
   callbacks — not just for the homepage's own store switch (?store=…
   reload), but for a plain click from any page to any other page. On the
   carousels that meant dutchieCarousels() constructed its observer and
   called observe() correctly, but the callback never fired within 32
   seconds, so load() was never called and four fully-reserved 485px panels
   sat empty forever — worse than a network block, because it never even
   reached the 8-second collapse logic. Stripping this one at-rule fixed it
   immediately in testing. The visual cross-fade was a nice-to-have; a
   silently broken lazy-load on every internal link is not an acceptable
   trade for it. If this is ever reinstated, it needs a per-navigation
   opt-out (skipping it during pageswap/pagereveal for store-switch and any
   navigation into a page with third-party lazy-loaded embeds) rather than
   the blanket `navigation: auto`, and js/site.js's own 2-second "still not
   loading" fallback (dutchieCarousels()) should stay regardless as
   insurance against the same class of bug.
   ========================================================================== */

/* ==========================================================================
   TOUCH: nothing above should ever leave a hover state stuck. Every effect
   that is not purely a colour/underline change is scoped to
   (hover:hover) and (pointer:fine); phones and tablets get the plain
   :active rules instead, which release the instant the finger lifts.
   ========================================================================== */
@media (hover: none) {
  .hero-lockup::after, .foot-lockup::after, .mark-frame::after { display: none; }
}
