@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('../fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('../fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:italic;font-weight:400;font-display:swap;
  src:url('../fonts/ibm-plex-sans-400-italic-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Sans';font-style:italic;font-weight:400;font-display:swap;
  src:url('../fonts/ibm-plex-sans-400-italic-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/ibm-plex-sans-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/ibm-plex-sans-400-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;
  src:url('../fonts/ibm-plex-sans-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;
  src:url('../fonts/ibm-plex-sans-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/ibm-plex-sans-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/ibm-plex-sans-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

/* =========================================================
   web—blog · style.css
   IBM Plex Sans / Mono · jasny + ciemny motyw
   ========================================================= */

:root{
  --bg:#ffffff; --surface:#f6f7f9; --text:#15181d; --muted:#5d6672; --faint:#8b95a3;
  --line:#e5e8ec; --line-soft:#eef0f3; --accent:#1f6feb; --accent-soft:rgba(31,111,235,.10);
  /* Dwie poświaty strony publicznej, przenikające się w tle (patrz body). */
  --glow-a:rgba(31,111,235,.08); --glow-b:rgba(180,90,220,.07);
  /* Poświata tła w panelu (patrz body.is-admin). */
  --admin-glow:rgba(31,111,235,.07); --admin-tint:rgba(21,24,29,.028);
  /* Paleta znaczków (Label) — niezależna od --accent, żeby dało się
     rozróżnić kilka flag na jednym wpisie. */
  --label-purple:#8b5cf6; --label-green:#1a9c6b; --label-amber:#b8860b;
  --label-red:#e5484d; --label-gray:#6d7683;
  --sans:"IBM Plex Sans",system-ui,-apple-system,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,monospace;
  --wrap:1160px; --measure:680px;
}
html[data-theme="dark"]{
  --bg:#0b0e13; --surface:#141920; --text:#e5e9ef; --muted:#98a1ae; --faint:#6d7683;
  --line:#222932; --line-soft:#181e26; --accent:#5b9dff; --accent-soft:rgba(91,157,255,.14);
  --glow-a:rgba(91,157,255,.09); --glow-b:rgba(190,110,240,.07);
  --admin-glow:rgba(91,157,255,.10); --admin-tint:rgba(255,255,255,.022);
  --label-purple:#a78bfa; --label-green:#34d399; --label-amber:#e0a840;
  --label-red:#f0656a; --label-gray:#98a1ae;
}
@media (prefers-color-scheme:dark){
  html:not([data-theme]){
    --bg:#0b0e13; --surface:#141920; --text:#e5e9ef; --muted:#98a1ae; --faint:#6d7683;
    --line:#222932; --line-soft:#181e26; --accent:#5b9dff; --accent-soft:rgba(91,157,255,.14);
    --glow-a:rgba(91,157,255,.09); --glow-b:rgba(190,110,240,.07);
    --admin-glow:rgba(91,157,255,.10); --admin-tint:rgba(255,255,255,.022);
    --label-purple:#a78bfa; --label-green:#34d399; --label-amber:#e0a840;
    --label-red:#f0656a; --label-gray:#98a1ae;
  }
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
/* Jeden ciągły klimat od góry do dołu CAŁEGO dokumentu, nie tylko
   pierwszego ekranu - rozmiar gradientów w % wysokości `html`, żeby się
   nie "urywały" na długich wpisach tak, jak działoby się z px/vh.
   Tło na <html>, nie na <body>: <body> ma tylko wysokość widocznej
   treści przy krótkich stronach, <html> rozciąga się z całym dokumentem. */
html{
  background:var(--bg);
  background-image:
    radial-gradient(80% 60% at 12% 0%, var(--glow-a), transparent 68%),
    radial-gradient(75% 70% at 100% 45%, var(--glow-b), transparent 68%);
  background-repeat:no-repeat;
}
body{
  background:transparent;color:var(--text);font-family:var(--sans);font-size:17px;line-height:1.7;
  -webkit-font-smoothing:antialiased;
}
/* Panel: bez kratki. Na stronie publicznej siatka jest tłem dla rzadkiego
   tekstu i działa, ale pod gęstym formularzem robi się szum, który zjada
   czytelność pól. W zamian miękka poświata akcentu u góry — daje głębię,
   nie konkurując z treścią. */
/* `min-height:100vh` + `background-color` są tu konieczne: tło strony
   publicznej żyje na <html> (patrz wyżej), a krótkie strony panelu (np.
   login) mają <body> niższe niż okno - bez tego pod spodem prześwitywałby
   przez <html> publiczny gradient. */
body.is-admin{background-color:var(--bg);background-attachment:fixed;min-height:100vh;
  background-image:
    radial-gradient(1100px 520px at 50% -8%, var(--admin-glow), transparent 70%),
    linear-gradient(180deg, var(--admin-tint) 0%, transparent 340px)}

a{color:var(--accent);text-decoration:none}
::selection{background:var(--accent-soft)}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:2px}
img{max-width:100%;display:block}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 32px}
.mono{font-family:var(--mono)}

/* ---------- pasek postępu czytania ---------- */
.progress{position:fixed;top:0;left:0;height:2px;width:0;background:var(--accent);z-index:60;transition:width .1s linear}

/* ---------- nagłówek ---------- */
.site-header{position:sticky;top:0;z-index:40;backdrop-filter:blur(12px);
  background:color-mix(in srgb,var(--bg) 82%,transparent);border-bottom:1px solid var(--line-soft)}
.site-header .wrap{height:64px;display:flex;align-items:center;justify-content:space-between;gap:24px}
.brand{display:flex;align-items:center;gap:10px;color:var(--text)}
.brand .dot{width:10px;height:10px;border-radius:2px;background:var(--accent)}
.brand .name{font-weight:600;letter-spacing:-.02em;font-size:1rem}
.brand .badge{font-family:var(--mono);font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint);border:1px solid var(--line);border-radius:2px;padding:2px 6px;margin-left:6px}
.site-nav{display:flex;align-items:center;gap:24px}
.site-nav a{font-size:.88rem;color:var(--muted);transition:color .2s}
.site-nav a:hover{color:var(--text)}
/* "Wyloguj" jest <button> w <form>, nie <a> — bez tego dziedziczy
   domyślny wygląd przycisku systemowego, niespójny z resztą nawigacji. */
.nav-logout{display:inline-flex;margin:0}
.nav-logout button{font-family:var(--sans);font-size:.88rem;color:var(--muted);
  background:none;border:none;padding:0;cursor:pointer;transition:color .2s}
.nav-logout button:hover{color:var(--text)}
.theme-toggle{display:flex;align-items:center;gap:8px;background:transparent;border:1px solid var(--line);
  color:var(--muted);font-family:var(--mono);font-size:.66rem;letter-spacing:.08em;text-transform:uppercase;
  padding:6px 11px;border-radius:3px;cursor:pointer;transition:border-color .25s,color .25s}
.theme-toggle:hover{border-color:var(--accent);color:var(--accent)}
.theme-toggle .dot{width:6px;height:6px;border-radius:50%;background:var(--accent)}

.header-actions{display:flex;align-items:center;gap:10px}
.menu-toggle{display:none;width:36px;height:34px;padding:7px;border:1px solid var(--line);border-radius:3px;background:transparent;color:var(--text);cursor:pointer}
.menu-toggle span{display:block;width:18px;height:2px;margin:3px auto;background:currentColor;transition:transform .2s,opacity .2s}

/* ---------- wejścia przy scrollu ---------- */
.reveal{transition:opacity .7s cubic-bezier(.2,.7,.3,1),transform .7s cubic-bezier(.2,.7,.3,1)}
.js-anim .reveal{opacity:0;transform:translateY(14px)}
.js-anim .reveal.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .js-anim .reveal{opacity:1;transform:none}
  *{animation:none !important;transition-duration:.01ms !important}
}

/* ---------- hero strony głównej ---------- */
.home-content{max-width:820px}.hero{padding:76px 0 56px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:28px}
.hero-kicker{display:block;font-family:var(--mono);font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);margin-bottom:24px}
.hero h1{margin:0;font-size:clamp(2.4rem,6vw,4.1rem);line-height:1.04;letter-spacing:-.045em;font-weight:600;text-wrap:balance}
.hero p{margin:28px 0 0;font-size:1.15rem;line-height:1.6;color:var(--muted);max-width:560px;text-wrap:pretty}

/* ---------- indeks wpisów ---------- */
.index-layout{max-width:820px}
.index-head{display:flex;align-items:baseline;justify-content:space-between;gap:20px;padding-bottom:16px;border-bottom:1px solid var(--line)}.index-head h2{margin:0;font-size:1.4rem;letter-spacing:-.025em}.tags-link,.filter-notice a,.start-here a,.empty a{font-family:var(--mono);font-size:.75rem;color:var(--accent)}
.index-head .label{font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint)}
.filters{display:flex;gap:6px;flex-wrap:wrap}
.filters a{font-family:var(--mono);font-size:.68rem;letter-spacing:.06em;color:var(--faint);border-radius:3px;padding:5px 10px;transition:color .2s}
.filters a:hover{color:var(--text)}
.filters a.is-active{background:var(--accent-soft);color:var(--accent)}
/* Link do pełnej listy tagów - odcięty od "chipów" wcięciem po lewej
   i lekką kursywą, żeby nie wyglądał jak kolejny tag, tylko jak wyjście
   do innej strony. Selektor z .filters a dla specyficzności (bez tego
   .filters a{color:var(--faint)} i ten dopisany reset mają tę samą wagę,
   a kolejność w pliku zdecydowałaby przypadkiem). */
.filters a.filters-more{margin-left:8px;font-style:italic;color:var(--faint)}
.filters a.filters-more:hover{color:var(--accent)}

.post-index{list-style:none;margin:0;padding:0}
.post-index > li{border-bottom:1px solid var(--line-soft)}
.row{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:24px;align-items:start;
  padding:26px 14px 26px 6px;color:inherit;overflow:hidden}
.row .wipe{position:absolute;inset:0;background:var(--surface);transform:scaleX(0);transform-origin:left;
  transition:transform .45s cubic-bezier(.2,.7,.3,1);z-index:0}
.row:hover .wipe,.row:focus-visible .wipe{transform:scaleX(1)}
.row .body{position:relative;z-index:1;display:block;transition:transform .45s cubic-bezier(.2,.7,.3,1)}
.row:hover .body{transform:translateX(10px)}
.row .meta{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:6px}
.row .kind{font-family:var(--mono);font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;color:var(--accent)}
.row .branch{font-family:var(--mono);font-size:.66rem;color:var(--faint)}
.row .title{display:block;font-size:1.3rem;line-height:1.3;letter-spacing:-.025em;font-weight:600;max-width:640px;text-wrap:pretty}
.row .lead{display:block;margin-top:8px;font-size:.96rem;line-height:1.6;color:var(--muted);max-width:600px}
.row .side{position:relative;z-index:1;display:flex;align-items:center;gap:14px;padding-top:6px}
.row time{font-family:var(--mono);font-size:.72rem;color:var(--faint);white-space:nowrap}
.row .read-time{font-family:var(--mono);font-size:.68rem;color:var(--faint);white-space:nowrap}
.row .arrow{font-family:var(--mono);font-size:.85rem;color:var(--accent);opacity:0;transform:translateX(-8px);transition:opacity .35s,transform .35s}
.row:hover .arrow{opacity:1;transform:none}

/* paginacja */
.pagination{display:flex;align-items:center;justify-content:space-between;padding-top:32px}
.pagination .count{font-family:var(--mono);font-size:.72rem;color:var(--faint)}
.pagination .links{display:flex;gap:8px}
.pagination a,.pagination span.disabled{font-family:var(--mono);font-size:.76rem;border-radius:3px;padding:8px 14px;transition:border-color .25s}
.pagination a{color:var(--accent);border:1px solid var(--line)}
.pagination a:hover{border-color:var(--accent)}
.pagination span.disabled{color:var(--faint);border:1px solid var(--line-soft)}

/* ---------- wpis ---------- */
.post-header{padding:76px 0 0;max-width:820px}
.back{display:inline-block;font-family:var(--mono);font-size:.74rem;color:var(--muted);transition:color .2s}
.back:hover{color:var(--accent)}
.post-meta{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:32px 0 18px}
.post-meta time,.post-meta .read,.post-meta .views,.post-meta .updated{font-family:var(--mono);font-size:.72rem;color:var(--faint)}
.post-meta .sep{width:3px;height:3px;border-radius:50%;background:var(--faint)}
.flag{display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);font-size:.66rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--accent);background:var(--accent-soft);border-radius:3px;padding:5px 10px}
.flag .dot{width:5px;height:5px;border-radius:50%;background:var(--accent)}
.post-header h1{margin:0;font-size:clamp(2.1rem,4.6vw,3.2rem);line-height:1.08;letter-spacing:-.04em;font-weight:600;text-wrap:balance}
.post-header .lead{margin:28px 0 0;font-size:1.2rem;line-height:1.55;color:var(--muted);max-width:var(--measure);text-wrap:pretty}
.rule{height:1px;background:var(--line);margin:52px 0 48px}
.post-layout{display:grid;grid-template-columns:200px minmax(0,1fr);gap:64px;align-items:start}
.post-body{width:100%;min-width:0;max-width:var(--measure)}

/* spis treści — sidebar sticky z podświetlaniem aktualnej sekcji (main.js).
   `max-height` + własny scroll zamiast gołego `position:sticky` — inaczej
   na krótkich wpisach (2-3 nagłówki) z długą treścią sticky "odczepiał się"
   wysoko na ekranie, zostawiając pustą przestrzeń pod spisem. Ograniczenie
   wysokości do widocznego obszaru viewportu eliminuje to strukturalnie,
   niezależnie od tego, ile nagłówków ma dany wpis. */
.toc-desktop{position:sticky;top:104px;max-height:calc(100vh - 104px - 32px);overflow-y:auto}
.toc-mobile{display:none}
.toc .label{display:block;font-family:var(--mono);font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);margin-bottom:12px}
.toc nav{display:flex;flex-direction:column}
.toc a{display:block;font-size:.82rem;line-height:1.4;color:var(--faint);padding:6px 0 6px 14px;
  border-left:1px solid var(--line-soft);transition:color .25s,border-color .25s}
.toc a:hover{color:var(--text)}
.toc a.active{color:var(--accent);border-left-color:var(--accent)}
.toc .tags{margin-top:24px;padding-top:16px;border-top:1px solid var(--line-soft);display:flex;flex-direction:column;gap:6px;
  font-family:var(--mono);font-size:.66rem;color:var(--faint)}

/* nawigacja poprzedni/następny */
.post-nav{margin-top:64px;display:grid;grid-template-columns:1fr 1fr;gap:16px}
.post-nav a{color:inherit;padding:22px;border:1px solid var(--line-soft);border-radius:4px;transition:border-color .3s,transform .3s}
.post-nav a:hover{border-color:var(--accent);transform:translateY(-2px)}
.post-nav .dir{font-family:var(--mono);font-size:.66rem;color:var(--faint)}
.post-nav p{margin:8px 0 0;font-size:.95rem;line-height:1.4;font-weight:500}
.post-nav .next{text-align:right}

/* linki do udostępnienia wpisu */
.share-links{margin-top:40px;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.share-links .label{font-family:var(--mono);font-size:.64rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint)}
.share-links a{font-family:var(--mono);font-size:.76rem;color:var(--muted);
  padding:6px 12px;border:1px solid var(--line-soft);border-radius:5px;
  transition:border-color .2s,color .2s}
.share-links a:hover{border-color:var(--accent);color:var(--accent)}

/* powiązane wpisy (wspólny tag) */
.related-posts{margin-top:48px;padding-top:28px;border-top:1px solid var(--line-soft)}
.related-posts .label{display:block;font-family:var(--mono);font-size:.64rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin-bottom:14px}
.related-posts ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.related-posts a{display:block;color:inherit;padding:16px 18px;border:1px solid var(--line-soft);
  border-radius:4px;transition:border-color .25s,transform .25s}
.related-posts a:hover{border-color:var(--accent);transform:translateY(-2px)}
.related-posts .title{display:block;font-size:.92rem;font-weight:500}
.related-posts .lead{display:block;margin-top:4px;font-size:.82rem;color:var(--faint);line-height:1.4}

/* ---------- TREŚĆ Z EDYTORA WYSIWYG ---------- */
.prose{font-size:17.5px;line-height:1.78;color:var(--text)}
.prose > * + *{margin-top:1.15em}
.prose h1{font-size:2rem;line-height:1.2;letter-spacing:-.02em;font-weight:600;margin:2.4rem 0 0}
.prose h2{font-size:1.5rem;line-height:1.28;letter-spacing:-.02em;font-weight:600;margin:3rem 0 0;scroll-margin-top:120px}
.prose h3{font-size:1.15rem;line-height:1.4;font-weight:600;margin:2.1rem 0 0;scroll-margin-top:120px}
.prose h4{font-size:.78rem;font-weight:500;font-family:var(--mono);text-transform:uppercase;letter-spacing:.1em;color:var(--muted);margin:1.9rem 0 0}
.prose h2 + *,.prose h3 + *,.prose h4 + *{margin-top:.6em}
.prose p{margin:0}
.prose p + p{margin-top:1.15em}
.prose p + :is(ul,ol){margin-top:.75em}
.prose :is(ul,ol) + p{margin-top:1em}
.prose blockquote + p{margin-top:1.4em}
.prose strong{font-weight:600}
.prose em{font-style:italic}
.prose ul,.prose ol{margin:0;padding-left:1.4em}
.prose li{margin:.45em 0;padding-left:.3em}
.prose li::marker{color:var(--accent);font-variant-numeric:tabular-nums;font-family:var(--mono);font-size:.85em}
.prose blockquote{margin:2.6rem 0;padding:0 0 0 1.6rem;border-left:2px solid var(--accent);font-size:1.25rem;line-height:1.55;font-style:italic}
.prose hr{border:0;border-top:1px solid var(--line);margin:3rem 0}
.prose a{border-bottom:1px solid var(--accent-soft)}
.prose code{font-family:var(--mono);font-size:.86em;background:var(--surface);border:1px solid var(--line-soft);border-radius:3px;padding:.1em .35em}
/* Kod pozostaje czytelny w oryginalnej postaci, ale jego przewijanie nigdy
   nie rozszerza całej strony. */
.prose pre{box-sizing:border-box;max-width:100%;margin:2rem 0;overflow-x:auto;-webkit-overflow-scrolling:touch;padding:1rem 1.15rem;background:var(--surface);border:1px solid var(--line-soft);border-radius:4px;white-space:pre;tab-size:2}
.prose pre code{display:block;width:max-content;min-width:100%;padding:0;border:0;background:transparent;border-radius:0;font-size:.82em}
.prose img{max-width:100%;height:auto;border-radius:4px}
.prose .dropcap{float:left;font-size:3.1rem;line-height:.82;font-weight:600;letter-spacing:-.04em;margin:6px 12px 0 0;color:var(--accent)}

/* Popover z definicją pojęcia — czysty CSS, bez JS. :focus obsługuje tap
   na dotyku (tabindex="0" na spanie) tak samo jak klawiaturę; :hover myszkę. */
.prose .glossary-term{position:relative;border-bottom:1px dashed var(--accent);
  cursor:help;outline:none}
.prose .glossary-term::after{content:attr(data-definition);position:absolute;
  bottom:calc(100% + 8px);left:0;z-index:10;width:min(320px,80vw);
  padding:10px 14px;border-radius:6px;background:var(--text);color:var(--bg);
  font-family:var(--sans);font-size:.82rem;font-weight:400;line-height:1.5;
  letter-spacing:normal;box-shadow:0 8px 22px rgba(0,0,0,.18);
  opacity:0;visibility:hidden;transform:translateY(4px);
  transition:opacity .15s ease,transform .15s ease}
.prose .glossary-term:hover::after,.prose .glossary-term:focus::after{
  opacity:1;visibility:visible;transform:translateY(0)}

/* galeria */
.prose figure{margin:2.6rem 0}
.prose figcaption{margin-top:.7rem;font-family:var(--mono);font-size:.72rem;line-height:1.5;color:var(--faint)}
.gallery{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px}
.gallery figure{margin:0}
.gallery img{aspect-ratio:4/5;object-fit:cover;width:100%}

/* placeholder / stan ładowania obrazka (Cloudinary) */
.ph{position:relative;overflow:hidden;background:var(--surface);border:1px solid var(--line-soft);border-radius:4px;
  display:flex;align-items:center;justify-content:center;padding:14px;text-align:center;
  font-family:var(--mono);font-size:.64rem;line-height:1.5;color:var(--faint);transition:border-color .3s}
.ph::after{content:"";position:absolute;inset:0;
  background:linear-gradient(105deg,transparent 35%,var(--accent-soft) 50%,transparent 65%);
  transform:translateX(-100%);animation:sheen 3.4s ease-in-out infinite}
.gallery figure:hover .ph{border-color:var(--accent)}
@keyframes sheen{0%{transform:translateX(-100%)}55%,100%{transform:translateX(100%)}}

/* tabela */
.table-scroll,.table-wrapper{max-width:100%;margin:2.6rem 0;overflow-x:auto;-webkit-overflow-scrolling:touch}
.prose table{border-collapse:collapse;width:100%;min-width:540px;font-size:.92rem;line-height:1.5}
.prose th,.prose td{text-align:left;padding:.8rem 1.2rem .8rem 0;border-bottom:1px solid var(--line-soft);vertical-align:top}
.prose th{font-family:var(--mono);font-size:.7rem;text-transform:uppercase;letter-spacing:.08em;font-weight:500;color:var(--muted);border-bottom:1px solid var(--line)}
.prose tbody tr{transition:background .2s}
.prose tbody tr:hover{background:var(--surface)}
.prose tbody tr:last-child td{border-bottom:0}
.prose td:first-child{font-weight:500}
.prose td.num{font-family:var(--mono);font-variant-numeric:tabular-nums;white-space:nowrap}

/* embed YouTube 16:9 */
.embed{margin:2.6rem 0;position:relative;aspect-ratio:16/9;background:var(--surface);
  border:1px solid var(--line-soft);border-radius:4px;overflow:hidden}
.embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}

/* klasy generowane przez edytor Quill */
.ql-align-center{text-align:center}
.ql-align-right{text-align:right}
.ql-align-justify{text-align:justify;text-justify:inter-word}
.ql-indent-1{padding-left:3em}.ql-indent-2{padding-left:6em}.ql-indent-3{padding-left:9em}
.ql-indent-4{padding-left:12em}.ql-indent-5{padding-left:15em}.ql-indent-6{padding-left:18em}
.ql-indent-7{padding-left:21em}.ql-indent-8{padding-left:24em}

/* ---------- strony statyczne i błędy ---------- */
.page{max-width:660px;padding-top:100px}
.page h1{margin:0;font-size:clamp(2rem,4.4vw,2.9rem);line-height:1.1;letter-spacing:-.04em;font-weight:600}

/* ---------- chmura tagów (/tagi) ---------- */
.tag-filter{display:block;width:100%;max-width:360px;margin-top:28px;
  padding:12px 16px;font-family:var(--sans);font-size:.98rem;
  color:var(--text);background:var(--surface);border:1px solid var(--line);border-radius:7px;
  transition:border-color .18s ease,box-shadow .18s ease}
.tag-filter:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.tag-cloud{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}
.tag-cloud a{font-family:var(--mono);font-size:.82rem;color:var(--muted);
  background:var(--surface);border:1px solid var(--line);border-radius:99px;
  padding:8px 16px;transition:border-color .18s ease,color .18s ease,background-color .18s ease}
.tag-cloud a:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.tag-filter-empty{margin-top:20px;color:var(--faint);font-size:.9rem}

/* ---------- szukaj (/szukaj) ---------- */
.search-form{display:flex;gap:10px;margin:32px 0 0}
.search-form input{flex:1;padding:12px 16px;font-family:var(--sans);font-size:.98rem;
  color:var(--text);background:var(--surface);border:1px solid var(--line);border-radius:7px;
  transition:border-color .18s ease,box-shadow .18s ease}
.search-form input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.search-form button{font-family:var(--sans);font-size:.95rem;font-weight:500;color:#fff;
  background:var(--accent);border:1px solid var(--accent);border-radius:7px;padding:12px 22px;
  cursor:pointer;transition:transform .18s ease,box-shadow .18s ease}
.search-form button:hover{transform:translateY(-1px);box-shadow:0 4px 14px var(--accent-soft)}
.search-summary{margin:28px 0 0;color:var(--faint);font-size:.9rem}
.search-form-wrap{position:relative}
.live-search-results{position:absolute;top:calc(100% + 6px);left:0;right:78px;z-index:20;
  list-style:none;margin:0;padding:6px;background:var(--surface);border:1px solid var(--line);
  border-radius:7px;box-shadow:0 10px 28px rgba(0,0,0,.12);max-height:340px;overflow-y:auto}
.live-search-results li + li{border-top:1px solid var(--line-soft)}
.live-search-results a{display:flex;flex-direction:column;gap:2px;padding:9px 10px;
  border-radius:5px;text-decoration:none;transition:background-color .15s ease}
.live-search-results a:hover,.live-search-results a:focus{background:var(--accent-soft)}
.live-search-results .title{font-family:var(--sans);font-size:.92rem;color:var(--text)}
.live-search-results .excerpt{font-size:.8rem;color:var(--faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.note{margin:52px 0 0;padding-top:22px;border-top:1px solid var(--line-soft);
  font-family:var(--mono);font-size:.74rem;line-height:1.7;color:var(--faint)}
.error{max-width:560px;padding-top:150px}
.error .code{font-family:var(--mono);font-size:.76rem;letter-spacing:.18em;color:var(--accent)}
.error.is-500 .code{color:#d1495b}
.error h1{margin:16px 0 0;font-size:clamp(2rem,4.4vw,2.9rem);line-height:1.12;letter-spacing:-.04em;font-weight:600}
.error p{margin:18px 0 0;font-size:1.05rem;line-height:1.6;color:var(--muted)}
.actions{display:flex;gap:10px;margin-top:32px}
.btn{font-family:var(--sans);font-size:.9rem;font-weight:500;border:1px solid transparent;
  border-radius:7px;padding:11px 22px;cursor:pointer;
  transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease,background-color .18s ease}
.btn-primary{color:#fff;background:var(--accent);border-color:var(--accent)}
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 14px var(--accent-soft)}
.btn-primary:active{transform:translateY(0)}
.btn-ghost{color:var(--muted);border-color:var(--line);background:transparent}
.btn-ghost:hover{border-color:var(--accent);color:var(--accent)}
.error .id{margin:36px 0 0;font-family:var(--mono);font-size:.72rem;color:var(--faint)}

/* ---------- stopka ---------- */
.site-footer{border-top:1px solid var(--line-soft)}
.site-footer .wrap{padding-top:38px;padding-bottom:64px;display:flex;flex-wrap:wrap;gap:18px;align-items:baseline;justify-content:space-between}
.footer-copy{max-width:510px}.footer-copy p{margin:6px 0 0;font-family:var(--mono);font-size:.72rem;line-height:1.55;color:var(--faint)}
.footer-copy .stack a{color:var(--faint);transition:color .2s}
.footer-copy .stack a:hover{color:var(--accent)}
.site-footer span,.site-footer a{font-family:var(--mono);font-size:.72rem;color:var(--faint)}
.site-footer a:hover{color:var(--accent)}
.site-footer nav{display:flex;gap:20px;flex-wrap:wrap}
.social-links{gap:14px !important}
.social-links a{display:flex}

/* przewiń do góry */
.scroll-top{position:fixed;right:20px;bottom:20px;z-index:30;width:42px;height:42px;
  display:flex;align-items:center;justify-content:center;font-size:1.1rem;line-height:1;
  color:var(--text);background:var(--surface);border:1px solid var(--line);border-radius:50%;
  box-shadow:0 6px 18px rgba(0,0,0,.14);cursor:pointer;
  transition:border-color .18s ease,color .18s ease,transform .18s ease}
.scroll-top:hover{border-color:var(--accent);color:var(--accent);transform:translateY(-2px)}
.scroll-top[hidden]{display:none}
.social-links svg{width:16px;height:16px}

/* ---------- responsywność ---------- */
@media (max-width:960px){
  .hide-md{display:none !important}
  .toc-mobile{display:block;margin:0 0 32px;border:1px solid var(--line-soft);border-radius:4px;background:var(--surface)}
  .toc-mobile summary{padding:14px 16px;font-family:var(--mono);font-size:.74rem;letter-spacing:.06em;color:var(--muted);cursor:pointer}
  .toc-mobile[open] summary{border-bottom:1px solid var(--line-soft)}
  .toc-mobile > div{padding:10px 16px 16px}
  .toc-mobile .tags{margin-top:16px;padding-top:14px}
  .hero{padding:48px 0}
  .index-layout{grid-template-columns:1fr}
  .post-layout{grid-template-columns:1fr;gap:0}
}
@media (max-width:720px){
  .wrap{padding:0 20px}
  .site-header .wrap{height:60px;gap:12px;position:relative}
  .brand{min-width:0}.brand .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .header-actions{margin-left:auto}.theme-toggle{width:36px;height:34px;justify-content:center;padding:6px}.theme-toggle [data-theme-label]{display:none}
  .menu-toggle{display:block}
  body.js-navigation .site-nav{display:none;position:absolute;top:calc(100% + 1px);left:0;right:0;padding:12px 20px 16px;background:var(--bg);border-bottom:1px solid var(--line);box-shadow:0 10px 18px rgba(0,0,0,.08)}
  body.js-navigation .site-nav.is-open{display:flex;flex-direction:column;align-items:stretch;gap:2px}
  body.js-navigation .site-nav a,body.js-navigation .nav-logout button{display:block;width:100%;padding:10px 4px;font-size:.95rem;text-align:left}
  body.js-navigation .nav-logout{display:block}
  body.js-navigation .menu-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(5px) rotate(45deg)}
  body.js-navigation .menu-toggle[aria-expanded="true"] span:nth-child(2){opacity:0}
  body.js-navigation .menu-toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}
  .row{grid-template-columns:1fr;gap:10px;padding:22px 4px}.row .side{padding-top:0}
  .post-index > li{border-bottom:1px solid var(--line)}
  .post-index > li:last-child{border-bottom:none}
  .row:hover .body{transform:none}
  .prose h1{font-size:1.6rem}.prose h2{font-size:1.28rem}
  .post-nav{grid-template-columns:1fr}
  .post-nav .next{text-align:left}
  .ql-indent-1,.ql-indent-2,.ql-indent-3,.ql-indent-4,.ql-indent-5,.ql-indent-6,.ql-indent-7,.ql-indent-8{padding-left:1.5em}
  .site-footer .wrap{padding-top:30px;padding-bottom:40px;align-items:flex-start;gap:22px}
  .site-footer nav{gap:12px 18px}
}

/* =========================================================
   Uzupełnienia poza eksportem designu
   ========================================================= */

/* Embed YouTube: `render_embeds()` generuje wrapper `.embed-responsive`
   (patrz app/utils/embeds.py). Nazwa jest częścią kontraktu z sanitizerem —
   whitelista klas w app/utils/sanitize.py przepuszcza dokładnie tę wartość,
   więc podpinamy ją pod istniejące style zamiast zmieniać nazwę w kodzie. */
.embed-responsive{margin:2.6rem 0;position:relative;aspect-ratio:16/9;background:var(--surface);
  border:1px solid var(--line-soft);border-radius:4px;overflow:hidden}
.embed-responsive iframe{position:absolute;inset:0;width:100%;height:100%;border:0}


/* ---------- komunikaty i podgląd szkicu ---------- */
.flash{margin:0 0 20px;padding:12px 16px;border-radius:4px;font-size:.9rem;
  border:1px solid var(--line)}
.flash--success{border-color:var(--accent);background:var(--accent-soft);color:var(--text)}
.flash--error{border-color:#d1495b;background:rgba(209,73,91,.10);color:var(--text)}

.empty{padding:56px 0;color:var(--faint);font-size:.95rem}

.preview-banner{margin:0 0 28px;padding:12px 16px;border-radius:4px;
  border:1px dashed var(--accent);background:var(--accent-soft);
  font-family:var(--mono);font-size:.74rem;letter-spacing:.04em;color:var(--text);
  display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}

/* Pasek na całą szerokość ekranu (nie ograniczony do .wrap jak reszta treści) —
   ma być widoczny na każdej stronie, publicznej i w panelu, dopóki zalogowane
   jest konto demo. Kolor ostrzegawczy (bursztyn), nie accent — to nie jest
   informacja o sukcesie ani neutralna nawigacja, tylko zastrzeżenie. */
.demo-banner{background:#7a5b12;color:#fff8e6;font-size:.85rem;text-align:center}
.demo-banner .wrap{padding-top:10px;padding-bottom:10px}
.preview-banner p{margin:0}
.preview-mobile-toggle{font-family:var(--mono);font-size:.7rem;letter-spacing:.04em;
  color:var(--accent);background:var(--bg);border:1px solid var(--accent);border-radius:4px;
  padding:6px 12px;cursor:pointer;white-space:nowrap;transition:background-color .15s ease}
.preview-mobile-toggle:hover{background:var(--accent-soft)}
.preview-mobile-toggle.is-active{background:var(--accent);color:#fff}

/* Podgląd mobilny: zawęża treść do szerokości typowego telefonu, żeby
   zobaczyć formatowanie (tabele, galerie) bez fizycznego resize okna. */
[data-preview-main].preview-mobile{max-width:390px;margin:0 auto;
  border-left:1px solid var(--line);border-right:1px solid var(--line);
  padding-left:16px;padding-right:16px}
[data-preview-main].preview-mobile .post-layout{grid-template-columns:1fr}
[data-preview-main].preview-mobile .toc-desktop{display:none}
[data-preview-main].preview-mobile .toc-mobile{display:block}

/* Wpis koncepcyjny — jawne oznaczenie, że klient jest fikcyjny. Ta druga
   definicja .flag (bez tła/paddingu) nadpisuje tę z linii ~204. */
.flag{display:inline-flex;align-items:center;gap:7px;
  font-family:var(--mono);font-size:.66rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--accent)}
.flag .dot{width:5px;height:5px;border-radius:50%;background:var(--accent)}
/* Znaczki własne (Label) — kolor niezależny od --accent, żeby kilka
   flag na jednym wpisie było od siebie odróżnialnych. */
.flag--purple{color:var(--label-purple)}
.flag--purple .dot{background:var(--label-purple)}
.flag--green{color:var(--label-green)}
.flag--green .dot{background:var(--label-green)}
.flag--amber{color:var(--label-amber)}
.flag--amber .dot{background:var(--label-amber)}
.flag--red{color:var(--label-red)}
.flag--red .dot{background:var(--label-red)}
.flag--gray{color:var(--label-gray)}
.flag--gray .dot{background:var(--label-gray)}
.flag + .flag{margin-left:10px}
/* W wierszu tabeli dashboardu tytuł już nie zawija się (kolumna szeroka),
   więc bez odstępu flaga stykałaby się z ostatnim słowem tytułu. Na stronie
   publicznej .flag stoi jako pierwszy element .post-meta — tam odstęp
   od lewej byłby błędem, więc margines tylko w tym konkretnym kontekście. */
.admin td .flag{margin-left:10px}

/* ---------- panel administracyjny ---------- */
/* Panel widzi jedna osoba, ale to nie powód, żeby był brzydki. Zasada:
   pola formularza muszą odcinać się od tła (dlatego --surface, nie --bg),
   a Quill dostaje pełny restyling, bo jego domyślne style są jasne
   i rozjeżdżają się z ciemnym motywem. */
.admin{max-width:var(--measure);padding:56px 0 120px}
/* Dashboard i formularz mają dużo poziomej treści (tabela, pola formularza) -
   zwężanie ich do tej samej miary co artykuł (--measure, myślany pod czytanie
   tekstu) sprawiało, że wyglądały jak ucięte sekcje na szerokim ekranie,
   z dużym marginesem po prawej mimo że nagłówek strony sięga --wrap. */
.admin.admin--wide{max-width:var(--wrap)}
.admin h1{font-size:1.75rem;letter-spacing:-.025em;font-weight:600;margin:0 0 4px}
.admin .subtitle{margin:0 0 34px;color:var(--faint);font-size:.9rem}
.demo-login-hint{margin:14px 0 28px;padding:12px 16px;border-radius:4px;
  border:1px dashed var(--accent);background:var(--accent-soft);
  font-size:.9rem;color:var(--text)}

/* Formularz wpisu ma 8+ pól w jednej kolumnie — bez podziału na sekcje
   trudno się w nim zorientować, gdzie kończy się "co to za wpis" a zaczyna
   "jak jest sklasyfikowany". legend przejmuje styl etykiet pola (mono,
   uppercase), żeby sekcja czytała się jak nagłówek, nie jak kolejne pole. */
.admin-section{border:0;margin:0 0 40px;padding:0}
.admin-section:last-of-type{margin-bottom:0}
.admin-section legend{padding:0 0 16px;margin-bottom:18px;width:100%;
  border-bottom:1px solid var(--line-soft);font-family:var(--mono);
  font-size:.72rem;letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
.admin-section .field:last-child{margin-bottom:0}
/* Fieldset ma domyślny min-width zależny od treści. Bez tego długi toolbar
   Quilla może poszerzyć całą stronę zamiast przewijać się wyłącznie lokalnie. */
.admin-post-form form,.admin-post-form .admin-section,.admin-post-form .field,.editor-shell{min-width:0;max-width:100%;box-sizing:border-box}
/* Publikacja to jedyna decyzja w formularzu, która natychmiast zmienia,
   co widzi czytelnik — obudowanie jej ramką odróżnia ją od reszty pól,
   które są tylko metadanymi. */
.admin-section--publish{padding:20px 24px;background:var(--surface);
  border:1px solid var(--line-soft);border-radius:10px}
.admin-section--publish legend{border-bottom:0;padding-bottom:0;margin-bottom:14px}

/* Grupa pola: etykieta + kontrolka + błędy/podpowiedź trzymają się razem.
   Odstęp MIĘDZY grupami musi być wyraźnie większy niż między etykietą
   a jej polem — inaczej etykieta wizualnie przykleja się do pola powyżej
   i nie widać, co do czego należy. */
.admin .field{margin:0 0 26px}
.admin label{display:block;margin:0 0 7px;font-family:var(--mono);font-size:.68rem;
  letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}

.admin input[type=text],.admin input[type=password],.admin input[type=datetime-local],
.admin textarea,.admin select{
  width:100%;padding:11px 13px;font-family:var(--sans);font-size:.95rem;color:var(--text);
  background:var(--surface);border:1px solid var(--line);border-radius:7px;
  transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease}
.admin input[type=text]:hover,.admin input[type=password]:hover,
.admin input[type=datetime-local]:hover,.admin textarea:hover,.admin select:hover{
  border-color:var(--faint)}
.admin input::placeholder,.admin textarea::placeholder{color:var(--faint)}
/* Pierścień focusu zamiast outline'u — nie skacze layout, widać wyraźnie. */
.admin input:focus,.admin textarea:focus,.admin select:focus{
  outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}

/* Własna strzałka selecta. Domyślna systemowa nie zna motywu i świeci
   jasnym trójkątem na ciemnym tle. */
.admin select{
  appearance:none;-webkit-appearance:none;padding-right:38px;cursor:pointer;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%238b95a3' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 13px center;background-size:12px}

.admin .checkbox{display:flex;align-items:flex-start;gap:11px;margin:0 0 6px;
  padding:13px 15px;background:var(--surface);border:1px solid var(--line);border-radius:7px;
  transition:border-color .18s ease}
.admin .checkbox:hover{border-color:var(--faint)}
.admin .checkbox input[type=checkbox]{
  appearance:none;-webkit-appearance:none;flex:none;width:17px;height:17px;margin:2px 0 0;
  background:var(--bg);border:1px solid var(--line);border-radius:4px;cursor:pointer;
  transition:background-color .15s ease,border-color .15s ease}
.admin .checkbox input[type=checkbox]:checked{background:var(--accent);border-color:var(--accent);
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M3 7.2 5.8 10 11 4.4' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:center;background-size:13px}
.admin .checkbox input[type=checkbox]:focus-visible{outline:none;box-shadow:0 0 0 3px var(--accent-soft)}
.admin .checkbox label{margin:0;text-transform:none;letter-spacing:0;font-family:var(--sans);
  font-size:.93rem;color:var(--text);cursor:pointer}

/* Kilka .checkbox pod sobą (znaczki wpisu) — sam .checkbox ma margines
   tylko na dole, więc grupa nie potrzebuje nic więcej niż wrapper. */
.admin .checkbox-group .checkbox{margin-bottom:8px}
.admin .checkbox-group .checkbox:last-child{margin-bottom:0}

.admin .hint{margin:8px 0 0;font-size:.8rem;line-height:1.55;color:var(--faint)}
.admin .errors{margin:7px 0 0;padding:0;list-style:none;font-size:.82rem;color:#e5484d}
.admin .actions{margin-top:34px;padding-top:26px;border-top:1px solid var(--line-soft)}

.admin table{width:100%;border-collapse:collapse;font-size:.92rem}
.admin th{text-align:left;font-family:var(--mono);font-size:.68rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);padding:0 12px 10px 0;border-bottom:1px solid var(--line)}
.admin td{padding:13px 12px 13px 0;border-bottom:1px solid var(--line-soft);vertical-align:top}
.admin tbody tr{transition:background-color .15s ease}
.admin tbody tr:hover{background:var(--line-soft)}
.admin .status{font-family:var(--mono);font-size:.64rem;letter-spacing:.07em;text-transform:uppercase;
  display:inline-block;padding:3px 9px;border-radius:99px;border:1px solid var(--line)}
.admin .status--draft{color:var(--faint)}
.admin .status--published{color:var(--accent);border-color:var(--accent-soft);background:var(--accent-soft)}
.admin .status--scheduled{color:var(--label-amber);border-color:var(--label-amber)}
/* Status jest teraz też przyciskiem (przełącznik szkic/opublikowany z listy) —
   reset domyślnych stylów <button>, żeby wyglądał identycznie jak wcześniej.
   Selektor .admin td button.admin-status-toggle (nie tylko button.admin-status-toggle)
   żeby wygrać specyficznością z `.admin td button:hover{color:#e5484d}` niżej w pliku. */
.admin td button.admin-status-toggle.status{background:none;cursor:pointer;
  transition:filter .15s ease}
.admin td button.admin-status-toggle.status--draft{background:var(--surface)}
.admin td button.admin-status-toggle:hover{color:inherit;filter:brightness(0.92)}
html[data-theme="dark"] .admin td button.admin-status-toggle:hover{filter:brightness(1.3)}
@media (prefers-color-scheme:dark){
  html:not([data-theme]) .admin td button.admin-status-toggle:hover{filter:brightness(1.3)}
}
.admin .toolbar{display:flex;flex-wrap:wrap;gap:18px;align-items:center;margin-bottom:26px;
  font-family:var(--mono);font-size:.72rem;letter-spacing:.05em}
.admin .editor-tools{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0 0}

/* Filtry statusu na pulpicie. */
.admin .filters{display:flex;gap:14px;align-items:center}
.admin .filters a{color:var(--faint);transition:color .15s ease}
.admin .filters a:hover{color:var(--text)}
.admin .filters a.is-active{color:var(--accent)}

/* Pasek statystyk nad tabelą — liczone od wszystkich wpisów, nie od
   aktywnie przefiltrowanej listy (patrz _dashboard_stats w routes.py). */
.dashboard-stats{display:flex;flex-wrap:wrap;gap:20px;margin:0 0 22px;
  font-family:var(--mono);font-size:.76rem;color:var(--muted)}
.dashboard-stats b{color:var(--text);font-weight:600}
.dashboard-stats a{color:var(--accent)}

/* Szukaj + filtr typu/branży na pulpicie — osobna klasa (nie input[type=text])
   bo pole jest type=search, i żeby nie mieszać z resztą .admin input. */
.dashboard-search{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:0 0 26px}
.dashboard-search input[type=search],.dashboard-search select{
  padding:9px 12px;font-family:var(--sans);font-size:.88rem;color:var(--text);
  background:var(--surface);border:1px solid var(--line);border-radius:7px}
.dashboard-search input[type=search]{flex:1;min-width:200px}
.dashboard-search input[type=search]:focus,.dashboard-search select:focus{
  outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}

.admin td.admin-date{font-family:var(--mono);font-size:.76rem;color:var(--faint);cursor:help}

/* Zarządzanie tagami — scalanie (pasek nad tabelą) i zmiana nazwy inline
   (input obok przycisku w komórce, więc width:100% z .admin input trzeba
   ograniczyć, inaczej input rozciąga się na całą szerokość i wypycha "Zapisz"). */
.tag-merge{display:flex;flex-wrap:wrap;gap:10px;align-items:center;
  font-family:var(--mono);font-size:.8rem;color:var(--muted)}
.tag-merge select{padding:8px 30px 8px 12px;font-family:var(--sans);font-size:.88rem;
  color:var(--text);background:var(--surface);border:1px solid var(--line);border-radius:7px}
.tag-rename{display:flex;gap:8px;align-items:center}
.tag-rename input[type=text]{width:auto;flex:1;min-width:140px;padding:8px 11px;font-size:.88rem}

/* Akcje w tabeli: „Edytuj · Podgląd · Duplikuj · Usuń”. Duplikuj/Usuń są
   <form><button>, więc bez .inline-action byłyby blokowe i łamałyby wiersz. */
.admin td a{color:var(--muted);transition:color .15s ease}
.admin td a:hover{color:var(--accent)}
.admin td .inline-action{display:inline}
.admin td button{font-family:var(--sans);font-size:inherit;color:var(--muted);
  background:none;border:none;padding:0;cursor:pointer;transition:color .15s ease}
.admin td button:hover{color:#e5484d}
/* Duplikuj nie jest destrukcyjne — bez czerwieni zarezerwowanej dla Usuń. */
.admin td button.action-neutral:hover{color:var(--accent)}
/* Ostatnia kolumna (akcje) w jednej linii — inaczej „Usuń” zawija się pod
   spód i wiersz robi się dwa razy wyższy. */
.admin th:last-child,.admin td:last-child{white-space:nowrap;width:1%;padding-right:0}
.admin td:first-child{padding-right:24px}

/* Akcje tabeli pozostają dostępne na telefonie; przewija się wyłącznie wrapper. */
.admin .dashboard-table-scroll{margin:0;max-width:100%;border-bottom:1px solid var(--line-soft)}
.admin .dashboard-table-scroll table{min-width:760px}
.admin .dashboard-table-scroll:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.table-scroll-hint{display:none}

/* Pasek narzędzi ma pełną szerokość, a skład tekstu w Quillu — miarę artykułu. */
.admin-post-form form,.admin-post-form .editor-shell{max-width:920px}

/* Wersje treści (/admin/post/<id>/historia) — lista <details>, każda
   rozwija podgląd treści i przycisk przywrócenia. */
.revision-list{list-style:none;margin:0;padding:0}
.revision-item{border-bottom:1px solid var(--line-soft)}
.revision-item summary{display:flex;gap:14px;align-items:baseline;padding:13px 0;
  cursor:pointer;font-size:.9rem}
.revision-item summary::marker{color:var(--faint)}
.revision-item .admin-date{font-family:var(--mono);font-size:.76rem;color:var(--faint)}
.revision-item .revision-title{color:var(--text);font-weight:500}
.revision-body{padding:0 0 22px 22px}
.revision-preview{margin:0 0 16px;padding:16px 18px;border:1px solid var(--line-soft);
  border-radius:6px;background:var(--surface);max-height:280px;overflow-y:auto;
  font-size:.92rem}
.revision-preview.prose{font-size:.92rem;line-height:1.65}

/* ---------- edytor ---------- */
/* Toolbar akcji (upload/URL/YouTube) i toolbar Quilla siedzą na jednej
   „karcie” razem z polem edycji — inaczej wyglądają jak trzy niezależne
   elementy przypadkiem położone obok siebie. */
.editor-shell{border:1px solid var(--line);border-radius:9px;background:var(--surface);
  overflow:hidden;transition:border-color .18s ease,box-shadow .18s ease}
.editor-shell:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.editor-actions{display:flex;flex-wrap:wrap;gap:7px;align-items:center;
  padding:11px 12px;border-bottom:1px solid var(--line)}

.button-like{display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  font-family:var(--mono);font-size:.67rem;letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);background:var(--bg);
  padding:7px 12px;border:1px solid var(--line);border-radius:6px;
  transition:border-color .18s ease,color .18s ease,background-color .18s ease}
.button-like:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.button-like:active{transform:translateY(1px)}

/* Obszar edytora Quill. Id musi zostać `editor-root` — pod tą nazwą
   szuka go app/static/js/admin-editor.js.
   Rośnie razem z treścią zamiast startować z wielkim pustym prostokątem,
   ale ma sufit, żeby przy długim wpisie pasek narzędzi nie uciekał
   w nieskończoność poza ekran. */
#editor-root{background:var(--bg)}
.editor-shell .ql-container{min-height:300px;max-height:62vh;overflow-y:auto}

/* Panel "Co zmieniłem?" — word-diff w przeglądarce, bez zapisu na serwer. */
.diff-panel{margin-top:14px;border:1px solid var(--line);border-radius:9px;
  background:var(--surface);overflow:hidden}
.diff-panel-head{display:flex;align-items:center;justify-content:space-between;
  padding:11px 14px;border-bottom:1px solid var(--line)}
.diff-panel-head .label{font-family:var(--mono);font-size:.68rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.diff-panel-head button{font-size:1.1rem;line-height:1;color:var(--faint);
  background:transparent;border:none;cursor:pointer;padding:2px 6px}
.diff-panel-head button:hover{color:var(--text)}
.diff-panel-body{padding:16px 18px;max-height:320px;overflow-y:auto;
  font-size:.92rem;line-height:1.7;color:var(--text)}
.diff-panel-body ins{background:var(--accent-soft);color:var(--accent);
  text-decoration:none;border-radius:2px;padding:0 2px}
.diff-panel-body del{background:rgba(209,73,91,.12);color:#d1495b;
  text-decoration:line-through;border-radius:2px;padding:0 2px}
.diff-empty{color:var(--faint);font-size:.88rem}

/* Pełne przejęcie stylów Quilla. Wysoka specyficzność (.editor-shell +
   .ql-snow), bo vendorowy quill.snow.css jest zminifikowany i ładowany
   po naszym arkuszu. */
.editor-shell .ql-toolbar.ql-snow{
  border:none;border-bottom:1px solid var(--line);background:var(--surface);
  padding:9px 10px;font-family:var(--sans);
  position:sticky;top:0;z-index:2}
.editor-shell .ql-container.ql-snow{border:none;font-family:var(--sans)}
.editor-shell .ql-editor{font-family:var(--sans);font-size:1rem;line-height:1.75;color:var(--text);
  padding:22px max(24px,calc((100% - var(--measure))/2))}
.editor-shell .ql-editor.ql-blank::before{color:var(--faint);font-style:normal;
  left:max(24px,calc((100% - var(--measure))/2));right:max(24px,calc((100% - var(--measure))/2))}

/* Ikony: vendorowy SVG rysuje się stroke/fill na sztywno w czerni. */
.editor-shell .ql-snow .ql-stroke{stroke:var(--muted);transition:stroke .15s ease}
.editor-shell .ql-snow .ql-fill,
.editor-shell .ql-snow .ql-stroke.ql-fill{fill:var(--muted);transition:fill .15s ease}
.editor-shell .ql-snow .ql-picker{color:var(--muted)}
.editor-shell .ql-snow button{width:30px;height:28px;padding:4px;border-radius:5px;
  transition:background-color .15s ease}
.editor-shell .ql-snow button:hover{background:var(--accent-soft)}
.editor-shell .ql-snow button:hover .ql-stroke{stroke:var(--accent)}
.editor-shell .ql-snow button:hover .ql-fill{fill:var(--accent)}
.editor-shell .ql-snow button.ql-active{background:var(--accent-soft)}
.editor-shell .ql-snow button.ql-active .ql-stroke{stroke:var(--accent)}
.editor-shell .ql-snow button.ql-active .ql-fill{fill:var(--accent)}
/* Separatory między grupami narzędzi zamiast jednego zbitego rzędu ikon. */
.editor-shell .ql-snow .ql-formats{margin-right:9px;padding-right:9px;
  border-right:1px solid var(--line)}
.editor-shell .ql-snow .ql-formats:last-child{border-right:none;margin-right:0;padding-right:0}

/* Rozwijana lista („Normal / Nagłówek”) — domyślnie biała karta. */
.editor-shell .ql-snow .ql-picker-label{border:none;border-radius:5px;padding:0 20px 0 8px;
  transition:background-color .15s ease}
.editor-shell .ql-snow .ql-picker-label:hover{background:var(--accent-soft);color:var(--accent)}
.editor-shell .ql-snow .ql-picker-label:hover .ql-stroke{stroke:var(--accent)}
.editor-shell .ql-snow .ql-picker.ql-expanded .ql-picker-label{color:var(--accent)}
.editor-shell .ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:var(--accent)}
.editor-shell .ql-snow .ql-picker-options{background:var(--surface);border:1px solid var(--line);
  border-radius:7px;padding:5px;box-shadow:0 8px 24px rgba(0,0,0,.18)}
.editor-shell .ql-snow .ql-picker-item{color:var(--muted);border-radius:5px;padding:5px 9px;
  transition:background-color .15s ease,color .15s ease}
.editor-shell .ql-snow .ql-picker-item:hover{background:var(--accent-soft);color:var(--accent)}
.editor-shell .ql-snow .ql-picker-item.ql-selected{color:var(--accent)}

/* Treść w edytorze ma wyglądać zbliżenie do tego, co zobaczy czytelnik. */
.editor-shell .ql-editor h2{font-size:1.35rem;font-weight:600;letter-spacing:-.015em;margin:1.6em 0 .5em}
.editor-shell .ql-editor h3{font-size:1.12rem;font-weight:600;margin:1.4em 0 .45em}
.editor-shell .ql-editor blockquote{border-left:2px solid var(--accent);margin:1.5em 0;
  padding:.2em 0 .2em 1.1em;color:var(--muted);font-style:italic}
.editor-shell .ql-editor pre,.editor-shell .ql-editor code{font-family:var(--mono);font-size:.88em}
.editor-shell .ql-editor code{color:var(--text);background:var(--line-soft);border:1px solid var(--line);border-radius:3px;padding:.08em .3em}
html[data-theme="dark"] .editor-shell .ql-editor code{color:#f4f7fb;background:#222b38;border-color:#3a4658}
@media (prefers-color-scheme:dark){html:not([data-theme]) .editor-shell .ql-editor code{color:#f4f7fb;background:#222b38;border-color:#3a4658}}
.editor-shell .ql-editor pre.ql-syntax,.editor-shell .ql-editor .ql-code-block-container{
  background:var(--surface);border:1px solid var(--line);border-radius:7px;color:var(--text);padding:14px 16px}
.editor-shell .ql-editor a{color:var(--accent)}
.editor-shell .ql-editor img{border-radius:7px;margin:1em 0}

/* Okienko wstawiania linku. */
.editor-shell .ql-snow .ql-tooltip{background:var(--surface);border:1px solid var(--line);
  border-radius:7px;box-shadow:0 8px 24px rgba(0,0,0,.22);color:var(--text)}
.editor-shell .ql-snow .ql-tooltip input[type=text]{background:var(--bg);border:1px solid var(--line);
  border-radius:5px;color:var(--text);padding:6px 8px}
.editor-shell .ql-snow .ql-tooltip a.ql-action,
.editor-shell .ql-snow .ql-tooltip a.ql-remove{color:var(--accent)}

/* ---------- strona główna: wprowadzenie i pojedyncza kolumna ---------- */
.start-here{padding:28px 0 30px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.start-here .label{font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint)}
.start-here h2{margin:10px 0 0;font-size:1.55rem;letter-spacing:-.025em}
.start-here p{margin:10px 0 0;max-width:620px;color:var(--muted);line-height:1.6}
.start-here a{display:inline-block;margin-top:16px}
.latest-posts{padding-top:52px;scroll-margin-top:80px}
.filter-notice{display:flex;align-items:baseline;justify-content:space-between;gap:18px;padding:16px 0;border-bottom:1px solid var(--line-soft)}
.filter-notice p{margin:0;color:var(--muted)}
.empty{padding:30px 0;color:var(--muted);line-height:1.6}.empty p{margin:0 0 10px}
.about-page{padding-top:76px;max-width:820px}.about-header{max-width:760px;margin-bottom:52px}.about-header h1{margin:0;font-size:clamp(2.2rem,4.8vw,3.5rem);line-height:1.08;letter-spacing:-.04em}.about-header p{margin:22px 0 0;color:var(--muted);font-size:1.15rem;line-height:1.6}.series-empty{padding:16px 18px;border-left:2px solid var(--accent);background:var(--surface);color:var(--muted)}
.series-list{margin:1.25rem 0 0;padding-left:1.35rem}.series-list li{margin:.7rem 0;padding-left:.25rem}.series-list a{font-weight:500}
@media (max-width:720px){.hero{padding:30px 0 28px}.hero-kicker{margin-bottom:16px}.hero h1{font-size:clamp(2.25rem,11vw,3rem)}.hero p{margin-top:16px;font-size:1.04rem}.hero-actions{margin-top:20px}.start-here{padding:20px 0 22px}.start-here h2{font-size:1.45rem}.start-here p{line-height:1.5}.start-here a{margin-top:8px}.latest-posts{padding-top:12px}.filter-notice{align-items:flex-start;flex-direction:column;gap:6px}.about-page{padding-top:48px}.about-header{margin-bottom:36px}}

/* Ta sekcja musi pozostać na końcu arkusza: style panelu są dopisane po
   wcześniejszym bloku mobilnym, więc tutaj świadomie wygrywają kaskadę. */
@media (max-width:720px){
  .admin{padding-top:36px;padding-bottom:72px}
  .admin .toolbar{gap:12px;margin-bottom:20px}
  .table-scroll-hint{display:block;margin:0 0 9px;font-family:var(--mono);font-size:.68rem;line-height:1.45;color:var(--faint)}
  .admin-section--publish{padding:18px}
  .editor-actions{padding:10px}
  .editor-actions .button-like{padding:7px 9px;font-size:.62rem}
  .editor-shell .ql-toolbar.ql-snow{overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}
  .editor-shell .ql-toolbar.ql-snow .ql-formats{display:inline-block;float:none}
  .editor-shell .ql-container{min-height:260px;max-height:58vh}
  .editor-shell .ql-editor{padding:18px}
  .editor-shell .ql-editor.ql-blank::before{left:18px;right:18px}
}
