/* ====== MOTION AND JAPANESE LAYER (2026-10-13) ======
   One motion system for every page: shared timing tokens and one tide rhythm, noren page
   transitions, hanko stamps, brush rules (element A) and seigaiha wave edges (element B).
   Decorative only. Pause, a background tab and reduced motion stop all of it; without
   JavaScript everything rests in its final state. No new Japanese text. */

/* ---- Motion tokens ---- */
:root {
  --ease-ink: cubic-bezier(.22, 1, .36, 1);
  --ease-stamp: cubic-bezier(.3, 1.5, .45, 1);
  --dur-quick: .18s;
  --dur-base: .5s;
  --dur-slow: .9s;
  --tide: 6s;
  --stagger: 70ms;
  --vt-dur: .62s;
  --crest: 22px;
  --brush-on-blue: var(--peach);
}

/* ---- One tide: the existing loops share one period instead of nine ---- */
.motion-ready .noren--shop .noren__panel { animation-duration: var(--tide); }

.motion-ready .shop__wide.is-seen .cat__paw { animation-duration: calc(var(--tide) / 4); }
.motion-ready .fish-lane .fish__tail { animation-duration: calc(var(--tide) / 6); }
.motion-ready .fish-lane .swimmer--two .fish__tail { animation-duration: calc(var(--tide) / 8); }

/* ---- Fish swim on the compositor (transform) instead of re-laying out the page (left).
   Same path as before: the keyframes offset each fish by its resting left position. ---- */
.fish-lane { container-type: inline-size; }
.swimmer { will-change: transform; animation-name: tide-swim; animation-duration: calc(var(--tide) * 3); }
.swimmer--two { animation-name: tide-swim-back; animation-duration: calc(var(--tide) * 4); }
@keyframes tide-swim {
  0% { transform: translateX(-33cqw) translateY(0) rotate(-3deg); }
  25% { transform: translateX(-1cqw) translateY(12px) rotate(3deg); }
  50% { transform: translateX(31cqw) translateY(-8px) rotate(-3deg); }
  75% { transform: translateX(63cqw) translateY(10px) rotate(3deg); }
  100% { transform: translateX(95cqw) translateY(0) rotate(-3deg); }
}
@keyframes tide-swim-back {
  0% { transform: translateX(45cqw) scaleX(-1) translateY(0); }
  50% { transform: translateX(-19cqw) scaleX(-1) translateY(-14px); }
  100% { transform: translateX(-83cqw) scaleX(-1) translateY(0); }
}

/* ---- Consolidation: the string lights hold a steady glow ---- */

/* ---- Rest when off screen or in a background tab ---- */
.ml-off, .ml-off *, .motion-hidden *, .motion-hidden *::before, .motion-hidden *::after { animation-play-state: paused !important; }

/* ---- Arrivals: side by side things land one after another ---- */
.js-reveal .reveal { transition-delay: calc(var(--ml-n, 0) * 40ms); }
/* Cards, tiles and board rows carry text, so they rise without fading (AA from the first frame);
   photo-only prints still fade as they rise */
.ml-on:not(.motion-paused) .ml-rise:not(.is-up) { translate: 0 1.4rem; }
.ml-on:not(.motion-paused) .menu-hero__tray > span.ml-rise:not(.is-up) { opacity: 0; }
.ml-on:not(.motion-paused) .ml-rise.is-up { animation: ml-rise var(--dur-slow) var(--ease-ink) both; animation-delay: calc(var(--ml-n, 0) * var(--stagger)); }
.ml-on:not(.motion-paused) .menu-hero__tray > span.ml-rise.is-up { animation-name: ml-rise-fade; }
@keyframes ml-rise { from { translate: 0 1.4rem; } to { translate: 0 0; } }
@keyframes ml-rise-fade { from { opacity: 0; translate: 0 1.4rem; } to { opacity: 1; translate: 0 0; } }
/* Item pages arrive with the dish photo and stamp, so their blocks are not faded */
.js-reveal .item-page .item .reveal { opacity: 1; transform: none; }

/* ---- Brush rule (element A): one stroke under each page heading, painted left to right ---- */
.brush-rule { display: block; width: clamp(7rem, 14vw, 11rem); margin: .25rem 0 1.25rem; color: var(--orange); }
.brush-rule svg { display: block; width: 100%; height: auto; overflow: visible; }
.visit--page .brush-rule { color: var(--brush-on-blue); }
.display--xl + .brush-rule { margin-top: .9rem; }
.ml-on:not(.motion-paused) .brush-rule.ml-watch:not(.is-up) svg { clip-path: inset(0 100% 0 0); }
.ml-on:not(.motion-paused) .brush-rule.is-up svg { animation: ml-brush .85s var(--ease-ink) .18s both; }
@keyframes ml-brush { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
/* First-visit path: on phones the stroke paints downward; on wide screens step 2's stroke follows step 1's */
.ml-on:not(.motion-paused) .step__path.ml-watch:not(.is-up) .step__path-v { clip-path: inset(0 0 100% 0); }
.ml-on:not(.motion-paused) .step__path.is-up .step__path-v { animation-name: ml-brush-down; }
@keyframes ml-brush-down { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@media (min-width: 64rem) { .ml-on:not(.motion-paused) .step:nth-child(2) .step__path.is-up svg { animation-delay: 1s; } }

/* ---- Hanko stamps: seals press in once, with a small rebound like ink on paper ---- */
@keyframes ml-stamp { 0% { opacity: 0; scale: 1.7; } 55% { opacity: 1; scale: .92; } 78% { scale: 1.04; } 100% { opacity: 1; scale: 1; } }
/* 2026-10-24: the section seals (tate) and the menu chips rest, so the number board is the one moment on the menu */
/* Homepage menu tiles: the seal presses again when you point at a tile */
.motion-ready:not(.motion-paused) .home .tile:hover .tile__kanji,
.motion-ready:not(.motion-paused) .home .tile:focus-visible .tile__kanji { animation: ml-stamp .45s var(--ease-stamp); }
/* Order sheet: Jay's seal stamps the card as it opens, a quiet confirmation */
.hanko--sheet { position: absolute; top: -1.55rem; right: 4.25rem; z-index: 1; margin: 0; rotate: -8deg; background: var(--ivory); }
.motion-ready:not(.motion-paused) .order-sheet[open] .hanko--sheet { animation: ml-stamp .5s var(--ease-stamp) .24s both; }

/* ---- Menu noren: the curtain panels drop onto the rod one by one ---- */
/* The panels are links: they drop a little onto the rod without fading */
@keyframes ml-hang { from { translate: 0 -.6rem; } to { translate: 0 0; } }
.ml-on:not(.motion-paused) .noren--menu.ml-watch:not(.is-up) .noren__panel { translate: 0 -.6rem; }
.ml-on:not(.motion-paused) .noren--menu.is-up .noren__panel { animation: ml-hang .7s var(--ease-stamp) both; }
.ml-on:not(.motion-paused) .noren--menu.is-up .noren__panel:nth-child(2) { animation-delay: .08s; }
.ml-on:not(.motion-paused) .noren--menu.is-up .noren__panel:nth-child(3) { animation-delay: .16s; }
.ml-on:not(.motion-paused) .noren--menu.is-up .noren__panel:nth-child(4) { animation-delay: .24s; }

/* ---- Seigaiha wave edge (element B): the ivory page meets the blue as a row of crests ---- */
.wave-edge { position: absolute; inset: 0 0 auto; z-index: 1; height: var(--crest); overflow: hidden; pointer-events: none; }
.wave-edge span {
  display: block; width: calc(100% + var(--crest) * 4); height: 100%; transform-origin: 50% 100%;
  background: radial-gradient(circle at 50% 100%,
    var(--blue) 0 calc(var(--crest) * .32), var(--ivory) calc(var(--crest) * .32 + .5px) calc(var(--crest) * .4),
    var(--blue) calc(var(--crest) * .4 + .5px) calc(var(--crest) * .64), var(--ivory) calc(var(--crest) * .64 + .5px) calc(var(--crest) * .72),
    var(--blue) calc(var(--crest) * .72 + .5px) calc(var(--crest) - .5px), var(--ivory) var(--crest)) 0 100% / calc(var(--crest) * 2) var(--crest) repeat-x;
  transition: scale var(--dur-slow) var(--ease-ink);
}
.ml-on:not(.motion-paused) .wave-edge.ml-watch:not(.is-up) span { scale: 1 0; }
.motion-ready .wave-edge span { animation: ml-drift calc(var(--tide) * 2) linear infinite; }
.motion-paused .wave-edge span { animation-play-state: paused; }
@keyframes ml-drift { to { translate: calc(var(--crest) * -2) 0; } }

/* ---- Micro interactions: sticky actions and menu cards answer a press ---- */
.bar__item { transition: scale var(--dur-quick) var(--ease-ink); }
.bar__item:active { scale: .96; }
.menu-cat .card:active .card__media { scale: .985; }

/* ---- Menu hero tray: the wide hero's empty half holds the round tray (ringed like an enso)
   and two taped prints, all supplied shop photos. Wide screens only; phones go straight to food. ---- */
.menu-hero__tray { display: none; }
@media (min-width: 64rem) {
  .menu-hero__grid { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(2rem, 5vw, 5rem); align-items: center; }
  .menu-hero__tray { display: block; position: relative; width: min(100%, 30rem); aspect-ratio: 1; justify-self: end; pointer-events: none; }
  .tray__round { position: absolute; inset: 7%; border-radius: 50%; overflow: hidden; box-shadow: var(--shadow); outline: 1.5px solid var(--orange); outline-offset: .7rem; }
  .tray__round picture, .tray__round img { display: block; width: 100%; height: 100%; object-fit: cover; }
  .tray__print { position: absolute; width: 40%; background: var(--white); padding: var(--print-pad) var(--print-pad) calc(var(--print-pad) * 3); box-shadow: var(--shadow); }
  .tray__print img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; }
  .tray__print::before { content: ""; position: absolute; top: -.6rem; left: 32%; width: 4.5rem; height: 1.3rem; background: var(--tape); rotate: -8deg; }
  .tray__print--rolls { left: -6%; bottom: 0; rotate: -6deg; }
  .tray__print--bento { right: 0; top: -2%; width: 36%; rotate: 5deg; }
  .tray__print--bento img { aspect-ratio: 4 / 3; }
}

/* ---- Page transitions: the next page appears through the parting noren ---- */
@view-transition { navigation: auto; }
.masthead { view-transition-name: masthead; }
.bar { view-transition-name: action-bar; }
.item-page .item__media img { view-transition-name: dish; }
::view-transition-group(dish) { animation-duration: var(--vt-dur); animation-timing-function: var(--ease-ink); }
::view-transition-old(root) { animation: ml-page-out var(--vt-dur) var(--ease-ink) both; }
::view-transition-new(root) { animation: ml-noren-open var(--vt-dur) var(--ease-ink) both; }
@keyframes ml-page-out { to { opacity: .5; scale: .985; } }
/* Six seams (the five noren panels and both edges) open at once, the middle ones first */
@keyframes ml-noren-open {
  0% { clip-path: polygon(0% 0%, 0% 0%, 0% 100%, 20% 100%, 20% 0%, 20% 0%, 20% 100%, 40% 100%, 40% 0%, 40% 0%, 40% 100%, 60% 100%, 60% 0%, 60% 0%, 60% 100%, 80% 100%, 80% 0%, 80% 0%, 80% 100%, 100% 100%, 100% 0%, 100% 0%, 100% 100%, 0% 100%); }
  55% { clip-path: polygon(-2% 0%, 2% 0%, 2% 100%, 15% 100%, 15% 0%, 25% 0%, 25% 100%, 32% 100%, 32% 0%, 48% 0%, 48% 100%, 52% 100%, 52% 0%, 68% 0%, 68% 100%, 75% 100%, 75% 0%, 85% 0%, 85% 100%, 98% 100%, 98% 0%, 102% 0%, 102% 100%, -2% 100%); }
  100% { clip-path: polygon(-10% 0%, 10% 0%, 10% 100%, 10% 100%, 10% 0%, 30% 0%, 30% 100%, 30% 100%, 30% 0%, 50% 0%, 50% 100%, 50% 100%, 50% 0%, 70% 0%, 70% 100%, 70% 100%, 70% 0%, 90% 0%, 90% 100%, 90% 100%, 90% 0%, 110% 0%, 110% 100%, -10% 100%); }
}

/* ---- Pause control in the footer (every page except Home, which has its own) ---- */
.motion-toggle--footer { margin: 0; color: var(--ivory); font-size: .75rem; }
@media (min-width: 48rem) {
  .footer__bottom:has(.motion-toggle--footer) { grid-template-columns: auto 1fr auto auto; }
}

/* ---- Reduced motion: everything rests, and pages change without a transition ---- */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  .ml-rise, .brush-rule svg, .tate span, .item__num, .noren--menu .noren__panel, .wave-edge span, .hanko--sheet { opacity: 1 !important; clip-path: none !important; scale: none !important; translate: none !important; animation: none !important; }
  .bar__item:active, .menu-cat .card:active .card__media { scale: none; }
}

/* ====== SIGNATURE MOTION (2026-10-24) ======
   The number board: item numbers flip into place once, like a split-flap call board, as they
   arrive (three flaps, 360 ms, staggered). The text never changes, so screen readers read it once.
   The heart seal: a small red heart stamps onto the drink cups once; on the Platters form it
   stamps beside the button once a request is sent. Transform and opacity only. */
:root { --flap: 120ms; --flaps: 3; --red-heart: #c8262c; }
@keyframes nb-flap { from { transform: perspective(14rem) rotateX(-88deg); } to { transform: perspective(14rem) rotateX(0deg); } }
@keyframes nb-seam { from { opacity: .45; } to { opacity: 0; } }
.card__num, .item__num, .order-sheet__num { transform-origin: 50% 50%; backface-visibility: hidden; }
.card__num::after, .item__num::after, .order-sheet__num::after { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: rgba(28, 26, 23, .55); opacity: 0; pointer-events: none; }
.ml-on:not(.motion-paused) :is(.card__num, .item__num).is-up { animation: nb-flap var(--flap) cubic-bezier(.55, 0, .9, .5) calc(var(--ml-n, 0) * 45ms) var(--flaps) backwards; }
.ml-on:not(.motion-paused) :is(.card__num, .item__num).is-up::after { animation: nb-seam calc(var(--flap) * var(--flaps)) linear calc(var(--ml-n, 0) * 45ms) backwards; }
.ml-on:not(.motion-paused) .item__num.is-up, .ml-on:not(.motion-paused) .item__num.is-up::after { animation-delay: .25s; }
/* order sheet: the picked number above "You picked #27 Rainbow Roll." */
.order-sheet__num { position: relative; display: inline-grid; place-items: center; min-width: 3.4rem; height: 3.4rem; margin: 0 0 var(--s3); padding: 0 .5rem; background: var(--orange); color: var(--ivory); font: 800 1.375rem/1 var(--font); border-radius: 5px; box-shadow: inset 0 0 0 2px rgba(255, 247, 232, .55); rotate: -4deg; }
.order-sheet__num[hidden] { display: none; }
.motion-ready:not(.motion-paused) .order-sheet__num.is-flipping { animation: nb-flap var(--flap) cubic-bezier(.55, 0, .9, .5) .2s var(--flaps) backwards; }
.motion-ready:not(.motion-paused) .order-sheet__num.is-flipping::after { animation: nb-seam calc(var(--flap) * var(--flaps)) linear .2s backwards; }

/* ---- Heart seal ---- */
.heart-seal { position: absolute; z-index: 3; width: clamp(2.4rem, 4vw, 3.1rem); aspect-ratio: 32 / 29; pointer-events: none; rotate: -8deg; filter: drop-shadow(0 2px 3px rgba(80, 10, 10, .3)); }
.heart-seal svg { display: block; width: 100%; height: 100%; overflow: visible; }
.heart-seal path { fill: var(--red-heart); stroke: rgba(255, 247, 232, .85); stroke-width: 1.4; }
.sips__cups .heart-seal { left: calc(var(--mat) * -.6); bottom: calc(var(--mat) * 1.2); rotate: -12deg; }
.sweets__cups { position: relative; }
.sweets__cups .heart-seal { right: -.6rem; bottom: .4rem; }
.ml-on:not(.motion-paused) .heart-seal.ml-watch:not(.is-up) { opacity: 0; }
.ml-on:not(.motion-paused) .heart-seal.is-up { animation: ml-stamp .55s var(--ease-stamp) .35s both; }
.inquiry__submit-row { position: relative; }
.heart-seal--form { position: static; width: 2.1rem; transition: opacity .2s ease; }
.inquiry__form:not(.is-sent) .heart-seal--form { opacity: 0; }
.motion-ready:not(.motion-paused) .inquiry__form.is-sent .heart-seal--form { animation: ml-stamp .5s var(--ease-stamp) both; }

@media (prefers-reduced-motion: reduce) {
  .card__num, .item__num, .order-sheet__num, .card__num::after, .item__num::after, .order-sheet__num::after, .heart-seal { animation: none !important; }
  .heart-seal:not(.heart-seal--form) { opacity: 1 !important; }
}
