/* motion.css — język ruchu ArtOn (23.09.2026). Ładowany jako ostatni arkusz na wszystkich stronach.
   Zasada: ruch potwierdza akcję i porządkuje przejścia, nigdy nie dekoruje. Animujemy WYŁĄCZNIE
   opacity, transform, background-color, border-color, box-shadow, color — nigdy width/height/top/left/margin.
   Tokeny czasu (--t-*) i krzywych (--ease-*) są zdefiniowane w :root (style.css). */

/* ============================================================
   1. KEYFRAMES — każdy kończy się stanem statycznym (nic nie znika po wyłączeniu ruchu)
   ============================================================ */
@keyframes view-in   { from { opacity: 0; transform: translateY(6px); }              to { opacity: 1; transform: none; } }
@keyframes panel-in  { from { opacity: 0; transform: translateY(-4px); }             to { opacity: 1; transform: none; } }
@keyframes row-in    { from { opacity: 0; transform: translateY(4px); }              to { opacity: 1; transform: none; } }
@keyframes fade-in   { from { opacity: 0; }                                          to { opacity: 1; } }
@keyframes fade-out  { from { opacity: 1; }                                          to { opacity: 0; } }
@keyframes modal-in  { from { opacity: 0; transform: translateY(10px) scale(.97); }  to { opacity: 1; transform: none; } }
@keyframes modal-out { from { opacity: 1; transform: none; }                         to { opacity: 0; transform: translateY(6px) scale(.98); } }
@keyframes sheet-in  { from { transform: translateY(100%); }                         to { transform: none; } }
@keyframes sheet-out { from { transform: none; }                                     to { transform: translateY(100%); } }
/* toast: translateX(-50%) MUSI zostać w obu klatkach — centrowanie toastu opiera się na transformie */
@keyframes toast-in  { from { opacity: 0; transform: translate(-50%, 12px) scale(.96); } to { opacity: 1; transform: translate(-50%, 0) scale(1); } }
@keyframes toast-out { from { opacity: 1; transform: translate(-50%, 0) scale(1); }      to { opacity: 0; transform: translate(-50%, 8px) scale(.98); } }
@keyframes badge-pop { from { opacity: 0; transform: scale(.6); }                    to { opacity: 1; transform: none; } }
@keyframes logo-in   { from { opacity: 0; transform: translateY(12px) scale(.94); }  to { opacity: 1; transform: none; } }
@keyframes check-in  { from { opacity: 0; transform: scale(.6); }                    to { opacity: 1; transform: none; } }
@keyframes shake     { 0%, 100% { transform: none; } 20%, 60% { transform: translateX(-3px); } 40%, 80% { transform: translateX(3px); } }
@keyframes spin      { to { transform: rotate(360deg); } }
/* jedyna pętla w systemie — shimmer szkieletu */
@keyframes skel      { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

/* ============================================================
   2. WEJŚCIE WIDOKU — JS przełącza .active/.hidden (display), animacja startuje przy każdym pokazaniu
   ============================================================ */
/* panel: animujemy karty, nie cały widok — transform na .tab robiłby containing block dla position:fixed */
.tab.active { animation: none; }
.tab.active > .panel,
.subview:not(.hidden) > .panel { --stagger: 0ms; animation: view-in var(--t-enter) var(--ease-out) var(--stagger) both; }
.tab.active > .panel:nth-child(2), .subview:not(.hidden) > .panel:nth-child(2) { --stagger: 40ms; }
.tab.active > .panel:nth-child(3), .subview:not(.hidden) > .panel:nth-child(3) { --stagger: 80ms; }
.tab.active > .panel:nth-child(4), .subview:not(.hidden) > .panel:nth-child(4) { --stagger: 120ms; }
.tab.active > .panel:nth-child(5), .subview:not(.hidden) > .panel:nth-child(5) { --stagger: 160ms; }
.tab.active > .panel:nth-child(n+6), .subview:not(.hidden) > .panel:nth-child(n+6) { --stagger: 200ms; }
/* portal: widok jako całość (brak potomków position:fixed), 320 ms */
.pv.active { animation: view-in var(--t-slow) var(--ease-out) both; }
/* pozostałe przełączane bloki */
.auth-pane:not(.hidden), #reset-confirm:not(.hidden),
#step-mode:not(.hidden), #step-city:not(.hidden), #step-form:not(.hidden), #step-done:not(.hidden),
#inbox-thread, #cp-body { animation: view-in var(--t-enter) var(--ease-out) both; }

/* ============================================================
   3. LISTY — wejście sterowane z JS (klasa .anim-in po renderze wywołanym działaniem użytkownika,
      zdejmowana po animationend). Sam render (polling co 60 s) NIE animuje — lista nie ma „falować".
   ============================================================ */
/* schodkowe reguły z style.css dla kart portalu wyłączamy — portal odświeża innerHTML w tle */
.home-tiles .tile:nth-child(n), .stat-tiles .tile:nth-child(n), .session-card:nth-child(n), .pay-month:nth-child(n) { animation: none; }
.anim-in:nth-child(n), .home-tiles .tile.anim-in, .stat-tiles .tile.anim-in { --stagger: 0ms; animation: row-in var(--t-base) var(--ease-out) var(--stagger) both; }
/* schodek 30 ms do 8. elementu, dalej razem */
.anim-in:nth-child(2) { --stagger: 30ms; }
.anim-in:nth-child(3) { --stagger: 60ms; }
.anim-in:nth-child(4) { --stagger: 90ms; }
.anim-in:nth-child(5) { --stagger: 120ms; }
.anim-in:nth-child(6) { --stagger: 150ms; }
.anim-in:nth-child(7) { --stagger: 180ms; }
.anim-in:nth-child(8) { --stagger: 210ms; }
/* wiersze tabel i płatności: tylko opacity — re-render po zapisaniu wpłaty ma się czytać jak miękkie odświeżenie */
tr.anim-in:nth-child(n), .pay-row.anim-in:nth-child(n), .hours-row.anim-in:nth-child(n) { animation-name: fade-in; }

/* ============================================================
   4. PANELE ZWIJANE, AKORDEONY, CARET — display:none nie animujemy, dlatego fade + 4 px, nie height
   ============================================================ */
.collapsible.open .col-body { animation: panel-in var(--t-base) var(--ease-out) both; }
.group-card.open .group-members,
.group-card.open .members-due-head,
.group-card.open .group-edit-slot:not(:empty),
.hours-detail td,
.cp-month-body:not(.hidden),
.indiv-edit,
.hint-details[open] > :not(summary) { animation: panel-in var(--t-base) var(--ease-out) both; }
/* formularze i paski pokazywane przez zdjęcie .hidden */
#group-form-wrap:not(.hidden), #child-form-wrap:not(.hidden),
#children-bulk:not(.hidden), #pay-bulk:not(.hidden), .bulk-bar:not(.hidden) { animation: panel-in var(--t-enter) var(--ease-out) both; }
/* caret: obrót 90° (chevron-right → chevron-down), ease-in-out */
.caret, .hours-row .caret, .group-caret { display: inline-flex; align-items: center; justify-content: center; transition: transform var(--t-base) var(--ease-in-out); transform-origin: center; }
.collapsible.open .caret, .hours-row.open .caret, .group-card.open .group-caret { transform: rotate(90deg); }
details > summary { transition: color var(--t-fast) var(--ease-standard); }
.group-card { transition: border-color var(--t-fast) var(--ease-standard), box-shadow var(--t-base) var(--ease-out); }
.group-head, .col-toggle { transition: background-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard); }
/* akcje karty grupy: pełna widoczność dopiero na hover (tylko urządzenia z kursorem; miejsce zarezerwowane — bez skoku) */
@media (hover: hover) {
  .group-card .group-actions { opacity: .72; transition: opacity var(--t-fast) var(--ease-standard); }
  .group-card:hover .group-actions, .group-card:focus-within .group-actions, .group-card.open .group-actions { opacity: 1; }
}

/* ============================================================
   5. MODALE — backdrop fade + dialog scale/translate; ≤700 px arkusz od dołu; wyjście przez .is-closing (JS)
      Stan końcowy zawsze .hidden (display:none) — panel.php czyta '.modal-backdrop:not(.hidden)'.
   ============================================================ */
.modal-backdrop { animation: fade-in var(--t-base) var(--ease-out) both; }
.modal-backdrop .modal { animation: modal-in var(--t-enter) var(--ease-out) both; }
.modal-backdrop.is-closing { animation: fade-out var(--t-fast) var(--ease-exit) both; pointer-events: none; }
.modal-backdrop.is-closing .modal { animation: modal-out var(--t-fast) var(--ease-exit) both; }
@media (max-width: 700px) {
  .modal-backdrop .modal { animation: sheet-in var(--t-slow) var(--ease-out) both; }
  .modal-backdrop.is-closing .modal { animation: sheet-out var(--t-base) var(--ease-exit) both; }
}

/* ============================================================
   6. TOASTY — wejście spring (jedyny większy element z overshootem), wyjście przez .toast-out (JS)
   ============================================================ */
.toast { animation: toast-in var(--t-enter) var(--ease-spring) both; }
.toast.toast-out { animation: toast-out var(--t-fast) var(--ease-exit) both; pointer-events: none; }

/* ============================================================
   7. BADGE, CHIPY, PIGUŁKI — spring tylko dla elementów < 40 px
   ============================================================ */
.nav-badge:not(.hidden) { animation: badge-pop var(--t-enter) var(--ease-spring) both; }
/* liczniki w listach odświeżanych w tle nie „skaczą" przy każdym renderze */
.thread-row .nav-badge, .thread-top .nav-badge { animation: none; }
.badge, .chip, .att-chip, .group-chip, .pay-chip, .st-pill { transition: background-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard), border-color var(--t-fast) var(--ease-standard); }
.chip-x, .att-x { transition: background-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard), transform var(--t-micro) var(--ease-out); }
.chip-x:active, .att-x:active { transform: scale(.9); }

/* ============================================================
   8. PRZYCISKI — hover tło/obramowanie 140 ms, press scale(.97) 90 ms, cień 200 ms
   ============================================================ */
button, .import-label, a.btn-link, .logout-link, .child-tab, .month-tile, .free-tile, .city-btn, .pay-due-btn, .rodo-back, .landing-actions a {
  transition: background-color var(--t-fast) var(--ease-standard), border-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard),
              box-shadow var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out), opacity var(--t-fast) var(--ease-standard);
}
/* karty-przyciski (.tile-btn/.month-tile/.free-tile/.city-btn) wyłączone z .97 — mają własne .98 niżej */
button:active:not(:disabled):not(.tile-btn):not(.month-tile):not(.free-tile):not(.city-btn), .import-label:active, .logout-link:active, .child-tab:active { transform: scale(.97); transition-duration: var(--t-micro); }
button:disabled { transition: opacity var(--t-fast) var(--ease-standard); }
/* karty klikalne: uniesienie o 1 px + cień poziomu 2 (tylko z kursorem), press scale(.98) */
@media (hover: hover) {
  .tile-btn:hover, .month-tile:hover, .free-tile:hover, .city-btn:hover, a.btn-link:hover, .landing-actions a:hover, .session-card.tile-btn:hover { transform: translateY(-1px); }
}
.tile-btn:active, .month-tile:active, .free-tile:active, .city-btn:active, a.btn-link:active, .landing-actions a:active { transform: scale(.98); transition-duration: var(--t-micro); }
/* zajęte przyciski wysyłki (formularz zapisów, reset hasła): klasa .is-busy z JS — tekst gaśnie, w środku obraca się spinner
   (:disabled zostaje wyłącznie blokadą; tło stanu zajętego daje public.css) */
#signup-submit.is-busy, #reset-req-btn.is-busy, #reset-confirm-btn.is-busy { position: relative; color: transparent; pointer-events: none; }
#signup-submit.is-busy::after, #reset-req-btn.is-busy::after, #reset-confirm-btn.is-busy::after {
  content: ''; position: absolute; inset: 0; margin: auto; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .45); border-top-color: #fff; animation: spin .7s linear infinite;
}

/* ============================================================
   9. WIERSZE LIST I TABEL — tylko tło/obramowanie/cień, bez transformu
   ============================================================ */
.att-row, .pay-row, .session-row, .slot-card, .thread-row, .note-item, .req-card, .parent-row, .cp-month, .hours-row, tbody tr, .tile, .session-card, .pay-month, .ann-card {
  transition: background-color var(--t-fast) var(--ease-standard), border-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard),
              box-shadow var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out);
}
tbody td { transition: background-color var(--t-fast) var(--ease-standard); }
/* akcje w wierszach: 70 % → 100 % na hover (tylko z kursorem) */
@media (hover: hover) {
  td.actions .small, .pay-row .pay-due-btn { opacity: 1; transition: opacity var(--t-fast) var(--ease-standard), background-color var(--t-fast) var(--ease-standard), border-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard); }
  tr:hover td.actions .small, .pay-row:hover .pay-due-btn, td.actions .small:focus-visible, .pay-row .pay-due-btn:focus-visible { opacity: 1; }
}

/* ============================================================
   10. NAWIGACJA — zakładki główne (podkreślenie scaleX), segmented control, dolna nawigacja portalu
   ============================================================ */
header nav .tab-btn, .portal-head .top-nav button { transition: color var(--t-fast) var(--ease-standard), background-color var(--t-fast) var(--ease-standard); }
header nav .tab-btn::after, .portal-head .top-nav button::after { transform-origin: center; transition: transform var(--t-base) var(--ease-out), opacity var(--t-fast) var(--ease-standard); }
/* ikony w zakładkach panelu: nieaktywny kafelek wygaszony, aktywny pełny + lekki scale (spring, < 40 px) */
header nav .tab-btn .ico {
  transition: opacity var(--t-fast) var(--ease-standard), filter var(--t-fast) var(--ease-standard), transform var(--t-enter) var(--ease-spring);
}
header nav .tab-btn.active .ico { transform: scale(1.06); }
/* nawigacja portalu: glif svg.gl zmienia tylko kolor (rodzic.css); ruch wyłącznie na kontenerze .nav-ico */
.nav-ico { transition: transform var(--t-enter) var(--ease-spring); }
#bottom-nav button.active .nav-ico { transform: translateY(-1px) scale(1.08); }
#bottom-nav button:active .nav-ico { transform: scale(.9); transition-duration: var(--t-micro); }
#bottom-nav button { transition: color var(--t-fast) var(--ease-standard); }
/* segmented control: tylko tło/cień/kolor — bez przesuwanego wskaźnika (elementy mogą się przewijać) */
.subnav .sub-tab, .subnav .rate-tab, .subnav .prate-tab, .subnav .pgroup-tab, .auth-tab { transition: background-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard), box-shadow var(--t-fast) var(--ease-standard); }
.subnav .sub-tab:active, .subnav .rate-tab:active, .subnav .prate-tab:active, .subnav .pgroup-tab:active, .auth-tab:active { transform: none; }
/* przycisk odświeżania kont rodziców: obrót ikony podczas pobierania (klasa .is-busy z JS) */
#parents-refresh .ui, #parents-refresh .ico { transition: transform var(--t-base) var(--ease-in-out); }
#parents-refresh.is-busy .ui, #parents-refresh.is-busy .ico { animation: spin .7s linear infinite; }

/* ============================================================
   11. POLA I FOKUS — obramowanie 140 ms, ring 0 → 4 px 200 ms
   ============================================================ */
input, select, textarea, #note-text { transition: border-color var(--t-fast) var(--ease-standard), box-shadow var(--t-base) var(--ease-out), background-color var(--t-fast) var(--ease-standard), color var(--t-fast) var(--ease-standard); }
:where(a, button, [tabindex], summary):focus-visible { transition: box-shadow var(--t-base) var(--ease-out); }
input[type=checkbox], input[type=radio] { transition: box-shadow var(--t-base) var(--ease-out), transform var(--t-micro) var(--ease-out); }
input[type=checkbox]:active, input[type=radio]:active { transform: scale(.9); }
/* paleta kolorów grupy: swatch rośnie na hover, pierścień wyboru „rozchodzi się", ptaszek wskakuje */
.swatch span { transition: box-shadow var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out); }
@media (hover: hover) { .swatch:hover span { transform: scale(1.08); } }
.swatch input:checked + span::after { animation: check-in var(--t-fast) var(--ease-out) both; }
/* przełączniki .inline-check / zgoda: kolory 140 ms */
.inline-check, .child-group-check, .consent { transition: background-color var(--t-fast) var(--ease-standard), border-color var(--t-fast) var(--ease-standard); }
/* komunikaty statusu: wejście fade + 4 px; błąd — krótkie „potrząśnięcie" jak pole hasła w macOS */
.sms-status:not(:empty), .banner:not(:empty) { animation: panel-in var(--t-base) var(--ease-out) both; }
.sms-status.error { animation: shake 320ms var(--ease-in-out) both; }

/* ============================================================
   12. SKELETON — shimmer 1.4 s linear infinite (jedyna pętla); tło definiują style.css / rodzic.css
   ============================================================ */
.skeleton { background-size: 200% 100%; animation: skel 1.4s linear infinite; }

/* ============================================================
   13. LANDING / LOGOWANIE — schodkowe wejście logo → CTA (łącznie ≤ 480 ms)
   ============================================================ */
/* fill-mode backwards: po zakończeniu wejścia transform wraca do kaskady, więc hover (translateY -1 px) działa */
.arton-logo-lg { animation: logo-in 480ms var(--ease-out) backwards; }
.landing-title, .landing-sub { animation: view-in var(--t-enter) var(--ease-out) 80ms backwards; }
.landing-actions a { animation: view-in var(--t-slow) var(--ease-out) backwards; }
.landing-actions a:nth-child(1) { animation-delay: 80ms; }
.landing-actions a:nth-child(2) { animation-delay: 160ms; }
.landing-actions a:nth-child(3) { animation-delay: 240ms; }
body.auth-page .panel { animation: modal-in var(--t-slow) var(--ease-out) backwards; }
/* ekran sukcesu zapisów: kółko z ptaszkiem wskakuje */
#step-done .done-ico { animation: check-in var(--t-slow) var(--ease-spring) backwards; }
/* linki powrotu: chevron przesuwa się o 2 px */
a .ui, button .ui { transition: transform var(--t-fast) var(--ease-out); }
@media (hover: hover) {
  #link-back-login:hover .ui, .rodo-back:hover .ui, .btn-back:hover .ui { transform: translateX(-2px); }
  .city-btn:hover .ui, .tile-btn:hover .ui { transform: translateX(2px); }
}

/* ============================================================
   14. REDUKCJA RUCHU — zerujemy tokeny i wszystkie czasy; każdy keyframe kończy się stanem statycznym,
       więc nic nie znika ani nie stoi przesunięte. Animacje wyjścia (modal, toast) wciąż wywołują animationend
       (.01 ms), więc JS chowa elementy natychmiast.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  :root { --t-micro: 0ms; --t-fast: 0ms; --t-base: 0ms; --t-enter: 0ms; --t-slow: 0ms; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  .skeleton { animation: none !important; }
  #parents-refresh.is-busy .ui, #parents-refresh.is-busy .ico { animation: none !important; }
  #signup-submit.is-busy::after, #reset-req-btn.is-busy::after, #reset-confirm-btn.is-busy::after { animation: none !important; border-top-color: rgba(255, 255, 255, .45); }
  .sms-status.error { animation: none !important; }
  header, .portal-head, #bottom-nav, .modal-backdrop, .toast, .child-tabs { -webkit-backdrop-filter: none; backdrop-filter: none; }
  #bottom-nav { background: #fff; }
  header, .portal-head { background: var(--header-bg) var(--header-grad); }
  .modal-backdrop { background: rgba(var(--ink), .45); }
  .toast { background: var(--lav-900); }
}
