/* T024.A.4 — wspolne UI tokens portowane z ux-html/assets/app.css.
 *
 * Inline'owany w base.html jako <link rel="stylesheet">. Cache-friendly
 * (oddzielny plik, nie inline w kazdym renderze).
 *
 * Konwencja prefiksu `wp-` (weryfikatorpartnera) zachowana - latwo
 * grep'ujemy bo nie kolidujemy z Tailwind utilities.
 *
 * NOTE: focus rings sa juz w `tailwind.css` (przez @tailwind base + ring
 * utilities). Skipujemy bo dublowalibysmy.
 */

/* ============================================================
 * SCROLLBARS — cienkie, neutralne
 * ============================================================ */
.wp-scroll {
  scrollbar-width: thin;
  scrollbar-color: #d1d5db transparent;
}
.wp-scroll::-webkit-scrollbar { width: 8px; height: 8px; }
.wp-scroll::-webkit-scrollbar-track { background: transparent; }
.wp-scroll::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 4px; }
.wp-scroll::-webkit-scrollbar-thumb:hover { background: #9ca3af; }

/* ============================================================
 * ANIMATIONS — keyframes uzywane w skeletonach + slide-in
 * ============================================================ */
@keyframes wpFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes wpSlideUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes wpSlideInRight { from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: translateX(0); } }
@keyframes wpSlideInLeft  { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: translateX(0); } }
@keyframes wpPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
@keyframes wpShimmer { 0% { background-position: -1000px 0; } 100% { background-position: 1000px 0; } }

.wp-fade-in { animation: wpFadeIn .2s ease both; }
.wp-slide-up { animation: wpSlideUp .25s ease both; }
.wp-slide-in-right { animation: wpSlideInRight .2s ease both; }
.wp-slide-in-left { animation: wpSlideInLeft .2s ease both; }

/* ============================================================
 * SKELETON LOADING — shimmer placeholder dla async UI
 * ============================================================ */
.skeleton {
  background: linear-gradient(90deg, #f3f4f6 0px, #e5e7eb 40px, #f3f4f6 80px);
  background-size: 1000px 100%;
  animation: wpShimmer 1.6s linear infinite;
  border-radius: 4px;
}
.skeleton-text { height: 0.875rem; border-radius: 4px; }
.skeleton-text-lg { height: 1.25rem; border-radius: 4px; }
.skeleton-circle { border-radius: 9999px; }
.skeleton-card {
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 1.25rem;
}

/* WCAG 2.1 — szanujemy preferencje system zezwala na rezygnacje z animacji. */
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; background: #f3f4f6; }
  .wp-fade-in, .wp-slide-up, .wp-slide-in-right, .wp-slide-in-left { animation: none; }
}

/* ============================================================
 * KBD — klawisze w UI (skroty, np. ⌘K dla cmd+k)
 * ============================================================ */
.wp-kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
  height: 18px;
  min-width: 18px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  font-weight: 600;
  color: #374151;
  background: #fff;
  border: 1px solid #d1d5db;
  border-bottom-width: 2px;
  border-radius: 4px;
}

/* ============================================================
 * STATUS DOTS — wskazniki statusu (sidebar quotas, badges, etc.)
 * Mapowanie kolorow: ok=success, warn=warning, err=danger, info=info
 * tailwind tokens (apps/api/tailwind.config.js T193).
 * ============================================================ */
.wp-dot { display: inline-block; width: 8px; height: 8px; border-radius: 9999px; }
.wp-dot-ok    { background: #10b981; }
.wp-dot-warn  { background: #f59e0b; }
.wp-dot-err   { background: #ef4444; }
.wp-dot-info  { background: #3b82f6; }
.wp-dot-pulse { animation: wpPulse 1.6s ease-in-out infinite; }

/* ============================================================
 * BLOBS — gradientowe tlo (hero landingu, login, onboarding)
 * Animowane translate, slow loop.
 * ============================================================ */
@keyframes wpFloat  { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(20px, -30px); } }
@keyframes wpFloat2 { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(-30px, 20px); } }
.blob1 { animation: wpFloat 14s ease-in-out infinite; }
.blob2 { animation: wpFloat2 18s ease-in-out infinite; }

/* WCAG: wylacz blob animacje przy reduce-motion. */
@media (prefers-reduced-motion: reduce) {
  .blob1, .blob2 { animation: none; }
}

/* ============================================================
 * TABLE — clickable rows (wspolny pattern w listach kontrahentow)
 * ============================================================ */
.wp-table-row-clickable { cursor: pointer; transition: background-color .12s ease; }
.wp-table-row-clickable:hover { background: #f9fafb; }

/* ============================================================
 * HTMX REQUEST STATES — T024.L1 visual feedback dla in-flight requests
 * ============================================================
 * Bez tego user widzi "klik nic sie nie dzieje" zanim swap przyjdzie.
 * HTMX automatycznie dodaje .htmx-request klase na element + descendants
 * w czasie request lifecycle. Tu styling: opacity + pointer-events.
 *
 * Per-button .htmx-indicator (loading spinner widget) jest osobne — to
 * jest GLOBAL fallback dla elements ktore nie maja explicit spinner.
 */
.htmx-request,
.htmx-request.htmx-swapping {
  opacity: 0.7;
  pointer-events: none;
  cursor: wait;
  transition: opacity .15s ease;
}

/* Buttons z explicit htmx-indicator — pelna opacity, spinner widoczny. */
button.htmx-request:has(.htmx-indicator),
.btn.htmx-request:has(.htmx-indicator) {
  opacity: 1;
}

/* Reduced motion — skip transition. */
@media (prefers-reduced-motion: reduce) {
  .htmx-request, .htmx-request.htmx-swapping { transition: none; }
}

/* ============================================================
 * FOCUS VISIBLE RINGS — T024.E1 WCAG 2.4.7 audit fix
 * ============================================================
 * 128 instances .btn-ghost w templates miały subtle (lub żaden)
 * focus state. WCAG 2.4.7 Level AA wymaga 'Focus Visible'.
 *
 * `:focus-visible` (NIE :focus) — ring tylko przy keyboard navigation.
 */
.btn.btn-ghost:focus-visible,
.btn.btn-outline:focus-visible,
.btn-ghost:focus-visible {
  outline: 2px solid #059669;  /* emerald-600, sync z skip link */
  outline-offset: 2px;
  border-radius: 6px;
}

.link:focus-visible {
  outline: 2px solid #059669;
  outline-offset: 2px;
  text-decoration: underline;
}

.btn[disabled]:focus-visible,
button[disabled]:focus-visible {
  outline: none;
}

/* ============================================================
 * SIDEBAR COLLAPSE LAYOUT — T026.I
 * ============================================================
 * BUGFIX 2026-05-17: te reguły były inline `<style nonce>` w
 * `app_base.html` `{% block layout %}` — czyli w `<body>`. `hx-boost`
 * wymienia `<body>`, więc swapnięty `<style>` dostawał NOWY per-request
 * nonce, podczas gdy CSP dokumentu wciąż miał STARY nonce z pierwszego
 * pełnego load → przeglądarka BLOKOWAŁA `<style>`. Efekt: po każdej
 * nawigacji hx-boost `.kc-content-shell` tracił `margin-left` (sidebar
 * nachodził na treść) a collapse się "zacinał" (brak reguł width).
 * External CSS w `<head>` nie podlega nonce i `<head>` nie jest
 * swapowany → reguły stabilne przez wszystkie nawigacje.
 *
 * `--kc-sidebar-w` = jedno źródło prawdy: szerokość sidebaru ORAZ
 * margines content-shell. Collapse aktywny tylko desktop (≥768px);
 * mobile ma slide-in (Alpine `sidebarOpen`).
 */
:root { --kc-sidebar-w: 16rem; }
html.sidebar-collapsed { --kc-sidebar-w: 4rem; }

@media (min-width: 768px) {
  .kc-content-shell { margin-left: var(--kc-sidebar-w); transition: margin-left .2s ease; }
  .kc-sidebar { transition: width .2s ease; }
  html.sidebar-collapsed .kc-sidebar { width: 4rem; }
  html.sidebar-collapsed .kc-sidebar .kc-sidebar-label { display: none; }
  html.sidebar-collapsed .kc-sidebar nav > div > ul > li > a,
  html.sidebar-collapsed .kc-sidebar nav > div > div > a { justify-content: center; }
  html.sidebar-collapsed .kc-sidebar .kc-collapse-toggle svg { transform: rotate(180deg); }
}

@media (prefers-reduced-motion: reduce) {
  .kc-content-shell, .kc-sidebar { transition: none; }
}

/* ─────────────────────────────────────────────────────────────────────────
 * T026.UI3 batch 4 — onboarding wizard (`/onboarding/welcome`).
 * Przeniesione z inline <style nonce> w onboarding/welcome.html — inline
 * <style> w <body> blokowany przez CSP po hx-boost swapie. Klasy `wiz-*`
 * scope'owane → globalny load w app.css bez efektów ubocznych.
 */
@keyframes wizfloat  { 0%,100% { transform: translate(0,0); } 50% { transform: translate(20px,-30px); } }
@keyframes wizfloat2 { 0%,100% { transform: translate(0,0); } 50% { transform: translate(-30px,20px); } }
.wiz-tile { transition: border-color .15s, transform .15s, box-shadow .15s; }
.wiz-tile:hover { transform: translateY(-2px); box-shadow: 0 8px 24px -8px rgba(0,0,0,.12); }
.wiz-tile[aria-pressed="true"] { border-color: #059669; background: #ecfdf5; }
.wiz-tile[aria-pressed="true"] .wiz-tile-icon { background: #059669; color: #fff; }
.wiz-plan { transition: border-color .15s, box-shadow .15s; }
.wiz-plan[aria-pressed="true"] { border-color: #059669; box-shadow: 0 0 0 3px #d1fae5; }


/* ─────────────────────────────────────────────────────────────────────────
 * TD-S4 — Touch targets ≥44×44px na mobile (WCAG 2.5.5 AAA, Apple HIG).
 *
 * 19+ wystąpień `btn-xs` (~24-28px) w admin/settings tabelach + modal close
 * buttons z `size-5` (20px) są poniżej WCAG 2.5.5 AA (24×24) i Apple HIG
 * (44pt minimum). Na desktop trzymamy gęste UI; mobile-only override
 * zachowuje compact layout > 640px.
 * ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  .btn-xs,
  .btn-sm.btn-square,
  .btn-square.btn-xs {
    min-height: 44px;
    min-width: 44px;
    padding-left: 0.625rem;
    padding-right: 0.625rem;
  }

  /* Close buttons w modałach (NPS, share, dziel, cancel-survey) używają
   * `size-5` SVG bez padding → łatwo trafić obok na mobile.
   */
  button.size-5,
  button[aria-label="Zamknij"],
  button[aria-label="Close"] {
    min-height: 44px;
    min-width: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Icon-only buttons w sidebarze / topbarze (theme toggle, bell, avatar). */
  button[aria-label]:not([aria-label=""]):empty,
  .btn-ghost.btn-circle.btn-sm {
    min-height: 44px;
    min-width: 44px;
  }
}

/* ─────────────────────────────────────────────────────────────────────────
 * TD-S1 — Safe area insets (iPhone 14+ Dynamic Island, notch, home bar).
 *
 * Bez tych regół `position: sticky/fixed` topbar/sidebar zachodzi pod
 * Dynamic Island na iOS Safari. Wymagane też `viewport-fit=cover` w meta
 * (już dodane w base.html).
 *
 * Konwencja: target'ujemy konkretne selektory (sticky topbar, fixed
 * hamburger, fixed sidebar) zamiast globalnego `*` — wąsko, deterministyczne.
 * Trick `max(default, env())` daje fallback dla przeglądarek bez env() support.
 * ───────────────────────────────────────────────────────────────────────── */

/* Sticky topbar (apps/api/templates/components/_topbar.html:29 + navbar.html). */
header.sticky.top-0,
header.sticky[class*="top-0"] {
  padding-top: max(0px, env(safe-area-inset-top));
}

/* Mobile hamburger (apps/api/templates/components/_sidebar.html:57 — top-3 left-3). */
.kc-sidebar-toggle,
button[aria-controls="sidebar"].fixed {
  top: max(0.75rem, calc(0.75rem + env(safe-area-inset-top)));
  left: max(0.75rem, calc(0.75rem + env(safe-area-inset-left)));
}

/* Sidebar drawer (apps/api/templates/components/_sidebar.html:72 — fixed h-screen). */
.kc-sidebar.fixed {
  padding-top: max(0px, env(safe-area-inset-top));
  padding-bottom: max(0px, env(safe-area-inset-bottom));
  padding-left: max(0px, env(safe-area-inset-left));
}

/* Bottom-anchored elements (cookie banner, FAB, sticky CTA). */
.safe-area-bottom,
[data-safe-area="bottom"] {
  padding-bottom: max(1rem, calc(1rem + env(safe-area-inset-bottom)));
}

/* Maintenance banner sticky-top (apps/api/templates/components/maintenance_banner.html). */
.alert.sticky.top-0,
.alert.sticky[class*="top-0"] {
  padding-top: max(0.75rem, env(safe-area-inset-top));
}

/* ─────────────────────────────────────────────────────────────────────────
 * TD-S2 — iOS Safari auto-zoom fix (mobile-only, ≤640px).
 *
 * Problem: iOS Safari ZAWSZE auto-zoom'uje viewport gdy user tap'nie input/
 * select/textarea o computed font-size < 16px. Reset zoom wymaga pinch
 * out — destruction UX, szczególnie na onboarding wizard (NIP field
 * = `text-sm` 14px), topbar search, import row edit, share modal email.
 *
 * Fix: mobile-only `!important` media query — wymusza ≥16px na wszystkie
 * inputy w viewporcie ≤640px (Tailwind `sm:` breakpoint). Desktop
 * NIE dotknięty (sm:text-sm normalnie renderowane).
 *
 * Why !important: Tailwind utility classes (`text-xs`, `text-sm`) mają
 * wysoką specificity przez selector chain (rare edge gdy theme'y w app
 * przepiszą). `!important` w global CSS najprostsze niż refactor 4+
 * miejsc inline.
 *
 * Reference: https://stackoverflow.com/a/6394497
 * Audyt 2026-05-25: 4 miejsca <16px na mobile:
 *   - `components/_topbar.html:79` topbar search
 *   - `import/_row.html:45` import row email/NIP edit
 *   - `contractors/report/_share_modal.html:138` share email
 *   - `profil/index.html:51` profile fields
 */
@media (max-width: 640px) {
  input,
  select,
  textarea {
    font-size: 16px !important;
  }
}
