/* ==========================================================================
   Aisle — motion layer
   Drop-in. Loads after style.css. Overrides nothing; adds only new tokens
   (all prefixed --m-) and new classes (all prefixed .m-).
   Pairs with motion.js.
   ========================================================================== */

:root {
  /* Durations. Presses are near-instant; arrivals are allowed to settle. */
  --m-dur-press: 90ms;
  --m-dur-quick: 160ms;
  --m-dur-base: 280ms;
  --m-dur-settle: 460ms;

  /* Easings. Long decelerating tail = things arrive and come to rest,
     rather than snapping into place. No overshoot/bounce anywhere. */
  --m-ease-settle: cubic-bezier(0.22, 1, 0.36, 1);
  --m-ease-exit: cubic-bezier(0.4, 0, 1, 1);
  --m-ease-inout: cubic-bezier(0.65, 0, 0.35, 1);

  /* How far content travels on arrival. Deliberately small. */
  --m-shift: 8px;

  /* Sticky-header allowance for in-page anchor scrolling. */
  --m-scroll-offset: 5.5rem;

  /* Falls back to brand gold if style.css doesn't expose these names. */
  --m-accent: var(--gold, var(--color-gold, #ad8a4e));
  --m-accent-deep: var(--burgundy, var(--color-burgundy, #7d2a35));
}

/* --------------------------------------------------------------------------
   1. Page transitions — native cross-document view transitions
   Chrome/Edge 126+, Safari 18.2+. The browser snapshots the outgoing page,
   renders the incoming one, and animates between them on the compositor.
   Header and footer are given their own names in motion.js so they stay
   put instead of blinking — that single detail is most of the "app, not
   website" feeling.
   -------------------------------------------------------------------------- */

@view-transition {
  navigation: auto;
}

::view-transition-old(m-main) {
  animation: m-leave var(--m-dur-quick) var(--m-ease-exit) both;
}

::view-transition-new(m-main) {
  animation: m-arrive var(--m-dur-settle) var(--m-ease-settle) both;
}

/* Chrome and footer: hold steady, no cross-fade flicker. */
::view-transition-old(m-header),
::view-transition-new(m-header),
::view-transition-old(m-footer),
::view-transition-new(m-footer) {
  animation: none;
  mix-blend-mode: normal;
}

/* Whole-page fallback for documents with no <main>. */
::view-transition-old(root) {
  animation: m-leave var(--m-dur-quick) var(--m-ease-exit) both;
}

::view-transition-new(root) {
  animation: m-arrive var(--m-dur-settle) var(--m-ease-settle) both;
}

@keyframes m-arrive {
  from {
    opacity: 0;
    transform: translateY(var(--m-shift));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes m-leave {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(calc(var(--m-shift) * -0.5));
  }
}

/* The clicked card and the destination's heading share a name, so the
   browser interpolates position and size between them instead of
   cross-fading the whole screen. motion.js assigns the names. */
::view-transition-group(m-hero) {
  animation-duration: var(--m-dur-settle);
  animation-timing-function: var(--m-ease-settle);
}

::view-transition-old(m-hero),
::view-transition-new(m-hero) {
  animation-duration: var(--m-dur-settle);
  animation-timing-function: var(--m-ease-settle);
}

/* Going back should feel like going back: the content settles downward
   rather than rising, mirroring the forward direction. */
.m-nav-back::view-transition-new(m-main),
.m-nav-back::view-transition-new(root) {
  animation-name: m-arrive-back;
}

.m-nav-back::view-transition-old(m-main),
.m-nav-back::view-transition-old(root) {
  animation-name: m-leave-back;
}

@keyframes m-arrive-back {
  from {
    opacity: 0;
    transform: translateY(calc(var(--m-shift) * -1));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes m-leave-back {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(calc(var(--m-shift) * 0.5));
  }
}

/* --------------------------------------------------------------------------
   2. Page transitions — fallback for browsers without view transitions
   (Firefox today). motion.js adds .m-no-vt to <html>, then .m-leaving on
   click and removes it on arrival. Visually near-identical.
   -------------------------------------------------------------------------- */

.m-no-vt main {
  animation: m-arrive var(--m-dur-settle) var(--m-ease-settle) both;
}

.m-no-vt.m-leaving main {
  animation: m-leave var(--m-dur-quick) var(--m-ease-exit) both;
}

/* --------------------------------------------------------------------------
   3. Navigation progress thread
   A 2px gold hairline across the top during the server round-trip. Only
   shown once a navigation has taken longer than a beat, so fast pages
   never flash it. This is the part that removes the "did my click land?"
   dead air on mobile networks.
   -------------------------------------------------------------------------- */

.m-progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 9999;
  width: 100%;
  height: 2px;
  background: linear-gradient(
    90deg,
    var(--m-accent-deep),
    var(--m-accent) 60%,
    var(--m-accent)
  );
  transform: scaleX(0);
  transform-origin: left center;
  opacity: 0;
  pointer-events: none;
  transition:
    transform 600ms var(--m-ease-settle),
    opacity var(--m-dur-quick) linear;
}

[dir="rtl"] .m-progress {
  transform-origin: right center;
}

.m-progress.m-progress-on {
  opacity: 1;
}

.m-progress.m-progress-done {
  transform: scaleX(1);
  opacity: 0;
  transition:
    transform 140ms var(--m-ease-exit),
    opacity 240ms 100ms linear;
}

/* --------------------------------------------------------------------------
   4. Press feedback
   Every clickable surface acknowledges the press within one frame.
   Transform-only, so it never triggers layout.
   -------------------------------------------------------------------------- */

button,
.btn,
a.primary,
a.button,
[role="button"],
input[type="submit"],
input[type="button"] {
  transition:
    transform var(--m-dur-press) var(--m-ease-exit),
    box-shadow var(--m-dur-base) var(--m-ease-settle),
    background-color var(--m-dur-base) var(--m-ease-settle),
    color var(--m-dur-base) var(--m-ease-settle);
  -webkit-tap-highlight-color: transparent;
}

button:active,
.btn:active,
a.primary:active,
a.button:active,
[role="button"]:active,
input[type="submit"]:active,
input[type="button"]:active {
  transform: scale(0.972);
}

/* Cards and tiles that are themselves links or contain a primary action:
   a lighter press, since they're large. */
.card:active,
.category-tile:active,
.quote-row:active {
  transform: scale(0.995);
  transition: transform var(--m-dur-press) var(--m-ease-exit);
}

/* Inputs settle into focus rather than jumping. */
input,
select,
textarea {
  transition:
    border-color var(--m-dur-base) var(--m-ease-settle),
    box-shadow var(--m-dur-base) var(--m-ease-settle),
    background-color var(--m-dur-base) var(--m-ease-settle);
}

/* Keyboard focus stays obvious — accessibility floor, not decoration. */
:focus-visible {
  outline: 2px solid var(--m-accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --------------------------------------------------------------------------
   5. Busy state on submit
   Server-rendered POSTs take a round-trip. The button says so, and the
   form can't be double-submitted. The button is NOT disabled, so its
   name/value still posts (matters for accept/decline style actions).
   -------------------------------------------------------------------------- */

.m-busy {
  position: relative;
  pointer-events: none;
  color: transparent !important;
}

.m-busy::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  width: 1em;
  height: 1em;
  margin-block-start: -0.5em;
  margin-inline-start: -0.5em;
  border: 2px solid currentColor;
  border-block-start-color: transparent;
  border-radius: 50%;
  color: var(--m-busy-ink, #fff);
  animation: m-spin 620ms linear infinite;
}

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

/* --------------------------------------------------------------------------
   6. Photos fade in instead of popping in
   Applied only to images that hadn't finished loading, so cached pages
   and back-navigation stay instant.
   -------------------------------------------------------------------------- */

img.m-img {
  opacity: 0;
  transition: opacity var(--m-dur-base) var(--m-ease-settle);
}

img.m-img-in {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   7. Panels that open — menus, dropdowns, dialogs, lightbox
   allow-discrete + @starting-style animate elements that are toggled with
   display:none / [hidden], which plain transitions can't touch. Selectors
   are deliberately broad; any that don't exist in the markup are inert.
   -------------------------------------------------------------------------- */

[data-motion="panel"],
[popover],
dialog,
.dropdown-menu,
.dropdown-panel,
.account-menu,
.menu-panel,
.mobile-menu,
.nav-panel,
.lightbox {
  transition:
    opacity var(--m-dur-base) var(--m-ease-settle),
    transform var(--m-dur-base) var(--m-ease-settle),
    overlay var(--m-dur-base) allow-discrete,
    display var(--m-dur-base) allow-discrete;
}

[data-motion="panel"]:not([hidden]),
[popover]:popover-open,
dialog[open],
.dropdown-menu.open,
.dropdown-menu.is-open,
.dropdown-panel.open,
.account-menu.open,
.menu-panel.open,
.mobile-menu.open,
.nav-panel.open,
.lightbox.open {
  opacity: 1;
  transform: translateY(0) scale(1);
}

@starting-style {
  [data-motion="panel"]:not([hidden]),
  [popover]:popover-open,
  dialog[open],
  .dropdown-menu.open,
  .dropdown-menu.is-open,
  .dropdown-panel.open,
  .account-menu.open,
  .menu-panel.open,
  .mobile-menu.open,
  .nav-panel.open,
  .lightbox.open {
    opacity: 0;
    transform: translateY(-6px) scale(0.985);
  }
}

/* --------------------------------------------------------------------------
   8. Anchor scrolling that clears the sticky header
   -------------------------------------------------------------------------- */

html {
  scroll-behavior: smooth;
  scroll-padding-block-start: var(--m-scroll-offset);
}

/* --------------------------------------------------------------------------
   9. Reduced motion — a real kill switch, not a token gesture
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }

  html {
    scroll-behavior: auto;
  }

  .m-no-vt main,
  .m-no-vt.m-leaving main,
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }

  button:active,
  .btn:active,
  a.primary:active,
  a.button:active,
  [role="button"]:active,
  .card:active,
  .category-tile:active,
  .quote-row:active {
    transform: none;
  }

  .m-progress {
    transition: opacity var(--m-dur-quick) linear;
  }

  img.m-img {
    opacity: 1;
  }
}
/* probe line 1 */
/* probe line 2 */
