@import url('fonts.css');

/* ═══════════════════════════════════════════════════════════════════════════
   PlantaHerb — skóra panelu. Kolejność: tokeny → sidebar/topbar → kafle
   i przyciski → linki → tabele.

   ZASADA NADRZĘDNA: brąz jest AKCENTEM, nie tłem — kotwiczy markę w sidebarze
   i na przyciskach akcji. Kolory ról (zielony/niebieski/złoty) rozróżniają role
   jako paski, kropki i liczby; nigdy jako pełne nasycone tło.

   ⚠ Plik musi zostać identyczny co do bajtu z office/public/assets/app.css.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
    /* ── Tła ─────────────────────────────────────────────────────────────── */
    --bg-app: #eceae4;        /* tło poza panelem */
    --bg-canvas: #f7f6f2;     /* tło obszaru treści */
    --surface: #ffffff;       /* karty, pola */
    --surface-soft: #faf9f5;  /* panele wtórne (np. wiersze linków) */
    --field: #f4f5f1;         /* tła pól, nagłówek tabeli */

    /* ── Sidebar (kotwica marki) ───────────────────────────────────────────
       Oba końce mają tę samą wartość — pasek jest jednolity, nie gradientowy. */
    --sidebar-top: #2a211d;
    --sidebar-bot: #2a211d;
    --sidebar-text: #cbbda4;
    --sidebar-text-strong: #f3ead9;
    --sidebar-muted: #a08a6a;

    /* ── Tekst ───────────────────────────────────────────────────────────── */
    --ink: #2c2219;
    --ink-soft: #5c4d3c;
    --muted: #877a6a;

    /* ── Marka / akcenty ─────────────────────────────────────────────────── */
    --brown: #92602f;         /* primary — przyciski akcji */
    --brown-hover: #7c5028;
    --green: #2f7a57;         /* rola Partner / sukces */
    --green-deep: #3d6b47;    /* kafel „Suma" */
    --blue: #35688f;          /* rola Ambasador */
    --gold: #a4761f;          /* rola Klient */

    /* Czerwień błędu (uśpieni klienci, walidacja, usuwanie). Wyprowadzona
       regułą „nowy odcień tylko przez zmianę hue przy tej samej jasności
       i nasyceniu": rodzina ról to hsl(~30-206°, 44-68%, 33-38%), więc
       czerwień siada na hsl(6°, 55%, 38%). */
    --red: #96362c;

    /* Bordo — kategoria „ryzyko" na Statystykach (uśpieni klienci).
       Wartość wprost z briefu ekranu Statystyk. */
    --bordo: #b04a34;

    /* Rozcieńczenia ról — chipy ikon, plakietki, paski. 13% wg wytycznych. */
    --green-soft: rgba(47, 122, 87, 0.13);

    /* ── Wzorzec kart „B" ──────────────────────────────────────────────────
       Pasek akcentu i tekst etykiety to DWA odcienie tej samej barwy: pasek
       jest grafiką, tekst musi mieć kontrast ≥4,5:1 na bieli przy 11,5 px
       bold. Jeden token na oba daje bladą kreskę albo nieczytelną etykietę. */
    --acc-green: #3d6b4f;
    --acc-amber: #b8862b;
    --acc-red:   #a5402d;
    --acc-blue:  #3a6b96;

    /* Karta neutralna to nie „karta bez paska", tylko karta z paskiem szarym.
       Inaczej w rzędzie stoją dwa typy obiektu i te bez krawędzi czytają się
       jako niedokończone. */
    --acc-neutral: #c4bba9;

    --ink-green: #33604a;
    --ink-amber: #8a6318;
    --ink-red:   #98392a;
    --ink-blue:  #2f5c85;
    --ink-neutral: #8a8172;

    /* Jedyna tinta tła w całym panelu — karta wyróżniona. */
    --hi-bg:     #e9efe7;
    --hi-border: #cbdacb;
    --hi-ink:    #2f5a40;
    --blue-soft: rgba(53, 104, 143, 0.13);
    --gold-soft: rgba(164, 118, 31, 0.13);
    --brown-soft: rgba(146, 96, 47, 0.13);
    --red-soft: rgba(150, 54, 44, 0.13);
    --green-deep-soft: rgba(61, 107, 71, 0.10);

    /* ── Linie / cienie / promienie ──────────────────────────────────────── */
    --line: rgba(51, 39, 29, 0.09);
    --line-strong: rgba(51, 39, 29, 0.16);
    --shadow-card: 0 6px 18px -6px rgba(51, 39, 29, 0.16), 0 2px 5px -2px rgba(51, 39, 29, 0.08);
    --shadow-sum: 0 6px 18px -6px rgba(61, 107, 71, 0.30), 0 2px 5px -2px rgba(61, 107, 71, 0.14);
    --radius-card: 18px;
    --radius-ctrl: 10px;

    /* ── Odstępy wewnętrzne ──────────────────────────────────────────────────
       Jeden token na odstęp tekstu od krawędzi karty. Wartości wpisywane
       w każdą regułę osobno rozjeżdżają się przy pierwszym nowym komponencie. */
    --pad-card: 1.75rem;      /* 28 px — karty treści, formularze, listy      */
    --pad-card-tight: 1.4rem; /* 22 px — komórki tabel, wiersze list          */

    /* Przycisk wtórny — jasny off-white z wytycznych. */
    --btn-secondary: #eef0ea;
    --btn-secondary-hover: #e4e8df;
    --btn-secondary-ink: #5c6a54;

    /* Tło wyróżnionego kafla „Suma" — --green-deep rozjaśniony do poziomu tła. */
    --sum-bg: #edf3ee;

    /* ── Typografia ────────────────────────────────────────────────────────
       Jeden krój; hierarchię robi wielkość i waga. --font-display i --font-ui
       mają tę samą wartość, ale zostają rozdzielone: niosą intencję, więc
       zmiana kroju nagłówków to jedna linia. */
    --font-display: 'Noto Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
    --font-ui: 'Noto Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

    /* ── Aliasy zgodności ────────────────────────────────────────────────────
       Stare tokeny --ph-* przepięte na nowe wartości. 138 miejsc w tym pliku
       i widoki dalej się do nich odwołują — dzięki temu stary kod działa,
       a nowy pisze się już w nowym nazewnictwie. */
    --ph-bg-app: var(--bg-app);
    --ph-bg-sidebar: var(--sidebar-top);
    --ph-bg-content: var(--bg-canvas);
    --ph-bg-card: var(--surface);
    --ph-border: var(--line);
    --ph-border-strong: var(--line-strong);
    --ph-text-main: var(--ink);
    --ph-text-muted: var(--muted);
    --ph-text-inverse: var(--sidebar-text-strong);
    --ph-primary: var(--brown);
    --ph-primary-hover: var(--brown-hover);
    --ph-success: var(--green);
    --ph-warning: var(--gold);
    --ph-danger: var(--red);
    --ph-info: var(--blue);
    --ph-shadow-sm: 0 1px 2px rgba(51, 39, 29, 0.06);
    --ph-shadow-md: var(--shadow-card);
    --ph-radius-lg: var(--radius-ctrl);
    --ph-radius-xl: var(--radius-card);
}

/* ── Typografia bazowa ───────────────────────────────────────────────────────
   Noto Sans na nagłówkach, liczbach i całym UI. Monospace tylko dla adresów. */

.ph-layout,
.ph-layout input,
.ph-layout select,
.ph-layout textarea,
.ph-layout button {
    font-family: var(--font-ui);
}

.ph-layout {
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.ph-layout {
    display: block;
    min-height: 100vh;
    width: 100%;
    margin: 0;
    background: var(--bg-app);
    border-radius: 0;
    box-shadow: none;
}

/* ═══ Sidebar ═══════════════════════════════════════════════════════════════ */

.ph-sidebar {
    background: linear-gradient(180deg, var(--sidebar-top), var(--sidebar-bot));
    color: var(--sidebar-text);
    padding: 1.5rem 0.9rem 1rem;
    border-right: 0;
    display: flex;
    flex-direction: column;
    gap: 1rem;
    position: fixed;
    top: 0;
    left: 0;
    width: 264px;
    height: 100vh;
    overflow-y: auto;
}

.ph-sidebar__brand {
    margin-bottom: 0.6rem;
    padding: 0 0.35rem;
}

.ph-sidebar__logo-link {
    display: inline-flex;
    align-items: center;
}

.ph-sidebar__logo {
    max-width: 146px;
    width: 100%;
    height: auto;
    object-fit: contain;
}

.ph-sidebar__sections {
    display: flex;
    flex-direction: column;
    gap: 1.4rem;
    flex: 1;
}

.ph-sidebar__section {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.ph-sidebar__label {
    margin: 0 0 0.15rem;
    padding: 0 0.75rem;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--sidebar-muted);
}

.ph-sidebar__nav {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.ph-sidebar__link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    color: var(--sidebar-text);
    text-decoration: none;
    padding: 10px 12px;
    border-radius: var(--radius-ctrl);
    font-size: 14px;
    font-weight: 500;
    transition: background-color 0.18s ease, color 0.18s ease;
}

.ph-sidebar__link i,
.ph-sidebar__link svg {
    width: 18px;
    height: 18px;
    stroke-width: 1.8;
    flex-shrink: 0;
}

.ph-sidebar__link span {
    font-size: 14px;
    line-height: 1.2;
}

.ph-sidebar__link:hover {
    background: rgba(243, 234, 217, 0.07);
    color: var(--sidebar-text-strong);
}

/* Aktywna pozycja: jasne półprzezroczyste tło + zielony pasek 3px po lewej. */
.ph-sidebar__link.is-active {
    background: rgba(243, 234, 217, 0.11);
    color: var(--sidebar-text-strong);
    font-weight: 600;
}

.ph-sidebar__link.is-active::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 22px;
    border-radius: 0 3px 3px 0;
    background: var(--green);
}

/* Plakietka planu przy pozycji menu. Neutralna, nie brązowa: brąz jest
   zarezerwowany dla akcji, a plakietka niczego nie uruchamia. */
/* Sama pigułka „PRO": obrysowa, bez wypełnienia. Pełna nazwa planu należy
   do ekranu Subskrypcja — w menu konkurowała z etykietą pozycji o to, co się
   w tym wierszu właściwie czyta. */
.ph-sidebar__badge {
    margin-left: auto;
    padding: 1px 6px;
    border: 1px solid rgba(243, 234, 217, 0.28);
    border-radius: 999px;
    background: none;
    color: var(--sidebar-text);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    white-space: nowrap;
}

/* Korekta optyczna ikony. Lucide rysuje wszystko w polu 24×24, ale wypełnia
   je różnie: „credit-card" to prostokąt na całą szerokość, więc przy tych
   samych 18 px wygląda większy od sąsiadów. */
.ph-sidebar__link--tight i,
.ph-sidebar__link--tight svg { width: 15px; height: 15px; }

/* ═══ Topbar ════════════════════════════════════════════════════════════════
   Breadcrumb po lewej, dzwonek po prawej. Wychodzi negatywnym marginesem poza
   padding .ph-content, żeby zetknąć się z krawędziami obszaru treści bez
   przebudowy każdego widoku. */

.ph-topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    padding: 0 2rem;
    min-height: 62px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    background: var(--bg-canvas);
    border-bottom: 1px solid var(--line);
}

.ph-topbar__crumb {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 13px;
    color: var(--muted);
    min-width: 0;
}

.ph-topbar__crumb a {
    color: var(--muted);
    text-decoration: none;
}

.ph-topbar__crumb a:hover { color: var(--ink); }

.ph-topbar__crumb strong {
    color: var(--ink);
    font-weight: 600;
}

.ph-topbar__crumb i,
.ph-topbar__crumb svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    opacity: 0.6;
}

.ph-topbar__actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-shrink: 0;
}

/* Szukajki globalnej w topbarze NIE MA — nie miałaby czego przeszukiwać.
   Wyszukiwanie żyje tam, gdzie są dane: jedno pole nad każdą tabelą
   (.ph-table-search). */

.ph-topbar__bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--line);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    color: var(--ink-soft);
    cursor: pointer;
    text-decoration: none;
    transition: background-color 0.18s ease;
}

.ph-topbar__bell:hover { background: var(--field); }

.ph-topbar__bell i,
.ph-topbar__bell svg {
    width: 17px;
    height: 17px;
    stroke-width: 1.8;
}

.ph-topbar__dot {
    position: absolute;
    top: 8px;
    right: 9px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--brown);
    border: 1.5px solid var(--surface);
}

/* ═══ Obszar treści ═════════════════════════════════════════════════════════
   ⚠ Odsunięcie od sidebara siedzi na .ph-main, nie na .ph-content: router
   podmienia całą zawartość .ph-content, więc topbar wstawiony do środka
   znikałby po pierwszym przejściu. Reguła na .ph-content to zapas dla
   szablonów bez wrappera — wygląda na duplikat, ale nie jest. */

.ph-main {
    margin-left: 264px;
    min-height: 100vh;
    background: var(--bg-canvas);
    display: flex;
    flex-direction: column;
}

.ph-content {
    background: var(--bg-canvas);
    padding: 2rem;
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    min-height: 100vh;
    margin-left: 264px;
}

.ph-main > .ph-content {
    margin-left: 0;
    min-height: 0;
    flex: 1;
}

.ph-page-header {
    margin-bottom: 1rem;
}

/* Nagłówek strony: H1 + podtytuł + opcjonalny pill statusu po prawej. */
.ph-page-header__row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.ph-section-title {
    margin: 0;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 38px;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.15;
}

.ph-page-subtitle {
    margin: 0.45rem 0 0;
    color: var(--muted);
    font-size: 14px;
}

.ph-grid-2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

/* Odstęp wewnętrzny kart: 1.75rem (28 px). Przy 1.4rem tekst dotykał
   krawędzi na szerokich kartach. Wartość z tokena, żeby zmienić ją naraz
   dla wszystkich kart. */
.ph-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
    padding: var(--pad-card);
}

.ph-card__title {
    margin: 0 0 0.8rem;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 700;
    line-height: 1.25;
}

.ph-text-success { color: var(--ph-success); }
.ph-text-warning { color: var(--ph-warning); }
.ph-text-danger { color: var(--ph-danger); }
.ph-text-info { color: var(--ph-info); }
.ph-text-muted { color: var(--ph-text-muted); }

.ph-meta {
    color: var(--ph-text-muted);
    font-size: 0.88rem;
    margin-top: 0.35rem;
}

.ph-meta--no-top { margin-top: 0; }

.ph-status-box {
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-lg);
    background: #fff;
    padding: 0.95rem 1rem;
    color: var(--ph-text-main);
    margin-bottom: 1rem;
}

/* Ramki statusu biorą kolor z roli i jej rozcieńczenia — jeden zestaw źródeł
   zamiast czterech osobnych trójek kolorów dobieranych ręcznie. */
.ph-status-box--compact { margin-top: 0.8rem; margin-bottom: 0; }
.ph-status-box--success { border-color: rgba(47, 122, 87, 0.28);   background: var(--green-soft); color: var(--green); }
.ph-status-box--warning { border-color: rgba(164, 118, 31, 0.28);  background: var(--gold-soft);  color: var(--gold); }
.ph-status-box--danger  { border-color: rgba(150, 54, 44, 0.28);   background: var(--red-soft);   color: var(--red); }
.ph-status-box--neutral { border-color: var(--line-strong);        background: var(--field);      color: var(--ink-soft); }

.ph-form { display: flex; flex-direction: column; gap: 1rem; }
.ph-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
.ph-form-group { display: flex; flex-direction: column; gap: 0.42rem; }

.ph-label {
    font-size: 0.87rem;
    font-weight: 600;
    color: var(--ph-text-main);
}

.ph-input,
.ph-textarea {
    width: 100%;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    color: var(--ink);
    padding: 0 0.8rem;
    font-size: 14px;
    min-height: 42px;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
}

.ph-input::placeholder,
.ph-textarea::placeholder { color: var(--muted); }

.ph-input:focus,
.ph-textarea:focus {
    outline: none;
    border-color: var(--brown);
    box-shadow: 0 0 0 3px var(--brown-soft);
}

.ph-textarea { resize: vertical; min-height: 112px; padding: 0.6rem 0.8rem; line-height: 1.55; }
.ph-input--mono { font-family: var(--font-mono); }

.ph-subdomain-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 0.55rem;
}

.ph-subdomain-host { color: var(--ph-text-muted); font-size: 0.88rem; }
.ph-subdomain-icon { min-width: 24px; text-align: center; }

.ph-field-hint {
    font-size: 0.78rem;
    color: var(--ph-text-muted);
    margin-top: 0.2rem;
}

.ph-field-hint--danger { color: var(--ph-danger); }
.ph-field-hint--success { color: var(--ph-success); }
.ph-field-hint--info { color: var(--ph-info); }

.ph-logo-field {
    display: grid;
    grid-template-columns: 180px minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
}

.ph-logo-field__preview {
    min-height: 180px;
    border: 1px dashed var(--ph-border-strong);
    border-radius: 16px;
    background: var(--surface-soft);
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.9rem;
    overflow: hidden;
}

.ph-logo-field__preview img {
    display: block;
    max-width: 100%;
    max-height: 160px;
    width: auto;
    height: auto;
    border-radius: 12px;
    object-fit: contain;
}

.ph-logo-field__preview.is-empty {
    color: var(--ph-text-muted);
    font-size: 0.84rem;
    text-align: center;
}

.ph-logo-field__controls {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    min-width: 0;
}

.ph-file-upload {
    position: relative;
}

.ph-file-upload__input {
    position: absolute;
    inset: 0;
    opacity: 0;
    pointer-events: none;
}

.ph-file-upload__label {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    min-height: 54px;
    padding: 0.7rem 0.8rem;
    border: 1px solid var(--ph-border-strong);
    border-radius: 14px;
    background: #fff;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.ph-file-upload__label:hover {
    border-color: var(--brown);
    background: var(--surface-soft);
}

.ph-file-upload__input:focus + .ph-file-upload__label,
.ph-file-upload__input:focus-visible + .ph-file-upload__label {
    border-color: var(--brown);
    box-shadow: 0 0 0 3px var(--brown-soft);
}

.ph-file-upload__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 38px;
    padding: 0.55rem 0.85rem;
    border-radius: 10px;
    background: var(--ph-primary);
    color: #fff;
    font-size: 0.86rem;
    font-weight: 700;
    white-space: nowrap;
}

.ph-file-upload__text {
    color: var(--ph-text-muted);
    font-size: 0.84rem;
    text-align: right;
}

.ph-logo-field__actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.ph-logo-field.is-marked-for-removal .ph-logo-field__preview {
    border-color: rgba(150, 54, 44, 0.28);
    background: var(--red-soft);
}

.ph-logo-field.is-marked-for-removal .ph-logo-field__preview img {
    opacity: 0.35;
}

.ph-logo-field.is-marked-for-removal .ph-logo-field__preview::after {
    /* Bez słowa „Logo”: ta sama klasa obsługuje trzy pola — logo sklepu,
       awatar i zdjęcie główne — więc nakładka mówiła „Logo” także nad
       twarzą. Polskie znaki wpisane, wcześniej stało tu „usuniecia”. */
    content: "Oznaczone do usunięcia";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.84rem;
    font-weight: 700;
    color: var(--ph-danger);
    background: rgba(255, 250, 249, 0.78);
}

.ph-form-actions {
    display: flex;
    gap: 0.8rem;
    align-items: center;
    flex-wrap: wrap;
}

/* ── Przyciski ───────────────────────────────────────────────────────────────
   Jeden kolor akcji na ekranie: brąz. Działania wtórne siadają na chłodnym
   off-white, żeby nie konkurowały o uwagę. */

.ph-button {
    border: 0;
    border-radius: var(--radius-ctrl);
    padding: 0 1.1rem;
    gap: 0.45rem;
    font-family: var(--font-ui);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 42px;
    transition: background-color 0.18s ease;
}

.ph-button i,
.ph-button svg { width: 16px; height: 16px; stroke-width: 1.8; flex-shrink: 0; }

.ph-button--primary {
    background: var(--brown);
    color: #fff;
    box-shadow: 0 1px 2px rgba(124, 80, 40, 0.3);
}

.ph-button--primary:hover { background: var(--brown-hover); }

.ph-button--secondary {
    background: var(--btn-secondary);
    color: var(--btn-secondary-ink);
    border: 1px solid var(--line);
}

.ph-button--secondary:hover { background: var(--btn-secondary-hover); }
.ph-button--sm { height: 34px; padding: 0 0.8rem; font-size: 13px; }
.ph-button--full { width: 100%; }

.ph-modal {
    position: fixed;
    inset: 0;
    z-index: 999;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(44, 34, 25, 0.55);
    padding: 1rem;
}

.ph-modal__panel {
    background: #fff;
    border-radius: var(--ph-radius-xl);
    border: 1px solid var(--ph-border);
    box-shadow: var(--ph-shadow-md);
    max-width: 760px;
    width: 100%;
    max-height: calc(100vh - 4rem);
    overflow: auto;
    padding: 1.1rem;
}

.ph-modal__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.7rem;
}

.ph-modal__header h3 {
    margin: 0;
    font-family: var(--font-display);
    color: var(--ph-text-main);
    font-size: 1.05rem;
}

.ph-modal__close {
    border: 0;
    background: transparent;
    color: var(--ph-text-muted);
    font-size: 1.2rem;
    cursor: pointer;
}

.ph-modal__body { display: flex; flex-direction: column; gap: 0.55rem; }

.ph-review-row {
    border-bottom: 1px solid var(--line);
    padding-bottom: 0.45rem;
}

.ph-review-row p {
    margin: 0;
    color: var(--ink-soft);
}

.ph-history-list {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    max-height: 420px;
    overflow-y: auto;
}

/* Lewa krawędź niesie STAN wniosku — ta sama zasada i paleta co pasek karty.
   Brązowa krawędź (kolor akcji) kazała czytać wniosek czekający na decyzję
   jako coś do kliknięcia. „Wysłano wniosek" to stan „W trakcie", a ten jest
   w panelu niebieski. */
.ph-history-item {
    border-left: 4px solid var(--acc-neutral);
    background: #fff;
    border-radius: 0 12px 12px 0;
    padding: 0.75rem 0.9rem;
    border-top: 1px solid var(--line);
    border-right: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
}

.ph-history-item.is-submitted { border-left-color: var(--acc-blue); }
.ph-history-item.is-approved  { border-left-color: var(--acc-green); }
.ph-history-item.is-rejected  { border-left-color: var(--acc-red); }

.ph-history-title {
    margin: 0;
    color: var(--ph-text-main);
    font-weight: 600;
}

.ph-history-meta {
    margin-top: 0.45rem;
    font-size: 0.82rem;
    color: var(--ph-text-muted);
}

.ph-history-meta p { margin: 0.25rem 0 0; }
.ph-history-old { color: var(--ph-danger); text-decoration: line-through; }
.ph-history-new { color: var(--ph-success); }


@media (max-width: 768px) {
    .ph-content { padding: 1.2rem; }
    .ph-grid-2,
    .ph-form-grid,
    .ph-subdomain-row { grid-template-columns: 1fr; }
    .ph-logo-field { grid-template-columns: 1fr; }
}

.ph-page-wrap {
    width: min(100%, 100vw);
    margin: 0 auto;
    padding: 1.25rem 1.25rem 1.75rem;
}

.ph-page-wrap--wide { width: min(100%, 1600px); }
.ph-page-wrap--narrow { width: min(100%, 1600px); }

.ph-kpi-grid {
    display: grid;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.ph-kpi-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ph-kpi-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ph-kpi-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ── Kafle statystyk ─────────────────────────────────────────────────────────
   Biała karta; rola wchodzi przez chip ikony, kolor liczby i pasek u góry.
   Pełne nasycone tło z białym tekstem jest zabronione.

   Modyfikatory mają stare nazwy, bo widoki już ich używają:
     --success → Partner · --info → Ambasador · --warning → Klient
     --neutral → kafel zbiorczy „Suma"                                        */

.ph-kpi-card {
    position: relative;
    border-radius: var(--radius-card);
    border: 1px solid var(--line);
    padding: 1.1rem 1.2rem;
    background: var(--surface);
    color: var(--ink);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

/* Cienki pasek roli u góry karty — jedyne pełne użycie koloru. */
.ph-kpi-card::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: transparent;
}

.ph-kpi-card--success::before { background: var(--green); }
.ph-kpi-card--info::before    { background: var(--blue); }
.ph-kpi-card--warning::before { background: var(--gold); }
.ph-kpi-card--danger::before  { background: var(--red); }
.ph-kpi-card--neutral::before { background: var(--green-deep); }

.ph-kpi-card--success .ph-kpi-card__value { color: var(--green); }
.ph-kpi-card--info    .ph-kpi-card__value { color: var(--blue); }
.ph-kpi-card--warning .ph-kpi-card__value { color: var(--gold); }
.ph-kpi-card--danger  .ph-kpi-card__value { color: var(--red); }

/* Kafel „Suma" — wyróżniony jasnozielonym tłem i zielonym cieniem. */
.ph-kpi-card--neutral {
    background: var(--sum-bg);
    border-color: rgba(61, 107, 71, 0.18);
    box-shadow: var(--shadow-sum);
}

.ph-kpi-card--neutral .ph-kpi-card__value { color: var(--green-deep); }
.ph-kpi-card--neutral .ph-kpi-card__label,
.ph-kpi-card--neutral .ph-kpi-card__hint { color: var(--green-deep); opacity: 0.75; }

.ph-kpi-card__label {
    margin: 0;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
}

.ph-kpi-card__value {
    margin: 0.4rem 0 0;
    font-family: var(--font-display);
    font-size: 34px;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.01em;
    color: var(--ink);
}

.ph-kpi-card__value--small { font-size: 26px; }

.ph-kpi-card__hint {
    margin: 0.3rem 0 0;
    font-size: 12.5px;
    color: var(--muted);
}

/* Kwadratowy chip ikony — tło w kolorze roli o niskim kryciu. */
.ph-kpi-card__chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-ctrl);
    margin-bottom: 0.75rem;
    background: var(--brown-soft);
    color: var(--brown);
}

.ph-kpi-card__chip i,
.ph-kpi-card__chip svg { width: 18px; height: 18px; stroke-width: 1.8; }

.ph-kpi-card--success .ph-kpi-card__chip { background: var(--green-soft); color: var(--green); }
.ph-kpi-card--info    .ph-kpi-card__chip { background: var(--blue-soft);  color: var(--blue); }
.ph-kpi-card--warning .ph-kpi-card__chip { background: var(--gold-soft);  color: var(--gold); }
.ph-kpi-card--danger  .ph-kpi-card__chip { background: var(--red-soft);   color: var(--red); }
.ph-kpi-card--neutral .ph-kpi-card__chip { background: var(--green-deep-soft); color: var(--green-deep); }

/* Numer pozycji rankingu jest etykietą porządkową, nie akcją. Brąz w tym
   panelu znaczy „tu się klika", więc brązowa cyfra obiecywała klikalność,
   której ta lista nie ma. */
.ph-rank-number {
  flex-shrink: 0;
  width: 1.5rem;
  height: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--field);
  border-radius: 50%;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--ink-soft);
}

/* Bez pasków proporcji w rankingu produktów: brąz jest zarezerwowany dla
   akcji, a przy 1–2 sztukach pasek nie ma czego pokazać — pełna szerokość
   przy dwóch sztukach czyta się jak wynik wybitny. Ranking i liczba
   wystarczą. */

.ph-grid-content {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.ph-col-span-2 { grid-column: span 2 / span 2; }
.ph-stack { display: flex; flex-direction: column; gap: 1rem; }
.ph-list-stack { display: flex; flex-direction: column; gap: 0.6rem; }

.ph-list-item {
    border-bottom: 1px solid var(--line);
    padding-bottom: 0.65rem;
}

.ph-list-item:last-child { border-bottom: 0; padding-bottom: 0; }

.ph-list-item__row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.8rem;
}

.ph-list-title { margin: 0; font-weight: 600; color: var(--ph-text-main); }
.ph-list-value { margin: 0.3rem 0 0; color: var(--ink-soft); }
.ph-link-row { margin-top: 1rem; }
.ph-link { color: var(--blue); text-decoration: none; font-size: 0.9rem; }
.ph-link:hover { text-decoration: underline; }

.ph-mt-4 { margin-top: 1rem; }

.ph-mono-link {
    margin: 0;
    color: var(--ph-info);
    font-family: var(--font-mono);
    font-size: 0.88rem;
}

.ph-empty {
    text-align: center;
    color: var(--ph-text-muted);
    padding: 1.1rem;
}

.ph-stat-list { display: flex; flex-direction: column; gap: 0.6rem; }
.ph-stat-row { display: flex; justify-content: space-between; align-items: center; }
.ph-stat-value { font-weight: 600; color: var(--ph-text-main); }

.ph-badge {
    display: inline-flex;
    align-items: center;
    border-radius: 999px;
    padding: 0.2rem 0.55rem;
    font-size: 0.75rem;
    font-weight: 600;
}

.ph-table {
    width: 100%;
    border-collapse: collapse;
    border-spacing: 0;
}

.ph-table thead {
    background: var(--field);
    border-bottom: 1px solid var(--line);
}

/* ⚠ Bez `font-size` i `color` — celowo.

   Stały tu `font-size: 11px` i `color: var(--muted)`, ale reguła niżej
   (`.ph-table th, .ph-table td`) ma DOKŁADNIE tę samą siłę selektora i stoi
   PÓŹNIEJ, więc obie te deklaracje nigdy nie działały: nagłówek renderuje się
   na 14px w kolorze --ink, tak samo jak komórka. Tak wygląda panel odebrany
   przez właściciela i tak wygląda demo, więc zapisu nie „naprawiamy" — bo
   naprawa zmieniłaby wygląd KAŻDEJ tabeli po odbiorze. Usunięty jest sam
   martwy zapis, żeby nikt nie przestawił go wyżej w dobrej wierze.

   Gdyby kiedyś zapadła decyzja o mniejszym, szarym nagłówku: przenieść tę
   regułę POD `.ph-table th, .ph-table td` i dopisać oba deklaracje z powrotem. */
.ph-table th {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.ph-table th,
.ph-table td {
    padding: 0.8rem;
    text-align: left;
    border-bottom: 1px solid var(--line);
    font-size: 14px;
    color: var(--ink);
}

.ph-table tbody tr:hover { background: var(--surface-soft); }

.ph-table-card__head {
    border-bottom: 1px solid var(--ph-border);
    padding: 0.85rem 1rem;
    background: var(--ph-bg-card);
}

.ph-table-card__head .ph-card__title { margin: 0; }

.ph-table-emphasis-success {
    color: var(--ph-success) !important;
    font-weight: 600;
}
.ph-table-emphasis-danger {
    color: var(--ph-danger) !important;
    font-weight: 600;
}

.ph-tabs {
    display: flex;
    gap: 0.55rem;
    margin-bottom: 1rem;
    padding: 0.35rem;
    border: 1px solid var(--ph-border);
    border-radius: 16px;
    background: var(--surface);
    box-shadow: var(--ph-shadow-sm);
    width: fit-content;
    max-width: 100%;
}

.ph-tab {
    border: 1px solid transparent;
    border-radius: 12px;
    background: transparent;
    color: var(--ph-text-muted);
    padding: 0.75rem 1rem;
    font-weight: 700;
    cursor: pointer;
    min-height: 48px;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

.ph-tab.is-active {
    color: #fff;
    background: var(--ph-primary);
    border-color: var(--ph-primary);
    box-shadow: 0 8px 18px var(--brown-soft);
}

.ph-tab:hover {
    color: var(--ph-text-main);
    background: var(--brown-soft);
}

.ph-tab:focus-visible {
    outline: none;
    border-color: var(--brown);
    box-shadow: 0 0 0 3px var(--brown-soft);
}

.ph-tab.is-active:hover {
    color: #fff;
    background: var(--ph-primary-hover);
}

.ph-tab-panels {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.ph-tab-panel[hidden] {
    display: none !important;
}

.ph-text-center { text-align: center; }
.ph-mb-4 { margin-bottom: 1rem; }

/* ── Card Containers (Parent wrappers) ───────────────────────────────────── */
.ph-cards-stack {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.ph-cards-stack:last-child {
    margin-bottom: 0;
}

.ph-cards-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.ph-cards-grid:last-child {
    margin-bottom: 0;
}

.ph-cards-grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 768px) {
    .ph-cards-grid,
    .ph-cards-grid--3 {
        grid-template-columns: 1fr;
    }
}

.ph-filter-card {
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    box-shadow: var(--ph-shadow-sm);
    padding: 1rem;
    margin-bottom: 1rem;
}

.ph-filter-grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 0.75rem;
}

.ph-filter-grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

.ph-filter-grid__actions {
    align-self: end;
    display: flex;
    align-items: flex-end;
}

/* ── Filters Panel (News) ───────────────────────────────────────────────── */
.ph-filters-panel {
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    box-shadow: var(--ph-shadow-sm);
    padding: var(--pad-card-tight);
    margin-bottom: 1.5rem;
}

.ph-filters-info {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--ph-border);
    font-size: 0.88rem;
}

.ph-filters-active {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--ph-primary);
    font-weight: 600;
}

.ph-filters-results {
    color: var(--ph-text-muted);
}

.ph-filters-results strong {
    color: var(--ph-text-main);
    font-weight: 700;
}

.ph-filters-form {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 1rem;
    align-items: end;
}

.ph-filter-field {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.ph-filter-label {
    font-size: 0.87rem;
    font-weight: 600;
    color: var(--ph-text-main);
}

.ph-filter-input,
.ph-filter-select {
    width: 100%;
    height: 42px;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    color: var(--ink);
    padding: 0 0.8rem;
    font-size: 14px;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
}

.ph-filter-input::placeholder { color: var(--muted); }

.ph-filter-input:focus,
.ph-filter-select:focus {
    outline: none;
    border-color: var(--brown);
    box-shadow: 0 0 0 3px var(--brown-soft);
}

.ph-filter-actions {
    display: flex;
    gap: 0.65rem;
    align-items: center;
}

/* ── News Grid & Cards ──────────────────────────────────────────────────── */
.ph-news-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 1.25rem;
    margin-bottom: 1.5rem;
}

.ph-news-card {
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    box-shadow: var(--ph-shadow-sm);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: transform 0.2s, box-shadow 0.2s;
}

.ph-news-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 24px -8px rgba(51, 39, 29, 0.22);
}

.ph-news-card__image {
    width: 100%;
    height: 180px;
    overflow: hidden;
    background: var(--field);
}

.ph-news-card__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.ph-news-card__content {
    padding: var(--pad-card-tight);
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
    flex: 1;
}

.ph-news-card__badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

.ph-news-card__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--ph-text-main);
    line-height: 1.3;
}

.ph-news-card__excerpt {
    margin: 0;
    color: var(--ph-text-muted);
    font-size: 0.9rem;
    line-height: 1.5;
    flex: 1;
}

.ph-news-card__footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--ph-border);
    margin-top: auto;
}

.ph-news-card__date {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.82rem;
    color: var(--ph-text-muted);
}

.ph-empty-state {
    text-align: center;
    padding: 3rem 1.5rem;
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    margin-bottom: 1.5rem;
}

.ph-empty-state__icon {
    margin-bottom: 1rem;
}

.ph-empty-state__title {
    margin: 0 0 0.5rem;
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--ph-text-main);
}

.ph-empty-state__description {
    margin: 0 0 1.5rem;
    color: var(--ph-text-muted);
    font-size: 0.95rem;
}

.ph-filter-btn {
    border: 0;
    border-radius: var(--radius-ctrl);
    height: 42px;
    padding: 0 1.1rem;
    font-family: var(--font-ui);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    transition: background-color 0.18s ease;
}

.ph-filter-btn i,
.ph-filter-btn svg { width: 16px; height: 16px; stroke-width: 1.8; flex-shrink: 0; }

.ph-filter-btn--primary {
    background: var(--brown);
    color: #fff;
    box-shadow: 0 1px 2px rgba(124, 80, 40, 0.3);
}

.ph-filter-btn--primary:hover {
    background: var(--brown-hover);
}

.ph-filter-btn--secondary {
    background: var(--btn-secondary);
    color: var(--btn-secondary-ink);
    border: 1px solid var(--line);
}

.ph-filter-btn--secondary:hover {
    background: var(--btn-secondary-hover);
}

@media (max-width: 768px) {
    .ph-news-grid {
        grid-template-columns: 1fr;
    }
}

.ph-table-card {
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    box-shadow: var(--ph-shadow-sm);
    overflow-x: auto;
    overflow-y: clip;
    position: relative;
    -webkit-overflow-scrolling: touch;
}

/* Right-edge scroll shadow — appears when table has more content to the right */
.ph-table-card::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 48px;
    height: 100%;
    background: linear-gradient(to right, transparent, rgba(30, 23, 20, 0.07));
    border-radius: 0 var(--ph-radius-xl) var(--ph-radius-xl) 0;
    pointer-events: none;
    z-index: 10;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.ph-table-card.ph-scroll-more-right::after { opacity: 1; }

/* Sticky first column — automatic on all tables inside scrollable cards */
.ph-table-card .ph-table thead th:first-child,
.ph-table-card .ph-table tbody td:first-child,
.ph-bottom-card .ph-table thead th:first-child,
.ph-bottom-card .ph-table tbody td:first-child {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--ph-bg-card);
}
.ph-table-card .ph-table thead th:first-child,
.ph-bottom-card .ph-table thead th:first-child { z-index: 3; }

/* Separator line on sticky col — visible only after scroll starts */
.ph-table-card .ph-table thead th:first-child::after,
.ph-table-card .ph-table tbody td:first-child::after,
.ph-bottom-card .ph-table thead th:first-child::after,
.ph-bottom-card .ph-table tbody td:first-child::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 1px;
    height: 100%;
    background: var(--ph-border);
    opacity: 0;
    transition: opacity 0.15s;
}
.ph-table-card.ph-scroll-started .ph-table th:first-child::after,
.ph-table-card.ph-scroll-started .ph-table td:first-child::after,
.ph-bottom-card.ph-scroll-started .ph-table th:first-child::after,
.ph-bottom-card.ph-scroll-started .ph-table td:first-child::after {
    opacity: 1;
}

.ph-pagination {
    margin-top: 1rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.ph-button[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
}

.ph-inline-actions {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.ph-breadcrumb {
    margin-bottom: 0.6rem;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.88rem;
}

.ph-heading-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.8rem;
}

.ph-details-grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
    gap: 1rem;
}

.ph-details-list {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.ph-details-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.8rem;
    border-top: 1px solid var(--line);
    padding-top: 0.55rem;
}

.ph-details-row:first-child {
    border-top: 0;
    padding-top: 0;
}

.ph-surface-soft {
    border: 1px solid var(--line);
    background: var(--surface-soft);
    border-radius: 12px;
    padding: 0.7rem 0.8rem;
}

.ph-address-block {
    color: var(--ph-text-muted);
    line-height: 1.55;
}

.ph-address-block p { margin: 0 0 0.2rem; }

.ph-kpi-card__value--reset {
    margin: 0;
    color: var(--ph-success);
}

.ph-loading {
    text-align: center;
    color: var(--ph-text-muted);
    padding: 1.5rem;
}

.ph-error {
    color: var(--ph-danger);
    padding: 0.9rem;
    border: 1px solid rgba(150, 54, 44, 0.28);
    border-radius: 12px;
    background: var(--red-soft);
}

/* ── Dashboard stat cards with sparklines ───────────────────────────────── */
.ph-stats-label {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--ph-text-muted);
    margin: 0 0 0.75rem;
}

.ph-stats-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.ph-stat-cards-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.ph-stat-card {
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    box-shadow: var(--ph-shadow-sm);
    padding: 1rem 1.15rem 0.85rem;
    min-width: 0;
    max-width: 100%;
}

.ph-stat-card__category {
    font-size: 0.7rem;
    color: var(--ph-text-muted);
    margin: 0 0 0.05rem;
}

.ph-stat-card__name {
    font-size: 0.86rem;
    font-weight: 700;
    color: var(--ph-text-main);
    margin: 0 0 0.65rem;
}

.ph-stat-card__body {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 0.5rem;
    min-width: 0;
}

.ph-stat-card__body > :first-child {
    min-width: 0;
    flex: 1;
}

.ph-stat-card__value {
    font-family: var(--font-display);
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--ph-text-main);
    line-height: 1.1;
    margin: 0;
    white-space: nowrap;
    word-break: keep-all;
    letter-spacing: -0.02em;
}

.ph-stat-card__value small {
    white-space: nowrap;
}

.ph-stat-card__pct {
    font-size: 0.74rem;
    font-weight: 600;
    margin: 0.3rem 0 0;
    color: var(--ph-success);
}

.ph-stat-card__pct--down { color: var(--ph-danger); }

/* ── Sales chart card ───────────────────────────────────────────────────── */
.ph-sales-chart-card {
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    box-shadow: var(--ph-shadow-sm);
    padding: 1.25rem 1.4rem 1.1rem;
    display: flex;
    flex-direction: column;
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
}

.ph-sales-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
}

.ph-sales-title {
    font-size: 0.84rem;
    color: var(--ph-text-muted);
    margin: 0;
}

.ph-sales-value {
    font-family: var(--font-display);
    font-size: 1.8rem;
    font-weight: 700;
    color: var(--ph-text-main);
    margin: 0.15rem 0 0;
    line-height: 1.15;
}

.ph-sales-yoy {
    font-size: 0.75rem;
    color: var(--ph-success);
    font-weight: 600;
    margin: 0.15rem 0 0;
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.ph-sales-yoy--down { color: var(--ph-danger); }

.ph-period-toggle {
    display: flex;
    gap: 0.2rem;
    background: var(--field);
    border-radius: 8px;
    padding: 0.2rem;
    flex-shrink: 0;
}

.ph-period-btn {
    border: 0;
    background: transparent;
    color: var(--ph-text-muted);
    padding: 0.28rem 0.65rem;
    font-size: 0.72rem;
    font-weight: 700;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    white-space: nowrap;
}

.ph-period-btn.is-active {
    background: var(--ph-text-main);
    color: #fff;
}

.ph-chart-wrap {
    flex: 1;
    margin-top: 0.9rem;
    min-height: 160px;
    width: 100%;
    max-width: 100%;
    position: relative;
    overflow: hidden;
}

.ph-chart-wrap canvas {
    max-width: 100% !important;
    height: auto !important;
}

/* ── Bottom tables grid ─────────────────────────────────────────────────── */
.ph-bottom-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    margin-bottom: 1rem;
}

.ph-bottom-card {
    background: var(--ph-bg-card);
    border: 1px solid var(--ph-border);
    border-radius: var(--ph-radius-xl);
    box-shadow: var(--ph-shadow-sm);
    overflow-x: auto;
    overflow-y: clip;
    position: relative;
    -webkit-overflow-scrolling: touch;
}
.ph-bottom-card::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 48px;
    height: 100%;
    background: linear-gradient(to right, transparent, rgba(30, 23, 20, 0.07));
    border-radius: 0 var(--ph-radius-xl) var(--ph-radius-xl) 0;
    pointer-events: none;
    z-index: 10;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.ph-bottom-card.ph-scroll-more-right::after { opacity: 1; }

.ph-bottom-card__title {
    font-size: 0.82rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ph-text-muted);
    margin: 0;
    padding: 0.9rem 1.1rem 0.6rem;
    border-bottom: 1px solid var(--ph-border);
}

.ph-bottom-card .ph-table {
    table-layout: fixed;
    width: 100%;
}

.ph-bottom-card .ph-table th,
.ph-bottom-card .ph-table td {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Keep referral list readable: name/email/date columns with stable widths. */
.ph-bottom-grid > .ph-bottom-card:last-child .ph-table th:nth-child(1),
.ph-bottom-grid > .ph-bottom-card:last-child .ph-table td:nth-child(1) {
    width: 30%;
}

.ph-bottom-grid > .ph-bottom-card:last-child .ph-table th:nth-child(2),
.ph-bottom-grid > .ph-bottom-card:last-child .ph-table td:nth-child(2) {
    width: 50%;
}

.ph-bottom-grid > .ph-bottom-card:last-child .ph-table th:nth-child(3),
.ph-bottom-grid > .ph-bottom-card:last-child .ph-table td:nth-child(3) {
    width: 20%;
}

/* Plakietki — tekst w kolorze roli na jej własnym rozcieńczeniu. */
.ph-badge--success { background: var(--green-soft); color: var(--green); }
.ph-badge--info    { background: var(--blue-soft);  color: var(--blue); }
.ph-badge--warning { background: var(--gold-soft);  color: var(--gold); }
.ph-badge--neutral { background: var(--field);      color: var(--ink-soft); }
.ph-badge--danger  { background: var(--red-soft);   color: var(--red); }

/* ── Kropka statusu aktywności ───────────────────────────────────────────── */
.ph-dot {
    display: inline-block;
    width: 8px; height: 8px;
    border-radius: 50%;
    vertical-align: middle;
    flex-shrink: 0;
}
/* Kropka bierze nazwę od KOLORU, nie od segmentu. Nazwy segmentowe
   (--active/--expiring/--inactive) powtarzałyby taksonomię w drugim miejscu:
   dodanie segmentu wymagałoby nowej klasy, a zmiana nazwy zostawiała martwą
   regułę. Taksonomia mieszka w core.js; arkusz wie tylko, jak wygląda kolor. */
.ph-dot--green { background: var(--green); }
.ph-dot--gold  { background: var(--gold); }
.ph-dot--red   { background: var(--red); }
.ph-dot--blue  { background: var(--blue); }
.ph-dot--muted { background: var(--muted); }

/* Nazwy segmentowe — zostają dla widoków, które jeszcze ich używają. */
.ph-dot--active   { background: var(--green); }
.ph-dot--expiring { background: var(--gold); }
.ph-dot--inactive { background: var(--red); }
.ph-dot--none     { background: var(--muted); }
.ph-dot-cell { display: flex; align-items: center; gap: .4rem; white-space: nowrap; }

/* ── Pill roli (kropka + etykieta) ───────────────────────────────────────── */
.ph-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.22rem 0.6rem 0.22rem 0.5rem;
    border-radius: 999px;
    font-size: 12.5px;
    font-weight: 600;
    white-space: nowrap;
    background: var(--field);
    color: var(--ink-soft);
}

.ph-pill::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.ph-pill--green { background: var(--green-soft); color: var(--green); }
.ph-pill--blue  { background: var(--blue-soft);  color: var(--blue); }
.ph-pill--gold  { background: var(--gold-soft);  color: var(--gold); }
.ph-pill--red   { background: var(--red-soft);   color: var(--red); }

/* Pill statusu w nagłówku strony (np. „Program aktywny"). */
.ph-status-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.4rem 0.85rem;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--surface);
    font-size: 13px;
    font-weight: 600;
    color: var(--ink-soft);
    white-space: nowrap;
}

.ph-status-pill::before {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--green);
    flex-shrink: 0;
}

/* ── Avatar z inicjałami ─────────────────────────────────────────────────── */
.ph-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
    flex-shrink: 0;
    background: var(--field);
    color: var(--ink-soft);
    text-transform: uppercase;
}

.ph-avatar--green { background: var(--green-soft); color: var(--green); }
.ph-avatar--blue  { background: var(--blue-soft);  color: var(--blue); }
.ph-avatar--gold  { background: var(--gold-soft);  color: var(--gold); }

/* Komórka tabeli „avatar + nazwisko (+ email pod spodem)". */
.ph-person-cell {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    min-width: 0;
}

.ph-person-cell__meta {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.35;
}

.ph-person-cell__name {
    font-weight: 600;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ph-person-cell__email {
    font-size: 12.5px;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Kwoty prowizji w kolorze roli. */
.ph-amount--green { color: var(--green); font-weight: 600; }
.ph-amount--blue  { color: var(--blue);  font-weight: 600; }
.ph-amount--gold  { color: var(--gold);  font-weight: 600; }

/* ── Sekcja linków polecających ──────────────────────────────────────────────
   Każdy link to osobny panel na tle wtórnym, z paskiem roli po lewej. Stała
   kolumna 190px trzyma tytuły w jednej osi, żeby pola URL zaczynały się równo
   niezależnie od długości nazwy roli. */

.ph-link-panel {
    display: grid;
    grid-template-columns: 190px minmax(0, 1fr) auto;
    align-items: center;
    gap: 1rem;
    padding: 0.9rem 1rem 0.9rem 1.15rem;
    border: 1px solid var(--line);
    border-left: 4px solid var(--muted);
    border-radius: var(--radius-ctrl);
    background: var(--surface-soft);
}

.ph-link-panel + .ph-link-panel { margin-top: 0.7rem; }

.ph-link-panel--green { border-left-color: var(--green); }
.ph-link-panel--blue  { border-left-color: var(--blue); }
.ph-link-panel--gold  { border-left-color: var(--gold); }

/* ── Trzy warianty jednego linku na wspólnej podkładce ───────────────────────
   To nie są trzy narzędzia, tylko ten sam kod polecający z innym parametrem
   roli — luzem na płótnie czytały się jak trzy osobne rzeczy. Podkładka niczego
   panelom nie odbiera: zachowują ramkę, tło wtórne, zaokrąglenie i lewy akcent. */
.ph-link-panels {
    padding: 0.9rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
    box-shadow: var(--shadow-card);
}

.ph-link-panel__label {
    margin: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--ink);
}

.ph-link-panel__desc {
    margin: 0.1rem 0 0;
    font-size: 12.5px;
    color: var(--muted);
    line-height: 1.4;
}

.ph-link-panel__url {
    display: block;
    width: 100%;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--ink-soft);
    overflow-x: auto;
    white-space: nowrap;
}

.ph-link-panel__actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Przycisk po skopiowaniu — zielone potwierdzenie zamiast brązu akcji. */
.ph-copy-btn.is-copied,
.ph-copy-btn.is-copied:hover {
    background: var(--green);
    box-shadow: none;
}

@media (max-width: 1080px) {
    .ph-link-panel {
        grid-template-columns: 1fr;
        gap: 0.6rem;
    }
}

/* ── Sidebar footer + account block ─────────────────────────────────────── */
.ph-sidebar__footer {
    margin-top: auto;
    padding: 0.6rem;
    border-radius: 14px;
    background: rgba(243, 234, 217, 0.05);
    border: 1px solid rgba(243, 234, 217, 0.08);
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.ph-sidebar__footer-link,
.ph-sidebar__user,
.ph-sidebar__logout {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    width: 100%;
    color: var(--sidebar-text);
    text-decoration: none;
    padding: 9px 12px;
    border-radius: var(--radius-ctrl);
    font-size: 14px;
    font-weight: 500;
    transition: background-color 0.18s ease, color 0.18s ease;
}

.ph-sidebar__footer-link i,
.ph-sidebar__user i,
.ph-sidebar__logout i,
.ph-sidebar__footer-link svg,
.ph-sidebar__user svg,
.ph-sidebar__logout svg {
    width: 18px;
    height: 18px;
    stroke-width: 1.8;
    flex-shrink: 0;
}

.ph-sidebar__footer-link:hover {
    background: rgba(243, 234, 217, 0.07);
    color: var(--sidebar-text-strong);
}

/* ── Karta użytkownika w stopce sidebara ─────────────────────────────────── */
.ph-sidebar__user-card {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 10px 12px;
    margin-bottom: 0.25rem;
    border-radius: var(--radius-ctrl);
    background: rgba(243, 234, 217, 0.07);
    text-decoration: none;
    min-width: 0;
}

.ph-sidebar__user-card:hover { background: rgba(243, 234, 217, 0.11); }

.ph-sidebar__user-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: rgba(243, 234, 217, 0.14);
    color: var(--sidebar-text-strong);
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    flex-shrink: 0;
}

.ph-sidebar__user-meta { min-width: 0; display: flex; flex-direction: column; }

.ph-sidebar__user-name {
    margin: 0;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--sidebar-text-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ph-sidebar__user-role {
    margin: 0;
    font-size: 11px;
    color: var(--sidebar-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ph-sidebar__logout {
    margin-top: 0.45rem;
    padding-top: 0.8rem;
    border-top: 1px solid rgba(248, 243, 236, 0.14);
    color: rgba(248, 243, 236, 0.7);
    font-size: 0.83rem;
    justify-content: center;
}

/* Tekst rozjaśniony do jasnego tonu sidebara, a sygnał „to wylogowanie" niesie
   czerwonawe tło. Jasna czerwień na ciemnym tle wymagałaby koloru spoza palety. */
.ph-sidebar__logout:hover {
    background: rgba(150, 54, 44, 0.26);
    color: var(--sidebar-text-strong);
}

@media (max-width: 1080px) {
    .ph-sidebar { width: 240px; }
    .ph-content { margin-left: 240px; }
    .ph-main { margin-left: 240px; }
    .ph-main > .ph-content { margin-left: 0; }
    .ph-stats-layout { grid-template-columns: 1fr; }
    .ph-bottom-grid  { grid-template-columns: 1fr; }
    .ph-kpi-grid--4,
    .ph-kpi-grid--3,
    .ph-grid-content { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ph-col-span-2 { grid-column: span 2 / span 2; }
    .ph-filter-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ph-filters-form { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .ph-details-grid { grid-template-columns: 1fr; }
}

@media (max-width: 768px) {
    .ph-layout { display: block; }
    /* ⚠ Sidebar NIE wraca tu do przepływu. `position: static` sprawiał, że
       schowane menu dalej zajmowało pełną wysokość, więc przy 390 px treść
       zaczynała się po ~900 px pustego ekranu. Sam transform nie odbiera
       elementowi miejsca w układzie. */
    .ph-content { margin-left: 0; min-height: auto; }
    .ph-kpi-grid--4,
    .ph-kpi-grid--3,
    .ph-grid-content { grid-template-columns: 1fr; }
    .ph-col-span-2 { grid-column: span 1 / span 1; }
    .ph-list-item__row { flex-direction: column; }
    .ph-filter-grid { grid-template-columns: 1fr; }
    .ph-filters-form { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
    .ph-stat-cards-grid { grid-template-columns: 1fr; }
}

/* ── Field tooltips ───────────────────────────────────────────────────────── */

.ph-tooltip-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin-left: 5px;
    vertical-align: middle;
    cursor: help;
}

.ph-tooltip-icon {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: var(--muted);
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    font-style: italic;
    font-family: var(--font-display);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    flex-shrink: 0;
    transition: background 0.15s;
}

/* Dymek otwiera się także z klawiatury i dotyku, nie tylko na najechanie.
   Ikona ma tabindex="0", więc daje się na nią wejść tabulatorem — bez tych
   selektorów fokus stawał na elemencie, który nic nie pokazuje, a treść
   podpowiedzi była nieosiągalna dla każdego bez myszy. */
.ph-tooltip-wrap:hover .ph-tooltip-icon,
.ph-tooltip-wrap:focus-within .ph-tooltip-icon {
    background: var(--ink-soft);
}

/* Obwódka fokusu na OPAKOWANIU, nie na ikonie: tabindex="0" siedzi na
   .ph-tooltip-wrap (ikona ma aria-hidden), więc selektor na .ph-tooltip-icon
   nigdy by nie zadziałał — dymek otwierałby się z klawiatury, ale nie byłoby
   widać, na czym stoi fokus. */
.ph-tooltip-wrap:focus-visible {
    outline: 2px solid var(--brown);
    outline-offset: 2px;
    border-radius: 50%;
}

.ph-tooltip-text {
    display: none;
    position: absolute;
    left: 50%;
    bottom: calc(100% + 6px);
    transform: translateX(-50%);
    background: var(--ink);
    color: var(--sidebar-text-strong);
    font-size: 12px;
    font-weight: 400;
    font-style: normal;
    line-height: 1.55;
    padding: 9px 13px;
    border-radius: 8px;
    width: 280px;
    white-space: normal;
    z-index: 999;
    pointer-events: none;
    box-shadow: 0 4px 12px rgba(0,0,0,.18);
}

.ph-tooltip-text::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--ink);
}

.ph-tooltip-wrap:hover .ph-tooltip-text,
.ph-tooltip-wrap:focus-within .ph-tooltip-text {
    display: block;
}

.ph-breadcrumb .ph-breadcrumb__link {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.ph-news-article {
    max-width: 860px;
    margin: 0 auto 1.5rem;
}

.ph-news-article > * + * {
    margin-top: 1.25rem;
}

.ph-news-article .ph-news-article__title,
.ph-news-article .ph-news-article__badges  {
    padding: 0 1.5rem;
}

/* Nagłówek artykułu — bez tej reguły renderował się domyślnym stylem
   przeglądarki dla h1 (nic w arkuszu go wcześniej nie ustawiało), stąd
   wyglądał nieproporcjonalnie duży. Wyraźnie mniejszy niż nagłówek strony
   .ph-section-title (38px/800) — to tytuł artykułu do czytania, nie
   nagłówek ekranu. */
.ph-news-article__title {
    font-size: 28px;
    font-weight: 800;
    line-height: 1.25;
}

.ph-news-article .ph-badge {
    gap: 0.4rem;
}

.ph-news-article .ph-news-article__content {
    padding: var(--pad-card);
    border-radius: 1.5rem;
    background: #fff;
}

.ph-news-article .ph-news-article__content > * + * {
    margin-top: 1rem;
}

/* ── Sortable table headers — global ──────────────────────────────────────── */
/* ⚠ Nagłówek sortowalny NIE dostaje white-space: nowrap. Strzałka dokłada
   ~12 px do każdej kolumny i przy sześciu kolumnach ostatnia wyjeżdżała poza
   kadr na 1440 px. Nagłówek może się zawinąć na dwie linie — kwota w wierszu
   nie może, i to jest ta różnica. */
.ph-table th.ph-sortable {
    cursor: pointer;
    user-select: none;
}
.ph-sort-icon {
    display: inline-block;
    margin-left: 4px;
    opacity: 0.38;
    font-size: 0.78em;
    vertical-align: middle;
    line-height: 1;
}
.ph-table th.ph-sortable:hover .ph-sort-icon { opacity: 0.75; }
/* Aktywna kolumna ma być widoczna bez wpatrywania się w strzałkę — po czym
   posortowana jest tabela, widać wtedy kątem oka, a nie dopiero po namyśle. */
.ph-table th.ph-sortable.is-sorted { color: var(--ink); }
.ph-table th.ph-sortable.is-sorted .ph-sort-icon { opacity: 1; }
.ph-table th.ph-sortable:focus-visible {
    outline: 2px solid var(--brown);
    outline-offset: -2px;
}

/* ── Clickable table rows ─────────────────────────────────────────────────── */
.ph-table tbody tr[data-href] { cursor: pointer; }
.ph-table tbody tr[data-href]:hover td { background: var(--surface-soft); }

/* ── Row action arrow ────────────────────────────────────────────────────── */
.ph-table-action-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 6px;
    color: var(--ph-text-muted);
    text-decoration: none;
    font-size: 1rem;
    transition: background 0.15s, color 0.15s;
}
.ph-table-action-arrow:hover {
    background: var(--brown);
    color: #fff;
}

/* ── Scroll hint pill (fixed to bottom of viewport) ─────────────────────── */
.ph-scroll-hint {
    position: fixed;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 9999;
    pointer-events: none;
    opacity: 1;
    transition: opacity 0.3s;
}
.ph-scroll-hint--hidden {
    opacity: 0;
}
.ph-scroll-hint__pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: var(--ink);
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    padding: 6px 12px;
    border-radius: 20px;
    letter-spacing: 0.03em;
    white-space: nowrap;
    cursor: default;
    user-select: none;
    backdrop-filter: blur(4px);
    box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}

/* ── Utility: treść tylko dla czytników ekranu ───────────────────────────── */
.ph-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── Wspólny pierścień skupienia ──────────────────────────────────────────
   Pola formularza, zakładki i sortowalne nagłówki miały już brązowy pierścień
   (osiem miejsc z `outline: none` + box-shadow). Przyciski, chipy, pozycje
   sidebara i strzałki pagera zostawały przy obwódce systemowej — więc ten sam
   panel sygnalizował skupienie na dwa sposoby, a na ciemnym sidebarze obwódka
   systemowa bywa ledwo widoczna.

   Wyłącznie :focus-visible, czyli tylko dla klawiatury — kliknięcie myszą nie
   rysuje niczego. Obrys nie wchodzi w układ, więc nic się nie przesuwa.
   Odnośniki w treści (.ph-link, .ph-breadcrumb) zostają przy obwódce
   systemowej: są częścią zdania, a pierścień wokół słowa rozpychałby wiersz. */
.ph-button:focus-visible,
.ph-chip:focus-visible,
.ph-copy-btn:focus-visible,
.ph-pager__nav:focus-visible,
.ph-modal__close:focus-visible,
.ph-file-upload__label:focus-visible,
.ph-topbar__menu:focus-visible {
    outline: 2px solid var(--brown);
    outline-offset: 2px;
}

/* Sidebar stoi na ciemnym tle — brąz zlewa się z nim, więc pierścień jest
   w jasnym tonie sidebara. */
.ph-sidebar__link:focus-visible,
.ph-sidebar__logout:focus-visible,
.ph-sidebar__footer-link:focus-visible {
    outline: 2px solid var(--sidebar-text-strong);
    outline-offset: -2px;
}

/* ── Utility: icon sizes ─────────────────────────────────────────────────── */
.ph-icon-12 { width: 12px; height: 12px; flex-shrink: 0; }
.ph-icon-14 { width: 14px; height: 14px; flex-shrink: 0; }
.ph-icon-16 { width: 16px; height: 16px; flex-shrink: 0; }
.ph-icon-20 { width: 20px; height: 20px; flex-shrink: 0; }
.ph-icon-24 { width: 24px; height: 24px; flex-shrink: 0; }
.ph-icon-32 { width: 32px; height: 32px; flex-shrink: 0; }
/* 48 px używa wyłącznie ikona pustego stanu — była wpisana atrybutem style
   wprost w widoku 404, czyli jedynym rozmiarem ikony poza tą rodziną. */
.ph-icon-48 { width: 48px; height: 48px; flex-shrink: 0; }

/* ── Utility: overlay blur (locked features) ─────────────────────────────── */
.ph-overlay-blur {
    position: absolute;
    inset: 0;
    background: rgba(255, 255, 255, 0.85);
    backdrop-filter: blur(4px);
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 24px;
    text-align: center;
}

/* ── Utility: inline meta row (label + value pairs) ─────────────────────── */
.ph-meta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 2rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--line);
    font-size: 0.8125rem;
    color: var(--ink);
}

/* ── Ledger: muted rows (pending / unsettled events) ────────────────────── */
.ph-table tbody tr.ph-row-muted td { opacity: 0.55; }

/* ═══════════════════════════════════════════════════════════════════════════
   Komponenty zastępujące style wpisywane wprost w atrybutach style= w widokach
   — bez nich ten sam element wyglądał inaczej w demo i w panelu.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Komunikaty ──────────────────────────────────────────────────────────── */
.ph-notice {
    margin-bottom: 1.5rem;
    padding: 0.85rem 1.1rem;
    border: 1px solid var(--line);
    border-left: 4px solid var(--muted);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    font-size: 14px;
    color: var(--ink);
}

.ph-notice--success { border-left-color: var(--green); }
.ph-notice--error   { border-left-color: var(--red); }
.ph-notice--warning { border-left-color: var(--gold); }

/* ── Kropka statusu (oczekujące zdarzenia w wyciągu) ─────────────────────── */
.ph-status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--muted);
    flex-shrink: 0;
}

.ph-status-dot--pending { background: var(--gold); }
.ph-status-dot--done    { background: var(--green); }

/* ── Wyciąg prowizji ─────────────────────────────────────────────────────── */
.ph-ledger-title  { font-weight: 600; color: var(--ink); }
.ph-ledger-balance { color: var(--muted); font-size: 13px; }
.ph-amount-cell   { white-space: nowrap; font-weight: 600; }
.ph-coin-amount--used { color: var(--muted); }

/* ── Kafle: jednostka przy dużej liczbie („zł", „szt.") ──────────────────── */
.ph-stat-card__unit {
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 600;
    color: var(--muted);
    margin-left: 0.2rem;
}

.ph-rank-item__name { font-weight: 600; color: var(--ink); }

/* ── Pola tylko do odczytu ───────────────────────────────────────────────── */
.ph-input--readonly {
    background: var(--field);
    color: var(--muted);
    cursor: default;
}

/* ── Nakładka „funkcja zablokowana" ──────────────────────────────────────── */
.ph-locked-feature__icon { color: var(--brown); }

.ph-locked-feature__hint {
    font-size: 13px;
    color: var(--muted);
    margin: 0;
}

/* ── Stany puste ─────────────────────────────────────────────────────────── */
.ph-empty-state__icon--muted { color: var(--muted); }
.ph-empty-state__icon--error { color: var(--red); }

/* ── Miniatura wideo w Bazie wiedzy ──────────────────────────────────────── */
.ph-kb-video-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
    background: rgba(44, 34, 25, 0.34);
}

.ph-kb-video-overlay__icon { color: #fff; }

/* ── Macierz funkcji w planach ───────────────────────────────────────────── */
.ph-matrix-yes { color: var(--green); }
.ph-matrix-no  { color: var(--muted); }

/* ═══ Subskrypcja ═══════════════════════════════════════════════════════════
   Dwa tła i tylko dwa: --surface i --surface-soft. */

.ph-plan-status {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: var(--pad-card);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
    box-shadow: var(--shadow-card);
    margin-bottom: 1.5rem;
}

.ph-plan-status__label {
    margin: 0;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
}

.ph-plan-status__level {
    margin: 0.3rem 0 0;
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 700;
    color: var(--ink);
}

.ph-plan-status__expiry { text-align: right; }

.ph-plan-status__days {
    margin: 0.3rem 0 0;
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 700;
    color: var(--ink);
}

.ph-plan-status__days--warn { color: var(--gold); }
.ph-plan-status__date  { margin: 0.15rem 0 0; font-size: 12.5px; color: var(--muted); }
.ph-plan-status__coins { margin: 0.9rem 0 0; font-size: 14px; color: var(--ink-soft); flex-basis: 100%; }

.ph-plans-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.ph-plan-card {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: var(--pad-card);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
    box-shadow: var(--shadow-card);
}

/* Wyróżniony plan — obramowanie w kolorze marki, bez zalewania tłem. */
.ph-plan-card--featured { border: 2px solid var(--brown); }

.ph-plan-card__ribbon {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 0.2rem 0.7rem;
    border-radius: 999px;
    background: var(--brown);
    color: #fff;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.04em;
    white-space: nowrap;
}

.ph-plan-card__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.9rem;
}

.ph-plan-card__icon { color: var(--muted); }
.ph-plan-card--pro        .ph-plan-card__icon { color: var(--brown); }
.ph-plan-card--enterprise .ph-plan-card__icon { color: var(--ink); }

.ph-plan-card__name {
    margin: 0;
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 700;
    color: var(--ink);
}

.ph-plan-card__price {
    margin: 0 0 0.15rem;
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 700;
    color: var(--ink);
    line-height: 1.1;
}

.ph-plan-card__period { margin: 0 0 1.2rem; font-size: 12.5px; color: var(--muted); }

.ph-plan-card__perks {
    list-style: none;
    margin: 0 0 1.2rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    flex: 1;
}

.ph-plan-card__perk {
    display: flex;
    align-items: flex-start;
    gap: 0.45rem;
    font-size: 13.5px;
    color: var(--ink);
}

.ph-plan-card__perk i,
.ph-plan-card__perk svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    margin-top: 3px;
    color: var(--green);
    stroke-width: 1.8;
}

.ph-plan-card__perk--locked { color: var(--muted); }

.ph-plan-card__perk--locked i,
.ph-plan-card__perk--locked svg { color: var(--muted); }

.ph-plan-card__note { margin: 0.7rem 0 0; font-size: 12px; color: var(--muted); text-align: center; }

.ph-sub-summary {
    margin-bottom: 0.9rem;
    padding: 0.9rem;
    border-radius: var(--radius-ctrl);
    background: var(--surface-soft);
    font-size: 14px;
}

.ph-sub-expiry-note { font-size: 12.5px; color: var(--muted); }

@media (max-width: 1080px) {
    .ph-plans-grid { grid-template-columns: 1fr; }
    .ph-plan-status__expiry { text-align: left; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Komponenty wspólne z demo. Widoki panelu używają tych klas, więc definicje
   muszą być tutaj, a nie w arkuszu demo.
   ═══════════════════════════════════════════════════════════════════════════ */

.ph-mt-1 { margin-top: 0.25rem; }
.ph-mt-2 { margin-top: 0.5rem; }

.ph-input--sm {
    height: 36px;
    padding: 0 0.55rem;
    font-size: 13px;
    width: auto;
    min-height: 0;
}

.ph-button--lg { height: 46px; padding: 0 1.4rem; font-size: 15px; }
.ph-button--block { display: flex; width: 100%; justify-content: center; }

.ph-news-article__cta {
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--line);
}

.ph-copy-status { color: var(--green); font-weight: 600; }
/* Niepowodzenie kopiowania odsłania ten napis (app.js zdejmuje wtedy klasę
   ukrywającą) — a odsłonięty komunikat o błędzie nie może być zielony. */
.ph-copy-status--error { color: var(--red); }

/* ── Pliki do pobrania ───────────────────────────────────────────────────── */
.ph-files-section { margin-top: 1.5rem; }

.ph-files-section__title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
    color: var(--ink);
    margin: 0 0 0.85rem;
}

.ph-files-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
}

.ph-file-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    padding: 1.1rem 1rem;
    text-align: center;
    box-shadow: var(--shadow-card);
}

.ph-file-card__icon { margin-bottom: 0.5rem; color: var(--brown); }

.ph-file-card__title {
    font-size: 14px;
    font-weight: 600;
    margin: 0 0 0.2rem;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ph-file-card__size { font-size: 12px; color: var(--muted); margin: 0 0 0.75rem; }

/* ── Wideo i miniatury ───────────────────────────────────────────────────── */
.ph-kb-video-wrap { width: 100%; position: relative; }

.ph-kb-video-placeholder {
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius-card);
    background: var(--field);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    color: var(--muted);
}

/* Płaskie tło zamiast gradientu — wytyczne nie przewidują teł gradientowych
   poza sidebarem. */
.ph-thumb-placeholder {
    width: 100%;
    height: 150px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--field);
    color: var(--muted);
}

.ph-thumb-placeholder--card    { border-radius: var(--radius-card) var(--radius-card) 0 0; }
.ph-thumb-placeholder--article { border-radius: var(--radius-card); height: 260px; }

/* ── Modal ───────────────────────────────────────────────────────────────────
   .ph-modal to nakładka na cały ekran, .ph-modal-panel to okno w środku.
   ⚠ Nie nadawać .ph-modal znaczenia okna — jeden selektor znaczyłby wtedy
   co innego w demo, a co innego w panelu. */

.ph-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(44, 34, 25, 0.55);
}

.ph-modal-panel {
    background: var(--surface);
    border-radius: var(--radius-card);
    padding: var(--pad-card);
    max-width: 420px;
    width: 100%;
    /* Bez tych dwóch linii okno rośnie poza ekran i wraz z nim wychodzą
       przyciski, którymi się je zamyka — a modal jest nakładką na cały
       widok, więc pod spodem nie ma czego przewinąć. Na niskim oknie
       (laptop 13", pasek zakładek, klawiatura ekranowa) „Potwierdź zakup"
       i „Anuluj" stawały się nieosiągalne. Bliźniacza .ph-modal__panel
       miała to od początku. */
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    box-shadow: 0 20px 60px rgba(44, 34, 25, 0.35);
}

.ph-modal__title {
    margin: 0 0 0.5rem;
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 700;
    color: var(--ink);
}

.ph-modal__text { margin: 0 0 1.25rem; font-size: 14px; color: var(--muted); line-height: 1.55; }
.ph-modal__actions { display: flex; gap: 0.6rem; justify-content: flex-end; }

/* ── Ranking produktów ───────────────────────────────────────────────────── */
.ph-rank-item__name { font-weight: 600; color: var(--ink); }

/* ═══════════════════════════════════════════════════════════════════════════
   Statystyki — strefy i kafle metryk. Strefę wyznacza label i światło, nie
   kolejna ramka. Dokładnie JEDEN bohater na strefę.
   ═══════════════════════════════════════════════════════════════════════════ */

.ph-zone { margin-bottom: 50px; }
.ph-zone:last-child { margin-bottom: 0; }

/* ⚠ Rytm stref jest nienaruszalny: 50 px wyznacza strefa, nie jej zawartość.
   Część komponentów (siatki, stany puste) niesie własny margin-bottom, który
   doklejałby się do rytmu i dawał 74 px zamiast 50. Zerujemy go ostatniemu
   dziecku strefy. */
.ph-zone > :last-child,
.ph-zone > .ph-plans-grid:last-child,
.ph-zone > .ph-news-grid:last-child,
.ph-zone > .ph-empty-state:last-child,
.ph-zone > .ph-action-grid:last-child,
.ph-zone > .ph-kpi-grid:last-child,
.ph-zone > .ph-cards-stack:last-child,
.ph-zone > .ph-cards-grid:last-child { margin-bottom: 0; }

/* Jednowierszowy przypis pod siatką kafli („Oczekujące: 307,80 zł").
   Bez tego kropka statusu i tekst nie stają w jednej linii. */
.ph-status-box--inline {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.62rem 1rem;
    margin-top: 0.8rem;
    margin-bottom: 0;
}

/* Bohater + dwa kafle wsparcia. Bez tego bohater dostaje tyle samo szerokości
   co wsparcie, mimo że jego liczba jest o połowę większa. Nazwa mówi
   o UKŁADZIE, nie o ekranie — tej samej siatki używa Saldo i Podsumowanie. */
.ph-zone__grid--hero2 {
    display: grid;
    gap: 1rem;
    grid-template-columns: 1.3fr 1fr 1fr;
}

@media (max-width: 1199px) {
    .ph-zone__grid--hero2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ph-zone__grid--hero2 > .ph-metric--hero { grid-column: 1 / -1; }
}

@media (max-width: 767px) {
    .ph-zone__grid--hero2 { grid-template-columns: 1fr; }
}

.ph-zone__label {
    margin: 0 0 1rem;
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--muted);
}

/* Strefa 1: bohater szerszy od trzech kafli wsparcia. */
.ph-zone__grid--activity {
    display: grid;
    gap: 1rem;
    grid-template-columns: 1.3fr 1fr 1fr 1fr;
}

/* Strefa 2: bohater z sumą i donutem obok siatki składowych. */
.ph-zone__grid--commission {
    display: grid;
    gap: 1rem;
    grid-template-columns: 1.15fr 1.85fr;
    align-items: start;
}

.ph-zone__parts {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* ── Kafel metryki ───────────────────────────────────────────────────────────
   Kafle w rzędzie mają mieć równą wysokość, a liczby stać na jednej linii.
   Robią to trzy rzeczy:
     • treść dosunięta do GÓRY i stałe odstępy 6 px — nadmiar wysokości zbiera
       się pod podpisem. Siatka o stałych wierszach rozkładała go MIĘDZY wiersze
       i rząd czytał się jak dwa różne komponenty;
     • etykieta z min-height: 32px = dwa wiersze wersalików 11,5 px przy
       line-height 1.35 — to ona trzyma liczby na jednej linii bazowej;
     • równą wysokość daje grid rodzica. ⚠ Nigdy min-height na karcie.
   ⚠ Bez ikon w rogu: zajmowały 34 px tylko w części kafli i rozjeżdżały rząd. */

.ph-metric {
    --metric-pad-left: 22px;

    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    /* NIE space-between — to on rozrzucał wolną przestrzeń między etykietę
       a liczbę zamiast zostawić ją pod podpisem. */
    justify-content: flex-start;
    gap: 0;
    padding: 18px 20px 18px var(--metric-pad-left);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
    overflow: hidden;
}

/* Kolor roli niesie kropka przy etykiecie, nie tło ani ramka. */
.ph-metric__label::before { content: none; }

/* ⚠ Lista MUSI obejmować wszystkie kolory z taksonomii. Przy dopisywaniu
   `--red` albo `--muted` łatwo dodać samo tło kropki i zapomnieć o regule,
   która ją w ogóle tworzy — wtedy kafel „Uśpiony" jako jedyny stoi bez kropki
   i wygląda to na brak w danych, a nie na brak w arkuszu. */
.ph-metric--green .ph-metric__label::before,
.ph-metric--gold  .ph-metric__label::before,
.ph-metric--blue  .ph-metric__label::before,
.ph-metric--bordo .ph-metric__label::before,
.ph-metric--red   .ph-metric__label::before,
.ph-metric--muted .ph-metric__label::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 0.45rem;
    vertical-align: 0.02em;
}

.ph-metric--green .ph-metric__label::before { background: var(--green); }
.ph-metric--gold  .ph-metric__label::before { background: var(--gold); }
.ph-metric--blue  .ph-metric__label::before { background: var(--blue); }
.ph-metric--bordo .ph-metric__label::before { background: var(--bordo); }
.ph-metric--red   .ph-metric__label::before { background: var(--red); }
.ph-metric--muted .ph-metric__label::before { background: var(--muted); }

/* ── Tinta + lewy akcent na kartach segmentowych ────────────────────────────
   Sama kropka na białej karcie jest za słaba — rząd czterech kart czyta się
   jako jeden blok. ⚠ Kolor MUSI się zgadzać z kropką tego samego segmentu
   w tabeli i z jego wycinkiem w pasku proporcji. */
/* ── Wzorzec B: kolor pełny, powierzchnia minimalna ─────────────────────────
   Białe tło, pasek 5 px w PEŁNYM kolorze, etykieta w ciemniejszym wariancie
   tego samego odcienia. Zero tinty poza kartą wyróżnioną.

   ⚠ Nie odróżniać kart tintą tła 5%: zieleń, bursztyn i czerwień PlantaHerb
   mają zbliżoną jasność, więc rozcieńczone na kremie dają trzy identyczne beże
   — i odbierają wyjątkowość karcie wyróżnionej, dla której tinta jest znakiem.

   Pasek dostaje KAŻDA karta (stąd selektor .ph-metric, nie --seg); wcięcie
   tekstu jest wszędzie takie samo, bo pasek jest pozycjonowany absolutnie.   */
.ph-metric::before {
    content: '';
    position: absolute;
    inset: -1px auto -1px -1px;
    width: 5px;
    border-radius: var(--radius-card) 0 0 var(--radius-card);
    background: var(--acc, var(--acc-neutral));
}

.ph-metric--seg .ph-metric__label { color: var(--seg-ink, var(--ink-neutral)); }

.ph-metric--green { --acc: var(--acc-green); --seg-ink: var(--ink-green); }
.ph-metric--gold  { --acc: var(--acc-amber); --seg-ink: var(--ink-amber); }
.ph-metric--blue  { --acc: var(--acc-blue);  --seg-ink: var(--ink-blue); }
.ph-metric--red   { --acc: var(--acc-red);   --seg-ink: var(--ink-red); }
.ph-metric--bordo { --acc: var(--acc-red);   --seg-ink: var(--ink-red); }

/* ── Karta wyróżniona ──────────────────────────────────────────────────────
   NIE MA paska. Tinta zastępuje akcent — dzięki temu zieleń paska zostaje
   w rzędzie wolna dla realnego segmentu zielonego („Zakupy własne",
   „Wypłacono") i nie dubluje się z tintą.                                    */
.ph-metric--hero.ph-metric--hero {
    background: var(--hi-bg);
    border-color: var(--hi-border);
}

.ph-metric--hero.ph-metric--hero::before { content: none; }

.ph-metric--hero .ph-metric__value,
.ph-metric--hero .ph-metric__label { color: var(--hi-ink); }
.ph-metric--hero .ph-metric__label { opacity: 1; }
.ph-metric--hero .ph-metric__desc { color: rgba(47, 90, 64, 0.78); }


/* Etykieta: rezerwa na DWA wiersze wersalików. To ona — a nie siatka o stałych
   wierszach — trzyma liczby całego rzędu na jednej linii bazowej: przy etykiecie
   jednowierszowej pusty wiersz zostaje pod tekstem, a nie między etykietą
   a liczbą. 32px = 2 × (11,5px × 1.35) w zaokrągleniu. */
.ph-metric__label {
    margin: 0 0 6px;
    min-height: 32px;
    font-size: 11.5px;
    font-weight: 700;
    line-height: 1.35;
    text-transform: uppercase;
    letter-spacing: 0.11em;
    /* Etykieta karty neutralnej — celowo osobny token od --muted, żeby zmiana
       koloru etykiet nie ruszała każdego szarego tekstu w panelu. */
    color: var(--ink-neutral);
}

/* ⚠ Wartość NIGDY się nie łamie — ani między tysiącami, ani przed jednostką.
   Ten sam rozmiar i ta sama odległość od etykiety we wszystkich kaflach, więc
   dolne krawędzie cyfr pokrywają się co do piksela.                          */
.ph-metric__value {
    margin: 0 0 6px;
    font-size: 30px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--ink);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.ph-metric__unit {
    white-space: nowrap;
    font-size: 0.55em;
    font-weight: 700;
    margin-left: 0.16em;
}

/* Opis zamyka kartę — cała nadwyżka wysokości rzędu zbiera się POD nim. */
.ph-metric__desc {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--muted);
}

/* Delta (▲/▼) pod liczbą — kolor wyłącznie semantyczny (wytyczne §3). */
.ph-metric__delta {
    margin: 0;
    font-size: 12.5px;
    font-weight: 700;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.ph-metric__delta--up   { color: var(--green); }
.ph-metric__delta--down { color: var(--red); }
.ph-metric__delta--flat { color: var(--muted); }

/* Kafel klikalny — prowadzi do widoku szczegółowego (wytyczne §4.2). */
a.ph-metric {
    text-decoration: none;
    transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
}

a.ph-metric:hover {
    border-color: var(--line-strong);
    box-shadow: 0 6px 18px -12px rgba(44, 34, 25, 0.4);
    transform: translateY(-1px);
}

/* ⚠ Tu stała druga definicja kafla wyróżnionego. Tło było martwe, ale kolory
   tekstu już nie — reguły dalej w pliku wygrywały remis i etykieta świeciła
   --green-deep zamiast --hi-ink. Zostaje jedna definicja, przy wzorcu B. */

.ph-metric__chart {
    margin-top: 1rem;
    position: relative;
    height: 190px;
}

/* ── Pasek liczb: kilka metryk w jednej karcie ───────────────────────────────
   Osobne kafle rozbijały górę Kokpitu na cztery pudła. Jedna karta z pionowymi
   kreskami czyta się jak jeden wiersz podsumowania i zostawia miejsce na
   wykres obok. */

.ph-stat-strip {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.ph-stat-strip--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ph-stat-strip--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ⚠ Pasek liczb NIE dostaje pasków 5 px. Przy czterech kolumnach w jednej
   karcie szary akcent czyta się jako gruby separator i rozbija kartę na cztery
   pudełka. To komponent zbiorczy: podział niesie kreska 1 px.

   Rytm etykieta→liczba jest TAKI SAM jak w karcie metryki — pasek stoi na
   Kokpicie obok kart prowizji i przy innym rytmie czytałby się jak inny
   komponent, choć niesie to samo.                                           */
.ph-stat-strip__item {
    padding: 18px 20px 18px 22px;
    min-width: 0;
}

.ph-stat-strip__item + .ph-stat-strip__item { border-left: 1px solid var(--line); }

.ph-stat-strip__label {
    margin: 0 0 6px;
    min-height: 32px;
    font-size: 11.5px;
    font-weight: 700;
    line-height: 1.35;
    text-transform: uppercase;
    letter-spacing: 0.11em;
    color: var(--ink-neutral);
}

.ph-stat-strip__row {
    display: flex;
    align-items: baseline;
    gap: 0.55rem;
    flex-wrap: nowrap;
}

/* Ta sama skala co liczba w karcie. Dwa kroje liczby na jednym ekranie każą
   się zastanawiać, czy różnica wielkości coś znaczy. */
.ph-stat-strip__value {
    margin: 0;
    font-size: 30px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--ink);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.ph-stat-strip__delta {
    font-size: 13px;
    font-weight: 700;
    color: var(--green);
    white-space: nowrap;
}

.ph-stat-strip__delta--down { color: var(--red); }

/* ── Karta wykresu z dużą wartością ──────────────────────────────────────── */

.ph-chart-card {
    display: flex;
    flex-direction: column;
    padding: 1.4rem 1.5rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
    min-width: 0;
    overflow: hidden;
}

.ph-chart-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
}

.ph-chart-card__title { margin: 0; font-size: 14px; color: var(--muted); }

.ph-chart-card__value {
    margin: 0.35rem 0 0;
    font-size: 34px;
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--ink);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.ph-chart-card__unit {
    font-size: 0.52em;
    font-weight: 700;
    color: var(--muted);
    margin-left: 0.2em;
    white-space: nowrap;
}

/* Pigułka dynamiki — zieleń dla wzrostu, czerwień dla spadku. */
.ph-trend-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.32rem 0.7rem;
    border-radius: 999px;
    background: var(--green-soft);
    color: var(--green);
    font-size: 12.5px;
    font-weight: 700;
    white-space: nowrap;
    flex-shrink: 0;
}

.ph-trend-pill i,
.ph-trend-pill svg { width: 14px; height: 14px; stroke-width: 2; }
.ph-trend-pill--down { background: var(--red-soft); color: var(--red); }

/* ── Karta-lista (ostatnie zamówienia, ostatnie polecenia) ───────────────────
   Lista wierszy zamiast tabeli: na skrót „co się ostatnio wydarzyło" nagłówki
   kolumn nie niosą informacji, a dokładają hałasu. */

.ph-list-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
    overflow: hidden;
    min-width: 0;
}

.ph-list-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.1rem 1.3rem;
    border-bottom: 1px solid var(--line);
}

.ph-list-card__title {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    color: var(--ink);
}

.ph-list-card__link {
    font-size: 13px;
    font-weight: 600;
    color: var(--brown);
    text-decoration: none;
    white-space: nowrap;
    flex-shrink: 0;
}

.ph-list-card__link:hover { color: var(--brown-hover); text-decoration: underline; }

.ph-list-card__row {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.85rem 1.3rem;
    border-bottom: 1px solid var(--line);
    text-decoration: none;
}

.ph-list-card__row:last-child { border-bottom: 0; }
a.ph-list-card__row:hover { background: var(--surface-soft); }

.ph-list-card__main { flex: 1; min-width: 0; }

/* display:block jest konieczne — te elementy bywają <span>, a jako liniowe
   skleiłyby się w jeden ciąg („ZM120105.08.2026"). */
.ph-list-card__primary {
    display: block;
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ph-list-card__secondary {
    display: block;
    margin: 0.1rem 0 0;
    font-size: 12.5px;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ph-list-card__amount {
    font-size: 14px;
    font-weight: 700;
    color: var(--ink);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

.ph-list-card__date {
    font-size: 12.5px;
    color: var(--muted);
    white-space: nowrap;
    flex-shrink: 0;
}

.ph-list-card__empty { padding: 1.6rem 1.3rem; text-align: center; color: var(--muted); }

/* Rząd „para" (np. ten miesiąc / łącznie). ⚠ Modyfikator siedzi na SIATCE,
   nie na pojedynczym kaflu — powiększając jeden kafel zdjęłoby się jego liczbę
   z linii sąsiada. */
/* Haczyk zgodności: JEDNA skala liczby w całym panelu (30px/700), więc ten
   modyfikator niczego już nie powiększa. Dwie skale kazały porównywać wzrokowo
   kwoty tego samego rzędu ważności; wyróżnienie niesie tinta karty, nie stopień
   pisma. Klasa zostaje, żeby widoki nie musiały jej usuwać naraz. */

@media (max-width: 1199px) {
    .ph-stat-strip,
    .ph-stat-strip--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    /* Pierwsza pozycja w rzędzie nie ma sąsiada po lewej — kreska po niej
       biegłaby po krawędzi karty. */
    .ph-stat-strip__item:nth-child(n+3) { border-top: 1px solid var(--line); }
    .ph-stat-strip__item:nth-child(odd) { border-left: 0; }
}

@media (max-width: 767px) {
    .ph-stat-strip,
    .ph-stat-strip--3,
    .ph-stat-strip--2 { grid-template-columns: 1fr; }
    .ph-stat-strip__item + .ph-stat-strip__item { border-left: 0; border-top: 1px solid var(--line); }
    /* Jedna pozycja w kolumnie — rezerwa na drugi wiersz podpisu jest tu
       samym pustym miejscem, tak samo jak w karcie metryki. */
    .ph-stat-strip__label { min-height: 0; }
    .ph-chart-card__value { font-size: 28px; }

    /* Kolejność w DOM (tytuł+wartość, potem pill) zostaje nietknięta — ważna
       dla czytników ekranu — zmienia się tylko kolejność wizualna, przez
       flex `order`, żeby pill stał nad tytułem karty, a nie obok niego
       w ciasnym rzędzie. */
    .ph-chart-card__head {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.5rem;
    }
    .ph-chart-card__head > div:first-child { order: 2; }
    .ph-trend-pill { order: 1; }
}

/* ── Pasek filtra okresu ─────────────────────────────────────────────────── */

.ph-period-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 1.1rem;
}

@media (max-width: 1199px) {
    .ph-zone__grid--activity { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ph-zone__grid--activity > .ph-metric--hero { grid-column: 1 / -1; }
    .ph-zone__grid--commission { grid-template-columns: 1fr; }
    .ph-zone__parts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 767px) {
    .ph-zone { margin-bottom: 40px; }
    .ph-zone__grid--activity,
    .ph-zone__parts { grid-template-columns: 1fr; }
    /* Jeden kafel w kolumnie — nie ma sąsiada, z którym trzeba trzymać linię,
       więc rezerwa na drugi wiersz etykiety jest tu samym pustym miejscem. */
    .ph-metric__label { min-height: 0; }
    /* ~15% mniej, żeby najdłuższa wartość dalej mieściła się bez zawijania. */
    .ph-metric__value { font-size: 26px; }
}

/* ── Dwie równorzędne akcje obok siebie ──────────────────────────────────────
   Jedna pod drugą — drugą opcję widać dopiero po przewinięciu. Karty
   rozciągają się do równej wysokości, a przycisk jest dosuwany do dołu
   (margin-top:auto), inaczej krótszy formularz ma CTA w połowie sąsiada. */

.ph-action-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    align-items: stretch;
    margin-bottom: 1.5rem;
}

.ph-action-grid > .ph-card {
    display: flex;
    flex-direction: column;
}

.ph-action-grid .ph-form { flex: 1; }
.ph-action-grid .ph-form > .ph-button { margin-top: auto; }

@media (max-width: 900px) {
    .ph-action-grid { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Domknięcie luk: miejsca, gdzie widok musiał zostać przy stylu inline albo
   sięgnąć po klasę spoza swojej semantyki.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Taby, plakietki i chipy bywają linkami — bez tego przeglądarka je podkreśla.
   ⚠ Arkusz nie ma globalnego resetu `a { text-decoration: none }`; wyjątki są
   wypisywane po jednym, żeby link w tekście zostawał podkreślony. */
a.ph-tab,
a.ph-badge,
a.ph-chip,
a.ph-pill { text-decoration: none; }

/* Nakładka „funkcja zablokowana" — brakowało kontenera, więc rozmyte tło
   wychodziło kwadratem poza zaokrąglony róg karty. */
.ph-locked-feature {
    position: relative;
    overflow: hidden;
    border-radius: var(--radius-card);
}

.ph-locked-feature__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
    color: var(--ink);
}

/* Plan BASIC — bez tego widok musiał znać wyjątek „basic → pusta klasa". */
.ph-plan-card--basic .ph-plan-card__icon { color: var(--muted); }

/* Status i modal subskrypcji — wcześniej podpierane klasami tabelowymi. */
.ph-plan-status__expired { color: var(--red); font-weight: 600; }

.ph-sub-summary__row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.2rem 0;
}

.ph-sub-summary__value { color: var(--ink); font-weight: 600; text-align: right; }
.ph-sub-summary__cost  { color: var(--red);  font-weight: 600; text-align: right; }
.ph-sub-expiry-note__value { color: var(--ink); font-weight: 600; }

/* Panel linku w karcie, która ma już własny nagłówek — bez pustej kolumny 190px. */
.ph-link-panel--bare { grid-template-columns: minmax(0, 1fr) auto; }

/* ⚠ Reguła mobilna .ph-link-panel stoi WYŻEJ w pliku (przy 2100), a przy
   równej sile wygrywa zapis późniejszy — bez tego powtórzenia panel z
   modyfikatorem --bare zostawał na telefonie dwukolumnowy i długi link
   polecający ściskał się obok przycisków. */
@media (max-width: 1080px) {
    .ph-link-panel--bare { grid-template-columns: 1fr; }
}

/* Wyciąg: tytuł pozycji jest blokiem, żeby meta trafiła do nowej linii. */
.ph-ledger-title { display: block; }

/* Okrągły podgląd awatara. ⚠ Zaokrąglamy WYŁĄCZNIE obrazek — objęcie regułą
   pojemnika zamienia kreskowaną ramkę 180×180 w koło. */
.ph-logo-field__preview--round img { border-radius: 50%; }

/* Komórka osoby, gdy całość jest linkiem: bez podkreślenia i bez zmniejszania
   nazwiska, które narzucała ogólna klasa .ph-link. */
a.ph-person-cell {
    text-decoration: none;
    font-size: 14px;
    color: var(--ink);
}

a.ph-person-cell:hover .ph-person-cell__name { color: var(--brown); }
/* ═══ Wspólne komponenty ═════════════════════════════════════════════════════
   Zbudowane raz, używane wszędzie. Każdy ekran, który potrzebuje filtra okresu,
   paska proporcji albo pigułki statusu, sięga tutaj — nie pisze własnej wersji.
   To jedyny sposób, żeby te same rzeczy wyglądały tak samo po następnej zmianie. */

/* ── PeriodFilter — chipy zakresu ───────────────────────────────────────────
   Zastępują pary „Filtruj / Wyczyść". Chip działa NATYCHMIAST; jedyny przycisk
   „Zastosuj" w panelu siedzi w popoverze własnego zakresu, bo dwie daty nie
   mają sensu wpół wpisane. */

.ph-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    height: 32px;
    padding: 0 0.85rem;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    background: var(--surface);
    color: var(--ink-soft);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.ph-chip:hover { border-color: var(--brown); color: var(--ink); }

.ph-chip.is-active {
    background: var(--brown);
    border-color: var(--brown);
    color: #fff;
}

.ph-chip i,
.ph-chip svg { width: 14px; height: 14px; stroke-width: 2; }

.ph-period {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 1.1rem;
}

.ph-period__range {
    margin-left: 0.35rem;
    font-size: 12.5px;
    color: var(--muted);
    white-space: nowrap;
}

.ph-period__custom { position: relative; }

.ph-period__popover {
    position: absolute;
    z-index: 40;
    top: calc(100% + 0.4rem);
    left: 0;
    display: none;
    gap: 0.6rem;
    align-items: flex-end;
    padding: 0.9rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    box-shadow: var(--shadow-card);
}

.ph-period__custom.is-open .ph-period__popover { display: flex; }

.ph-period__popover label {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
}

/* ── ShareBar — pasek część–całość ──────────────────────────────────────────
   Nieklikalny i bez kwot w legendzie: kwoty stoją w kartach obok, a ten sam
   fakt dwa razy na ekranie każe sprawdzać, czy to na pewno ta sama liczba.
   Filtrują chipy tuż nad tabelą.                                            */

.ph-share-bar { margin-top: 0.9rem; }

.ph-share-bar__track {
    display: flex;
    height: 12px;
    border-radius: 999px;
    overflow: hidden;
    background: var(--field);
}

.ph-share-bar__seg {
    border: 0;
    padding: 0;
    min-width: 3px;
    cursor: default;
}

.ph-share-bar__seg--green { background: var(--green); }
.ph-share-bar__seg--blue  { background: var(--blue); }
.ph-share-bar__seg--gold  { background: var(--gold); }
.ph-share-bar__seg--bordo { background: var(--bordo); }
.ph-share-bar__seg--red   { background: var(--red); }
.ph-share-bar__seg--muted { background: var(--line-strong); }

/* ── Legenda paska: nazwy i procenty, zero kwot ─────────────────────────────
   Kropka w kolorze etykiety (--ink-*), nie paska (--acc-*): kropka jest tekstem
   i przy 9 px musi mieć kontrast, a nie tylko barwę. */
.ph-share-bar__legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem 1.25rem;
    margin: 0.7rem 0 0;
    padding: 0;
    list-style: none;
}

.ph-share-bar__item {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    font-size: 13px;
    color: var(--ink-soft);
}

.ph-share-bar__item::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex: none;
    align-self: center;
    background: var(--ink-neutral);
}

.ph-share-bar__item--green::before { background: var(--ink-green); }
.ph-share-bar__item--gold::before  { background: var(--ink-amber); }
.ph-share-bar__item--blue::before  { background: var(--ink-blue); }
.ph-share-bar__item--red::before   { background: var(--ink-red); }
.ph-share-bar__item--bordo::before { background: var(--ink-red); }

.ph-share-bar__pct {
    font-weight: 700;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

/* Haczyk zgodności — rzędy z tym modyfikatorem nie powiększają już liczb
   (jedna skala w panelu). Klasa zostaje, żeby kontrola nie zgłaszała braku
   definicji, a widoki nie musiały jej usuwać naraz. */
.ph-metric-row--lg { }


/* ── ChipFilter ─────────────────────────────────────────────────────────────
   ⚠ Rząd stoi BEZPOŚREDNIO nad tabelą, którą filtruje. Na wąskim ekranie
   przewija się w poziomie, a nie zawija na trzy linie.                       */

.ph-chip-row {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.9rem;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: 2px;
}

.ph-chip-row::-webkit-scrollbar { display: none; }

.ph-chip--count {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex: none;
}

.ph-chip__count {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--muted);
}

.ph-chip--count.is-active .ph-chip__count { color: inherit; opacity: 0.75; }

/* Kropka segmentu w chipie ma ten sam kolor co kropka w tabeli i wycinek
   paska — trzy miejsca, jedno znaczenie. */
.ph-chip--count .ph-dot { flex: none; }

/* ── Przełącznik widoku: kafelki / lista ────────────────────────────────────
   Dwa stany, wybór zapamiętany. Kafelka na 390 px zajmuje pół ekranu na jeden
   wpis, więc na telefonie domyślna jest lista.                               */

.ph-view-toggle {
    display: inline-flex;
    border: 1px solid var(--line);
    border-radius: var(--radius-ctrl);
    overflow: hidden;
    background: var(--surface);
}

.ph-view-toggle__btn {
    display: grid;
    place-items: center;
    min-width: 44px;
    min-height: 38px;
    border: 0;
    background: none;
    color: var(--muted);
    cursor: pointer;
}

.ph-view-toggle__btn + .ph-view-toggle__btn { border-left: 1px solid var(--line); }
.ph-view-toggle__btn:hover { color: var(--ink); }
.ph-view-toggle__btn.is-active { background: var(--field); color: var(--brown); }
.ph-view-toggle__btn i,
.ph-view-toggle__btn svg { width: 16px; height: 16px; }

/* ── DataTable: szukajka i pager ────────────────────────────────────────────
   Jedno pole nad tabelą, po prawej wybór liczby wierszy. Bez przycisku —
   filtruje w trakcie pisania. */

.ph-table-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.9rem;
}

.ph-table-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 260px;
    max-width: 380px;
}

.ph-table-search i,
.ph-table-search svg {
    position: absolute;
    left: 11px;
    width: 15px;
    height: 15px;
    color: var(--muted);
    pointer-events: none;
}

.ph-table-search input {
    width: 100%;
    height: 38px;
    padding: 0 0.8rem 0 2.2rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    color: var(--ink);
    font-family: inherit;
    font-size: 13px;
}

.ph-table-search input::placeholder { color: var(--muted); }

.ph-table-search input:focus {
    outline: none;
    border-color: var(--brown);
    box-shadow: 0 0 0 3px var(--brown-soft);
}

.ph-table-tools__spacer { margin-left: auto; }

/* Pager: „Strona 1 z 6 (111 osób)" po lewej, sterowanie po prawej. */
.ph-pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1.1rem;
    padding-top: 1.1rem;
    border-top: 1px solid var(--line);
}

.ph-pager__info {
    font-size: 13px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.ph-pager__controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
}

.ph-pager__size {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 13px;
    color: var(--muted);
}

.ph-pager__size select {
    height: 34px;
    padding: 0 1.9rem 0 0.65rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-ctrl);
    background: var(--surface) url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%237b6b57' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right 0.6rem center;
    color: var(--ink);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    appearance: none;
    cursor: pointer;
}

.ph-pager__size select:focus {
    outline: none;
    border-color: var(--brown);
    box-shadow: 0 0 0 3px var(--brown-soft);
}

.ph-pager__nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    color: var(--ink-soft);
    cursor: pointer;
}

.ph-pager__nav:hover:not([disabled]) { background: var(--field); color: var(--ink); }
.ph-pager__nav[disabled] { opacity: 0.4; cursor: not-allowed; }
.ph-pager__nav i,
.ph-pager__nav svg { width: 16px; height: 16px; stroke-width: 2; }

@media (max-width: 767px) {
    .ph-pager__controls { margin-left: 0; }
    .ph-pager__size { display: none; }
}

/* ── Znacznik świeżości danych ─────────────────────────────────────────────── */

.ph-freshness {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 12.5px;
    color: var(--muted);
    white-space: nowrap;
}

.ph-freshness i,
.ph-freshness svg { width: 13px; height: 13px; stroke-width: 2; }

/* Nagłówek strony: tytuł po lewej, znacznik świeżości dosunięty do prawej. */
.ph-page-header--split {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem 1rem;
}

/* Etykieta strefy z zakresem po prawej — „PROWIZJE · OSTATNIE 6 MIES." + data. */
.ph-zone__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.4rem 1rem;
    margin-bottom: 1rem;
}

.ph-zone__head .ph-zone__label { margin-bottom: 0; }

/* ── Strzałka „wejdź w wiersz" ──────────────────────────────────────────────
   Zastępuje kolumnę „Akcje → Szczegóły": jest wąska i pusta do momentu
   najechania, więc nie zabiera miejsca danym. */

.ph-table td.ph-table__go {
    width: 34px;
    padding-left: 0;
    padding-right: 0.9rem;
    text-align: right;
    color: var(--muted);
}

/* Strzałka jest PRAWDZIWYM odnośnikiem, nie ozdobą: cały wiersz klika się
   myszą przez data-href, ale z klawiatury trzeba mieć na czym stanąć. Przed
   przebudową rolę tę pełniła kolumna „Akcje → Szczegóły"; po jej usunięciu
   wiersz przez chwilę nie miał ŻADNEGO elementu, na który da się wejść
   tabulatorem, więc profilu klienta nie dało się otworzyć bez myszy. */
.ph-table td.ph-table__go a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: inherit;
    text-decoration: none;
    border-radius: var(--radius-ctrl);
}

.ph-table td.ph-table__go i,
.ph-table td.ph-table__go svg {
    width: 16px;
    height: 16px;
    stroke-width: 2;
    opacity: 0;
    transform: translateX(-3px);
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.ph-table tbody tr:hover td.ph-table__go i,
.ph-table tbody tr:hover td.ph-table__go svg,
.ph-table td.ph-table__go a:focus-visible i,
.ph-table td.ph-table__go a:focus-visible svg {
    opacity: 1;
    transform: none;
}

.ph-table td.ph-table__go a:focus-visible {
    outline: 2px solid var(--brown);
    outline-offset: 2px;
}

/* ── EmptyState w kaflu metryki ─────────────────────────────────────────────
   Zamiast kafla z samą kreską: zdanie, które mówi, co ta pustka znaczy. */

.ph-metric--empty .ph-metric__value {
    font-size: 20px;
    font-weight: 700;
    color: var(--muted);
    /* ⚠ Wartość liczbowa nigdy się nie łamie — zdanie musi. Zakaz zawijania jest
       po to, żeby „12 345,67 zł" nie pękło między tysiącami; przy zdaniu w stanie
       pustym ten sam zakaz wypychał tekst poza kartę (overflow: hidden), więc
       urywał się w połowie słowa. */
    white-space: normal;
    line-height: 1.3;
}

/* ── Zasady programu przy saldzie ─────────────────────────────────────────── */

.ph-rules {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1.1rem;
    margin-top: 0.85rem;
    padding: 0.7rem 0.95rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-ctrl);
    background: var(--field);
    font-size: 12.5px;
    color: var(--ink-soft);
}

.ph-rules strong { color: var(--ink); font-weight: 700; }

/* ── Kwoty w tabelach ───────────────────────────────────────────────────────
   Do prawej i cyframi o stałej szerokości — inaczej kolumna kwot faluje
   i porównanie dwóch wierszy wymaga czytania cyfra po cyfrze. */

.ph-table th.ph-num,
.ph-table td.ph-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── Tabela wąska ───────────────────────────────────────────────────────────
   Kwoty do prawej obowiązują od PIĘCIU kolumn w górę. Wyrównanie służy
   porównywaniu rzędów wielkości między wierszami i działa tylko przy wąskiej
   kolumnie kwot; w tabeli czterokolumnowej na pełnej szerokości kwota odlatuje
   na prawy kraniec, a wiersz rozpada się na dwa fragmenty. W wąskich wszystko
   idzie do lewej — cyfry równa tabular-nums.

   ⚠ Modyfikator siedzi na PUDEŁKU tabeli: .ph-table ma width:100%, więc limit
   nałożony na nią zwęża wiersze wewnątrz ramki rozciągniętej dalej.          */
.ph-table-card--narrow { max-width: 720px; }

.ph-table-card--narrow th,
.ph-table-card--narrow td,
.ph-table-card--narrow th.ph-num,
.ph-table-card--narrow td.ph-num { text-align: left; }

.ph-table-card--narrow .ph-col-date   { width: 180px; }
.ph-table-card--narrow .ph-col-amount { width: 160px; font-variant-numeric: tabular-nums; }
.ph-table-card--narrow .ph-col-status { width: auto; }

/* Poniżej 768 px tabela zamienia się w karty (td::before z data-label), więc
   stałe szerokości kolumn i limit szerokości przestają cokolwiek znaczyć. */
@media (max-width: 767px) {
    .ph-table-card--narrow { max-width: none; }
    .ph-table-card--narrow .ph-col-date,
    .ph-table-card--narrow .ph-col-amount { width: auto; }
}

/* Select filtra obok szukajki. ⚠ Nie .ph-filter-select (width:100%, do kolumny
   formularza) i nie .ph-pager__size (znika poniżej 768 px, a filtr statusu jest
   na telefonie potrzebny tak samo). */
.ph-table-tools__filter {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 13px;
    color: var(--muted);
    white-space: nowrap;
}

.ph-table-tools__filter select {
    height: 38px;
    padding: 0 1.9rem 0 0.7rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-ctrl);
    background: var(--surface) url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%237b6b57' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right 0.6rem center;
    color: var(--ink);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    appearance: none;
    cursor: pointer;
}

.ph-table-tools__filter select:focus {
    outline: none;
    border-color: var(--brown);
    box-shadow: 0 0 0 3px var(--brown-soft);
}

/* Karta aktualności / bazy wiedzy jest w całości odnośnikiem — przycisk
   „Czytaj więcej" zawężał klikalny obszar do rogu, choć kliknięcie gdziekolwiek
   w kartę i tak znaczy to samo. */
a.ph-news-card {
    text-decoration: none;
    color: inherit;
}

a.ph-news-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-card);
    border-color: var(--line-strong);
}

/* Metadane w stopce karty: przypięcie i liczba załączników. Jako plakietki
   obok wagi i kategorii dawały karcie cztery etykiety przy dopuszczalnych
   dwóch. Tu są tym, czym są: drobną informacją przy dacie. */
.ph-news-card__meta {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 12.5px;
    color: var(--muted);
}

.ph-news-card__meta i,
.ph-news-card__meta svg { width: 14px; height: 14px; stroke-width: 1.8; }

.ph-news-card__date i,
.ph-news-card__date svg { width: 14px; height: 14px; stroke-width: 1.8; }

/* Relatywna data („125 dni temu") nie ma się łamać — to jedna informacja.
   ⚠ Reguła celowo nie jest zawężona do `td`: ta sama klasa trzyma strzałkę
   sortowania przy ostatnim słowie nagłówka. */
.ph-table td .ph-meta,
.ph-table .ph-dot-cell,
.ph-nowrap { white-space: nowrap; }

/* Bohater i karta obok mają być tej samej wysokości. Przy align-items: start
   bohater zostaje krótszy od sąsiada, rząd wygląda na niedokończony
   i przyciąga wzrok do dziury, a nie do liczby. */
.ph-zone__grid--commission { align-items: stretch; }

/* Odnośnik w treści bierze BRĄZ, nie niebieski. Niebieski jest zarezerwowany
   dla roli Ambasadora i statusu „W trakcie" — jako kolor linku znaczyłby dwie
   rzeczy naraz, a „← Wróć do listy" wyglądałoby jak pigułka statusu. */
.ph-link { color: var(--brown); }
.ph-link:hover { color: var(--brown-hover); }

/* Kafel metryki obok wysokiej karty. Bez tego kafel rozciąga się do wysokości
   sąsiada i pod liczbą zostaje kilkaset pikseli pustki, co czyta się jak
   brakująca treść. W rzędach z samych kafli rozciąganie jest pożądane. */
.ph-grid-2--start { align-items: start; }

/* Cztery równorzędne kafle segmentów aktywności. ⚠ .ph-zone__parts ma trzy
   kolumny, więc czwarty kafel zawija się do drugiego rzędu i rozbija rząd
   na 3 + 1. */
.ph-zone__parts--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 1199px) {
    .ph-zone__parts--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Segment „Brak zakupów" — kropka szara. To nie jest stan alarmowy (jak
   Uśpiony) ani dobry (jak Aktywny); to brak zdarzenia, więc i brak koloru. */
.ph-metric--muted .ph-metric__label::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 0.45rem;
    vertical-align: 0.02em;
    background: var(--muted);
}

/* ═══ RESPONSYWNOŚĆ ═════════════════════════════════════════════════════════
   ≥1024 px pełny layout · <1024 px sidebar w szufladzie · <768 px jedna kolumna
   i tabele jako karty. Przy łamaniu karta wyróżniona idzie pierwsza — „pierwsze"
   znaczy tu „jedyne widoczne bez przewijania".                               */

/* ── Przycisk menu: widoczny dopiero, gdy sidebar znika ── */
.ph-topbar__menu {
    display: none;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    margin-right: 0.25rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    color: var(--ink-soft);
    cursor: pointer;
}

.ph-topbar__menu i,
.ph-topbar__menu svg { width: 18px; height: 18px; }

@media (max-width: 1023px) {
    .ph-topbar__menu { display: inline-flex; }

    .ph-sidebar {
        position: fixed;
        width: 264px;
        height: 100vh;
        overflow-y: auto;
        transform: translateX(-100%);
        transition: transform 0.22s ease;
        z-index: 60;
        box-shadow: none;
    }

    .ph-drawer-open .ph-sidebar {
        transform: none;
        box-shadow: 0 0 0 100vmax rgba(30, 23, 20, 0.45);
    }

    .ph-main { margin-left: 0; }

    .ph-content { padding: 1.25rem; }
}

@media (prefers-reduced-motion: reduce) {
    .ph-sidebar { transition: none; }
}

/* ── Tablet: karty łamią się do dwóch kolumn ── */
@media (max-width: 1023px) {
    .ph-zone__grid--activity,
    .ph-zone__grid--hero2,
    .ph-zone__parts,
    .ph-zone__parts--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    .ph-zone__grid--commission { grid-template-columns: 1fr; }

    /* Karta wyróżniona zajmuje pełną szerokość i stoi pierwsza — to ta liczba,
       po którą wchodzi się na ekran. */
    .ph-zone__grid--activity .ph-metric--hero,
    .ph-zone__grid--hero2 .ph-metric--hero { grid-column: 1 / -1; }
}

/* ── Telefon ── */
@media (max-width: 767px) {
    .ph-zone__grid--activity,
    .ph-zone__grid--hero2,
    .ph-zone__parts,
    .ph-zone__parts--4,
    .ph-grid-2,
    .ph-action-grid { grid-template-columns: 1fr; }

    .ph-content { padding: 1rem; }

    .ph-section-title { font-size: 27px; }

    .ph-metric { --metric-pad-left: 20px; }
    .ph-metric__value { font-size: 26px; }

    /* Chipy w jednym rzędzie z przewijaniem — trzy linie filtrów zajmowały
       pół ekranu, zanim widać było pierwszy wiersz danych. */
    .ph-period,
    .ph-tabs,
    .ph-chip-row {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .ph-period::-webkit-scrollbar,
    .ph-tabs::-webkit-scrollbar { display: none; }

    .ph-period .ph-chip,
    .ph-chip-row .ph-chip,
    .ph-tabs .ph-tab { flex: none; }

    /* Cele dotykowe 44 px. Chip ma 32 px na desktopie — na telefonie to
       trafienie na wyczucie. */
    .ph-chip,
    .ph-tab,
    .ph-button,
    .ph-pager__nav,
    .ph-copy-btn { min-height: 44px; }

    /* „Dane na dziś" schodzi pod tytuł — obok H1 nie mieści się na 390 px
       i było ucinane przez krawędź ekranu. */
    .ph-page-header--split {
        flex-wrap: wrap;
        gap: 0.35rem;
    }

    .ph-table-tools { gap: 0.5rem; }
    .ph-table-tools__spacer { margin-left: 0; }

    /* ── Tabela jako lista kart ─────────────────────────────────────────────
       ⚠ Poziomy scroll tabeli jako JEDYNE rozwiązanie jest zakazany. Nagłówki
       znikają, a nazwę kolumny niesie data-label wpisany przez PH.bindTable —
       bez niej karta jest kolumną liczb bez wyjaśnienia. */
    .ph-table-card { overflow-x: visible; }
    .ph-table-card::after { display: none; }

    .ph-table thead { display: none; }

    .ph-table,
    .ph-table tbody,
    .ph-table tr,
    .ph-table td { display: block; width: 100%; }

    .ph-table tr {
        padding: 0.9rem 1rem;
        border-bottom: 1px solid var(--line);
    }

    .ph-table tr:last-child { border-bottom: 0; }

    .ph-table td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 1rem;
        padding: 0.2rem 0;
        border: 0;
        text-align: right;
    }

    .ph-table td::before {
        content: attr(data-label);
        flex: none;
        font-size: 11px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--muted);
        text-align: left;
    }

    /* Pierwsza komórka jest tytułem karty: bez etykiety, pełna szerokość. */
    .ph-table td:first-child {
        display: block;
        margin-bottom: 0.45rem;
        text-align: left;
    }

    .ph-table td:first-child::before { content: none; }

    /* Komórka „Opis" w Historii prowizji (commission_history.php) niesie
       tytuł zdarzenia + stawkę/numer zamówienia pod spodem — ten sam wzorzec
       co pierwsza kolumna wszędzie indziej, tylko że tu jest trzecią kolumną
       (Data, Typ, Opis…), więc bez tej reguły dostawała zwykłe, jednoliniowe
       traktowanie flex/space-between (wyżej) i wychodziła poza kartę.
       Dobrana po klasie, nie po pozycji — odporne na zmianę kolejności
       kolumn w przyszłości. */
    .ph-table td.ph-ledger-cell {
        display: block;
        text-align: left;
    }
    .ph-table td.ph-ledger-cell::before { content: none; }

    /* ⚠ Strzałka NIE znika na karcie — zamienia się w podpisaną akcję.

       Stało tu `display: none` z uzasadnieniem „klikalna jest cała karta".
       Kliknięcie w kartę obsługuje jednak wyłącznie mysz i palec (data-href
       w app.js), a ten odnośnik jest JEDYNYM elementem wiersza, na którym da
       się stanąć tabulatorem. Ukryty zabierał dostęp z klawiatury dokładnie
       w trybie, w którym tabela zamienia się w listę kart. Sam znak „›" nic
       nie znaczy bez nagłówka kolumny, więc dostaje słowo. */
    .ph-table td.ph-table__go {
        display: block;
        margin-top: 0.55rem;
        padding: 0;
        text-align: left;
    }

    .ph-table td.ph-table__go::before { content: none; }

    .ph-table td.ph-table__go a {
        gap: 0.3rem;
        font-size: 13px;
        font-weight: 600;
        color: var(--brown);
    }

    .ph-table td.ph-table__go a::before { content: "Otwórz"; }

    /* Na karcie strzałka jest widoczna od razu — nie ma tu najechania. */
    .ph-table td.ph-table__go i,
    .ph-table td.ph-table__go svg {
        opacity: 1;
        transform: none;
    }

    .ph-table td.ph-num { justify-content: space-between; }

    .ph-table .ph-empty { text-align: center; }

    /* Formularze kwot: pełna szerokość i przycisk akcji przyklejony dołem. */
    .ph-form { width: 100%; }
    .ph-button--full { position: sticky; bottom: 0.5rem; }
}

/* ── Nagłówek nie chowa się pod przyklejonym paskiem ────────────────────────
   H1 i link powrotu wjeżdżały pod ph-topbar przy skoku do kotwicy i przy
   powrocie na stronę już przewiniętą. Offset musi znać wysokość paska. */
:root { --topbar-h: 62px; }

.ph-page-wrap,
.ph-section-title,
.ph-breadcrumb { scroll-margin-top: calc(var(--topbar-h) + 12px); }

/* ── Widok listy dla Aktualności i Bazy wiedzy ──────────────────────────────
   Kafelka na 390 px zajmuje pół ekranu na jeden wpis. Ta sama siatka dostaje
   modyfikator zamiast drugiego kontenera — inaczej trzeba trzymać dwa zestawy
   kart w DOM i pilnować, żeby filtr chował je w obu naraz.                   */

.ph-news-grid.is-list {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
    overflow: hidden;
}

.ph-news-grid.is-list .ph-news-card {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 0.35rem 1.25rem;
    padding: var(--pad-card-tight);
    min-height: 44px;
    border: 0;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
    box-shadow: none;
    background: none;
}

.ph-news-grid.is-list .ph-news-card:last-child { border-bottom: 0; }
.ph-news-grid.is-list .ph-news-card:hover { background: var(--surface-soft); }

/* Na liście znika wszystko, co jest atrakcją kafelki, a nie informacją:
   zajawka, miniatura i osobna stopka. Zostaje tytuł i metadane. */
.ph-news-grid.is-list .ph-news-card__excerpt,
.ph-news-grid.is-list .ph-news-card__thumb { display: none; }

.ph-news-grid.is-list .ph-news-card__content {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.35rem 0.75rem;
    padding: 0;
}

.ph-news-grid.is-list .ph-news-card__title {
    margin: 0;
    font-size: 15px;
    flex: 1 1 18ch;
}

.ph-news-grid.is-list .ph-news-card__badges { order: 2; margin: 0; }

.ph-news-grid.is-list .ph-news-card__footer {
    order: 3;
    margin: 0;
    padding: 0;
    border: 0;
    gap: 0.75rem;
    white-space: nowrap;
}

@media (max-width: 767px) {
    .ph-news-grid.is-list .ph-news-card { grid-template-columns: 1fr; }
}

/* Lista „etykieta ↔ wartość" na karcie o pełnej szerokości. .ph-details-row
   dosuwa oba końce do krawędzi, więc na 1440 px para „ID" / „#1201" rozjeżdża
   się na pół ekranu i przestaje być parą. */
.ph-details-list--narrow { max-width: 46rem; }

/* Wiersz sumy: mocniejszy od tego, co sumuje, i oddzielony wyraźniejszą
   kreską. Bez tego „Suma pozycji" ma wagę nazwy produktu, a kreska nad nią nie
   odróżnia jej od kolejnej pozycji. */
.ph-details-row--total {
    margin-top: 0.25rem;
    padding-top: 0.7rem;
    border-top: 1px solid var(--line-strong);
    font-weight: 700;
}

/* ═══════════════════════════════════════════════════════════════════════════
   PRZEDSIONEK — zgłoszenie współpracy i brak dostępu
   ═══════════════════════════════════════════════════════════════════════════
   Ekrany, na które użytkownik trafia zamiast panelu. Ta sama paleta co panel,
   inny wygląd: ciemna szyba na zdjęciu to brama, panel to biurko.

   ⚠ login.php do tej rodziny NIE należy — został przy swojej wersji pierwotnej
   (Tailwind z CDN-u i własna paleta w <style>). Zmiana tokenów tutaj NIE dotrze
   do ekranu logowania.                                                       */

.ph-gate {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
    background-color: var(--sidebar-top);
    background-image: var(--gate-bg, none);
    background-repeat: no-repeat;
    background-position: center center;
    background-size: cover;
    background-attachment: fixed;
    font-family: var(--font-ui);
}

/* Przyciemnienie pod szybą. Bez niego jasne partie zdjęcia zjadają biały
   tekst — a zdjęcie bywa podmieniane w motywie, więc czytelność nie może
   zależeć od tego, jakie akurat jest.                                        */
.ph-gate::before {
    content: '';
    position: fixed;
    inset: 0;
    background: rgba(30, 23, 20, 0.55);
    pointer-events: none;
}

.ph-gate__wrap {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 27rem;
}

.ph-gate__wrap--wide { max-width: 44rem; }

.ph-gate__panel {
    padding: 2rem;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: var(--radius-card);
    background: rgba(24, 18, 15, 0.42);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.55);
}

.ph-gate__logo {
    display: block;
    height: 5.5rem;
    width: auto;
    margin: 0 auto 1.75rem;
}

.ph-gate__head { text-align: center; margin-bottom: 1.75rem; }

.ph-gate__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 800;
    color: #fff;
}

.ph-gate__subtitle {
    margin: 0.4rem 0 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.7);
}

/* ── Komunikaty ────────────────────────────────────────────────────────────
   Na jasnej płytce, nie na przezroczystym tle: komunikat musi się czytać
   niezależnie od zdjęcia pod spodem.                                         */
.ph-gate__notice {
    margin-bottom: 1.5rem;
    padding: 0.9rem 1rem;
    border: 1px solid transparent;
    border-radius: var(--radius-ctrl);
    background: var(--surface-soft);
    font-size: 13.5px;
    line-height: 1.5;
}

.ph-gate__notice--error {
    border-color: var(--red-soft);
    color: var(--red);
}

.ph-gate__notice--success {
    padding: 1.5rem;
    border-radius: 14px;
    text-align: center;
}

.ph-gate__notice-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 700;
    color: var(--green);
}

.ph-gate__notice-text {
    margin: 0.5rem 0 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--ink-soft);
}

/* ── Formularz ─────────────────────────────────────────────────────────── */
.ph-gate__form { display: flex; flex-direction: column; gap: 1.15rem; }

.ph-gate__field { display: flex; flex-direction: column; gap: 0.5rem; }

.ph-gate__label {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.88);
}

.ph-gate__input,
.ph-gate__select {
    width: 100%;
    padding: 0.65rem 0.85rem;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--radius-ctrl);
    background: var(--surface);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: 14px;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.ph-gate__select { appearance: none; }

/* Obrys skupienia jest brązowy, a nie systemowy niebieski — niebieski w tym
   panelu znaczy dokładnie jedno („W trakcie") i nie ma go w bramie.         */
.ph-gate__input:focus,
.ph-gate__select:focus,
.ph-gate__file:focus {
    outline: none;
    border-color: var(--brown);
    box-shadow: 0 0 0 3px rgba(146, 96, 47, 0.35);
}

.ph-gate__file {
    width: 100%;
    padding: 0.5rem 0.85rem;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--radius-ctrl);
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
    font-family: var(--font-ui);
    font-size: 13px;
}

.ph-gate__file::file-selector-button {
    margin-right: 0.75rem;
    padding: 0.3rem 0.8rem;
    border: 0;
    border-radius: var(--radius-ctrl);
    background: var(--brown);
    color: #fff;
    font-family: var(--font-ui);
    font-weight: 600;
    cursor: pointer;
}

.ph-gate__hint {
    margin: 0;
    font-size: 12px;
    line-height: 1.45;
    color: rgba(255, 255, 255, 0.55);
}

.ph-gate__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

.ph-gate__row--address {
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    gap: 0.6rem;
}

.ph-gate__stack { display: flex; flex-direction: column; gap: 0.6rem; }

/* ── Wybory ────────────────────────────────────────────────────────────────
   Rola i typ rozliczenia to decyzje z konsekwencjami (dokument kwalifikacyjny,
   pola firmy), więc dostają płytki do klikania w całości, a nie same kropki. */
.ph-gate__choices {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

.ph-gate__choice {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.9rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: var(--radius-ctrl);
    background: rgba(255, 255, 255, 0.08);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}

.ph-gate__choice:hover { background: rgba(255, 255, 255, 0.16); }

.ph-gate__choice:focus-within {
    border-color: var(--brown);
    box-shadow: 0 0 0 3px rgba(146, 96, 47, 0.35);
}

.ph-gate__choice-name {
    display: block;
    font-weight: 700;
    font-size: 14px;
    color: #fff;
}

.ph-gate__choice-desc {
    display: block;
    margin-top: 0.2rem;
    font-size: 12px;
    line-height: 1.45;
    color: rgba(255, 255, 255, 0.62);
}

.ph-gate__inline {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
}

.ph-gate__check {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    font-size: 13.5px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.92);
    cursor: pointer;
}

.ph-gate__check input { margin-top: 0.2rem; accent-color: var(--brown); }

.ph-gate__consents {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding-top: 1rem;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
}

/* ── Akcje ─────────────────────────────────────────────────────────────────
   Przycisk jest JASNY, nie brązowy. Brąz to primary panelu, ale tutaj tłem jest
   ciemna szyba na zdjęciu — brąz na niej ginie, a jasna płytka jest jedynym
   takim elementem na ekranie, więc czyta się jako główna akcja.              */
/* ⚠ `display: block` + `text-decoration: none` są po to, żeby ta sama klasa
   działała na <button> i na <a>. Bez nich link zostaje inline: `width: 100%`
   go nie rozciąga, a podkreślenie zostaje i płytka wygląda jak przycisk
   z linkiem w środku. */
.ph-gate__submit {
    display: block;
    width: 100%;
    padding: 0.8rem 1rem;
    border: 0;
    border-radius: var(--radius-ctrl);
    background: var(--surface-soft);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: 14.5px;
    font-weight: 700;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s, transform 0.1s;
}

.ph-gate__submit:hover { text-decoration: none; }

.ph-gate__submit:hover { background: var(--field); }
.ph-gate__submit:active { transform: translateY(1px); }

.ph-gate__submit:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(146, 96, 47, 0.55);
}

.ph-gate__submit--secondary {
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.24);
}

.ph-gate__submit--secondary:hover { background: rgba(255, 255, 255, 0.18); }

.ph-gate__divider {
    margin-top: 1.75rem;
    padding-top: 1.5rem;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
    text-align: center;
}

.ph-gate__divider-label {
    margin: 0 0 1rem;
    font-size: 13px;
    color: rgba(255, 255, 255, 0.6);
}

.ph-gate__links {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    align-items: center;
    margin-top: 1.25rem;
}

.ph-gate__link {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--surface-soft);
    text-decoration: none;
}

.ph-gate__link:hover { color: #fff; text-decoration: underline; }

.ph-gate__footer {
    position: relative;
    z-index: 1;
    margin-top: 1.75rem;
    text-align: center;
    font-size: 12.5px;
    color: rgba(255, 255, 255, 0.62);
}

/* ── Wariant „brak dostępu" ────────────────────────────────────────────────
   Ekran bez formularza, więc pusty stan: ikona (nie emoji — emoji ignoruje
   `color` i wnosi barwy spoza palety), powód i jedno wyjście. */
.ph-gate__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    margin: 0 auto 1.5rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.1);
    color: var(--gold);
}

.ph-gate__icon i,
.ph-gate__icon svg { width: 28px; height: 28px; }

.ph-gate__body {
    margin: 0 0 1.5rem;
    font-size: 14px;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.82);
    text-align: center;
}

.ph-gate__note {
    padding: 0.9rem 1rem;
    margin-bottom: 1.5rem;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: var(--radius-ctrl);
    background: rgba(255, 255, 255, 0.07);
    font-size: 13px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.72);
    text-align: center;
}

@media (max-width: 560px) {
    .ph-gate { padding: 1.25rem 0.85rem; }
    .ph-gate__panel { padding: 1.4rem; }
    .ph-gate__row,
    .ph-gate__row--address,
    .ph-gate__choices { grid-template-columns: 1fr; }
}

/* Wiersz etykiety: nazwa pola + dymek obok niej.
   ⚠ Dymek MUSI stać poza <label>. `<span tabindex="0">` nie jest treścią
   interaktywną, więc kliknięcie ikonki „i" aktywuje etykietę — przy polu
   plikowym otwiera okno wyboru pliku. Czytnik ekranu doczytuje przy tym całą
   podpowiedź do nazwy pola. */
.ph-label-row {
    display: flex;
    align-items: center;
}
