/* Motion and colour layer (progressive enhancement, see motion.js).
 *
 * Kept apart from app.css on purpose: everything here can be removed and
 * the site still works and looks right. Colours come from the poster:
 * every event element carries .p-<image> (palette.css) or a .t-* venue
 * tint, which define --p-bg/--p-fg/--p-muted/--p-accent and, here,
 * --p-halo (Bg with more colour, same contrast for the text on it) and
 * --p-glow (the picture's vivid colour, for shadows and glows only).
 *
 * prefers-reduced-motion: reduce switches every movement off: no view
 * transitions, tilt, bursts, reveals or kinetic type. The colours stay.
 */

/* ---------- palette fallbacks ---------- */
:root { --p-glow: var(--indigo); --p-halo: var(--p-bg, var(--paper)); }
:is(.t-0, .t-1, .t-2, .t-3, .t-4, .t-5, .t-6, .t-7, .t-g) {
  --p-halo: hsl(var(--h) calc(58% * var(--sat, 1)) 93%);
  --p-glow: hsl(var(--h) calc(70% * var(--sat, 1)) 52%);
}
:root[data-theme="dark"] :is(.t-0, .t-1, .t-2, .t-3, .t-4, .t-5, .t-6, .t-7, .t-g) {
  --p-halo: hsl(var(--h) calc(45% * var(--sat, 1)) 15%);
  --p-glow: hsl(var(--h) calc(70% * var(--sat, 1)) 60%);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) :is(.t-0, .t-1, .t-2, .t-3, .t-4, .t-5, .t-6, .t-7, .t-g) {
    --p-halo: hsl(var(--h) calc(45% * var(--sat, 1)) 15%);
    --p-glow: hsl(var(--h) calc(70% * var(--sat, 1)) 60%);
  }
}

:root {
  /* A damped spring (ζ ≈ 0.72): a few percent of overshoot, then rest. */
  --mo-spring: linear(0, 0.0331, 0.1153, 0.2256, 0.3479, 0.4706, 0.5861, 0.6895, 0.7783, 0.8519, 0.9106, 0.9556, 0.9887, 1.0117, 1.0264, 1.0347, 1.0381, 1.038, 1.0356, 1.0318, 1.0272, 1.0225, 1.0179, 1.0137, 1.01, 1.0069, 1.0044, 1.0024, 1.001, 0.9999, 0.9992, 0.9988, 0.9986, 0.9985, 0.9986, 0.9987, 0.9989, 0.9991, 0.9992, 0.9994, 1);
  --mo-out: cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* ---------- 1. view transitions between pages ----------
   Same-origin navigations morph; the clicked tile's poster and title get
   the names poster-<id> / title-<id> (motion.js, pageswap/pagereveal), the
   event page's hero the same ones. Without support: a normal navigation. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
.tabbar { view-transition-name: tabbar; }

::view-transition-old(root) { animation: 140ms cubic-bezier(0.4, 0, 1, 1) both mo-vt-out; }
::view-transition-new(root) { animation: 280ms var(--mo-out) 70ms both mo-vt-in; }
@keyframes mo-vt-out { to { opacity: 0; } }
@keyframes mo-vt-in { from { opacity: 0; transform: translateY(10px); } }

::view-transition-group(*.vt-poster) {
  animation-duration: 560ms; animation-timing-function: var(--mo-spring);
  border-radius: 14px; overflow: clip;
}
::view-transition-old(*.vt-poster), ::view-transition-new(*.vt-poster) {
  height: 100%; object-fit: cover; animation-duration: 260ms; animation-timing-function: ease;
}
::view-transition-group(*.vt-title) { animation-duration: 500ms; animation-timing-function: var(--mo-spring); }
::view-transition-old(*.vt-title) { animation-duration: 200ms; }
::view-transition-new(*.vt-title) { animation-duration: 320ms; animation-delay: 60ms; }
::view-transition-image-pair(*.vt-title) { isolation: auto; }

/* ---------- 2. colour from the poster ---------- */
/* (The hover glow on tiles and rows was removed on 17.10.) */

/* The event page is tinted by its poster throughout: a halo of the
   picture's colour behind the hero (same lightness as --p-bg, so the
   text keeps its contrast), the page itself between paper and --p-bg. */
.event { background: color-mix(in srgb, var(--p-bg) 55%, var(--paper)); }
.event .hero {
  background:
    radial-gradient(ellipse 70% 85% at 14% 22%, var(--p-halo), transparent 72%),
    radial-gradient(ellipse 55% 70% at 100% 0%, color-mix(in srgb, var(--p-halo) 75%, transparent), transparent 70%),
    var(--p-bg);
}
.event .hero-poster img {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--p-fg) 10%, transparent),
    0 34px 70px -30px color-mix(in srgb, var(--p-glow) 85%, #000),
    0 0 90px -30px color-mix(in srgb, var(--p-glow) 60%, transparent);
}
.event .btn-accent:not(.tk) { box-shadow: 0 10px 26px -12px var(--p-glow); }
.event :focus-visible { outline-color: var(--p-accent); }
.event-body :is(h2, .o-day, .o-time) { color: var(--p-fg); }
.event-body a:not(.btn):not(.show) { color: var(--p-accent); }
.event .place {
  background: color-mix(in srgb, var(--p-bg) 72%, var(--surface));
  border-color: color-mix(in srgb, var(--p-fg) 14%, transparent);
}
.event .place a { color: var(--p-accent); }

/* (3. The pointer tilt was removed on 17.10: too much effort for too little.) */
.hero-poster .zoom { border-radius: 14px; }

/* ---------- 4. "Купи билет" is a ticket ----------
   Two pieces with notches at the perforation; the stub carries the
   price (or an arrow) and tears off on click (motion.js). The colour is
   painted on the pieces, so the focus outline of the link is never
   clipped by the masks. */
.btn.tk {
  --tk-r: 7px;
  padding: 0; gap: 0; align-items: stretch; border: 0; background: none; color: var(--p-bg);
  position: relative; isolation: isolate;
  filter: drop-shadow(0 10px 14px color-mix(in srgb, var(--p-glow) 38%, transparent));
}
.btn.tk:hover { filter: drop-shadow(0 12px 16px color-mix(in srgb, var(--p-glow) 50%, transparent)) brightness(1.06); }
.tk-main, .tk-stub { display: inline-flex; align-items: center; justify-content: center; background: var(--p-accent); }
.tk-main {
  flex: 1 1 auto; padding: 0 16px 0 20px; border-radius: var(--r-btn) 0 0 var(--r-btn);
  -webkit-mask: radial-gradient(circle var(--tk-r) at 100% 0, #0000 97%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle var(--tk-r) at 100% 100%, #0000 97%, #000) bottom / 100% 51% no-repeat;
  mask: radial-gradient(circle var(--tk-r) at 100% 0, #0000 97%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle var(--tk-r) at 100% 100%, #0000 97%, #000) bottom / 100% 51% no-repeat;
}
.tk-stub {
  flex: none; min-width: 52px; padding: 0 14px 0 13px; border-radius: 0 var(--r-btn) var(--r-btn) 0;
  font: 850 20px/1 var(--display); font-variant-numeric: tabular-nums; white-space: nowrap;
  /* the perforation: a column of holes in the page colour */
  background:
    radial-gradient(circle, var(--p-bg) 1.3px, transparent 1.9px) 0 50% / 3px 7px repeat-y,
    var(--p-accent);
  -webkit-mask: radial-gradient(circle var(--tk-r) at 0 0, #0000 97%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle var(--tk-r) at 0 100%, #0000 97%, #000) bottom / 100% 51% no-repeat;
  mask: radial-gradient(circle var(--tk-r) at 0 0, #0000 97%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle var(--tk-r) at 0 100%, #0000 97%, #000) bottom / 100% 51% no-repeat;
  transform-origin: 0 100%;
}
.tk-stub .icon { width: 18px; height: 18px; stroke-width: 2.2; }
.tk-price + .tk-arrow { display: none; }
@media (max-width: 899px) {
  .actionbar > .btn.tk { padding: 0; flex: 1.25 1 0; }
  .actionbar .tk-main { padding: 0 10px 0 14px; }
  .actionbar .tk-stub { min-width: 0; padding: 0 10px; font-size: 18px; }
}
@media (max-width: 380px) {
  .actionbar > .btn.tk { flex: 1 1 0; }
  .actionbar .tk-price { display: none; }
  .actionbar .tk-price + .tk-arrow { display: block; }
}
@media (prefers-reduced-motion: no-preference) {
  .tk.is-torn .tk-stub { animation: mo-tear 0.5s cubic-bezier(0.45, 0, 0.75, 0.3) forwards; }
  .tk.is-torn .tk-main { animation: mo-jolt 0.18s ease-out; }
}
@keyframes mo-tear {
  0% { transform: none; }
  22% { transform: translate(2px, -2px) rotate(9deg); }
  100% { transform: translate(28px, 46px) rotate(34deg); opacity: 0; }
}
@keyframes mo-jolt { 40% { transform: translateX(-3px); } }

/* The price chip of a tile: a small ticket with notched sides. */
.tile .tag-price {
  box-shadow: none; padding-inline: 10px; border-radius: 4px;
  -webkit-mask: radial-gradient(circle 4px at 0 50%, #0000 96%, #000) left / 51% 100% no-repeat,
    radial-gradient(circle 4px at 100% 50%, #0000 96%, #000) right / 51% 100% no-repeat;
  mask: radial-gradient(circle 4px at 0 50%, #0000 96%, #000) left / 51% 100% no-repeat,
    radial-gradient(circle 4px at 100% 50%, #0000 96%, #000) right / 51% 100% no-repeat;
}

/* ---------- 5. heart burst ---------- */
.mo-spark {
  position: fixed; z-index: 70; left: 0; top: 0; width: 8px; height: 8px; margin: -4px 0 0 -4px;
  border-radius: 50%; pointer-events: none; will-change: transform, opacity;
}
.mo-spark.is-heart { width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 2px 50% 50% 50%; }
@media (prefers-reduced-motion: no-preference) {
  .fav-count.is-bump { animation: mo-bump 0.6s var(--mo-spring); }
  .is-pop > .icon-heart { animation: mo-pop 0.45s var(--mo-spring); }
}
@keyframes mo-bump { 0% { transform: scale(1); } 30% { transform: scale(1.55) translateY(-3px); } 100% { transform: scale(1); } }
@keyframes mo-pop { 0% { transform: scale(0.6); } 60% { transform: scale(1.25); } 100% { transform: scale(1); } }

/* (6. The scroll-driven reveal was removed on 17.10: rows at the bottom
   looked faded, as if over.) */

/* The sticky day heading gets smaller once it sticks: a scroll-state
   query where supported, else .is-stuck from an IntersectionObserver
   (motion.js). Transforms only: nothing below moves. --rel-w/--rel-h are
   the size of the day name, measured once (motion.js). */
.day-head { container-type: scroll-state; }
.day-rel, .day-date { transition: transform 0.35s var(--mo-out); }
.day-rel { transform-origin: 0 75%; }
@container scroll-state(stuck: top) {
  .day-rel { transform: scale(0.8); }
  .day-date { transform: translateX(calc(var(--rel-w, 0px) * -0.2)); }
}
.day-head.is-stuck .day-rel { transform: scale(0.8); }
.day-head.is-stuck .day-date { transform: translateX(calc(var(--rel-w, 0px) * -0.2)); }
/* Desktop list (not the grid): the heading is a column beside the day. */
@media (min-width: 900px) {
  .day-rel { transform-origin: 0 0; }
  @container scroll-state(stuck: top) {
    .day-date { transform: translateY(calc(var(--rel-h, 0px) * -0.2)); }
  }
  .day-head.is-stuck .day-date { transform: translateY(calc(var(--rel-h, 0px) * -0.2)); }
  .is-grid .day-rel { transform-origin: 0 75%; }
  @container scroll-state(stuck: top) {
    .is-grid .day-date { transform: translateX(calc(var(--rel-w, 0px) * -0.2)); }
  }
  .is-grid .day-head.is-stuck .day-date { transform: translateX(calc(var(--rel-w, 0px) * -0.2)); }
}

/* (7. The kinetic headings were removed on 17.10: letters drifting apart
   on scroll looked odd.) */

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .tile-img, .hero-poster .zoom, .film-poster { transform: none !important; }
  .tile-img::before, .hero-poster .zoom::before, .film-poster::before, .mo-spark { display: none; }
  .day-rel, .day-date { transform: none !important; }
}

@media print {
  .event, .event .hero { background: none; }
}

/* The sticky day heading: see-through and softly blurred over whatever
   is behind it (gradients, the sky, a tinted page), not a flat sheet of
   paper with an edge. */
.day-head, .is-grid .day-head {
  background: color-mix(in srgb, var(--paper) 78%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  box-shadow: none;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .day-head, .is-grid .day-head { background: var(--paper); }
}
