/**
 * Overlay V3 — strona /{slug}/v3
 * Kompletny redesign: piękny UI, użyteczny UX, desktop + mobile.
 * Uses CSS variables z variables.css (--color-*, --space-*, --radius-*, --font-family).
 */

/* ════════════════════════════════════════════════════════
   ROOT
   ════════════════════════════════════════════════════════ */
.omv3 {
    --omv3-radius: 16px;
    --omv3-radius-sm: 10px;
    --omv3-border: rgba(15, 23, 42, 0.07);
    --omv3-border-strong: rgba(15, 23, 42, 0.14);
    --omv3-bg-card: #ffffff;
    --omv3-bg-soft: rgba(15, 23, 42, 0.04);
    /* Tekst hardcoded slate-900 (#0F172A) — NIE używamy var(--color-black) bo
       variables.css ma `[data-theme="dark"] { --color-black: #E8E8F0 }` (jasny
       w dark mode strony). V3 jest zawsze light, więc tekst musi być zawsze
       slate-900 niezależnie od globalnego data-theme. */
    --omv3-text: #0F172A;
    --omv3-text-soft: rgba(15, 23, 42, 0.72);
    --omv3-text-muted: rgba(15, 23, 42, 0.50);

    /* Akcent strony jako RGB — używany w gradientach tła i wszystkich efektach
       wybranego stanu. View nadpisuje wartość z ColorExtractor::generatePalette. */
    --omv3-accent-rgb: 124, 92, 252;

    /* CTA download — jedyny element z subtelnym glow akcentu (visual anchor) */
    --omv3-shadow-cta: 0 6px 20px rgba(var(--omv3-accent-rgb, 124, 92, 252), 0.30);

    /* Easing — Material standard + Quint out */
    --omv3-ease: cubic-bezier(0.4, 0, 0.2, 1);

    display: block;
    font-family: var(--font-family, 'Host Grotesk', system-ui, -apple-system, sans-serif);
    color: var(--omv3-text);

    /* Tło z accent gradientem — radial spot u góry, delikatne nawiązanie do koloru
       nakładki. Karty pozostają białe → naturalny kontrast bez potrzeby cieni. */
    background:
        radial-gradient(ellipse 120% 70% at 50% -10%,
            rgba(var(--omv3-accent-rgb), 0.12) 0%,
            transparent 50%),
        radial-gradient(ellipse 80% 50% at 100% 100%,
            rgba(var(--omv3-accent-rgb), 0.06) 0%,
            transparent 55%),
        linear-gradient(180deg, #F2F4FA 0%, #E8EBF2 100%);
    background-attachment: fixed;
    min-height: 100vh;
}

/* Gdy strona ma branding background-image (na body.page--v3) — nasze accent-gradient
   się nie miesza z bg strony. Tło zostaje przez body, .omv3 staje się transparentne. */
body.page--v3[style*="background-image"] .omv3,
body.page--v3.has-branding-bg .omv3 {
    background: transparent;
    background-attachment: initial;
}

/* Wymusza ukrywanie elementów z atrybutem `hidden` (display:flex/grid zjada display:none). */
.omv3 [hidden] { display: none !important; }

/* ════════════════════════════════════════════════════════
   ANIMATION STRATEGY — minimalne, paint-free, GPU-only
   ════════════════════════════════════════════════════════
   Reguły:
   1. Transitions wyłącznie na `transform` i `opacity` (GPU-composited).
      Border-color/background-color/box-shadow → INSTANT change (browser
      nigdy nie animuje paint property po słabszej karcie graficznej).
   2. `will-change` — TYLKO przy aktywnym hover/focus (nie permanentnie —
      permanentne rezerwowanie layerów wyczerpuje pamięć GPU).
   3. `translate3d(0,0,0)` na elementach z transform-hover — wymusza
      composite layer od startu (bez kosztu reflow w trakcie hover). */
.omv3__thumb,
.omv3__group-card,
.omv3__download,
.omv3__upload {
    transform: translate3d(0, 0, 0);
}

/* Container */
.omv3__shell {
    max-width: 1200px;
    margin: 0 auto;
    /* Minimalne marginesy nad/pod modułem — żeby nie przyklejało się do hero/stopki.
       Dolne 120px na space dla mobile sticky CTA. */
    padding: 24px 16px 120px;
}
@media (min-width: 720px) {
    .omv3__shell { padding: 32px 24px 64px; }
}

/* ════════════════════════════════════════════════════════
   HERO HEADER
   ════════════════════════════════════════════════════════ */
.omv3__hero {
    text-align: center;
    margin-bottom: 28px;
}
.omv3__hero-logo {
    display: inline-flex; align-items: center; justify-content: center;
    width: 76px; height: 76px;
    margin: 0 auto 14px;
    padding: 10px;
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: 18px;
}
.omv3__hero-logo img {
    max-width: 100%; max-height: 100%;
    object-fit: contain;
}
.omv3__hero-title {
    margin: 0;
    font-size: clamp(24px, 4.5vw, 38px);
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: var(--omv3-text);
}
.omv3__hero-desc {
    margin: 10px auto 0;
    max-width: 580px;
    font-size: clamp(14px, 2.3vw, 16px);
    line-height: 1.55;
    color: var(--omv3-text-soft);
}
.omv3__hero-meta {
    list-style: none;
    margin: 18px 0 0;
    padding: 0;
    display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;
}
.omv3__hero-pill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px;
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    color: var(--omv3-text-soft);
}
.omv3__hero-pill span { font-size: 14px; line-height: 1; }

/* Banners — top/bottom inline w kolumnie content */
.omv3__banner {
    margin: 20px 0;
    border-radius: var(--omv3-radius);
    overflow: hidden;
}
.omv3__banner-img { display: block; width: 100%; height: auto; }

/* Side banners — float w 4 narożnikach na desktopie. Ukryte na mobile (< 1100px)
   żeby nie zaśmiecały małych ekranów. Position fixed względem viewport. */
.omv3__sidebar-banner {
    position: fixed;
    z-index: 5;
    max-width: 160px;
    max-height: 240px;
    pointer-events: none;
    user-select: none;
}
.omv3__sidebar-banner img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--omv3-radius-sm);
}
.omv3__sidebar-banner--lt { top: 90px;     left: 16px; }
.omv3__sidebar-banner--lb { bottom: 16px;  left: 16px; }
.omv3__sidebar-banner--rt { top: 90px;     right: 16px; }
.omv3__sidebar-banner--rb { bottom: 16px;  right: 16px; }
@media (max-width: 1280px) {
    .omv3__sidebar-banner { display: none; }
}

/* Group picker — w controls column, kwadratowe miniaturki w gridzie */
.omv3__section-label {
    margin: 0 0 10px;
    font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--omv3-text-muted);
}
.omv3__groups-grid {
    display: grid;
    /* Min 96px / max 1fr — większe pudełka gdy zestaw mały (2-3 grupy),
       auto-fill gdy więcej (np. 6+ → automatycznie zwija do 2-3 kolumn). */
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 8px;
}
/* Gdy zestawy ≤3: ogranicz max-szerokość kafelka żeby nie puchły */
.omv3__card--groups[data-count="2"] .omv3__groups-grid,
.omv3__card--groups[data-count="3"] .omv3__groups-grid {
    grid-template-columns: repeat(auto-fill, minmax(110px, 140px));
}
.omv3__group-card {
    position: relative;
    aspect-ratio: 1 / 1;
    background: var(--omv3-bg-soft);
    border: 2px solid transparent;
    border-radius: var(--omv3-radius-sm);
    overflow: hidden;
    cursor: pointer;
    padding: 0;
    transition: transform 160ms var(--omv3-ease);
}
.omv3__group-card img {
    display: block;
    width: 100%; height: 100%;
    object-fit: cover;
    background: var(--omv3-bg-soft);
}
.omv3__group-card-fallback {
    display: flex; align-items: center; justify-content: center;
    width: 100%; height: 100%;
    background: var(--omv3-bg-soft);
    font-size: 22px;
}
.omv3__group-card:hover:not(.is-active) {
    transform: translate3d(0, -2px, 0);
    border-color: rgba(var(--omv3-accent-rgb), 0.45);
}
.omv3__group-card.is-active {
    border-color: var(--color-primary);
}
.omv3__group-card.is-active::after {
    content: "✓";
    position: absolute; top: 4px; right: 4px;
    width: 18px; height: 18px;
    background: var(--color-primary);
    color: #fff;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 10px; font-weight: 700;
}
/* Zestaw zablokowany tierem — kafelek wyszarzony + kłódka SVG (ten sam znak
   co pille „Co pobrać" i miniatury formatów). Klik → upsell (limit-nudge). */
.omv3__group-card.is-locked {
    opacity: 0.72;
    cursor: pointer;
}
.omv3__group-card.is-locked img,
.omv3__group-card.is-locked .omv3__group-card-fallback {
    filter: grayscale(0.5);
}
.omv3__group-card.is-locked:hover {
    transform: translate3d(0, -2px, 0);
    border-color: rgba(var(--omv3-accent-rgb), 0.45);
    opacity: 0.9;
}
.omv3__group-card-lock {
    position: absolute;
    top: 4px; right: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px; height: 20px;
    background: var(--omv3-bg-card);
    border: 1.5px solid var(--omv3-border-strong);
    border-radius: 6px;
    color: var(--omv3-text-muted);
    z-index: 3;
    pointer-events: none;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.10);
}
.omv3__group-card-lock svg { display: block; opacity: 0.85; }
/* Gdy zestaw zablokowany JEST aktywny (np. admin ustawił domyślny na płatny)
   — kłódka wygrywa nad znacznikiem ✓, żeby nie sugerować „wybrany/gotowy". */
.omv3__group-card.is-locked.is-active::after { content: none; }

/* ── Linked page: source filter pills + source badges na group cards ── */
.omv3__source-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 12px;
    padding: 6px;
    background: var(--omv3-bg-soft);
    border-radius: 10px;
}
.omv3__source-filter-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: transparent;
    border: 0;
    border-radius: 7px;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    color: var(--omv3-text-soft);
    cursor: pointer;
    transition: background-color 140ms ease, color 140ms ease;
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.omv3__source-filter-btn:hover { background: var(--omv3-bg-card); color: var(--omv3-text); }
.omv3__source-filter-btn.is-active {
    background: var(--color-primary);
    color: var(--color-primary-text, #fff);
}
.omv3__source-filter-count {
    background: rgba(15,23,42,0.10);
    padding: 1px 6px;
    border-radius: 9px;
    font-size: 10px;
    font-weight: 700;
    flex-shrink: 0;
}
.omv3__source-filter-btn.is-active .omv3__source-filter-count {
    background: rgba(255,255,255,0.22);
    color: inherit;
}

/* Source label badge na group card (bottom-left) */
.omv3__group-card-source-badge {
    position: absolute;
    bottom: 4px; left: 4px;
    background: rgba(15,23,42,0.78);
    color: #fff;
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 9px;
    font-weight: 600;
    max-width: calc(100% - 12px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    backdrop-filter: blur(4px);
}
/* Card hiding by source filter — robione przez JS */
.omv3__group-card.is-source-hidden { display: none; }

/* ════════════════════════════════════════════════════════
   GRID — desktop: 2 col | mobile: stack z reorderem
   ════════════════════════════════════════════════════════
   Mobile flow (user feedback: "kolejność elementów nieintuicyjna"):
     1. Upload / Canvas (preview top)
     2. Group picker (od razu po canvasie — wybór nakładki)
     3. Settings card (imię, wariant, format, watermark, co pobrać)
     4. Download CTA inline (zanim sticky bottom)
     5. Contact link
     6. Gallery "Podgląd wszystkich formatów" — na końcu, jako bonus

   Realizacja: na mobile `.omv3__preview` i `.omv3__controls` mają
   `display: contents` żeby ich dzieci stały się bezpośrednimi dziećmi
   gridu i można im przydzielić `order`. Na desktop (>=900px) wracamy
   do klasycznego 2-col layoutu. */
.omv3__grid {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.omv3__grid > .omv3__preview,
.omv3__grid > .omv3__controls {
    display: contents;
}
/* Mobile order — preview children first, then controls children, gallery last */
.omv3__upload-wrap   { order: 1; }
.omv3__crop          { order: 2; }
.omv3__canvas        { order: 3; }
.omv3__card--groups  { order: 4; }
.omv3__card--settings{ order: 5; }
.omv3__download-wrap { order: 6; }
.omv3__error,
#omDlError           { order: 7; }
.omv3__contact-link  { order: 8; }
.omv3__gallery       { order: 9; }

@media (min-width: 900px) {
    /* Desktop: classic 2-col layout, preview left + controls right (sticky).
       Reset display:contents → wracamy do flex columns wewnątrz sekcji. */
    .omv3__grid {
        display: grid;
        grid-template-columns: minmax(0, 0.85fr) minmax(360px, 1.15fr);
        gap: 24px;
        align-items: start;
    }
    .omv3__grid > .omv3__preview {
        display: flex; flex-direction: column; gap: 16px; min-width: 0;
    }
    .omv3__grid > .omv3__controls {
        display: flex; flex-direction: column; gap: 12px; min-width: 0;
    }
    /* Reset order — desktop używa DOM order */
    .omv3__upload-wrap, .omv3__crop, .omv3__canvas,
    .omv3__card--groups, .omv3__card--settings,
    .omv3__download-wrap, .omv3__error, #omDlError,
    .omv3__contact-link, .omv3__gallery { order: 0; }
}

/* ════════════════════════════════════════════════════════
   PREVIEW COLUMN
   ════════════════════════════════════════════════════════ */
.omv3__preview {
    display: flex; flex-direction: column; gap: 16px;
    min-width: 0;
}

/* Upload wrapper */
.omv3__upload-wrap {
    display: block;
}

/* Upload zone — czysta, biała karta z dashed borderem; transform-only animacja */
.omv3__upload {
    position: relative;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    aspect-ratio: 1 / 1;
    width: 100%;
    padding: 24px;
    background: var(--omv3-bg-card);
    border: 2px dashed var(--omv3-border-strong);
    border-radius: var(--omv3-radius);
    text-align: center;
    cursor: pointer;
    transition: transform 180ms var(--omv3-ease);
    overflow: hidden;
}
.omv3__upload::before {
    content: "";
    position: absolute; inset: 0;
    background: radial-gradient(circle at 50% 40%,
        rgba(var(--omv3-accent-rgb), 0.10), transparent 65%);
    opacity: 0; pointer-events: none;
    transition: opacity 180ms var(--omv3-ease);
}
.omv3__upload:hover, .omv3__upload:focus-visible,
.omv3__upload.is-drag {
    border-color: var(--color-primary);
    transform: translate3d(0, -2px, 0);
    outline: none;
}
.omv3__upload:hover::before, .omv3__upload.is-drag::before { opacity: 1; }
.omv3__upload-icon {
    width: 56px; height: 56px;
    margin-bottom: 10px;
    display: flex; align-items: center; justify-content: center;
    background: rgba(var(--omv3-accent-rgb), 0.12);
    color: var(--color-primary);
    border-radius: 50%;
    transition: transform 180ms var(--omv3-ease);
}
.omv3__upload-icon svg { width: 28px; height: 28px; }
.omv3__upload:hover .omv3__upload-icon, .omv3__upload.is-drag .omv3__upload-icon {
    transform: scale3d(1.08, 1.08, 1);
    background: var(--color-primary);
    color: #fff;
}
.omv3__upload-title {
    margin: 0 0 2px;
    font-size: 15px; font-weight: 700;
    color: var(--omv3-text);
}
.omv3__upload-sub {
    margin: 0 0 10px;
    font-size: 13px;
    color: var(--omv3-text-soft);
}
.omv3__upload-formats {
    margin: 0;
    padding: 3px 10px;
    background: var(--omv3-bg-soft);
    border-radius: 6px;
    font-size: 10px; font-weight: 600;
    color: var(--omv3-text-muted);
    letter-spacing: 0.06em;
}
/* Privacy info wewnątrz upload zone — subtle pod listą formatów */
.omv3__upload-privacy {
    display: flex; align-items: center; justify-content: center; gap: 6px;
    margin: 14px 0 0;
    font-size: 12px;
    color: var(--omv3-text-muted);
    line-height: 1.4;
    text-align: center;
}
.omv3__upload-privacy svg { flex-shrink: 0; }
.omv3__upload-privacy strong {
    color: var(--omv3-text-soft);
    font-weight: 700;
}

/* Canvas — po wgraniu zdjęcia. Subtle gray bg (zamiast mylącego chess pattern). */
.omv3__canvas {
    position: relative;
    background: var(--omv3-bg-soft);
    border: 1px solid var(--omv3-border);
    border-radius: var(--omv3-radius);
    overflow: hidden;
    animation: omv3FadeIn 240ms var(--omv3-ease);
}
.omv3__canvas canvas {
    display: block;
    width: 100%;
    height: auto;
    background: transparent;
    /* Płynna zmiana proporcji przy przełączaniu wariantu (np. 1:1 → 9:16).
       Engine ustawia inline `aspect-ratio: w/h`, transition tutaj interpoluje
       między wartościami zamiast pozwolić na ostry skok wymiarów. */
    transition: aspect-ratio 280ms cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes omv3FadeIn {
    from { opacity: 0; transform: translate3d(0, 8px, 0); }
    to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* Snapshot overlay dla płynnego przejścia jasny↔ciemny (i zmiany zestawu).
   JS robi zrzut canvasu jako <img>, kładzie nad canvasem, w tle re-render
   canvasu, potem klasa .is-fading-out animuje opacity → 0.
   Pozycja/wymiary ustawiane inline z getBoundingClientRect. */
.omv3__fade-snapshot {
    opacity: 1;
    transition: opacity 220ms cubic-bezier(0.4, 0, 0.2, 1);
}
.omv3__fade-snapshot.is-fading-out {
    opacity: 0;
}

/* Anti-extraction guard — blokuje drag-and-drop, native image callout (iOS),
   text selection. JS dokłada contextmenu/dragstart preventDefault listenery.
   Razem: prawy klik nie ma menu "Zapisz obraz", long-press na mobile
   nie pokazuje share-sheet, nie da się przeciągnąć canvasu do innego okna. */
.omv3__protected {
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    -webkit-user-drag: none;
    -khtml-user-drag: none;
    -moz-user-drag: none;
    -o-user-drag: none;
    user-drag: none;
}

/* Toast informacyjny pokazywany przy próbie prawego kliku / drag.
   Pozycjonowany sticky-bottom-center, znika po 2.4s. */
.omv3__protect-toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translate3d(-50%, 20px, 0);
    z-index: 9999;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    background: rgba(15, 23, 42, 0.92);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: #fff;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 500;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.25);
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms ease-out, transform 220ms cubic-bezier(0.4, 0, 0.2, 1);
}
.omv3__protect-toast.is-visible {
    opacity: 1;
    transform: translate3d(-50%, 0, 0);
}
.omv3__protect-toast svg {
    flex-shrink: 0;
    opacity: 0.85;
}
.omv3__protect-toast strong {
    font-weight: 700;
}

/* DevTools detected (size-diff heuristic, hysteresis 2 sample'y).
   Rozmywa canvas + thumby + crop image — skilled user może zdjąć przez
   element.classList.remove(), ale wtedy świadomie omija. */
body.omv3-devtools-open .omv3__canvas canvas,
body.omv3-devtools-open .omv3__thumb canvas,
body.omv3-devtools-open #om-crop-img,
body.omv3-devtools-open .omv3__upload {
    filter: blur(24px) saturate(0.4);
    transition: filter 280ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Offline copy / wrong origin — strona zapisana lokalnie (file://) lub
   otwarta z innej domeny. Blokuje cały moduł + pełnoekranowy overlay
   z linkiem do canonical site. */
body.omv3-offline-copy .omv3__shell {
    filter: blur(12px) saturate(0.3);
    pointer-events: none;
    user-select: none;
}
body.omv3-offline-copy::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 99998;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
body.omv3-offline-copy::after {
    content: "Ta strona musi być otwarta z nakladki.com.pl. Skopiowana lokalnie wersja nie zadziała poprawnie.";
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 99999;
    max-width: 360px;
    padding: 22px 28px;
    background: #fff;
    color: var(--omv3-text);
    border-radius: 16px;
    font-family: var(--font-family, system-ui, sans-serif);
    font-size: 14px;
    font-weight: 500;
    line-height: 1.5;
    text-align: center;
    box-shadow: 0 16px 48px rgba(15, 23, 42, 0.4);
}
.omv3__canvas-swap {
    position: absolute; top: 12px; right: 12px;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 14px;
    /* Bez backdrop-filter — kosztowny na słabszych GPU; solid bg z wystarczającym kontrastem */
    background-color: rgba(15, 23, 42, 0.88);
    color: #fff;
    border: 0; border-radius: 999px;
    font: inherit; font-size: 12px; font-weight: 600;
    cursor: pointer;
    transition: transform 140ms var(--omv3-ease),
                background-color 140ms ease-out;
}
.omv3__canvas-swap:hover { background-color: rgba(15, 23, 42, 0.96); }
.omv3__canvas-swap:active { transform: scale3d(0.96, 0.96, 1); }

/* ── Silnik V4 (M4): personalizacja kadru (pan/zoom) + opcje elementów ── */
.omv3__adjust {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    margin-top: 10px; padding: 8px 12px;
    background: var(--omv3-bg-soft, #f8fafc);
    border: 1px solid var(--omv3-border, #e2e8f0);
    border-radius: 12px;
    font-size: 12px; color: var(--omv3-text-soft, #64748b);
    animation: omv3FadeIn 240ms var(--omv3-ease);
}
.omv3__adjust-hint { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }
.omv3__adjust-zoom { display: inline-flex; align-items: center; gap: 8px; flex: 1 1 160px; min-width: 140px; }
.omv3__adjust-zoom input[type="range"] { flex: 1; accent-color: var(--omv3-accent, #7C5CFC); cursor: pointer; }
.omv3__adjust-reset {
    border: 1px solid var(--omv3-border, #e2e8f0); background: #fff;
    border-radius: 999px; padding: 4px 12px;
    font: inherit; font-size: 11px; font-weight: 700; cursor: pointer;
    color: var(--omv3-text, #0f172a);
    transition: background-color 140ms ease-out;
}
.omv3__adjust-reset:hover { background: var(--omv3-bg-soft, #f1f5f9); }
/* Drag na canvasie aktywny → kursor łapki */
.omv3__canvas.is-pannable canvas { cursor: grab; touch-action: none; }
.omv3__canvas.is-panning canvas { cursor: grabbing; }

.omv3__el-options { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.omv3__el-options-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.omv3__el-options-label { font-size: 11px; font-weight: 700; color: var(--omv3-text-soft, #64748b); text-transform: uppercase; letter-spacing: 0.04em; }
.omv3__el-chip {
    border: 1px solid var(--omv3-border, #e2e8f0); background: #fff;
    border-radius: 999px; padding: 5px 14px;
    font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
    color: var(--omv3-text, #0f172a);
    transition: border-color 140ms ease-out, background-color 140ms ease-out;
}
.omv3__el-chip.is-active {
    border-color: var(--omv3-accent, #7C5CFC);
    background: color-mix(in srgb, var(--omv3-accent, #7C5CFC) 10%, #fff);
}

/* Chip "Zdjęcie zapamiętane" — pokazywany gdy zdjęcie wczytane z sessionStorage.
   Kolor z akcentu strony (spójność z brandingiem nakładki) zamiast hardcoded green. */
.omv3__restored-chip {
    position: absolute; bottom: 12px; left: 12px;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 4px 4px 12px;
    background: rgba(15, 23, 42, 0.78);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: #fff;
    border-radius: 999px;
    font-size: 11px; font-weight: 700;
    letter-spacing: 0.02em;
    animation: omv3FadeIn 240ms var(--omv3-ease);
}
.omv3__restored-chip[hidden] { display: none !important; }
.omv3__restored-chip svg { flex-shrink: 0; }
.omv3__restored-chip-close {
    flex-shrink: 0;
    width: 20px; height: 20px;
    display: flex; align-items: center; justify-content: center;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    border: 0; border-radius: 999px;
    cursor: pointer;
    font: inherit; font-size: 14px; line-height: 1;
    padding: 0;
    transition: background-color 120ms ease-out;
}
.omv3__restored-chip-close:hover { background: rgba(255, 255, 255, 0.32); }

/* Gallery — pod canvasem w preview column. JEDNA LINIA, flex nowrap.
   Każdy thumb ma RÓWNĄ WYSOKOŚĆ canvasu (height: fixed) i SZEROKOŚĆ
   liczy się z natywnego aspect-ratio (width: auto na canvasie).
   Nakładka 1:1 = szeroka kwadratowa, story 9:16 = najwęższa wysoka. */
.omv3__gallery {
    margin-top: 4px;
}
/* Pełna szerokość lewej kolumny — CSS grid z grid-template-columns ustawianym
   dynamicznie w JS (proporcjonalnie do aspect-ratio każdego formatu).
   Trik matematyczny: jeśli grid-cols = AR1 AR2 ... ARn, to każdy thumb dostaje
   szerokość proporcjonalną do AR. Canvas `width:100%, height:auto` daje wtedy
   wysokość = width/AR = ten sam X dla wszystkich thumbów → RÓWNA WYSOKOŚĆ
   bez kosztu overflow. JS ustawia row.style.gridTemplateColumns w renderGallery. */
.omv3__gallery-grid {
    display: grid;
    /* Fallback — JS nadpisuje na podstawie payloadu. Pasuje do 4-formatowego zestawu */
    grid-template-columns: 1fr 1fr 0.75fr 0.5625fr;
    gap: 8px;
    align-items: end;
    width: 100%;
}
.omv3__thumb {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;              /* żeby grid nie wybuchł */
    background: var(--omv3-bg-card);
    border: 2px solid var(--omv3-border);
    border-radius: var(--omv3-radius-sm);
    overflow: hidden;
    cursor: pointer;
    padding: 0;
    font: inherit;
    transition: transform 160ms var(--omv3-ease);
}
.omv3__thumb:hover:not(.is-active) {
    transform: translate3d(0, -2px, 0);
    border-color: rgba(var(--omv3-accent-rgb), 0.45);
}
.omv3__thumb.is-active {
    border-color: var(--color-primary);
    background-color: rgba(var(--omv3-accent-rgb), 0.06);
}
/* Canvas: width=100% (szerokość z grid column), height=auto (z natywnego
   aspect-ratio canvasu). Matematyka grida (AR-proportional columns) gwarantuje
   że wszystkie thumby kończą z TĄ SAMĄ wysokością bez ustawiania jej explicite. */
.omv3__thumb canvas {
    display: block;
    width: 100%;
    height: auto;
    background: var(--omv3-bg-soft);
}
.omv3__thumb-label {
    padding: 5px 6px;
    font-size: 11px; font-weight: 700; text-align: center;
    color: var(--omv3-text);
    background: var(--omv3-bg-card);
    border-top: 1px solid var(--omv3-border);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    width: 100%;
    box-sizing: border-box;
}

/* Mobile — mniejszy gap i fontsize label; height z grida (auto, AR-driven) */
@media (max-width: 640px) {
    .omv3__gallery-grid { gap: 4px; }
    .omv3__thumb-label { font-size: 10px; padding: 4px 3px; }
    .omv3__related-grid { grid-template-columns: repeat(3, 1fr); gap: 8px; }
    .omv3__related-card-title { font-size: 11px; }
    .omv3__contact { padding: 14px 16px; }
    .omv3__contact-title { font-size: 14px; }
    .omv3__contact-desc { font-size: 12px; }
}

/* Mobile inline gallery — galeria przeniesiona przez JS do slotu w settings card.
   Klasa nakładana dynamicznie przez `applyMobileLayout()` (variant-cards-v3.js).
   Differences vs default:
     • brak nadrzędnego top margin (siedzi w stack settings)
     • section-label ukryty (sekcja "Plik do pobrania" już ma nagłówek "Co pobrać")
     • subtelny separator nad galerią — wizualne rozdzielenie od pillsów
     • thumb is-active = "wybrany do pobrania" zamiast "aktywny preview"
   Slot wrapper na mobile dostaje margin-top żeby oddzielić od pillsów.
   Na desktopie slot jest pusty (gallery siedzi w preview), więc bez wpływu. */
.omv3__mobile-gallery-slot {
    display: contents;   /* nie rezerwuje miejsca gdy gallery nie jest w środku */
}
.omv3__gallery--mobile-inline {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px dashed var(--omv3-border);
}
.omv3__gallery--mobile-inline .omv3__section-label {
    margin-bottom: 8px;
    font-size: 10.5px;
    color: var(--omv3-text-muted);
}
/* Inline thumby — równe pole, dotykowy comfort. is-active = wybrany do pobrania,
   pełny accent ring (jak pill "Co pobrać" is-selected) zamiast subtelny ring. */
.omv3__gallery--mobile-inline .omv3__thumb {
    border-width: 2px;
}
.omv3__gallery--mobile-inline .omv3__thumb.is-active {
    border-color: var(--color-primary);
    background-color: rgba(var(--omv3-accent-rgb), 0.10);
}
/* Checkbox-like check w prawym górnym rogu thumba — wizualne potwierdzenie
   że thumb jest w "Co pobrać" selectedFormats. Pojawia się tylko na inline
   gallery (mobile), nie na desktopowej (gdzie thumb = switch preview). */
.omv3__gallery--mobile-inline .omv3__thumb::before {
    content: "";
    position: absolute;
    top: 4px; right: 4px;
    width: 18px; height: 18px;
    background: var(--omv3-bg-card);
    border: 1.5px solid var(--omv3-border-strong);
    border-radius: 5px;
    z-index: 2;
    transition: background-color 140ms ease, border-color 140ms ease;
}
.omv3__gallery--mobile-inline .omv3__thumb.is-active::before {
    background: var(--color-primary);
    border-color: var(--color-primary);
}
.omv3__gallery--mobile-inline .omv3__thumb.is-active::after {
    content: "";
    position: absolute;
    top: 7px; right: 8px;
    width: 5px; height: 9px;
    border: solid var(--color-primary-text, #fff);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
    z-index: 3;
}
/* Zablokowany format — kłódka SVG (.omv3__thumb-lock) zamiast checkboxa
   (nie da się zaznaczyć do pobrania). Ten sam znak co pill „Co pobrać",
   więc chowamy pseudo-checkbox i pokazujemy odznakę z ikoną. */
.omv3__gallery--mobile-inline .omv3__thumb.is-locked::before,
.omv3__gallery--mobile-inline .omv3__thumb.is-locked::after { content: none; }
.omv3__thumb.is-locked { opacity: 0.72; }
.omv3__thumb.is-locked canvas { filter: grayscale(0.35); }
/* Odznaka z kłódką — identyczna ikona jak w pillach „Co pobrać"
   (.omv3__fmt-check svg), w prawym górnym rogu miniatury. Widoczna zawsze
   (desktop i mobile), bo miniatura zablokowana nigdy nie ma checkboxa. */
.omv3__thumb-lock {
    position: absolute;
    top: 4px; right: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px; height: 18px;
    background: var(--omv3-bg-card);
    border: 1.5px solid var(--omv3-border-strong);
    border-radius: 5px;
    color: var(--omv3-text-muted);
    z-index: 3;
    pointer-events: none;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
}
.omv3__thumb-lock svg { display: block; opacity: 0.85; }

/* Privacy note */
.omv3__privacy {
    display: flex; align-items: center; gap: 8px;
    margin: 4px 0 0;
    padding: 10px 14px;
    background: var(--omv3-bg-soft);
    border-radius: var(--omv3-radius-sm);
    font-size: 12px;
    color: var(--omv3-text-soft);
    line-height: 1.4;
}
.omv3__privacy strong { color: var(--omv3-text); }

/* ════════════════════════════════════════════════════════
   CONTROLS COLUMN
   ════════════════════════════════════════════════════════ */
.omv3__controls {
    display: flex; flex-direction: column; gap: 12px;
    min-width: 0;
}
@media (min-width: 900px) {
    .omv3__controls { position: sticky; top: 20px; }
}

/* Cards — białe, z subtelną ramką, BEZ cieni (kontrast wystarczająco buduje tło) */
.omv3__card {
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: var(--omv3-radius);
    padding: 16px 18px;
}

/* Counter widget — pokazywany dla zalogowanych, między groups picker i settings */
.omv3__counter {
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: var(--omv3-radius);
    padding: 12px 16px;
}
.omv3__counter-top {
    display: flex; align-items: center; justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}
.omv3__counter-label {
    font-size: 11px; font-weight: 700;
    color: var(--omv3-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.omv3__counter-text {
    font-size: 13px; font-weight: 700;
    color: var(--omv3-text);
}
.omv3__counter-bar {
    width: 100%;
    height: 6px;
    background: var(--omv3-bg-soft);
    border-radius: 999px;
    overflow: hidden;
}
.omv3__counter-fill {
    height: 100%;
    background: var(--color-primary);
    border-radius: 999px;
    transition: width 240ms var(--omv3-ease);
}
.omv3__card-title {
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 12px;
    font-size: 13px; font-weight: 700;
    color: var(--omv3-text);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.omv3__card-icon { font-size: 16px; line-height: 1; }
.omv3__card-hint {
    margin-left: auto;
    font-size: 10px; font-weight: 600;
    color: var(--omv3-text-muted);
    text-transform: none;
    letter-spacing: 0;
}

/* Nagłówek karty z elementami obok tytułu (np. counter pobrań inline) */
.omv3__card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.omv3__card-head .omv3__card-title {
    margin: 0;
}

/* Counter inline (mała pigułka w nagłówku karty Ustawienia) — zastępuje
   wcześniejszą osobną kartę POBRANIA z dużym paskiem postępu. */
.omv3__counter--inline {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 0;
    flex-shrink: 0;
    min-width: 0;
}
.omv3__counter--inline .omv3__counter-text {
    font-size: 11px;
    font-weight: 700;
    color: var(--omv3-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
}
.omv3__counter--inline .omv3__counter-bar {
    width: 80px;
    height: 4px;
    background: var(--omv3-bg-soft);
    border-radius: 999px;
    overflow: hidden;
}

/* Sekcje wewnątrz karty ustawień — "Wygląd nakładki" i "Plik do pobrania".
   Wyraźny separator (kolorowa kropka przy tytule) + większy oddech między
   grupami, żeby user widział że to dwie różne strefy zadań. */
.omv3__group {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-top: 14px;
    margin-top: 4px;
    border-top: 1px dashed var(--omv3-border);
    position: relative;
}
.omv3__group:first-child {
    padding-top: 2px;
    margin-top: 0;
    border-top: 0;
}
.omv3__group-title {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: 11px;
    font-weight: 700;
    color: var(--omv3-text);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
/* Kolorowa kropka akcentem strony — wizualny "tag" sekcji */
.omv3__group-title::before {
    content: "";
    flex-shrink: 0;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: rgb(var(--omv3-accent-rgb, 124, 92, 252));
}

/* Skondensowana karta ustawień — z subsekcjami (Imię / Wariant+CTA / Formaty) */
.omv3__card--settings {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.omv3__sub {
    display: flex;
    flex-direction: column;
    gap: 7px;
    min-width: 0;
}
.omv3__sub-label {
    /* Mniejsze + jaśniejsze od group-title żeby hierarchia była czytelna:
       card-title (12-13px dark) > group-title (11px dark + accent dot) > sub-label (10px muted) */
    font-size: 10px; font-weight: 600;
    color: var(--omv3-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.omv3__sub-hint {
    font-weight: 600;
    color: var(--omv3-text-muted);
    text-transform: none;
    letter-spacing: 0;
    margin-left: 4px;
}
.omv3__sub-label-row {
    display: flex; align-items: center; gap: 8px;
}

/* Watermark — kompaktowy switch (iOS-style toggle) w osobnym małym wierszu.
   Mniejszy niż format pills, nie zajmuje karty. Locked state (anonim/free)
   z ikoną kłódki obok. */
.omv3__wm-row {
    display: flex;
    align-items: center;
    padding: 6px 4px 0;
}
.omv3__wm-row.is-locked {
    cursor: not-allowed;
}
.omv3__wm-switch {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    user-select: none;
}
.omv3__wm-row.is-locked .omv3__wm-switch { cursor: not-allowed; }
.omv3__wm-check {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
}
.omv3__wm-slider {
    position: relative;
    flex-shrink: 0;
    width: 34px; height: 20px;
    background: rgba(15, 23, 42, 0.18);
    border-radius: 999px;
    transition: background-color 140ms ease-out;
}
.omv3__wm-slider::after {
    content: "";
    position: absolute;
    top: 2px; left: 2px;
    width: 16px; height: 16px;
    background: #fff;
    border-radius: 50%;
    transition: transform 140ms var(--omv3-ease);
}
.omv3__wm-check:checked + .omv3__wm-slider {
    background: rgb(var(--omv3-accent-rgb, 124, 92, 252));
}
.omv3__wm-check:checked + .omv3__wm-slider::after {
    transform: translateX(14px);
}
.omv3__wm-label {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 12px; font-weight: 700;
    color: var(--omv3-text-soft);
    letter-spacing: 0.02em;
}
.omv3__wm-lock-badge {
    font-size: 10px;
    opacity: 0.7;
    filter: grayscale(0.4);
}
.omv3__wm-check:focus-visible + .omv3__wm-slider {
    outline: 2px solid rgba(var(--omv3-accent-rgb), 0.55);
    outline-offset: 2px;
}

/* Note dla wyłączonej sekcji — gdy aktywna grupa nakładek nie wspiera danego
   pola. Używamy max-height + opacity zamiast display:none żeby pokazanie/
   schowanie wyglądało jak płynne wsuwanie, nie skok layoutu. */
.omv3__sub-note {
    overflow: hidden;
    margin: 0;
    max-height: 80px;
    opacity: 1;
    font-size: 12px;
    color: var(--omv3-text-muted);
    line-height: 1.4;
    font-style: italic;
    transition: max-height 240ms cubic-bezier(0.4, 0, 0.2, 1),
                opacity 180ms ease-out,
                margin 240ms cubic-bezier(0.4, 0, 0.2, 1);
}
.omv3__sub-note[hidden] {
    display: block !important;   /* override globalnego [hidden] żeby transition działał */
    max-height: 0;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}

/* is-disabled — wyszarzenie inputu + obniżenie opacity całej sekcji.
   Transition na opacity/colors żeby przełączenie wariantu zestawu (które
   może aktywować/dezaktywować pole tekstu) nie skakało wizualnie. */
.omv3__sub-label,
.omv3__sub-hint {
    transition: opacity 180ms ease-out;
}
.omv3__name-input {
    transition: background-color 180ms ease-out,
                color 180ms ease-out,
                border-color 180ms ease-out;
}
.omv3__sub.is-disabled .omv3__sub-label {
    opacity: 0.65;
}
/* User feedback: "Inne rozwiązanie z nieaktywnym polem tekstowym".
   Zamiast wyszarzonego inputa (wygląda jak zepsute pole) — całkowicie
   ukrywamy input + presets + secondary input gdy aktywna grupa nie
   obsługuje tekstu. Zostaje tylko sub-label "Imię" i note (pełne info
   dlaczego pole znikło). UX: zero "rozwalone disabled inputs". */
.omv3__sub.is-disabled .omv3__name-input,
.omv3__sub.is-disabled .omv3__name-input--secondary,
.omv3__sub.is-disabled .omv3__presets,
.omv3__sub.is-disabled .omv3__sub-hint {
    display: none !important;
}
.omv3__sub-row {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
}
@media (min-width: 720px) {
    /* Wariant + CTA obok siebie na średnich/dużych ekranach.
       Min 720px (było 540) — na małych ekranach 3-way format toggle
       (JPG/PNG/WEBP) obok 2-way watermark (Tak/Nie) robił się ciasny
       i WEBP z 🔒 lock-iconem się rozjeżdżał. Pełna szerokość na mobile. */
    .omv3__sub-row { grid-template-columns: 1fr 1fr; }
    .omv3__sub-row--solo { grid-template-columns: 1fr; }
}

.omv3__select-all {
    margin-left: auto;
    background: transparent; border: 0; padding: 0;
    color: var(--color-primary);
    font: inherit; font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
    cursor: pointer;
}
.omv3__select-all:hover { text-decoration: underline; color: var(--color-primary-dark); }

/* Name input — czyste pole, accent ring tylko na focus (instant, bez transitions) */
.omv3__name-input {
    width: 100%;
    padding: 11px 14px;
    background: var(--omv3-bg-card);
    border: 1.5px solid var(--omv3-border-strong);
    border-radius: var(--omv3-radius-sm);
    font: inherit; font-size: 15px;
    color: var(--omv3-text);
}
.omv3__name-input::placeholder { color: var(--omv3-text-muted); }
.omv3__name-input:hover { border-color: rgba(var(--omv3-accent-rgb), 0.50); }
.omv3__name-input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(var(--omv3-accent-rgb), 0.18);
}
.omv3__name-input[readonly] {
    background: var(--omv3-bg-card-soft, rgba(15,23,42,0.03));
    cursor: pointer;
}
.omv3__name-input--secondary {
    font-size: 14px;
    padding: 9px 12px;
}

/* Text presets — gotowe sugestie klikalne (page setting text_presets[]) */
.omv3__presets {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}
.omv3__preset-btn {
    background: var(--omv3-bg-card);
    border: 1.5px solid var(--omv3-border);
    border-radius: 999px;
    padding: 6px 12px;
    font: inherit; font-size: 12px; font-weight: 600;
    color: var(--omv3-text-soft);
    cursor: pointer;
    transition: all 140ms ease-out;
    letter-spacing: 0.01em;
}
.omv3__preset-btn:hover {
    border-color: var(--color-primary);
    background: rgba(var(--omv3-accent-rgb), 0.08);
    color: var(--color-primary);
}
.omv3__preset-btn.is-active {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: #fff;
}

/* 2-button toggle (theme, CTA variant) — Apple-style segmented control.
   Container: gray track tła + gap między buttonami. Active button ma własny
   border-radius (zero białych szczelin w rogach) + accent ring + tinted bg
   + ciemny (neutralny) tekst dla pełnej czytelności. */
/* Toggle group — segmented control look (iOS-style: gray track + white
   pill na active). SEMANTYCZNIE odróżnia "wybór jednej opcji" (radio:
   Wariant, Link CTA, Format pliku, Znak wodny) od "zaznaczania wielu"
   (.omv3__fmt — Co pobrać). User od razu rozumie różnicę bez czytania. */
.omv3__toggle2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 3px;
    padding: 3px;
    background: rgba(15, 23, 42, 0.05);
    border-radius: 10px;
}
/* 3-way variant (np. format pliku PNG/JPG/WEBP) */
.omv3__toggle3 {
    grid-template-columns: 1fr 1fr 1fr;
}
.omv3__toggle2-btn {
    display: flex; align-items: center; justify-content: center; gap: 7px;
    padding: 8px 10px;
    background: transparent;
    border: 0;
    border-radius: 7px;
    font: inherit; font-size: 13px; font-weight: 700;
    color: var(--omv3-text-soft);
    cursor: pointer;
    letter-spacing: 0.01em;
    transition: transform 120ms var(--omv3-ease),
                background-color 140ms ease-out,
                color 140ms ease-out;
}
.omv3__toggle2-btn:hover:not(.is-active):not(.is-locked) {
    color: var(--omv3-text);
    background: rgba(255, 255, 255, 0.5);
}
/* Active — biała "pill" na szarym tracku (iOS segmented control).
   Subtelny accent ring 1.5px daje sygnał wyboru bez krzykliwego koloru. */
.omv3__toggle2-btn.is-active {
    background: var(--omv3-bg-card);
    color: var(--omv3-text);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06),
                inset 0 0 0 1.5px rgb(var(--omv3-accent-rgb, 124, 92, 252));
}
.omv3__toggle2-btn:active { transform: scale3d(0.97, 0.97, 1); }
/* Ikona SVG dziedziczy currentColor */
.omv3__toggle2-icon {
    flex-shrink: 0;
    line-height: 1;
}

/* Format pills "Co pobrać" — pełna szerokość rzędu, równe kolumny.
   Desktop: auto-fit z minmax(110px, 1fr) — 4 kolumny gdy szerokie, mniej gdy wąsko.
   Mobile (<540px): 2 kolumny (grid 2×2) — żeby pille z ikoną + label + dim
   nie tnęły tekstu w wąskie paski. Ultra-narrow (<360px): 1 kolumna stack. */
.omv3__formats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 6px;
    width: 100%;
}
@media (max-width: 540px) {
    .omv3__formats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
}
@media (max-width: 360px) {
    .omv3__formats { grid-template-columns: 1fr; }
}
.omv3__fmt {
    display: flex; align-items: center; gap: 9px;
    padding: 9.5px 12px;
    background: var(--omv3-bg-card);
    border: 2px solid var(--omv3-border);
    border-radius: 10px;
    cursor: pointer;
    font: inherit;
    width: 100%;
    min-width: 0;   /* żeby flex pozwolił truncate na .omv3__fmt-label */
    transition: transform 120ms var(--omv3-ease);
}
@media (max-width: 540px) {
    /* Kompaktowy mobile pill — mniej paddingu, mniejszy gap, czytelne minimum. */
    .omv3__fmt { padding: 9px 10px; gap: 7px; }
    .omv3__fmt-label { font-size: 12.5px; }
    .omv3__fmt-dim   { font-size: 9.5px; }
}
.omv3__fmt:hover:not(.is-selected):not(.is-locked) {
    border-color: rgba(var(--omv3-accent-rgb), 0.45);
}
.omv3__fmt:active { transform: scale3d(0.97, 0.97, 1); }
/* Selected — bardzo subtle accent tint + accent border 2px (zmiana koloru).
   Pill jest na karcie białej, więc tinted bg pozwala odróżnić od inactive
   bez konieczności tworzenia "gray track" wokół. Border przez bezpośredni
   rgb(--omv3-accent-rgb) — patrz komentarz przy .omv3__toggle2-btn.is-active. */
.omv3__fmt.is-selected {
    background: rgba(var(--omv3-accent-rgb), 0.08);
    border-color: rgb(var(--omv3-accent-rgb, 124, 92, 252));
}
.omv3__fmt-check {
    flex-shrink: 0;
    width: 17px; height: 17px;
    display: flex; align-items: center; justify-content: center;
    background: var(--omv3-bg-card);
    border: 1.5px solid var(--omv3-border-strong);
    border-radius: 5px;
    color: var(--color-primary);
}
.omv3__fmt-check svg { opacity: 0; transition: opacity 120ms var(--omv3-ease); }
.omv3__fmt.is-selected .omv3__fmt-check {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-primary-text, #fff);
}
.omv3__fmt.is-selected .omv3__fmt-check svg { opacity: 1; }
.omv3__fmt-text {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.15;
    gap: 1px;
}
.omv3__fmt-label {
    font-size: 13px; font-weight: 700;
    color: var(--omv3-text);
    white-space: nowrap;
}
.omv3__fmt-dim {
    font-size: 10px; font-weight: 600;
    color: var(--omv3-text-muted);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
}
/* Tekst neutralny (omv3-text) — accent ring i checkbox niosą informację
   o "selected", tekst pozostaje czytelny dla każdego accenta strony. */
.omv3__fmt.is-selected .omv3__fmt-label {
    color: var(--omv3-text);
}
.omv3__fmt.is-selected .omv3__fmt-dim {
    color: var(--omv3-text-soft);
}

/* Info o wymiarach + formatach pliku pod sekcją "Co pobrać".
   Pokazuje co user dostanie w aktualnym tierze + opcjonalny upsell link. */
.omv3__format-info {
    margin: 4px 0 0;
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--omv3-text-muted);
}
.omv3__format-info strong {
    color: var(--omv3-text);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.omv3__format-info-tier {
    color: var(--omv3-text);
    font-weight: 700;
}
.omv3__format-info-link {
    color: var(--color-primary-dark, var(--color-primary));
    font-weight: 700;
    text-decoration: none;
    border-bottom: 1px dashed currentColor;
}
.omv3__format-info-link:hover {
    color: var(--color-primary);
    border-bottom-style: solid;
}

/* Locked pill (Co pobrać: posty dla anonim/free wymagają Supporter+).
   Spójny wizualny język z .omv3__toggle2-btn.is-locked (format pliku):
   szare tło + opacity + przekreślony label + lock icon. */
.omv3__fmt.is-locked {
    background: rgba(15, 23, 42, 0.04);
    border-color: transparent;
    cursor: pointer;
    opacity: 0.65;
}
.omv3__fmt.is-locked .omv3__fmt-label {
    color: var(--omv3-text-muted);
    text-decoration: line-through;
    text-decoration-color: rgba(15, 23, 42, 0.35);
    text-decoration-thickness: 1px;
}
.omv3__fmt.is-locked .omv3__fmt-dim {
    color: rgba(15, 23, 42, 0.35);
}
.omv3__fmt.is-locked .omv3__fmt-check {
    background: transparent;
    border: 0;
    color: var(--omv3-text-muted);
    width: 17px; height: 17px;
}
.omv3__fmt.is-locked .omv3__fmt-check svg { opacity: 0.85; }
.omv3__fmt.is-locked:hover {
    border-color: rgba(var(--omv3-accent-rgb), 0.45);
    background: rgba(var(--omv3-accent-rgb), 0.06);
    opacity: 0.85;
}
.omv3__fmt.is-locked:hover .omv3__fmt-label {
    color: var(--omv3-text);
}

/* Toggle button locked — wyraźnie odróżnialny od dostępnych opcji.
   Wewnątrz szarego tracku: locked dostaje wyciszony tekst + line-through
   + lock icon. Opacity 0.55 dim'uje cały button, ikonki w środku też. */
.omv3__toggle2-btn.is-locked {
    color: var(--omv3-text-muted);
    cursor: pointer;
    position: relative;
    opacity: 0.55;
}
.omv3__toggle2-btn.is-locked::after {
    content: "🔒";
    margin-left: 4px;
    font-size: 11px;
    opacity: 0.9;
    filter: grayscale(0.2);
}
.omv3__toggle2-btn.is-locked:hover {
    color: var(--omv3-text);
    background: rgba(255, 255, 255, 0.4);
    opacity: 0.8;
}
/* Podpis przy zablokowanej opcji — „z kontem" (odblokowuje samo konto)
   albo „z Pro" (płatny plan). Mały badge, celowo BEZ przekreślenia —
   przekreślona jest nazwa opcji, podpis mówi jak ją odblokować. */
.omv3__toggle2-hint {
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--omv3-text-muted);
    background: rgba(15, 23, 42, 0.08);
    padding: 2px 5px;
    border-radius: 5px;
    white-space: nowrap;
    line-height: 1.3;
}
.omv3__toggle2-btn.is-locked > .omv3__toggle2-hint {
    text-decoration: none;
}
/* Podpis już mówi jak odblokować — emoji 🔒 obok byłoby dublem i rozpycha
   przycisk (zwłaszcza mobile). Zostaje na lockach bez podpisu (np. Ciemny). */
.omv3__toggle2-btn.is-locked:has(> .omv3__toggle2-hint)::after {
    content: none;
}
@media (max-width: 540px) {
    /* Wąski ekran: nazwa formatu w pierwszej linii, podpis wskakuje pod nią —
       bez tego 3 przyciski z badge'ami ucinały tekst („Z KONT…"). */
    .omv3__toggle3 .omv3__toggle2-btn {
        flex-wrap: wrap;
        row-gap: 2px;
        padding: 7px 4px;
    }
    .omv3__toggle2-hint { font-size: 8.5px; padding: 1.5px 4px; }
}
.omv3__toggle2-btn.is-locked > span {
    text-decoration: line-through;
    text-decoration-color: rgba(15, 23, 42, 0.35);
    text-decoration-thickness: 1px;
}

/* ─── CROP MODAL (inline w preview column) ─── */
.omv3__crop {
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: var(--omv3-radius);
    overflow: hidden;
    animation: omv3FadeIn 200ms var(--omv3-ease);
}
.omv3__crop-view {
    position: relative;
    background: #0F172A;
    overflow: hidden;
    user-select: none;
    touch-action: none;
}
.omv3__crop-view img {
    display: block;
    max-width: 100%;
    max-height: 60vh;
    width: auto;
    height: auto;
    margin: 0 auto;
    pointer-events: none;
}
.omv3__crop-sel {
    position: absolute;
    box-sizing: border-box;
    border: 2px solid #fff;
    box-shadow:
        0 0 0 99999px rgba(15, 23, 42, 0.55),
        0 1px 4px rgba(0,0,0,0.4);
    cursor: move;
    touch-action: none;
}
.omv3__crop-handle {
    position: absolute;
    width: 14px; height: 14px;
    background: #fff;
    border: 2px solid var(--color-primary);
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.omv3__crop-handle--nw { top: -8px; left: -8px;  cursor: nwse-resize; }
.omv3__crop-handle--ne { top: -8px; right: -8px; cursor: nesw-resize; }
.omv3__crop-handle--sw { bottom: -8px; left: -8px; cursor: nesw-resize; }
.omv3__crop-handle--se { bottom: -8px; right: -8px; cursor: nwse-resize; }
.omv3__crop-bar {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px;
    background: var(--omv3-bg-card);
    border-top: 1px solid var(--omv3-border);
}
.omv3__crop-info {
    font-size: 12px; font-weight: 600;
    color: var(--omv3-text-soft);
    font-family: ui-monospace, SFMono-Regular, monospace;
    flex: 1;
}
.omv3__crop-btn {
    padding: 8px 14px;
    background-color: var(--omv3-bg-soft);
    border: 0; border-radius: var(--omv3-radius-sm);
    font: inherit; font-size: 13px; font-weight: 600;
    color: var(--omv3-text);
    cursor: pointer;
    transition: transform 120ms var(--omv3-ease),
                background-color 140ms ease-out;
}
.omv3__crop-btn:hover { background-color: rgba(15, 23, 42, 0.08); }
.omv3__crop-btn:active { transform: scale3d(0.97, 0.97, 1); }
.omv3__crop-btn--ghost {
    background-color: transparent;
    color: var(--omv3-text-soft);
}
.omv3__crop-btn--primary {
    background-color: var(--color-primary);
    color: var(--color-primary-text, #fff);
}
.omv3__crop-btn--primary:hover {
    background-color: var(--color-primary-dark);
}

/* Download button — main CTA, flat solid accent (bez gradient, bez shadow).
   Kolor tekstu/ikony dziedziczony z --color-primary-text (auto biały/czarny). */
.omv3__download {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    width: 100%;
    padding: 16px 20px;
    background: var(--color-primary);
    color: var(--color-primary-text, #fff);
    border: 0; border-radius: var(--omv3-radius);
    font: inherit; font-size: 16px; font-weight: 700;
    cursor: pointer;
    transition: transform 140ms var(--omv3-ease),
                background-color 140ms ease-out,
                opacity 200ms ease-out;
    margin-top: 4px;
}
.omv3__download:hover:not(:disabled) {
    background: var(--color-primary-dark, var(--color-primary));
    transform: translate3d(0, -1px, 0);
}
.omv3__download:active:not(:disabled) { transform: translate3d(0, 0, 0); }
.omv3__download:disabled {
    background: var(--omv3-bg-soft);
    color: var(--omv3-text-muted);
    cursor: not-allowed;
}
.omv3__download.is-loading {
    cursor: progress; pointer-events: none;
    background: var(--color-primary);
    color: var(--color-primary-text, #fff);
}
.omv3__download.is-loading::after {
    content: "";
    width: 14px; height: 14px;
    /* Spinner używa currentColor (= primary_text) — biały dla ciemnego accenta,
       czarny dla jasnego (żółty). Ring tła ma niższą alpha. */
    border: 2px solid currentColor;
    border-color: currentColor currentColor currentColor transparent;
    border-radius: 50%;
    opacity: 0.85;
    animation: omv3Spin 0.8s linear infinite;
}
.omv3__download:disabled svg { opacity: 0.4; }
@keyframes omv3Spin { to { transform: rotate(360deg); } }

/* Wrapper przycisku pobierania — pozwala na sticky na desktop (≥1100px)
   żeby user zawsze miał dostęp do akcji niezależnie od scrolla. */
.omv3__download-wrap {
    margin-top: 4px;
}

/* Pulse — krótka, subtelna animacja na aktywnym thumbie galerii lub
   kafelku group-card po przełączeniu wariantu. Wskazuje user-flow:
   "kliknąłeś toggle → spójrz tu, to się zmieniło". */
@keyframes omv3Pulse {
    0%   { transform: translate3d(0, 0, 0) scale(1); }
    35%  { transform: translate3d(0, 0, 0) scale(1.04); }
    100% { transform: translate3d(0, 0, 0) scale(1); }
}
.omv3__thumb.is-pulsing {
    animation: omv3Pulse 360ms cubic-bezier(0.4, 0, 0.2, 1);
}

.omv3__error {
    display: none;
    margin-top: 8px;
    padding: 10px 12px;
    background: rgba(220, 38, 38, 0.08);
    color: #B91C1C;
    border-radius: var(--omv3-radius-sm);
    font-size: 13px;
}
.omv3__error.is-visible { display: block; }

/* Help (collapsible) */
.omv3__help {
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: var(--omv3-radius-sm);
    padding: 12px 16px;
    font-size: 13px;
    color: var(--omv3-text-soft);
}
.omv3__help summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--omv3-text);
    user-select: none;
    list-style: none;
    display: flex; align-items: center; gap: 6px;
}
.omv3__help summary::after {
    content: "▾";
    margin-left: auto;
    transition: transform 200ms var(--omv3-ease);
}
.omv3__help[open] summary::after { transform: rotate(180deg); }
.omv3__help ul { margin: 10px 0 0; padding-left: 18px; line-height: 1.6; }
.omv3__help li { margin: 4px 0; }

/* ════════════════════════════════════════════════════════
   RELATED PAGES + CONTACT — sekcja pod opcjami nakładkowymi
   ════════════════════════════════════════════════════════ */
.omv3__related {
    margin-top: 40px;
}
.omv3__related-title {
    margin: 0 0 16px;
    font-size: 18px; font-weight: 700;
    color: var(--omv3-text);
}
.omv3__related-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
}
.omv3__related-card {
    display: flex; flex-direction: column; gap: 6px;
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: var(--omv3-radius-sm);
    padding: 8px;
    text-decoration: none;
    color: var(--omv3-text);
    transition: transform 160ms var(--omv3-ease),
                border-color 160ms ease-out;
}
.omv3__related-card:hover {
    transform: translate3d(0, -2px, 0);
    border-color: rgb(var(--omv3-accent-rgb, 124, 92, 252));
}
.omv3__related-card img {
    width: 100%; aspect-ratio: 1/1;
    object-fit: cover;
    border-radius: 6px;
    background: var(--omv3-bg-soft);
}
.omv3__related-card-fallback {
    display: flex; align-items: center; justify-content: center;
    width: 100%; aspect-ratio: 1/1;
    background: var(--omv3-bg-soft);
    border-radius: 6px;
    font-size: 32px;
}
.omv3__related-card-title {
    font-size: 12px; font-weight: 600;
    text-align: center;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    color: var(--omv3-text-soft);
}

/* Contact link — kompaktowy under-CTA w prawej kolumnie. */
.omv3__contact-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin-top: 12px;
    padding: 10px 12px;
    background: transparent;
    color: var(--omv3-text-muted);
    border: 0;
    border-radius: var(--omv3-radius-sm);
    text-decoration: none;
    font: inherit; font-size: 12px; font-weight: 600;
    transition: color 140ms ease-out, background-color 140ms ease-out;
}
.omv3__contact-link:hover {
    color: var(--omv3-text);
    background: rgba(15, 23, 42, 0.04);
}
.omv3__contact-link svg { flex-shrink: 0; opacity: 0.7; }

/* Legacy contact box style (unused after refactor — zostaje na wszelki wypadek) */
.omv3__contact {
    margin-top: 32px;
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
    background: var(--omv3-bg-card);
    border: 1px solid var(--omv3-border);
    border-radius: var(--omv3-radius);
    padding: 18px 22px;
}
.omv3__contact-text { flex: 1; min-width: 200px; }
.omv3__contact-title {
    margin: 0 0 4px;
    font-size: 15px; font-weight: 700;
    color: var(--omv3-text);
}
.omv3__contact-desc {
    margin: 0;
    font-size: 13px;
    color: var(--omv3-text-soft);
}
.omv3__contact-btn {
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: 8px;
    padding: 10px 18px;
    background: rgba(15, 23, 42, 0.05);
    color: var(--omv3-text);
    border: 1px solid var(--omv3-border-strong);
    border-radius: var(--omv3-radius-sm);
    text-decoration: none;
    font: inherit; font-size: 13px; font-weight: 700;
    transition: background-color 140ms ease-out, border-color 140ms ease-out;
}
.omv3__contact-btn:hover {
    background: rgba(var(--omv3-accent-rgb), 0.08);
    border-color: rgb(var(--omv3-accent-rgb, 124, 92, 252));
}

/* ════════════════════════════════════════════════════════
   DESKTOP NO-SCROLL LAYOUT (≥1100px)
   ════════════════════════════════════════════════════════
   Wymusza że cała strona mieści się w viewport: header + main + footer.
   Wewnątrz main: hero (compact) + grid (flex:1 z internal scroll w preview/controls).
   Related/contact ukryte na desktop — mobile/tablet ma normalny scroll z nimi. */
@media (min-width: 1100px) {
    /* .omv3 wypełnia widoczną część viewportu pod sticky site-header
       (≈56px). Marginesy pion shellu są LOCK'owane po pierwszym renderze
       przez JS (lockShellVerticalPadding) — top = bottom = (omv3.h - content.h)/2.
       Dzięki temu: a) początkowo content wycentrowany symetrycznie, b) gdy
       user później przełączy na Stories (wyższy canvas), padding NIE zmienia
       się — content rośnie w dół poza viewport, body scrolluje naturalnie,
       bez "skoku" pozycji modułu. */
    body.page--v3 .omv3 {
        min-height: calc(100vh - 56px);
    }
    body.page--v3 .omv3__shell {
        /* Spójna szerokość z site-headerem (--container-max: 1040px) */
        max-width: 1040px;
        /* Initial values — JS nadpisuje policzonymi po pierwszym renderze.
           Te służą jako fallback gdy JS się nie odpali. */
        padding-top: 24px;
        padding-bottom: 24px;
    }
    /* Card-head bez podwójnego spacingu — flex gap parent karty (10px)
       wystarcza między headem a pierwszą sekcją grupy. */
    body.page--v3 .omv3__card-head {
        margin-bottom: 0;
    }
    /* Kompaktowy spacing wewnątrz settings card */
    body.page--v3 .omv3__card--settings {
        gap: 10px;
    }
    /* "Coś nie działa" bliżej przycisku Pobierz */
    body.page--v3 .omv3__contact-link {
        margin-top: 2px;
        padding: 6px 10px;
        font-size: 11px;
    }
    /* Grupa: mniej padding-top żeby separator nie tworzył dużego odstępu */
    body.page--v3 .omv3__group {
        gap: 10px;
        padding-top: 10px;
    }
    body.page--v3 .omv3__hero {
        text-align: left;
        margin-bottom: 14px;
    }
    body.page--v3 .omv3__hero-title {
        font-size: clamp(18px, 2vw, 24px);
        margin: 0;
    }
    body.page--v3 .omv3__hero-desc,
    body.page--v3 .omv3__hero-meta {
        display: none;
    }
    body.page--v3 .omv3__hero-logo {
        display: inline-flex;
        width: 38px; height: 38px;
        margin: 0 0 6px;
    }
    body.page--v3 .omv3__grid {
        align-items: start;
        gap: 18px;
    }
    body.page--v3 .omv3__controls {
        position: static;
        display: flex;
        flex-direction: column;
        gap: 10px;
    }
    /* Sticky download — zawsze dostępny niezależnie od scrolla. */
    body.page--v3 .omv3__download-wrap {
        position: sticky;
        bottom: 14px;
        z-index: 20;
        margin-top: 2px;
        filter: drop-shadow(0 8px 20px rgba(15, 23, 42, 0.12));
    }
    body.page--v3 .omv3__card {
        padding: 12px 14px;
    }
    body.page--v3 .omv3__card-title {
        font-size: 12px;
        margin-bottom: 10px;
    }
    body.page--v3 .omv3__download {
        padding: 12px 18px;
        font-size: 14px;
    }
    body.page--v3 .omv3__related,
    body.page--v3 .omv3__contact {
        display: none;
    }
    body.page--v3 .omv3__banner {
        display: none;
    }
}

/* ════════════════════════════════════════════════════════
   MOBILE: STICKY BOTTOM CTA
   ════════════════════════════════════════════════════════ */
.omv3__sticky {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 90;
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    background: linear-gradient(180deg, rgba(255,255,255,0) 0%, var(--omv3-bg-card) 30%);
    pointer-events: none;
}
.omv3__sticky[hidden] { display: none !important; }
.omv3__sticky .omv3__download { pointer-events: auto; }
.omv3__download--sticky {
    margin-top: 0;
}
@media (min-width: 900px) {
    .omv3__sticky { display: none !important; }
}

/* ════════════════════════════════════════════════════════
   RESPONSIVE TUNING
   ════════════════════════════════════════════════════════ */
@media (max-width: 720px) {
    .omv3__hero { margin-bottom: 18px; }
    .omv3__hero-logo { width: 60px; height: 60px; margin-bottom: 10px; }
    .omv3__hero-meta { gap: 6px; }
    .omv3__hero-pill { padding: 5px 10px; font-size: 11px; }

    /* Mobile upload — kompaktowy, nie zajmuje całego ekranu jak na desktopie.
       Aspect-ratio 16/10 jest dużo niższy niż 1/1, daje przestrzeń na inne
       elementy bez konieczności scrolla. */
    .omv3__upload {
        aspect-ratio: auto;
        height: 180px;
        padding: 14px;
    }
    .omv3__upload-icon { width: 44px; height: 44px; margin-bottom: 6px; }
    .omv3__upload-icon svg { width: 24px; height: 24px; }
    .omv3__upload-title { font-size: 14px; margin: 0; }
    .omv3__upload-sub { font-size: 12px; margin: 2px 0 6px; }
    .omv3__upload-formats { font-size: 9px; padding: 2px 8px; }
    .omv3__upload-privacy { margin-top: 10px; font-size: 11px; }

    .omv3__card { padding: 14px 16px; }
    .omv3__card-title { font-size: 12px; }

    /* Toggle buttons na ciasnym mobile — mniejszy padding/font + min-width:0
       żeby 3-way format toggle (JPG/PNG/WEBP) z lock-iconem mieścił się
       równo, bez przepychania kolumn. */
    .omv3__toggle2 { gap: 2px; padding: 2px; }
    .omv3__toggle2-btn {
        padding: 8px 6px;
        font-size: 12px;
        gap: 5px;
        min-width: 0;
    }
    .omv3__toggle2-btn > span {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /* Lock icon na mobile nie ma marginu w przeciwnym razie wypycha tekst */
    .omv3__toggle2-btn.is-locked::after {
        margin-left: 2px;
        font-size: 10px;
    }
    /* 3-way (Format pliku) — jeszcze mniej paddingu bo 3 kolumny */
    .omv3__toggle3 .omv3__toggle2-btn {
        padding: 8px 4px;
        font-size: 11.5px;
    }
}

/* Ultra-narrow (≤360px iPhone SE/podobne) — radykalniejsza redukcja paddingu */
@media (max-width: 360px) {
    .omv3__toggle3 .omv3__toggle2-btn {
        padding: 7px 2px;
        font-size: 11px;
    }
}

/* ════════════════════════════════════════════════════════
   DARK MODE (CSS variables theme-aware)
   ════════════════════════════════════════════════════════ */
/* V3 jest ZAWSZE LIGHT — globalny dark mode strony (html[data-theme="dark"])
   nie wpływa na ten UI. Toggle "Jasny/Ciemny" w v3 jest semantically inny:
   przełącza tylko WARIANT NAKŁADKI renderowany w canvas (light/dark overlay),
   nie zmienia kolorów interfejsu wokół. */

/* ════════════════════════════════════════════════════════
   REDUCED MOTION
   ════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    .omv3 *, .omv3 *::before, .omv3 *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

/* ════════════════════════════════════════════════════════
   LEGACY V1 CLASS BRIDGE
   ════════════════════════════════════════════════════════
   Niektóre selektory w variant-cards-v3.js szukają starych klas
   (om-v3-variant, om-v3-thumb itp.). Dla zachowania kompatybilności:
*/
.omv3 .om-v3-variant, .omv3__variants .om-v3-variant {
    /* alias do .omv3__variant — niepotrzebny gdy JS generuje nowe klasy */
}

/* ── Strona łącząca: picker pogrupowany SEKCJAMI per źródło ── */
.omv3__groups-grid--sectioned {
    display: block; /* sekcje jedna pod drugą; grid żyje w sekcjach */
}
.omv3__source-section + .omv3__source-section { margin-top: 14px; }
.omv3__source-section.is-source-hidden { display: none; }
.omv3__source-section-head {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 700;
    color: #475569;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.omv3__source-section-dot {
    width: 9px; height: 9px;
    border-radius: 50%;
    flex: none;
}
.omv3__source-section-count {
    background: rgba(15, 23, 42, 0.06);
    color: #64748b;
    font-size: 11px;
    font-weight: 700;
    padding: 1px 8px;
    border-radius: 999px;
}
.omv3__source-section-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 8px;
}
