/* co:carte motion
   ===============
   The rules, after Apple's "Designing Fluid Interfaces", and the reason for
   each:

   - Respond on the press, not the release. A control gives the instant a
     finger lands on it; waiting for the click to show anything feels dead.
   - Springs, not easing curves, and critically damped by default: things
     arrive with weight and stop without wobbling. Overshoot is only for
     motion the visitor threw (the feature carousel, in home.render.js).
   - Anything a visitor can touch is driven by a live spring in
     public/scripts/motion.js (window.coMotion), which starts from where the
     thing is on screen and keeps its velocity, so it can be grabbed and
     reversed mid-flight. CSS transitions are only for things nobody can
     interrupt: entrances and hovers.
   - Things leave the way they came. The phone menu grows out of its button
     and shrinks back into it; the FAQ answer folds up into its question.
   - Nothing simply fades in. Type rises out of a cut, a kicker is scored
     left to right, cards are set down, ticks are stamped. Body copy does not
     move: a paragraph that waits to appear is a paragraph that is late.
   - No idle loops and no glow. The menu in the story moves only when the
     visitor scrolls, and backwards when they scroll back.
   - Reduced motion is gentler, not absent: no entrances, no slides, but the
     menu and the FAQ still cross-fade so a change is never a jump cut. Every
     hidden starting state below is scoped to html[data-motion="on"], which
     lib/motion-arm.js only sets for visitors who have not asked for less. */

:root {
  /* Fallbacks for engines without linear(): close, never overshooting. */
  --spring-ui: cubic-bezier(.2, .8, .25, 1);   --spring-ui-dur: 520ms;
  --spring-set: cubic-bezier(.2, .8, .25, 1);  --spring-set-dur: 660ms;
  --spring-type: cubic-bezier(.2, .8, .25, 1); --spring-type-dur: 810ms;
}
@supports (transition-timing-function: linear(0, 1)) {
  :root {
    /* Generated by `node scripts/springs.mjs`; regenerate rather than edit. */
    /* ui: damping 1, response 0.35s, settles in 517ms */
    --spring-ui: linear(0, 0.0231, 0.0794, 0.1543, 0.2376, 0.3227, 0.4052, 0.4825, 0.5533, 0.617, 0.6735, 0.7229, 0.7659, 0.803, 0.8347, 0.8618, 0.8847, 0.9041, 0.9204, 0.934, 0.9454, 0.9549, 0.9629, 0.9694, 0.9749, 0.9794, 0.9831, 0.9861, 0.9887, 0.9907, 0.9924, 0.9938, 0.995, 0.9959, 0.9967, 0.9973, 0.9978, 0.9982, 0.9985, 0.9988, 1);
    --spring-ui-dur: 517ms;
    /* set: damping 1, response 0.45s, settles in 662ms */
    --spring-set: linear(0, 0.023, 0.0791, 0.1536, 0.2367, 0.3215, 0.4039, 0.4811, 0.5519, 0.6156, 0.672, 0.7216, 0.7646, 0.8018, 0.8336, 0.8608, 0.8838, 0.9033, 0.9196, 0.9334, 0.9449, 0.9544, 0.9624, 0.969, 0.9745, 0.9791, 0.9828, 0.9859, 0.9885, 0.9906, 0.9923, 0.9937, 0.9949, 0.9958, 0.9966, 0.9972, 0.9977, 0.9982, 0.9985, 0.9988, 1);
    --spring-set-dur: 662ms;
    /* type: damping 1, response 0.55s, settles in 808ms */
    --spring-type: linear(0, 0.0229, 0.0788, 0.1532, 0.2361, 0.3208, 0.403, 0.4802, 0.551, 0.6146, 0.6711, 0.7207, 0.7638, 0.801, 0.8329, 0.8601, 0.8832, 0.9027, 0.9192, 0.933, 0.9445, 0.9541, 0.9621, 0.9688, 0.9743, 0.9789, 0.9827, 0.9858, 0.9884, 0.9905, 0.9922, 0.9936, 0.9948, 0.9958, 0.9965, 0.9972, 0.9977, 0.9981, 0.9985, 0.9988, 1);
    --spring-type-dur: 808ms;
  }
}

/* ---- Press: instant in, spring out ----
   The press is 100ms and plain ease-out because it must be immediate; the
   release is the UI spring, from wherever the press had got to. Double-tap
   zoom is off on controls, which takes away the 300ms some browsers still
   hold a tap for. motion.js adds an empty touchstart listener, without
   which iOS Safari never applies :active at all. */
a, button, summary, [role="button"] { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
.tap, .carousel-arrow, .demo-card, [data-hero-cta] a, #cta a, .client-access {
  transition: transform var(--spring-ui-dur) var(--spring-ui), background-color .15s linear, color .15s linear, box-shadow .2s linear;
}
.tap:active, .carousel-arrow:active, [data-hero-cta] a:active, #cta a:active {
  transform: scale(.96); transition: transform 100ms ease-out;
}
.demo-card:active { transform: scale(.985); transition: transform 100ms ease-out; }

@media (hover: hover) and (pointer: fine) {
  [data-hero-cta] a svg, #cta a svg, .demo-card .text-cocarte-flameDark {
    transition: transform var(--spring-ui-dur) var(--spring-ui);
  }
  [data-hero-cta] a:hover svg, #cta a:hover svg { transform: translateX(3px); }
  .demo-card:hover .text-cocarte-flameDark { transform: translateX(3px); }
}

/* ---- Type rising out of a cut ----
   motion.js wraps every word of a heading in a mask (.mo-w) holding the word
   itself (.mo-wi), and numbers the lines in --l. The words of one line rise
   together and each line follows the one above it by 80ms. Until the split
   has happened a heading is held back, so it never flashes up in full and is
   then pulled down to animate. */
.mo-w {
  display: inline-block; overflow: hidden; vertical-align: top;
  padding: .06em .04em .16em; margin: -.06em -.04em -.16em;
}
.mo-wi { display: inline-block; }
html[data-motion="on"] :is(h1, h2):not(.mo-split):not(.ap-cap-title) { visibility: hidden; }
/* Far enough that no ascender peeks into the mask's bottom padding. */
html[data-motion="on"] .mo-type .mo-wi { transform: translateY(calc(100% + .35em)); }
html[data-motion="on"] .mo-type.is-in .mo-wi {
  transform: none;
  transition: transform var(--spring-type-dur) var(--spring-type);
  transition-delay: calc(var(--d0, 0ms) + var(--l, 0) * 80ms);
}

/* ---- Kicker: scored left to right, like the laser ---- */
html[data-motion="on"] .mo-kicker { clip-path: inset(0 100% 0 0); }
html[data-motion="on"] .mo-kicker.is-in {
  clip-path: inset(0 0 0 0);
  transition: clip-path var(--spring-type-dur) var(--spring-type);
}

/* ---- Set down ----
   Cards arrive from a little below, a fraction off square, and settle
   without overshoot. --i staggers what came into view together. */
html[data-motion="on"] .mo-set {
  opacity: 0;
  transform: translateY(24px) rotate(var(--mo-r, .6deg));
}
html[data-motion="on"] .mo-set.is-in {
  opacity: 1; transform: none;
  transition:
    transform var(--spring-set-dur) var(--spring-set),
    opacity 200ms linear;
  transition-delay: calc(var(--d0, 0ms) + var(--i, 0) * 70ms);
}

/* ---- The ledger: crosses first, then the ticks stamped one by one ---- */
html[data-motion="on"] .rev-ledger:not(.is-in) .rev-no { opacity: 0; }
html[data-motion="on"] .rev-ledger:not(.is-in) .rev-yes { opacity: 0; transform: scale(.4); }
html[data-motion="on"] .rev-ledger.is-in .rev-no {
  transition: opacity 200ms linear;
  transition-delay: calc(250ms + var(--i, 0) * 40ms);
}
html[data-motion="on"] .rev-ledger.is-in .rev-yes {
  transition: transform var(--spring-ui-dur) var(--spring-ui), opacity 120ms linear;
  transition-delay: calc(600ms + var(--i, 0) * 100ms);
}
/* The flame rule under the three verbs is burnt in, left to right. */
html[data-motion="on"] .rev-ledger:not(.is-in) .rev-verb { background-size: 0% 100%; }
html[data-motion="on"] .rev-ledger.is-in .rev-verb {
  transition: background-size var(--spring-type-dur) var(--spring-type);
  transition-delay: calc(420ms + var(--i, 0) * 260ms);
}

/* ---- Stand swatches: the drawn stand is set onto its tilt ---- */
[data-stand] { transform: rotate(var(--r, 0deg)); }
html[data-motion="on"] .mo-set:not(.is-in) [data-stand] {
  transform: translateY(-14px) rotate(calc(var(--r, 0deg) + 6deg));
}
html[data-motion="on"] .mo-set.is-in [data-stand] {
  transition: transform var(--spring-set-dur) var(--spring-set);
  transition-delay: calc(var(--i, 0) * 70ms + 220ms);
}

/* ---- "Probeer": one knock when the card first comes fully into view ----
   It used to wiggle every five seconds forever. A slow loop like that is
   the kind of motion that makes some people unwell, and a cue repeated
   until ignored stops being a cue. */
.try-badge.is-knock { animation: tryKnock 900ms linear; }
@keyframes tryKnock {
  0%, 100% { transform: none; }
  12% { transform: rotate(-7deg) scale(1.06); }
  30% { transform: rotate(5deg) scale(1.04); }
  48% { transform: rotate(-2.5deg); }
  66% { transform: rotate(1deg); }
  82% { transform: rotate(-.3deg); }
}

/* ---- FAQ: motion.js drives the height and the chevron from one spring ---- */
details.faq > div { overflow: hidden; }
details.faq .chev { transition: none !important; }

/* ---- Phone menu: a panel of material, grown out of its button ----
   motion.js runs one spring (0 closed, 1 open) and paints the panel, the
   scrim and the links from it; it scales from the button's corner, and
   closes back into it along the same path. */
#mobileMenu {
  position: absolute; top: calc(100% + 8px); right: 12px; left: auto;
  width: min(20rem, calc(100vw - 24px));
  transform-origin: calc(100% - 22px) -8px;
  will-change: transform, opacity;
}
.mo-scrim {
  position: fixed; inset: 0; z-index: 40; background: rgba(15, 6, 2, .32);
  opacity: 0; pointer-events: none;
}
.mo-scrim.is-on { pointer-events: auto; }

/* ---- Hero: the menu that plays itself ---- */
[data-hero-screen] { position: relative; }
/* Two lines stacked in a one-line window; motion.js moves the stack by half
   its own height to roll from one to the other. */
.rz-roll {
  display: inline-flex; flex-direction: column; vertical-align: top;
  line-height: 1.2em;
}
.rz-roll > span { display: block; height: 1.2em; }
.rz-cur, .rz-price { display: inline-block; height: 1.2em; line-height: 1.2em; overflow: hidden; }
/* The currency chip clips at its padding edge, so its padding is folded into
   the line height instead: otherwise the next code shows in the padding. */
.rz-cur { padding-block: 0; height: 1.8em; line-height: 1.8em; }
.rz-cur .rz-roll { line-height: 1.8em; }
.rz-cur .rz-roll > span { height: 1.8em; }

.rz-allergy { position: relative; }
.rz-count {
  position: absolute; top: 50%; right: .45rem; margin-top: -.42rem;
  height: .84rem; min-width: .84rem; padding: 0 .2rem; border-radius: 999px;
  background: #A32E19; color: #fff; font-size: 7.5px; letter-spacing: 0;
  display: flex; align-items: center; justify-content: center;
  transform: scale(0);
}

/* The list is a window onto a longer menu: two postcards and the top of a
   third, so when the croissant is filtered out the next dish has somewhere
   to come up from. */
.rz-list {
  position: relative; overflow: hidden;
  height: 236px; padding: .65rem .75rem 0;
}
.rz-tilt-c { transform: rotate(-0.5deg); }
.rz-flag-id { background: linear-gradient(180deg, #CE1126 0 50%, #FFFFFF 50%); }
.rz-diet-vegan { background: #C9E7CE; color: #1F5C33; }

.rz-add-morph { position: relative; display: inline-flex; justify-content: center; overflow: hidden; white-space: nowrap; }
.rz-add-a { display: inline-block; }
.rz-add-b {
  position: absolute; top: 0; bottom: 0; right: 0;
  display: flex; align-items: center; gap: .6rem; padding: 0 .55rem;
  opacity: 0; font-variant-numeric: tabular-nums;
}

.rz-tabs { position: relative; z-index: 1; }
.rz-tab-badge {
  position: absolute; top: -.45rem; right: -.6rem;
  min-width: .78rem; height: .78rem; padding: 0 .15rem; border-radius: 999px;
  background: #A32E19; color: #fff;
  font-family: Inter, sans-serif; font-size: 7px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  transform: scale(0);
}

.rz-scrim { position: absolute; inset: 0; z-index: 2; background: #000; opacity: 0; pointer-events: none; }
.rz-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  background: #FBF3E7; border-radius: 1.1rem 1.1rem 0 0;
  padding: .8rem .8rem .75rem;
  transform: translateY(101%); visibility: hidden;
}
.rz-sheet-title {
  font-family: "Fraunces", Georgia, serif; font-style: italic; font-weight: 600;
  font-size: 13px; color: #2B1810; margin: 0 0 .5rem;
}
.rz-sheet-kicker {
  font-family: "Space Mono", ui-monospace, monospace; font-size: 6.5px;
  text-transform: uppercase; letter-spacing: .18em; color: rgba(43,24,16,.65);
  margin: 0 0 .3rem;
}
.rz-chips { display: flex; flex-wrap: wrap; gap: .25rem; margin-bottom: .55rem; }
.rz-chip {
  font-family: "Space Mono", ui-monospace, monospace; font-size: 6.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  border-radius: 999px; padding: .2rem .4rem; border: 1px solid transparent; line-height: 1.2;
}
/* The guest menu's own chip colours (FILTER_STYLE in demo-gezellig.render.js). */
.rz-chip-vegan       { background: #C9E7CE; color: #1F5C33; border-color: rgba(31,92,51,.2); }
.rz-chip-vegetarian  { background: #C6DCF2; color: #1D4E80; border-color: rgba(29,78,128,.2); }
.rz-chip-pescatarian { background: #C2E4E2; color: #1B5C58; border-color: rgba(27,92,88,.2); }
.rz-chip-gluten      { background: #F6D3D3; color: #8A2A2A; border-color: rgba(138,42,42,.2); }
.rz-chip-dairy       { background: #EFDFC2; color: #7A5423; border-color: rgba(122,84,35,.2); }
.rz-chip-nut         { background: #DCD2F0; color: #4B3480; border-color: rgba(75,52,128,.2); }
.rz-chip-crustacean  { background: #F3D9E6; color: #8A2A5C; border-color: rgba(138,42,92,.2); }
.rz-chip-egg         { background: #FBEAC6; color: #8A6A1A; border-color: rgba(138,106,26,.2); }
.rz-chip-fish        { background: #CDE7E3; color: #1F6B5C; border-color: rgba(31,107,92,.2); }
.rz-status {
  position: relative; height: 1.3em; margin: .1rem 0 .55rem;
  font-size: 7.5px; font-weight: 600; color: rgba(43,24,16,.7);
}
.rz-status > span { position: absolute; left: 0; top: 0; white-space: nowrap; }
.rz-status > [data-h="statusOn"] { opacity: 0; }
.rz-sheet-foot {
  display: flex; align-items: center; justify-content: space-between;
  border-top: 1px solid rgba(193,58,34,.2); padding-top: .5rem;
}
.rz-clear, .rz-done {
  font-family: "Space Mono", ui-monospace, monospace; font-size: 6.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
}
.rz-clear { color: rgba(43,24,16,.65); }
.rz-done { background: #A32E19; color: #fff; border-radius: 999px; padding: .3rem .6rem; }

/* A thumb, not a cursor: this is a phone. */
.rz-touch {
  position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none;
  width: 22px; height: 22px; margin: -11px 0 0 -11px; border-radius: 999px;
  background: rgba(26,11,5,.22); border: 1.5px solid rgba(255,255,255,.9);
  box-shadow: 0 2px 6px -1px rgba(26,11,5,.35);
  transform: translate(400px, 300px);
}

/* Hero entrance, before motion.js has painted its first frame. */
html[data-motion="on"] [data-hero-phone]:not(.is-live) { opacity: 0; }
html[data-motion="on"] [data-hero-plaque]:not(.is-live) { opacity: 0; }
html[data-motion="on"] [data-hero-cta] { opacity: 0; transform: translateY(14px); }
html[data-motion="on"] [data-hero-cta].is-in {
  opacity: 1; transform: none;
  transition: transform var(--spring-set-dur) var(--spring-set), opacity 200ms linear;
  transition-delay: 360ms;
}
[data-hero-plaque] { transform: rotate(-2deg); }
