/*
Theme Name: BOOKFORGE Child
Template: bricks
Description: Motyw potomny Bricks dla BOOKFORGE. Strona główna renderowana przez front-page.php jako samodzielny dokument (celowo z pominięciem buildera Bricks) — patrz docs/WEBSITE_PROGRESS.md.
Version: 3.0.45
*/

/* Zapas czcionki dla Poppins (2026-10-03, PageSpeed CLS 0,127: przyciski hero
   przesuwały się, gdy Poppins podmieniał Arial i tytuł zawijał się inaczej).
   Arial z size-adjust dopasowanym do szerokości Poppins — zmierzone na
   żywych nagłówkach strony (canvas measureText, 77 elementów): Poppins 700 =
   1.074 × Arial, Poppins 400 = 1.1055 × Arial. Wartości ascent/descent/gap
   Poppinsa (1.05 / 0.35 / 0.10) podzielone przez size-adjust. local() działa
   tylko tam, gdzie Arial/Liberation/Arimo istnieje (Windows, Mac, Linux) —
   inaczej wraca do zwykłego fallbacku, bez regresji. Dla wagi 700 MUSZĄ być
   nazwy "... Bold": samo local("Arial") daje Regular (zmierzone: tytuł hero
   przy 412px nadal miał 2 linie zamiast 3 = to samo przesunięcie). Po
   poprawce wysokość tytułu hero w zapasie = wysokość w Poppins (110 px). */
@font-face {
  font-family: "Poppins Fallback";
  src: local("Arial Bold"), local("Arial-BoldMT"), local("Liberation Sans Bold"), local("LiberationSans-Bold"), local("Arimo Bold"), local("Arimo-Bold"), local("Helvetica Bold"), local("Helvetica-Bold");
  font-weight: 700;
  size-adjust: 107.4%;
  ascent-override: 97.8%;
  descent-override: 32.6%;
  line-gap-override: 9.3%;
}
@font-face {
  font-family: "Poppins Fallback";
  src: local("Arial"), local("ArialMT"), local("Liberation Sans"), local("LiberationSans"), local("Arimo"), local("Arimo-Regular"), local("Helvetica");
  font-weight: 400;
  size-adjust: 110.5%;
  ascent-override: 95%;
  descent-override: 31.7%;
  line-gap-override: 9%;
}

/* ==========================================================================
   Tokeny marki — ZATWIERDZONE 2026-08-24, akcent przefarbowany na
   pomarańcz/Miami 2026-09-19 (wyraźna decyzja właściciela: podgląd lokalny
   zaakceptowany, "wgraj to wszędzie gdzie tylko możesz"). Nazwy zmiennych
   (--bf-blue/--bf-indigo/--bf-purple) świadomie NIE zmienione mimo że kolory
   już nie są niebieskie/fioletowe — przemianowanie wymagałoby dotknięcia
   dziesiątek miejsc w całym motywie bez żadnej korzyści; same WARTOŚCI
   propagują się wszędzie przez te tokeny automatycznie. Logo zostaje jak
   było — właściciel mówił o akcentach strony, nie o samym logo. Patrz
   docs/WEBSITE_DESIGN_SYSTEM.md.
   ========================================================================== */
:root {
  --bf-bg-950: #14121f;
  --bf-bg-900: #1a1730;
  --bf-bg-800: #232047;
  --bf-bg-700: #2c2856;

  --bf-text-50: #f5f4fa;
  --bf-text-300: #b8b4cf;
  --bf-text-400: #8f8ab0;

  --bf-blue: #ffb648;
  --bf-indigo: #ff7a45;
  --bf-purple: #ff5f6d;
  --bf-purple-600: #ff6f4d;

  --bf-success: #4a9d6f;
  --bf-danger: #d3563f;

  /* The one deliberate exception to "the palette above is locked" (owner
     approved 2026-08-27, scoped narrowly): a single warm ember accent for
     the pipeline's forge-spark animation only. Not a palette change — every
     other color on the site stays exactly as approved 2026-08-24. Do not
     reuse this outside .bf-feature-flow--pipeline without asking first. */
  --bf-ember: #e8a85a;

  --bf-gradient-brand: linear-gradient(135deg, var(--bf-blue) 0%, var(--bf-indigo) 55%, var(--bf-purple) 100%);

  --bf-font-display: "Poppins", "Poppins Fallback", "Segoe UI", Arial, sans-serif;
  --bf-font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;

  --bf-radius: 16px;
  --bf-container: 1120px;

  --bf-ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ==========================================================================
   Reset / base
   ========================================================================== */
.bf-page, .bf-page * , .bf-page *::before, .bf-page *::after {
  box-sizing: border-box;
}

/* Global safety net (2026-08-28 bug fix) — any element toggled via the
   native `hidden` attribute (JS: el.hidden = true/false) must actually stay
   hidden even when it also carries a class that sets its own `display`.
   Without this, an author rule like ".foo { display: flex }" always beats
   the browser's own "[hidden] { display: none }" default at equal
   specificity (author origin wins over user-agent origin, regardless of
   source order) — confirmed live: every "⋮" card menu, and the Generator's
   addon price rows, showed permanently and ignored `hidden` entirely. One
   !important here, instead of patching each affected class individually,
   so this can't silently recur the next time someone adds display to a
   class that's also toggled via `hidden`. */
[hidden] { display: none !important; }

.bf-page {
  margin: 0;
  background: var(--bf-bg-950);
  color: var(--bf-text-50);
  font-family: var(--bf-font-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Desktop-only 80% scale (2026-09-20, owner: "strona najlepiej wygląda jak
   jest zmniejszona do 80%" — live-tested via browser zoom, confirmed it
   reads tighter/more premium, not just "smaller"). Every size in this
   stylesheet is hardcoded px, not rem — there's no root font-size lever
   that would cleanly rescale the whole design system, and hand-editing
   every font-size/padding value across the theme days before launch is
   its own risk. `zoom` (not `transform:scale`) reflows layout exactly like
   real browser zoom does, so it doesn't leave extra scroll space the way
   transform would. Scoped to min-width:1024px only — mobile/tablet already
   have their own separately-tuned compact sizes throughout this file;
   zooming those down further was never tested and risks touch targets
   getting too small. Un-supporting browsers just ignore `zoom` and render
   at 100% — same as today, not broken. */
@media (min-width: 1024px) {
  .bf-page { zoom: 0.8; }
}

.bf-page img { max-width: 100%; display: block; }
.bf-page a { color: inherit; text-decoration: none; }

.bf-page ::selection { background: var(--bf-indigo); color: #fff; }
.bf-page :focus-visible { outline: 2px solid var(--bf-indigo); outline-offset: 2px; }

/* Document scrollbar — targets html (the actual scrolling box), not .bf-page
   itself, which would only style scrollbars on elements INSIDE the body. */
html { scrollbar-color: var(--bf-indigo) var(--bf-bg-900); scrollbar-width: thin; }
html::-webkit-scrollbar { width: 10px; height: 10px; }
html::-webkit-scrollbar-track { background: var(--bf-bg-900); }
html::-webkit-scrollbar-thumb { background: var(--bf-indigo); border-radius: 10px; }
html::-webkit-scrollbar-thumb:hover { background: var(--bf-purple); }

/* ==========================================================================
   Visual Upgrade V2 (2026-08-25) — motion, depth, premium polish.
   Scroll-reveal + everything below respects prefers-reduced-motion: content
   is always in its final, visible state by default; JS only ever ADDS the
   reveal effect for users who haven't asked to avoid motion (see
   assets/js/scroll-reveal.js, which checks the same media query before
   attaching anything).
   ========================================================================== */
/* Scoped under html.js (set by a tiny inline script in wp_head, functions.php)
   so content NEVER depends on JS to become visible — without JS (or if it
   fails/is blocked), .bf-reveal elements simply render normally, no hidden
   state to get stuck in. */
html.js .bf-reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.7s var(--bf-ease), transform 0.7s var(--bf-ease);
}
/* Must be at least as specific as the hiding rule above (html + 2 classes) —
   plain ".bf-reveal.is-visible" (2 classes, no element) previously LOST to
   "html.js .bf-reveal" in the cascade despite coming later in the file, so
   the class was being added by JS correctly but never actually took visual
   effect. This is the real bug behind "text disappeared" (2026-08-25). */
html.js .bf-reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.js .bf-reveal { opacity: 1; transform: none; transition: none; }
}

/* Subtle film-grain texture over the whole page — inline SVG noise filter,
   no image request, no library. Kept very low-opacity on purpose (premium
   depth cue, not a visible pattern) per the "subtle, not chaotic" brief. */
.bf-page { position: relative; }
.bf-page::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Shrink-on-scroll (2026-09-02 rebuild) — .bf-header__inner's HEIGHT used to
   change here (92/128px -> 68px), which is exactly what caused the reported
   "skakanie": .bf-header is `position: sticky` (see its own rule below), so
   it still occupies real space in the document flow, and shrinking that
   flow height the instant .is-scrolled toggled yanked the header (logo,
   nav) and every bit of page content below it upward by the height delta —
   a real layout shift, not just a visual animation. Fixed at the source:
   .bf-header__inner's height is now constant at every scroll position (see
   its own rule below, no .is-scrolled override left) — only the LOGO IMAGE
   shrinks, via its own height + transition. Flexbox's align-items:center on
   .bf-header__inner recenters the smaller logo automatically within the
   same fixed-height row, so nothing else moves. */
.bf-header { transition: background 0.3s var(--bf-ease); }

/* Decorative blurred glow orbs — drop into any position:relative section to
   add depth behind flat-color content without competing with photos (the
   hero keeps its own real image untouched; orbs are for the plain-color
   sections around it). */
.bf-glow-orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.25;
  pointer-events: none;
  z-index: 0;
  animation: bf-orb-drift 16s ease-in-out infinite alternate;
}
.bf-glow-orb--indigo { background: var(--bf-indigo); }
.bf-glow-orb--blue { background: var(--bf-blue); }
@keyframes bf-orb-drift {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(24px, -18px) scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
  .bf-glow-orb { animation: none; }
}

/* Merged pipeline section ("Od pomysłu do gotowego produktu") — reuses
   .bf-feature-flow's card/icon/arrow language at 6 items instead of 4,
   wrapped 3-per-row on desktop (arrows only between horizontally adjacent
   steps, not across the row wrap). */
@media (min-width: 860px) {
  /* Flexbox, not grid — a 3-column grid leaves the leftover 6th-item row
     stuck against the left edge when it doesn't fill all 3 columns; flex
     with justify-content:center centers an incomplete last row instead.
     Selector is the TWO classes chained on one compound selector
     (.bf-feature-flow.bf-feature-flow--pipeline), not ".bf-feature-flow--pipeline"
     alone — that alone has the SAME specificity as the plain ".bf-feature-flow"
     base rule below, and whichever of the two sits later in the file wins
     regardless of this media query matching. This exact mistake shipped
     twice already today (2026-08-26); chaining classes is the fix that
     survives future reordering, not moving rules around by hand again. */
  .bf-feature-flow.bf-feature-flow--pipeline {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 56px;
    column-gap: 40px;
  }
  .bf-feature-flow--pipeline .bf-feature-flow__item {
    flex: 0 0 calc((100% - 80px) / 3);
    max-width: calc((100% - 80px) / 3);
  }
  .bf-feature-flow--pipeline .bf-feature-flow__item::after { content: none; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:not(:nth-child(3n))::after {
    content: "→";
    position: absolute;
    top: 28px;
    right: -30px;
    transform: translateY(-50%);
    font-size: 20px;
    color: var(--bf-indigo);
    animation: bf-forge-arrow-pulse 4.8s ease-in-out infinite;
  }

  /* Forge spark (2026-08-27): a warm glow travels icon-by-icon through the
     pipeline, arrows briefly lighting up ember as the "spark" crosses them
     — a nod to BOOKFORGE's own name. Lives on .bf-feature-flow__icon::after
     (a separate layer), NOT on .bf-feature-flow__icon's own box-shadow —
     that property is already owned by the existing :hover glow
     (.bf-feature-flow__item:hover .bf-feature-flow__icon), and a running
     CSS animation always wins the cascade over an author :hover rule for
     the same property, which would have silently broken hover for as long
     as this animation runs (i.e. permanently). Six icons over one 4.8s
     loop = 0.8s apart; arrow delays sit halfway between the icons they
     connect so the glow visibly travels rather than jumping. */
  .bf-feature-flow--pipeline .bf-feature-flow__icon::after {
    content: "";
    position: absolute;
    inset: -6px;
    border-radius: 50%;
    pointer-events: none;
    animation: bf-forge-pulse 4.8s ease-in-out infinite;
  }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(1) .bf-feature-flow__icon::after { animation-delay: 0s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(2) .bf-feature-flow__icon::after { animation-delay: 0.8s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(3) .bf-feature-flow__icon::after { animation-delay: 1.6s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(4) .bf-feature-flow__icon::after { animation-delay: 2.4s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(5) .bf-feature-flow__icon::after { animation-delay: 3.2s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(6) .bf-feature-flow__icon::after { animation-delay: 4.0s; }

  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(1)::after { animation-delay: 0.4s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(2)::after { animation-delay: 1.2s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(4)::after { animation-delay: 2.8s; }
  .bf-feature-flow--pipeline .bf-feature-flow__item:nth-child(5)::after { animation-delay: 3.6s; }
}

@keyframes bf-forge-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(232, 168, 90, 0); }
  4% { box-shadow: 0 0 4px 2px rgba(232, 168, 90, 0.3); }
  8% { box-shadow: 0 0 22px 6px rgba(232, 168, 90, 0.7); }
  16% { box-shadow: 0 0 4px 2px rgba(232, 168, 90, 0.15); }
  22%, 100% { box-shadow: 0 0 0 0 rgba(232, 168, 90, 0); }
}
@keyframes bf-forge-arrow-pulse {
  0%, 100% { color: var(--bf-indigo); }
  50% { color: var(--bf-ember); }
}
@media (prefers-reduced-motion: reduce) {
  .bf-feature-flow--pipeline .bf-feature-flow__icon::after,
  .bf-feature-flow--pipeline .bf-feature-flow__item::after {
    animation: none;
  }
}
.bf-feature-flow__step { font-size: 12px; font-weight: 700; color: var(--bf-text-400); letter-spacing: 0.05em; margin-bottom: 6px; }

/* BOOKFORGE Studio — an honest illustration of the pipeline stages as a
   mini "product interface" card. Checkmarks only, deliberately no invented
   quality score or numeric stat (see docs/WEBSITE_PROGRESS.md — the real
   Quality Engine doesn't exist yet, so no real number could ever back one). */
.bf-studio-card {
  position: relative;
  z-index: 1;
  max-width: 420px;
  margin: 48px auto 0;
  background: linear-gradient(160deg, rgba(255, 122, 69, 0.14), rgba(20, 18, 31, 0.5));
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 20px;
  padding: 28px 32px;
  box-shadow: 0 30px 80px -30px rgba(255, 122, 69, 0.35);
}
.bf-studio-card__title {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bf-text-400);
  margin-bottom: 18px;
}
.bf-studio-card__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 11px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 14px;
}
.bf-studio-card__row:last-of-type { border-bottom: none; }
.bf-studio-card__row-label { display: flex; align-items: center; gap: 10px; }
.bf-studio-card__row-icon { width: 18px; height: 18px; flex: none; color: var(--bf-indigo); }
.bf-studio-card__check { color: var(--bf-success); font-weight: 700; }
.bf-studio-card__status {
  margin-top: 20px;
  text-align: center;
  padding: 12px;
  border-radius: 10px;
  background: rgba(74, 157, 111, 0.12);
  color: var(--bf-success);
  font-weight: 700;
  letter-spacing: 0.06em;
  font-size: 13px;
}
.bf-page h1, .bf-page h2, .bf-page h3 {
  font-family: var(--bf-font-display);
  margin: 0;
  color: var(--bf-text-50);
  letter-spacing: -0.01em;
}

.bf-container {
  width: 100%;
  max-width: var(--bf-container);
  margin: 0 auto;
  padding: 0 24px;
}

/* Base brand gradient + a second, brighter "highlight band" layer on top
   (multiple backgrounds — first-listed paints on top), both clipped to the
   text shape together. Animating only the highlight layer's position
   sweeps a shimmer across the letters every few seconds; the base gradient
   underneath never moves, so the text's actual color never shifts. The
   sweep's start/end positions sit fully outside the 0–100% text width, so
   the animation loop's reset is invisible — nothing is on-screen at either
   end, only during the transit through the middle. */
.bf-gradient-text {
  background:
    linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, 0.6) 47%, rgba(255, 255, 255, 0.6) 53%, transparent 70%),
    var(--bf-gradient-brand);
  background-size: 250% 100%, 100% 100%;
  background-repeat: no-repeat;
  background-position: -150% 0, 0 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: bf-gradient-shimmer 5s ease-in-out infinite;
}
@keyframes bf-gradient-shimmer {
  0% { background-position: -150% 0, 0 0; }
  100% { background-position: 250% 0, 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .bf-gradient-text { animation: none; }
}

/* ==========================================================================
   Buttons
   ========================================================================== */
.bf-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 15px;
  padding: 12px 24px;
  transition: transform 0.15s ease, opacity 0.15s ease;
  border: 1px solid transparent;
  cursor: pointer;
}
.bf-btn:hover { transform: translateY(-1px); }

.bf-btn--primary {
  background: var(--bf-gradient-brand);
  color: var(--bf-bg-950);
}
.bf-btn--primary:hover { opacity: 0.92; }

.bf-btn--secondary {
  background: transparent;
  border-color: var(--bf-bg-700);
  color: var(--bf-text-50);
}
.bf-btn--secondary:hover { border-color: var(--bf-indigo); }

.bf-btn--lg { padding: 15px 30px; font-size: 16px; }
.bf-btn--block { width: 100%; margin-top: 24px; }

/* ==========================================================================
   Header
   ========================================================================== */
.bf-header {
  position: sticky;
  top: 0;
  z-index: 50;
  /* 0.85 alpha + blur(10px) let scrolled-under text "ghost" through the
     header for the first ~40px of scroll (before JS adds .is-scrolled below)
     — most visible on mobile now that the hero title is 3 lines tall right
     under the header. Opaque enough on its own now that .is-scrolled is just
     a slightly darker shade for visual polish, not the thing preventing
     ghosting. */
  background: rgba(20, 18, 31, 0.97);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

/* WP admin toolbar offset rules removed 2026-08-30 — the toolbar itself is
   now hidden sitewide (show_admin_bar filter, inc/auth.php; owner: "ten
   pasek wordpress trzeba usunąć"), so body.admin-bar never applies to any
   BOOKFORGE page anymore and these would be permanently-dead CSS. */

.bf-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Constant at every scroll position — this height participates in real
     page layout (.bf-header is sticky, not fixed), so it must never change
     after scroll or every bit of content below jumps with it. */
  height: 92px;
  gap: 24px;
}

@media (min-width: 640px) {
  .bf-header__inner { height: 128px; }
}

/* flex-shrink:0 (2026-09-21, owner: "loga w ogóle nie widać" na mobile
   zalogowany) — .bf-logo is a flex child of .bf-header__inner alongside
   .bf-header__actions. An <img> is a replaced element, so flexbox's
   automatic minimum-size rule lets it shrink toward 0 width even with no
   explicit flex-shrink set, while the text/button content next to it
   (Wyloguj, credit badge) has real min-content and resists shrinking —
   so on a narrow logged-in mobile header (social icon + credit badge +
   Wyloguj + hamburger all competing for the same row) ALL the necessary
   squeeze landed on the logo alone. Live-measured before this fix:
   logo rendered at width:0 (height still 64px) — completely invisible,
   not just small. See also the credit-badge hide rule below, which
   removes enough width that the logo no longer needs to fight for room
   at all. */
.bf-logo { flex-shrink: 0; }
.bf-logo img {
  height: 64px;
  width: auto;
  transition: height 0.3s var(--bf-ease);
}
/* The actual "shrink" cue on scroll (2026-09-02) — only the logo image
   scales down; .bf-header__inner's own height (above) never moves, so this
   never shifts the header's box or anything on the page below it, just
   recenters within the same fixed-height row via align-items:center. */
.bf-header.is-scrolled .bf-logo img { height: 48px; }

@media (min-width: 640px) {
  .bf-logo img { height: 88px; }
  .bf-header.is-scrolled .bf-logo img { height: 64px; }
}

.bf-nav { display: none; align-items: center; gap: 32px; }
.bf-nav a {
  position: relative;
  font-size: 15px;
  font-weight: 500;
  color: var(--bf-text-50);
  opacity: 0.75;
  padding-bottom: 4px;
}
.bf-nav a:hover { opacity: 1; }
.bf-nav a.is-active {
  opacity: 1;
  color: var(--bf-blue);
}
.bf-nav a.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  border-radius: 999px;
  background: var(--bf-gradient-brand);
}

.bf-header__actions { display: flex; align-items: center; gap: 12px; }
.bf-header__actions .bf-header__login-link { display: none; }

@media (min-width: 480px) {
  .bf-header__actions .bf-header__login-link { display: inline-flex; }
}

.bf-header__actions .bf-btn {
  padding: 10px 16px;
  font-size: 14px;
}

@media (min-width: 860px) {
  .bf-nav { display: flex; }
}

/* Mobile nav toggle + dropdown (2026-08-29) — same 3-span hamburger as the
   account sidebar's own toggle (.bf-account-menu-toggle), so the two never
   look like two different components doing the same job. Hidden entirely
   at the breakpoint where .bf-nav itself becomes visible — there is
   nothing left for it to reveal above 860px. */
.bf-header__menu-toggle {
  width: 40px;
  height: 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  flex: none;
}
.bf-header__menu-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--bf-text-50);
  border-radius: 2px;
}
@media (min-width: 860px) {
  .bf-header__menu-toggle { display: none; }
}

.bf-mobile-nav {
  display: none;
  flex-direction: column;
  gap: 4px;
  padding: 4px 24px 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.bf-mobile-nav.is-open { display: flex; }
.bf-mobile-nav a:not(.bf-btn) {
  padding: 12px 4px;
  font-size: 15px;
  font-weight: 500;
  color: var(--bf-text-50);
  opacity: 0.85;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.bf-mobile-nav a.is-active { opacity: 1; color: var(--bf-blue); }
.bf-mobile-nav .bf-btn--block { margin-top: 12px; }
.bf-mobile-nav .bf-mobile-nav__form { margin: 12px 0 0; }
.bf-mobile-nav .bf-mobile-nav__form .bf-btn--block { margin-top: 0; }
@media (min-width: 860px) {
  .bf-mobile-nav { display: none !important; }
}

/* ==========================================================================
   Hero
   ========================================================================== */
.bf-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid rgba(255, 95, 109, 0.4);
  background: rgba(255, 122, 69, 0.12);
  color: var(--bf-blue);
  font-size: 12px;
  font-weight: 600;
  padding: 6px 14px;
  border-radius: 999px;
}

/* Plakietka "NOWOŚĆ" na slajdzie hero "Opublikuj swój ebook" (2026-09-19,
   owner: "ma się rzucać w oczy" — pierwsza, mała wersja uznana za
   niewidoczną, ta jest świadomie duża i mocna, jak naklejka promocyjna, nie
   subtelny badge). Świadomie CZERWONA (--bf-danger), nie pomarańczowa jak
   reszta akcentów strony po zmianie palety — kontrast z otoczeniem jest tu
   celem. display:flex (nie inline-flex) + width:max-content, żeby zawsze
   lądowała na WŁASNEJ linii nad .bf-badge poniżej. */
.bf-badge-new-pulse {
  display: flex;
  width: max-content;
  align-items: center;
  gap: 8px;
  background: var(--bf-danger);
  color: #fff;
  font-size: 22px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 14px 32px;
  border-radius: 999px;
  margin-bottom: 18px;
  transform: rotate(-3deg);
  box-shadow: 0 12px 30px -8px rgba(211, 86, 63, 0.7);
  animation: bf-badge-new-pulse 1.6s ease-in-out infinite;
}
@keyframes bf-badge-new-pulse {
  0%, 100% { transform: rotate(-3deg) scale(1); box-shadow: 0 12px 30px -8px rgba(211, 86, 63, 0.7), 0 0 0 0 rgba(211, 86, 63, 0.55); }
  50% { transform: rotate(-3deg) scale(1.08); box-shadow: 0 16px 38px -8px rgba(211, 86, 63, 0.8), 0 0 0 16px rgba(211, 86, 63, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .bf-badge-new-pulse { animation: none; }
}
@media (max-width: 640px) {
  .bf-badge-new-pulse { font-size: 16px; padding: 10px 22px; }
}

/* Score "Znajdź pomysł" (2026-09-17, owner request) — potencjal sprzedazowy
   1-100 zwracany przez BOOKFORGE_TOPIC_IDEAS_ENGINE. Reuzywa ksztalt .bf-badge,
   tylko kolor niesie znaczenie (semantyczny, nie akcent marki) - wysoki wynik
   zielony (--bf-success), niski przygaszony czerwony (--bf-danger), srodek
   zostaje domyslnym fioletem .bf-badge. */
.bf-score-badge--high { border-color: rgba(74, 157, 111, 0.4); background: rgba(74, 157, 111, 0.14); color: var(--bf-success); }
.bf-score-badge--low { border-color: rgba(211, 86, 63, 0.35); background: rgba(211, 86, 63, 0.1); color: var(--bf-danger); }

/* Saldo kredytu BOOKForge w nagłówku (2026-09-16) — .bf-badge daje kształt/
   kolor, tu tylko dopinam rozmiar ikony (surowe <svg> bez width/height
   renderuje się domyślnie ogromne) i usuwam podkreślenie linku. */
.bf-header__credit-badge {
  text-decoration: none;
  white-space: nowrap;
}
.bf-header__credit-badge svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

/* Hide the top-row credit badge below 860px (2026-09-21, same fix as
   .bf-logo's flex-shrink:0 above) — same breakpoint as the .bf-nav/
   hamburger swap just below, so this only ever disappears exactly where
   the compact mobile header takes over. Scoped to .bf-header__actions
   specifically — template-parts/site-header.php renders this exact same
   badge markup a SECOND time inside .bf-mobile-nav (the hamburger
   dropdown) for logged-in users, so the balance is still one tap away,
   never actually removed, just not fighting the logo for room in the
   36px-tall top row on a phone. */
@media (max-width: 859px) {
  .bf-header__actions .bf-header__credit-badge { display: none; }
}

/* --bf-hero-photo / --bf-hero-photo-desktop are set inline per-request
   (front-page.php, since the URLs come from PHP) — this swaps which one
   actually paints at the same 720px breakpoint as everything else here.
   Mobile/tablet: a separate, portrait-composed image with the subject
   centered (2026-08-31) — the wide desktop banner below forced `cover` to
   blow it up so much on a narrow, tall mobile hero that only a random,
   heavily-cropped sliver of it was ever visible (confirmed live via owner
   screenshots), because that image deliberately keeps its left half empty
   for desktop text and its subject in the right ~45%. */
.bf-hero {
  position: relative;
  /* padding-bottom was 420px (sized for the old `cover` behavior, which
     needed a big reserved zone for the image to fill edge-to-edge).
     2026-09-21, owner: "trzeba coś zrobić z tą przestrzenią tylko na
     mobile" — now that the photo layer uses `contain` anchored to `top`
     (see the position comment below), the image's own displayed height
     already determines how much room it needs; the old 420px just left
     a large empty gap of pure background color under it before the next
     section. Live-measured: 48px keeps a bit of breathing room without
     the dead space (at this padding, .bf-hero's box height and the
     `contain` image's natural width-bound height come out almost equal,
     so there's barely any letterbox left over to sit empty). Desktop
     padding-bottom (32px, in the @media block below) was never part of
     this problem — different composition, not touched. */
  padding: 56px 0 48px;
  background-color: var(--bf-bg-950);
  background-repeat: no-repeat;
  background-image:
    radial-gradient(55% 70% at 8% 15%, rgba(20, 18, 31, 0.85) 0%, rgba(20, 18, 31, 0.55) 45%, rgba(20, 18, 31, 0.05) 75%),
    linear-gradient(180deg, rgba(20, 18, 31, 0.2) 0%, rgba(20, 18, 31, 0.9) 100%),
    var(--bf-hero-photo);
  /* right center, not center center (2026-08-31 live pixel-check) — the
     mobile artwork's PDF/DOCX/EPUB icons sit right at its own right edge
     (measured: ~0.1% margin), so even `cover`'s small, mathematically-
     correct crop on a narrow phone clipped them. Anchoring right instead
     crops entirely from the LEFT (the decorative empty portal/stairs area),
     keeping the book+anvil+icons — the actual subject — fully intact. */
  /* `cover` → `contain` on the photo layer (2026-09-19, owner: "zmieszczenie
     całej grafiki w hero" — noticed real cropping). The mobile artwork is a
     tall 0.46 ratio (853×1844) portrait; .bf-hero's own box ratio varies by
     device/content height and is NEVER that tall-and-narrow, so `cover`
     scaled the image up to fill height and sliced off its sides — exactly
     the crop the 2026-08-31 fix above was trying to avoid, `cover` just
     couldn't fully solve it. `contain` guarantees the whole image is always
     visible; the two gradient layers above still paint at 100%/100% so any
     letterboxed space reads as more moody background, not empty gaps. */
  /* Photo layer's vertical anchor: `top`, not `center` (2026-09-21, owner:
     "obraz hero nadal za nisko" on mobile). .bf-hero's own box is very
     tall on mobile — padding-bottom:420px plus a multi-line title/lead
     stacks up to 1000px+ before the box even ends — and with `contain`
     centering the image vertically in THAT WHOLE box put its top edge
     ~150px down and its visible subject mostly below the fold on a real
     phone viewport (shorter than what this was tested against on
     2026-08-31, before `contain` existed). Anchoring to `top` instead
     means the image starts immediately below the header, so the anvil/
     hammer/format icons are visible in the first screen without
     scrolling; the leftover `contain` letterbox space (image is narrower
     than the box is tall) now lands entirely in the padding-bottom zone
     at the BOTTOM, which is exactly where it was always meant to be
     empty. Desktop keeps `center` below — different composition
     (landscape, subject in the right ~45%), not reported as an issue. */
  background-position: center 90px, center, center top;
  background-size: 100% 100%, 100% 100%, contain;
  overflow: hidden;
}

@media (min-width: 720px) {
  .bf-hero {
    padding: 72px 0 32px;
    /* This hero image (2026-08-25) was purpose-designed at a ~3:1 canvas
       (2000×667) with the laptop/book/icons kept in the right ~45% and the
       left ~55% left empty for text. `cover` anchored right worked cleanly
       ONLY when .bf-hero's own box happened to be close to 3:1 too — on
       narrower/taller desktop windows the box is far more square, so
       `cover` scaled the image up to fill height and cropped its sides
       (2026-09-19, owner: "zmieszczenie całej grafiki w hero"). `contain`
       below always shows the full image regardless of the box's ratio. */
    background-image:
      radial-gradient(55% 70% at 8% 15%, rgba(20, 18, 31, 0.85) 0%, rgba(20, 18, 31, 0.55) 45%, rgba(20, 18, 31, 0.05) 75%),
      linear-gradient(180deg, rgba(20, 18, 31, 0.2) 0%, rgba(20, 18, 31, 0.9) 100%),
      var(--bf-hero-photo-desktop);
    background-position: center 90px, center, right center;
    background-size: 100% 100%, 100% 100%, contain;
  }
}

.bf-hero__title {
  margin-top: 20px;
  font-size: 40px;
  line-height: 1.14;
  max-width: 460px;
}

/* 40px reads oversized on real phones (owner screenshot, 2026-08-31) — with
   the longer "...ebooka lub książki" heading it wraps to 3 huge lines and
   dominates the whole first screen. Scale it down specifically on narrow
   phones; tablets (600-719px) keep the 40px size from the base rule above. */
@media (max-width: 599px) {
  .bf-hero__title { font-size: 30px; line-height: 1.22; margin-top: 14px; }
  .bf-hero__lead { margin-top: 14px; font-size: 15.5px; }
  .bf-hero__actions { margin-top: 22px; }
}

.bf-hero__lead {
  margin-top: 20px;
  max-width: 480px;
  color: var(--bf-text-300);
  font-size: 17px;
  line-height: 1.6;
}

.bf-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 32px;
}

.bf-formats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 28px;
}

.bf-formats__label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--bf-text-400);
}

.bf-format-badge {
  display: inline-flex;
  align-items: center;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  border-radius: 8px;
  padding: 5px 11px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--bf-text-300);
}

/* SEO tag badges (2026-09-16) — clickable, unlike the static .bf-format-badge
   they're visually based on, so they get a hover state and no letter-spacing
   (tag phrases read better without it). */
.bf-tag-badges { display: flex; flex-wrap: wrap; gap: 8px; }
.bf-tag-badge {
  display: inline-flex;
  align-items: center;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  border-radius: 8px;
  padding: 5px 11px;
  font-size: 12px;
  font-weight: 600;
  color: var(--bf-text-300);
  text-decoration: none;
  transition: border-color 0.2s, color 0.2s;
}
.bf-tag-badge:hover { border-color: var(--bf-indigo); color: var(--bf-text-50); }
.bf-tag-badge.is-active { border-color: var(--bf-indigo); background: rgba(255, 122, 69, 0.16); color: var(--bf-text-50); }

/* "Znajdź pomysł" category picker (2026-09-16, Feature 8). Redesigned
   2026-09-19 — owner: 24 identical flat pills in one unbroken column read
   as a "wall of buttons", "trzeba uporządkować". Each group now sits in
   its own card (matches the card language used everywhere else on the
   site) with an icon next to its label, instead of one long flat list. */
.bf-idea-categories { display: flex; flex-direction: column; gap: 14px; }
.bf-idea-categories__group {
  background: var(--bf-bg-900);
  border: 1px solid var(--bf-bg-700);
  border-radius: var(--bf-radius);
  padding: 18px 20px;
}
.bf-idea-categories__group-label { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; letter-spacing: 0.02em; text-transform: none; color: var(--bf-text-300); margin-bottom: 12px; }
.bf-idea-categories__group-icon { font-size: 16px; line-height: 1; }
.bf-idea-categories__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.bf-idea-category-btn.is-active { border-color: var(--bf-indigo); background: rgba(255, 122, 69, 0.16); color: var(--bf-text-50); }

/* "Pokaż inne pomysły" — deliberately its OWN style, not .bf-btn--secondary
   (that class is shared with the 24 plain category chips above; reusing it
   here made this actual action button disappear right next to the
   gradient "Stwórz ten ebook" CTAs on the cards above it — owner: "ten
   przycisk jest chujowy"). Gradient border via the double-background/
   background-clip trick — a filled gradient like the primary CTA would
   outrank "Stwórz ten ebook", which is the one action that should win. */
.bf-idea-refresh-wrap { text-align: center; margin-top: 28px; }
.bf-idea-refresh-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 28px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 15px;
  color: var(--bf-text-50);
  border: 1px solid transparent;
  background-image: linear-gradient(var(--bf-bg-900), var(--bf-bg-900)), var(--bf-gradient-brand);
  background-origin: border-box;
  background-clip: padding-box, border-box;
  cursor: pointer;
  transition: transform 0.15s ease, background-image 0.15s ease;
}
.bf-idea-refresh-btn:hover { transform: translateY(-1px); background-image: linear-gradient(rgba(255,122,69,0.14), rgba(255,122,69,0.14)), var(--bf-gradient-brand); }

/* Marketing Pack sections (2026-09-16, Feature 4) */
.bf-marketing-pack__sections { display: flex; flex-direction: column; gap: 14px; }
.bf-marketing-pack__section { border: 1px solid rgba(255, 255, 255, 0.08); border-radius: var(--bf-radius); padding: 14px 16px; background: rgba(255, 255, 255, 0.02); }
.bf-marketing-pack__toggle { display: flex; align-items: center; gap: 8px; font-weight: 700; cursor: pointer; }
.bf-marketing-pack__body { margin-top: 10px; }
.bf-marketing-pack__body ul { margin: 0 0 10px; padding-left: 18px; color: var(--bf-text-300); font-size: 13.5px; line-height: 1.6; }
.bf-marketing-pack__body p { margin: 0 0 10px; color: var(--bf-text-300); font-size: 13.5px; line-height: 1.6; white-space: pre-wrap; }

/* Marketing Pack cards (2026-09-24) — posts / captions / Meta ads are
   standalone multi-paragraph texts published one at a time, so each gets its
   own card and its own "Kopiuj" instead of one bullet list copied as a blob. */
.bf-marketing-pack__count {
	margin-left: auto;
	min-width: 26px;
	padding: 2px 8px;
	border-radius: 999px;
	background: rgba(124, 92, 255, 0.18);
	color: var(--bf-text-200, #d9d6ea);
	font-size: 12px;
	font-weight: 600;
	text-align: center;
}
.bf-mp-cards {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
	gap: 12px;
}
.bf-mp-card {
	display: flex;
	flex-direction: column;
	border: 1px solid rgba(255, 255, 255, 0.09);
	border-radius: var(--bf-radius);
	background: linear-gradient(160deg, rgba(124, 92, 255, 0.07), rgba(255, 255, 255, 0.015) 55%);
	padding: 14px 16px 16px;
	transition: border-color 0.2s ease;
}
.bf-mp-card:hover { border-color: rgba(124, 92, 255, 0.45); }
.bf-mp-card__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	margin-bottom: 10px;
	padding-bottom: 10px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.07);
	font-size: 11.5px;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--bf-text-400);
}
.bf-mp-card__head .bf-marketing-pack__copy { padding: 6px 14px; font-size: 12.5px; }
.bf-mp-card__text {
	color: var(--bf-text-200, #d9d6ea);
	font-size: 14px;
	line-height: 1.65;
	white-space: pre-wrap;
	overflow-wrap: anywhere;
}
.bf-mp-tags span {
	display: inline-block;
	margin: 0 6px 6px 0;
	padding: 4px 10px;
	border-radius: 999px;
	background: rgba(124, 92, 255, 0.14);
	color: var(--bf-text-200, #d9d6ea);
}

@media (min-width: 720px) {
  .bf-hero__title { font-size: 48px; max-width: 560px; }
}

/* Hero copy carousel (2026-09-12, owner: hero only ever advertised the
   topic-based Generator, "Z własnego materiału" had zero visibility above
   the fold) — CSS grid crossfade, NOT a hard side-by-side flex slide.
   First attempt used a flex track translateX'd 0/-100% — looked broken in
   testing: mid-transition, both full-opacity slides are simultaneously
   partially visible with raw, legible-but-cut-off text overlapping (a
   screenshot or even a quick glance mid-animation reads as garbled/broken,
   confirmed live on bookforge.pl, 2026-09-12). All slides share the same
   grid cell (grid-area 1/1) — the grid container auto-sizes to the tallest
   slide's natural height, no absolute-positioning/height juggling needed.
   `.is-active` fades a slide in with a small translateX(0) settle;
   `.is-leaving` (added by JS for one transition-length, then removed)
   fades the outgoing slide out to the left — so it still visually "slides
   out left / next enters from the right", just via opacity+transform on
   each slide independently rather than dragging raw text across the other
   slide's space. Background artwork is untouched — only this text column
   rotates. First slide ships with `is-active` server-side (no FOUC / works
   before JS runs); JS only ever toggles classes, never inline transforms. */
.bf-hero__slider { display: grid; }
.bf-hero__slide {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateX(28px);
  transition: opacity 0.6s var(--bf-ease), transform 0.6s var(--bf-ease);
  pointer-events: none;
}
.bf-hero__slide.is-active {
  opacity: 1;
  transform: translateX(0);
  pointer-events: auto;
}
.bf-hero__slide.is-leaving {
  opacity: 0;
  transform: translateX(-28px);
}
.bf-hero__dots { display: flex; gap: 8px; margin-top: 32px; }
/* Kropki są teraz <button> (2026-09-19, były dekoracyjnymi <span>, stąd
   klikanie "nic nie robiło" — owner zgłosił). Reset domyślnego wyglądu
   przycisku (ramka/padding/tło), reszta wyglądu bez zmian. */
.bf-hero__dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
  cursor: pointer;
  transition: background 0.3s var(--bf-ease), transform 0.3s var(--bf-ease);
}
.bf-hero__dot:hover { background: rgba(255, 255, 255, 0.45); }
.bf-hero__dot.is-active { background: var(--bf-gradient-brand); transform: scale(1.3); }

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

/* Top-of-page loading bar (assets/js/site.js, 2026-08-27) — element is
   created by JS, not present in any template's markup. z-index above the
   sticky .bf-header (40) so it's visible even when the header is pinned. */
.bf-loading-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0%;
  background: var(--bf-gradient-brand);
  z-index: 200;
  opacity: 0;
  transition: width 0.3s var(--bf-ease), opacity 0.3s var(--bf-ease);
  pointer-events: none;
}
.bf-loading-bar.is-active { opacity: 1; }

/* ==========================================================================
   Sections / cards
   ========================================================================== */
.bf-section { padding: 64px 0; }
.bf-section--alt { background: var(--bf-bg-900); border-top: 1px solid rgba(255,255,255,0.05); border-bottom: 1px solid rgba(255,255,255,0.05); }

.bf-section__heading { max-width: 640px; margin: 0 auto; text-align: center; }

.bf-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 12px;
  font-weight: 600;
  color: var(--bf-purple);
  margin: 0 0 12px;
}

.bf-section__heading h2 { font-size: 30px; }

.bf-section__desc {
  margin-top: 16px;
  color: var(--bf-text-300);
  font-size: 16px;
  line-height: 1.6;
}

.bf-grid-3 {
  display: grid;
  gap: 20px;
  margin-top: 48px;
}

@media (min-width: 720px) {
  .bf-grid-3 { grid-template-columns: repeat(3, 1fr); }
  .bf-section__heading h2 { font-size: 34px; }
}

.bf-card {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: var(--bf-radius);
  padding: 28px;
  transition: transform 0.3s var(--bf-ease), border-color 0.3s var(--bf-ease), background 0.3s var(--bf-ease);
}
.bf-card:hover {
  transform: translateY(-4px);
  border-color: rgba(255, 122, 69, 0.35);
  background: rgba(255, 255, 255, 0.045);
}

.bf-card h3 { font-size: 19px; }
.bf-card p { margin: 12px 0 0; color: var(--bf-text-300); font-size: 15px; line-height: 1.6; }

.bf-persona-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--bf-indigo);
  margin-bottom: 14px;
}
.bf-persona-icon svg { width: 22px; height: 22px; }

/* Problem/Rozwiązanie cards (2026-08-29, owner: "biednie wygląda") — these
   two homepage sections were plain <h3>+<p> with no icon, the one spot on
   the page that never got the icon treatment already established for the
   persona cards further down (.bf-persona-icon, reused as-is for Problem).
   Solution cards get a filled brand-gradient variant instead of the same
   flat dark circle — a deliberate visual "problem is muted, solution is
   vibrant" contrast, not a new arbitrary color (reuses --bf-gradient-brand,
   already the site's one accent gradient). */
.bf-persona-icon--brand { background: var(--bf-gradient-brand); border-color: transparent; color: #fff; }
.bf-card--solution { border-color: rgba(255, 122, 69, 0.15); }
.bf-card--solution:hover { border-color: rgba(255, 122, 69, 0.5); }

/* Statyczny wybór ścieżki (2026-10-02, CRO audyt) — dwie karty jednocześnie
   widoczne pod hero, uzupełniają rotującą karuzelę wyżej. Ten sam wizualny
   język co .bf-card (tło/border/radius/hover), ale jako link-karta z CTA. */
.bf-path-choice {
  display: grid;
  gap: 20px;
  max-width: 760px;
  margin: 0 auto;
}
@media (min-width: 640px) {
  .bf-path-choice { grid-template-columns: 1fr 1fr; }
}
.bf-path-card {
  display: block;
  text-align: center;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 182, 72, 0.35);
  border-radius: var(--bf-radius);
  padding: 32px 24px;
  text-decoration: none;
  color: inherit;
  transition: transform 0.3s var(--bf-ease), border-color 0.3s var(--bf-ease), background 0.3s var(--bf-ease), box-shadow 0.3s var(--bf-ease);
  box-shadow: 0 0 24px rgba(255, 122, 69, 0.08);
}
.bf-path-choice a.bf-path-card:nth-child(2) { border-color: rgba(255, 122, 69, 0.35); }
.bf-path-card:hover {
  transform: translateY(-4px);
  border-color: rgba(255, 122, 69, 0.6);
  background: rgba(255, 255, 255, 0.045);
  box-shadow: 0 0 32px rgba(255, 122, 69, 0.18);
}
.bf-path-card h3 { font-size: 20px; margin: 0; }
.bf-path-card p { margin: 10px 0 0; color: var(--bf-text-300); font-size: 14px; line-height: 1.5; }
.bf-path-card__cta { display: block; margin-top: 16px; font-weight: 700; color: var(--bf-indigo); font-size: 15px; }

/* Homepage section glows (2026-09-17, owner: "to biedne... zrób to z
   kunsztem") — every major section below the hero was 100% flat
   var(--bf-bg-950)/var(--bf-bg-900), the one visual-richness gap the
   .bf-cta/.bf-studio-card/.bf-hero sections already avoided. Same soft
   radial-glow language as .bf-cta below (low-opacity radial-gradient over
   the section's existing solid base, nothing added to markup), reusing
   ONLY the locked palette (--bf-blue/--bf-indigo/--bf-purple) — a
   different position + hue emphasis per section purely for rhythm, so
   scrolling the page doesn't feel like the same glow repeated eight times.
   Scoped to each section's own id/class, never to the shared
   .bf-section/.bf-section--alt base rules those also carry — this theme
   reuses those two classes on FAQ/Kontakt/Regulamin/Polityka/404/product
   pages too, which must stay exactly as plain as they are today. */
#problem {
  background:
    radial-gradient(45% 55% at 15% 0%, rgba(255, 122, 69, 0.10) 0%, rgba(255, 122, 69, 0) 65%),
    var(--bf-bg-950);
}
#rozwiazanie {
  background:
    radial-gradient(50% 65% at 85% 0%, rgba(255, 95, 109, 0.16) 0%, rgba(255, 95, 109, 0) 60%),
    radial-gradient(40% 50% at 5% 100%, rgba(255, 182, 72, 0.08) 0%, rgba(255, 182, 72, 0) 60%),
    var(--bf-bg-900);
}
.bf-howitworks {
  background:
    radial-gradient(60% 70% at 50% 15%, rgba(255, 122, 69, 0.14) 0%, rgba(255, 122, 69, 0) 62%),
    radial-gradient(40% 50% at 90% 90%, rgba(255, 182, 72, 0.08) 0%, rgba(255, 182, 72, 0) 60%),
    var(--bf-bg-950);
}
#jak-to-dziala-import {
  background:
    radial-gradient(55% 70% at 0% 50%, rgba(255, 122, 69, 0.14) 0%, rgba(255, 122, 69, 0) 65%),
    var(--bf-bg-900);
}
#jak-to-wyglada {
  background:
    radial-gradient(50% 60% at 50% 0%, rgba(255, 182, 72, 0.10) 0%, rgba(255, 182, 72, 0) 60%),
    var(--bf-bg-950);
}
#marketplace-preview {
  background:
    radial-gradient(50% 65% at 90% 100%, rgba(255, 95, 109, 0.14) 0%, rgba(255, 95, 109, 0) 60%),
    var(--bf-bg-900);
}
#dla-kogo {
  background:
    radial-gradient(55% 60% at 50% 0%, rgba(255, 122, 69, 0.13) 0%, rgba(255, 122, 69, 0) 60%),
    var(--bf-bg-900);
}
#cennik {
  background:
    radial-gradient(45% 55% at 10% 0%, rgba(255, 182, 72, 0.10) 0%, rgba(255, 182, 72, 0) 60%),
    radial-gradient(45% 55% at 90% 100%, rgba(255, 95, 109, 0.12) 0%, rgba(255, 95, 109, 0) 60%),
    var(--bf-bg-950);
}

/* Shared by the pipeline (.bf-feature-flow--pipeline is the only user of
   .bf-feature-flow now — "Co dostajesz" was merged into it, 2026-08-25).
   Base/mobile: simple vertical stack. Desktop layout comes entirely from
   the --pipeline modifier below (single source of truth for display/grid
   vs flex — having two rules at equal specificity for the same property
   caused a real, shipped bug: the base grid rule silently overrode the
   flex fix because it came later in the file). */
.bf-feature-flow {
  display: flex;
  flex-direction: column;
  gap: 32px;
  margin-top: 48px;
}
.bf-feature-flow__item { position: relative; text-align: center; }
.bf-feature-flow__item:hover .bf-feature-flow__icon {
  border-color: rgba(255, 122, 69, 0.5);
  box-shadow: 0 0 24px -6px rgba(255, 122, 69, 0.6);
  transform: translateY(-3px);
}
.bf-feature-flow__icon { transition: transform 0.3s var(--bf-ease), border-color 0.3s var(--bf-ease), box-shadow 0.3s var(--bf-ease); }
.bf-feature-flow__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--bf-indigo);
  margin-bottom: 16px;
  position: relative;
  z-index: 1;
}
.bf-feature-flow__icon svg { width: 24px; height: 24px; }
.bf-feature-flow__item h3 { font-size: 15px; margin: 0; }
.bf-feature-flow__item p { margin: 6px 0 0; font-size: 13px; color: var(--bf-text-400); line-height: 1.5; }


/* ==========================================================================
   Real Ebook Showcase — literal page scans of real generated products,
   grouped by category family, small thumbnails that zoom large on
   hover/focus so a visitor can actually read a sample page.
   (2026-08-26. Verified live: :hover correctly matches and the whole
   hover rule block applies — a background/non-composited preview tab can
   make the animated `transform` computed value look stuck, but that's a
   tooling artifact of that check, not the CSS; z-index flips instantly
   confirming the rule itself is correct.)
   ========================================================================== */
.bf-showcase-tabs__radio { position: absolute; opacity: 0; pointer-events: none; }

.bf-showcase-tabs__nav {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
  margin: 40px 0 36px;
}
.bf-showcase-tabs__nav label {
  padding: 9px 18px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.03);
  color: var(--bf-text-400);
  font-size: 14px;
  cursor: pointer;
  transition: background 0.25s var(--bf-ease), border-color 0.25s var(--bf-ease), color 0.25s var(--bf-ease);
}
.bf-showcase-tabs__nav label:hover { border-color: rgba(255, 122, 69, 0.4); color: var(--bf-text-300); }

.bf-showcase-tabs__panel { display: none; }

/* Radios precede .bf-showcase-tabs__nav/__panels in the DOM (front-page.php),
   so ~ reaches both — ids are the $showcase_families ids there. Add a pair
   here whenever a new family id is added to that PHP array. */
#bf-tab-historia:checked ~ .bf-showcase-tabs__nav label[for="bf-tab-historia"],
#bf-tab-dom:checked ~ .bf-showcase-tabs__nav label[for="bf-tab-dom"],
#bf-tab-rozwoj:checked ~ .bf-showcase-tabs__nav label[for="bf-tab-rozwoj"],
#bf-tab-zdrowie:checked ~ .bf-showcase-tabs__nav label[for="bf-tab-zdrowie"] {
  background: var(--bf-indigo);
  border-color: var(--bf-indigo);
  color: #fff;
}
#bf-tab-historia:checked ~ .bf-showcase-tabs__panels #bf-panel-historia,
#bf-tab-dom:checked ~ .bf-showcase-tabs__panels #bf-panel-dom,
#bf-tab-rozwoj:checked ~ .bf-showcase-tabs__panels #bf-panel-rozwoj,
#bf-tab-zdrowie:checked ~ .bf-showcase-tabs__panels #bf-panel-zdrowie {
  display: block;
}

.bf-showcase-book { margin-bottom: 44px; }
.bf-showcase-book:last-child { margin-bottom: 0; }
.bf-showcase-book__meta {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.bf-showcase-book__badge {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--bf-indigo);
  border: 1px solid rgba(255, 122, 69, 0.4);
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}
.bf-showcase-book__meta h3 { margin: 0; font-size: 18px; }

.bf-showcase-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
@media (min-width: 640px) {
  .bf-showcase-grid { grid-template-columns: repeat(4, 1fr); }
}

.bf-showcase-thumb {
  position: relative;
  z-index: 1;
  margin: 0;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.03);
  cursor: zoom-in;
  transition: transform 0.28s var(--bf-ease), box-shadow 0.28s var(--bf-ease), border-color 0.28s var(--bf-ease);
}
.bf-showcase-thumb img { display: block; width: 100%; aspect-ratio: 707 / 1000; object-fit: cover; }
.bf-showcase-thumb figcaption {
  padding: 8px 10px;
  font-size: 11px;
  color: var(--bf-text-400);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.bf-showcase-thumb:hover,
.bf-showcase-thumb:focus-within {
  transform: scale(2.3);
  z-index: 5;
  border-color: rgba(255, 122, 69, 0.5);
  box-shadow: 0 30px 70px -20px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 122, 69, 0.5);
}
@media (max-width: 640px) {
  .bf-showcase-thumb:hover,
  .bf-showcase-thumb:focus-within { transform: scale(1.8); }
}
@media (prefers-reduced-motion: reduce) {
  .bf-showcase-thumb:hover,
  .bf-showcase-thumb:focus-within { transform: none; }
}

/* ==========================================================================
   Pricing
   ========================================================================== */
.bf-pricing-grid {
  display: grid;
  gap: 20px;
  margin: 48px auto 0;
  max-width: 640px;
}

@media (min-width: 640px) {
  .bf-pricing-grid { grid-template-columns: 1fr 1fr; }
}
/* Third card ("Zaproponuj temat", 2026-09-02) needs more room than the
   original 2-card 640px grid — widens only once there's space for all 3
   side by side; between 640-959px it still wraps to 2+1, which reads fine. */
.bf-pricing-grid--3 { max-width: 940px; }
@media (min-width: 960px) {
  .bf-pricing-grid--3 { grid-template-columns: repeat(3, 1fr); }
}

.bf-price-card {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  padding: 28px;
  transition: transform 0.3s var(--bf-ease), border-color 0.3s var(--bf-ease), box-shadow 0.3s var(--bf-ease);
}
.bf-price-card:hover {
  transform: translateY(-6px);
  border-color: rgba(255, 95, 109, 0.4);
  box-shadow: 0 20px 50px -20px rgba(255, 122, 69, 0.4);
}

.bf-price-card--highlight {
  position: relative;
  border-color: rgba(255, 95, 109, 0.5);
  box-shadow: 0 0 0 1px rgba(255, 95, 109, 0.25), 0 20px 60px -25px rgba(255, 122, 69, 0.5);
}
.bf-price-card__badge {
  position: absolute;
  top: -13px;
  left: 28px;
  background: var(--bf-gradient-brand);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 5px 14px;
  border-radius: 999px;
}

.bf-price-card h3 { font-size: 22px; }
.bf-price-card__meta { margin: 6px 0 0; color: var(--bf-text-400); font-size: 13px; }
.bf-price-card__price { margin: 20px 0 0; font-family: var(--bf-font-display); font-size: 36px; }
.bf-price-card__price span { font-size: 16px; color: var(--bf-text-400); font-family: var(--bf-font-body); }

.bf-addons-label {
  text-align: center;
  margin: 32px 0 0;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--bf-text-400);
}

.bf-addons {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 560px;
  margin: 16px auto 0;
}

@media (min-width: 560px) {
  .bf-addons { flex-direction: row; align-items: stretch; }
}

.bf-addon {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 12px;
  padding: 14px 18px;
  font-size: 14px;
}

.bf-addon__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.bf-addon strong { color: var(--bf-blue); }
.bf-addon__desc { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--bf-text-400); }

/* ==========================================================================
   CTA
   ========================================================================== */
.bf-cta {
  padding: 72px 0;
  background:
    radial-gradient(50% 60% at 50% 0%, rgba(255, 122, 69, 0.2) 0%, rgba(255, 122, 69, 0) 60%),
    var(--bf-bg-950);
  text-align: center;
}

.bf-cta__inner { max-width: 520px; margin: 0 auto; }
.bf-cta h2 { font-size: 30px; }
.bf-cta p { margin: 14px 0 0; color: var(--bf-text-300); }
.bf-cta .bf-btn { margin-top: 30px; }

/* Wariant "zarabiaj" (2026-09-18c) — czerwony akcent (--bf-danger) zamiast
   domyślnego fioletu .bf-cta, do promowania zarobku 50% dla autorów na
   Marketplace. Węższy, wpięty w layout strony (nie pełna sekcja jak .bf-cta
   na dole front-page.php), z widoczną ramką, żeby wybijał się z reszty
   strony bez wychodzenia poza premium, ciemny styl motywu (świadomie nie
   czysty #ff0000 — patrz --bf-danger, ten sam odcień co bf-alert--error). */
.bf-cta--earn {
  padding: 28px 24px;
  margin-bottom: 24px;
  border-radius: 16px;
  border: 1px solid rgba(211, 86, 63, 0.45);
  background:
    radial-gradient(60% 140% at 0% 0%, rgba(211, 86, 63, 0.22) 0%, rgba(211, 86, 63, 0) 70%),
    var(--bf-bg-900);
  text-align: left;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.bf-cta--earn .bf-cta__inner { max-width: none; margin: 0; }
.bf-cta--earn h2 { font-size: 22px; color: var(--bf-danger); }
.bf-cta--earn p { color: var(--bf-text-300); }
.bf-cta--earn .bf-btn { margin-top: 0; flex-shrink: 0; }
@media (max-width: 640px) {
  .bf-cta--earn { flex-direction: column; align-items: stretch; text-align: center; }
  .bf-cta--earn .bf-btn { width: 100%; }
}

/* ==========================================================================
   Process flow diagram (strona "Jak to działa")
   ========================================================================== */
.bf-flow {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: 56px;
  max-width: 720px;
  margin-left: auto;
  margin-right: auto;
}

.bf-flow__item {
  display: flex;
  gap: 24px;
  position: relative;
  padding-bottom: 40px;
}

.bf-flow__item:last-child { padding-bottom: 0; }

.bf-flow__marker {
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--bf-gradient-brand);
  color: var(--bf-bg-950);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--bf-font-display);
  font-weight: 700;
  font-size: 20px;
  position: relative;
  z-index: 1;
}

.bf-flow__item:not(:last-child) .bf-flow__marker::after {
  content: "";
  position: absolute;
  top: 56px;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: calc(100% + 40px - 56px);
  background: linear-gradient(var(--bf-indigo), rgba(255, 122, 69, 0.15));
}

.bf-flow__body { padding-top: 8px; }
.bf-flow__body h3 { font-size: 19px; }
.bf-flow__body p { margin: 8px 0 0; color: var(--bf-text-300); font-size: 15px; line-height: 1.6; max-width: 480px; }

/* "Kuźnia doskonali, zanim to zobaczysz" (2026-08-29, redesigned same day
   after "wygląda jak z przedszkola") — first pass was a flat tinted box,
   read as a plain note rather than a premium reveal. Now matches the site's
   actual premium vocabulary instead of inventing a new one: contained glow
   orbs (same component as the hero/pipeline sections), a gradient-filled
   icon circle (same treatment as .bf-persona-icon--brand), a .bf-badge
   eyebrow pill, and .bf-gradient-text on the heading — every piece reused
   from elsewhere on this exact page/site, not new visual language. */
.bf-secret-callout {
  position: relative;
  overflow: hidden;
  margin: 8px 0 40px;
  padding: 44px 32px;
  border-radius: var(--bf-radius);
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 122, 69, 0.3);
  box-shadow: 0 0 60px rgba(255, 122, 69, 0.12);
  text-align: center;
}
.bf-secret-callout__inner { position: relative; z-index: 1; max-width: 560px; margin: 0 auto; }
.bf-secret-callout__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin: 0 auto 20px;
  border-radius: 50%;
  background: var(--bf-gradient-brand);
  color: #fff;
  box-shadow: 0 0 24px rgba(255, 122, 69, 0.5);
}
.bf-secret-callout__icon svg { width: 24px; height: 24px; }
.bf-secret-callout__badge { margin: 0 0 14px; }
.bf-secret-callout h3 { font-size: 24px; margin: 0; }
.bf-secret-callout__text { margin: 14px 0 0; color: var(--bf-text-300); font-size: 15px; line-height: 1.7; }
@media (min-width: 900px) { .bf-secret-callout { padding: 52px 60px; } }
.bf-flow__meta {
  display: inline-flex;
  margin-top: 12px;
  gap: 8px;
  flex-wrap: wrap;
}
/* Combined with .bf-showcase-thumb (not just .bf-flow__proof alone) so this
   always outranks the shared .bf-showcase-thumb:hover rule regardless of
   file order — the documented lesson from the pipeline bug (2026-08-26):
   two same-specificity class selectors on one element let source order
   decide the winner by accident. */
.bf-flow__proof {
  max-width: 150px;
  margin: 16px auto 0;
}
@media (min-width: 720px) {
  .bf-showcase-thumb.bf-flow__proof:hover,
  .bf-showcase-thumb.bf-flow__proof:focus-within { transform: scale(2); }
}
.bf-flow__tag {
  font-size: 12px;
  font-weight: 600;
  color: var(--bf-blue);
  border: 1px solid rgba(255, 182, 72, 0.3);
  background: rgba(255, 182, 72, 0.08);
  border-radius: 999px;
  padding: 4px 12px;
}

/* Above 900px there's room for the 4 steps side by side with arrows between
   them instead of stacked with a vertical line — below that, the vertical
   layout above stays (4 columns wouldn't fit legibly on a phone/tablet). */
@media (min-width: 900px) {
  .bf-flow {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 20px 40px;
    max-width: none;
  }
  .bf-flow__item {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0;
    padding-bottom: 0;
  }
  .bf-flow__item:not(:last-child) .bf-flow__marker::after { display: none; }
  .bf-flow__item:not(:last-child)::before {
    content: "→";
    position: absolute;
    top: 28px;
    right: -30px;
    transform: translateY(-50%);
    font-size: 22px;
    color: var(--bf-indigo);
  }
  .bf-flow__body { padding-top: 16px; }
  .bf-flow__meta { justify-content: center; }

  /* 8 steps in a 4-column grid wrap to 2 rows — the "→" after every
     non-last item would otherwise point rightward off the edge at the end
     of row 1 (step 4) into empty space above row 2, not at step 5 below.
     .bf-secret-callout lives OUTSIDE .bf-flow now (2026-08-29 — an earlier
     attempt at putting it BETWEEN steps as a grid child landed as a
     squeezed 5th cell instead of the intended full-width break; simplest
     fix was moving it out of the grid entirely rather than fighting
     auto-placement), so it needs no special-casing here anymore. */
  .bf-flow__item:nth-child(4)::before { display: none; }

  /* "Opublikuj swój ebook" (2026-09-19) ma 5 krokÓw, nie 4 — .bf-flow jest
     współdzielony z innymi stronami (stąd twardy repeat(4, 1fr) i nth-child(4)
     hack wyżej dla 8-krokowego wariantu), więc scoped override tylko dla tej
     sekcji zamiast zmieniać globalny komponent. Bez tego 5. krok osierociłby
     się sam w nowym wierszu, source: 8-step comment above describes the same
     failure mode. */
  #opublikuj-swoj-ebook-jak-to-dziala .bf-flow { grid-template-columns: repeat(5, 1fr); }
}

.bf-compare {
  display: grid;
  gap: 16px;
  margin-top: 20px;
}

@media (min-width: 640px) {
  .bf-compare { grid-template-columns: 1fr 1fr; }
}

.bf-compare__row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  font-size: 14px;
}
.bf-compare__row:last-child { border-bottom: none; }
.bf-compare__row span:first-child { color: var(--bf-text-400); }

/* "Or buy one ready-made" alternative-path card, between generator addons
   and the trust bar (2026-08-27) — deliberately NOT a third pricing-grid
   card: Standard/Premium are about generating YOUR OWN ebook, this is a
   different product (an existing catalog item), so it reads as its own
   call-out rather than a visually-identical third option in the same grid.
   Copy says "Przeglądaj", not "Kup teraz" — checkout isn't live yet
   (single-bf_product.php's buy button is still disabled), so anything
   implying an instant purchase/download here would be false. */
.bf-marketplace-cta {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  margin-top: 40px;
  padding: 28px 32px;
  border: 1px solid rgba(255, 95, 109, 0.4);
  border-radius: var(--bf-radius);
  background: linear-gradient(135deg, rgba(255, 182, 72, 0.1), rgba(255, 122, 69, 0.14) 55%, rgba(255, 95, 109, 0.1));
  box-shadow: 0 24px 60px -28px rgba(255, 122, 69, 0.55);
  transition: transform 0.3s var(--bf-ease), box-shadow 0.3s var(--bf-ease);
}
.bf-marketplace-cta:hover {
  transform: translateY(-3px);
  box-shadow: 0 28px 70px -25px rgba(255, 122, 69, 0.7);
}
.bf-marketplace-cta__icon {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--bf-gradient-brand);
  color: #fff;
  flex: none;
  box-shadow: 0 8px 24px -8px rgba(255, 122, 69, 0.7);
}
.bf-marketplace-cta__icon svg { width: 22px; height: 22px; }
.bf-marketplace-cta__text { position: relative; z-index: 1; flex: 1; min-width: 220px; }
.bf-marketplace-cta__text h3 { font-size: 17px; margin: 0; }
.bf-marketplace-cta__text p { margin: 4px 0 0; font-size: 14px; color: var(--bf-text-300); }
.bf-marketplace-cta__text strong { color: var(--bf-text-50); }
.bf-marketplace-cta > .bf-btn { position: relative; z-index: 1; }
@media (max-width: 640px) {
  .bf-marketplace-cta { flex-direction: column; align-items: flex-start; text-align: left; }
  .bf-marketplace-cta .bf-btn { width: 100%; }
}

/* Trust facts row under the pricing addons — reinforces facts already true
   elsewhere on the site (formats in the hero, one-time pricing in this same
   section's description, resale rights in Regulamin §8) at the exact
   moment a visitor is deciding whether to buy. No new claims invented. */
.bf-trust-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px 32px;
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.bf-trust-bar__item {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--bf-text-300);
  font-size: 13px;
}
.bf-trust-bar__item svg { width: 18px; height: 18px; color: var(--bf-indigo); flex: none; }

/* ==========================================================================
   Auth (login / register / forgot / reset)
   ========================================================================== */
.bf-auth {
  min-height: calc(100vh - 92px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px 20px;
  background:
    radial-gradient(50% 50% at 50% 0%, rgba(255, 122, 69, 0.16) 0%, rgba(255, 122, 69, 0) 60%),
    var(--bf-bg-950);
}

@media (min-width: 640px) {
  .bf-auth { min-height: calc(100vh - 128px); }
}

.bf-auth__card {
  width: 100%;
  max-width: 400px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  padding: 36px 28px;
}

.bf-auth__title { font-size: 24px; text-align: center; }
.bf-auth__subtitle { margin: 8px 0 0; text-align: center; color: var(--bf-text-300); font-size: 14px; }

.bf-field { margin-top: 20px; }
.bf-field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--bf-text-300);
  margin-bottom: 6px;
}
.bf-field input[type="text"],
.bf-field input[type="email"],
.bf-field input[type="password"],
.bf-field input[type="number"],
.bf-field select,
.bf-field textarea {
  width: 100%;
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 15px;
  color: var(--bf-text-50);
  font-family: var(--bf-font-body);
}
.bf-field select { appearance: auto; }
.bf-field textarea { resize: vertical; }
.bf-field input:focus,
.bf-field select:focus,
.bf-field textarea:focus {
  outline: none;
  border-color: var(--bf-indigo);
}

/* Generator layout (2026-08-28) — desktop uses the empty right-hand space
   for a sticky "Podsumowanie ebooka" panel instead of leaving the form
   centered in a narrow column; mobile stacks the summary below the form
   (both cases: one shared DOM order, CSS grid handles placement, so there's
   no duplicated markup to keep in sync). */
.bf-generator-form { max-width: none; }
.bf-generator-fields { max-width: 640px; }
@media (min-width: 1080px) {
  .bf-generator-form { display: grid; grid-template-columns: minmax(0, 640px) 320px; gap: 32px; align-items: start; }
  .bf-generator-fields { max-width: none; }
  .bf-generator-summary { position: sticky; top: 24px; }
}

.bf-generator-summary__inner {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  padding: 24px;
  margin-top: 32px;
}
@media (min-width: 1080px) { .bf-generator-summary__inner { margin-top: 0; } }
.bf-generator-summary__inner h3 { margin: 0 0 4px; font-size: 16px; }
.bf-generator-summary__list { margin: 16px 0 0; }
.bf-generator-summary__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 13px;
}
.bf-generator-summary__row:last-child { border-bottom: none; }
.bf-generator-summary__row dt { color: var(--bf-text-400); flex: none; }
.bf-generator-summary__row dd { margin: 0; color: var(--bf-text-50); font-weight: 600; text-align: right; }

/* Process status (section 2 of the 2026-08-28 spec) — only the 3 real
   bf_status stages a customer's order passes through, never a fabricated
   percentage (see template-generator.php's own comment on $stage_steps). */
.bf-generation-progress { margin-top: 24px; text-align: left; max-width: 520px; margin-left: auto; margin-right: auto; }
.bf-generation-progress__steps { display: flex; flex-direction: column; gap: 4px; }
.bf-generation-progress__step { display: flex; align-items: center; gap: 12px; padding: 6px 0; }
.bf-generation-progress__dot { width: 12px; height: 12px; border-radius: 50%; flex: none; background: rgba(255, 255, 255, 0.15); }
.bf-generation-progress__step--done .bf-generation-progress__dot { background: var(--bf-success); }
.bf-generation-progress__step--active .bf-generation-progress__dot { background: var(--bf-indigo); box-shadow: 0 0 0 4px rgba(255, 122, 69, 0.25); }
.bf-generation-progress__step--pending .bf-generation-progress__label { color: var(--bf-text-400); }
.bf-generation-progress__step--done .bf-generation-progress__label { color: var(--bf-text-300); }
.bf-generation-progress__step--active .bf-generation-progress__label { color: var(--bf-text-50); font-weight: 600; }
.bf-generation-progress__note { margin: 12px 0 0; font-size: 12px; color: var(--bf-text-400); }
.bf-generation-progress__chapters { margin: 16px 0 0; }
.bf-generation-progress__bar { height: 6px; border-radius: 3px; background: rgba(255, 255, 255, 0.08); overflow: hidden; }
.bf-generation-progress__bar-fill { height: 100%; background: var(--bf-gradient-brand); border-radius: 3px; transition: width 0.4s var(--bf-ease); }
.bf-generation-progress__chapters-label { margin: 8px 0 0; font-size: 12px; color: var(--bf-text-300); text-align: center; }

/* Duży, "żywy" pasek postępu generowania (2026-10-03, owner: wyróżnić, powiększyć
   i dodać coś, co się kręci). Spinner + poruszające się paski na wypełnieniu +
   pulsująca kropka aktywnego etapu — wszystko wyłączane dla
   prefers-reduced-motion. Same tokeny marki, nic nowego kolorystycznie. */
.bf-genprog {
  margin: 28px 0 0;
  padding: 22px 24px;
  border-radius: var(--bf-radius);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 122, 69, 0.4);
  box-shadow: 0 0 40px rgba(255, 122, 69, 0.14);
}
.bf-genprog__head { display: flex; align-items: center; gap: 12px; }
.bf-genprog__spinner {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.15);
  border-top-color: var(--bf-indigo);
  animation: bf-spin 0.9s linear infinite;
}
.bf-genprog__title { flex: 1; font-weight: 700; font-size: 15px; }
.bf-genprog__pct {
  font-size: 30px;
  font-weight: 800;
  line-height: 1;
  background: var(--bf-gradient-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.bf-genprog__bar {
  margin-top: 16px;
  height: 20px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
.bf-genprog__fill {
  height: 100%;
  border-radius: 10px;
  background:
    repeating-linear-gradient(115deg, rgba(255, 255, 255, 0.24) 0 10px, rgba(255, 255, 255, 0) 10px 20px),
    var(--bf-gradient-brand);
  background-size: 40px 100%, 100% 100%;
  animation: bf-genprog-stripes 0.9s linear infinite;
  transition: width 0.6s var(--bf-ease);
}
.bf-genprog__label { margin: 12px 0 0; text-align: center; font-size: 14px; color: var(--bf-text-300); }
.bf-genprog__label strong { color: var(--bf-text-50); }
/* "Ostatnie szlify": wszystkie rozdziały gotowe, trwa skład/okładka/pliki. Pasek
   pełny, ale wyraźnie pulsuje, a zamiast "100%" jest znacznik etapu. */
.bf-genprog--finishing { border-color: rgba(255, 182, 72, 0.7); }
.bf-genprog__tag {
  flex: none;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--bf-gradient-brand);
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  animation: bf-genprog-tag-pulse 1.4s ease-in-out infinite;
}
.bf-genprog--finishing .bf-genprog__fill {
  animation: bf-genprog-stripes 0.9s linear infinite, bf-genprog-bar-glow 1.4s ease-in-out infinite;
}
@keyframes bf-genprog-tag-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
@keyframes bf-genprog-bar-glow { 0%, 100% { box-shadow: 0 0 6px rgba(255, 122, 69, 0.3); } 50% { box-shadow: 0 0 22px rgba(255, 122, 69, 0.85); } }
@media (prefers-reduced-motion: reduce) {
  .bf-genprog__tag, .bf-genprog--finishing .bf-genprog__fill { animation: none; }
}

/* Stan końcowy: zielony, pełny pasek, "pop" ikony. */
/* Stan "WYKUTE!" (2026-10-03, owner: "zmień na w chuj zielone, żeby user wiedział,
   że to gotowe") — celowo jaskrawa zieleń POZA paletą marki pomarańczowej, żeby
   stan końcowy nie dało się pomylić z trwającym generowaniem. */
.bf-genprog--done {
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.22), rgba(22, 163, 74, 0.1));
  border: 2px solid #22c55e;
  box-shadow: 0 0 56px rgba(34, 197, 94, 0.35);
}
.bf-genprog--done .bf-genprog__pct { background: none; color: #4ade80; -webkit-text-fill-color: #4ade80; }
.bf-genprog__check {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #22c55e;
  color: #fff;
  font-size: 15px;
  font-weight: 800;
  box-shadow: 0 0 14px rgba(34, 197, 94, 0.7);
}
.bf-genprog__fill--done { background: linear-gradient(90deg, #16a34a, #22c55e, #4ade80); animation: none; box-shadow: 0 0 16px rgba(34, 197, 94, 0.6); }
.bf-confirm__icon--pop.bf-confirm__icon--success { background: #22c55e; box-shadow: 0 0 44px rgba(34, 197, 94, 0.65); }
.bf-confirm .bf-btn--primary { color: var(--bf-bg-950); }
.bf-forged-badge {
  display: block;
  width: fit-content;
  margin: 14px auto 0;
  padding: 10px 22px;
  border-radius: 999px;
  background: #22c55e;
  color: #052e16;
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  box-shadow: 0 0 28px rgba(34, 197, 94, 0.55);
}
.bf-confirm__success-title { color: #4ade80; }
.bf-confirm__icon--pop { animation: bf-genprog-pop 0.6s var(--bf-ease) both; }
@keyframes bf-genprog-pop { 0% { transform: scale(0.3); opacity: 0; } 70% { transform: scale(1.15); opacity: 1; } 100% { transform: scale(1); } }
@keyframes bf-genprog-stripes { from { background-position: 0 0, 0 0; } to { background-position: 40px 0, 0 0; } }
@keyframes bf-genprog-dot-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.35); } }
.bf-generation-progress__step--active .bf-generation-progress__dot { animation: bf-genprog-dot-pulse 1.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .bf-genprog__spinner, .bf-genprog__fill, .bf-generation-progress__step--active .bf-generation-progress__dot { animation: none; }
}

.bf-confirm__icon--error { background: var(--bf-danger); }
.bf-confirm__icon--success { background: var(--bf-success); }
.bf-confirm__downloads { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 20px; }

/* Field text helpers — replace ad-hoc inline styles that used to be
   scattered across template-generator.php (2026-08-26 cleanup). */
.bf-field__hint { margin: 6px 0 0; color: var(--bf-text-400); font-size: 12px; }
.bf-field__label-text { display: block; font-size: 13px; font-weight: 600; color: var(--bf-text-300); margin-bottom: 6px; }
.bf-field__custom-input { margin-top: 8px; }

/* Generator form grouped into cards (2026-08-26 — was one long unbroken
   column of 9 fields, the single biggest source of "przytłaczające" in the
   whole account area). Step 3 is a native <details> — zero JS, same
   pattern as the FAQ accordion — so the truly optional fine-tuning fields
   are collapsed by default instead of adding to the visible wall of inputs. */
.bf-form-section {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  padding: 24px;
  margin-top: 20px;
}
.bf-form-section:first-child { margin-top: 32px; }
.bf-form-section__header {
  display: flex;
  align-items: center;
  gap: 12px;
}
.bf-form-section__step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--bf-gradient-brand);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  flex: none;
}
.bf-form-section__header h2 { flex: 1; font-size: 16px; margin: 0; }
.bf-form-section__optional {
  font-size: 11px;
  color: var(--bf-text-400);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}
.bf-form-section > .bf-field:first-of-type { margin-top: 20px; }
.bf-form-section--danger {
  background: rgba(211, 86, 63, 0.06);
  border-color: rgba(211, 86, 63, 0.3);
}
.bf-form-section--danger .bf-form-section__header h2 { color: var(--bf-danger); }

.bf-form-section--collapsible { padding: 0; }
.bf-form-section--collapsible > summary {
  padding: 24px;
  cursor: pointer;
  list-style: none;
}
.bf-form-section--collapsible > summary::-webkit-details-marker { display: none; }
.bf-form-section--collapsible > summary::after {
  content: "";
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--bf-text-400);
  border-bottom: 2px solid var(--bf-text-400);
  transform: rotate(45deg);
  transition: transform 0.2s var(--bf-ease);
}
.bf-form-section--collapsible[open] > summary::after { transform: rotate(-135deg); }
.bf-form-section__body { padding: 0 24px 24px; }
.bf-form-section__body .bf-field:first-child { margin-top: 0; }

.bf-required-mark { color: var(--bf-danger); font-weight: 700; }
.bf-field__optional-mark { font-size: 12px; font-weight: 400; color: var(--bf-text-400); }

.bf-example-box {
  margin-top: 10px;
  padding: 10px 14px;
  border: 1px solid rgba(255, 122, 69, 0.3);
  border-radius: 8px;
  background: rgba(255, 122, 69, 0.08);
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--bf-text-300);
}
.bf-example-box strong { color: var(--bf-text-50); }

.bf-package-select {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.bf-package-option {
  display: block;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  padding: 12px 14px;
  cursor: pointer;
}
.bf-package-option input { margin-right: 8px; }
.bf-package-option:has(input:checked) {
  border-color: var(--bf-indigo);
  background: rgba(255, 122, 69, 0.1);
}
.bf-package-option span { display: inline-flex; flex-direction: column; vertical-align: middle; }
.bf-package-option strong { font-size: 14px; }
.bf-package-option small { font-size: 12px; color: var(--bf-text-400); }

.bf-confirm {
  max-width: 480px;
  margin: 40px auto;
  text-align: center;
}
.bf-confirm__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--bf-gradient-brand);
  color: #fff;
  font-size: 28px;
  font-weight: 700;
  margin-bottom: 20px;
}
.bf-confirm h1 { font-size: 26px; }
.bf-confirm p { margin: 12px 0 0; color: var(--bf-text-300); }
.bf-confirm__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 28px;
}

.bf-price-summary {
  margin-top: 24px;
  padding: 16px 18px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  background: var(--bf-bg-900);
}
.bf-price-summary__row {
  display: flex;
  justify-content: space-between;
  font-size: 14px;
  color: var(--bf-text-300);
  padding: 4px 0;
}
.bf-price-summary__row--total {
  margin-top: 8px;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  font-size: 16px;
  font-weight: 700;
  color: var(--bf-text-50);
}

.bf-field--checkbox {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.bf-field--checkbox input { margin-top: 3px; }
.bf-field--checkbox label { font-size: 13px; color: var(--bf-text-300); font-weight: 400; margin: 0; }
.bf-field--checkbox a { color: var(--bf-blue); text-decoration: underline; }

.bf-auth__submit { width: 100%; margin-top: 24px; }

.bf-auth__links {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  text-align: center;
  font-size: 14px;
  color: var(--bf-text-300);
}
.bf-auth__links a { color: var(--bf-blue); font-weight: 600; }

.bf-alert {
  margin-top: 20px;
  padding: 12px 14px;
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.5;
  /* Neutral "info" look (2026-09-03 fix) — this base class previously had
     no background/border/color of its own at all (only the --error/
     --success/--warning modifiers did), so a plain, unmodified .bf-alert
     rendered as unstyled body text in a padded box — easy to mistake for a
     formatting mistake rather than a deliberate callout. */
  background: rgba(255, 122, 69, 0.08);
  border: 1px solid rgba(255, 122, 69, 0.3);
  color: var(--bf-text-300);
}
/* "Jak to działa" step list (2026-09-03, template-zaproponuj-temat.php) —
   reuses .bf-form-section__step's numbered circle for visual consistency
   with the rest of the account area, instead of one dense paragraph with
   mid-sentence bold that read as a formatting mistake. */
.bf-how-steps {
  margin-top: 20px;
  padding: 20px;
  border-radius: var(--bf-radius);
  background: rgba(255, 122, 69, 0.06);
  border: 1px solid rgba(255, 122, 69, 0.25);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.bf-how-steps__item { display: flex; align-items: flex-start; gap: 14px; }
.bf-how-steps__item strong { display: block; font-size: 14px; color: var(--bf-text-50); }
.bf-how-steps__item p { margin: 3px 0 0; font-size: 13px; color: var(--bf-text-400); line-height: 1.5; }

.bf-alert--error {
  background: rgba(211, 86, 63, 0.1);
  border: 1px solid rgba(211, 86, 63, 0.35);
  color: #f2a898;
}
.bf-alert--success {
  background: rgba(74, 157, 111, 0.1);
  border: 1px solid rgba(74, 157, 111, 0.35);
  color: #9fd6b6;
}
.bf-alert--warning {
  background: rgba(214, 168, 74, 0.1);
  border: 1px solid rgba(214, 168, 74, 0.35);
  color: #e8c98a;
}

/* ==========================================================================
   Account area (dashboard, sidebar, drawer)
   ========================================================================== */
/* flex-direction: column by default (2026-08-30 mobile fix) — found live
   from an owner screenshot on a real phone: .bf-account-sidebar is
   position:fixed (out of flow) at every width, but .bf-account-topbar and
   .bf-account-main are both normal flex children of this container. With
   the default row direction (never overridden below 960px until now),
   they sat SIDE BY SIDE on mobile instead of stacked — the topbar's own
   natural width on the left, .bf-account-main squeezed into whatever
   width was left on the right, looking like a big empty dark block down
   the left side of every single /konto page on a real phone (Dashboard,
   Generator, Biblioteka, Poczekalnia, all of them — nobody had tested this
   area on an actual device before). Switched back to row only at the
   960px breakpoint below, where .bf-account-sidebar itself also switches
   from fixed to sticky/in-flow and genuinely needs to sit beside main
   content instead of stacked above it. */
.bf-account-body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--bf-bg-950);
}

/* Mobile top bar (logo + hamburger) — desktop hides this, sidebar is static */
.bf-account-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 64px;
  padding: 0 20px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--bf-bg-950);
}

.bf-account-menu-toggle {
  width: 40px;
  height: 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
}
.bf-account-menu-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--bf-text-50);
  border-radius: 2px;
}

.bf-account-sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 280px;
  background: var(--bf-bg-900);
  border-right: 1px solid rgba(255, 255, 255, 0.07);
  display: flex;
  flex-direction: column;
  padding: 24px 20px;
  transform: translateX(-100%);
  transition: transform 0.25s ease;
  z-index: 60;
  overflow-y: auto;
}

.bf-account-sidebar.is-open { transform: translateX(0); }

.bf-account-sidebar__logo { display: none; margin-bottom: 32px; }

.bf-account-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 50;
}
.bf-account-overlay.is-visible { display: block; }

/* Branded confirm dialog (2026-08-29, assets/js/account.js) — replaces the
   native browser confirm() everywhere in the account area (owner: it
   "looked cheap", wrong colors, stuck at the top of the viewport). Higher
   z-index than .bf-account-overlay (50) since it can be triggered from any
   page, including with the mobile sidebar already open. */
.bf-modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(10, 9, 16, 0.7);
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.bf-modal-overlay.is-visible { display: flex; }
.bf-modal {
  width: 100%;
  max-width: 420px;
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--bf-radius);
  padding: 28px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}
.bf-modal__message { margin: 0; font-size: 16px; line-height: 1.5; color: var(--bf-text-50); }
.bf-modal__actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 24px; }

/* Cookie consent banner (2026-08-30, inc/cookie-consent.php) */
.bf-cookie-consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 24px;
  background: var(--bf-bg-900);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.3);
}
.bf-cookie-consent p { margin: 0; font-size: 14px; color: var(--bf-text-300); max-width: 640px; }
.bf-cookie-consent p a { color: var(--bf-text-50); text-decoration: underline; }
.bf-cookie-consent__actions { display: flex; gap: 10px; flex: none; }
.bf-cookie-consent__actions .bf-btn { padding: 10px 20px; font-size: 14px; }
@media (max-width: 640px) {
  .bf-cookie-consent { flex-direction: column; align-items: stretch; text-align: center; }
  .bf-cookie-consent__actions { justify-content: center; }
}

.bf-account-nav { display: flex; flex-direction: column; gap: 4px; flex: 1; }
.bf-account-nav__link {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 14px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 500;
  color: var(--bf-text-300);
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--bf-font-body);
}
.bf-account-nav__icon { width: 18px; height: 18px; flex: none; color: var(--bf-text-400); transition: color 0.15s ease; }
.bf-account-nav__link:hover { background: rgba(255, 255, 255, 0.04); color: var(--bf-text-50); }
.bf-account-nav__link:hover .bf-account-nav__icon { color: var(--bf-text-300); }
.bf-account-nav__link.is-active {
  background: rgba(255, 122, 69, 0.14);
  color: var(--bf-text-50);
}
.bf-account-nav__link.is-active .bf-account-nav__icon { color: var(--bf-indigo); }

/* Generator: permanent, always-on highlight (owner, 2026-08-27) — the one
   primary action in this sidebar, meant to stand out from the rest of the
   dark, uniform nav at a glance, not just once you're already on it. Every
   selector below chains BOTH classes on the element (never the modifier
   alone) so this deterministically outranks the plain .is-active rule
   above regardless of file order — the exact footgun documented at length
   elsewhere in this file (the pipeline's three same-day specificity bugs). */
.bf-account-nav__link.bf-account-nav__link--generator {
  background: var(--bf-gradient-brand);
  color: #fff;
}
.bf-account-nav__link.bf-account-nav__link--generator .bf-account-nav__icon { color: #fff; }
.bf-account-nav__link.bf-account-nav__link--generator:hover { filter: brightness(1.08); }
.bf-account-nav__link.bf-account-nav__link--generator.is-active {
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3) inset;
}
/* "Moje rozliczenia" (2026-09-19) — zielony akcent zamiast pomarańczowego
   gradientu Generatora, ten sam język co .bf-dash-stat--money (Dashboard) —
   zielony w tym motywie oznacza konkretnie "Twoje pieniądze". */
.bf-account-nav__link.bf-account-nav__link--money {
  background: rgba(74, 157, 111, 0.14);
  border: 1px solid rgba(74, 157, 111, 0.4);
  color: var(--bf-success);
}
.bf-account-nav__link.bf-account-nav__link--money .bf-account-nav__icon { color: var(--bf-success); }
.bf-account-nav__link.bf-account-nav__link--money:hover { background: rgba(74, 157, 111, 0.22); }
.bf-account-nav__link.bf-account-nav__link--money.is-active {
  box-shadow: 0 0 0 2px rgba(74, 157, 111, 0.35) inset;
}
.bf-account-nav__link--logout { width: 100%; color: var(--bf-text-400); }

.bf-account-sidebar__footer {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}
.bf-account-user { padding: 0 14px 12px; display: flex; flex-direction: column; }
.bf-account-user__name { font-size: 14px; font-weight: 600; color: var(--bf-text-50); }
.bf-account-user__email { font-size: 12px; color: var(--bf-text-400); }

.bf-account-main {
  flex: 1;
  min-width: 0;
  padding: 32px 20px 60px;
}

@media (min-width: 960px) {
  .bf-account-body { flex-direction: row; }
  .bf-account-topbar { display: none; }
  .bf-account-sidebar { position: sticky; transform: none; }
  .bf-account-sidebar__logo { display: flex; }
  .bf-account-overlay { display: none !important; }
  .bf-account-main { padding: 48px 48px 60px; }
}

.bf-account-header { margin-bottom: 32px; }
.bf-account-header h1 { font-size: 26px; }
.bf-account-header p { margin: 8px 0 0; color: var(--bf-text-300); }

/* Structure preview (2026-09-12) — "podgląd struktury przed generowaniem",
   inc/generator.php bf_render_outline_preview(). Chapter list uses the same
   dark-card language as .bf-card, just denser and numbered since it's a
   sequential list, not a navigation grid. */
.bf-outline-preview { max-width: 760px; }
.bf-outline-preview__hero { display: flex; gap: 24px; margin-bottom: 28px; }
.bf-outline-preview__cover {
  flex: none;
  width: 140px;
  aspect-ratio: 2 / 3;
  border-radius: 10px;
  object-fit: cover;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: var(--bf-bg-900);
}
.bf-outline-preview__cover--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  text-align: center;
  font-size: 11px;
  line-height: 1.5;
  color: var(--bf-text-400);
}
.bf-outline-preview__hero-text { flex: 1; min-width: 0; }
.bf-outline-preview__title { font-size: 22px; margin: 0 0 8px; }
.bf-outline-preview__description { color: var(--bf-text-300); font-size: 15px; line-height: 1.6; margin: 0 0 8px; }
.bf-outline-preview__cover-note { color: var(--bf-text-400); font-size: 12px; margin: 12px 0 0; }
@media (max-width: 560px) {
  .bf-outline-preview__hero { flex-direction: column; }
  .bf-outline-preview__cover { width: 120px; }
}
.bf-outline-preview__list { list-style: none; margin: 0 0 28px; padding: 0; counter-reset: bf-outline-item; display: flex; flex-direction: column; gap: 12px; }
.bf-outline-preview__item {
  counter-increment: bf-outline-item;
  display: flex;
  gap: 16px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: var(--bf-radius);
  padding: 18px 20px;
}
.bf-outline-preview__item::before {
  content: counter(bf-outline-item);
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--bf-gradient-brand);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.bf-outline-preview__item-body strong { display: block; font-size: 15px; color: var(--bf-text-50); }
.bf-outline-preview__item-body p { margin: 6px 0 0; font-size: 13px; color: var(--bf-text-400); line-height: 1.5; }
.bf-outline-preview__actions { display: flex; flex-wrap: wrap; gap: 12px; }
.bf-outline-preview__actions form { margin: 0; }
.bf-outline-preview__note { margin: 16px 0 0; font-size: 12px; color: var(--bf-text-400); }

/* Dashboard stats row (2026-09-02, "pro SaaS" pass) — sits above the nav
   cards below, same card language, smaller/denser since it's numbers not
   navigation. */
.bf-dash-stats {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  margin-bottom: 20px;
}
.bf-dash-stat {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  padding: 18px 20px;
}
.bf-dash-stat__value { display: block; font-family: var(--bf-font-display); font-size: 26px; color: var(--bf-text-50); }
.bf-dash-stat__label { display: block; margin-top: 4px; font-size: 12px; color: var(--bf-text-400); }
/* Wyróżnienie kredytu/pieniędzy na Dashboardzie klienta (2026-09-19, owner:
   "to powinno się świecić na zielono") — jedyna karta reprezentująca realne
   pieniądze użytkownika, stąd --bf-success (zielony) zamiast pomarańczowego
   akcentu reszty strony; zielony w tym motywie już oznacza "dobra
   wiadomość"/sukces (patrz .bf-alert--success), więc to spójne, nie nowy
   kolor wymyślony na potrzeby jednej karty. */
.bf-dash-stat--money {
  border-color: rgba(74, 157, 111, 0.45);
  background: rgba(74, 157, 111, 0.08);
  box-shadow: 0 0 28px -6px rgba(74, 157, 111, 0.4);
}
.bf-dash-stat--money .bf-dash-stat__value { color: var(--bf-success); }

/* Baner zarobków na stronie głównej (2026-09-19) — sam komponent jest nowy
   (strona główna nie ma siatki .bf-dash-stats jak Dashboard), ale język
   wizualny (zielony akcent = pieniądze) ten sam co .bf-dash-stat--money. */
.bf-homepage-earnings-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 16px 20px;
  margin-bottom: 8px;
  border-radius: var(--bf-radius);
  border: 1px solid rgba(74, 157, 111, 0.45);
  background: rgba(74, 157, 111, 0.1);
  color: var(--bf-text-50);
  font-size: 14px;
  text-decoration: none;
  transition: border-color 0.2s var(--bf-ease), background 0.2s var(--bf-ease);
}
.bf-homepage-earnings-banner:hover {
  border-color: rgba(74, 157, 111, 0.7);
  background: rgba(74, 157, 111, 0.16);
}
.bf-homepage-earnings-banner strong { color: var(--bf-success); }
.bf-homepage-earnings-banner span:last-child { font-weight: 600; color: var(--bf-success); white-space: nowrap; }

.bf-dash-cards {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
}
@media (min-width: 640px) {
  .bf-dash-cards { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1100px) {
  .bf-dash-cards { grid-template-columns: repeat(4, 1fr); }
}

.bf-dash-card {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  padding: 22px;
  display: block;
  transition: transform 0.25s var(--bf-ease), border-color 0.25s var(--bf-ease), box-shadow 0.25s var(--bf-ease);
}
.bf-dash-card:hover {
  border-color: rgba(255, 122, 69, 0.4);
  transform: translateY(-3px);
  box-shadow: 0 16px 40px -22px rgba(255, 122, 69, 0.5);
}
.bf-dash-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: var(--bf-indigo);
  margin-bottom: 14px;
}
.bf-dash-card__icon svg { width: 19px; height: 19px; }
.bf-dash-card h3 { font-size: 16px; color: var(--bf-text-50); }
.bf-dash-card p { margin: 6px 0 0; font-size: 13px; color: var(--bf-text-400); }

/* "Przygotuj do sprzedaży" (2026-09-19, owner: "powinna się podświetlać na
   pomarańczowo") — stały, pełny gradient jak .bf-account-nav__link--generator
   w menu bocznym (nie tylko hover), bo to druga obok Generatora "główna"
   akcja na Dashboardzie, tyle że prowadząca do zarabiania zamiast tworzenia. */
.bf-dash-card.bf-dash-card--sell {
  background: var(--bf-gradient-brand);
  border-color: transparent;
}
.bf-dash-card.bf-dash-card--sell .bf-dash-card__icon { background: rgba(255, 255, 255, 0.2); border-color: transparent; color: #fff; }
.bf-dash-card.bf-dash-card--sell h3,
.bf-dash-card.bf-dash-card--sell p { color: #fff; }
.bf-dash-card.bf-dash-card--sell:hover { filter: brightness(1.08); border-color: transparent; box-shadow: 0 16px 40px -22px rgba(255, 122, 69, 0.6); }

.bf-empty-state {
  border: 1px dashed rgba(255, 255, 255, 0.15);
  border-radius: var(--bf-radius);
  padding: 48px 24px;
  text-align: center;
  color: var(--bf-text-300);
}
.bf-empty-state p { margin: 0 0 16px; }

/* ==========================================================================
   Poczekalnia (2026-08-29) — first real styling pass. The markup/classes
   (.bf-poczekalnia-card etc.) existed since 2026-08-28 but had zero CSS —
   owner explicitly wants to live on this page from his phone, so it gets
   the same card/field language as the rest of the account area instead of
   staying raw HTML.
   ========================================================================== */
.bf-notice { border-radius: 10px; padding: 14px 18px; margin-bottom: 24px; }
.bf-notice p { margin: 0; font-size: 14px; }
.bf-notice--success { background: rgba(74, 157, 111, 0.12); border: 1px solid rgba(74, 157, 111, 0.35); color: #8fd6ac; }
.bf-notice--error { background: rgba(211, 86, 63, 0.12); border: 1px solid rgba(211, 86, 63, 0.35); color: #f0a496; }

.bf-tabs { display: flex; gap: 8px; border-bottom: 1px solid rgba(255, 255, 255, 0.08); margin-bottom: 32px; }
.bf-tabs__item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 4px;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--bf-text-400);
  font-weight: 600;
  font-size: 15px;
}
.bf-tabs__item:hover { color: var(--bf-text-50); }
.bf-tabs__item.is-active { color: var(--bf-text-50); border-bottom-color: var(--bf-indigo); }
.bf-tabs__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  font-size: 12px;
  font-weight: 700;
}
.bf-tabs__item.is-active .bf-tabs__count { background: var(--bf-gradient-brand); color: var(--bf-bg-950); }

.bf-poczekalnia-section { margin-top: 40px; }
.bf-poczekalnia-section:first-of-type { margin-top: 0; }
.bf-poczekalnia-section__title { font-size: 18px; margin: 0 0 8px; }
.bf-poczekalnia-section__hint { margin: 0 0 16px; font-size: 13px; color: var(--bf-text-400); }

.bf-poczekalnia-list,
.bf-topic-queue-list { display: flex; flex-direction: column; gap: 16px; }

.bf-poczekalnia-card {
  display: flex;
  gap: 20px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  background: rgba(255, 255, 255, 0.02);
  padding: 20px;
}
.bf-poczekalnia-card__checkbox { flex: none; width: 16px; height: 16px; margin-top: 3px; }
@media (max-width: 640px) { .bf-poczekalnia-card { flex-direction: column; } }
.bf-poczekalnia-card__cover {
  flex: none;
  width: 120px;
  aspect-ratio: 3 / 4;
  border-radius: 10px;
  overflow: hidden;
  background: var(--bf-bg-800);
  display: flex;
  align-items: center;
  justify-content: center;
}
.bf-poczekalnia-card__cover img { width: 100%; height: 100%; object-fit: cover; }
.bf-poczekalnia-card__cover-placeholder { font-size: 12px; color: var(--bf-text-400); text-align: center; padding: 0 8px; }
.bf-poczekalnia-card__body { flex: 1; min-width: 0; }
.bf-poczekalnia-card__body h2 { font-size: 17px; margin: 0 0 6px; }
.bf-poczekalnia-card__meta { margin: 0 0 10px; font-size: 13px; color: var(--bf-text-400); }
.bf-poczekalnia-card__excerpt { margin: 0 0 10px; font-size: 14px; color: var(--bf-text-300); }
.bf-poczekalnia-card__toc { margin-bottom: 12px; font-size: 13px; color: var(--bf-text-300); }
.bf-poczekalnia-card__toc summary { cursor: pointer; color: var(--bf-text-50); font-weight: 600; }
.bf-poczekalnia-card__actions { display: flex; flex-wrap: wrap; gap: 10px; }
.bf-poczekalnia-card__actions .bf-btn { padding: 9px 18px; font-size: 13px; }

.bf-topic-queue-card {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  background: rgba(255, 255, 255, 0.02);
  padding: 20px;
}
.bf-topic-queue-card__row { display: flex; gap: 16px; justify-content: space-between; align-items: flex-start; }
.bf-topic-queue-card__checkbox { flex: none; width: 16px; height: 16px; margin-top: 3px; }
@media (max-width: 640px) { .bf-topic-queue-card__row { flex-direction: column; } }
.bf-topic-queue-card__main { flex: 1; min-width: 0; }
.bf-topic-queue-card__main h3 { font-size: 16px; margin: 0 0 6px; }
.bf-topic-queue-card__meta { margin: 0; font-size: 13px; color: var(--bf-text-400); }
.bf-topic-queue-card__rationale { margin: 8px 0 0; font-size: 13px; color: var(--bf-text-300); font-style: italic; }
.bf-topic-queue-card__actions { flex: none; display: flex; flex-wrap: wrap; gap: 10px; }
.bf-topic-queue-card__actions .bf-btn { padding: 9px 18px; font-size: 13px; }

.bf-topic-queue-card__edit { margin-top: 14px; padding-top: 14px; border-top: 1px solid rgba(255, 255, 255, 0.06); }
.bf-topic-queue-card__edit summary { cursor: pointer; color: var(--bf-text-300); font-size: 13px; font-weight: 600; }
.bf-topic-queue-edit-form { margin-top: 16px; display: grid; grid-template-columns: 1fr; gap: 4px 16px; }
@media (min-width: 640px) { .bf-topic-queue-edit-form { grid-template-columns: 1fr 1fr; } }
.bf-topic-queue-edit-form .bf-field:has(textarea) { grid-column: 1 / -1; }
.bf-topic-queue-edit-form button { grid-column: 1 / -1; justify-self: start; margin-top: 8px; }

/* ==========================================================================
   Library / ebooks
   ========================================================================== */
.bf-library-search {
  display: flex;
  gap: 10px;
  margin-top: 24px;
  margin-bottom: 20px;
  max-width: 480px;
}
.bf-library-search input[type="search"] {
  flex: 1;
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 14px;
  color: var(--bf-text-50);
  font-family: var(--bf-font-body);
}

.bf-library-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 32px;
}
.bf-library-filter {
  font-size: 13px;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: var(--bf-text-300);
}
.bf-library-filter.is-active {
  background: rgba(255, 122, 69, 0.15);
  border-color: rgba(255, 122, 69, 0.4);
  color: var(--bf-text-50);
}
/* Per-category product count on the Marketplace sidebar (owner asked,
   2026-08-28) — muted, so it reads as metadata, not a second label. */
.bf-library-filter__count { color: var(--bf-text-400); font-weight: 400; margin-left: 2px; }
.bf-library-filter.is-active .bf-library-filter__count { color: var(--bf-text-300); }

/* Marketplace pagination (2026-08-31, replaces the old per-category shelf
   stack — see archive-bf_product.php) */
.bf-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 32px;
}
.bf-pagination__status { font-size: 13px; color: var(--bf-text-400); }

/* Dashboard/Biblioteka/Moje ebooki cards shrunk (2026-08-28, owner: "za
   duże"). First pass just doubled the column count and left everything
   else full-size — looked broken live (huge stacked buttons, wrapping
   checkbox labels on a narrow card, wildly uneven card heights). This pass
   compacts the WHOLE card to match — buttons back to a row, the admin
   toggle block (Marketplace/Polecane/Kolejność/Edytuj, staff-only) shrunk
   throughout, not just its outer font-size — not just a narrower grid.
   :not(.bf-ebook-grid--compact) is deliberate: archive-bf_product.php's
   Marketplace grid carries BOTH "bf-ebook-grid" and "bf-ebook-grid--compact"
   on the same element (already independently sized, further down this
   file) — without this exclusion these rules would double-apply there too
   and fight the Marketplace-specific ones on source order. */
.bf-ebook-grid {
  display: grid;
  gap: 20px;
  grid-template-columns: 1fr;
}
.bf-ebook-grid:not(.bf-ebook-grid--compact) { gap: 14px; grid-template-columns: repeat(2, 1fr); }
@media (min-width: 640px) {
  .bf-ebook-grid { grid-template-columns: repeat(2, 1fr); }
  .bf-ebook-grid:not(.bf-ebook-grid--compact) { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 960px) {
  .bf-ebook-grid { grid-template-columns: repeat(3, 1fr); }
  .bf-ebook-grid:not(.bf-ebook-grid--compact) { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 1300px) {
  .bf-ebook-grid { grid-template-columns: repeat(4, 1fr); }
  .bf-ebook-grid:not(.bf-ebook-grid--compact) { grid-template-columns: repeat(5, 1fr); }
}
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__body { padding: 10px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__body h3 { font-size: 12px; line-height: 1.3; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__meta { font-size: 10px; margin-top: 4px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__badges { gap: 4px; margin-top: 6px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-status-badge,
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-format-badge { font-size: 9px; padding: 2px 6px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__actions { gap: 6px; margin-top: 10px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__actions .bf-btn { padding: 6px 4px; font-size: 11px; gap: 4px; flex: 1; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__actions .bf-btn svg { width: 12px; height: 12px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__pending { font-size: 10px; }

/* Admin toggle block (staff-only: Publikuj w Marketplace / Polecane /
   Kolejność / Edytuj) — the actual source of the "looks broken" complaint,
   not the grid itself: full-size checkboxes/labels/number input on a card
   this narrow wrapped onto multiple lines each. Shrunk throughout instead
   of just the block's own base font-size (inherited font-size alone
   doesn't shrink child inputs/checkboxes, which is exactly what stayed
   full-size and broke the layout the first time). */
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__admin { margin-top: 8px; padding-top: 8px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__marketplace-toggle label { font-size: 10px; gap: 5px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__marketplace-toggle input[type="checkbox"] { width: 12px; height: 12px; flex-shrink: 0; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__order-form label { font-size: 10px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__order-form input[type="number"] { width: 44px; padding: 3px 5px; font-size: 10px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__admin-links { margin-top: 6px; }
.bf-ebook-grid:not(.bf-ebook-grid--compact) .bf-ebook-card__admin-link { font-size: 10px; }

.bf-ebook-card {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
  overflow: hidden;
  background: rgba(255, 255, 255, 0.02);
}
.bf-ebook-card__cover {
  position: relative;
  aspect-ratio: 3 / 4;
  background: var(--bf-bg-800) center/cover no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Cover-missing placeholder — a subtle line icon (2026-08-26), not the
   keyboard emoji 📘 this used to be. Shared by product-card.php,
   ebook-card.php and single-bf_product.php (--lg modifier there). */
.bf-cover-placeholder { color: var(--bf-text-400); opacity: 0.5; }
.bf-cover-placeholder svg { width: 40px; height: 40px; }
.bf-cover-placeholder--lg svg { width: 64px; height: 64px; }
.bf-ebook-card__badge {
  position: absolute;
  top: 10px;
  left: 10px;
  background: var(--bf-gradient-brand);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 4px 10px;
  border-radius: 999px;
}
.bf-ebook-card__body { padding: 16px; }
.bf-ebook-card__body h3 { font-size: 15px; line-height: 1.4; margin: 0; }

/* ==========================================================================
   Marketplace product card — 3D "uchylona książka" (2026-09-18, owner
   request after visual review). Scoped to .bf-ebook-card--link — the
   modifier product-card.php already puts on its own root <a> — NOT the
   bare .bf-ebook-card ebook-card.php uses for Biblioteka/Moje
   ebooki/Dashboard. Those share the same base classes above but carry
   admin toggles, status badges and a "⋮" menu a 3D tilt would fight with,
   and 3D was only ever asked for the public catalog.
   ========================================================================== */
.bf-ebook-card--link {
  display: block;
  border: none;
  overflow: visible;
  background: none;
}
.bf-ebook-card--link .bf-ebook-card__cover {
  perspective: 1500px;
  margin-bottom: 22px;
  display: block;
  /* Ambientowa poświata — sugeruje, że książka stoi w oświetlonej scenie,
     nie na płaskiej czerni; bez tego cień poniżej nie ma na czym się
     odciąć. */
  background: radial-gradient(58% 55% at 34% 26%, rgba(140, 126, 230, 0.4) 0%, rgba(100, 90, 190, 0.14) 45%, transparent 78%);
  border-radius: 20px;
}
/* Jasna "podłoga" pod książką, potem ciemny kontaktowy cień nad nią (kolejność
   w kodzie nie ma znaczenia dzięki z-index, ale kontaktowy cień musi być
   węższy i mocniejszy niż poświata, żeby czytać się jako "dotyka podłoża"). */
.bf-ebook-card--link .bf-ebook-card__cover::after {
  content: "";
  position: absolute;
  left: 2%;
  right: -10%;
  bottom: -20px;
  height: 40px;
  background: radial-gradient(closest-side, rgba(180, 170, 235, 0.3) 0%, rgba(130, 120, 210, 0.12) 55%, transparent 80%);
  filter: blur(7px);
  z-index: 0;
}
.bf-ebook-card--link .bf-ebook-card__cover::before {
  content: "";
  position: absolute;
  left: 8%;
  right: 2%;
  bottom: -8px;
  height: 14px;
  background: radial-gradient(closest-side, rgba(8, 6, 16, 0.75) 0%, transparent 75%);
  filter: blur(3px);
  z-index: 0;
}
/* Sama okładka, przechylona w 3D — grzbiet (inset shadow), kartki widoczne
   z prawej i od góry (::after/::before poniżej), unosi się i prostuje na
   hover. */
.bf-ebook-card__cover-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  border-radius: 2px 6px 6px 2px;
  background: var(--bf-bg-800) center/cover no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: rotateY(38deg) rotateX(4deg);
  transform-style: preserve-3d;
  transform-origin: left center;
  box-shadow:
    inset 10px 0 18px -8px rgba(0, 0, 0, 0.8),
    26px 30px 46px -10px rgba(0, 0, 0, 0.65),
    0 14px 24px rgba(0, 0, 0, 0.4);
  transition: transform 0.45s var(--bf-ease), box-shadow 0.45s var(--bf-ease);
}
.bf-ebook-card--link:hover .bf-ebook-card__cover-inner {
  transform: rotateY(16deg) rotateX(2deg) translateY(-6px);
  box-shadow:
    inset 10px 0 18px -8px rgba(0, 0, 0, 0.8),
    10px 34px 50px -10px rgba(0, 0, 0, 0.65),
    0 18px 30px rgba(0, 0, 0, 0.4);
}
/* kartki — krawędź z prawej (grubość książki, bocznie) */
.bf-ebook-card__cover-inner::after {
  content: "";
  position: absolute;
  top: 1%;
  bottom: 1%;
  right: 0;
  width: 26px;
  background: repeating-linear-gradient(180deg, #f2ecdc 0 2px, #d7d1bc 2px 3px, #f2ecdc 3px 4px);
  transform: rotateY(90deg) translateZ(13px) translateX(13px);
  transform-origin: left center;
  border-radius: 0 2px 2px 0;
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.25);
}
/* kartki — krawędź od góry (grubość książki widziana z wierzchu) */
.bf-ebook-card__cover-inner::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 26px;
  background: repeating-linear-gradient(90deg, #f2ecdc 0 2px, #d7d1bc 2px 3px, #f2ecdc 3px 4px);
  transform: rotateX(-90deg) translateZ(13px) translateY(-13px);
  transform-origin: top center;
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.25);
}
/* Tytuł "wydrukowany" na okładce — prawdziwy tekst, nie dogenerowany
   obrazek, więc zawsze aktualny. Scrim od dołu robi miejsce pod tekst
   niezależnie od jasności zdjęcia pod spodem. */
.bf-ebook-card__cover-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  /* 2026-09-18 fix — 2 linii/14px ucinało większość realnych, opisowych
     tytułów w katalogu ("Archeologia Polski północno-..."), właściciel
     zgłosił na żywym zrzucie. Wyższy scrim + więcej linii + mniejsza
     czcionka, żeby tytuł faktycznie dawało się przeczytać, nie tylko
     zasugerować. */
  background: linear-gradient(to top, rgba(10, 8, 20, 0.95) 0%, rgba(10, 8, 20, 0.8) 42%, rgba(10, 8, 20, 0.15) 78%, transparent 100%);
}
/* 2026-09-19 — właściciel: "wszystkie napisy na okładkach powinny być
   mniejsze" (odwrotność do poprzedniej poprawki 2026-09-18 wyżej, ale inny
   problem: nie ucinanie tekstu, tylko zbyt duży wizualny "ciężar" napisu na
   wąskich kartach siatki Marketplace). Mniejsza czcionka + ten sam
   line-clamp 4 w praktyce mieści WIĘCEJ znaków niż poprzednio (krótsze
   linie przy tej samej szerokości), więc nie wraca problem ucinania. */
.bf-ebook-card__cover-title {
  position: absolute;
  left: 12px;
  right: 14px;
  bottom: 12px;
  z-index: 2;
  margin: 0;
  font-family: var(--bf-font-display);
  font-weight: 700;
  font-size: 10px;
  line-height: 1.3;
  color: #fff;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Malutkie logo-znak w rogu, jak "wytłoczone" na okładce — logo-mark.svg
   już istnieje w motywie. brightness(0) invert(1) wymusza biały bez
   względu na własne kolory pliku, żeby działało na dowolnym zdjęciu. */
.bf-ebook-card__cover-logo {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  width: 18px;
  height: 18px;
  opacity: 0.8;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6)) brightness(0) invert(1);
}
.bf-ebook-card--link .bf-ebook-card__badge { z-index: 2; }
.bf-ebook-card--link .bf-cover-placeholder { position: relative; z-index: 1; }
.bf-ebook-card--link .bf-ebook-card__body { padding: 0 4px; }

/* "⋮" card menu (2026-08-28, Biblioteka action-menu spec) */
.bf-ebook-card__title-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.bf-ebook-menu { position: relative; flex: none; }
.bf-ebook-menu__toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--bf-text-400);
  cursor: pointer;
}
.bf-ebook-menu__toggle:hover { background: rgba(255, 255, 255, 0.08); color: var(--bf-text-50); }
.bf-ebook-menu__toggle svg { width: 18px; height: 18px; }
.bf-ebook-menu__dropdown {
  position: absolute;
  top: 32px;
  right: 0;
  z-index: 5;
  display: none;
  flex-direction: column;
  min-width: 190px;
  padding: 6px;
  background: var(--bf-bg-800);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
/* :not([hidden]) rather than a bare "display: flex" above (2026-08-28 bug
   fix) — a class-based display rule always beats the browser's own
   [hidden]{display:none} default at equal specificity (author stylesheet
   wins over UA stylesheet, regardless of source order), so every dropdown
   was showing permanently and ignoring the hidden attribute JS was setting
   correctly. Confirmed live: all 4 card menus open at once, on page load,
   with no click at all. */
.bf-ebook-menu__dropdown:not([hidden]) { display: flex; }
.bf-ebook-menu__dropdown a,
.bf-ebook-menu__dropdown button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border-radius: 6px;
  border: none;
  background: none;
  color: var(--bf-text-50);
  font-size: 13px;
  font-family: var(--bf-font-body);
  cursor: pointer;
}
.bf-ebook-menu__dropdown a:hover,
.bf-ebook-menu__dropdown button:hover { background: rgba(255, 255, 255, 0.06); }
.bf-ebook-menu__dropdown form { margin: 0; }
.bf-ebook-menu__danger { color: var(--bf-danger); }

.bf-ebook-card__badges { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 8px; }
.bf-ebook-card__badges .bf-status-badge { margin-top: 0; }
.bf-status-badge--favorite { background: rgba(232, 168, 90, 0.15); color: #e8a85a; }
.bf-format-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--bf-text-300);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 3px 9px;
}
.bf-ebook-card__meta { margin: 6px 0 0; font-size: 12px; color: var(--bf-text-400); }
.bf-ebook-card__actions { display: flex; gap: 8px; margin-top: 14px; }
.bf-ebook-card__actions .bf-btn { padding: 8px 14px; font-size: 13px; }
.bf-ebook-card__actions .bf-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
.bf-ebook-card__pending { font-size: 12px; color: var(--bf-text-400); font-style: italic; }
.bf-ebook-card__admin {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.bf-ebook-card__marketplace-toggle { margin-top: 0; }
.bf-ebook-card__marketplace-toggle label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--bf-text-400);
  cursor: pointer;
}
.bf-ebook-card__order-form { margin-top: 8px; }
.bf-ebook-card__order-form label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 12px;
  color: var(--bf-text-400);
}
.bf-ebook-card__order-form input[type="number"] {
  width: 64px;
  background: var(--bf-bg-900);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px;
  padding: 5px 8px;
  font-size: 12px;
  color: var(--bf-text-50);
}
.bf-ebook-card__admin-links {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 10px;
}
.bf-ebook-card__admin-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 600;
  color: var(--bf-blue);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font-family: var(--bf-font-body);
}
.bf-ebook-card__admin-link svg { width: 13px; height: 13px; flex-shrink: 0; }
.bf-ebook-card__admin-link:hover { text-decoration: underline; }
.bf-ebook-card__admin-link--danger { color: var(--bf-danger); }

.bf-status-badge {
  display: inline-block;
  margin-top: 8px;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
}
/* Amber, not the neutral gray this used to be (2026-08-28) — spec's status
   legend is explicit that "Oczekuje" reads as orange, distinct from
   "Generowanie" (blue) and "Gotowe" (green). Literal hex, not the protected
   --bf-ember token (that one's scoped to the pipeline spark animation only,
   see its own comment above in :root) — same amber hue, kept as a separate
   declaration so nothing outside this rule depends on --bf-ember's scope. */
.bf-status-badge--queued { background: rgba(232, 168, 90, 0.15); color: #e8a85a; }
.bf-status-badge--generating { background: rgba(255, 182, 72, 0.12); color: var(--bf-blue); }
.bf-status-badge--completed { background: rgba(74, 157, 111, 0.15); color: var(--bf-success); }
.bf-status-badge--dispatch_failed { background: rgba(211, 86, 63, 0.15); color: var(--bf-danger); }
.bf-status-badge--rejected { background: rgba(211, 86, 63, 0.1); color: var(--bf-text-400); }
/* bf_order statuses (template-zamowienia.php) — same amber/green/red
   language as the ebook statuses above, just a different status vocabulary. */
.bf-status-badge--pending { background: rgba(232, 168, 90, 0.15); color: #e8a85a; }
.bf-status-badge--paid { background: rgba(74, 157, 111, 0.15); color: var(--bf-success); }
.bf-status-badge--failed { background: rgba(211, 86, 63, 0.15); color: var(--bf-danger); }

/* Rozliczenia autorów (2026-09-18) — bf_order_author_earning_status, klucze
   lowercase (template-rozliczenia.php robi strtolower() przed użyciem jako
   klasa CSS). */
.bf-status-badge--earned { background: rgba(232, 168, 90, 0.15); color: #e8a85a; }
.bf-status-badge--claimed_for_payout { background: rgba(255, 182, 72, 0.12); color: var(--bf-blue); }
.bf-status-badge--paid_out { background: rgba(74, 157, 111, 0.15); color: var(--bf-success); }
.bf-status-badge--cancelled { background: rgba(211, 86, 63, 0.1); color: var(--bf-text-400); }

/* Zamówienia list (2026-09-02) */
.bf-orders-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: 760px;
  margin-bottom: 14px;
}
.bf-orders-toolbar__select-all {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--bf-text-300);
  cursor: pointer;
}
.bf-orders-list { display: flex; flex-direction: column; gap: 10px; max-width: 760px; }
.bf-order-row__checkbox,
.bf-order-row__checkbox-spacer { flex: none; width: 16px; height: 16px; }
.bf-order-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  padding: 16px 18px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--bf-radius);
}
.bf-order-row__main { flex: 1; min-width: 180px; }
.bf-order-row__title { margin: 0; font-size: 14px; font-weight: 600; color: var(--bf-text-50); }
.bf-order-row__meta { margin: 4px 0 0; font-size: 12px; color: var(--bf-text-400); }
.bf-order-row .bf-status-badge { margin-top: 0; }
.bf-order-row__amount { font-size: 14px; font-weight: 700; color: var(--bf-text-50); white-space: nowrap; }

.bf-ebook-card--link { display: block; position: relative; transition: transform 0.15s ease, border-color 0.15s ease; }
.bf-ebook-card--link:hover { transform: translateY(-2px) scale(1.03); border-color: rgba(255, 122, 69, 0.4); }
.bf-ebook-card__price { margin: 10px 0 0; font-family: var(--bf-font-display); font-size: 18px; }
.bf-ebook-card__price span { font-size: 12px; color: var(--bf-text-400); font-family: var(--bf-font-body); }

/* Marketplace card readability (2026-08-28, section 6) — long titles no
   longer stretch card height unpredictably; clamped at 3 lines with a real
   ellipsis, full title still lives on the product's own page. */
.bf-ebook-card__title--clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Pełny temat na hover (2026-09-19, poprawka tego samego dnia — pierwsza
   wersja pozycjonowała dymek POD kartą, absolutnie, i przy małym odstępie
   między wierszami siatki wjeżdżał na kartę z NASTĘPNEGO rzędu, zasłaniając
   inny produkt. Naprawione: nakładka teraz żyje W GRANICACH samej karty
   (.bf-ebook-card__body, position:relative niżej), nigdy nie wychodzi poza
   nią, więc fizycznie nie może zasłonić sąsiedniej karty.) Pojawia się na
   hover całej karty, wypełnia obszar pod okładką ciemnym tłem z pełnym,
   niezawijanym-a-obciętym tekstem. */
.bf-ebook-card--link .bf-ebook-card__body { position: relative; }
.bf-ebook-card__full-topic {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
  padding: 12px;
  border-radius: 10px;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.15s ease, visibility 0.15s;
  background: rgba(10, 8, 20, 0.96);
  border: 1px solid rgba(255, 122, 69, 0.4);
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--bf-text-50);
}
.bf-ebook-card--link:hover .bf-ebook-card__full-topic {
  opacity: 1;
  visibility: visible;
}
.bf-ebook-card__details-link { display: block; margin-top: 8px; font-size: 12px; font-weight: 600; color: var(--bf-indigo); }
.bf-ebook-card__badge--new { background: var(--bf-success); }

/* "Polecane" carousel (template-parts/featured-spotlight.php, rebuilt
   2026-08-31) — premium treatment: animated gradient border + glow "frame"
   around the whole carousel, one full-bleed slide at a time, dot navigation
   below. A lone card previously read as an accident, not a deliberate
   editorial pick; the frame + motion now makes "we chose this on purpose"
   unmistakable instead. */
.bf-shelf--featured .bf-featured-carousel {
  position: relative;
  padding: 2px;
  border-radius: calc(var(--bf-radius) + 3px);
  background: linear-gradient(135deg, rgba(255, 122, 69, 0.75), rgba(255, 182, 72, 0.6), rgba(255, 95, 109, 0.75));
  background-size: 200% 200%;
  box-shadow: 0 24px 64px -24px rgba(255, 122, 69, 0.55);
  animation: bf-featured-frame-glow 6s ease-in-out infinite;
}
@keyframes bf-featured-frame-glow {
  0%, 100% { background-position: 0% 50%; box-shadow: 0 24px 64px -24px rgba(255, 122, 69, 0.55); }
  50% { background-position: 100% 50%; box-shadow: 0 24px 72px -18px rgba(255, 182, 72, 0.55); }
}
@media (prefers-reduced-motion: reduce) {
  .bf-shelf--featured .bf-featured-carousel { animation: none; }
}

.bf-featured-carousel__track {
  position: relative;
  border-radius: calc(var(--bf-radius) + 1px);
  overflow: hidden;
  /* One continuous surface for the card AND the dots strip below it — this
     used to be a flat var(--bf-bg-950) here with the card's own lighter
     gradient painted on top only for its own box, which left an ugly hard
     seam exactly at the card's bottom edge, right above the dots (owner
     screenshot, 2026-08-31). Card and dots bar now go transparent and let
     this one gradient show through both, edge to edge. */
  background: linear-gradient(135deg, rgba(255, 122, 69, 0.14), rgba(255, 182, 72, 0.07)), var(--bf-bg-950);
}

.bf-featured-spotlight {
  display: none;
  grid-template-columns: 200px 1fr;
  gap: 24px;
  padding: 24px;
  background: transparent;
  opacity: 1;
  transition: opacity 0.3s ease;
}
.bf-featured-spotlight.is-active { display: grid; }
.bf-featured-spotlight.is-leaving { opacity: 0; }
@media (max-width: 560px) { .bf-featured-spotlight { grid-template-columns: 1fr; } }
.bf-featured-spotlight__cover {
  aspect-ratio: 3 / 4;
  border-radius: 10px;
  background: var(--bf-bg-800);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 12px 30px -10px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}
.bf-featured-spotlight__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.bf-featured-spotlight__body { display: flex; flex-direction: column; }
.bf-featured-spotlight__reason { margin: 0 0 8px; font-size: 13px; font-style: italic; color: var(--bf-text-300); }
.bf-featured-spotlight__body h4 { margin: 0; font-size: 20px; }
.bf-featured-spotlight__excerpt { margin: 10px 0 0; font-size: 13px; color: var(--bf-text-300); max-width: 60ch; }
.bf-featured-spotlight__body .bf-btn { align-self: flex-start; margin-top: 16px; }

.bf-featured-carousel__dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  padding: 14px 0 18px;
  background: transparent;
}
.bf-featured-carousel__dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  cursor: pointer;
  transition: all 0.25s var(--bf-ease);
}
.bf-featured-carousel__dot:hover { background: rgba(255, 255, 255, 0.4); }
.bf-featured-carousel__dot.is-active {
  width: 26px;
  background: var(--bf-gradient-brand);
}

.bf-btn--disabled, .bf-btn--disabled:hover { opacity: 0.5; cursor: not-allowed; transform: none; }

/* Submit loading state (assets/js/site.js) — spinner sits in the button's
   existing flex gap before the (JS-swapped) label text, no layout shift. */
.bf-btn.is-loading, .bf-btn.is-loading:hover { opacity: 0.75; cursor: wait; transform: none; }
.bf-btn.is-loading::before {
  content: "";
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: bf-spin 0.7s linear infinite;
}
@keyframes bf-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .bf-btn.is-loading::before { animation: none; }
}

/* ==========================================================================
   Marketplace — strona produktu (single-bf_product.php)
   ========================================================================== */
.bf-product-single__breadcrumb { font-size: 13px; color: var(--bf-text-400); margin: 0 0 28px; }
.bf-product-single__breadcrumb a { color: var(--bf-text-300); }
.bf-product-single__breadcrumb a:hover { color: var(--bf-blue); }

.bf-product-single__hero { display: grid; grid-template-columns: 1fr; gap: 32px; }
@media (min-width: 860px) { .bf-product-single__hero { grid-template-columns: 340px 1fr; } }

.bf-product-single__cover {
  aspect-ratio: 3 / 4;
  border-radius: var(--bf-radius);
  background: var(--bf-bg-800);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.08);
  overflow: hidden;
}

/* Prawdziwy <img> zamiast CSS background-image (2026-10-02, Google Image
   Search) — kontener wyżej dalej pilnuje proporcji/zaokrąglenia, obrazek
   tylko wypełnia go tak jak wcześniej background-size:cover. */
.bf-product-single__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.bf-product-single__info h1 { margin: 14px 0 0; font-size: 30px; }
.bf-product-single__excerpt { margin: 14px 0 0; color: var(--bf-text-300); font-size: 16px; line-height: 1.6; }
.bf-product-single__info .bf-formats { margin-top: 20px; }

/* Mobile CRO (2026-10-01, znalezione na żywo telefonem: okładka w proporcji
   3:4 na pełną szerokość ekranu + duży H1 zajmowały ~3 ekrany przewijania,
   zanim była widoczna cena i "Kup teraz" — klasyczny błąd, treść decyzyjna
   wypchnięta poniżej zrzutu ekranu. WYŁĄCZNIE poniżej 860px (ten sam próg co
   przełączenie na jedną kolumnę wyżej) — desktop (dwie kolumny, okładka i
   cena obok siebie) bez zmian. Okładka dostaje stałą, niższą wysokość
   zamiast proporcji 3:4 — nadal background:center/cover (reguła wyżej), więc
   po prostu pokazuje środek obrazu zamiast całego kadru. */
@media (max-width: 859px) {
  .bf-product-single__cover { aspect-ratio: unset; height: 200px; }
  .bf-product-single__info h1 { font-size: 24px; }
}

.bf-product-single__price-row { margin-top: 28px; display: flex; flex-wrap: wrap; gap: 24px; align-items: stretch; }
.bf-product-single__price-box {
  padding: 20px;
  width: 320px;
  max-width: 100%;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--bf-radius);
  background: rgba(255, 255, 255, 0.02);
}
.bf-product-single__price { margin: 0 0 16px; font-family: var(--bf-font-display); font-size: 30px; }
.bf-product-single__price span { font-size: 14px; color: var(--bf-text-400); font-family: var(--bf-font-body); }
.bf-product-single__cta-note { margin: 10px 0 0; font-size: 12px; color: var(--bf-text-400); text-align: center; }

/* "Nie znaleziles idealnego tematu?" hero promo (2026-09-16, owner: fills the
   empty space beside the price box on wide screens, must visibly "glow" so
   it reads as a real second option, not filler). flex:1 so it only appears
   once .bf-product-single__price-row actually has spare width to give it —
   wraps below the price box on narrower screens instead of squeezing. */
.bf-product-single__generate-promo {
  flex: 1 1 280px;
  position: relative;
  padding: 24px 22px;
  border-radius: var(--bf-radius);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background:
    radial-gradient(120% 140% at 50% 0%, rgba(255, 122, 69, 0.22) 0%, rgba(255, 182, 72, 0.08) 45%, rgba(20, 18, 31, 0) 75%),
    var(--bf-bg-900);
  border: 1px solid rgba(255, 95, 109, 0.35);
  box-shadow: 0 0 0 1px rgba(255, 122, 69, 0.08), 0 0 32px 4px rgba(255, 122, 69, 0.28), 0 0 64px 12px rgba(255, 182, 72, 0.12);
  animation: bf-generate-promo-glow 3.2s ease-in-out infinite;
}
.bf-product-single__generate-promo-spark { font-size: 20px; color: var(--bf-blue); }
.bf-product-single__generate-promo h3 { margin: 0; font-size: 18px; }
.bf-product-single__generate-promo p { margin: 0 0 6px; color: var(--bf-text-300); font-size: 13.5px; line-height: 1.5; max-width: 30ch; }
@keyframes bf-generate-promo-glow {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255, 122, 69, 0.08), 0 0 32px 4px rgba(255, 122, 69, 0.28), 0 0 64px 12px rgba(255, 182, 72, 0.12); }
  50% { box-shadow: 0 0 0 1px rgba(255, 122, 69, 0.14), 0 0 44px 8px rgba(255, 122, 69, 0.4), 0 0 84px 18px rgba(255, 182, 72, 0.2); }
}
@media (prefers-reduced-motion: reduce) {
  .bf-product-single__generate-promo { animation: none; }
}

.bf-product-single__columns { display: grid; grid-template-columns: 1fr; gap: 40px; margin-top: 56px; }
@media (min-width: 860px) { .bf-product-single__columns { grid-template-columns: 1.6fr 1fr; } }
.bf-product-single__description :is(h2), .bf-product-single__toc h2, .bf-product-single__details h2, .bf-product-single__related h2 { font-size: 20px; margin: 0 0 16px; }
.bf-product-single__description { color: var(--bf-text-300); font-size: 15px; line-height: 1.7; }
.bf-product-single__toc ol { margin: 0; padding-left: 20px; color: var(--bf-text-300); font-size: 14px; line-height: 2; }

.bf-product-single__details { margin-top: 48px; padding-top: 32px; border-top: 1px solid rgba(255, 255, 255, 0.08); }
.bf-product-single__details dl { display: grid; grid-template-columns: auto 1fr; gap: 10px 20px; margin: 0; max-width: 480px; }
.bf-product-single__details dt { color: var(--bf-text-400); font-size: 14px; }
.bf-product-single__details dd { margin: 0; font-size: 14px; }

.bf-product-single__related { margin-top: 56px; padding-top: 32px; border-top: 1px solid rgba(255, 255, 255, 0.08); }

/* ==========================================================================
   Marketplace shelves (template-parts/product-shelf.php) — Netflix-style
   horizontally-scrolling rows on archive-bf_product.php's default browse
   view. Scrolling is plain CSS (overflow-x + scroll-snap); the arrow
   buttons are progressive enhancement (assets/js/marketplace-shelf.js).
   ========================================================================== */
.bf-shelf {
	width: 100%;
	max-width: var(--bf-container);
	margin: 40px auto 0;
	padding: 0 24px;
}
.bf-shelf:first-of-type { margin-top: 32px; }

.bf-shelf__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 16px;
}
.bf-shelf__header h3 { font-size: 20px; margin: 0; }

.bf-shelf__arrows { display: flex; gap: 8px; }
.bf-shelf__arrow {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border-radius: 999px;
	border: 1px solid rgba(255, 255, 255, 0.15);
	background: rgba(255, 255, 255, 0.04);
	color: var(--bf-text-50);
	cursor: pointer;
	transition: border-color 0.2s var(--bf-ease), background 0.2s var(--bf-ease);
}
.bf-shelf__arrow svg { width: 18px; height: 18px; }
.bf-shelf__arrow:hover { border-color: var(--bf-indigo); background: rgba(255, 122, 69, 0.12); }

.bf-shelf__track {
	display: flex;
	gap: 16px;
	overflow-x: auto;
	scroll-snap-type: x proximity;
	scroll-behavior: smooth;
	padding-bottom: 8px;
	scrollbar-width: none;
}
.bf-shelf__track::-webkit-scrollbar { display: none; }

/* Homepage "Najnowsze w Marketplace" teaser shrunk (2026-08-29, owner: "za
   duże") — this is the only place .bf-shelf__item still renders today
   (archive-bf_product.php's own shelves switched to a wrapping grid
   earlier, 2026-08-28), so no extra scoping needed here. Card body scaled
   down to match the narrower tile, same approach as the Biblioteka fix
   earlier today. */
.bf-shelf__item { flex: 0 0 auto; width: 110px; scroll-snap-align: start; }
@media (min-width: 640px) { .bf-shelf__item { width: 130px; } }
.bf-shelf__item .bf-ebook-card__body { padding: 10px; }
.bf-shelf__item .bf-ebook-card__body h3 { font-size: 12px; line-height: 1.3; }
.bf-shelf__item .bf-ebook-card__meta { font-size: 10px; }
.bf-shelf__item .bf-ebook-card__price { font-size: 13px; margin-top: 6px; }
.bf-shelf__item .bf-ebook-card__price span { font-size: 10px; }
.bf-shelf__item .bf-ebook-card__details-link { font-size: 10px; margin-top: 4px; }
.bf-shelf__item .bf-ebook-card__badge { font-size: 9px; padding: 3px 8px; top: 6px; left: 6px; }

/* ==========================================================================
   Marketplace page furniture (archive-bf_product.php) — self-editable
   banner + promo tile row (inc/marketplace-promo.php) and the left category
   sidebar, 2026-08-28 (Empik-style layout, owner's reference).
   ========================================================================== */
/* Fixed height, not height:auto (2026-08-30 mobile fix) — with height:auto
   this wide (~1400×360) banner image shrank to ~90px tall on a narrow
   phone viewport (width:100% at ~360px wide, same aspect ratio), leaving
   the absolutely-positioned text overlay and corner logo below almost no
   room and colliding with each other — confirmed live from an owner
   screenshot. A fixed height + object-fit:cover on the image (crops the
   sides instead of shrinking the whole banner) keeps the overlay's
   available space constant regardless of viewport width. */
.bf-marketplace-banner {
	position: relative;
	display: block;
	margin: 24px 0 0;
	border-radius: var(--bf-radius);
	overflow: hidden;
	height: 200px;
}
@media (min-width: 640px) { .bf-marketplace-banner { height: 320px; } }
/* Dedicated class, not a bare ">img" child selector (2026-08-28 bug fix) —
   .bf-marketplace-banner has TWO direct-child <img> elements (this
   background photo AND .bf-marketplace-banner__logo). A tag+class selector
   here outranks a single-class selector in specificity regardless of
   source order, so the logo was silently inheriting width:100%/height:auto
   from this rule instead of its own 130px — confirmed live (owner
   screenshot: logo ballooned to nearly the full banner width). */
.bf-marketplace-banner__bg { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Text/logo overlay (2026-08-28) — real HTML, not baked into the image, so
   the owner can reword it any time from the Baner settings screen without
   asking for a new graphic. Scrim is a left-to-transparent gradient (not a
   flat dark layer over the whole image) so the artwork on the right stays
   visible while the text on the left stays legible over any banner image. */
/* 2026-09-18 — tinted with brand indigo (was flat neutral black), so the
   scrim itself ties any future banner photo to the palette instead of
   reading as a generic dark overlay unrelated to the rest of the site
   (owner feedback: banner felt "disconnected" from the hero). Same
   left-to-transparent shape as before, just brand-colored. */
.bf-marketplace-banner__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(100deg, rgba(26, 20, 51, 0.92) 0%, rgba(35, 26, 66, 0.62) 45%, rgba(35, 26, 66, 0.08) 80%);
}
.bf-marketplace-banner__content {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 10px;
	padding: 20px 24px;
	max-width: 480px;
}
/* Bottom-right, large and deliberate (owner asked twice, 2026-08-28 — first
   attempt at 22px/top-left read as an afterthought) — pulled out of
   .bf-marketplace-banner__content (which stays left-aligned for the text
   stack) into its own absolutely-positioned corner element. */
.bf-marketplace-banner__logo {
	position: absolute;
	right: 24px;
	bottom: 20px;
	height: 130px;
	width: auto;
	opacity: 0.95;
	filter: drop-shadow(0 4px 24px rgba(0, 0, 0, 0.5));
}
@media (max-width: 640px) { .bf-marketplace-banner__logo { height: 70px; right: 16px; bottom: 14px; } }
/* 2026-09-18 — switched from the flat --bf-danger red (a "sale" color the
   owner explicitly did NOT want to imply, see docblock above — this badge
   just happened to reuse it for shape, not meaning) to the same brand
   gradient every other accent pill/badge on the site uses
   (.bf-ebook-card__badge, hero CTA). Red read as a discount sticker next to
   a purple/blue site; this reads as the same brand instead. */
.bf-marketplace-banner__badge {
	display: inline-block;
	align-self: flex-start;
	background: var(--bf-gradient-brand);
	color: #fff;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.04em;
	padding: 4px 10px;
	border-radius: 999px;
}
.bf-marketplace-banner__headline {
	margin: 0;
	font-size: 22px;
	line-height: 1.25;
	color: #fff;
}
/* Reuses the hero's animated gradient-clip text (.bf-gradient-text,
   defined near the top of this file) instead of a second, separate
   treatment — same signature effect as "gotowego ebooka lub książki" on
   the homepage, now on the banner too (2026-09-18, visual cohesion fix). */
.bf-marketplace-banner__headline.bf-gradient-text { color: transparent; }
.bf-marketplace-banner__subtext {
	margin: 0;
	font-size: 13px;
	color: var(--bf-text-300);
}
@media (min-width: 640px) {
	.bf-marketplace-banner__content { padding: 28px 40px; }
	.bf-marketplace-banner__headline { font-size: 28px; }
	.bf-marketplace-banner__subtext { font-size: 15px; }
}

.bf-promo-row {
	display: flex;
	gap: 20px;
	overflow-x: auto;
	margin-top: 20px;
	padding-bottom: 8px;
	scrollbar-width: none;
}
.bf-promo-row::-webkit-scrollbar { display: none; }
.bf-promo-tile {
	flex: 0 0 auto;
	width: 92px;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	text-align: center;
}
.bf-promo-tile__icon {
	width: 72px;
	height: 72px;
	border-radius: 999px;
	background: var(--bf-bg-800) center/cover no-repeat;
	border: 1px solid rgba(255, 255, 255, 0.08);
}
.bf-promo-tile__label { font-size: 12px; color: var(--bf-text-300); line-height: 1.3; }

.bf-marketplace-layout {
	display: block;
	margin-top: 24px;
}
.bf-marketplace-sidebar {
	display: flex;
	gap: 8px;
	overflow-x: auto;
	margin-bottom: 24px;
	padding-bottom: 8px;
	scrollbar-width: none;
}
.bf-marketplace-sidebar::-webkit-scrollbar { display: none; }
.bf-marketplace-sidebar .bf-library-filter { flex: 0 0 auto; }

@media (min-width: 900px) {
	.bf-marketplace-layout { display: grid; grid-template-columns: 200px 1fr; gap: 32px; align-items: start; }
	.bf-marketplace-sidebar {
		flex-direction: column;
		align-items: stretch;
		overflow-x: visible;
		margin-bottom: 0;
		position: sticky;
		top: 24px;
	}
	.bf-marketplace-sidebar .bf-library-filter { text-align: left; }
}
/* A grid item defaults to min-width:auto, which refuses to shrink below its
   CONTENT's intrinsic minimum — with a horizontally-scrolling flex track
   inside (the old shelf layout), that content has no real minimum, so the
   whole .bf-marketplace-content column (and the page with it) blew out
   wider than the viewport, pushing the sidebar out of view (live bug found
   2026-08-28, confirmed by the owner's own screenshot). Explicit min-width:0
   is the standard fix — lets the column actually respect the grid track's
   width instead of its content's. Kept even after switching the shelves to
   a wrapping grid (below) as correct defensive practice, not just a patch
   for the old layout. */
.bf-marketplace-content { min-width: 0; }

/* Shelves render inside .bf-marketplace-content now (nested in the content
   column, not full-bleed across the page like front-page.php's own shelf
   usage) — drop the standalone centering/padding (owner asked for smaller
   cards too, 2026-08-28 — handled via .bf-ebook-grid--compact below, since
   .bf-shelf--grid shelves now render that instead of the old scroll track).
   Scoped to this container so front-page.php's shelves are untouched. */
.bf-marketplace-content .bf-shelf { max-width: none; margin: 32px 0 0; padding: 0; }
.bf-marketplace-content .bf-shelf:first-of-type { margin-top: 0; }
/* Extra breathing room below "Polecane" before the plain product grid starts
   right underneath it (owner, 2026-09-02: felt cramped) — the carousel's own
   glow/border already gives it visual weight, it needs space to read as its
   own section rather than bumping straight into the grid. */
.bf-marketplace-content .bf-shelf--featured { margin-bottom: 40px; }

/* .bf-shelf--grid (template-parts/product-shelf.php, layout:'grid') — the
   owner explicitly does not want a horizontal scrollbar on the actual
   Marketplace page (2026-08-28): every shelf there wraps in rows instead of
   scrolling sideways, via the same .bf-ebook-grid--compact used by the
   filtered/search results below. No .bf-shelf__track/.bf-shelf__item rules
   apply here — grid layout renders .bf-ebook-grid directly, arrows are
   simply not output for this layout (see product-shelf.php). */

.bf-ebook-grid--compact { grid-template-columns: repeat(2, 1fr); }
@media (min-width: 640px) { .bf-ebook-grid--compact { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 960px) { .bf-ebook-grid--compact { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1300px) { .bf-ebook-grid--compact { grid-template-columns: repeat(5, 1fr); } }
.bf-marketplace-content .bf-ebook-card__body { padding: 12px; }
.bf-marketplace-content .bf-ebook-card__body h3 { font-size: 13px; }
.bf-marketplace-content .bf-ebook-card__price { font-size: 15px; }

/* ==========================================================================
   Panel admina (template-panel-admina.php) — branded equivalent of the
   wp-admin dashboard widget (inc/admin-dashboard.php), same data
   (inc/dashboard-stats.php), on-brand markup instead of wp-admin chrome.
   ========================================================================== */
.bf-stats-section { margin-top: 40px; }
.bf-stats-section h2 { font-size: 18px; margin: 0 0 16px; }

.bf-stats-cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
	gap: 16px;
}
.bf-stats-card {
	border: 1px solid rgba(255, 255, 255, 0.08);
	border-radius: var(--bf-radius);
	background: rgba(255, 255, 255, 0.02);
	padding: 18px;
}
.bf-stats-card__label { display: block; font-size: 13px; color: var(--bf-text-400); }
.bf-stats-card__value { display: block; margin-top: 6px; font-family: var(--bf-font-display); font-size: 28px; }
.bf-stats-card--placeholder .bf-stats-card__value { color: var(--bf-text-400); }

/* Money KPI cards (owner, 2026-09-23): animated glowing border, one colour
   per meaning — przychód niebieski, koszt AI czerwony, zysk jaskrawa
   zieleń, sprzedaż stonowana zieleń. --bf-glow is an "r, g, b" triplet so
   the same colour feeds the border, the halo and the value's text glow.
   The border is a rotating conic gradient painted on border-box under an
   opaque padding-box layer; @property makes the angle animatable. */
@property --bf-glow-angle {
	syntax: '<angle>';
	inherits: false;
	initial-value: 0deg;
}
.bf-stats-card--glow {
	--bf-glow: 59, 155, 255;
	position: relative;
	border: 1.5px solid transparent;
	background:
		linear-gradient(160deg, rgba(var(--bf-glow), 0.16), rgba(var(--bf-glow), 0.03) 65%) padding-box,
		linear-gradient(var(--bf-bg-900), var(--bf-bg-900)) padding-box,
		conic-gradient(
			from var(--bf-glow-angle),
			rgba(var(--bf-glow), 0.2),
			rgba(var(--bf-glow), 1) 20%,
			rgba(var(--bf-glow), 0.2) 45%,
			rgba(var(--bf-glow), 0.85) 70%,
			rgba(var(--bf-glow), 0.2)
		) border-box;
	box-shadow:
		0 0 22px -6px rgba(var(--bf-glow), 0.55),
		0 0 48px -18px rgba(var(--bf-glow), 0.6),
		inset 0 0 28px -16px rgba(var(--bf-glow), 0.7);
	animation: bf-glow-spin 5s linear infinite;
	transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.bf-stats-card--glow:hover {
	transform: translateY(-2px);
	box-shadow:
		0 0 28px -4px rgba(var(--bf-glow), 0.7),
		0 0 64px -16px rgba(var(--bf-glow), 0.75),
		inset 0 0 32px -14px rgba(var(--bf-glow), 0.8);
}
.bf-stats-card--glow .bf-stats-card__label {
	color: rgba(var(--bf-glow), 0.95);
	font-weight: 600;
	letter-spacing: 0.02em;
}
.bf-stats-card--glow .bf-stats-card__value,
.bf-stats-card--glow.bf-stats-card--placeholder .bf-stats-card__value {
	color: rgb(var(--bf-glow));
	text-shadow: 0 0 16px rgba(var(--bf-glow), 0.6);
}
.bf-stats-card--revenue { --bf-glow: 59, 155, 255; }  /* niebieski */
.bf-stats-card--cost    { --bf-glow: 255, 64, 84; }   /* czerwony */
.bf-stats-card--profit  { --bf-glow: 57, 255, 20; }   /* jaskrawa zieleń (neon) */
.bf-stats-card--sales   { --bf-glow: 74, 222, 128; }  /* zieleń stonowana */
.bf-stats-card--claude  { --bf-glow: 255, 140, 26; }  /* pomarańcz — kafelek Claude */
@keyframes bf-glow-spin {
	to { --bf-glow-angle: 360deg; }
}
@media (prefers-reduced-motion: reduce) {
	.bf-stats-card--glow { animation: none; transition: none; }
	.bf-stats-card--glow:hover { transform: none; }
}

.bf-stats-note { margin: 10px 0 0; font-size: 12px; color: var(--bf-text-400); }

.bf-stats-bar-chart {
	display: flex;
	align-items: flex-end;
	gap: 6px;
	height: 160px;
	margin-top: 4px;
	overflow-x: auto;
	padding-bottom: 4px;
}
.bf-stats-bar-chart__col { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; min-width: 30px; flex: 1; height: 100%; }
.bf-stats-bar-chart__bar { width: 100%; min-height: 2px; background: var(--bf-gradient-brand); border-radius: 4px 4px 0 0; }
.bf-stats-bar-chart__count { font-size: 11px; font-weight: 600; margin-top: 4px; }
.bf-stats-bar-chart__label { font-size: 10px; color: var(--bf-text-400); margin-top: 2px; white-space: nowrap; }

.bf-stats-hbar-list { display: flex; flex-direction: column; gap: 10px; }
.bf-stats-hbar-row { display: grid; grid-template-columns: 140px 1fr 40px; align-items: center; gap: 10px; }
.bf-stats-hbar-row__label { font-size: 13px; }
.bf-stats-hbar-row__track { background: var(--bf-bg-800); border-radius: 6px; height: 10px; overflow: hidden; }
.bf-stats-hbar-row__fill { height: 100%; background: var(--bf-gradient-brand); }
.bf-stats-hbar-row__count { font-size: 12px; text-align: right; color: var(--bf-text-400); }

.bf-stats-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.bf-stats-table th, .bf-stats-table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.06); white-space: nowrap; }
.bf-stats-table th { color: var(--bf-text-400); font-weight: 600; font-size: 12px; }

/* Panel Admina expansion (2026-08-28) — wide tables (Użytkownicy, Wszystkie
   generowania) scroll horizontally inside their own box instead of blowing
   out the page on mobile (section 18's explicit requirement). */
.bf-stats-table-scroll { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }
/* Mobile safety net (2026-09-25): long UTM links / codes wrap instead of
   widening the whole Panel Admina page past the phone screen. */
.bf-stats-card code, .bf-utm-builder code { white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-all; }
.bf-stats-section, .bf-utm-builder, .bf-utm-builder label { min-width: 0; max-width: 100%; }
.bf-utm-builder input, .bf-utm-builder select { max-width: 100%; box-sizing: border-box; }
.bf-stats-section__header-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.bf-stats-section__header-row h2 { margin: 0; }

/* ==========================================================================
   Footer
   ========================================================================== */
.bf-footer {
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  padding: 48px 0;
}

.bf-footer__inner {
  display: flex;
  flex-direction: column;
  gap: 20px;
  justify-content: space-between;
}

@media (min-width: 640px) {
  .bf-footer__inner { flex-direction: row; align-items: flex-start; }
}

.bf-footer__tagline {
  margin: 12px 0 0;
  max-width: 280px;
  color: var(--bf-text-400);
  font-size: 14px;
  line-height: 1.6;
}

/* Shared by the footer and header (2026-08-28) — same circular icon-badge
   language as .bf-persona-icon / .bf-dash-card__icon elsewhere in this
   theme, just sized down for a nav/footer context. */
.bf-social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--bf-text-300);
  transition: border-color 0.2s var(--bf-ease), color 0.2s var(--bf-ease), transform 0.2s var(--bf-ease);
}
.bf-social-link svg { width: 16px; height: 16px; }
.bf-social-link:hover {
  border-color: var(--bf-indigo);
  color: var(--bf-blue);
  transform: translateY(-2px);
}
.bf-footer__social { display: flex; gap: 10px; margin-top: 16px; }

.bf-footer__copy { color: var(--bf-text-400); font-size: 13px; }

.bf-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
}
.bf-footer__links a {
  color: var(--bf-text-300);
  font-size: 13px;
  text-decoration: none;
}
.bf-footer__links a:hover { color: var(--bf-text-50); }

/* FAQ (2026-09-19, owner: "strona jest biedna, dodaj gradienty") — dwie
   poświaty w tle sekcji (.bf-glow-orb, ten sam komponent co reszta strony)
   + gradientowy nagłówek (.bf-gradient-text) + gradientowa ramka na każdej
   pozycji akordeonu, mocniejsza po otwarciu. Zero nowego języka wizualnego —
   wszystko reużyte z istniejących tokenów/komponentów. */
.bf-faq-section { position: relative; overflow: hidden; }
.bf-faq { display: flex; flex-direction: column; gap: 10px; }
.bf-faq__item {
  position: relative;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  padding: 16px 18px;
  background: linear-gradient(160deg, rgba(255, 122, 69, 0.05), rgba(255, 255, 255, 0.02));
  transition: border-color 0.25s var(--bf-ease), box-shadow 0.25s var(--bf-ease);
}
.bf-faq__item:hover {
  border-color: rgba(255, 122, 69, 0.35);
}
.bf-faq__item[open] {
  border-color: rgba(255, 122, 69, 0.5);
  box-shadow: 0 16px 40px -24px rgba(255, 122, 69, 0.5);
}
.bf-faq__item summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 15px;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.bf-faq__item summary::-webkit-details-marker { display: none; }
.bf-faq__item summary::after {
  content: "+";
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--bf-gradient-brand);
  color: #fff;
  font-size: 16px;
  line-height: 1;
  transition: transform 0.25s var(--bf-ease);
}
.bf-faq__item[open] summary::after { transform: rotate(135deg); }
.bf-faq__item p {
  margin: 12px 0 0;
  color: var(--bf-text-300);
  font-size: 14px;
  line-height: 1.6;
}

.bf-legal { max-width: 760px; padding: 48px 0; line-height: 1.7; }
.bf-legal h1 { margin-bottom: 4px; }
.bf-legal__meta { color: var(--bf-text-400); font-size: 13px; margin-bottom: 32px; }
.bf-legal h2 { margin-top: 32px; font-size: 18px; }
.bf-legal ol, .bf-legal ul { padding-left: 20px; color: var(--bf-text-300); }
.bf-legal li { margin-bottom: 8px; }
.bf-legal p { color: var(--bf-text-300); }
.bf-legal a { color: var(--bf-indigo); }

/* ==========================================================================
   Panel Admina "kombajn" (2026-09-25) — service limit cards. The colour
   comes from PHP (--bf-limit-color, hsl 120° green = full → 0° red = empty,
   template-parts/panel-limits.php) so border, glow, value and bar all move
   along the same continuous scale.
   ========================================================================== */
.bf-limit-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--bf-limit-color); box-shadow: 0 0 18px -4px var(--bf-limit-color), inset 0 0 24px -12px var(--bf-limit-color); }
.bf-limit-card .bf-stats-card__label, .bf-limit-card .bf-stats-card__value { color: var(--bf-limit-color); }
.bf-limit-card--missing, .bf-limit-card--error { box-shadow: none; border-style: dashed; }
.bf-limit-card--error { --bf-limit-color: hsl(0, 70%, 60%) !important; }
.bf-limit-bar { height: 10px; border-radius: 999px; background: rgba(255, 255, 255, 0.08); overflow: hidden; }
.bf-limit-bar__fill { height: 100%; border-radius: inherit; background: var(--bf-limit-color); box-shadow: 0 0 12px var(--bf-limit-color); transition: width .6s ease; }
.bf-limit-card__pct { font-size: 13px; font-weight: 600; color: var(--bf-limit-color); }
.bf-limit-card__detail { font-size: 12px; line-height: 1.45; color: var(--bf-text-400); overflow-wrap: anywhere; }
.bf-insights-two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 24px; }
.bf-insights-two-col > div { min-width: 0; }
.bf-insights-two-col h3 { margin: 0 0 12px; font-size: 16px; }
.bf-stats-card__value small { font-size: 0.5em; opacity: 0.75; }
.bf-traffic-recent { margin-top: 16px; }
.bf-traffic-recent > summary { cursor: pointer; font-weight: 600; color: var(--bf-text-400); padding: 10px 0; }
.bf-traffic-recent[open] > summary { color: inherit; }

/* Panel Admina breathing room (2026-09-25, owner: "za fest napaćkane … za
   dużo rzeczy nachodzi na siebie"). A note under a card row sat 10px above
   the NEXT row / filter bar with no bottom margin, so text, cards and
   buttons visually glued together. Every block now gets real separation,
   and sections are divided by a thin line. */
.bf-stats-cards { margin-bottom: 8px; }
.bf-stats-cards + .bf-stats-cards { margin-top: 16px; }
.bf-stats-note { margin: 14px 0 28px; line-height: 1.55; max-width: 980px; }
.bf-stats-note:last-child { margin-bottom: 0; }
.bf-stats-section { margin-top: 56px; padding-top: 40px; border-top: 1px solid rgba(255, 255, 255, 0.06); }
.bf-stats-section h2 { margin-bottom: 20px; }
.bf-stats-section__header-row { margin-bottom: 20px; }
.bf-stats-table-scroll { margin-top: 20px; margin-bottom: 8px; }
.bf-stats-cards + .bf-library-filters, .bf-stats-note + .bf-library-filters { margin-top: 8px; }
.bf-library-filters + .bf-stats-cards { margin-top: 8px; }
.bf-stats-card { min-height: 128px; }
.bf-stats-card__label { line-height: 1.4; }
.bf-stats-card .bf-limit-card__detail { margin-top: 4px; }
.bf-traffic-recent { margin-top: 24px; }
@media (max-width: 640px) {
	.bf-stats-section { margin-top: 40px; padding-top: 28px; }
	.bf-stats-note { margin-bottom: 22px; }
}

/* Generator add-ons (2026-09-26, owner: "dodatki powinny być bardziej
   rozbudowane, żeby user wiedział, za co płaci") — itemised list of what
   each +20 zł add-on actually delivers. */
.bf-package-option span { gap: 6px; }
.bf-addon-list { margin: 6px 0 4px; padding: 0; list-style: none; display: grid; gap: 7px; }
.bf-addon-list li { position: relative; padding-left: 22px; font-size: 13px; line-height: 1.5; color: var(--bf-text-300); }
.bf-addon-list li::before { content: "✓"; position: absolute; left: 0; top: 0; font-weight: 700; color: var(--bf-indigo); }
.bf-addon-list b { color: var(--bf-text-50); font-weight: 600; }
.bf-addon-list a { color: inherit; text-decoration: underline; }
/* Same itemised add-on lists on the homepage + "Jak to działa" pricing
   (2026-09-26) — cards widened so the lists don't get cramped. */
.bf-addons { max-width: 820px; }
.bf-addon { padding: 18px 20px; gap: 8px; }
.bf-addon .bf-addon__desc { color: var(--bf-text-300); }
.bf-addon .bf-addon-list li { font-size: 12.5px; }
.bf-addon .bf-addon-list b { color: var(--bf-text-50); }

/* Warunek 50/50 wewnątrz dodatku Personalizacja (2026-09-29, owner: "ma się
   rzucać w oczy, na pomarańczowo") — wyciągnięty z .bf-addon-list na osobny,
   mocniej zaakcentowany box, bo to najbardziej konsekwencyjne zdanie w całym
   opisie dodatku (przeoczone → user publikuje niespersonalizowany ebook
   licząc na 50/50 i się rozczarowuje). Mocniejszy kontrast niż .bf-alert
   celowo. */
.bf-earn-highlight {
  margin-top: 10px;
  padding: 10px 14px;
  border-radius: 10px;
  background: rgba(255, 122, 69, 0.16);
  border: 1.5px solid var(--bf-indigo);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--bf-text-50);
}
.bf-earn-highlight strong { color: var(--bf-indigo); }
.bf-earn-highlight a { color: inherit; text-decoration: underline; }

/* ==========================================================================
   Asystent AI — czat (2026-09-26). assets/js/chat.js + inc/chat.php.
   Only loaded when BF_OPENAI_CHAT_KEY is set.
   ========================================================================== */
.bf-chat { position: fixed; right: 20px; bottom: 20px; z-index: 9990; font-size: 14px; }
.bf-chat__launcher { display: flex; align-items: center; gap: 10px; padding: 12px 18px 12px 14px; border: 0; border-radius: 999px; cursor: pointer; color: #1a1026; font-weight: 700; background: var(--bf-gradient-brand); box-shadow: 0 10px 30px -8px rgba(255, 122, 69, .7); transition: transform .2s ease; }
.bf-chat__launcher:hover { transform: translateY(-2px); }
.bf-chat__launcher svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }
.bf-chat.is-open .bf-chat__launcher-label { display: none; }
.bf-chat__panel { position: absolute; right: 0; bottom: 64px; width: 380px; height: min(620px, calc(100vh - 110px)); display: flex; flex-direction: column; background: var(--bf-bg-900); border: 1px solid rgba(255, 255, 255, .09); border-radius: 18px; overflow: hidden; box-shadow: 0 24px 60px -12px rgba(0, 0, 0, .7), 0 0 0 1px rgba(255, 122, 69, .12); }
.bf-chat__panel[hidden] { display: none; }
.bf-chat__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 16px; background: linear-gradient(135deg, rgba(255, 182, 72, .16), rgba(255, 95, 109, .12)); border-bottom: 1px solid rgba(255, 255, 255, .07); }
.bf-chat__head strong { display: block; color: var(--bf-text-50); font-size: 15px; }
.bf-chat__head small { color: var(--bf-text-400); font-size: 12px; }
.bf-chat__head-actions { display: flex; gap: 6px; }
.bf-chat__head-actions button { width: 32px; height: 32px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, .1); background: transparent; color: var(--bf-text-300); font-size: 18px; line-height: 1; cursor: pointer; }
.bf-chat__head-actions button:hover { color: var(--bf-text-50); border-color: rgba(255, 255, 255, .25); }
.bf-chat__log { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; overscroll-behavior: contain; }
.bf-chat__msg { max-width: 88%; line-height: 1.5; border-radius: 14px; padding: 10px 13px; overflow-wrap: anywhere; }
.bf-chat__msg--bot { align-self: flex-start; background: var(--bf-bg-800); color: var(--bf-text-50); border-bottom-left-radius: 4px; }
.bf-chat__msg--user { align-self: flex-end; background: var(--bf-gradient-brand); color: #1a1026; font-weight: 500; border-bottom-right-radius: 4px; white-space: pre-wrap; }
.bf-chat__msg--note { align-self: center; background: transparent; color: var(--bf-text-400); font-size: 12.5px; text-align: center; }
.bf-chat__text p { margin: 0 0 6px; } .bf-chat__text p:last-child { margin-bottom: 0; }
.bf-chat__text ul { margin: 4px 0 6px; padding-left: 18px; } .bf-chat__text li { margin: 2px 0; }
.bf-chat__text a { color: var(--bf-blue); text-decoration: underline; }
.bf-chat__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.bf-chat__chips button { border: 1px solid rgba(255, 122, 69, .45); background: rgba(255, 122, 69, .08); color: var(--bf-text-50); border-radius: 999px; padding: 7px 12px; font-size: 13px; cursor: pointer; }
.bf-chat__chips button:hover { background: rgba(255, 122, 69, .2); }
.bf-chat__cards { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.bf-chat__card { display: flex; gap: 10px; padding: 8px; border-radius: 12px; background: var(--bf-bg-950); border: 1px solid rgba(255, 255, 255, .07); text-decoration: none; color: inherit; transition: border-color .2s ease; }
.bf-chat__card:hover { border-color: rgba(255, 122, 69, .6); }
.bf-chat__card-cover { flex: 0 0 56px; height: 78px; border-radius: 6px; background: var(--bf-bg-700) center / cover no-repeat; }
.bf-chat__card-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.bf-chat__card-body strong { font-size: 13px; line-height: 1.3; color: var(--bf-text-50); }
.bf-chat__card-body small { font-size: 11.5px; line-height: 1.4; color: var(--bf-text-400); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.bf-chat__card-body em { font-style: normal; font-size: 12px; font-weight: 700; color: var(--bf-blue); }
.bf-chat__handoff { display: inline-block; margin-top: 10px; padding: 8px 12px; border-radius: 999px; background: rgba(255, 182, 72, .14); border: 1px solid rgba(255, 182, 72, .5); color: var(--bf-text-50); text-decoration: none; font-size: 13px; font-weight: 600; }
.bf-chat__recap { margin-top: 10px; padding-top: 10px; border-top: 1px dashed rgba(255, 255, 255, .12); }
.bf-chat__recap > small { color: var(--bf-text-400); }
.bf-chat__rate { display: flex; gap: 4px; margin-top: 6px; }
.bf-chat__rate button { border: 0; background: transparent; cursor: pointer; font-size: 14px; opacity: .45; padding: 2px 4px; }
.bf-chat__rate button:hover, .bf-chat__rate button.is-on { opacity: 1; }
.bf-chat__final { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; padding: 10px; border-radius: 10px; background: rgba(255, 255, 255, .04); }
.bf-chat__final span { font-weight: 600; margin-right: 4px; }
.bf-chat__final button { border: 1px solid rgba(255, 255, 255, .15); background: transparent; color: var(--bf-text-50); border-radius: 999px; padding: 5px 11px; cursor: pointer; }
.bf-chat__typing { display: flex; gap: 5px; padding: 14px; }
.bf-chat__typing span { width: 7px; height: 7px; border-radius: 50%; background: var(--bf-text-400); animation: bf-chat-dot 1.2s infinite ease-in-out; }
.bf-chat__typing span:nth-child(2) { animation-delay: .15s; } .bf-chat__typing span:nth-child(3) { animation-delay: .3s; }
@keyframes bf-chat-dot { 0%, 80%, 100% { transform: translateY(0); opacity: .4; } 40% { transform: translateY(-5px); opacity: 1; } }
.bf-chat__form { display: flex; gap: 8px; padding: 12px; border-top: 1px solid rgba(255, 255, 255, .07); }
.bf-chat__form textarea { flex: 1; resize: none; min-height: 42px; max-height: 120px; padding: 10px 12px; border-radius: 12px; border: 1px solid rgba(255, 255, 255, .12); background: var(--bf-bg-950); color: var(--bf-text-50); font: inherit; font-size: 16px; line-height: 1.4; }
.bf-chat__form textarea:focus { outline: none; border-color: rgba(255, 122, 69, .7); }
.bf-chat__form button { flex: 0 0 44px; border: 0; border-radius: 12px; background: var(--bf-gradient-brand); color: #1a1026; font-size: 16px; cursor: pointer; }
.bf-chat__form button:disabled { opacity: .5; cursor: default; }
.bf-chat__legal { margin: 0; padding: 0 14px 10px; font-size: 10.5px; line-height: 1.4; color: var(--bf-text-400); }
.bf-chat__legal a { color: inherit; }
@media (max-width: 520px) {
	.bf-chat { right: 12px; bottom: 12px; }
	.bf-chat__launcher-label { display: none; }
	.bf-chat__launcher { padding: 14px; }
	.bf-chat.is-open { inset: 0; }
	.bf-chat.is-open .bf-chat__launcher { display: none; }
	.bf-chat__panel { position: fixed; inset: 0; width: auto; height: auto; bottom: 0; border-radius: 0; }
}
.bf-chat-log { margin: 8px 0; border: 1px solid rgba(255, 255, 255, .07); border-radius: 10px; padding: 8px 12px; }
.bf-chat-log > summary { cursor: pointer; font-size: 13px; color: var(--bf-text-300); }
.bf-chat-log__body { padding: 10px 0 4px; display: grid; gap: 8px; }
.bf-chat-log__msg { font-size: 13px; line-height: 1.5; padding: 8px 10px; border-radius: 8px; background: rgba(255, 255, 255, .03); }
.bf-chat-log__msg--user { background: rgba(255, 122, 69, .08); }

/* Marketplace category sidebar (2026-09-26, owner: "nie ma wypisanych
   wszystkich kategorii"). All 28 categories were in the HTML, but the
   sticky sidebar had no max-height: ~1600px of buttons in a ~900px window,
   so everything below ~"Nowe technologie" could never scroll into view, and
   top:24px put the first items under the 128px sticky site header. Now it
   sits below the header and scrolls on its own. */
@media (min-width: 900px) {
	.bf-marketplace-sidebar {
		top: 144px;
		max-height: calc(100vh - 164px);
		overflow-y: auto;
		overscroll-behavior: contain;
		padding-right: 6px;
		scrollbar-width: thin;
		scrollbar-color: rgba(255, 122, 69, .55) transparent;
	}
	.bf-marketplace-sidebar::-webkit-scrollbar { display: block; width: 6px; }
	.bf-marketplace-sidebar::-webkit-scrollbar-thumb { background: rgba(255, 122, 69, .55); border-radius: 3px; }
}
/* Chat reset — visible, labelled (2026-09-26, owner: "powinien być reset czatu"). */
.bf-chat__head-actions .bf-chat__reset { width: auto; padding: 0 12px; border-radius: 999px; font-size: 13px; font-weight: 600; display: inline-flex; align-items: center; gap: 6px; }
.bf-chat__head-actions .bf-chat__reset span { font-size: 12px; }
.bf-chat__restart { display: block; margin-top: 10px; border: 1px solid rgba(255, 122, 69, .5); background: rgba(255, 122, 69, .1); color: var(--bf-text-50); border-radius: 999px; padding: 7px 14px; font-size: 13px; font-weight: 600; cursor: pointer; }
.bf-chat__restart:hover { background: rgba(255, 122, 69, .22); }
@media (max-width: 360px) { .bf-chat__head-actions .bf-chat__reset span { display: none; } }
/* Chat launcher pulse (2026-09-26, owner: "gradient cień za przyciskiem
   trochę większy, niech miga — żeby user od razu widział, że ma wsparcie").
   A blurred brand-gradient halo breathes behind the button + an expanding
   ring every 2.2s. Stops while the chat is open; off for reduced-motion. */
.bf-chat__launcher { position: relative; isolation: isolate; box-shadow: 0 14px 40px -6px rgba(255, 122, 69, .85); animation: bf-chat-ring 2.2s ease-out infinite; }
.bf-chat__launcher::before { content: ""; position: absolute; inset: -14px; z-index: -1; border-radius: 999px; background: var(--bf-gradient-brand); filter: blur(18px); opacity: .55; animation: bf-chat-halo 2.2s ease-in-out infinite; }
@keyframes bf-chat-halo { 0%, 100% { opacity: .35; transform: scale(.92); } 50% { opacity: .85; transform: scale(1.12); } }
@keyframes bf-chat-ring {
	0% { box-shadow: 0 14px 40px -6px rgba(255, 122, 69, .85), 0 0 0 0 rgba(255, 122, 69, .6); }
	70% { box-shadow: 0 14px 40px -6px rgba(255, 122, 69, .85), 0 0 0 20px rgba(255, 122, 69, 0); }
	100% { box-shadow: 0 14px 40px -6px rgba(255, 122, 69, .85), 0 0 0 0 rgba(255, 122, 69, 0); }
}
.bf-chat.is-open .bf-chat__launcher, .bf-chat.is-open .bf-chat__launcher::before { animation: none; }
.bf-chat.is-open .bf-chat__launcher::before { opacity: .3; }
@media (prefers-reduced-motion: reduce) {
	.bf-chat__launcher, .bf-chat__launcher::before { animation: none; }
}
/* Chat header on phones (preview 26.09): "Nowa rozmowa" and the subtitle wrapped to 2 lines. */
.bf-chat__head > div:first-child { min-width: 0; }
.bf-chat__head small { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bf-chat__head-actions { flex-shrink: 0; }
.bf-chat__head-actions .bf-chat__reset { white-space: nowrap; height: 32px; }
/* Chat → prefilled Generator (2026-09-26). */
.bf-chat__go { display: block; margin-top: 10px; padding: 11px 14px; border-radius: 12px; background: var(--bf-gradient-brand); color: #1a1026; font-weight: 700; font-size: 14px; text-align: center; text-decoration: none; box-shadow: 0 8px 22px -8px rgba(255, 122, 69, .8); }
.bf-chat__countdown { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; font-size: 12.5px; color: var(--bf-text-300); }
.bf-chat__countdown button { border: 1px solid rgba(255, 255, 255, .18); background: transparent; color: var(--bf-text-50); border-radius: 999px; padding: 4px 10px; font-size: 12px; cursor: pointer; }
/* Chat order card — clickable options instead of typing (2026-09-26). */
.bf-chat__order { margin-top: 12px; padding: 12px; border-radius: 14px; background: var(--bf-bg-950); border: 1px solid rgba(255, 122, 69, .35); display: grid; gap: 12px; }
.bf-chat__order fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.bf-chat__order legend { padding: 0; margin-bottom: 6px; font-size: 12px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; color: var(--bf-text-400); }
.bf-chat__order-title { font-size: 14px; line-height: 1.4; }
.bf-chat__chips-row { display: flex; flex-wrap: wrap; gap: 6px; }
.bf-chat__chip { position: relative; cursor: pointer; }
.bf-chat__chip input { position: absolute; opacity: 0; pointer-events: none; }
.bf-chat__chip span { display: inline-block; padding: 7px 11px; border-radius: 999px; border: 1px solid rgba(255, 255, 255, .16); font-size: 12.5px; line-height: 1.2; color: var(--bf-text-300); transition: all .15s ease; }
.bf-chat__chip input:checked + span { background: var(--bf-gradient-brand); border-color: transparent; color: #1a1026; font-weight: 700; }
.bf-chat__chip input:focus-visible + span { outline: 2px solid var(--bf-blue); outline-offset: 2px; }
.bf-chat__order-row { display: flex; gap: 10px; flex-wrap: wrap; }
.bf-chat__order-row label { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--bf-text-300); }
.bf-chat__order select { background: var(--bf-bg-800); color: var(--bf-text-50); border: 1px solid rgba(255, 255, 255, .16); border-radius: 10px; padding: 7px 10px; font-size: 14px; }
.bf-chat__order-select { width: 100%; }
.bf-chat__order-other { width: 100%; margin-top: 6px; padding: 7px 10px; border-radius: 10px; border: 1px solid rgba(255, 255, 255, .12); background: transparent; color: var(--bf-text-50); font-size: 14px; }
.bf-chat__check { display: flex; gap: 8px; align-items: flex-start; margin-top: 6px; font-size: 13px; line-height: 1.4; color: var(--bf-text-300); cursor: pointer; }
.bf-chat__check input { margin-top: 2px; width: 18px; height: 18px; accent-color: #ff7a45; flex: 0 0 18px; }
.bf-chat__check b { color: var(--bf-text-50); }
.bf-chat__order-total { font-size: 14px; color: var(--bf-text-300); }
.bf-chat__order-total strong { font-size: 18px; color: var(--bf-text-50); }
button.bf-chat__go { width: 100%; border: 0; cursor: pointer; font-family: inherit; }
.bf-chat__order-note { font-size: 11.5px; color: var(--bf-text-400); line-height: 1.4; }
/* Structure preview — "Coś Ci nie pasuje?" notes for the next version (2026-09-26). */
.bf-outline-preview__actions form:last-child { flex: 1 1 100%; display: grid; gap: 10px; margin-top: 8px; padding: 16px; border-radius: 14px; border: 1px dashed rgba(255, 255, 255, .14); background: rgba(255, 255, 255, .02); }
.bf-outline-feedback { display: grid; gap: 8px; }
.bf-outline-feedback label { font-size: 14px; line-height: 1.5; color: var(--bf-text-300); }
.bf-outline-feedback label strong { color: var(--bf-text-50); }
.bf-outline-feedback textarea { width: 100%; box-sizing: border-box; padding: 10px 12px; border-radius: 12px; border: 1px solid rgba(255, 255, 255, .14); background: var(--bf-bg-950); color: var(--bf-text-50); font: inherit; font-size: 15px; line-height: 1.5; resize: vertical; }
.bf-outline-feedback textarea:focus { outline: none; border-color: rgba(255, 122, 69, .7); }
.bf-outline-preview__actions form:last-child .bf-btn { justify-self: start; }
/* Fixed chapter count label in the chat order card (2026-09-26). */
.bf-chat__order-fixed { display: inline-flex; align-items: center; padding: 7px 12px; border-radius: 10px; background: var(--bf-bg-800); border: 1px solid rgba(255, 255, 255, .12); font-size: 13px; font-weight: 600; color: var(--bf-text-50); }

/* ==========================================================================
   BOOKForge EDU / siostrzane strony (2026-09-27, przeprojektowane po
   uwagach właściciela — usunięto ikonkę z nagłówka i kolumnę w stopce,
   zostaje: prawdziwe logo w karuzeli + osobna sekcja pod .bf-cta na
   stronie głównej, celowo generyczna nazwa .bf-cta--sister-sites, żeby dało
   się dopisać kolejne strony obok EDU bez przebudowy). Logo to przezroczysty
   PNG wycięty z materiału właściciela (assets/images/logo-bookforge-edu.png).
   ========================================================================== */
.bf-hero__edu-logo { display: block; height: 44px; width: auto; margin: 18px 0; }
@media (min-width: 900px) { .bf-hero__edu-logo { height: 56px; } }

.bf-cta--sister-sites {
	position: relative;
	background:
		radial-gradient(60% 90% at 50% 0%, rgba(124, 92, 240, 0.32) 0%, rgba(34, 184, 240, 0.1) 45%, rgba(124, 92, 240, 0) 75%),
		var(--bf-bg-950);
}
/* Wyróżnienie kontenera (2026-09-27, owner: "nadole ten kontener jakoś
   wyróżnij") — ramka + wewnętrzna poświata w kolorach EDU (niebiesko-
   -fioletowy), żeby sekcja wybijała się z reszty strony tak jak "Opublikuj
   swój ebook" na górze, bez kopiowania jego pomarańczowego akcentu. */
.bf-cta--sister-sites::before {
	content: "";
	position: absolute;
	inset: 20px;
	border: 1px solid rgba(124, 92, 240, 0.35);
	border-radius: 24px;
	box-shadow: inset 0 0 60px -20px rgba(124, 92, 240, 0.35);
	pointer-events: none;
}
.bf-sister-card__logo { display: block; height: 40px; width: auto; margin: 0 auto; }

/* Odznaka "NOWOŚĆ" w kolorach EDU — ten sam pulsujący kształt co
   .bf-badge-new-pulse (hero, akcent czerwony BOOKFORGE), tu z gradientem
   logo EDU, żeby dwa produkty zostały wizualnie rozróżnialne. */
.bf-badge-new-pulse--edu {
	background: linear-gradient(135deg, #22b8f0 0%, #7c5cf0 100%);
	box-shadow: 0 12px 30px -8px rgba(124, 92, 240, 0.7);
	animation: bf-badge-new-pulse-edu 1.6s ease-in-out infinite;
}
@keyframes bf-badge-new-pulse-edu {
	0%, 100% { transform: rotate(-3deg) scale(1); box-shadow: 0 12px 30px -8px rgba(124, 92, 240, 0.7), 0 0 0 0 rgba(124, 92, 240, 0.55); }
	50% { transform: rotate(-3deg) scale(1.08); box-shadow: 0 16px 38px -8px rgba(124, 92, 240, 0.8), 0 0 0 16px rgba(124, 92, 240, 0); }
}
@media (prefers-reduced-motion: reduce) {
	.bf-badge-new-pulse--edu { animation: none; }
}

/* Wysokość hero na desktopie (2026-10-09). Tło hero to `contain` (obraz
   2058x764), więc obraz wypełnia całą szerokość tylko wtedy, gdy hero ma
   proporcję obrazu. Dotąd wysokość wyznaczał najdłuższy slajd ("Opublikuj
   swój ebook") — po jego usunięciu hero zmalało do ok. 465 px, obraz się
   zmniejszył i zostawił pustą lewą stronę (zgłoszenie właściciela:
   "wygląd się rozjechał"). aspect-ratio działa tu jak min-height: gdy treść
   slajdu jest wyższa, hero i tak rośnie. Tylko ≥900px — mobile ma osobny
   obraz i układ. */
@media (min-width: 900px) {
  .bf-hero { aspect-ratio: 2058 / 764; }
}

/* Odznaka "JUŻ WKRÓTCE" obok "NOWOŚĆ" w sekcji EDU (2026-10-09, właściciel:
   "zajebiście przyciągające wzrok"). Ten sam kształt co NOWOŚĆ, ale ciepły
   gradient (żółć→pomarańcz→róż) kontrastuje z chłodnym niebiesko-fioletem
   obok, przechylona w drugą stronę (+3deg), puls opóźniony o pół cyklu, a po
   odznace co 2,8 s przebiega błysk. Bez animacji przy prefers-reduced-motion. */
.bf-badge-row {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: center;
  gap: 18px 22px;
  margin-bottom: 18px;
}
/* Kontener .bf-cta__inner ma max-width 520px — dwie odznaki w 22 px się tam
   nie mieszczą w jednym rzędzie, stąd 18 px na desktopie. */
.bf-badge-row .bf-badge-new-pulse { margin-bottom: 0; font-size: 18px; padding: 12px 26px; }
.bf-badge-soon-pulse {
  position: relative;
  overflow: hidden;
  display: flex;
  width: max-content;
  align-items: center;
  gap: 8px;
  background: linear-gradient(135deg, #ffd45e 0%, #ff9a3c 45%, #ff4f7b 100%);
  color: #2a1204;
  font-size: 18px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 12px 26px;
  white-space: nowrap;
  border-radius: 999px;
  transform: rotate(3deg);
  box-shadow: 0 12px 30px -8px rgba(255, 130, 60, 0.75);
  animation: bf-badge-soon-pulse 1.6s ease-in-out infinite;
  animation-delay: 0.8s;
}
.bf-badge-soon-pulse::after {
  content: "";
  position: absolute;
  top: 0;
  left: -60%;
  width: 40%;
  height: 100%;
  background: linear-gradient(100deg, transparent 0%, rgba(255, 255, 255, 0.65) 50%, transparent 100%);
  transform: skewX(-20deg);
  animation: bf-badge-soon-shine 2.8s ease-in-out infinite;
}
@keyframes bf-badge-soon-pulse {
  0%, 100% { transform: rotate(3deg) scale(1); box-shadow: 0 12px 30px -8px rgba(255, 130, 60, 0.75), 0 0 0 0 rgba(255, 130, 60, 0.55); }
  50% { transform: rotate(3deg) scale(1.08); box-shadow: 0 16px 38px -8px rgba(255, 130, 60, 0.85), 0 0 0 16px rgba(255, 130, 60, 0); }
}
@keyframes bf-badge-soon-shine {
  0%, 55% { left: -60%; }
  100% { left: 130%; }
}
@media (prefers-reduced-motion: reduce) {
  .bf-badge-soon-pulse, .bf-badge-soon-pulse::after { animation: none; }
}
/* Mobile (2026-10-09): NOWOŚĆ po lewej, JUŻ WKRÓTCE po prawej — zawsze w
   jednym rzędzie (nowrap), mniejsze, żeby zmieściły się na 320-390 px. */
@media (max-width: 640px) {
  .bf-badge-row { flex-wrap: nowrap; gap: 10px; }
  .bf-badge-row .bf-badge-new-pulse,
  .bf-badge-soon-pulse { font-size: 12px; padding: 8px 12px; gap: 5px; white-space: nowrap; }
}
@media (max-width: 359px) {
  .bf-badge-row { gap: 6px; }
  .bf-badge-row .bf-badge-new-pulse,
  .bf-badge-soon-pulse { font-size: 11px; padding: 7px 9px; }
}

/* Hero na telefonie (2026-10-09). Obraz mobilny 853x1844 jest `contain` przy
   górze, więc wypełnia całą szerokość tylko, gdy hero ma jego proporcję. Po
   usunięciu najdłuższego slajdu (50/50) hero skurczyło się z ok. 840 do
   644 px, obraz zmalał do 298 px szerokości i po bokach wyszły ciemne pasy.
   aspect-ratio działa jak min-height — jeśli treść slajdu jest wyższa, hero i
   tak rośnie. Tylko do 480 px; szersze ekrany mobilne zostają bez zmian. */
@media (max-width: 480px) {
  .bf-hero { aspect-ratio: 853 / 1844; }
}

/* Sekcja EDU na stronie głównej — kompozycja premium (2026-10-09, owner:
   "ładna zblurowana a zarazem premium"). Tłem ramki jest zdjęcie z hero
   bookforge-edu.pl (biurko nauczyciela: laptop, regały, globus), lekko
   rozmyte (blur 4,5 px — widać laptop, regały, globus; 49 KB, wersja
   mobilna 24 KB), pod ciemną nakładką w kolorach EDU (cyjan #55c8ff, fiolet #a13bff z
   ich strony) i z dwiema poświatami. Treść leży na szklanej karcie
   (backdrop-filter), więc tekst zostaje czytelny niezależnie od zdjęcia.
   ::before musi być pod treścią — stąd z-index na .bf-cta__inner. */
.bf-cta--sister-sites::before {
	inset: 20px;
	border: 1px solid rgba(135, 150, 255, 0.28);
	border-radius: 28px;
	background:
		radial-gradient(45% 60% at 12% 10%, rgba(85, 200, 255, 0.28) 0%, rgba(85, 200, 255, 0) 70%),
		radial-gradient(50% 65% at 90% 95%, rgba(161, 59, 255, 0.32) 0%, rgba(161, 59, 255, 0) 70%),
		linear-gradient(180deg, rgba(9, 11, 20, 0.22) 0%, rgba(9, 11, 20, 0.60) 100%),
		url("assets/images/edu-backdrop-blur.webp?v=2") center / cover no-repeat;
	box-shadow:
		inset 0 0 80px -24px rgba(124, 92, 240, 0.45),
		0 30px 90px -40px rgba(91, 108, 255, 0.55);
}
.bf-cta--sister-sites .bf-cta__inner {
	position: relative;
	z-index: 1;
	padding: 36px 32px 40px;
	background: rgba(12, 15, 28, 0.46);
	-webkit-backdrop-filter: blur(12px) saturate(140%);
	backdrop-filter: blur(12px) saturate(140%);
	border: 1px solid rgba(255, 255, 255, 0.12);
	border-radius: 24px;
	box-shadow:
		0 30px 80px -30px rgba(0, 0, 0, 0.75),
		inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.bf-cta--sister-sites .bf-cta__inner p { color: rgba(236, 240, 255, 0.86); }
@media (max-width: 640px) {
	.bf-cta--sister-sites::before {
		inset: 10px;
		border-radius: 22px;
		background:
			radial-gradient(60% 40% at 10% 6%, rgba(85, 200, 255, 0.28) 0%, rgba(85, 200, 255, 0) 70%),
			radial-gradient(70% 45% at 90% 96%, rgba(161, 59, 255, 0.32) 0%, rgba(161, 59, 255, 0) 70%),
			linear-gradient(180deg, rgba(9, 11, 20, 0.28) 0%, rgba(9, 11, 20, 0.64) 100%),
			url("assets/images/edu-backdrop-blur-mobile.webp?v=2") center / cover no-repeat;
	}
	.bf-cta--sister-sites .bf-cta__inner { padding: 28px 20px 32px; }
}

/* BOOKForge TRAVEL — druga karta siostrzana (2026-10-11), ta sama kompozycja
   co EDU, tło: rozmyte zdjęcie Santorini z hero bookforge-travel.pl
   (travel-backdrop-blur.webp 41 KB, mobile 21 KB), akcenty cyjan→fiolet z ich
   strony (#19c2ff / #2f6bff / #9238ff). ?v=1 = cache-bust (IONOS daje obrazom
   bez parametru tylko 30 min). */
.bf-cta--travel { margin-top: 0; }
.bf-cta--travel::before {
	background:
		radial-gradient(45% 60% at 12% 10%, rgba(25, 194, 255, 0.28) 0%, rgba(25, 194, 255, 0) 70%),
		radial-gradient(50% 65% at 90% 95%, rgba(146, 56, 255, 0.32) 0%, rgba(146, 56, 255, 0) 70%),
		linear-gradient(180deg, rgba(6, 11, 30, 0.22) 0%, rgba(6, 11, 30, 0.60) 100%),
		url("assets/images/travel-backdrop-blur.webp?v=1") center / cover no-repeat;
}
.bf-cta--travel .bf-sister-card__logo { height: 44px; max-width: 100%; }
@media (max-width: 640px) {
	.bf-cta--travel::before {
		background:
			radial-gradient(60% 40% at 10% 6%, rgba(25, 194, 255, 0.28) 0%, rgba(25, 194, 255, 0) 70%),
			radial-gradient(70% 45% at 90% 96%, rgba(146, 56, 255, 0.32) 0%, rgba(146, 56, 255, 0) 70%),
			linear-gradient(180deg, rgba(6, 11, 30, 0.28) 0%, rgba(6, 11, 30, 0.64) 100%),
			url("assets/images/travel-backdrop-blur-mobile.webp?v=1") center / cover no-repeat;
	}
	.bf-cta--travel .bf-sister-card__logo { height: auto; width: 100%; max-width: 300px; }
}

/* Przyklejony pasek zakupu na karcie produktu (2026-10-21) — tylko telefon/tablet.
   single-bf_product.php chowa go, gdy ramka z ceną jest na ekranie. */
.bf-buybar { display: none; }
@media (max-width: 768px) {
	.bf-buybar:not([hidden]) {
		position: fixed; left: 0; right: 0; bottom: 0; z-index: 9980;
		display: flex; align-items: center; justify-content: space-between; gap: 12px;
		padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
		background: rgba(18, 15, 34, .96); border-top: 1px solid rgba(255, 122, 69, .45);
		-webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
	}
	.bf-buybar__price strong { display: block; font-size: 22px; font-weight: 800; color: #fff; line-height: 1.1; }
	.bf-buybar__price small { display: block; font-size: 12px; color: var(--bf-text-400); }
	.bf-buybar__btn { flex: 0 0 auto; padding: 12px 22px; }
	.has-buybar .bf-chat { bottom: 84px; }
	.has-buybar { padding-bottom: 72px; }
}

/* Telefon: tagi pod opisem (hero) powtarzały się w sekcji „Szczegóły" niżej — ukryte tylko na telefonie/tablecie (2026-10-21),
   żeby cena i przycisk „Kup" były wyżej. Linki zostają w HTML (SEO), a ten sam zestaw tagów jest w „Szczegółach". */
@media (max-width: 768px) {
	.bf-product-single__tags { display: none !important; } /* !important: assets/css/premium.css (ładuje się później) ustawia tu display:flex */
}

/* 2026-10-21: karta produktu — notka przy cenie, blok „W środku" (3 pierwsze rozdziały), skrócone tagi na desktopie.
   Tagi: na desktopie w hero zostają 4 pierwsze (7 zajmowało ~3 rzędy nad ramką zakupu); wszystkie 7 są nadal w „Szczegółach". */
.bf-product-single__price-note { margin: 2px 0 12px !important; font-size: 12.5px; color: var(--bf-text-400); }
.bf-peek { margin: 0 0 14px; padding: 10px 12px; border: 1px solid var(--bf-border, rgba(255,255,255,.12)); border-radius: 10px; background: rgba(255,255,255,.03); }
.bf-peek__title { margin: 0 0 6px !important; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--bf-text-400); }
.bf-peek__list { margin: 0; padding: 0 0 0 18px; font-size: 13px; line-height: 1.45; color: var(--bf-text-300); }
.bf-peek__list li { margin: 0 0 3px; }
.bf-peek__more { display: inline-block; margin-top: 4px; font-size: 12.5px; color: var(--bf-blue, #5ac8e8); text-decoration: none; }
.bf-peek__more:hover { text-decoration: underline; }
.bf-product-single__toc { scroll-margin-top: 90px; }
.bf-peek { margin: 14px 0 0; }

/* 22.10.2026 — koszyk (inc/cart.php, template-cart.php) */
.bf-cart-link { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; color: var(--bf-text-50, #f5f4fa); border: 1px solid rgba(255,255,255,.14); }
.bf-cart-link:hover { border-color: rgba(255,255,255,.35); }
.bf-cart-link__count { position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: #ff7a45; color: #1d1a33; font-size: 11px; font-weight: 800; line-height: 18px; text-align: center; }
.bf-cart { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; margin-top: 8px; }
.bf-cart__items { display: grid; gap: 10px; align-content: start; }
.bf-cart-item { display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 12px; border: 1px solid rgba(255,255,255,.1); border-radius: 12px; background: rgba(255,255,255,.03); }
.bf-cart-item__cover { width: 64px; height: 92px; border-radius: 6px; background: #2a2748 center / cover no-repeat; display: block; }
.bf-cart-item__info { display: grid; gap: 4px; min-width: 0; }
.bf-cart-item__title { font-weight: 700; font-size: 15px; line-height: 1.35; color: var(--bf-text-50, #f5f4fa); text-decoration: none; }
.bf-cart-item__meta { font-size: 12.5px; color: var(--bf-text-400); }
.bf-cart-item__side { display: grid; gap: 6px; justify-items: end; }
.bf-cart-item__price { font-weight: 700; white-space: nowrap; }
.bf-cart-item__remove { background: none; border: 0; padding: 0; color: var(--bf-text-300); font-size: 12.5px; text-decoration: underline; cursor: pointer; }
.bf-cart__summary { padding: 18px; border: 1px solid rgba(255,255,255,.12); border-radius: 14px; background: rgba(255,255,255,.04); align-self: start; }
.bf-cart__summary h2 { font-size: 18px; margin: 0 0 12px; }
.bf-cart__row { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; font-size: 14.5px; }
.bf-cart__row--total { border-top: 1px solid rgba(255,255,255,.14); margin-top: 6px; padding-top: 12px; font-size: 18px; font-weight: 800; }
.bf-cart__checkout { margin-top: 14px; }
.bf-cart__more { margin: 12px 0 0; font-size: 13px; }
.bf-cart__suggest { margin-top: 34px; }
.bf-cart__suggest h2 { margin: 0 0 4px; }
.bf-cart-suggest-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 14px; }
.bf-cart-suggest { display: grid; gap: 6px; align-content: start; padding: 10px; border: 1px solid rgba(255,255,255,.1); border-radius: 12px; background: rgba(255,255,255,.03); }
.bf-cart-suggest__cover { display: block; aspect-ratio: 2 / 3; border-radius: 8px; background: #2a2748 center / cover no-repeat; }
.bf-cart-suggest__title { font-weight: 700; font-size: 14px; line-height: 1.35; color: var(--bf-text-50, #f5f4fa); text-decoration: none; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.bf-cart-suggest__meta { font-size: 12.5px; color: var(--bf-text-400); }
.bf-cart-suggest .bf-btn { padding: 9px 10px; font-size: 13.5px; }
/* 22.10.2026 — sekcja „Ebooki po polsku w jednym miejscu" (front-page.php, .bf-fh-about): na telefonie nagłówek miał 48 px (reszta strony 30 px),
   zero odstępu pod nagłówkiem i serifowy tekst 18 px — wyglądało jak błąd. Selektory z .bf-section, bo premium.css ładuje się później. */
.bf-section .bf-fh-about h2 { margin: 0 0 18px; }
@media (max-width: 768px) {
	.bf-section .bf-fh-about h2 { font-size: 30px; line-height: 1.2; margin: 0 0 16px; }
	.bf-section .bf-fh-about p { font-family: inherit; font-size: 16px; line-height: 1.65; margin: 0 0 14px; }
}
.bf-cart__title { font-size: clamp(32px, 9vw, 56px); line-height: 1.05; margin: 0 0 8px; }
.bf-cart__suggest h2 { font-size: clamp(22px, 6vw, 30px); line-height: 1.2; }
.bf-cart-suggest { display: flex; flex-direction: column; }
.bf-cart-suggest form { margin-top: auto; padding-top: 6px; }
@media (max-width: 640px) {
	/* ikona koszyka poszerzała nagłówek ponad szerokość telefonu (wypychała menu) — na telefonie chowamy ikonę Facebooka obok koszyka */
	.bf-header__actions .bf-cart-link { width: 36px; height: 36px; }
	.bf-header__actions .bf-cart-link ~ .bf-social-link { display: none; }
	/* 22.10.2026: nagłówek na telefonie (375 px) wystawał poza ekran już przed koszykiem — pusty .bf-nav liczył się jako odstęp 24 px, a logo
	   miało 165 px; ikona menu była przycięta przy prawej krawędzi. Mniejsze odstępy i logo → całość mieści się w ekranie. */
	.bf-header__inner { gap: 8px !important; }
	.bf-logo img { width: 136px !important; height: auto !important; }
	.bf-header__actions { gap: 8px !important; }
	.bf-header__cta { padding-left: 12px !important; padding-right: 12px !important; font-size: 13px !important; }
}
@media (min-width: 900px) {
	.bf-cart { grid-template-columns: minmax(0, 1fr) 360px; gap: 28px; }
	.bf-cart-suggest-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* 22.10.2026 (audyt): linia faktów na karcie listy + linia „Sprzedawca" w ramce zakupu */
.bf-ebook-card__facts { margin: 0 0 8px; font-size: 12.5px; line-height: 1.4; color: var(--bf-text-300); }
.bf-product-single__seller { margin: 12px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--bf-text-400); }
.bf-product-single__seller a { color: var(--bf-text-300); text-decoration: underline; }

/* 22.10.2026 — lejek na telefonie (audyt: 74% ruchu to telefony; cena i „Kup" były pod banerem cookies, lista kategorii zaczynała się
   ok. 1600 px od góry). Reguły z podwójnym selektorem/!important, bo assets/css/premium.css ładuje się później i ma !important. */
.bf-cc-short { display: none; }
@media (max-width: 640px) {
	.bf-cc-long { display: none; }
	.bf-cc-short { display: inline; }
	.bf-cookie-consent { padding: 10px 14px calc(10px + env(safe-area-inset-bottom)); gap: 8px; }
	.bf-cookie-consent p { font-size: 12.5px; line-height: 1.4; }
	.bf-cookie-consent__actions { gap: 8px; }
	.bf-cookie-consent__actions .bf-btn { flex: 1 1 0; padding: 9px 12px; font-size: 14px; }
}
@media (max-width: 768px) {
	.bf-product-single__breadcrumb { display: none; }
	.bf-section .bf-mp-forge--top { display: none !important; }
	.bf-section .bf-mp-forge--bottom { display: flex; margin: 24px 0 0; }
	.bf-mp-filtered .bf-marketplace-banner { display: none; }
	.bf-section .bf-marketplace-layout .bf-marketplace-sidebar.bf-marketplace-sidebar {
		flex-wrap: nowrap !important; overflow-x: auto !important; overflow-y: hidden !important;
		margin: 0 0 14px !important; padding-bottom: 6px !important; -webkit-overflow-scrolling: touch; scrollbar-width: none;
	}
	.bf-marketplace-sidebar::-webkit-scrollbar { display: none; }
}
@media (min-width: 769px) {
	.bf-section .bf-mp-forge--bottom { display: none !important; }
}
@media (min-width: 769px) {
	.bf-product-single__tags .bf-tag-badge:nth-child(n+5) { display: none !important; }
}
